commit e0f67c0550237d185358321af3ec98c065338cd4 Author: PProvost Date: Mon May 11 08:51:44 2020 -0600 Initial commit diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..ee9315d --- /dev/null +++ b/.gitattributes @@ -0,0 +1,40 @@ +.git* export-ignore +.hooks* export-ignore + +# Custom attribute to mark sources as using our C code style. +[attr]our-c-style whitespace=tab-in-indent eol=lf format.clang-format-6.0 + +# Custom attribute to mark sources as generated. +# Do not perform whitespace checks. Do not format. +[attr]generated whitespace=-tab-in-indent,-indent-with-non-tab -format.clang-format-6.0 + +bootstrap eol=lf +configure eol=lf +*.[1-9] eol=lf +*.bash eol=lf +*.sh eol=lf +*.sh.in eol=lf + +*.bat eol=crlf +*.bat.in eol=crlf +*.sln eol=crlf +*.vcproj eol=crlf + +*.pfx -text +*.png -text +*.png.in -text + +*.c our-c-style +*.cc our-c-style +*.cpp our-c-style +*.cu our-c-style +*.cxx our-c-style +*.h our-c-style +*.hh our-c-style +*.hpp our-c-style +*.hxx our-c-style +*.notcu our-c-style + +*.cmake whitespace=tab-in-indent +*.rst whitespace=tab-in-indent conflict-marker-size=79 +*.txt whitespace=tab-in-indent \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100755 index 0000000..9c33dc7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +.vscode/ +_deps/ +build/ +CMakeFiles/ +CMakeScripts/ +CMakeLists.txt.user +CMakeCache.txt +Testing +Makefile +cmake_install.cmake +install_manifest.txt +compile_commands.json +CTestTestfile.cmake + diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100755 index 0000000..ed9d1a3 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,49 @@ +cmake_minimum_required(VERSION 3.0.0 FATAL_ERROR) + +# Set up the project +project(netx + VERSION 6.0.0 + LANGUAGES C ASM +) + +if(NOT DEFINED THREADX_ARCH) + message(FATAL_ERROR "Error: THREADX_ARCH not defined") +endif() +if(NOT DEFINED THREADX_TOOLCHAIN) + message(FATAL_ERROR "Error: THREADX_TOOLCHAIN not defined") +endif() + +# Define our target library and an alias for consumers +add_library(${PROJECT_NAME}) +add_library("azrtos::${PROJECT_NAME}" ALIAS ${PROJECT_NAME}) + +# Define any required dependencies between this library and others +target_link_libraries(${PROJECT_NAME} PUBLIC + "azrtos::threadx" +) + +# A place for generated/copied include files (no need to change) +set(CUSTOM_INC_DIR ${CMAKE_CURRENT_BINARY_DIR}/custom_inc) + +# Pick up the port specific stuff first +add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/ports/${THREADX_ARCH}/${THREADX_TOOLCHAIN}) + +# Then the common files +add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/common) + + + + +# If the user provided an override, copy it to the custom directory +if (NOT NX_USER_FILE) + message(STATUS "Using default nx_user.h file") + set(NX_USER_FILE ${CMAKE_CURRENT_LIST_DIR}/common/inc/nx_user_sample.h) +else() + message(STATUS "Using custom nx_user.h file from ${NX_USER_FILE}") +endif() +configure_file(${NX_USER_FILE} ${CUSTOM_INC_DIR}/nx_user.h COPYONLY) +target_include_directories(${PROJECT_NAME} + PUBLIC + ${CUSTOM_INC_DIR} +) +target_compile_definitions(${PROJECT_NAME} PUBLIC "NX_INCLUDE_USER_DEFINE_FILE" ) diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..76974a3 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,246 @@ +MICROSOFT SOFTWARE LICENSE TERMS + +MICROSOFT AZURE RTOS + +Shape + +These license terms are an agreement between you and Microsoft Corporation (or +one of its affiliates). They apply to the software named above and any Microsoft +services or software updates (except to the extent such services or updates are +accompanied by new or additional terms, in which case those different terms +apply prospectively and do not alter your or Microsoft’s rights relating to +pre-updated software or services). IF YOU COMPLY WITH THESE LICENSE TERMS, YOU +HAVE THE RIGHTS BELOW. BY USING THE SOFTWARE, YOU ACCEPT THESE TERMS. + +INSTALLATION AND USE RIGHTS. + +General. You may install and use the software and the included Microsoft +applications solely for internal development, testing and evaluation purposes. +Any distribution or production use requires a separate license as set forth in +Section 2. + +Contributions. Microsoft welcomes contributions to this software. In the event +that you make a contribution to this software you will be required to agree to a +Contributor License Agreement (CLA) declaring that you have the right to, and +actually do, grant Microsoft the rights to use your contribution. For details, +visit https://cla.microsoft.com. + +Included Microsoft Applications. The software includes other Microsoft +applications which are governed by the licenses embedded in or made available +with those applications. + +Third Party Components. The software may include third party components with +separate legal notices or governed by other agreements, as may be described +within the software or in the ThirdPartyNotices file(s) accompanying the +software. + +Competitive Benchmarking. If you are a direct competitor, and you access or use +the software for purposes of competitive benchmarking, analysis, or intelligence +gathering, you waive as against Microsoft, its subsidiaries, and its affiliated +companies (including prospectively) any competitive use, access, and +benchmarking test restrictions in the terms governing your software to the +extent your terms of use are, or purport to be, more restrictive than +Microsoft’s terms. If you do not waive any such purported restrictions in the +terms governing your software, you are not allowed to access or use this +software, and will not do so. + +DISTRIBUTION AND PRODUCTION USE. If you have obtained and/or are developing on +microprocessor(s) and/or microcontroller(s) (“hardware”) listed in the file +named “LICENSED-HARDWARE.txt” included in the repository and/or distributed with +the software you have the following rights in and to the software solely when +used in combination with the hardware. In the event hardware is not listed in +the LICENSED-HARDWARE.txt file, you do not have the rights in this Section 2. + +Distribution and Production Use Rights. + +You may use the software in production (e.g. program the modified or unmodified +software to devices you own or control) and distribute (i.e. make available to +third parties) the modified or unmodified binary image produced from this code. + + +You may permit your device distributors or developers to copy and distribute the +binary image as programmed or to be programmed to your devices. + +You may redistribute the unmodified or modified source to your device +distributors or developers. Modifications must be clearly marked. Any +redistribution in source code form must contain this license and any other +licenses that accompany the software. + +Requirements. For any code you distribute, you must: + +when distributed in binary form, except as embedded in a device, include with +such distribution the terms of this agreement; + +when distributed in source code form to distributors or developers of your +devices, include with such distribution the terms of this agreement; and + +indemnify, defend and hold harmless Microsoft from any claims, including +attorneys’ fees, related to the distribution or use of your devices, except to +the extent that any claim is based solely on the unmodified software. + +Restrictions. You may not: + +use or modify the software to create a competing real time operating system +software; + +remove any copyright notices or licenses contained in the software; + +use Microsoft’s trademarks or trade dress in your application in any way that +suggests your device or application comes from or is endorsed by Microsoft; + +transfer individual components, specific libraries, classes, functions or code +fragments of the software separately for purposes unrelated to the software; or + +use or distribute the software in any way that would subject the software or +Microsoft’s intellectual property or technology to any other license terms. + +SCOPE OF LICENSE. The software is licensed, not sold. Microsoft reserves all +other rights. Unless applicable law gives you more rights despite this +limitation, you will not (and have no right to): + +remove, minimize, block, or modify any notices of Microsoft or its suppliers in +the software; + +use the software in any way that is against the law or to create or propagate +malware; or + +share, publish, distribute, or lease the software (except as permitted in +Section 2 above), or provide the software as a stand-alone offering for others +to use. + +DATA. This software may interact with other Microsoft products that collect data +that is transmitted to Microsoft. To learn more about how Microsoft processes +personal data we collect, please see the Microsoft Privacy Statement at +https://go.microsoft.com/fwlink/?LinkId=248681. + +EXPORT RESTRICTIONS. You must comply with all domestic and international export +laws and regulations that apply to the software, which include restrictions on +destinations, end users, and end use. For further information on export +restrictions, visit https://aka.ms/exporting. + +SUPPORT SERVICES. Microsoft is not obligated under this agreement to provide any +support services for the software. Any support provided is “as is”, “with all +faults”, and without warranty of any kind. + +UPDATES. Microsoft may periodically update the software. You may obtain updates +only from Microsoft or Microsoft-authorized sources. Updates may not include or +support all existing software features, services, or peripheral devices. + +TERMINATION. Without prejudice to any other rights, Microsoft may terminate this +agreement if you fail to comply with any of its terms or conditions. In such +event, you must destroy all copies of the software and all of its component +parts. + +ENTIRE AGREEMENT. This agreement, and any other terms Microsoft may provide for +supplements, updates, or third-party applications, is the entire agreement for +the software. To the extent you have entered into a separate agreement with +Microsoft relating specifically to the software, the terms in such agreement +shall control. + +APPLICABLE LAW AND PLACE TO RESOLVE DISPUTES. If you acquired the software in +the United States or Canada, the laws of the state or province where you live +(or, if a business, where your principal place of business is located) govern +the interpretation of this agreement, claims for its breach, and all other +claims (including consumer protection, unfair competition, and tort claims), +regardless of conflict of laws principles. If you acquired the software in any +other country, its laws apply. If U.S. federal jurisdiction exists, you and +Microsoft consent to exclusive jurisdiction and venue in the federal court in +King County, Washington for all disputes heard in court. If not, you and +Microsoft consent to exclusive jurisdiction and venue in the Superior Court of +King County, Washington for all disputes heard in court. + +CONSUMER RIGHTS; REGIONAL VARIATIONS. This agreement describes certain legal +rights. You may have other rights, including consumer rights, under the laws of +your state or country. Separate and apart from your relationship with Microsoft, +you may also have rights with respect to the party from which you acquired the +software. This agreement does not change those other rights if the laws of your +state or country do not permit it to do so. For example, if you acquired the +software in one of the below regions, or mandatory country law applies, then the +following provisions apply to you: + +Australia. You have statutory guarantees under the Australian Consumer Law and +nothing in this agreement is intended to affect those rights. + +Germany and Austria. + +i.Warranty. The properly licensed software will perform substantially as +described in any Microsoft materials that accompany the software. However, +Microsoft gives no contractual guarantee in relation to the licensed software. + +ii.Limitation of Liability. In case of intentional conduct, gross negligence, +claims based on the Product Liability Act, as well as, in case of death or +personal or physical injury, Microsoft is liable according to the statutory law. + + +Subject to the foregoing clause ii., Microsoft will only be liable for slight +negligence if Microsoft is in breach of such material contractual obligations, +the fulfillment of which facilitate the due performance of this agreement, the +breach of which would endanger the purpose of this agreement and the compliance +with which a party may constantly trust in (so-called "cardinal obligations"). +In other cases of slight negligence, Microsoft will not be liable for slight +negligence. + +DISCLAIMER OF WARRANTY. THE SOFTWARE IS LICENSED “AS IS.” YOU BEAR THE RISK OF +USING IT. MICROSOFT GIVES NO EXPRESS WARRANTIES, GUARANTEES, OR CONDITIONS. TO +THE EXTENT PERMITTED UNDER APPLICABLE LAWS, MICROSOFT EXCLUDES ALL IMPLIED +WARRANTIES, INCLUDING MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND +NON-INFRINGEMENT. + +LIMITATION ON AND EXCLUSION OF DAMAGES. IF YOU HAVE ANY BASIS FOR RECOVERING +DAMAGES DESPITE THE PRECEDING DISCLAIMER OF WARRANTY, YOU CAN RECOVER FROM +MICROSOFT AND ITS SUPPLIERS ONLY DIRECT DAMAGES UP TO U.S. $5.00. YOU CANNOT +RECOVER ANY OTHER DAMAGES, INCLUDING CONSEQUENTIAL, LOST PROFITS, SPECIAL, +INDIRECT, OR INCIDENTAL DAMAGES. + +This limitation applies to (a) anything related to the software, services, +content (including code) on third party Internet sites, or third party +applications; and (b) claims for breach of contract, warranty, guarantee, or +condition; strict liability, negligence, or other tort; or any other claim; in +each case to the extent permitted by applicable law. + +It also applies even if Microsoft knew or should have known about the +possibility of the damages. The above limitation or exclusion may not apply to +you because your state, province, or country may not allow the exclusion or +limitation of incidental, consequential, or other damages. + + + +Please note: As this software is distributed in Canada, some of the clauses in +this agreement are provided below in French. + +Remarque: Ce logiciel étant distribué au Canada, certaines des clauses dans ce +contrat sont fournies ci-dessous en français. + +EXONÉRATION DE GARANTIE. Le logiciel visé par une licence est offert « tel quel +». Toute utilisation de ce logiciel est à votre seule risque et péril. Microsoft +n’accorde aucune autre garantie expresse. Vous pouvez bénéficier de droits +additionnels en vertu du droit local sur la protection des consommateurs, que ce +contrat ne peut modifier. La ou elles sont permises par le droit locale, les +garanties implicites de qualité marchande, d’adéquation à un usage particulier +et d’absence de contrefaçon sont exclues. + +LIMITATION DES DOMMAGES-INTÉRÊTS ET EXCLUSION DE RESPONSABILITÉ POUR LES +DOMMAGES. Vous pouvez obtenir de Microsoft et de ses fournisseurs une +indemnisation en cas de dommages directs uniquement à hauteur de 5,00 $ US. Vous +ne pouvez prétendre à aucune indemnisation pour les autres dommages, y compris +les dommages spéciaux, indirects ou accessoires et pertes de bénéfices. + +Cette limitation concerne: + +•tout ce qui est relié au logiciel, aux services ou au contenu (y compris le +code) figurant sur des sites Internet tiers ou dans des programmes tiers; et + +•les réclamations au titre de violation de contrat ou de garantie, ou au titre +de responsabilité stricte, de négligence ou d’une autre faute dans la limite +autorisée par la loi en vigueur. + +Elle s’applique également, même si Microsoft connaissait ou devrait connaître +l’éventualité d’un tel dommage. Si votre pays n’autorise pas l’exclusion ou la +limitation de responsabilité pour les dommages indirects, accessoires ou de +quelque nature que ce soit, il se peut que la limitation ou l’exclusion +ci-dessus ne s’appliquera pas à votre égard. + +EFFET JURIDIQUE. Le présent contrat décrit certains droits juridiques. Vous +pourriez avoir d’autres droits prévus par les lois de votre pays. Le présent +contrat ne modifie pas les droits que vous confèrent les lois de votre pays si +celles-ci ne le permettent pas. \ No newline at end of file diff --git a/LICENSED-HARDWARE.txt b/LICENSED-HARDWARE.txt new file mode 100644 index 0000000..77dd1ab --- /dev/null +++ b/LICENSED-HARDWARE.txt @@ -0,0 +1,16 @@ +LICENSED HARDWARE LIST + +Last Updated: 2020-05-08 + +Microsoft has entered into OEM Agreements with manufacturers of the following +microprocessors and microcontrollers (the “hardware”) to enable those +manufacturers to include and distribute Azure RTOS in certain hardware. If you +have obtained and/or are developing on microprocessor(s) and/or +microcontroller(s) (“hardware”) listed below you inherit the “Distribution and +Production Use” rights in Section 2 of the Microsoft Software License Terms for +Microsoft Azure RTOS. If hardware is not listed below, you do not have those +rights. + +-------------------------------------------------------------------------------- + +More coming soon. Please check back frequently for updates. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100755 index 0000000..3b4ffac --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# NetX + +TODO: Description here diff --git a/TODO b/TODO new file mode 100644 index 0000000..14100f6 --- /dev/null +++ b/TODO @@ -0,0 +1 @@ +* exFAT is still in here... do we need to remove it? \ No newline at end of file diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt new file mode 100644 index 0000000..2b75835 --- /dev/null +++ b/common/CMakeLists.txt @@ -0,0 +1,321 @@ +target_sources(${PROJECT_NAME} PRIVATE + # {{BEGIN_TARGET_SOURCES}} + ${CMAKE_CURRENT_LIST_DIR}/src/nx_arp_announce_send.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_arp_dynamic_entries_invalidate.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_arp_dynamic_entry_set.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_arp_enable.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_arp_entry_allocate.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_arp_gratuitous_send.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_arp_hardware_address_find.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_arp_info_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_arp_ip_address_find.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_arp_packet_deferred_receive.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_arp_packet_receive.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_arp_packet_send.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_arp_periodic_update.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_arp_probe_send.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_arp_queue_process.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_arp_static_entries_delete.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_arp_static_entry_create.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_arp_static_entry_delete.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_icmp_checksum_compute.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_icmp_cleanup.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_icmp_enable.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_icmp_info_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_icmp_packet_process.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_icmp_packet_receive.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_icmp_ping.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_icmp_queue_process.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_igmp_enable.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_igmp_info_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_igmp_interface_report_send.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_igmp_loopback_disable.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_igmp_loopback_enable.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_igmp_multicast_check.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_igmp_multicast_interface_join.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_igmp_multicast_join.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_igmp_multicast_leave.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_igmp_packet_process.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_igmp_packet_receive.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_igmp_periodic_processing.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_igmp_queue_process.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_ip_address_change_notify.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_ip_address_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_ip_address_set.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_ip_create.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_ip_deferred_link_status_process.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_ip_delete.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_ip_delete_queue_clear.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_ip_driver_deferred_enable.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_ip_driver_deferred_processing.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_ip_driver_deferred_receive.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_ip_driver_direct_command.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_ip_driver_interface_direct_command.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_ip_driver_link_status_event.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_ip_forward_packet_process.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_ip_forwarding_disable.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_ip_forwarding_enable.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_ip_fragment_assembly.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_ip_fragment_disable.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_ip_fragment_enable.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_ip_fragment_packet.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_ip_fragment_timeout_check.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_ip_gateway_address_set.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_ip_info_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_ip_initialize.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_ip_interface_address_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_ip_interface_address_set.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_ip_interface_attach.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_ip_interface_info_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_ip_interface_status_check.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_ip_link_status_change_notify_set.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_ip_loopback_send.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_ip_packet_deferred_receive.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_ip_packet_receive.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_ip_packet_send.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_ip_periodic_timer_entry.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_ip_raw_packet_cleanup.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_ip_raw_packet_disable.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_ip_raw_packet_enable.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_ip_raw_packet_interface_send.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_ip_raw_packet_processing.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_ip_raw_packet_receive.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_ip_raw_packet_send.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_ip_route_find.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_ip_static_route_add.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_ip_static_route_delete.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_ip_status_check.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_ip_thread_entry.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_packet_allocate.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_packet_copy.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_packet_data_append.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_packet_data_extract_offset.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_packet_data_retrieve.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_packet_length_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_packet_pool_cleanup.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_packet_pool_create.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_packet_pool_delete.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_packet_pool_info_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_packet_pool_initialize.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_packet_release.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_packet_transmit_release.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_ram_network_driver.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_rarp_disable.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_rarp_enable.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_rarp_info_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_rarp_packet_deferred_receive.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_rarp_packet_receive.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_rarp_packet_send.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_rarp_periodic_update.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_rarp_queue_process.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_system_initialize.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_tcp_checksum.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_tcp_cleanup_deferred.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_tcp_client_bind_cleanup.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_tcp_client_socket_bind.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_tcp_client_socket_connect.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_tcp_client_socket_port_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_tcp_client_socket_unbind.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_tcp_connect_cleanup.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_tcp_deferred_cleanup_check.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_tcp_disconnect_cleanup.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_tcp_enable.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_tcp_fast_periodic_processing.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_tcp_fast_periodic_timer_entry.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_tcp_free_port_find.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_tcp_info_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_tcp_initialize.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_tcp_mss_option_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_tcp_no_connection_reset.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_tcp_packet_process.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_tcp_packet_receive.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_tcp_packet_send_ack.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_tcp_packet_send_fin.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_tcp_packet_send_rst.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_tcp_packet_send_syn.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_tcp_periodic_processing.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_tcp_queue_process.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_tcp_receive_cleanup.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_tcp_server_socket_accept.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_tcp_server_socket_listen.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_tcp_server_socket_relisten.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_tcp_server_socket_unaccept.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_tcp_server_socket_unlisten.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_tcp_socket_bytes_available.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_tcp_socket_connection_reset.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_tcp_socket_create.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_tcp_socket_delete.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_tcp_socket_disconnect.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_tcp_socket_disconnect_complete_notify.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_tcp_socket_establish_notify.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_tcp_socket_info_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_tcp_socket_mss_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_tcp_socket_mss_peer_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_tcp_socket_mss_set.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_tcp_socket_packet_process.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_tcp_socket_peer_info_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_tcp_socket_receive.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_tcp_socket_receive_notify.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_tcp_socket_receive_queue_flush.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_tcp_socket_retransmit.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_tcp_socket_send.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_tcp_socket_state_ack_check.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_tcp_socket_state_closing.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_tcp_socket_state_data_check.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_tcp_socket_state_established.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_tcp_socket_state_fin_wait1.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_tcp_socket_state_fin_wait2.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_tcp_socket_state_last_ack.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_tcp_socket_state_syn_received.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_tcp_socket_state_syn_sent.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_tcp_socket_state_transmit_check.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_tcp_socket_state_wait.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_tcp_socket_thread_resume.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_tcp_socket_thread_suspend.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_tcp_socket_timed_wait_callback.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_tcp_socket_transmit_configure.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_tcp_socket_transmit_queue_flush.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_tcp_socket_window_update_notify_set.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_tcp_transmit_cleanup.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_trace_event_insert.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_trace_event_update.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_trace_object_register.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_trace_object_unregister.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_udp_bind_cleanup.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_udp_enable.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_udp_free_port_find.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_udp_info_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_udp_packet_info_extract.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_udp_packet_receive.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_udp_receive_cleanup.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_udp_socket_bind.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_udp_socket_bytes_available.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_udp_socket_checksum_disable.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_udp_socket_checksum_enable.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_udp_socket_create.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_udp_socket_delete.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_udp_socket_info_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_udp_socket_interface_send.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_udp_socket_port_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_udp_socket_receive.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_udp_socket_receive_notify.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_udp_socket_send.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_udp_socket_unbind.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_udp_source_extract.c + ${CMAKE_CURRENT_LIST_DIR}/src/nx_utility.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_arp_dynamic_entries_invalidate.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_arp_dynamic_entry_set.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_arp_enable.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_arp_gratuitous_send.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_arp_hardware_address_find.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_arp_info_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_arp_ip_address_find.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_arp_static_entries_delete.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_arp_static_entry_create.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_arp_static_entry_delete.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_icmp_enable.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_icmp_info_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_icmp_ping.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_igmp_enable.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_igmp_info_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_igmp_loopback_disable.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_igmp_loopback_enable.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_igmp_multicast_interface_join.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_igmp_multicast_join.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_igmp_multicast_leave.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_ip_address_change_notify.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_ip_address_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_ip_address_set.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_ip_create.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_ip_delete.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_ip_driver_direct_command.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_ip_driver_interface_direct_command.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_ip_forwarding_disable.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_ip_forwarding_enable.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_ip_fragment_disable.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_ip_fragment_enable.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_ip_gateway_address_set.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_ip_info_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_ip_interface_address_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_ip_interface_address_set.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_ip_interface_attach.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_ip_interface_info_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_ip_interface_status_check.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_ip_link_status_change_notify_set.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_ip_raw_packet_disable.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_ip_raw_packet_enable.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_ip_raw_packet_interface_send.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_ip_raw_packet_receive.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_ip_raw_packet_send.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_ip_static_route_add.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_ip_static_route_delete.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_ip_status_check.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_packet_allocate.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_packet_copy.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_packet_data_append.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_packet_data_extract_offset.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_packet_data_retrieve.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_packet_length_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_packet_pool_create.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_packet_pool_delete.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_packet_pool_info_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_packet_release.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_packet_transmit_release.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_rarp_disable.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_rarp_enable.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_rarp_info_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_tcp_client_socket_bind.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_tcp_client_socket_connect.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_tcp_client_socket_port_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_tcp_client_socket_unbind.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_tcp_enable.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_tcp_free_port_find.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_tcp_info_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_tcp_server_socket_accept.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_tcp_server_socket_listen.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_tcp_server_socket_relisten.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_tcp_server_socket_unaccept.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_tcp_server_socket_unlisten.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_tcp_socket_bytes_available.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_tcp_socket_create.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_tcp_socket_delete.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_tcp_socket_disconnect.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_tcp_socket_disconnect_complete_notify.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_tcp_socket_establish_notify.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_tcp_socket_info_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_tcp_socket_mss_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_tcp_socket_mss_peer_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_tcp_socket_mss_set.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_tcp_socket_peer_info_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_tcp_socket_receive.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_tcp_socket_receive_notify.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_tcp_socket_send.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_tcp_socket_state_wait.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_tcp_socket_timed_wait_callback.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_tcp_socket_transmit_configure.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_tcp_socket_window_update_notify_set.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_udp_enable.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_udp_free_port_find.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_udp_info_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_udp_packet_info_extract.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_udp_socket_bind.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_udp_socket_bytes_available.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_udp_socket_checksum_disable.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_udp_socket_checksum_enable.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_udp_socket_create.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_udp_socket_delete.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_udp_socket_info_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_udp_socket_interface_send.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_udp_socket_port_get.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_udp_socket_receive.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_udp_socket_receive_notify.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_udp_socket_send.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_udp_socket_unbind.c + ${CMAKE_CURRENT_LIST_DIR}/src/nxe_udp_source_extract.c + + # {{END_TARGET_SOURCES}} +) + +target_include_directories(${PROJECT_NAME} PUBLIC + ${CMAKE_CURRENT_LIST_DIR}/inc +) diff --git a/common/inc/nx_api.h b/common/inc/nx_api.h new file mode 100644 index 0000000..5c2b94e --- /dev/null +++ b/common/inc/nx_api.h @@ -0,0 +1,2370 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Application Interface (API) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* APPLICATION INTERFACE DEFINITION RELEASE */ +/* */ +/* nx_api.h PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file defines the basic Application Interface (API) to the */ +/* high-performance NetX TCP/IP implementation for the ThreadX */ +/* real-time kernel. All service prototypes and data structure */ +/* definitions are defined in this file. Please note that basic data */ +/* type definitions and other architecture-specific information is */ +/* contained in the file nx_port.h. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +#ifndef NX_API_H +#define NX_API_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 + + +/* Disable warning of parameter not used. */ +#ifndef NX_PARAMETER_NOT_USED +#define NX_PARAMETER_NOT_USED(p) ((void)(p)) +#endif /* NX_PARAMETER_NOT_USED */ + + +/* Bypass ThreadX API error checking for internal NetX calls. */ + +#ifdef NX_SOURCE_CODE +#ifndef TX_DISABLE_ERROR_CHECKING +#define TX_DISABLE_ERROR_CHECKING +#endif +#endif + +/* Include the ThreadX and port-specific data type file. */ + +#include "tx_api.h" +#include "nx_port.h" + + +/* Include the ThreadX trace information. */ +#include "tx_trace.h" + +/* Define symbols for compatibility before and after ThreadX 5.8. */ +#if (((THREADX_MAJOR_VERSION << 16) | THREADX_MINOR_VERSION) >= 0x0508) +#define NX_CLEANUP_PARAMETER , ULONG suspension_sequence +#define NX_CLEANUP_ARGUMENT , 0 +#define NX_CLEANUP_EXTENSION NX_PARAMETER_NOT_USED(suspension_sequence); +#else +#define NX_CLEANUP_PARAMETER +#define NX_CLEANUP_ARGUMENT +#define NX_CLEANUP_EXTENSION +#endif /* (((THREADX_MAJOR_VERSION << 16) | THREADX_MINOR_VERSION) >= 0x0508) */ + +/* Define the get system state macro. By default, it simply maps to the variable _tx_thread_system_state. */ +#ifndef TX_THREAD_GET_SYSTEM_STATE +#define TX_THREAD_GET_SYSTEM_STATE() _tx_thread_system_state +#endif + +/* This defines specifies the number of ThreadX timer ticks in one second. The default value is based + on ThreadX timer interrupt. */ + +#ifndef NX_IP_PERIODIC_RATE +#ifdef TX_TIMER_TICKS_PER_SECOND +#define NX_IP_PERIODIC_RATE TX_TIMER_TICKS_PER_SECOND +#else +#define NX_IP_PERIODIC_RATE 100 +#endif +#endif + +#ifndef NX_RAND +#ifdef NX_HIGH_SECURITY +#error "The symbol NX_RAND must be defined to use a qualified random number generator." +#else +#define NX_RAND rand +#endif +#endif + +#ifndef NX_SRAND +#ifdef NX_HIGH_SECURITY +#error "The symbol NX_SRAND must be defined to use a qualified random number seed." +#else +#define NX_SRAND srand +#endif +#endif + +/* Define the max string length. */ +#ifndef NX_MAX_STRING_LENGTH +#define NX_MAX_STRING_LENGTH 1024 +#endif /* NX_MAX_STRING_LENGTH */ + +/* Determine if tracing is enabled. */ + +#ifdef TX_ENABLE_EVENT_TRACE + +/* Define the object types in NetX, if not defined. */ + +#ifndef NX_TRACE_OBJECT_TYPE_IP +#define NX_TRACE_OBJECT_TYPE_IP 11 /* P1 = stack start address, P2 = stack size */ +#define NX_TRACE_OBJECT_TYPE_PACKET_POOL 12 /* P1 = packet size, P2 = number of packets */ +#define NX_TRACE_OBJECT_TYPE_TCP_SOCKET 13 /* P1 = IP address, P2 = window size */ +#define NX_TRACE_OBJECT_TYPE_UDP_SOCKET 14 /* P1 = IP address, P2 = receive queue maximum */ +#endif + + +/* Define event filters that can be used to selectively disable certain events or groups of events. */ + +#define NX_TRACE_ALL_EVENTS 0x00FF8000 /* All NetX events */ +#define NX_TRACE_INTERNAL_EVENTS 0x00008000 /* NetX internal events */ +#define NX_TRACE_ARP_EVENTS 0x00010000 /* NetX ARP events */ +#define NX_TRACE_ICMP_EVENTS 0x00020000 /* NetX ICMP events */ +#define NX_TRACE_IGMP_EVENTS 0x00040000 /* NetX IGMP events */ +#define NX_TRACE_IP_EVENTS 0x00080000 /* NetX IP events */ +#define NX_TRACE_PACKET_EVENTS 0x00100000 /* NetX Packet events */ +#define NX_TRACE_RARP_EVENTS 0x00200000 /* NetX RARP events */ +#define NX_TRACE_TCP_EVENTS 0x00400000 /* NetX TCP events */ +#define NX_TRACE_UDP_EVENTS 0x00800000 /* NetX UDP events */ + + +/* Define the trace events in NetX, if not defined. */ + +/* Define NetX Trace Events, along with a brief description of the additional information fields, + where I1 -> Information Field 1, I2 -> Information Field 2, etc. */ + +/* Define the NetX internal events first. */ + +#ifndef NX_TRACE_INTERNAL_ARP_REQUEST_RECEIVE +#define NX_TRACE_INTERNAL_ARP_REQUEST_RECEIVE 300 /* I1 = ip ptr, I2 = source IP address, I3 = packet ptr */ +#define NX_TRACE_INTERNAL_ARP_REQUEST_SEND 301 /* I1 = ip ptr, I2 = destination IP address, I3 = packet ptr */ +#define NX_TRACE_INTERNAL_ARP_RESPONSE_RECEIVE 302 /* I1 = ip ptr, I2 = source IP address, I3 = packet ptr */ +#define NX_TRACE_INTERNAL_ARP_RESPONSE_SEND 303 /* I1 = ip ptr, I2 = destination IP address, I3 = packet ptr */ +#define NX_TRACE_INTERNAL_ICMP_RECEIVE 304 /* I1 = ip ptr, I2 = source IP address, I3 = packet ptr, I4 = header word 0 */ +#define NX_TRACE_INTERNAL_ICMP_SEND 305 /* I1 = ip ptr, I2 = destination IP address, I3 = packet ptr, I4 = header 0 */ +#define NX_TRACE_INTERNAL_IGMP_RECEIVE 306 /* I1 = ip ptr, I2 = source IP address, I3 = packet ptr, I4 = header word 0 */ + +#define NX_TRACE_INTERNAL_IP_RECEIVE 308 /* I1 = ip ptr, I2 = source IP address, I3 = packet ptr, I4 = packet length */ +#define NX_TRACE_INTERNAL_IP_SEND 309 /* I1 = ip ptr, I2 = destination IP address, I3 = packet ptr, I4 = length */ +#define NX_TRACE_INTERNAL_TCP_DATA_RECEIVE 310 /* I1 = ip ptr, I2 = source IP address, I3 = packet ptr, I4 = sequence */ +#define NX_TRACE_INTERNAL_TCP_DATA_SEND 311 /* I1 = ip ptr, I2 = socket ptr, I3 = packet ptr, I4 = sequence */ +#define NX_TRACE_INTERNAL_TCP_FIN_RECEIVE 312 /* I1 = ip ptr, I2 = socket ptr, I3 = packet ptr, I4 = sequence */ +#define NX_TRACE_INTERNAL_TCP_FIN_SEND 313 /* I1 = ip ptr, I2 = socket ptr, I3 = packet ptr, I4 = sequence */ +#define NX_TRACE_INTERNAL_TCP_RESET_RECEIVE 314 /* I1 = ip ptr, I2 = socket ptr, I3 = packet ptr, I4 = sequence */ +#define NX_TRACE_INTERNAL_TCP_RESET_SEND 315 /* I1 = ip ptr, I2 = socket ptr, I3 = packet ptr, I4 = sequence */ +#define NX_TRACE_INTERNAL_TCP_SYN_RECEIVE 316 /* I1 = ip ptr, I2 = socket ptr, I3 = packet ptr, I4 = sequence */ +#define NX_TRACE_INTERNAL_TCP_SYN_SEND 317 /* I1 = ip ptr, I2 = socket ptr, I3 = packet ptr, I4 = sequence */ +#define NX_TRACE_INTERNAL_UDP_RECEIVE 318 /* I1 = ip ptr, I2 = socket ptr, I3 = packet ptr, I4 = header word 0 */ +#define NX_TRACE_INTERNAL_UDP_SEND 319 /* I1 = ip ptr, I2 = socket_ptr, I3 = packet ptr, I4 = header 0 */ +#define NX_TRACE_INTERNAL_RARP_RECEIVE 320 /* I1 = ip ptr, I2 = target IP address, I3 = packet ptr, I4 = header word 1 */ +#define NX_TRACE_INTERNAL_RARP_SEND 321 /* I1 = ip ptr, I2 = target IP address, I3 = packet ptr, I4 = header word 1 */ +#define NX_TRACE_INTERNAL_TCP_RETRY 322 /* I1 = ip ptr, I2 = socket ptr, I3 = packet ptr, I4 = number of retries */ +#define NX_TRACE_INTERNAL_TCP_STATE_CHANGE 323 /* I1 = ip ptr, I2 = socket ptr, I3 = previous state, I4 = new state */ +#define NX_TRACE_INTERNAL_IO_DRIVER_PACKET_SEND 324 /* I1 = ip ptr, I2 = packet ptr, I3 = packet size */ +#define NX_TRACE_INTERNAL_IO_DRIVER_INITIALIZE 325 /* I1 = ip ptr */ +#define NX_TRACE_INTERNAL_IO_DRIVER_LINK_ENABLE 326 /* I1 = ip ptr */ +#define NX_TRACE_INTERNAL_IO_DRIVER_LINK_DISABLE 327 /* I1 = ip ptr */ +#define NX_TRACE_INTERNAL_IO_DRIVER_PACKET_BROADCAST 328 /* I1 = ip ptr, I2 = packet ptr, I3 = packet size */ +#define NX_TRACE_INTERNAL_IO_DRIVER_ARP_SEND 329 /* I1 = ip ptr, I2 = packet ptr, I3 = packet size */ +#define NX_TRACE_INTERNAL_IO_DRIVER_ARP_RESPONSE_SEND 330 /* I1 = ip ptr, I2 = packet ptr, I3 = packet size */ +#define NX_TRACE_INTERNAL_IO_DRIVER_RARP_SEND 331 /* I1 = ip ptr, I2 = packet ptr, I3 = packet size */ +#define NX_TRACE_INTERNAL_IO_DRIVER_MULTICAST_JOIN 332 /* I1 = ip ptr */ +#define NX_TRACE_INTERNAL_IO_DRIVER_MULTICAST_LEAVE 333 /* I1 = ip ptr */ +#define NX_TRACE_INTERNAL_IO_DRIVER_GET_STATUS 334 /* I1 = ip ptr */ +#define NX_TRACE_INTERNAL_IO_DRIVER_GET_SPEED 335 /* I1 = ip ptr */ +#define NX_TRACE_INTERNAL_IO_DRIVER_GET_DUPLEX_TYPE 336 /* I1 = ip ptr */ +#define NX_TRACE_INTERNAL_IO_DRIVER_GET_ERROR_COUNT 337 /* I1 = ip ptr */ +#define NX_TRACE_INTERNAL_IO_DRIVER_GET_RX_COUNT 338 /* I1 = ip ptr */ +#define NX_TRACE_INTERNAL_IO_DRIVER_GET_TX_COUNT 339 /* I1 = ip ptr */ +#define NX_TRACE_INTERNAL_IO_DRIVER_GET_ALLOC_ERRORS 340 /* I1 = ip ptr */ +#define NX_TRACE_INTERNAL_IO_DRIVER_UNINITIALIZE 341 /* I1 = ip ptr */ +#define NX_TRACE_INTERNAL_IO_DRIVER_DEFERRED_PROCESSING 342 /* I1 = ip ptr, I2 = packet ptr, I3 = packet size */ + +#define NX_TRACE_ARP_DYNAMIC_ENTRIES_INVALIDATE 350 /* I1 = ip ptr, I2 = entries invalidated */ +#define NX_TRACE_ARP_DYNAMIC_ENTRY_SET 351 /* I1 = ip ptr, I2 = ip address, I3 = physical msw, I4 = physical lsw */ +#define NX_TRACE_ARP_ENABLE 352 /* I1 = ip ptr, I2 = arp cache memory, I3 = arp cache size */ +#define NX_TRACE_ARP_GRATUITOUS_SEND 353 /* I1 = ip ptr */ +#define NX_TRACE_ARP_HARDWARE_ADDRESS_FIND 354 /* I1 = ip ptr, I2 = ip_address, I3 = physical msw, I4 = physical lsw */ +#define NX_TRACE_ARP_INFO_GET 355 /* I1 = ip ptr, I2 = arps sent, I3 = arp responses, I3 = arps received */ +#define NX_TRACE_ARP_IP_ADDRESS_FIND 356 /* I1 = ip ptr, I2 = ip address, I3 = physical msw, I4 = physical lsw */ +#define NX_TRACE_ARP_STATIC_ENTRIES_DELETE 357 /* I1 = ip ptr, I2 = entries deleted */ +#define NX_TRACE_ARP_STATIC_ENTRY_CREATE 358 /* I1 = ip ptr, I2 = ip address, I3 = physical msw, I4 = physical_lsw */ +#define NX_TRACE_ARP_STATIC_ENTRY_DELETE 359 /* I1 = ip ptr, I2 = ip address, I3 = physical_msw, I4 = physical_lsw */ +#define NX_TRACE_ICMP_ENABLE 360 /* I1 = ip ptr */ +#define NX_TRACE_ICMP_INFO_GET 361 /* I1 = ip ptr, I2 = pings sent, I3 = ping responses, I4 = pings received */ +#define NX_TRACE_ICMP_PING 362 /* I1 = ip ptr, I2 = ip_address, I3 = data ptr, I4 = data size */ +#define NX_TRACE_IGMP_ENABLE 363 /* I1 = ip ptr */ +#define NX_TRACE_IGMP_INFO_GET 364 /* I1 = ip ptr, I2 = reports sent, I3 = queries received, I4 = groups joined*/ +#define NX_TRACE_IGMP_LOOPBACK_DISABLE 365 /* I1 = ip ptr */ +#define NX_TRACE_IGMP_LOOPBACK_ENABLE 366 /* I1 = ip ptr */ +#define NX_TRACE_IGMP_MULTICAST_JOIN 367 /* I1 = ip ptr, I2 = group address, I3=interface index */ +#define NX_TRACE_IGMP_MULTICAST_LEAVE 368 /* I1 = ip ptr, I2 = group_address */ +#define NX_TRACE_IP_ADDRESS_CHANGE_NOTIFY 369 /* I1 = ip ptr, I2 = ip address change notify, I3 = additional info */ +#define NX_TRACE_IP_ADDRESS_GET 370 /* I1 = ip ptr, I2 = ip address, I3 = network_mask */ +#define NX_TRACE_IP_ADDRESS_SET 371 /* I1 = ip ptr, I2 = ip address, I3 = network_mask */ +#define NX_TRACE_IP_CREATE 372 /* I1 = ip ptr, I2 = ip address, I3 = network mask, I4 = default_pool */ +#define NX_TRACE_IP_DELETE 373 /* I1 = ip ptr */ +#define NX_TRACE_IP_DRIVER_DIRECT_COMMAND 374 /* I1 = ip ptr, I2 = command, I3 = return value */ +#define NX_TRACE_IP_FORWARDING_DISABLE 375 /* I1 = ip ptr */ +#define NX_TRACE_IP_FORWARDING_ENABLE 376 /* I1 = ip ptr */ +#define NX_TRACE_IP_FRAGMENT_DISABLE 377 /* I1 = ip ptr */ +#define NX_TRACE_IP_FRAGMENT_ENABLE 378 /* I1 = ip ptr */ +#define NX_TRACE_IP_GATEWAY_ADDRESS_SET 379 /* I1 = ip ptr, I2 = gateway address */ +#define NX_TRACE_IP_INFO_GET 380 /* I1 = ip ptr, I2 = bytes sent, I3 = bytes received, I4 = packets dropped */ +#define NX_TRACE_IP_RAW_PACKET_DISABLE 381 /* I1 = ip ptr */ +#define NX_TRACE_IP_RAW_PACKET_ENABLE 382 /* I1 = ip ptr */ +#define NX_TRACE_IP_RAW_PACKET_RECEIVE 383 /* I1 = ip ptr, I2 = packet ptr, I3 = wait option */ +#define NX_TRACE_IP_RAW_PACKET_SEND 384 /* I1 = ip ptr, I2 = packet ptr, I3 = destination ip, I4 = type of service */ +#define NX_TRACE_IP_STATUS_CHECK 385 /* I1 = ip ptr, I2 = needed status, I3 = actual status, I4 = wait option */ +#define NX_TRACE_PACKET_ALLOCATE 386 /* I1 = pool ptr, I2 = packet ptr, I3 = packet type, I4 = available packets */ +#define NX_TRACE_PACKET_COPY 387 /* I1 = packet ptr, I2 = new packet ptr, I3 = pool ptr, I4 = wait option */ +#define NX_TRACE_PACKET_DATA_APPEND 388 /* I1 = packet ptr, I2 = data start, I3 = data size, I4 = pool ptr */ +#define NX_TRACE_PACKET_DATA_RETRIEVE 389 /* I1 = packet ptr, I2 = buffer start, I3 = bytes copied */ +#define NX_TRACE_PACKET_LENGTH_GET 390 /* I1 = packet ptr, I2 = length */ +#define NX_TRACE_PACKET_POOL_CREATE 391 /* I1 = pool ptr, I2 = payload size, I3 = memory ptr, I4 = memory_size */ +#define NX_TRACE_PACKET_POOL_DELETE 392 /* I1 = pool ptr */ +#define NX_TRACE_PACKET_POOL_INFO_GET 393 /* I1 = pool ptr, I2 = total_packets, I3 = free packets, I4 = empty requests*/ +#define NX_TRACE_PACKET_RELEASE 394 /* I1 = packet ptr, I2 = packet status, I3 = available packets */ +#define NX_TRACE_PACKET_TRANSMIT_RELEASE 395 /* I1 = packet ptr, I2 = packet status, I3 = available packets */ +#define NX_TRACE_RARP_DISABLE 396 /* I1 = ip ptr */ +#define NX_TRACE_RARP_ENABLE 397 /* I1 = ip ptr */ +#define NX_TRACE_RARP_INFO_GET 398 /* I1 = ip ptr, I2 = requests sent, I3 = responses received, I4 = invalids */ +#define NX_TRACE_SYSTEM_INITIALIZE 399 /* none */ +#define NX_TRACE_TCP_CLIENT_SOCKET_BIND 400 /* I1 = ip ptr, I2 = socket ptr, I3 = port, I4 = wait option */ +#define NX_TRACE_TCP_CLIENT_SOCKET_CONNECT 401 /* I1 = ip ptr, I2 = socket ptr, I3 = server ip, I4 = server port */ +#define NX_TRACE_TCP_CLIENT_SOCKET_PORT_GET 402 /* I1 = ip ptr, I2 = socket ptr, I3 = port */ +#define NX_TRACE_TCP_CLIENT_SOCKET_UNBIND 403 /* I1 = ip ptr, I2 = socket ptr */ +#define NX_TRACE_TCP_ENABLE 404 /* I1 = ip ptr */ +#define NX_TRACE_TCP_FREE_PORT_FIND 405 /* I1 = ip ptr, I2 = port, I3 = free port */ +#define NX_TRACE_TCP_INFO_GET 406 /* I1 = ip ptr, I2 = bytes sent, I3 = bytes received, I4 = invalid packets */ +#define NX_TRACE_TCP_SERVER_SOCKET_ACCEPT 407 /* I1 = ip ptr, I2 = socket ptr, I3 = wait option, I4 = socket state */ +#define NX_TRACE_TCP_SERVER_SOCKET_LISTEN 408 /* I1 = ip ptr, I2 = port, I3 = socket ptr, I4 = listen queue size */ +#define NX_TRACE_TCP_SERVER_SOCKET_RELISTEN 409 /* I1 = ip ptr, I2 = port, I3 = socket ptr, I4 = socket state */ +#define NX_TRACE_TCP_SERVER_SOCKET_UNACCEPT 410 /* I1 = ip ptr, I2 = socket ptr, I3 = socket state */ +#define NX_TRACE_TCP_SERVER_SOCKET_UNLISTEN 411 /* I1 = ip ptr, I2 = port */ +#define NX_TRACE_TCP_SOCKET_CREATE 412 /* I1 = ip ptr, I2 = socket ptr, I3 = type of service, I4 = window size */ +#define NX_TRACE_TCP_SOCKET_DELETE 413 /* I1 = ip ptr, I2 = socket ptr, I3 = socket state */ +#define NX_TRACE_TCP_SOCKET_DISCONNECT 414 /* I1 = ip ptr, I2 = socket ptr, I3 = wait option, I4 = socket state */ +#define NX_TRACE_TCP_SOCKET_INFO_GET 415 /* I1 = ip ptr, I2 = socket ptr, I3 = bytes sent, I4 = bytes received */ +#define NX_TRACE_TCP_SOCKET_MSS_GET 416 /* I1 = ip ptr, I2 = socket ptr, I3 = mss, I4 = socket state */ +#define NX_TRACE_TCP_SOCKET_MSS_PEER_GET 417 /* I1 = ip ptr, I2 = socket ptr, I3 = peer_mss, I4 = socket state */ +#define NX_TRACE_TCP_SOCKET_MSS_SET 418 /* I1 = ip ptr, I2 = socket ptr, I3 = mss, I4 socket state */ +#define NX_TRACE_TCP_SOCKET_RECEIVE 419 /* I1 = socket ptr, I2 = packet ptr, I3 = length, I4 = rx sequence */ +#define NX_TRACE_TCP_SOCKET_RECEIVE_NOTIFY 420 /* I1 = ip ptr, I2 = socket ptr, I3 = receive notify */ +#define NX_TRACE_TCP_SOCKET_SEND 421 /* I1 = socket ptr, I2 = packet ptr, I3 = length, I4 = tx sequence */ +#define NX_TRACE_TCP_SOCKET_STATE_WAIT 422 /* I1 = ip ptr, I2 = socket ptr, I3 = desired state, I4 = previous state */ +#define NX_TRACE_TCP_SOCKET_TRANSMIT_CONFIGURE 423 /* I1 = ip ptr, I2 = socket ptr, I3 = queue depth, I4 = timeout */ +#define NX_TRACE_UDP_ENABLE 424 /* I1 = ip ptr */ +#define NX_TRACE_UDP_FREE_PORT_FIND 425 /* I1 = ip ptr, I2 = port, I3 = free port */ +#define NX_TRACE_UDP_INFO_GET 426 /* I1 = ip ptr, I2 = bytes sent, I3 = bytes received, I4 = invalid packets */ +#define NX_TRACE_UDP_SOCKET_BIND 427 /* I1 = ip ptr, I2 = socket ptr, I3 = port, I4 = wait option */ +#define NX_TRACE_UDP_SOCKET_CHECKSUM_DISABLE 428 /* I1 = ip ptr, I2 = socket ptr */ +#define NX_TRACE_UDP_SOCKET_CHECKSUM_ENABLE 429 /* I1 = ip ptr, I2 = socket ptr */ +#define NX_TRACE_UDP_SOCKET_CREATE 430 /* I1 = ip ptr, I2 = socket ptr, I3 = type of service, I4 = queue maximum */ +#define NX_TRACE_UDP_SOCKET_DELETE 431 /* I1 = ip ptr, I2 = socket ptr */ +#define NX_TRACE_UDP_SOCKET_INFO_GET 432 /* I1 = ip ptr, I2 = socket ptr, I3 = bytes sent, I4 = bytes received */ +#define NX_TRACE_UDP_SOCKET_PORT_GET 433 /* I1 = ip ptr, I2 = socket ptr, I3 = port */ +#define NX_TRACE_UDP_SOCKET_RECEIVE 434 /* I1 = ip ptr, I2 = socket ptr, I3 = packet ptr, I4 = packet size */ +#define NX_TRACE_UDP_SOCKET_RECEIVE_NOTIFY 435 /* I1 = ip ptr, I2 = socket ptr, I3 = receive notify */ +#define NX_TRACE_UDP_SOCKET_SEND 436 /* I1 = socket ptr, I2 = packet ptr, I3 = packet size, I4 = ip address */ +#define NX_TRACE_UDP_SOCKET_UNBIND 437 /* I1 = ip ptr, I2 = socket ptr, I3 = port */ +#define NX_TRACE_UDP_SOURCE_EXTRACT 438 /* I1 = packet ptr, I2 = ip address, I3 = port */ +#define NX_TRACE_IP_INTERFACE_ATTACH 439 /* I1 = ip ptr, I2 = ip address, I3 = interface index */ +#define NX_TRACE_UDP_SOCKET_BYTES_AVAILABLE 440 /* I1 = ip ptr, I2 = socket ptr, I3 = bytes available */ +#define NX_TRACE_IP_STATIC_ROUTE_ADD 441 /* I1 = ip_ptr, I2 = network_address, I3 = net_mask, I4 = next_hop */ +#define NX_TRACE_IP_STATIC_ROUTE_DELETE 442 /* I1 = ip_ptr, I2 = network_address, I3 = net_mask */ +#define NX_TRACE_TCP_SOCKET_PEER_INFO_GET 443 /* I1 = socket ptr, I2 = network_address, I3 = port */ +#define NX_TRACE_TCP_SOCKET_WINDOW_UPDATE_NOTIFY_SET 444 /* I1 = socket ptr, */ +#define NX_TRACE_UDP_SOCKET_INTERFACE_SET 445 /* I1 = socket_ptr, I2 = interface_index, */ +#define NX_TRACE_IP_INTERFACE_INFO_GET 446 /* I1 = ip_ptr, I2 = ip_address, I3 = physical address msw, I4 = physical address lsw */ +#define NX_TRACE_PACKET_DATA_EXTRACT_OFFSET 447 /* I1 = packet_ptr, I2 = buffer_length, I3 = bytes_copied, */ +#define NX_TRACE_TCP_SOCKET_BYTES_AVAILABLE 448 /* I1 = ip ptr, I2 = socket ptr, I3 = bytes available */ + +#endif + + +/* Map the trace macros to internal NetX versions so we can get interrupt protection. */ + +#ifdef NX_SOURCE_CODE + +#define NX_TRACE_OBJECT_REGISTER(t, p, n, a, b) _nx_trace_object_register(t, (VOID *)p, (CHAR *)n, (ULONG)a, (ULONG)b); +#define NX_TRACE_OBJECT_UNREGISTER(o) _nx_trace_object_unregister((VOID *)o); +#define NX_TRACE_IN_LINE_INSERT(i, a, b, c, d, f, g, h) _nx_trace_event_insert((ULONG)i, (ULONG)a, (ULONG)b, (ULONG)c, (ULONG)d, (ULONG)f, g, h); +#define NX_TRACE_EVENT_UPDATE(e, t, i, a, b, c, d) _nx_trace_event_update((TX_TRACE_BUFFER_ENTRY *)e, (ULONG)t, (ULONG)i, (ULONG)a, (ULONG)b, (ULONG)c, (ULONG)d); + +/* Define NetX trace prototypes. */ + +VOID _nx_trace_object_register(UCHAR object_type, VOID *object_ptr, CHAR *object_name, ULONG parameter_1, ULONG parameter_2); +VOID _nx_trace_object_unregister(VOID *object_ptr); +VOID _nx_trace_event_insert(ULONG event_id, ULONG info_field_1, ULONG info_field_2, ULONG info_field_3, ULONG info_field_4, ULONG filter, TX_TRACE_BUFFER_ENTRY **current_event, ULONG *current_timestamp); +VOID _nx_trace_event_update(TX_TRACE_BUFFER_ENTRY *event, ULONG timestamp, ULONG event_id, ULONG info_field_1, ULONG info_field_2, ULONG info_field_3, ULONG info_field_4); +#endif + +#else +#define NX_TRACE_OBJECT_REGISTER(t, p, n, a, b) +#define NX_TRACE_OBJECT_UNREGISTER(o) +#define NX_TRACE_IN_LINE_INSERT(i, a, b, c, d, f, g, h) +#define NX_TRACE_EVENT_UPDATE(e, t, i, a, b, c, d) +#endif + + +/* If NX_PACKET_HEADER_PAD is defined, make sure NX_PACKET_HEADER_PAD_SIZE is also defined. The default is 1, for backward compatibility. */ + +#ifdef NX_PACKET_HEADER_PAD +#ifndef NX_PACKET_HEADER_PAD_SIZE +#define NX_PACKET_HEADER_PAD_SIZE 1 +#endif /* NX_PACKET_HEADER_PAD_SIZE */ +#endif /* NX_PACKET_HEADER_PAD */ + +/* Define basic constants for the NetX TCP/IP Stack. */ +#define EL_PRODUCT_NETX +#define NETX_MAJOR_VERSION 6 +#define NETX_MINOR_VERSION 0 + +/* The following symbols are defined for backward compatibility reasons.*/ +#define __PRODUCT_NETX__ +#define __NETX_MAJOR_VERSION__ NETX_MAJOR_VERSION +#define __NETX_MINOR_VERSION__ NETX_MINOR_VERSION + + +/* API input parameters and general constants. */ + +#define NX_NO_WAIT 0 +#define NX_WAIT_FOREVER ((ULONG)0xFFFFFFFF) +#define NX_TRUE 1 +#define NX_FALSE 0 +#define NX_NULL 0 +#define NX_FOREVER 1 +#define NX_INIT_PACKET_ID 1 +#ifndef NX_MAX_PORT +#define NX_MAX_PORT 0xFFFF +#endif /* NX_MAX_PORT */ +#define NX_LOWER_16_MASK ((ULONG)0x0000FFFF) +#define NX_CARRY_BIT ((ULONG)0x10000) +#define NX_SHIFT_BY_16 16 +#define NX_TCP_CLIENT 1 +#define NX_TCP_SERVER 2 +#define NX_ANY_PORT 0 +#ifndef NX_SEARCH_PORT_START +#define NX_SEARCH_PORT_START 0xC000 /* Free port search start UDP/TCP */ +#endif /* NX_SEARCH_PORT_START */ + +#ifndef NX_PHYSICAL_HEADER +#define NX_PHYSICAL_HEADER 16 /* Maximum physical header */ +#endif + +#ifndef NX_PHYSICAL_TRAILER +#define NX_PHYSICAL_TRAILER 4 /* Maximum physical trailer */ +#endif + +#define NX_IP_PACKET (NX_PHYSICAL_HEADER + 20) /* 20 bytes of IP header */ +#define NX_UDP_PACKET (NX_IP_PACKET + 8) /* IP header plus 8 bytes */ +#define NX_TCP_PACKET (NX_IP_PACKET + 20) /* IP header plus 20 bytes */ +#define NX_ICMP_PACKET NX_IP_PACKET /* IP header */ +#define NX_IGMP_PACKET NX_IP_PACKET /* IP header */ +#define NX_RECEIVE_PACKET 0 /* This is for driver receive */ + /* packets. */ + + +/* Define the ARP update rate, in terms of IP periodic intervals. This can be defined on the + command line as well. */ + +#ifndef NX_ARP_UPDATE_RATE +#define NX_ARP_UPDATE_RATE 10 +#endif + + +/* Define the ARP entry expiration rate, in terms of IP periodic intervals. This can be defined on the + command line as well. A value of 0 disables ARP entry expiration, and is the default. */ + +#ifndef NX_ARP_EXPIRATION_RATE +#define NX_ARP_EXPIRATION_RATE 0 +#endif + + +/* Define the ARP maximum retry constant that specifies the maximum number of ARP requests that will be sent + without receiving an ARP response. Once this limit is reached, the ARP attempt is abandoned and + any queued packet is released. */ + +#ifndef NX_ARP_MAXIMUM_RETRIES +#define NX_ARP_MAXIMUM_RETRIES 18 +#endif + + +/* Define the maximum number of packets that can be queued while waiting for ARP resolution of an + IP address. */ + +#ifndef NX_ARP_MAX_QUEUE_DEPTH +#define NX_ARP_MAX_QUEUE_DEPTH 4 +#endif + + +#ifndef NX_IP_ROUTING_TABLE_SIZE +#define NX_IP_ROUTING_TABLE_SIZE 8 +#endif /* NX_IP_ROUTING_TABLE_SIZE */ + + +#ifdef NX_ENABLE_EXTENDED_NOTIFY_SUPPORT +#ifdef NX_DISABLE_EXTENDED_NOTIFY_SUPPORT +#undef NX_DISABLE_EXTENDED_NOTIFY_SUPPORT +#endif /* NX_ENABLE_EXTENDED_NOTIFY_SUPPORT */ +#else +#define NX_DISABLE_EXTENDED_NOTIFY_SUPPORT +#endif /* !NX_ENABLE_EXTENDED_NOTIFY_SUPPORT */ + + +/* For backward compatibility, convert map NX_ARP_MAC_CHANGE_NOTIFICATION_ENABLE to NX_ENABLE_ARP_MAC_CHANGE_NOTIFICATION */ +#ifdef NX_ARP_MAC_CHANGE_NOTIFICATION_ENABLE +#ifndef NX_ENABLE_ARP_MAC_CHANGE_NOTIFICATION +#define NX_ENABLE_ARP_MAC_CHANGE_NOTIFICATION +#endif /* NX_ENABLE_ARP_MAC_CHANGE_NOTIFICATION */ +#endif /* NX_ARP_MAC_CHANGE_NOTIFICATION_ENABLE */ + + +/* For backward compatibility, convert map NX_ARP_DISABLE_AUTO_ARP_ENTRY to NX_DISABLE_ARP_AUTO_ENTRY */ +#ifdef NX_ARP_DISABLE_AUTO_ARP_ENTRY +#ifndef NX_DISABLE_ARP_AUTO_ENTRY +#define NX_DISABLE_ARP_AUTO_ENTRY +#endif /* NX_DISABLE_ARP_AUTO_ENTRY */ +#endif /* NX_ARP_DISABLE_AUTO_ARP_ENTRY */ + + +/* For backward compatibility, convert map NX_TCP_ENABLE_KEEPALIVE to NX_ENABLE_TCP_KEEPALIVE */ +#ifdef NX_TCP_ENABLE_KEEPALIVE +#ifndef NX_ENABLE_TCP_KEEPALIVE +#define NX_ENABLE_TCP_KEEPALIVE +#endif /* NX_ENABLE_TCP_KEEPALIVE */ +#endif /* NX_TCP_ENABLE_KEEPALIVE */ + + +/* For backward compatibility, convert map NX_TCP_ENABLE_WINDOW_SCALING to NX_ENABLE_TCP_WINDOW_SCALING */ +#ifdef NX_TCP_ENABLE_WINDOW_SCALING +#ifndef NX_ENABLE_TCP_WINDOW_SCALING +#define NX_ENABLE_TCP_WINDOW_SCALING +#endif /* NX_ENABLE_TCP_WINDOW_SCALING */ +#endif /* NX_TCP_ENABLE_WINDOW_SCALING */ + + +/* For backward compatibility, convert map NX_TCP_MSS_CHECKING_ENABLED to NX_ENABLE_TCP_MSS_CHECKING */ +#ifdef NX_TCP_MSS_CHECKING_ENABLED +#ifndef NX_ENABLE_TCP_MSS_CHECKING +#define NX_ENABLE_TCP_MSS_CHECKING +#endif /* NX_ENABLE_TCP_MSS_CHECKING */ +#endif /* NX_TCP_MSS_CHECKING_ENABLED */ + + +/* Define the IP fragment options. */ + +#define NX_FRAGMENT_OKAY ((ULONG)0x00000000) +#define NX_DONT_FRAGMENT ((ULONG)0x00004000) +#define NX_MORE_FRAGMENTS ((ULONG)0x00002000) +#define NX_FRAG_OFFSET_MASK ((ULONG)0x00001FFF) + + +/* Define the IP Type Of Service constants. These will be supplied to the + IP output packet routine. */ + +#define NX_IP_NORMAL ((ULONG)0x00000000) /* Normal IP delivery */ +#define NX_IP_MIN_DELAY ((ULONG)0x00100000) /* Minimum Delay delivery */ +#define NX_IP_MAX_DATA ((ULONG)0x00080000) /* Maximum Throughput delivery */ +#define NX_IP_MAX_RELIABLE ((ULONG)0x00040000) /* Maximum Reliable delivery */ +#define NX_IP_MIN_COST ((ULONG)0x00020000) /* Minimum Cost deliver */ +#define NX_IP_TOS_MASK ((ULONG)0x00FF0000) /* Type of Service Mask */ + + +/* Define the IP length mask. */ + +#define NX_IP_PACKET_SIZE_MASK ((ULONG)0x0000FFFF) /* Mask for isolating the IP packet length */ + + +/* Define the default time to live. */ + +#define NX_IP_TIME_TO_LIVE ((ULONG)0x00000080) /* Default packet time to live */ +#define NX_IP_TIME_TO_LIVE_MASK ((ULONG)0xFF000000) /* Mask for isolating the time to live */ +#define NX_IP_TIME_TO_LIVE_SHIFT 24 /* Number of bits to shift left */ + + +/* Define the type of Protocol in this IP packet. */ + +#define NX_IP_ICMP ((ULONG)0x00010000) /* ICMP Protocol Type */ +#define NX_IP_IGMP ((ULONG)0x00020000) /* IGMP Protocol Type */ +#define NX_IP_TCP ((ULONG)0x00060000) /* TCP Protocol Type */ +#define NX_IP_UDP ((ULONG)0x00110000) /* UDP Protocol Type */ +#define NX_IP_PROTOCOL_MASK ((ULONG)0x00FF0000) /* Protocol Type mask */ + + +/* Define IP address type masks and values. These will determine the net id and + host id fields of the supplied IP address. */ + +#define NX_IP_CLASS_A_MASK ((ULONG)0x80000000) /* Define mask for class A IP addresses */ +#define NX_IP_CLASS_A_TYPE ((ULONG)0x00000000) /* Define class A address type */ +#define NX_IP_CLASS_A_NETID ((ULONG)0x7F000000) /* Define class A network ID mask */ +#define NX_IP_CLASS_A_HOSTID ((ULONG)0x00FFFFFF) /* Define class A host ID mask */ + +#define NX_IP_CLASS_B_MASK ((ULONG)0xC0000000) /* Define mask for class B IP addresses */ +#define NX_IP_CLASS_B_TYPE ((ULONG)0x80000000) /* Define class B address type */ +#define NX_IP_CLASS_B_NETID ((ULONG)0x3FFF0000) /* Define class B network ID mask */ +#define NX_IP_CLASS_B_HOSTID ((ULONG)0x0000FFFF) /* Define class B host ID mask */ + +#define NX_IP_CLASS_C_MASK ((ULONG)0xE0000000) /* Define mask for class A IP addresses */ +#define NX_IP_CLASS_C_TYPE ((ULONG)0xC0000000) /* Define class A address type */ +#define NX_IP_CLASS_C_NETID ((ULONG)0x1FFFFF00) /* Define class A network ID mask */ +#define NX_IP_CLASS_C_HOSTID ((ULONG)0x000000FF) /* Define class A host ID mask */ + +#define NX_IP_CLASS_D_MASK ((ULONG)0xF0000000) /* Define mask for class D IP addresses */ +#define NX_IP_CLASS_D_TYPE ((ULONG)0xE0000000) /* Define class D address type */ +#define NX_IP_CLASS_D_GROUP ((ULONG)0x0FFFFFFF) /* Define class D group ID mask */ +#define NX_IP_CLASS_D_HOSTID ((ULONG)0x00000000) /* Define class D host ID mask N/A */ + +#define NX_IP_LIMITED_BROADCAST ((ULONG)0xFFFFFFFF) /* Limited broadcast address (local net) */ +#define NX_IP_LOOPBACK_FIRST ((ULONG)0x7F000000) /* First loopback address 127.0.0.0 */ +#define NX_IP_LOOPBACK_LAST ((ULONG)0x7FFFFFFF) /* Last loopback address 127.255.255.255 */ + +#define NX_IP_MULTICAST_UPPER ((ULONG)0x00000100) /* Upper two bytes of multicast Ethernet */ +#define NX_IP_MULTICAST_LOWER ((ULONG)0x5E000000) /* Lower 23 bits of address are from IP */ +#define NX_IP_MULTICAST_MASK ((ULONG)0x007FFFFF) /* Mask to pickup the lower 23 bits of IP */ + + +/* Define the constants that determine how big the hash table is for destination IP + addresses. The value must be a power of two, so subtracting one gives us + the mask. */ + +#define NX_ROUTE_TABLE_SIZE 32 +#define NX_ROUTE_TABLE_MASK (NX_ROUTE_TABLE_SIZE - 1) + + +/* By default use 0xFF when sending raw packet. */ +#ifndef NX_IP_RAW +#define NX_IP_RAW 0x00FF0000 +#endif /* NX_IP_RAW */ + +/* Define the constants that determine how big the hash table is for UDP ports. The + value must be a power of two, so subtracting one gives us the mask. */ + +#define NX_UDP_PORT_TABLE_SIZE 32 +#define NX_UDP_PORT_TABLE_MASK (NX_UDP_PORT_TABLE_SIZE - 1) + + +/* Define the constants that determine how big the hash table is for TCP ports. The + value must be a power of two, so subtracting one gives us the mask. */ + +#define NX_TCP_PORT_TABLE_SIZE 32 +#define NX_TCP_PORT_TABLE_MASK (NX_TCP_PORT_TABLE_SIZE - 1) + + +/* Define the maximum number of multicast groups the system can support. This might + be further limited by the underlying physical hardware. */ + +#ifndef NX_MAX_MULTICAST_GROUPS +#define NX_MAX_MULTICAST_GROUPS 7 +#endif + + +/* Define the maximum number of internal server resources for TCP connections. Server + connections require a listen control structure. */ + +#ifndef NX_MAX_LISTEN_REQUESTS +#define NX_MAX_LISTEN_REQUESTS 10 +#endif + + +/* Define the IP status checking/return bits. */ + +#define NX_IP_INITIALIZE_DONE 0x0001 +#define NX_IP_ADDRESS_RESOLVED 0x0002 +#define NX_IP_LINK_ENABLED 0x0004 +#define NX_IP_ARP_ENABLED 0x0008 +#define NX_IP_UDP_ENABLED 0x0010 +#define NX_IP_TCP_ENABLED 0x0020 +#define NX_IP_IGMP_ENABLED 0x0040 +#define NX_IP_RARP_COMPLETE 0x0080 +#define NX_IP_INTERFACE_LINK_ENABLED 0x0100 + + +/* Define various states in the TCP connection state machine. */ + +#define NX_TCP_CLOSED 1 /* Connection is closed state */ +#define NX_TCP_LISTEN_STATE 2 /* Server listen state */ +#define NX_TCP_SYN_SENT 3 /* SYN sent state */ +#define NX_TCP_SYN_RECEIVED 4 /* SYN received state */ +#define NX_TCP_ESTABLISHED 5 /* Connection established state */ +#define NX_TCP_CLOSE_WAIT 6 /* Close Wait state */ +#define NX_TCP_FIN_WAIT_1 7 /* Finished Wait 1 state */ +#define NX_TCP_FIN_WAIT_2 8 /* Finished Wait 2 state */ +#define NX_TCP_CLOSING 9 /* Closing state */ +#define NX_TCP_TIMED_WAIT 10 /* Timed wait state */ +#define NX_TCP_LAST_ACK 11 /* Last ACK state */ + + +/* API return values. */ + +#define NX_SUCCESS 0x00 +#define NX_NO_PACKET 0x01 +#define NX_UNDERFLOW 0x02 +#define NX_OVERFLOW 0x03 +#define NX_NO_MAPPING 0x04 +#define NX_DELETED 0x05 +#define NX_POOL_ERROR 0x06 +#define NX_PTR_ERROR 0x07 +#define NX_WAIT_ERROR 0x08 +#define NX_SIZE_ERROR 0x09 +#define NX_OPTION_ERROR 0x0a +#define NX_DELETE_ERROR 0x10 +#define NX_CALLER_ERROR 0x11 +#define NX_INVALID_PACKET 0x12 +#define NX_INVALID_SOCKET 0x13 +#define NX_NOT_ENABLED 0x14 +#define NX_ALREADY_ENABLED 0x15 +#define NX_ENTRY_NOT_FOUND 0x16 +#define NX_NO_MORE_ENTRIES 0x17 +#define NX_ARP_TIMER_ERROR 0x18 +#define NX_RESERVED_CODE0 0x19 +#define NX_WAIT_ABORTED 0x1A +#define NX_IP_INTERNAL_ERROR 0x20 +#define NX_IP_ADDRESS_ERROR 0x21 +#define NX_ALREADY_BOUND 0x22 +#define NX_PORT_UNAVAILABLE 0x23 +#define NX_NOT_BOUND 0x24 +#define NX_RESERVED_CODE1 0x25 +#define NX_SOCKET_UNBOUND 0x26 +#define NX_NOT_CREATED 0x27 +#define NX_SOCKETS_BOUND 0x28 +#define NX_NO_RESPONSE 0x29 +#define NX_POOL_DELETED 0x30 +#define NX_ALREADY_RELEASED 0x31 +#define NX_RESERVED_CODE2 0x32 +#define NX_MAX_LISTEN 0x33 +#define NX_DUPLICATE_LISTEN 0x34 +#define NX_NOT_CLOSED 0x35 +#define NX_NOT_LISTEN_STATE 0x36 +#define NX_IN_PROGRESS 0x37 +#define NX_NOT_CONNECTED 0x38 +#define NX_WINDOW_OVERFLOW 0x39 +#define NX_ALREADY_SUSPENDED 0x40 +#define NX_DISCONNECT_FAILED 0x41 +#define NX_STILL_BOUND 0x42 +#define NX_NOT_SUCCESSFUL 0x43 +#define NX_UNHANDLED_COMMAND 0x44 +#define NX_NO_FREE_PORTS 0x45 +#define NX_INVALID_PORT 0x46 +#define NX_INVALID_RELISTEN 0x47 +#define NX_CONNECTION_PENDING 0x48 +#define NX_TX_QUEUE_DEPTH 0x49 +#define NX_NOT_IMPLEMENTED 0x4A +#define NX_NOT_SUPPORTED 0x4B +#define NX_INVALID_INTERFACE 0x4C +#define NX_INVALID_PARAMETERS 0x4D +#define NX_NOT_FOUND 0x4E +#define NX_CANNOT_START 0x4F +#define NX_NO_INTERFACE_ADDRESS 0x50 +#define NX_INVALID_MTU_DATA 0x51 +#define NX_DUPLICATED_ENTRY 0x52 +#define NX_PACKET_OFFSET_ERROR 0x53 + + + +/* Define Link Driver constants. */ + +#define NX_LINK_PACKET_SEND 0 +#define NX_LINK_INITIALIZE 1 +#define NX_LINK_ENABLE 2 +#define NX_LINK_DISABLE 3 +#define NX_LINK_PACKET_BROADCAST 4 +#define NX_LINK_ARP_SEND 5 +#define NX_LINK_ARP_RESPONSE_SEND 6 +#define NX_LINK_RARP_SEND 7 +#define NX_LINK_MULTICAST_JOIN 8 +#define NX_LINK_MULTICAST_LEAVE 9 +#define NX_LINK_GET_STATUS 10 +#define NX_LINK_GET_SPEED 11 +#define NX_LINK_GET_DUPLEX_TYPE 12 +#define NX_LINK_GET_ERROR_COUNT 13 +#define NX_LINK_GET_RX_COUNT 14 +#define NX_LINK_GET_TX_COUNT 15 +#define NX_LINK_GET_ALLOC_ERRORS 16 +#define NX_LINK_UNINITIALIZE 17 +#define NX_LINK_DEFERRED_PROCESSING 18 +#define NX_LINK_INTERFACE_ATTACH 19 +#define NX_LINK_USER_COMMAND 50 /* Values after this value are reserved for application. */ + + +/* Define the macro for building IP addresses. */ + +#define IP_ADDRESS(a, b, c, d) ((((ULONG)a) << 24) | (((ULONG)b) << 16) | (((ULONG)c) << 8) | ((ULONG)d)) + +/* Define the direction of IP packet. */ +#define NX_IP_PACKET_IN 0 +#define NX_IP_PACKET_OUT 1 + +/* Define the control block definitions for all system objects. */ + + +/* Define the basic memory management packet structure. This structure is + used to hold application data as well as internal control data. */ +struct NX_PACKET_POOL_STRUCT; + +typedef struct NX_PACKET_STRUCT +{ + + /* Define the pool this packet is associated with. */ + struct NX_PACKET_POOL_STRUCT + *nx_packet_pool_owner; + + /* Define the link that will be used to queue the packet. */ + struct NX_PACKET_STRUCT + *nx_packet_queue_next; + + /* Define the link that will be used to keep outgoing TCP packets queued + so they can be ACKed or re-sent. */ + struct NX_PACKET_STRUCT + *nx_packet_tcp_queue_next; + + /* Define the link to the chain (one or more) of packet extensions. If this is NULL, there + are no packet extensions for this packet. */ + struct NX_PACKET_STRUCT + *nx_packet_next; + + /* Define the link to the last packet (if any) in the chain. This is used to append + information to the end without having to traverse the entire chain. */ + struct NX_PACKET_STRUCT + *nx_packet_last; + + /* Define the link to the next fragment. This is only used in IP fragmentation + re-assembly. */ + struct NX_PACKET_STRUCT + *nx_packet_fragment_next; + + /* Define the total packet length. */ + ULONG nx_packet_length; + + /* Define the interface from which the packet was received, or the interface to transmit to. */ + struct NX_INTERFACE_STRUCT + *nx_packet_ip_interface; + ULONG nx_packet_next_hop_address; + + /* Define the packet data area start and end pointer. These will be used to + mark the physical boundaries of the packet. */ + UCHAR *nx_packet_data_start; + UCHAR *nx_packet_data_end; + + /* Define the pointer to the first byte written closest to the beginning of the + buffer. This is used to prepend information in front of the packet. */ + UCHAR *nx_packet_prepend_ptr; + + /* Define the pointer to the byte after the last character written in the buffer. */ + UCHAR *nx_packet_append_ptr; + +#ifdef NX_PACKET_HEADER_PAD + + /* Define a pad word for 16-byte alignment, if necessary. */ + ULONG nx_packet_pad[NX_PACKET_HEADER_PAD_SIZE]; +#endif +} NX_PACKET; + + +/* Define the Packet Pool control block that will be used to manage each individual + packet pool. */ + +typedef struct NX_PACKET_POOL_STRUCT +{ + + /* Define the block pool ID used for error checking. */ + ULONG nx_packet_pool_id; + + /* Define the packet pool's name. */ + CHAR *nx_packet_pool_name; + + /* Define the number of available memory packets in the pool. */ + ULONG nx_packet_pool_available; + + /* Save the initial number of blocks. */ + ULONG nx_packet_pool_total; + + /* Define statistics and error counters for this packet pool. */ + ULONG nx_packet_pool_empty_requests; + ULONG nx_packet_pool_empty_suspensions; + ULONG nx_packet_pool_invalid_releases; + + /* Define the head pointer of the available packet pool. */ + struct NX_PACKET_STRUCT *nx_packet_pool_available_list; + + /* Save the start address of the packet pool's memory area. */ + CHAR *nx_packet_pool_start; + + /* Save the packet pool's size in bytes. */ + ULONG nx_packet_pool_size; + + /* Save the individual packet payload size - rounded for alignment. */ + ULONG nx_packet_pool_payload_size; + + /* Define the packet pool suspension list head along with a count of + how many threads are suspended. */ + TX_THREAD *nx_packet_pool_suspension_list; + ULONG nx_packet_pool_suspended_count; + + /* Define the created list next and previous pointers. */ + struct NX_PACKET_POOL_STRUCT + *nx_packet_pool_created_next, + *nx_packet_pool_created_previous; +} NX_PACKET_POOL; + + +/* Define the Address Resolution Protocol (ARP) structure that makes up the + route table in each IP instance. This is how IP addresses are translated + to physical addresses in the system. */ + +typedef struct NX_ARP_STRUCT +{ + + /* Define a flag that indicates whether or not the mapping in this ARP + entry is static. */ + UINT nx_arp_route_static; + + /* Define the counter that indicates when the next ARP update request is + sent. This is always zero for static entries and initialized to the maximum + value for new entries. */ + UINT nx_arp_entry_next_update; + + /* Define the ARP retry counter that is incremented each time the ARP request + is sent. */ + UINT nx_arp_retries; + + /* Define the links for the IP ARP dynamic structures in the system. This list + is maintained in a most recently used fashion. */ + struct NX_ARP_STRUCT + *nx_arp_pool_next, + *nx_arp_pool_previous; + + /* Define the links for the active ARP entry that is part of route + information inside of an IP instance. */ + struct NX_ARP_STRUCT + *nx_arp_active_next, + *nx_arp_active_previous, + **nx_arp_active_list_head; + + /* Define the IP address that this entry is setup for. */ + ULONG nx_arp_ip_address; + + /* Define the physical address that maps to this IP address. */ + ULONG nx_arp_physical_address_msw; + ULONG nx_arp_physical_address_lsw; + + /* Define the physical interface attached to this IP address. */ + struct NX_INTERFACE_STRUCT *nx_arp_ip_interface; + + /* Define a pointer to the queue holding one or more packets while address + resolution is pending. The maximum number of packets that can be queued + is defined by NX_APR_MAX_QUEUE_DEPTH. If ARP packet queue is exceeded, + the oldest packet is discarded in favor of keeping the newer packet. */ + struct NX_PACKET_STRUCT + *nx_arp_packets_waiting; +} NX_ARP; + + +/* Define the basic UDP socket structure. This structure is used to manage all information + necessary to manage UDP transmission and reception. */ + +typedef struct NX_UDP_SOCKET_STRUCT +{ + + /* Define the UDP identification that is used to determine if the UDP socket has + been created. */ + ULONG nx_udp_socket_id; + + /* Define the Application defined name for this UDP socket instance. */ + CHAR *nx_udp_socket_name; + + /* Define the UDP port that was bound to. */ + UINT nx_udp_socket_port; + + /* Define the entry that this UDP socket belongs to. */ + struct NX_IP_STRUCT + *nx_udp_socket_ip_ptr; + + /* Define the statistic and error counters for this UDP socket. */ + ULONG nx_udp_socket_packets_sent; + ULONG nx_udp_socket_bytes_sent; + ULONG nx_udp_socket_packets_received; + ULONG nx_udp_socket_bytes_received; + ULONG nx_udp_socket_invalid_packets; + ULONG nx_udp_socket_packets_dropped; + ULONG nx_udp_socket_checksum_errors; + + /* Define the type of service for this UDP instance. */ + ULONG nx_udp_socket_type_of_service; + + /* Define the time-to-live for this UDP instance. */ + UINT nx_udp_socket_time_to_live; + + /* Define the fragment enable bit for this UDP instance. */ + ULONG nx_udp_socket_fragment_enable; + + /* Define the UDP checksum disable flag for this UDP socket. */ + UINT nx_udp_socket_disable_checksum; + + /* Define the UDP receive packet queue pointers, queue counter, and + the maximum queue depth. */ + ULONG nx_udp_socket_receive_count; + ULONG nx_udp_socket_queue_maximum; + NX_PACKET *nx_udp_socket_receive_head, + *nx_udp_socket_receive_tail; + + /* Define the UDP socket bound list. These pointers are used to manage the list + of UDP sockets on a particular hashed port index. */ + struct NX_UDP_SOCKET_STRUCT + *nx_udp_socket_bound_next, + *nx_udp_socket_bound_previous; + + /* Define the UDP socket bind suspension thread pointer. This pointer points + to the thread that that is suspended attempting to bind to a port that is + already bound to another socket. */ + TX_THREAD *nx_udp_socket_bind_in_progress; + + /* Define the UDP receive suspension list head associated with a count of + how many threads are suspended attempting to receive from the same UDP port. */ + TX_THREAD *nx_udp_socket_receive_suspension_list; + ULONG nx_udp_socket_receive_suspended_count; + + /* Define the UDP bind suspension list head associated with a count of + how many threads are suspended attempting to bind to the same UDP port. The + currently bound socket will maintain the head pointer. When a socket unbinds, + the head of the suspension list is given the port and the remaining entries + of the suspension list are transferred to its suspension list head pointer. */ + TX_THREAD *nx_udp_socket_bind_suspension_list; + ULONG nx_udp_socket_bind_suspended_count; + + /* Define the link between other UDP structures created by the application. This + is linked to the IP instance the socket was created on. */ + struct NX_UDP_SOCKET_STRUCT + *nx_udp_socket_created_next, + *nx_udp_socket_created_previous; + + /* Define the callback function for receive packet notification. If specified + by the application, this function is called whenever a receive packet is + available on for the socket. */ + VOID (*nx_udp_receive_callback)(struct NX_UDP_SOCKET_STRUCT *socket_ptr); + + /* This pointer is reserved for application specific use. */ + void *nx_udp_socket_reserved_ptr; + + struct NX_INTERFACE_STRUCT *nx_udp_socket_ip_interface; +} NX_UDP_SOCKET; + + +/* Define the basic TCP socket structure. This structure is used to manage all information + necessary to manage TCP transmission and reception. */ + +typedef struct NX_TCP_SOCKET_STRUCT +{ + + /* Define the TCP identification that is used to determine if the TCP socket has + been created. */ + ULONG nx_tcp_socket_id; + + /* Define the Application defined name for this TCP socket instance. */ + CHAR *nx_tcp_socket_name; + + /* Define the socket type flag. If true, this socket is a client socket. */ + UINT nx_tcp_socket_client_type; + + /* Define the TCP port that was bound to. */ + UINT nx_tcp_socket_port; + + /* Define the TCP socket's maximum segment size (mss). By default, this is setup to the + IP's MTU less the size of the IP and TCP headers. */ + ULONG nx_tcp_socket_mss; + + /* Define the connected IP and port information, as well as the outgoing interface. */ + ULONG nx_tcp_socket_connect_ip; + UINT nx_tcp_socket_connect_port; + ULONG nx_tcp_socket_connect_mss; + ULONG nx_tcp_socket_peer_mss; + struct NX_INTERFACE_STRUCT + *nx_tcp_socket_connect_interface; + ULONG nx_tcp_socket_next_hop_address; + + /* mss2 is the holding place for the smss * smss value. + It is computed and stored here once for later use. */ + ULONG nx_tcp_socket_connect_mss2; + + ULONG nx_tcp_socket_tx_slow_start_threshold; + + /* Define the state of the TCP connection. */ + UINT nx_tcp_socket_state; + + /* Define the receive and transmit sequence numbers. */ + ULONG nx_tcp_socket_tx_sequence; + ULONG nx_tcp_socket_rx_sequence; + ULONG nx_tcp_socket_rx_sequence_acked; + ULONG nx_tcp_socket_delayed_ack_timeout; + ULONG nx_tcp_socket_fin_sequence; + ULONG nx_tcp_socket_fin_received; + + /* Track the advertised window size */ + ULONG nx_tcp_socket_tx_window_advertised; + ULONG nx_tcp_socket_tx_window_congestion; + ULONG nx_tcp_socket_tx_outstanding_bytes; /* Data transmitted but not acked. */ + + /* Define the transmit sequence that enters fast transmit. */ + ULONG nx_tcp_socket_tx_sequence_recover; + + /* Define the previous cumulative acknowledgment. */ + ULONG nx_tcp_socket_previous_highest_ack; + + /* Define whether or not TCP socket is in fast recovery procedure. */ + UCHAR nx_tcp_socket_fast_recovery; + + /* Reserved to four bytes alignment. */ + UCHAR nx_tcp_socket_reserved[3]; + + /* Counter for "ack-N-packet" */ + ULONG nx_tcp_socket_ack_n_packet_counter; + + /* Counter for duplicated ACK */ + UINT nx_tcp_socket_duplicated_ack_received; + + /* Define the window size fields of the TCP socket structure. */ + ULONG nx_tcp_socket_rx_window_default; + ULONG nx_tcp_socket_rx_window_current; + ULONG nx_tcp_socket_rx_window_last_sent; + + /* Define the statistic and error counters for this TCP socket. */ + ULONG nx_tcp_socket_packets_sent; + ULONG nx_tcp_socket_bytes_sent; + ULONG nx_tcp_socket_packets_received; + ULONG nx_tcp_socket_bytes_received; + ULONG nx_tcp_socket_retransmit_packets; + ULONG nx_tcp_socket_checksum_errors; + + /* Define the entry that this TCP socket belongs to. */ + struct NX_IP_STRUCT + *nx_tcp_socket_ip_ptr; + + /* Define the type of service for this TCP instance. */ + ULONG nx_tcp_socket_type_of_service; + + /* Define the time-to-live for this TCP instance. */ + UINT nx_tcp_socket_time_to_live; + + /* Define the fragment enable bit for this TCP instance. */ + ULONG nx_tcp_socket_fragment_enable; + + /* Define the TCP receive packet queue pointers, queue counter, and + the maximum queue depth. */ + ULONG nx_tcp_socket_receive_queue_count; + NX_PACKET *nx_tcp_socket_receive_queue_head, + *nx_tcp_socket_receive_queue_tail; + + /* Define the TCP packet sent queue. This queue is used to keep track of the + transmit packets already send. Before they can be released we need to receive + an ACK back from the other end of the connection. If no ACK is received, the + packet(s) need to be re-transmitted. */ + ULONG nx_tcp_socket_transmit_queue_maximum; + ULONG nx_tcp_socket_transmit_sent_count; + NX_PACKET *nx_tcp_socket_transmit_sent_head, + *nx_tcp_socket_transmit_sent_tail; + + /* Define the TCP transmit timeout parameters. If the socket timeout is non-zero, + there is an active timeout on the TCP socket. Subsequent timeouts are derived + from the timeout rate, which is adjusted higher as timeouts occur. */ + ULONG nx_tcp_socket_timeout; + ULONG nx_tcp_socket_timeout_rate; + ULONG nx_tcp_socket_timeout_retries; + ULONG nx_tcp_socket_timeout_max_retries; + ULONG nx_tcp_socket_timeout_shift; + +#ifdef NX_ENABLE_TCP_WINDOW_SCALING + /* Local receive window size, when user creates the TCP socket. */ + ULONG nx_tcp_socket_rx_window_maximum; + + /* Window scale this side needs to offer to the peer. */ + ULONG nx_tcp_rcv_win_scale_value; + + /* Window scale offered by the peer. 0xFF indicates the peer does not support window scaling. */ + ULONG nx_tcp_snd_win_scale_value; +#endif /* NX_ENABLE_TCP_WINDOW_SCALING */ + + /* Define the TCP keepalive timer parameters. If enabled with NX_ENABLE_TCP_KEEPALIVE, + these parameters are used to implement the keepalive timer. */ + ULONG nx_tcp_socket_keepalive_timeout; + ULONG nx_tcp_socket_keepalive_retries; + + /* Define the TCP socket bound list. These pointers are used to manage the list + of TCP sockets on a particular hashed port index. */ + struct NX_TCP_SOCKET_STRUCT + *nx_tcp_socket_bound_next, + *nx_tcp_socket_bound_previous; + + /* Define the TCP socket bind suspension thread pointer. This pointer points + to the thread that that is suspended attempting to bind to a port that is + already bound to another socket. */ + TX_THREAD *nx_tcp_socket_bind_in_progress; + + /* Define the TCP 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_tcp_socket_receive_suspension_list; + ULONG nx_tcp_socket_receive_suspended_count; + + /* Define the TCP transmit suspension list head associated with a count of + how many threads are suspended attempting to transmit from the same TCP port. */ + TX_THREAD *nx_tcp_socket_transmit_suspension_list; + ULONG nx_tcp_socket_transmit_suspended_count; + + /* Define the TCP connect suspension pointer that contains the pointer to the + thread suspended attempting to establish a TCP connection. */ + TX_THREAD *nx_tcp_socket_connect_suspended_thread; + + /* Define the TCP disconnect suspension pointer that contains the pointer to the + thread suspended attempting to break a TCP connection. */ + TX_THREAD *nx_tcp_socket_disconnect_suspended_thread; + + /* Define the TCP bind suspension list head associated with a count of + how many threads are suspended attempting to bind to the same TCP port. The + currently bound socket will maintain the head pointer. When a socket unbinds, + the head of the suspension list is given the port and the remaining entries + of the suspension list are transferred to its suspension list head pointer. */ + TX_THREAD *nx_tcp_socket_bind_suspension_list; + ULONG nx_tcp_socket_bind_suspended_count; + + /* Define the link between other TCP structures created by the application. This + is linked to the IP instance the socket was created on. */ + struct NX_TCP_SOCKET_STRUCT + *nx_tcp_socket_created_next, + *nx_tcp_socket_created_previous; + + /* Define the callback function for urgent data reception. This is for future use. */ + VOID (*nx_tcp_urgent_data_callback)(struct NX_TCP_SOCKET_STRUCT *socket_ptr); + +#ifndef NX_DISABLE_EXTENDED_NOTIFY_SUPPORT + /* Define the callback function for notifying an incoming SYN request. */ + UINT (*nx_tcp_socket_syn_received_notify)(struct NX_TCP_SOCKET_STRUCT *socket_ptr, NX_PACKET *packet_ptr); + + /* Define the callback function for notifying the host application of a connection handshake completion + with a remote host. */ + VOID (*nx_tcp_establish_notify)(struct NX_TCP_SOCKET_STRUCT *socket_ptr); + + /* Define the callback function for notifying the host application of disconnection completion + with a remote host. */ + VOID (*nx_tcp_disconnect_complete_notify)(struct NX_TCP_SOCKET_STRUCT *socket_ptr); + + /* Define the callback function for notifying the host application to set the socket + state in the timed wait state. */ + VOID (*nx_tcp_timed_wait_callback)(struct NX_TCP_SOCKET_STRUCT *socket_ptr); +#endif + + /* Define the callback function for disconnect detection from the other side of + the connection. */ + VOID (*nx_tcp_disconnect_callback)(struct NX_TCP_SOCKET_STRUCT *socket_ptr); + + /* Define the callback function for receive packet notification. If specified + by the application, this function is called whenever a receive packet is + available on for the socket. */ + VOID (*nx_tcp_receive_callback)(struct NX_TCP_SOCKET_STRUCT *socket_ptr); + + /* Define the callback function for change in window size notification. If specified + by the application, this function is called whenever a TCP packet is received that + indicates a change in the transmit window size. */ + VOID (*nx_tcp_socket_window_update_notify)(struct NX_TCP_SOCKET_STRUCT *socket_ptr); + + /* This pointer is reserved for application specific use. */ + void *nx_tcp_socket_reserved_ptr; + + /* Define the default maximum queue size. This is necessary to dynamically + change the maximum queue size dynamically. */ + ULONG nx_tcp_socket_transmit_queue_maximum_default; + + /* Define a flag for enabling the keepalive feature per TCP socket. */ + UINT nx_tcp_socket_keepalive_enabled; +} NX_TCP_SOCKET; + + +/* Define the basic TCP listen request structure. This structure is used to indicate + which, if any, TCP ports are allowing a client connection. */ + +typedef struct NX_TCP_LISTEN_STRUCT +{ + + /* Define the port number that we are allowing a connection on. */ + UINT nx_tcp_listen_port; + + /* Define the listen callback routine that will be called when a connection + request is received. */ + VOID (*nx_tcp_listen_callback)(NX_TCP_SOCKET *socket_ptr, UINT port); + + /* Define the previously created socket for this listen request. */ + NX_TCP_SOCKET + *nx_tcp_listen_socket_ptr; + + /* Define the listen queue for connect requests that come in when the previous socket + given for a listen or relisten has been used. */ + ULONG nx_tcp_listen_queue_maximum; + ULONG nx_tcp_listen_queue_current; + NX_PACKET *nx_tcp_listen_queue_head, + *nx_tcp_listen_queue_tail; + + /* Define the link between other TCP listen structures created by the application. */ + struct NX_TCP_LISTEN_STRUCT + *nx_tcp_listen_next, + *nx_tcp_listen_previous; +} NX_TCP_LISTEN; + +struct NX_IP_DRIVER_STRUCT; + +/* There should be at least one physical interface. */ +#ifndef NX_MAX_PHYSICAL_INTERFACES +#define NX_MAX_PHYSICAL_INTERFACES 1 +#endif /* NX_MAX_PHYSICAL_INTERFACES */ + +#ifndef NX_DISABLE_LOOPBACK_INTERFACE +/* Inside interface array, entries 0 up to NX_MAX_PHYSICAL_INTERFACES are assigned to the + physical interfaces. Entry NX_MAX_PHYSICAL_INTERFACES is assigned to the loopback interface. */ +#define NX_LOOPBACK_INTERFACE NX_MAX_PHYSICAL_INTERFACES +#else +#define NX_LOOPBACK_INTERFACE 0 +#endif /* NX_DISALBE_LOOPBACK_INTERFACE */ + +#if (defined(NX_DISABLE_LOOPBACK_INTERFACE) && (NX_MAX_PHYSICAL_INTERFACES == 0)) +#error "NetX is built without either physical interfaces or loopback interfaces." +#endif + +#if defined(NX_DISABLE_LOOPBACK_INTERFACE) +#define NX_MAX_IP_INTERFACES NX_MAX_PHYSICAL_INTERFACES +#else +#define NX_MAX_IP_INTERFACES (NX_MAX_PHYSICAL_INTERFACES + 1) +#endif /* NX_DISABLE_LOOPBACK_INTERFACE */ + + +/* Define the Interface (iface) strcuture. */ +typedef struct NX_INTERFACE_STRUCT +{ + + /* Flag indicating whether or not the interface entry is valid. */ + CHAR *nx_interface_name; + UCHAR nx_interface_valid; + UCHAR nx_interface_address_mapping_needed; + + /* Define the Link Up field that is manipulated by the associated link driver. */ + UCHAR nx_interface_link_up; + + /* Define a flag to check if link status change. */ + UCHAR nx_interface_link_status_change; + + /* Link to the IP instance which this interface is associated with. */ + struct NX_IP_STRUCT *nx_interface_ip_instance; + + /* Define the physical address of this IP instance. These field are + setup by the link driver during initialization. */ + ULONG nx_interface_physical_address_msw; + ULONG nx_interface_physical_address_lsw; + + /* Define the IP address of this IP instance. Loopback can be done by + either using the same address or by using 127.*.*.*. */ + ULONG nx_interface_ip_address; + + /* Define the network portion of the IP address. */ + ULONG nx_interface_ip_network_mask; + + /* Define the network only bits of the IP address. */ + ULONG nx_interface_ip_network; + + /* Define information setup by the Link Driver. */ + ULONG nx_interface_ip_mtu_size; + + /* Define a pointer for use by the applicaiton. Typically this is going to be + used by the link drvier. */ + VOID *nx_interface_additional_link_info; + + /* Define the Link Driver entry point. */ + VOID (*nx_interface_link_driver_entry)(struct NX_IP_DRIVER_STRUCT *); + + /* Define the ARP defend timeout. */ + ULONG nx_interface_arp_defend_timeout; + + /* Define the IP probe address. */ + ULONG nx_interface_ip_probe_address; + + /* Define the IP conflict notify handler. A non-null value for this function + pointer results in NetX calling it when an IP address is found in an incoming + ARP packet that matches that of nx_interface_ip_probe_address. */ + VOID (*nx_interface_ip_conflict_notify_handler)(struct NX_IP_STRUCT *, UINT, ULONG, ULONG, ULONG); +} NX_INTERFACE; + +#ifdef NX_ENABLE_IP_STATIC_ROUTING +/* Define the static routing table entry structure. */ +typedef struct NX_IP_ROUTING_ENTRY_STRUCT +{ + /* Destination IP address, in host byte order */ + ULONG nx_ip_routing_entry_destination_ip; + + /* Net mask, in host byte order */ + ULONG nx_ip_routing_entry_net_mask; + + /* Next hop address, in host byte order. */ + ULONG nx_ip_routing_entry_next_hop_address; + + struct NX_INTERFACE_STRUCT + *nx_ip_routing_entry_ip_interface; +} NX_IP_ROUTING_ENTRY; +#endif /* NX_ENABLE_IP_STATIC_ROUTING */ + + +/* Define the Internet Protocol (IP) structure. Any number of IP instances + may be used by the application. */ + +typedef struct NX_IP_STRUCT +{ + + /* Define the IP identification that is used to determine if the IP has + been created. */ + ULONG nx_ip_id; + + /* Define the Application defined name for this IP instance. */ + CHAR *nx_ip_name; + + /* Define the IP address of this IP instance. Loopback can be done by + either using the same address or by using 127.*.*.*. */ + /* ULONG nx_ip_address; MOVED TO IP_INTERFACE_STRUCTURE */ +#define nx_ip_address nx_ip_interface[0].nx_interface_ip_address +#define nx_ip_driver_mtu nx_ip_interface[0].nx_interface_ip_mtu_size +#define nx_ip_driver_mapping_needed nx_ip_interface[0].nx_interface_address_mapping_needed +#define nx_ip_network_mask nx_ip_interface[0].nx_interface_ip_network_mask +#define nx_ip_network nx_ip_interface[0].nx_interface_ip_network +#define nx_ip_arp_physical_address_msw nx_ip_interface[0].nx_interface_physical_address_msw +#define nx_ip_arp_physical_address_lsw nx_ip_interface[0].nx_interface_physical_address_lsw +#define nx_ip_driver_link_up nx_ip_interface[0].nx_interface_link_up +#define nx_ip_link_driver_entry nx_ip_interface[0].nx_interface_link_driver_entry +#define nx_ip_additional_link_info nx_ip_interface[0].nx_interface_additional_link_info + + /* Define the gateway IP address. */ + ULONG nx_ip_gateway_address; + struct NX_INTERFACE_STRUCT + *nx_ip_gateway_interface; + /* Define the statistic and error counters for this IP instance. */ + ULONG nx_ip_total_packet_send_requests; + ULONG nx_ip_total_packets_sent; + ULONG nx_ip_total_bytes_sent; + ULONG nx_ip_total_packets_received; + ULONG nx_ip_total_packets_delivered; + ULONG nx_ip_total_bytes_received; + ULONG nx_ip_packets_forwarded; + ULONG nx_ip_packets_reassembled; + ULONG nx_ip_reassembly_failures; + ULONG nx_ip_invalid_packets; + ULONG nx_ip_invalid_transmit_packets; + ULONG nx_ip_invalid_receive_address; + ULONG nx_ip_unknown_protocols_received; + ULONG nx_ip_transmit_resource_errors; + ULONG nx_ip_transmit_no_route_errors; + ULONG nx_ip_receive_packets_dropped; + ULONG nx_ip_receive_checksum_errors; + ULONG nx_ip_send_packets_dropped; + ULONG nx_ip_total_fragment_requests; + ULONG nx_ip_successful_fragment_requests; + ULONG nx_ip_fragment_failures; + ULONG nx_ip_total_fragments_sent; + ULONG nx_ip_total_fragments_received; + ULONG nx_ip_arp_requests_sent; + ULONG nx_ip_arp_requests_received; + ULONG nx_ip_arp_responses_sent; + ULONG nx_ip_arp_responses_received; + ULONG nx_ip_arp_aged_entries; + ULONG nx_ip_arp_invalid_messages; + ULONG nx_ip_arp_static_entries; + ULONG nx_ip_udp_packets_sent; + ULONG nx_ip_udp_bytes_sent; + ULONG nx_ip_udp_packets_received; + ULONG nx_ip_udp_bytes_received; + ULONG nx_ip_udp_invalid_packets; + ULONG nx_ip_udp_no_port_for_delivery; + ULONG nx_ip_udp_receive_packets_dropped; + ULONG nx_ip_udp_checksum_errors; + ULONG nx_ip_tcp_packets_sent; + ULONG nx_ip_tcp_bytes_sent; + ULONG nx_ip_tcp_packets_received; + ULONG nx_ip_tcp_bytes_received; + ULONG nx_ip_tcp_invalid_packets; + ULONG nx_ip_tcp_receive_packets_dropped; + ULONG nx_ip_tcp_checksum_errors; + ULONG nx_ip_tcp_connections; + ULONG nx_ip_tcp_passive_connections; + ULONG nx_ip_tcp_active_connections; + ULONG nx_ip_tcp_disconnections; + ULONG nx_ip_tcp_connections_dropped; + ULONG nx_ip_tcp_retransmit_packets; + ULONG nx_ip_tcp_resets_received; + ULONG nx_ip_tcp_resets_sent; + ULONG nx_ip_icmp_total_messages_received; + ULONG nx_ip_icmp_checksum_errors; + ULONG nx_ip_icmp_invalid_packets; + ULONG nx_ip_icmp_unhandled_messages; + ULONG nx_ip_pings_sent; + ULONG nx_ip_ping_timeouts; + ULONG nx_ip_ping_threads_suspended; + ULONG nx_ip_ping_responses_received; + ULONG nx_ip_pings_received; + ULONG nx_ip_pings_responded_to; + ULONG nx_ip_igmp_invalid_packets; + ULONG nx_ip_igmp_reports_sent; + ULONG nx_ip_igmp_queries_received; + ULONG nx_ip_igmp_checksum_errors; + ULONG nx_ip_igmp_groups_joined; +#ifndef NX_DISABLE_IGMPV2 + ULONG nx_ip_igmp_router_version; +#endif + ULONG nx_ip_rarp_requests_sent; + ULONG nx_ip_rarp_responses_received; + ULONG nx_ip_rarp_invalid_messages; + + /* Define the IP forwarding flag. This is by default set to NX_NULL. + If forwarding is desired, the nx_ip_forward_packet_process service + pointed to by this member should be called. */ + VOID (*nx_ip_forward_packet_process)(struct NX_IP_STRUCT *, NX_PACKET *); + + /* Define the packet ID. */ + ULONG nx_ip_packet_id; + + /* Define the default packet pool. */ + struct NX_PACKET_POOL_STRUCT + *nx_ip_default_packet_pool; + + /* Define the internal mutex used for protection inside the NetX + data structures. */ + TX_MUTEX nx_ip_protection; + + /* Define the initialize done flag. */ + UINT nx_ip_initialize_done; + + /* Define the Link Driver hardware deferred packet queue. */ + NX_PACKET *nx_ip_driver_deferred_packet_head, + *nx_ip_driver_deferred_packet_tail; + + /* Define the Link Driver hardware deferred packet processing routine. If the driver + deferred processing is enabled, this routine is called from the IP helper thread. */ + VOID (*nx_ip_driver_deferred_packet_handler)(struct NX_IP_STRUCT *, NX_PACKET *); + + /* Define the deferred packet processing queue. This is used to + process packets not initially processed in the receive ISR. */ + NX_PACKET *nx_ip_deferred_received_packet_head, + *nx_ip_deferred_received_packet_tail; + + /* Define the raw IP function pointer that also indicates whether or + not raw IP packet sending and receiving is enabled. */ + VOID (*nx_ip_raw_ip_processing)(struct NX_IP_STRUCT *, NX_PACKET *); + + /* Define the pointer to the raw IP packet queue. */ + NX_PACKET *nx_ip_raw_received_packet_head, + *nx_ip_raw_received_packet_tail; + + /* Define the count of raw IP packets on the queue. */ + ULONG nx_ip_raw_received_packet_count; + + /* Define the raw packet suspension list head along with a count of + how many threads are suspended. */ + TX_THREAD *nx_ip_raw_packet_suspension_list; + ULONG nx_ip_raw_packet_suspended_count; + + /* Define the IP helper thread that processes periodic ARP requests, + reassembles IP messages, and helps handle TCP/IP packets. */ + TX_THREAD nx_ip_thread; + + /* Define the IP event flags that are used to stimulate the IP helper + thread. */ + TX_EVENT_FLAGS_GROUP + nx_ip_events; + + /* Define the IP periodic timer for this IP instance. */ + TX_TIMER nx_ip_periodic_timer; + + /* Define the IP fragment function pointer that also indicates whether or + IP fragmenting is enabled. */ + VOID (*nx_ip_fragment_processing)(struct NX_IP_DRIVER_STRUCT *); + + /* Define the IP unfragment function pointer. */ + VOID (*nx_ip_fragment_assembly)(struct NX_IP_STRUCT *); + + /* Define the IP unfragment timeout checking function pointer. */ + VOID (*nx_ip_fragment_timeout_check)(struct NX_IP_STRUCT *); + + /* Define the fragment pointer to the oldest fragment re-assembly. If this is + the same between any periodic the fragment re-assembly is too old and + will be deleted. */ + NX_PACKET *nx_ip_timeout_fragment; + + /* Define the pointer to the fragmented IP packet queue. This queue is + appended when a fragmented packet is received and is drained inside + the IP. */ + NX_PACKET *nx_ip_received_fragment_head, + *nx_ip_received_fragment_tail; + + /* Define the pointer to the fragment re-assembly queue. */ + NX_PACKET *nx_ip_fragment_assembly_head, + *nx_ip_fragment_assembly_tail; + + /* Define the IP address change notification callback routine pointer. */ + VOID (*nx_ip_address_change_notify)(struct NX_IP_STRUCT *, VOID *); + VOID *nx_ip_address_change_notify_additional_info; + + /* Define the IGMP registered group list. */ + ULONG nx_ip_igmp_join_list[NX_MAX_MULTICAST_GROUPS]; + + /* Define the IGMP regstiered group interface list. */ + NX_INTERFACE *nx_ip_igmp_join_interface_list[NX_MAX_MULTICAST_GROUPS]; + + /* Define the IGMP registration count. */ + ULONG nx_ip_igmp_join_count[NX_MAX_MULTICAST_GROUPS]; + + /* Define the IGMP random time list. */ + ULONG nx_ip_igmp_update_time[NX_MAX_MULTICAST_GROUPS]; + + /* Define the IGMP loopback flag list. This flag is set based on the global + loopback enable at the time the group was joined. */ + UINT nx_ip_igmp_group_loopback_enable[NX_MAX_MULTICAST_GROUPS]; + + /* Define global IGMP loopback enable/disable flag. By default, IGMP loopback is + disabled. */ + UINT nx_ip_igmp_global_loopback_enable; + + /* Define the IGMP receive packet processing routine. This is setup when IGMP + is enabled. */ + void (*nx_ip_igmp_packet_receive)(struct NX_IP_STRUCT *, struct NX_PACKET_STRUCT *); + + /* Define the IGMP periodic processing routine. This is also setup when IGMP + is enabled. */ + void (*nx_ip_igmp_periodic_processing)(struct NX_IP_STRUCT *); + + /* Define the IGMP packet queue processing routine. This is setup when IGMP is + enabled. */ + void (*nx_ip_igmp_queue_process)(struct NX_IP_STRUCT *); + + /* Define the IGMP message queue. */ + NX_PACKET *nx_ip_igmp_queue_head; + + /* Define the ICMP sequence number. This is used in ICMP messages that + require a sequence number. */ + ULONG nx_ip_icmp_sequence; + + /* Define the ICMP packet receive routine. This also doubles as a + mechanism to make sure ICMP is enabled. If this function is NULL, ICMP + is not enabled. */ + void (*nx_ip_icmp_packet_receive)(struct NX_IP_STRUCT *, struct NX_PACKET_STRUCT *); + + /* Define the ICMP packet queue processing routine. This is setup when ICMP is + enabled. */ + void (*nx_ip_icmp_queue_process)(struct NX_IP_STRUCT *); + + /* Define the ICMP message queue. */ + NX_PACKET *nx_ip_icmp_queue_head; + + /* Define the ICMP ping suspension list head associated with a count of + how many threads are suspended attempting to ping. */ + TX_THREAD *nx_ip_icmp_ping_suspension_list; + ULONG nx_ip_icmp_ping_suspended_count; + + /* Define the UDP port information structure associated with this IP instance. */ + struct NX_UDP_SOCKET_STRUCT + *nx_ip_udp_port_table[NX_UDP_PORT_TABLE_SIZE]; + + /* Define the head pointer of the created UDP socket list. */ + struct NX_UDP_SOCKET_STRUCT + *nx_ip_udp_created_sockets_ptr; + + /* Define the number of created UDP socket instances. */ + ULONG nx_ip_udp_created_sockets_count; + + /* Define the UDP packet receive routine. This also doubles as a + mechanism to make sure UDP is enabled. If this function is NULL, UDP + is not enabled. */ + void (*nx_ip_udp_packet_receive)(struct NX_IP_STRUCT *, struct NX_PACKET_STRUCT *); + + /* Define the TCP port information structure associated with this IP instance. */ + struct NX_TCP_SOCKET_STRUCT + *nx_ip_tcp_port_table[NX_TCP_PORT_TABLE_SIZE]; + + /* Define the head pointer of the created TCP socket list. */ + struct NX_TCP_SOCKET_STRUCT + *nx_ip_tcp_created_sockets_ptr; + + /* Define the number of created TCP socket instances. */ + ULONG nx_ip_tcp_created_sockets_count; + + /* Define the TCP packet receive routine. This also doubles as a + mechanism to make sure TCP is enabled. If this function is NULL, TCP + is not enabled. */ + void (*nx_ip_tcp_packet_receive)(struct NX_IP_STRUCT *, struct NX_PACKET_STRUCT *); + + /* Define the TCP periodic processing routine for transmit timeout logic. */ + void (*nx_ip_tcp_periodic_processing)(struct NX_IP_STRUCT *); + + /* Define the TCP fast periodic processing routine for transmit timeout logic. */ + void (*nx_ip_tcp_fast_periodic_processing)(struct NX_IP_STRUCT *); + + /* Define the TCP packet queue processing routine. This is setup when TCP is + enabled. */ + void (*nx_ip_tcp_queue_process)(struct NX_IP_STRUCT *); + + /* Define the pointer to the incoming TCP packet queue. */ + NX_PACKET *nx_ip_tcp_queue_head, + *nx_ip_tcp_queue_tail; + + /* Define the count of incoming TCP packets on the queue. */ + ULONG nx_ip_tcp_received_packet_count; + + /* Define the TCP listen request structure that contains the maximum number of + listen requests allowed for this IP instance. */ + struct NX_TCP_LISTEN_STRUCT + nx_ip_tcp_server_listen_reqs[NX_MAX_LISTEN_REQUESTS]; + + /* Define the head pointer of the available listen request structures. */ + struct NX_TCP_LISTEN_STRUCT + *nx_ip_tcp_available_listen_requests; + + /* Define the head pointer of the active listen requests. These are made + by issuing the nx_tcp_server_socket_listen service. */ + struct NX_TCP_LISTEN_STRUCT + *nx_ip_tcp_active_listen_requests; + + /* Define the fast TCP periodic timer used for high resolution events for + this IP instance. */ + TX_TIMER nx_ip_tcp_fast_periodic_timer; + + /* Define the destination routing information associated with this IP + instance. */ + struct NX_ARP_STRUCT + *nx_ip_arp_table[NX_ROUTE_TABLE_SIZE]; + + /* Define the head pointer of the static ARP list. */ + struct NX_ARP_STRUCT + *nx_ip_arp_static_list; + + /* Define the head pointer of the dynamic ARP list. */ + struct NX_ARP_STRUCT + *nx_ip_arp_dynamic_list; + + /* Define the number of dynamic entries that are active. */ + ULONG nx_ip_arp_dynamic_active_count; + + /* Define the ARP deferred packet processing queue. This is used to + process ARP packets not initially processed in the receive ISR. */ + NX_PACKET *nx_ip_arp_deferred_received_packet_head, + *nx_ip_arp_deferred_received_packet_tail; + + /* Define the ARP entry allocate routine. This also doubles as a + mechanism to make sure ARP is enabled. If this function is NULL, ARP + is not enabled. */ + UINT (*nx_ip_arp_allocate)(struct NX_IP_STRUCT *, struct NX_ARP_STRUCT **); + + /* Define the ARP periodic processing routine. This is setup when ARP is + enabled. */ + void (*nx_ip_arp_periodic_update)(struct NX_IP_STRUCT *); + + /* Define the ARP receive queue processing routine. This is setup when ARP is + enabled. */ + void (*nx_ip_arp_queue_process)(struct NX_IP_STRUCT *); + + /* Define the ARP send packet routine. This is setup when ARP is + enabled. */ + void (*nx_ip_arp_packet_send)(struct NX_IP_STRUCT *, ULONG destination_ip, NX_INTERFACE *nx_interface); + + /* Define the ARP gratuitous response handler. This routine is setup in the + nx_arp_gratuitous_send function. */ + void (*nx_ip_arp_gratuitous_response_handler)(struct NX_IP_STRUCT *, NX_PACKET *); + +#ifdef NX_ENABLE_ARP_MAC_CHANGE_NOTIFICATION + /* Define the ARP collision notify handler. A non-null value for this function + pointer results in NetX calling it whenever an IP address is found in an incoming + ARP packet that matches that of the IP address in our ARP table. */ + void (*nx_ip_arp_collision_notify_response_handler)(void *); +#endif + + /* Define the ARP cache memory area. This memory is supplied + by the ARP enable function and is carved up by that function into as + many ARP entries that will fit. */ + struct NX_ARP_STRUCT + *nx_ip_arp_cache_memory; + + /* Define the number of ARP entries that will fit in the ARP cache. */ + ULONG nx_ip_arp_total_entries; + + /* Define the RARP periodic processing routine. This is setup when RARP is + enabled. It is also used to indicate RARP is enabled. */ + void (*nx_ip_rarp_periodic_update)(struct NX_IP_STRUCT *); + + /* Define the RARP receive queue processing routine. This is setup when RARP is + enabled. */ + void (*nx_ip_rarp_queue_process)(struct NX_IP_STRUCT *); + + /* Define the RARP deferred packet processing queue. This is used to + process RARP packets not initially processed in the receive ISR. */ + NX_PACKET *nx_ip_rarp_deferred_received_packet_head, + *nx_ip_rarp_deferred_received_packet_tail; + + /* Define the link between other IP structures created by the application. */ + struct NX_IP_STRUCT + *nx_ip_created_next, + *nx_ip_created_previous; + + /* This pointer is reserved for application specific use. */ + void *nx_ip_reserved_ptr; + + /* Define the TCP devered cleanup processing routine. */ + void (*nx_tcp_deferred_cleanup_check)(struct NX_IP_STRUCT *); + /* Define the interfaces attached to this IP instance. */ + NX_INTERFACE nx_ip_interface[NX_MAX_IP_INTERFACES]; + + + /* Define the static routing table, if the feature is enabled. */ +#ifdef NX_ENABLE_IP_STATIC_ROUTING + NX_IP_ROUTING_ENTRY nx_ip_routing_table[NX_IP_ROUTING_TABLE_SIZE]; + + ULONG nx_ip_routing_table_entry_count; + +#endif /* NX_ENABLE_IP_STATIC_ROUTING */ + + /* Define the link status change notify routine. */ + VOID (*nx_ip_link_status_change_callback)(struct NX_IP_STRUCT *, UINT, UINT); + +#ifdef NX_ENABLE_IP_PACKET_FILTER + /* Define the IP packet filter routine. */ + UINT (*nx_ip_packet_filter)(VOID *, UINT); +#endif /* NX_ENABLE_IP_PACKET_FILTER */ +} NX_IP; + +/* Define the Driver interface structure that is typically allocated off of the + local stack and passed to the IP Link Driver. */ + +typedef struct NX_IP_DRIVER_STRUCT +{ + + /* Define the driver command. */ + UINT nx_ip_driver_command; + + /* Define the driver return status. */ + UINT nx_ip_driver_status; + + /* Define the physical address that maps to the destination IP address. */ + ULONG nx_ip_driver_physical_address_msw; + ULONG nx_ip_driver_physical_address_lsw; + + /* Define the datagram packet (if any) for the driver to send. */ + NX_PACKET *nx_ip_driver_packet; + + /* Define the return pointer for raw driver command requests. */ + ULONG *nx_ip_driver_return_ptr; + + /* Define the IP pointer associated with the request. */ + struct NX_IP_STRUCT + *nx_ip_driver_ptr; + + NX_INTERFACE *nx_ip_driver_interface; +} NX_IP_DRIVER; + + +/* Define the system API mappings based on the error checking + selected by the user. Note: this section is only applicable to + application source code, hence the conditional that turns off this + stuff when the include file is processed by the ThreadX source. */ + +#ifndef NX_SOURCE_CODE + + +/* 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_arp_dynamic_entries_invalidate _nx_arp_dynamic_entries_invalidate +#define nx_arp_dynamic_entry_set _nx_arp_dynamic_entry_set +#define nx_arp_enable _nx_arp_enable +#define nx_arp_gratuitous_send _nx_arp_gratuitous_send +#define nx_arp_hardware_address_find _nx_arp_hardware_address_find +#define nx_arp_info_get _nx_arp_info_get +#define nx_arp_ip_address_find _nx_arp_ip_address_find +#define nx_arp_static_entries_delete _nx_arp_static_entries_delete +#define nx_arp_static_entry_create _nx_arp_static_entry_create +#define nx_arp_static_entry_delete _nx_arp_static_entry_delete + +#define nx_icmp_enable _nx_icmp_enable +#define nx_icmp_info_get _nx_icmp_info_get +#define nx_icmp_ping _nx_icmp_ping + +#define nx_igmp_enable _nx_igmp_enable +#define nx_igmp_info_get _nx_igmp_info_get +#define nx_igmp_loopback_disable _nx_igmp_loopback_disable +#define nx_igmp_loopback_enable _nx_igmp_loopback_enable +#define nx_igmp_multicast_join _nx_igmp_multicast_join +#define nx_igmp_multicast_interface_join _nx_igmp_multicast_interface_join +#define nx_igmp_multicast_leave _nx_igmp_multicast_leave + +#define nx_ip_address_change_notify _nx_ip_address_change_notify +#define nx_ip_address_get _nx_ip_address_get +#define nx_ip_address_set _nx_ip_address_set +#define nx_ip_create _nx_ip_create +#define nx_ip_delete _nx_ip_delete +#define nx_ip_driver_direct_command _nx_ip_driver_direct_command +#define nx_ip_driver_interface_direct_command _nx_ip_driver_interface_direct_command +#define nx_ip_forwarding_disable _nx_ip_forwarding_disable +#define nx_ip_forwarding_enable _nx_ip_forwarding_enable +#define nx_ip_fragment_disable _nx_ip_fragment_disable +#define nx_ip_fragment_enable _nx_ip_fragment_enable +#define nx_ip_gateway_address_set _nx_ip_gateway_address_set +#define nx_ip_info_get _nx_ip_info_get +#define nx_ip_interface_attach _nx_ip_interface_attach +#define nx_ip_interface_address_get _nx_ip_interface_address_get +#define nx_ip_interface_address_set _nx_ip_interface_address_set +#define nx_ip_interface_info_get _nx_ip_interface_info_get +#define nx_ip_interface_status_check _nx_ip_interface_status_check +#define nx_ip_raw_packet_disable _nx_ip_raw_packet_disable +#define nx_ip_raw_packet_enable _nx_ip_raw_packet_enable +#define nx_ip_raw_packet_receive _nx_ip_raw_packet_receive +#define nx_ip_raw_packet_send _nx_ip_raw_packet_send +#define nx_ip_raw_packet_interface_send _nx_ip_raw_packet_interface_send +#define nx_ip_static_route_add _nx_ip_static_route_add +#define nx_ip_static_route_delete _nx_ip_static_route_delete +#define nx_ip_status_check _nx_ip_status_check +#define nx_ip_link_status_change_notify_set _nx_ip_link_status_change_notify_set + +#define nx_packet_allocate _nx_packet_allocate +#define nx_packet_copy _nx_packet_copy +#define nx_packet_data_append _nx_packet_data_append +#define nx_packet_data_extract_offset _nx_packet_data_extract_offset +#define nx_packet_data_retrieve _nx_packet_data_retrieve +#define nx_packet_length_get _nx_packet_length_get +#define nx_packet_pool_create _nx_packet_pool_create +#define nx_packet_pool_delete _nx_packet_pool_delete +#define nx_packet_pool_info_get _nx_packet_pool_info_get +#define nx_packet_release _nx_packet_release +#define nx_packet_transmit_release _nx_packet_transmit_release + +#define nx_rarp_disable _nx_rarp_disable +#define nx_rarp_enable _nx_rarp_enable +#define nx_rarp_info_get _nx_rarp_info_get + +#define nx_system_initialize _nx_system_initialize + +#define nx_tcp_client_socket_bind _nx_tcp_client_socket_bind +#define nx_tcp_client_socket_connect _nx_tcp_client_socket_connect +#define nx_tcp_client_socket_port_get _nx_tcp_client_socket_port_get +#define nx_tcp_client_socket_unbind _nx_tcp_client_socket_unbind +#define nx_tcp_enable _nx_tcp_enable +#define nx_tcp_free_port_find _nx_tcp_free_port_find +#define nx_tcp_info_get _nx_tcp_info_get +#define nx_tcp_server_socket_accept _nx_tcp_server_socket_accept +#define nx_tcp_server_socket_listen _nx_tcp_server_socket_listen +#define nx_tcp_server_socket_relisten _nx_tcp_server_socket_relisten +#define nx_tcp_server_socket_unaccept _nx_tcp_server_socket_unaccept +#define nx_tcp_server_socket_unlisten _nx_tcp_server_socket_unlisten +#define nx_tcp_socket_bytes_available _nx_tcp_socket_bytes_available +#define nx_tcp_socket_create _nx_tcp_socket_create +#define nx_tcp_socket_delete _nx_tcp_socket_delete +#define nx_tcp_socket_disconnect _nx_tcp_socket_disconnect +#ifndef NX_DISABLE_EXTENDED_NOTIFY_SUPPORT +#define nx_tcp_socket_establish_notify _nx_tcp_socket_establish_notify +#define nx_tcp_socket_disconnect_complete_notify _nx_tcp_socket_disconnect_complete_notify +#define nx_tcp_socket_timed_wait_callback _nx_tcp_socket_timed_wait_callback +#endif +#define nx_tcp_socket_info_get _nx_tcp_socket_info_get +#define nx_tcp_socket_mss_get _nx_tcp_socket_mss_get +#define nx_tcp_socket_mss_peer_get _nx_tcp_socket_mss_peer_get +#define nx_tcp_socket_mss_set _nx_tcp_socket_mss_set +#define nx_tcp_socket_peer_info_get _nx_tcp_socket_peer_info_get +#define nx_tcp_socket_receive _nx_tcp_socket_receive +#define nx_tcp_socket_receive_notify _nx_tcp_socket_receive_notify +#define nx_tcp_socket_send _nx_tcp_socket_send +#define nx_tcp_socket_state_wait _nx_tcp_socket_state_wait +#define nx_tcp_socket_transmit_configure _nx_tcp_socket_transmit_configure +#define nx_tcp_socket_window_update_notify_set _nx_tcp_socket_window_update_notify_set + +#define nx_udp_enable _nx_udp_enable +#define nx_udp_free_port_find _nx_udp_free_port_find +#define nx_udp_info_get _nx_udp_info_get +#define nx_udp_packet_info_extract _nx_udp_packet_info_extract +#define nx_udp_socket_bind _nx_udp_socket_bind +#define nx_udp_socket_bytes_available _nx_udp_socket_bytes_available +#define nx_udp_socket_checksum_disable _nx_udp_socket_checksum_disable +#define nx_udp_socket_checksum_enable _nx_udp_socket_checksum_enable +#define nx_udp_socket_create _nx_udp_socket_create +#define nx_udp_socket_delete _nx_udp_socket_delete +#define nx_udp_socket_info_get _nx_udp_socket_info_get +#define nx_udp_socket_interface_send _nx_udp_socket_interface_send +#define nx_udp_socket_port_get _nx_udp_socket_port_get +#define nx_udp_socket_receive _nx_udp_socket_receive +#define nx_udp_socket_receive_notify _nx_udp_socket_receive_notify +#define nx_udp_socket_send _nx_udp_socket_send +#define nx_udp_socket_unbind _nx_udp_socket_unbind +#define nx_udp_source_extract _nx_udp_source_extract + +#else + +/* Services with error checking. */ + +#define nx_arp_dynamic_entries_invalidate _nxe_arp_dynamic_entries_invalidate +#define nx_arp_dynamic_entry_set _nxe_arp_dynamic_entry_set +#define nx_arp_enable _nxe_arp_enable +#define nx_arp_gratuitous_send _nxe_arp_gratuitous_send +#define nx_arp_hardware_address_find _nxe_arp_hardware_address_find +#define nx_arp_info_get _nxe_arp_info_get +#define nx_arp_ip_address_find _nxe_arp_ip_address_find +#define nx_arp_static_entries_delete _nxe_arp_static_entries_delete +#define nx_arp_static_entry_create _nxe_arp_static_entry_create +#define nx_arp_static_entry_delete _nxe_arp_static_entry_delete + +#define nx_icmp_enable _nxe_icmp_enable +#define nx_icmp_info_get _nxe_icmp_info_get +#define nx_icmp_ping _nxe_icmp_ping + +#define nx_igmp_enable _nxe_igmp_enable +#define nx_igmp_info_get _nxe_igmp_info_get +#define nx_igmp_loopback_disable _nxe_igmp_loopback_disable +#define nx_igmp_loopback_enable _nxe_igmp_loopback_enable +#define nx_igmp_multicast_join _nxe_igmp_multicast_join +#define nx_igmp_multicast_interface_join _nxe_igmp_multicast_interface_join +#define nx_igmp_multicast_leave _nxe_igmp_multicast_leave + +#define nx_ip_address_change_notify _nxe_ip_address_change_notify +#define nx_ip_address_get _nxe_ip_address_get +#define nx_ip_address_set _nxe_ip_address_set +#define nx_ip_interface_address_get _nxe_ip_interface_address_get +#define nx_ip_interface_address_set _nxe_ip_interface_address_set +#define nx_ip_interface_info_get _nxe_ip_interface_info_get +#define nx_ip_interface_status_check _nxe_ip_interface_status_check +#define nx_ip_create(i, n, a, m, d, l, p, s, y) _nxe_ip_create(i, n, a, m, d, l, p, s, y, sizeof(NX_IP)) +#define nx_ip_delete _nxe_ip_delete +#define nx_ip_driver_direct_command _nxe_ip_driver_direct_command +#define nx_ip_driver_interface_direct_command _nxe_ip_driver_interface_direct_command +#define nx_ip_forwarding_disable _nxe_ip_forwarding_disable +#define nx_ip_forwarding_enable _nxe_ip_forwarding_enable +#define nx_ip_fragment_disable _nxe_ip_fragment_disable +#define nx_ip_fragment_enable _nxe_ip_fragment_enable +#define nx_ip_gateway_address_set _nxe_ip_gateway_address_set +#define nx_ip_info_get _nxe_ip_info_get +#define nx_ip_interface_attach _nxe_ip_interface_attach +#define nx_ip_raw_packet_disable _nxe_ip_raw_packet_disable +#define nx_ip_raw_packet_enable _nxe_ip_raw_packet_enable +#define nx_ip_raw_packet_receive _nxe_ip_raw_packet_receive +#define nx_ip_raw_packet_send(i, p, d, t) _nxe_ip_raw_packet_send(i, &p, d, t) +#define nx_ip_raw_packet_interface_send(i, p, d, f, t) _nxe_ip_raw_packet_interface_send(i, &p, d, f, t) +#define nx_ip_static_route_add _nxe_ip_static_route_add +#define nx_ip_static_route_delete _nxe_ip_static_route_delete + +#define nx_ip_status_check _nxe_ip_status_check +#define nx_ip_link_status_change_notify_set _nxe_ip_link_status_change_notify_set + +#define nx_packet_allocate _nxe_packet_allocate +#define nx_packet_copy _nxe_packet_copy +#define nx_packet_data_append _nxe_packet_data_append +#define nx_packet_data_extract_offset _nxe_packet_data_extract_offset +#define nx_packet_data_retrieve _nxe_packet_data_retrieve +#define nx_packet_length_get _nxe_packet_length_get +#define nx_packet_pool_create(p, n, l, m, s) _nxe_packet_pool_create(p, n, l, m, s, sizeof(NX_PACKET_POOL)) +#define nx_packet_pool_delete _nxe_packet_pool_delete +#define nx_packet_pool_info_get _nxe_packet_pool_info_get +#define nx_packet_release(p) _nxe_packet_release(&p) +#define nx_packet_transmit_release(p) _nxe_packet_transmit_release(&p) + +#define nx_rarp_disable _nxe_rarp_disable +#define nx_rarp_enable _nxe_rarp_enable +#define nx_rarp_info_get _nxe_rarp_info_get + +#define nx_system_initialize _nx_system_initialize + +#define nx_tcp_client_socket_bind _nxe_tcp_client_socket_bind +#define nx_tcp_client_socket_connect _nxe_tcp_client_socket_connect +#define nx_tcp_client_socket_port_get _nxe_tcp_client_socket_port_get +#define nx_tcp_client_socket_unbind _nxe_tcp_client_socket_unbind +#define nx_tcp_enable _nxe_tcp_enable +#define nx_tcp_free_port_find _nxe_tcp_free_port_find +#define nx_tcp_info_get _nxe_tcp_info_get +#define nx_tcp_server_socket_accept _nxe_tcp_server_socket_accept +#define nx_tcp_server_socket_listen _nxe_tcp_server_socket_listen +#define nx_tcp_server_socket_relisten _nxe_tcp_server_socket_relisten +#define nx_tcp_server_socket_unaccept _nxe_tcp_server_socket_unaccept +#define nx_tcp_server_socket_unlisten _nxe_tcp_server_socket_unlisten +#define nx_tcp_socket_bytes_available _nxe_tcp_socket_bytes_available +#define nx_tcp_socket_create(i, s, n, t, f, l, w, u, d) _nxe_tcp_socket_create(i, s, n, t, f, l, w, u, d, sizeof(NX_TCP_SOCKET)) +#define nx_tcp_socket_delete _nxe_tcp_socket_delete +#define nx_tcp_socket_disconnect _nxe_tcp_socket_disconnect +#ifndef NX_DISABLE_EXTENDED_NOTIFY_SUPPORT +#define nx_tcp_socket_establish_notify _nxe_tcp_socket_establish_notify +#define nx_tcp_socket_disconnect_complete_notify _nxe_tcp_socket_disconnect_complete_notify +#define nx_tcp_socket_timed_wait_callback _nxe_tcp_socket_timed_wait_callback +#endif +#define nx_tcp_socket_info_get _nxe_tcp_socket_info_get +#define nx_tcp_socket_mss_get _nxe_tcp_socket_mss_get +#define nx_tcp_socket_mss_peer_get _nxe_tcp_socket_mss_peer_get +#define nx_tcp_socket_mss_set _nxe_tcp_socket_mss_set +#define nx_tcp_socket_peer_info_get _nxe_tcp_socket_peer_info_get +#define nx_tcp_socket_receive _nxe_tcp_socket_receive +#define nx_tcp_socket_receive_notify _nxe_tcp_socket_receive_notify +#define nx_tcp_socket_send(s, p, t) _nxe_tcp_socket_send(s, &p, t) +#define nx_tcp_socket_state_wait _nxe_tcp_socket_state_wait +#define nx_tcp_socket_transmit_configure _nxe_tcp_socket_transmit_configure +#define nx_tcp_socket_window_update_notify_set _nxe_tcp_socket_window_update_notify_set + +#define nx_udp_enable _nxe_udp_enable +#define nx_udp_free_port_find _nxe_udp_free_port_find +#define nx_udp_info_get _nxe_udp_info_get +#define nx_udp_packet_info_extract _nxe_udp_packet_info_extract +#define nx_udp_socket_bind _nxe_udp_socket_bind +#define nx_udp_socket_bytes_available _nxe_udp_socket_bytes_available +#define nx_udp_socket_checksum_disable _nxe_udp_socket_checksum_disable +#define nx_udp_socket_checksum_enable _nxe_udp_socket_checksum_enable +#define nx_udp_socket_create(i, s, n, t, f, l, q) _nxe_udp_socket_create(i, s, n, t, f, l, q, sizeof(NX_UDP_SOCKET)) +#define nx_udp_socket_delete _nxe_udp_socket_delete +#define nx_udp_socket_info_get _nxe_udp_socket_info_get +#define nx_udp_socket_interface_send(s, p, i, t, a) _nxe_udp_socket_interface_send(s, &p, i, t, a) +#define nx_udp_socket_port_get _nxe_udp_socket_port_get +#define nx_udp_socket_receive _nxe_udp_socket_receive +#define nx_udp_socket_receive_notify _nxe_udp_socket_receive_notify +#define nx_udp_socket_send(s, p, i, t) _nxe_udp_socket_send(s, &p, i, t) +#define nx_udp_socket_unbind _nxe_udp_socket_unbind +#define nx_udp_source_extract _nxe_udp_source_extract + +#endif + + +/* Define the function prototypes of the NetX API. */ + + +UINT nx_arp_dynamic_entries_invalidate(NX_IP *ip_ptr); +UINT nx_arp_dynamic_entry_set(NX_IP *ip_ptr, ULONG ip_address, + ULONG physical_msw, ULONG physical_lsw); +UINT nx_arp_enable(NX_IP *ip_ptr, VOID *arp_cache_memory, ULONG arp_cache_size); +UINT nx_arp_gratuitous_send(NX_IP *ip_ptr, VOID (*response_handler)(NX_IP *ip_ptr, NX_PACKET *packet_ptr)); +UINT nx_arp_hardware_address_find(NX_IP *ip_ptr, ULONG ip_address, + ULONG *physical_msw, ULONG *physical_lsw); +UINT nx_arp_info_get(NX_IP *ip_ptr, ULONG *arp_requests_sent, ULONG *arp_requests_received, + ULONG *arp_responses_sent, ULONG *arp_responses_received, + ULONG *arp_dynamic_entries, ULONG *arp_static_entries, + ULONG *arp_aged_entries, ULONG *arp_invalid_messages); +UINT nx_arp_ip_address_find(NX_IP *ip_ptr, ULONG *ip_address, + ULONG physical_msw, ULONG physical_lsw); +UINT nx_arp_static_entries_delete(NX_IP *ip_ptr); +UINT nx_arp_static_entry_create(NX_IP *ip_ptr, ULONG ip_address, + ULONG physical_msw, ULONG physical_lsw); +UINT nx_arp_static_entry_delete(NX_IP *ip_ptr, ULONG ip_address, + ULONG physical_msw, ULONG physical_lsw); + +UINT nx_icmp_enable(NX_IP *ip_ptr); +UINT nx_icmp_info_get(NX_IP *ip_ptr, ULONG *pings_sent, ULONG *ping_timeouts, + ULONG *ping_threads_suspended, ULONG *ping_responses_received, + ULONG *icmp_checksum_errors, ULONG *icmp_unhandled_messages); +UINT nx_icmp_ping(NX_IP *ip_ptr, ULONG ip_address, CHAR *data, ULONG data_size, + NX_PACKET **response_ptr, ULONG wait_option); + +UINT nx_igmp_enable(NX_IP *ip_ptr); +UINT nx_igmp_info_get(NX_IP *ip_ptr, ULONG *igmp_reports_sent, ULONG *igmp_queries_received, + ULONG *igmp_checksum_errors, ULONG *current_groups_joined); +UINT nx_igmp_loopback_disable(NX_IP *ip_ptr); +UINT nx_igmp_loopback_enable(NX_IP *ip_ptr); +UINT nx_igmp_multicast_join(NX_IP *ip_ptr, ULONG group_address); +UINT nx_igmp_multicast_interface_join(NX_IP *ip_ptr, ULONG group_address, UINT nx_interface_index); +UINT nx_igmp_multicast_leave(NX_IP *ip_ptr, ULONG group_address); + +UINT nx_ip_address_change_notify(NX_IP *ip_ptr, VOID (*ip_address_change_notify)(NX_IP *, VOID *), VOID *additional_info); +UINT nx_ip_address_get(NX_IP *ip_ptr, ULONG *ip_address, ULONG *network_mask); +UINT nx_ip_address_set(NX_IP *ip_ptr, ULONG ip_address, ULONG network_mask); +UINT nx_ip_interface_address_get(NX_IP *ip_ptr, ULONG interface_index, ULONG *ip_address, ULONG *network_mask); +UINT nx_ip_interface_address_set(NX_IP *ip_ptr, ULONG interface_index, ULONG ip_address, ULONG network_mask); +UINT nx_ip_interface_info_get(NX_IP *ip_ptr, UINT interface_index, CHAR **interface_name, ULONG *ip_address, + ULONG *network_mask, ULONG *mtu_size, ULONG *phsyical_address_msw, ULONG *physical_address_lsw); +#ifndef NX_DISABLE_ERROR_CHECKING +UINT _nxe_ip_create(NX_IP *ip_ptr, CHAR *name, ULONG ip_address, ULONG network_mask, + NX_PACKET_POOL *default_pool, + VOID (*ip_link_driver)(NX_IP_DRIVER *), + VOID *memory_ptr, ULONG memory_size, UINT priority, UINT ip_control_block_size); +#else +UINT _nx_ip_create(NX_IP *ip_ptr, CHAR *name, ULONG ip_address, ULONG network_mask, + NX_PACKET_POOL *default_pool, + VOID (*ip_link_driver)(NX_IP_DRIVER *), + VOID *memory_ptr, ULONG memory_size, UINT priority); +#endif +UINT nx_ip_delete(NX_IP *ip_ptr); +UINT nx_ip_driver_direct_command(NX_IP *ip_ptr, UINT command, ULONG *return_value_ptr); +UINT nx_ip_driver_interface_direct_command(NX_IP *ip_ptr, UINT command, UINT interface_index, ULONG *return_value_ptr); +UINT nx_ip_forwarding_disable(NX_IP *ip_ptr); +UINT nx_ip_forwarding_enable(NX_IP *ip_ptr); +UINT nx_ip_fragment_disable(NX_IP *ip_ptr); +UINT nx_ip_fragment_enable(NX_IP *ip_ptr); +UINT nx_ip_gateway_address_set(NX_IP *ip_ptr, ULONG ip_address); +UINT nx_ip_info_get(NX_IP *ip_ptr, ULONG *ip_total_packets_sent, ULONG *ip_total_bytes_sent, + ULONG *ip_total_packets_received, ULONG *ip_total_bytes_received, + ULONG *ip_invalid_packets, ULONG *ip_receive_packets_dropped, + ULONG *ip_receive_checksum_errors, ULONG *ip_send_packets_dropped, + ULONG *ip_total_fragments_sent, ULONG *ip_total_fragments_received); +UINT nx_ip_interface_attach(NX_IP *ip_ptr, CHAR *interface_name, ULONG ip_address, ULONG network_mask, + VOID (*ip_link_driver)(struct NX_IP_DRIVER_STRUCT *)); +UINT nx_ip_interface_status_check(NX_IP *ip_ptr, UINT interface_index, ULONG needed_status, + ULONG *actual_status, ULONG wait_option); + +UINT nx_ip_raw_packet_disable(NX_IP *ip_ptr); +UINT nx_ip_raw_packet_enable(NX_IP *ip_ptr); +UINT nx_ip_raw_packet_receive(NX_IP *ip_ptr, NX_PACKET **packet_ptr, ULONG wait_option); +#ifndef NX_DISABLE_ERROR_CHECKING +UINT _nxe_ip_raw_packet_send(NX_IP *ip_ptr, NX_PACKET **packet_ptr_ptr, + ULONG destination_ip, ULONG type_of_service); +UINT _nxe_ip_raw_packet_packet_send(NX_IP *ip_ptr, NX_PACKET **packet_ptr_ptr, + ULONG destination_ip, UINT interface_index, ULONG type_of_service); +#else +UINT _nx_ip_raw_packet_send(NX_IP *ip_ptr, NX_PACKET *packet_ptr, + ULONG destination_ip, ULONG type_of_service); +UINT _nx_ip_raw_packet_interface_send(NX_IP *ip_ptr, NX_PACKET *packet_ptr, + ULONG destination_ip, UINT interface_index, ULONG type_of_service); +#endif +UINT nx_ip_static_route_add(NX_IP *ip_ptr, ULONG network_address, ULONG net_mask, ULONG next_hop); +UINT nx_ip_static_route_delete(NX_IP *ip_ptr, ULONG network_address, ULONG net_mask); +UINT nx_ip_status_check(NX_IP *ip_ptr, ULONG needed_status, ULONG *actual_status, + ULONG wait_option); +UINT nx_ip_link_status_change_notify_set(NX_IP *ip_ptr, VOID (*link_status_change_notify)(NX_IP *ip_ptr, UINT interface_index, UINT link_up)); + +UINT nx_packet_allocate(NX_PACKET_POOL *pool_ptr, NX_PACKET **packet_ptr, + ULONG packet_type, ULONG wait_option); +UINT nx_packet_copy(NX_PACKET *packet_ptr, NX_PACKET **new_packet_ptr, + NX_PACKET_POOL *pool_ptr, ULONG wait_option); +UINT nx_packet_data_append(NX_PACKET *packet_ptr, VOID *data_start, ULONG data_size, + NX_PACKET_POOL *pool_ptr, ULONG wait_option); +UINT nx_packet_data_extract_offset(NX_PACKET *packet_ptr, ULONG offset, VOID *buffer_start, + ULONG buffer_length, ULONG *bytes_copied); +UINT nx_packet_data_retrieve(NX_PACKET *packet_ptr, VOID *buffer_start, ULONG *bytes_copied); +UINT nx_packet_length_get(NX_PACKET *packet_ptr, ULONG *length); +#ifndef NX_DISABLE_ERROR_CHECKING +UINT _nxe_packet_pool_create(NX_PACKET_POOL *pool_ptr, CHAR *name, ULONG payload_size, + VOID *memory_ptr, ULONG memory_size, UINT pool_control_block_size); +#else +UINT _nx_packet_pool_create(NX_PACKET_POOL *pool_ptr, CHAR *name, ULONG payload_size, + VOID *memory_ptr, ULONG memory_size); +#endif +UINT nx_packet_pool_delete(NX_PACKET_POOL *pool_ptr); +UINT nx_packet_pool_info_get(NX_PACKET_POOL *pool_ptr, ULONG *total_packets, ULONG *free_packets, + ULONG *empty_pool_requests, ULONG *empty_pool_suspensions, + ULONG *invalid_packet_releases); +#ifndef NX_DISABLE_ERROR_CHECKING +UINT _nxe_packet_release(NX_PACKET **packet_ptr_ptr); +UINT _nxe_packet_transmit_release(NX_PACKET **packet_ptr_ptr); +#else +UINT _nx_packet_release(NX_PACKET *packet_ptr); +UINT _nx_packet_transmit_release(NX_PACKET *packet_ptr); +#endif + + +UINT nx_rarp_disable(NX_IP *ip_ptr); +UINT nx_rarp_enable(NX_IP *ip_ptr); +UINT nx_rarp_info_get(NX_IP *ip_ptr, ULONG *rarp_requests_sent, ULONG *rarp_responses_received, + ULONG *rarp_invalid_messages); + +VOID nx_system_initialize(VOID); + +UINT nx_tcp_client_socket_bind(NX_TCP_SOCKET *socket_ptr, UINT port, ULONG wait_option); +UINT nx_tcp_client_socket_connect(NX_TCP_SOCKET *socket_ptr, ULONG server_ip, UINT server_port, ULONG wait_option); +UINT nx_tcp_client_socket_port_get(NX_TCP_SOCKET *socket_ptr, UINT *port_ptr); +UINT nx_tcp_client_socket_unbind(NX_TCP_SOCKET *socket_ptr); +UINT nx_tcp_enable(NX_IP *ip_ptr); +UINT nx_tcp_free_port_find(NX_IP *ip_ptr, UINT port, UINT *free_port_ptr); +UINT nx_tcp_info_get(NX_IP *ip_ptr, ULONG *tcp_packets_sent, ULONG *tcp_bytes_sent, + ULONG *tcp_packets_received, ULONG *tcp_bytes_received, + ULONG *tcp_invalid_packets, ULONG *tcp_receive_packets_dropped, + ULONG *tcp_checksum_errors, ULONG *tcp_connections, + ULONG *tcp_disconnections, ULONG *tcp_connections_dropped, + ULONG *tcp_retransmit_packets); +UINT nx_tcp_server_socket_accept(NX_TCP_SOCKET *socket_ptr, ULONG wait_option); +UINT nx_tcp_server_socket_listen(NX_IP *ip_ptr, UINT port, NX_TCP_SOCKET *socket_ptr, UINT listen_queue_size, + VOID (*tcp_listen_callback)(NX_TCP_SOCKET *socket_ptr, UINT port)); +UINT nx_tcp_server_socket_relisten(NX_IP *ip_ptr, UINT port, NX_TCP_SOCKET *socket_ptr); +UINT nx_tcp_server_socket_unaccept(NX_TCP_SOCKET *socket_ptr); +UINT nx_tcp_server_socket_unlisten(NX_IP *ip_ptr, UINT port); +UINT nx_tcp_socket_bytes_available(NX_TCP_SOCKET *socket_ptr, ULONG *bytes_available); +UINT nx_tcp_socket_peer_info_get(NX_TCP_SOCKET *socket_ptr, ULONG *peer_ip_address, ULONG *peer_port); +#ifndef NX_DISABLE_ERROR_CHECKING +UINT _nxe_tcp_socket_create(NX_IP *ip_ptr, NX_TCP_SOCKET *socket_ptr, CHAR *name, + ULONG type_of_service, ULONG fragment, UINT time_to_live, ULONG window_size, + VOID (*tcp_urgent_data_callback)(NX_TCP_SOCKET *socket_ptr), + VOID (*tcp_disconnect_callback)(NX_TCP_SOCKET *socket_ptr), + UINT tcp_socket_size); +#else +UINT _nx_tcp_socket_create(NX_IP *ip_ptr, NX_TCP_SOCKET *socket_ptr, CHAR *name, + ULONG type_of_service, ULONG fragment, UINT time_to_live, ULONG window_size, + VOID (*tcp_urgent_data_callback)(NX_TCP_SOCKET *socket_ptr), + VOID (*tcp_disconnect_callback)(NX_TCP_SOCKET *socket_ptr)); +#endif +UINT nx_tcp_socket_delete(NX_TCP_SOCKET *socket_ptr); +UINT nx_tcp_socket_disconnect(NX_TCP_SOCKET *socket_ptr, ULONG wait_option); +#ifndef NX_DISABLE_EXTENDED_NOTIFY_SUPPORT +UINT nx_tcp_socket_establish_notify(NX_TCP_SOCKET *socket_ptr, VOID (*tcp_establish_notify)(NX_TCP_SOCKET *socket_ptr)); +UINT nx_tcp_socket_disconnect_complete_notify(NX_TCP_SOCKET *socket_ptr, VOID (*tcp_disconnect_complete_notify)(NX_TCP_SOCKET *socket_ptr)); +UINT nx_tcp_socket_timed_wait_callback(NX_TCP_SOCKET *socket_ptr, VOID (*tcp_timed_wait_callback)(NX_TCP_SOCKET *socket_ptr)); +#endif +UINT nx_tcp_socket_info_get(NX_TCP_SOCKET *socket_ptr, ULONG *tcp_packets_sent, ULONG *tcp_bytes_sent, + ULONG *tcp_packets_received, ULONG *tcp_bytes_received, + ULONG *tcp_retransmit_packets, ULONG *tcp_packets_queued, + ULONG *tcp_checksum_errors, ULONG *tcp_socket_state, + ULONG *tcp_transmit_queue_depth, ULONG *tcp_transmit_window, + ULONG *tcp_receive_window); +UINT nx_tcp_socket_mss_get(NX_TCP_SOCKET *socket_ptr, ULONG *mss); +UINT nx_tcp_socket_mss_peer_get(NX_TCP_SOCKET *socket_ptr, ULONG *peer_mss); +UINT nx_tcp_socket_mss_set(NX_TCP_SOCKET *socket_ptr, ULONG mss); +UINT nx_tcp_socket_receive(NX_TCP_SOCKET *socket_ptr, NX_PACKET **packet_ptr, ULONG wait_option); +UINT nx_tcp_socket_receive_notify(NX_TCP_SOCKET *socket_ptr, VOID (*tcp_receive_notify)(NX_TCP_SOCKET *socket_ptr)); +#ifndef NX_DISABLE_ERROR_CHECKING +UINT _nxe_tcp_socket_send(NX_TCP_SOCKET *socket_ptr, NX_PACKET **packet_ptr_ptr, ULONG wait_option); +#else +UINT _nx_tcp_socket_send(NX_TCP_SOCKET *socket_ptr, NX_PACKET *packet_ptr, ULONG wait_option); +#endif +UINT nx_tcp_socket_state_wait(NX_TCP_SOCKET *socket_ptr, UINT desired_state, ULONG wait_option); +UINT nx_tcp_socket_transmit_configure(NX_TCP_SOCKET *socket_ptr, ULONG max_queue_depth, ULONG timeout, + ULONG max_retries, ULONG timeout_shift); +UINT nx_tcp_socket_window_update_notify_set(NX_TCP_SOCKET *socket_ptr, + VOID (*tcp_window_update_notify)(NX_TCP_SOCKET *socket_ptr)); + + +UINT nx_udp_enable(NX_IP *ip_ptr); +UINT nx_udp_free_port_find(NX_IP *ip_ptr, UINT port, UINT *free_port_ptr); +UINT nx_udp_info_get(NX_IP *ip_ptr, ULONG *udp_packets_sent, ULONG *udp_bytes_sent, + ULONG *udp_packets_received, ULONG *udp_bytes_received, + ULONG *udp_invalid_packets, ULONG *udp_receive_packets_dropped, + ULONG *udp_checksum_errors); +UINT nx_udp_packet_info_extract(NX_PACKET *packet_ptr, ULONG *ip_address, UINT *protocol, UINT *port, UINT *interface_index); +UINT nx_udp_socket_bind(NX_UDP_SOCKET *socket_ptr, UINT port, ULONG wait_option); +UINT nx_udp_socket_bytes_available(NX_UDP_SOCKET *socket_ptr, ULONG *bytes_available); +UINT nx_udp_socket_checksum_disable(NX_UDP_SOCKET *socket_ptr); +UINT nx_udp_socket_checksum_enable(NX_UDP_SOCKET *socket_ptr); +#ifndef NX_DISABLE_ERROR_CHECKING +UINT _nxe_udp_socket_create(NX_IP *ip_ptr, NX_UDP_SOCKET *socket_ptr, CHAR *name, + ULONG type_of_service, ULONG fragment, UINT time_to_live, ULONG queue_maximum, UINT udp_socket_size); +UINT _nxe_udp_socket_interface_send(NX_UDP_SOCKET *socket_ptr, NX_PACKET **packet_ptr, ULONG ip_address, UINT port, UINT interface_index); + +#else +UINT _nx_udp_socket_create(NX_IP *ip_ptr, NX_UDP_SOCKET *socket_ptr, CHAR *name, + ULONG type_of_service, ULONG fragment, UINT time_to_live, ULONG queue_maximum); +UINT _nx_udp_socket_interface_send(NX_UDP_SOCKET *socket_ptr, NX_PACKET *packet_ptr, ULONG ip_address, UINT port, UINT interface_index); + +#endif +UINT nx_udp_socket_delete(NX_UDP_SOCKET *socket_ptr); +UINT nx_udp_socket_info_get(NX_UDP_SOCKET *socket_ptr, ULONG *udp_packets_sent, ULONG *udp_bytes_sent, + ULONG *udp_packets_received, ULONG *udp_bytes_received, ULONG *udp_packets_queued, + ULONG *udp_receive_packets_dropped, ULONG *udp_checksum_errors); +UINT nx_udp_socket_port_get(NX_UDP_SOCKET *socket_ptr, UINT *port_ptr); +UINT nx_udp_socket_receive(NX_UDP_SOCKET *socket_ptr, NX_PACKET **packet_ptr, + ULONG wait_option); +UINT nx_udp_socket_receive_notify(NX_UDP_SOCKET *socket_ptr, + VOID (*udp_receive_notify)(NX_UDP_SOCKET *socket_ptr)); +#ifndef NX_DISABLE_ERROR_CHECKING +UINT _nxe_udp_socket_send(NX_UDP_SOCKET *socket_ptr, NX_PACKET **packet_ptr_ptr, + ULONG ip_address, UINT port); +#else +UINT _nx_udp_socket_send(NX_UDP_SOCKET *socket_ptr, NX_PACKET *packet_ptr, + ULONG ip_address, UINT port); +#endif +UINT nx_udp_socket_unbind(NX_UDP_SOCKET *socket_ptr); +UINT nx_udp_source_extract(NX_PACKET *packet_ptr, ULONG *ip_address, UINT *port); + + +/* Define several function prototypes for exclusive use by NetX I/O drivers. These routines + are used by NetX drivers to report received packets to NetX. */ + +/* Define the driver deferred packet routines. Using these routines results in the lowest + possible ISR processing time. However, it does require slightly more overhead than the + other NetX receive processing routines. The _nx_ip_driver_deferred_enable routine + should be called from the driver's initialization routine, with the driver's deferred + packet processing routine provided. Each packet the driver receives should be + delivered to NetX via the _nx_ip_driver_deferred_receive function. This function + queues the packet for the NetX IP thread. The NetX IP thread will then call the driver's + deferred packet processing routine, which can then process the packet at a thread level + of execution. The deferred packet processing routine should use the _nx_ip_packet_receive, + _nx_arp_packet_deferred_receive, and _nx_rarp_packet_deferred_receive to dispatch the + appropriate packets to NetX. In order to use the deferred packet processing, NetX + must be built with NX_DRIVER_DEFERRED_PROCESSING defined. */ + +VOID _nx_ip_driver_deferred_enable(NX_IP *ip_ptr, VOID (*driver_deferred_packet_handler)(NX_IP *ip_ptr, NX_PACKET *packet_ptr)); +VOID _nx_ip_driver_deferred_receive(NX_IP *ip_ptr, NX_PACKET *packet_ptr); + + +/* Define the driver deferred processing notification routine. Calling this routine from + the driver will cause the driver to be called with the NX_LINK_DEFERRED_PROCESSING + value specified in the nx_ip_driver_command field of the NX_IP_DRIVER request + structure. This is useful in situations where the driver wishes to process activities + like transmit complete interrupts at the thread level rather than in the ISR. Note + that the driver must set its own internal variables in order to know what processing + needs to be done when subsequently called from the IP helper thread. */ + +VOID _nx_ip_driver_deferred_processing(NX_IP *ip_ptr); + + +/* Define the deferred NetX receive processing routines. These routines depend on the + NetX I/O drive to perform enough processing in the ISR to strip the link protocol + header and dispatch to the appropriate NetX receive processing. These routines + can also be called from the previously mentioned driver deferred processing. */ + +VOID _nx_ip_packet_deferred_receive(NX_IP *ip_ptr, NX_PACKET *packet_ptr); +VOID _nx_arp_packet_deferred_receive(NX_IP *ip_ptr, NX_PACKET *packet_ptr); +VOID _nx_rarp_packet_deferred_receive(NX_IP *ip_ptr, NX_PACKET *packet_ptr); + + +/* Define the direct IP packet receive processing. This is the lowest overhead way + to notify NetX of a received IP packet, however, it results in the most amount of + processing in the driver's receive ISR. If the driver deferred packet processing + is used, this routine should be used to notify NetX of the newly received IP packet. */ + +VOID _nx_ip_packet_receive(NX_IP *ip_ptr, NX_PACKET *packet_ptr); + +/* Define the direct link status event. This is the lowest overhead way + to notify NetX of link status event, however, it results in the most amount of + processing in the driver's receive ISR. */ +VOID _nx_ip_driver_link_status_event(NX_IP *ip_ptr, UINT interface_index); +#endif + + +#ifdef NX_ENABLE_IP_STATIC_ROUTING +#define nx_ip_static_routing_enable(a) (NX_SUCCESS) +#define nx_ip_static_routing_disable(a) (NX_SUCCESS) +#else /* !NX_ENABLE_IP_STATIC_ROUTING */ +#define nx_ip_static_routing_enable(a) (NX_NOT_IMPLEMENTED) +#define nx_ip_static_routing_disable(a) (NX_NOT_IMPLEMENTED) +#endif /* NX_ENABLE_IP_STATIC_ROUTING */ + +/* Utility functions. */ +UINT _nx_utility_string_length_check(CHAR *input_string, UINT *string_length, UINT max_string_length); + +/* Determine if a C++ compiler is being used. If so, complete the standard + C conditional started above. */ +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/common/inc/nx_arp.h b/common/inc/nx_arp.h new file mode 100644 index 0000000..60a053f --- /dev/null +++ b/common/inc/nx_arp.h @@ -0,0 +1,154 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Address Resolution Protocol (ARP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* COMPONENT DEFINITION RELEASE */ +/* */ +/* nx_arp.h PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file defines the NetX Address Resolution Protocol 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_ARP_H +#define NX_ARP_H + + +/* Define ARP Message format. This will get encapsulated by an Ethernet frame + as well. The Ethernet frame will typically have a 6-byte Ethernet destination + address, a 6-byte Ethernet source address, and a 2-byte Ethernet Frame type, + which is 0x0806. Regular IP frames have a frame type of 0x0800. + + Byte offset Size Meaning + + 0 2 Hardware type (1 for Ethernet) + 2 2 Protocol type (0x0800 for IP) + 4 1 Number of bytes for hardware address (6 for Ethernet) + 5 1 Number of bytes for IP address (4 for IP) + 6 2 Operation, ARP request is 1, ARP reply is 2 + 8 6 Sender's Ethernet Address + 14 4 Sender's IP Address + 18 6 Target Ethernet Address + 24 4 Target IP Address + */ + +#define NX_ARP_HARDWARE_TYPE ((ULONG)0x0001) +#define NX_ARP_PROTOCOL_TYPE ((ULONG)0x0800) +#define NX_ARP_HARDWARE_SIZE ((ULONG)0x06) +#define NX_ARP_PROTOCOL_SIZE ((ULONG)0x04) +#define NX_ARP_OPTION_REQUEST ((ULONG)0x0001) +#define NX_ARP_OPTION_RESPONSE ((ULONG)0x0002) +#define NX_ARP_MESSAGE_SIZE 28 + + +/* Define the ARP defend interval. The default value is 10 seconds. */ +#ifndef NX_ARP_DEFEND_INTERVAL +#define NX_ARP_DEFEND_INTERVAL 10 +#endif /* NX_ARP_DEFEND_INTERVAL */ + + +/* Define ARP function prototypes. */ + +VOID _nx_arp_initialize(VOID); +UINT _nx_arp_dynamic_entries_invalidate(NX_IP *ip_ptr); +UINT _nx_arp_dynamic_entry_set(NX_IP *ip_ptr, ULONG ip_address, + ULONG physical_msw, ULONG physical_lsw); +UINT _nx_arp_enable(NX_IP *ip_ptr, VOID *arp_cache_memory, ULONG arp_cache_size); +UINT _nx_arp_gratuitous_send(NX_IP *ip_ptr, VOID (*response_handler)(NX_IP *ip_ptr, NX_PACKET *packet_ptr)); +UINT _nx_arp_hardware_address_find(NX_IP *ip_ptr, ULONG ip_address, + ULONG *physical_msw, ULONG *physical_lsw); +UINT _nx_arp_info_get(NX_IP *ip_ptr, ULONG *arp_requests_sent, ULONG *arp_requests_received, + ULONG *arp_responses_sent, ULONG *arp_responses_received, + ULONG *arp_dynamic_entries, ULONG *arp_static_entries, + ULONG *arp_aged_entries, ULONG *arp_invalid_messages); +UINT _nx_arp_ip_address_find(NX_IP *ip_ptr, ULONG *ip_address, + ULONG physical_msw, ULONG physical_lsw); +VOID _nx_arp_queue_process(NX_IP *ip_ptr); +UINT _nx_arp_static_entries_delete(NX_IP *ip_ptr); +UINT _nx_arp_static_entry_create(NX_IP *ip_ptr, ULONG ip_address, + ULONG physical_msw, ULONG physical_lsw); +UINT _nx_arp_static_entry_delete(NX_IP *ip_ptr, ULONG ip_address, + ULONG physical_msw, ULONG physical_lsw); +UINT _nx_arp_entry_allocate(NX_IP *ip_ptr, NX_ARP **arp_ptr); +VOID _nx_arp_packet_send(NX_IP *ip_ptr, ULONG destination_ip, NX_INTERFACE *nx_interface); +VOID _nx_arp_packet_receive(NX_IP *ip_ptr, NX_PACKET *packet_ptr); +VOID _nx_arp_packet_deferred_receive(NX_IP *ip_ptr, NX_PACKET *packet_ptr); +VOID _nx_arp_periodic_update(NX_IP *ip_ptr); +UINT _nx_arp_probe_send(NX_IP *ip_ptr, UINT interface_index, ULONG probe_address); +UINT _nx_arp_announce_send(NX_IP *ip_ptr, UINT interface_index); + + +/* Define error checking shells for ARP services. These are only referenced by the + application. */ + +UINT _nxe_arp_dynamic_entries_invalidate(NX_IP *ip_ptr); +UINT _nxe_arp_dynamic_entry_set(NX_IP *ip_ptr, ULONG ip_address, + ULONG physical_msw, ULONG physical_lsw); +UINT _nxe_arp_enable(NX_IP *ip_ptr, VOID *arp_cache_memory, ULONG arp_cache_size); +UINT _nxe_arp_gratuitous_send(NX_IP *ip_ptr, VOID (*response_handler)(NX_IP *ip_ptr, NX_PACKET *packet_ptr)); +UINT _nxe_arp_hardware_address_find(NX_IP *ip_ptr, ULONG ip_address, + ULONG *physical_msw, ULONG *physical_lsw); +UINT _nxe_arp_info_get(NX_IP *ip_ptr, ULONG *arp_requests_sent, ULONG *arp_requests_received, + ULONG *arp_responses_sent, ULONG *arp_responses_received, + ULONG *arp_dynamic_entries, ULONG *arp_static_entries, + ULONG *arp_aged_entries, ULONG *arp_invalid_messages); +UINT _nxe_arp_ip_address_find(NX_IP *ip_ptr, ULONG *ip_address, + ULONG physical_msw, ULONG physical_lsw); +VOID _nxe_arp_queue_process(NX_IP *ip_ptr); +UINT _nxe_arp_static_entries_delete(NX_IP *ip_ptr); +UINT _nxe_arp_static_entry_create(NX_IP *ip_ptr, ULONG ip_address, + ULONG physical_msw, ULONG physical_lsw); +UINT _nxe_arp_static_entry_delete(NX_IP *ip_ptr, ULONG ip_address, + ULONG physical_msw, ULONG physical_lsw); + + +/* ARP management component data declarations follow. */ + +/* Determine if the initialization function of this component is including + this file. If so, make the data definitions really happen. Otherwise, + make them extern so other functions in the component can access them. */ + +#ifdef NX_ARP_INIT +#define ARP_DECLARE +#else +#define ARP_DECLARE extern +#endif + + +#endif + diff --git a/common/inc/nx_icmp.h b/common/inc/nx_icmp.h new file mode 100644 index 0000000..b5d210e --- /dev/null +++ b/common/inc/nx_icmp.h @@ -0,0 +1,186 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Control Message Protocol (ICMP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* COMPONENT DEFINITION RELEASE */ +/* */ +/* nx_icmp.h PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file defines the NetX Internet Control Message Protocol (ICMP) */ +/* 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_ICMP_H +#define NX_ICMP_H + + +/* Define ICMP types and codes. */ + +#define NX_ICMP_ECHO_REPLY_TYPE 0 +#define NX_ICMP_DEST_UNREACHABLE_TYPE 3 +#define NX_ICMP_SOURCE_QUENCH_TYPE 4 +#define NX_ICMP_REDIRECT_TYPE 5 +#define NX_ICMP_ECHO_REQUEST_TYPE 8 +#define NX_ICMP_TIME_EXCEEDED_TYPE 11 +#define NX_ICMP_PARAMETER_PROB_TYPE 12 +#define NX_ICMP_TIMESTAMP_REQ_TYPE 13 +#define NX_ICMP_TIMESTAMP_REP_TYPE 14 +#define NX_ICMP_ADDRESS_MASK_REQ_TYPE 17 +#define NX_ICMP_ADDRESS_MASK_REP_TYPE 18 + +#define NX_ICMP_NETWORK_UNREACH_CODE 0 +#define NX_ICMP_HOST_UNREACH_CODE 1 +#define NX_ICMP_PROTOCOL_UNREACH_CODE 2 +#define NX_ICMP_PORT_UNREACH_CODE 3 +#define NX_ICMP_FRAMENT_NEEDED_CODE 4 +#define NX_ICMP_SOURCE_ROUTE_CODE 5 +#define NX_ICMP_NETWORK_UNKNOWN_CODE 6 +#define NX_ICMP_HOST_UNKNOWN_CODE 7 +#define NX_ICMP_SOURCE_ISOLATED_CODE 8 +#define NX_ICMP_NETWORK_PROHIBIT_CODE 9 +#define NX_ICMP_HOST_PROHIBIT_CODE 10 +#define NX_ICMP_NETWORK_SERVICE_CODE 11 +#define NX_ICMP_HOST_SERVICE_CODE 12 + +/* Define Basic ICMP packet header data type. This will be used to + build new ICMP packets and to examine incoming packets into NetX. */ + +typedef struct NX_ICMP_HEADER_STRUCT +{ + /* Define the first 32-bit word of the ICMP header. This word contains + the following information: + + bits 31-24 ICMP 8-bit type defined as follows: + + Type Field ICMP Message Type + + 0 Echo Reply + 3 Destination Unreachable + 4 Source Quench + 5 Redirect (change a route) + 8 Echo Request + 11 Time exceeded for Datagram + 12 Parameter Problem on a Datagram + 13 Timestamp Request + 14 Timestamp Reply + 17 Address Mask Request + 18 Address Mask Reply + + bits 23-16 ICMP 8-bit code defined as follows: + + Code Field ICMP Code Meaning + + 0 Network unreachable + 1 Host unreachable + 2 Protocol unreachable + 3 Port unreachable + 4 Fragmentation needed and DF is set + 5 Source route failed + 6 Destination network unknown + 7 Destination host unknown + 8 Source host isolated + 9 Communication with destination network + administratively prohibited + 10 Communication with destination host + administratively prohibited + 11 Network unreachable for type of service + 12 Host unreachable for type of service + + bits 15-0 ICMP 16-bit checksum + + */ + + ULONG nx_icmp_header_word_0; + + /* Define the second and final word of the ICMP header. This word contains + the following information: + + bits 31-16 ICMP 16-bit Identification + bits 15-0 ICMP 16-bit Sequence Number + */ + ULONG nx_icmp_header_word_1; +} NX_ICMP_HEADER; + + +/* Define the ICMP echo request header message size. */ + +#define NX_ICMP_HEADER_SIZE sizeof(NX_ICMP_HEADER) + + +/* Define ICMP function prototypes. */ + +UINT _nx_icmp_enable(NX_IP *ip_ptr); +UINT _nx_icmp_info_get(NX_IP *ip_ptr, ULONG *pings_sent, ULONG *ping_timeouts, + ULONG *ping_threads_suspended, ULONG *ping_responses_received, + ULONG *icmp_checksum_errors, ULONG *icmp_unhandled_messages); +UINT _nx_icmp_ping(NX_IP *ip_ptr, ULONG ip_address, CHAR *data, ULONG data_size, + NX_PACKET **response_ptr, ULONG wait_option); +VOID _nx_icmp_initialize(VOID); +VOID _nx_icmp_cleanup(TX_THREAD *thread_ptr NX_CLEANUP_PARAMETER); +VOID _nx_icmp_packet_receive(NX_IP *ip_ptr, NX_PACKET *packet_ptr); +VOID _nx_icmp_queue_process(NX_IP *ip_ptr); +VOID _nx_icmp_packet_process(NX_IP *ip_ptr, NX_PACKET *packet_ptr); +ULONG _nx_icmp_checksum_compute(NX_PACKET *packet_ptr); + + +/* Define error checking shells for API services. These are only referenced by the + application. */ + +UINT _nxe_icmp_enable(NX_IP *ip_ptr); +UINT _nxe_icmp_info_get(NX_IP *ip_ptr, ULONG *pings_sent, ULONG *ping_timeouts, + ULONG *ping_threads_suspended, ULONG *ping_responses_received, + ULONG *icmp_checksum_errors, ULONG *icmp_unhandled_messages); +UINT _nxe_icmp_ping(NX_IP *ip_ptr, ULONG ip_address, CHAR *data, ULONG data_size, + NX_PACKET **response_ptr, ULONG wait_option); + + + +/* ICMP component data declarations follow. */ + +/* Determine if the initialization function of this component is including + this file. If so, make the data definitions really happen. Otherwise, + make them extern so other functions in the component can access them. */ + +#ifdef NX_ICMP_INIT +#define ICMP_DECLARE +#else +#define ICMP_DECLARE extern +#endif + +#endif + diff --git a/common/inc/nx_igmp.h b/common/inc/nx_igmp.h new file mode 100644 index 0000000..c8a6ffd --- /dev/null +++ b/common/inc/nx_igmp.h @@ -0,0 +1,211 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Group Management Protocol (IGMP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* COMPONENT DEFINITION RELEASE */ +/* */ +/* nx_igmp.h PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file defines the NetX Internet Group Management Protocol (IGMP)*/ +/* 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_IGMP_H +#define NX_IGMP_H + + +/* Define IGMP types and codes. */ + +/* IGMPv2 combines version field with the type field ffectively, and calls the 8 bit + field the Type field. IGMPv2 uses Type 0x11, 0x16, and 0x17 in this field, while + IGMPv1 uses Type 1 and 2 in the lower 4 bits, combined with version 1 in the upper 4 bits + for 0x11 and 0x12 as the possible values. */ + + +/* Define the IGMP version in the IGMP header. */ + +#define NX_IGMP_VERSION 0x10000000 + + +/* Define the numeric version of IGMP protocol used by NetX. */ + +#define NX_IGMP_HOST_VERSION_1 1 +#define NX_IGMP_HOST_VERSION_2 2 + + +/* Define the IGMP query message type and mask in the IGMP header. */ + +#define NX_IGMP_ROUTER_QUERY_TYPE 0x01000000 +#define NX_IGMP_TYPE_MASK 0x0F000000 + + +/* Define the IGMPv1 type for membership join reports. */ + +#define NX_IGMP_HOST_RESPONSE_TYPE 0x02000000 + + +/* Define IGMPv2 types for membership join and leave reports. */ + +#define NX_IGMP_HOST_V2_JOIN_TYPE 0x16000000 +#define NX_IGMP_HOST_V2_LEAVE_TYPE 0x17000000 + + +/* Define the IGMPv2 type mask in the IGMP header. */ + +#define NX_IGMPV2_TYPE_MASK 0xFF000000 + + +/* Define the IGMPv2 maximum response time mask in the IGMP header. Max value is 0x64, + left intentionally blank in IGMPv1 queries and all IGMP reports. Maximum response time + is in tenth's of a second. */ + +#define NX_IGMP_MAX_RESP_TIME_MASK 0x00FF0000 + + +/* For IGMPv1 only, define the IGMP maximum delay time to 10 seconds as per RFC 1112. This is achieved if + the slow NetX IP periodic thread timer executes every second (e.g. NX_IP_PERIODIC_RATE is set to 100) + and the threadx timer interrupt occurs every 10 ms). */ + +#define NX_IGMP_MAX_UPDATE_TIME 10 + + +/* Define the time to live for IGMP packets. RFC 1112 and 2236 specify + time to live should be set at 1. */ + +#define NX_IGMP_TTL 1 + + +/* Define the mask for IGMPv1 packets' type field. */ + +#define NX_IGMP_TYPE_MASK 0x0F000000 + + +/* Define the IP "all hosts" multicast address. */ + +#define NX_ALL_HOSTS_ADDRESS IP_ADDRESS(224, 0, 0, 1) + + +/* Define the IP "all routers" multicast address. */ + +#define NX_ALL_ROUTERS_ADDRESS IP_ADDRESS(224, 0, 0, 2) + + +/* Define Basic IGMP packet header data type. This will be used to + build new IGMP packets and to examine incoming IGMP queries sent + to NetX. */ + +typedef struct NX_IGMP_HEADER_STRUCT +{ + /* Define the first 32-bit word of the IGMP header. This word contains + the following information: + + bits 31-28 IGMP 4-bit version (Version 1) + + bits 27-24 IGMP 4-bit type defined as follows: + + Type Field IGMP Message Type + + 1 Router Query Request + 2 Host Query Response + + bits 15-0 IGMP 16-bit checksum + + */ + + ULONG nx_igmp_header_word_0; + + /* Define the second and final word of the IGMP header. This word contains + the following information: + + bits 31-0 32-bit group address (class D IP address) + */ + ULONG nx_igmp_header_word_1; +} NX_IGMP_HEADER; + + +/* Define the IGMP query response message size. */ + +#define NX_IGMP_HEADER_SIZE sizeof(NX_IGMP_HEADER) + + +/* Define IGMP function prototypes. */ + +UINT _nx_igmp_enable(NX_IP *ip_ptr); +UINT _nx_igmp_info_get(NX_IP *ip_ptr, ULONG *igmp_reports_sent, ULONG *igmp_queries_received, + ULONG *igmp_checksum_errors, ULONG *current_groups_joined); +UINT _nx_igmp_loopback_disable(NX_IP *ip_ptr); +UINT _nx_igmp_loopback_enable(NX_IP *ip_ptr); +UINT _nx_igmp_multicast_join(NX_IP *ip_ptr, ULONG group_address); +UINT _nx_igmp_multicast_interface_join(NX_IP *ip_ptr, ULONG group_address, UINT nx_interface_index); +UINT _nx_igmp_multicast_leave(NX_IP *ip_ptr, ULONG group_address); +VOID _nx_igmp_initialize(VOID); +UINT _nx_igmp_interface_report_send(NX_IP *ip_ptr, ULONG group_address, UINT interface_index, UINT is_joining); +VOID _nx_igmp_periodic_processing(NX_IP *ip_ptr); +VOID _nx_igmp_packet_process(NX_IP *ip_ptr, NX_PACKET *packet_ptr); +VOID _nx_igmp_packet_receive(NX_IP *ip_ptr, NX_PACKET *packet_ptr); +VOID _nx_igmp_queue_process(NX_IP *ip_ptr); +UINT _nx_igmp_multicast_check(NX_IP *ip_ptr, ULONG group_address, NX_INTERFACE *nx_interface); + + +/* Define error checking shells for API services. These are only referenced by the + application. */ + +UINT _nxe_igmp_enable(NX_IP *ip_ptr); +UINT _nxe_igmp_info_get(NX_IP *ip_ptr, ULONG *igmp_reports_sent, ULONG *igmp_queries_received, + ULONG *igmp_checksum_errors, ULONG *current_groups_joined); +UINT _nxe_igmp_loopback_disable(NX_IP *ip_ptr); +UINT _nxe_igmp_loopback_enable(NX_IP *ip_ptr); +UINT _nxe_igmp_multicast_join(NX_IP *ip_ptr, ULONG group_address); +UINT _nxe_igmp_multicast_interface_join(NX_IP *ip_ptr, ULONG group_address, UINT nx_interface_index); +UINT _nxe_igmp_multicast_leave(NX_IP *ip_ptr, ULONG group_address); + + +/* IGMP component data declarations follow. */ + +/* Determine if the initialization function of this component is including + this file. If so, make the data definitions really happen. Otherwise, + make them extern so other functions in the component can access them. */ + +#ifdef NX_IGMP_INIT +#define IGMP_DECLARE +#else +#define IGMP_DECLARE extern +#endif + +#endif + diff --git a/common/inc/nx_ip.h b/common/inc/nx_ip.h new file mode 100644 index 0000000..e52cffb --- /dev/null +++ b/common/inc/nx_ip.h @@ -0,0 +1,300 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* COMPONENT DEFINITION RELEASE */ +/* */ +/* nx_ip.h PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file defines the NetX Internet Protocol 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_IP_H +#define NX_IP_H + + +/* Define IP constants. */ + +#define NX_IP_ID ((ULONG)0x49502020) + + +/* Define basic IP Header constant. */ + +#define NX_IP_VERSION ((ULONG)0x45000000) /* Version 4, Length of 5 */ + + +/* Define the mask for the IP header length field. */ + +#define NX_IP_LENGTH_MASK ((ULONG)0x0F000000) /* Mask for length bit */ +#define NX_IP_NORMAL_LENGTH 5 /* Normal IP header length */ + + +/* Define IP fragmenting information. */ + +#define NX_IP_DONT_FRAGMENT ((ULONG)0x00004000) /* Don't fragment bit */ +#define NX_IP_MORE_FRAGMENT ((ULONG)0x00002000) /* More fragments */ +#define NX_IP_FRAGMENT_MASK ((ULONG)0x00003FFF) /* Mask for fragment bits */ +#define NX_IP_OFFSET_MASK ((ULONG)0x00001FFF) /* Mask for fragment offset */ +#define NX_IP_ALIGN_FRAGS 8 /* Fragment alignment */ + + +/* Define IP event flags. These events are processed by the IP thread. */ + +#define NX_IP_ALL_EVENTS ((ULONG)0xFFFFFFFF) /* All event flags */ +#define NX_IP_PERIODIC_EVENT ((ULONG)0x00000001) /* Periodic ARP event */ +#define NX_IP_UNFRAG_EVENT ((ULONG)0x00000002) /* Unfragment event */ +#define NX_IP_ICMP_EVENT ((ULONG)0x00000004) /* ICMP message event */ +#define NX_IP_RECEIVE_EVENT ((ULONG)0x00000008) /* IP receive packet event */ +#define NX_IP_ARP_REC_EVENT ((ULONG)0x00000010) /* ARP deferred receive event */ +#define NX_IP_RARP_REC_EVENT ((ULONG)0x00000020) /* RARP deferred receive event */ +#define NX_IP_IGMP_EVENT ((ULONG)0x00000040) /* IGMP message event */ +#define NX_IP_TCP_EVENT ((ULONG)0x00000080) /* TCP message event */ +#define NX_IP_TCP_FAST_EVENT ((ULONG)0x00000100) /* Fast TCP timer event */ +#define NX_IP_DRIVER_PACKET_EVENT ((ULONG)0x00000200) /* Driver Deferred packet event */ +#define NX_IP_IGMP_ENABLE_EVENT ((ULONG)0x00000400) /* IGMP enable event */ +#define NX_IP_DRIVER_DEFERRED_EVENT ((ULONG)0x00000800) /* Driver deferred processing */ + /* event */ +#define NX_IP_TCP_CLEANUP_DEFERRED ((ULONG)0x00001000) /* Deferred TCP cleanup event */ +#define NX_IP_LINK_STATUS_EVENT ((ULONG)0x00002000) /* Link status change event */ + + +#ifndef NX_IP_DEBUG_LOG_SIZE +#define NX_IP_DEBUG_LOG_SIZE 100 /* Maximum size of optional log */ +#endif + + +/* Define the amount of time to sleep in nx_ip_(interface_)status_check */ + +#ifndef NX_IP_STATUS_CHECK_WAIT_TIME +#define NX_IP_STATUS_CHECK_WAIT_TIME 1 +#endif /* NX_IP_STATUS_CHECK_WAIT_TIME */ + + +/* Define Basic Internet packet header data type. This will be used to + build new IP packets and to examine incoming packets into NetX. */ + +typedef struct NX_IP_HEADER_STRUCT +{ + /* Define the first 32-bit word of the IP header. This word contains + the following information: + + bits 31-28 IP Version = 0x4 (IP Version4) + bits 27-24 IP Header Length of 32-bit words (5 if no options) + bits 23-16 IP Type of Service, where 0x00 -> Normal + 0x10 -> Minimize Delay + 0x08 -> Maximize Throughput + 0x04 -> Maximize Reliability + 0x02 -> Minimize Monetary Cost + bits 15-0 IP Datagram length in bytes + */ + ULONG nx_ip_header_word_0; + + /* Define the second word of the IP header. This word contains + the following information: + + bits 31-16 IP Packet Identification (just an incrementing number) + bits 15-0 IP Flags and Fragment Offset (used for IP fragmenting) + bit 15 Zero + bit 14 Don't Fragment + bit 13 More Fragments + bits 12-0 (Fragment offset)/8 + */ + ULONG nx_ip_header_word_1; + + /* Define the third word of the IP header. This word contains + the following information: + + bits 31-24 IP Time-To-Live (maximum number of routers + packet can traverse before being + thrown away. Default values are typically + 32 or 64) + bits 23-16 IP Protocol, where 0x01 -> ICMP Messages + 0x02 -> IGMP Messages + 0x06 -> TCP Messages + 0x11 -> UDP Messages + bits 15-0 IP Checksum + */ + ULONG nx_ip_header_word_2; + + /* Define the source IP address. */ + ULONG nx_ip_header_source_ip; + + /* Define the destination IP address. */ + ULONG nx_ip_header_destination_ip; +} NX_IP_HEADER; + + +/* Define IP function prototypes. */ + +UINT _nx_ip_address_change_notify(NX_IP *ip_ptr, VOID (*ip_address_change_notify)(NX_IP *, VOID *), VOID *additional_info); +UINT _nx_ip_address_get(NX_IP *ip_ptr, ULONG *ip_address, ULONG *network_mask); +UINT _nx_ip_address_set(NX_IP *ip_ptr, ULONG ip_address, ULONG network_mask); +UINT _nx_ip_interface_address_get(NX_IP *ip_ptr, ULONG interface_index, ULONG *ip_address, ULONG *network_mask); +UINT _nx_ip_interface_address_set(NX_IP *ip_ptr, ULONG interface_index, ULONG ip_address, ULONG network_mask); +UINT _nx_ip_interface_info_get(NX_IP *ip_ptr, UINT interface_index, CHAR **interface_name, ULONG *ip_address, + ULONG *network_mask, ULONG *mtu_size, ULONG *phsyical_address_msw, + ULONG *physical_address_lsw); +UINT _nx_ip_interface_status_check(NX_IP *ip_ptr, UINT interface_index, ULONG needed_status, ULONG *actual_status, + ULONG wait_option); +UINT _nx_ip_create(NX_IP *ip_ptr, CHAR *name, ULONG ip_address, ULONG network_mask, + NX_PACKET_POOL *default_pool, + VOID (*ip_link_driver)(NX_IP_DRIVER *), + VOID *memory_ptr, ULONG memory_size, UINT priority); +UINT _nx_ip_delete(NX_IP *ip_ptr); +VOID _nx_ip_delete_queue_clear(NX_PACKET *head_ptr); +VOID _nx_ip_deferred_link_status_process(NX_IP *ip_ptr); +VOID _nx_ip_driver_link_status_event(NX_IP *ip_ptr, UINT interface_index); +VOID _nx_ip_driver_deferred_enable(NX_IP *ip_ptr, VOID (*driver_deferred_packet_handler)(NX_IP *ip_ptr, NX_PACKET *packet_ptr)); +VOID _nx_ip_driver_deferred_processing(NX_IP *ip_ptr); +VOID _nx_ip_driver_deferred_receive(NX_IP *ip_ptr, NX_PACKET *packet_ptr); +UINT _nx_ip_driver_direct_command(NX_IP *ip_ptr, UINT command, ULONG *return_value_ptr); +UINT _nx_ip_driver_interface_direct_command(NX_IP *ip_ptr, UINT command, UINT interface_index, ULONG *return_value_ptr); +UINT _nx_ip_forwarding_disable(NX_IP *ip_ptr); +UINT _nx_ip_forwarding_enable(NX_IP *ip_ptr); +UINT _nx_ip_fragment_disable(NX_IP *ip_ptr); +UINT _nx_ip_fragment_enable(NX_IP *ip_ptr); +UINT _nx_ip_gateway_address_set(NX_IP *ip_ptr, ULONG ip_address); +UINT _nx_ip_info_get(NX_IP *ip_ptr, ULONG *ip_total_packets_sent, ULONG *ip_total_bytes_sent, + ULONG *ip_total_packets_received, ULONG *ip_total_bytes_received, + ULONG *ip_invalid_packets, ULONG *ip_receive_packets_dropped, + ULONG *ip_receive_checksum_errors, ULONG *ip_send_packets_dropped, + ULONG *ip_total_fragments_sent, ULONG *ip_total_fragments_received); +UINT _nx_ip_interface_attach(NX_IP *ip_ptr, CHAR *interface_name, ULONG ip_address, ULONG network_mask, VOID (*ip_link_driver)(struct NX_IP_DRIVER_STRUCT *)); +UINT _nx_ip_raw_packet_disable(NX_IP *ip_ptr); +UINT _nx_ip_raw_packet_enable(NX_IP *ip_ptr); +UINT _nx_ip_raw_packet_receive(NX_IP *ip_ptr, NX_PACKET **packet_ptr, ULONG wait_option); +UINT _nx_ip_raw_packet_send(NX_IP *ip_ptr, NX_PACKET *packet_ptr, + ULONG destination_ip, ULONG type_of_service); +UINT _nx_ip_raw_packet_interface_send(NX_IP *ip_ptr, NX_PACKET *packet_ptr, + ULONG destination_ip, UINT interface_index, ULONG type_of_service); +VOID _nx_ip_initialize(VOID); +VOID _nx_ip_forward_packet_process(NX_IP *ip_ptr, NX_PACKET *packet_ptr); +VOID _nx_ip_fragment_timeout_check(NX_IP *ip_ptr); +VOID _nx_ip_loopback_send(NX_IP *ip_ptr, NX_PACKET *packet_ptr, UINT packet_release); +ULONG _nx_ip_route_find(NX_IP *ip_ptr, ULONG destination_address, NX_INTERFACE **nx_ip_interface, ULONG *next_hop_address); +VOID _nx_ip_periodic_timer_entry(ULONG ip_address); +VOID _nx_ip_packet_send(NX_IP *ip_ptr, NX_PACKET *packet_ptr, ULONG destination_ip, ULONG type_of_service, ULONG time_to_live, ULONG protocol, ULONG fragment); +VOID _nx_ip_packet_receive(NX_IP *ip_ptr, NX_PACKET *packet_ptr); +VOID _nx_ip_packet_deferred_receive(NX_IP *ip_ptr, NX_PACKET *packet_ptr); +UINT _nx_ip_status_check(NX_IP *ip_ptr, ULONG needed_status, ULONG *actual_status, + ULONG wait_option); +UINT _nx_ip_link_status_change_notify_set(NX_IP *ip_ptr, VOID (*link_status_change_notify)(NX_IP *ip_ptr, UINT interface_index, UINT link_up)); +VOID _nx_ip_thread_entry(ULONG ip_ptr_value); +VOID _nx_ip_raw_packet_cleanup(TX_THREAD *thread_ptr NX_CLEANUP_PARAMETER); +VOID _nx_ip_raw_packet_processing(NX_IP *ip_ptr, NX_PACKET *packet_ptr); +VOID _nx_ip_fragment_packet(struct NX_IP_DRIVER_STRUCT *driver_req_ptr); +VOID _nx_ip_fragment_assembly(NX_IP *ip_ptr); + +UINT _nx_ip_static_route_add(NX_IP *ip_ptr, ULONG network_address, ULONG net_mask, ULONG next_hop); +UINT _nx_ip_static_route_delete(NX_IP *ip_ptr, ULONG network_address, ULONG net_mask); +ULONG _nx_ip_static_route_find(NX_IP *ip_ptr, ULONG destination_address); + +/* Define error checking shells for API services. These are only referenced by the + application. */ + +UINT _nxe_ip_address_change_notify(NX_IP *ip_ptr, VOID (*ip_address_change_notify)(NX_IP *, VOID *), VOID *additional_info); +UINT _nxe_ip_address_get(NX_IP *ip_ptr, ULONG *ip_address, ULONG *network_mask); +UINT _nxe_ip_address_set(NX_IP *ip_ptr, ULONG ip_address, ULONG network_mask); +UINT _nxe_ip_interface_address_get(NX_IP *ip_ptr, ULONG interface_index, ULONG *ip_address, ULONG *network_mask); +UINT _nxe_ip_interface_address_set(NX_IP *ip_ptr, ULONG interface_index, ULONG ip_address, ULONG network_mask); +UINT _nxe_ip_interface_info_get(NX_IP *ip_ptr, UINT interface_index, CHAR **interface_name, ULONG *ip_address, + ULONG *network_mask, ULONG *mtu_size, ULONG *phsyical_address_msw, + ULONG *physical_address_lsw); +UINT _nxe_ip_interface_status_check(NX_IP *ip_ptr, UINT interface_index, ULONG needed_status, ULONG *actual_status, + ULONG wait_option); +UINT _nxe_ip_create(NX_IP *ip_ptr, CHAR *name, ULONG ip_address, ULONG network_mask, + NX_PACKET_POOL *default_pool, + VOID (*ip_link_driver)(NX_IP_DRIVER *), + VOID *memory_ptr, ULONG memory_size, UINT priority, UINT ip_control_block_size); +UINT _nxe_ip_delete(NX_IP *ip_ptr); +UINT _nxe_ip_driver_direct_command(NX_IP *ip_ptr, UINT command, ULONG *return_value_ptr); +UINT _nxe_ip_driver_interface_direct_command(NX_IP *ip_ptr, UINT command, UINT interface_index, ULONG *return_value_ptr); +UINT _nxe_ip_forwarding_disable(NX_IP *ip_ptr); +UINT _nxe_ip_forwarding_enable(NX_IP *ip_ptr); +UINT _nxe_ip_fragment_disable(NX_IP *ip_ptr); +UINT _nxe_ip_fragment_enable(NX_IP *ip_ptr); +UINT _nxe_ip_gateway_address_set(NX_IP *ip_ptr, ULONG ip_address); +UINT _nxe_ip_info_get(NX_IP *ip_ptr, ULONG *ip_total_packets_sent, ULONG *ip_total_bytes_sent, + ULONG *ip_total_packets_received, ULONG *ip_total_bytes_received, + ULONG *ip_invalid_packets, ULONG *ip_receive_packets_dropped, + ULONG *ip_receive_checksum_errors, ULONG *ip_send_packets_dropped, + ULONG *ip_total_fragments_sent, ULONG *ip_total_fragments_received); +UINT _nxe_ip_interface_attach(NX_IP *ip_ptr, CHAR *interface_name, ULONG ip_address, ULONG network_mask, VOID (*ip_link_driver)(struct NX_IP_DRIVER_STRUCT *)); +UINT _nxe_ip_raw_packet_disable(NX_IP *ip_ptr); +UINT _nxe_ip_raw_packet_enable(NX_IP *ip_ptr); +UINT _nxe_ip_raw_packet_receive(NX_IP *ip_ptr, NX_PACKET **packet_ptr, ULONG wait_option); +UINT _nxe_ip_raw_packet_send(NX_IP *ip_ptr, NX_PACKET **packet_ptr_ptr, + ULONG destination_ip, ULONG type_of_service); +UINT _nxe_ip_raw_packet_interface_send(NX_IP *ip_ptr, NX_PACKET **packet_ptr_ptr, + ULONG destination_ip, UINT interface_index, ULONG type_of_service); +UINT _nxe_ip_status_check(NX_IP *ip_ptr, ULONG needed_status, ULONG *actual_status, + ULONG wait_option); +UINT _nxe_ip_link_status_change_notify_set(NX_IP *ip_ptr, VOID (*link_status_change_notify)(NX_IP *ip_ptr, UINT interface_index, UINT link_up)); + +UINT _nxe_ip_static_route_add(NX_IP *ip_ptr, ULONG network_address, ULONG net_mask, ULONG next_hop); +UINT _nxe_ip_static_route_delete(NX_IP *ip_ptr, ULONG network_address, ULONG net_mask); +UINT _nxe_ip_static_routing_disable(NX_IP *ip_ptr); +UINT _nxe_ip_static_routing_enable(NX_IP *ip_ptr); + + +/* IP component data declarations follow. */ + +/* Determine if the initialization function of this component is including + this file. If so, make the data definitions really happen. Otherwise, + make them extern so other functions in the component can access them. */ + +#ifdef NX_IP_INIT +#define IP_DECLARE +#else +#define IP_DECLARE extern +#endif + + +/* Define the head pointer of the created IP list. */ + +IP_DECLARE NX_IP *_nx_ip_created_ptr; + + +/* Define the number of created IP instances. */ + +IP_DECLARE ULONG _nx_ip_created_count; + + +#endif + diff --git a/common/inc/nx_packet.h b/common/inc/nx_packet.h new file mode 100644 index 0000000..fc11b73 --- /dev/null +++ b/common/inc/nx_packet.h @@ -0,0 +1,146 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Packet Pool Management (Packet) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* COMPONENT DEFINITION RELEASE */ +/* */ +/* nx_packet.h PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file defines the NetX packet memory management 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_PAC_H +#define NX_PAC_H + + +#define NX_PACKET_POOL_ID ((ULONG)0x5041434B) + + +/* Define constants for packet free, allocated, enqueued, and driver transmit done. + These will be used in the nx_packet_tcp_queue_next field to indicate the state of + the packet. */ + +#define NX_PACKET_FREE ((ULONG)0xFFFFFFFF) /* Packet is available and in the pool */ +#define NX_PACKET_ALLOCATED ((ULONG)0xAAAAAAAA) /* Packet has been allocated */ +#define NX_PACKET_ENQUEUED ((ULONG)0xEEEEEEEE) /* Packet is the tail of TCP queue. */ + /* A value that is none of the above */ + /* also indicates the packet is in a */ + /* TCP queue */ + +/* Define the constant for driver done and receive packet is available. These will be + used in the nx_packet_queue_next field to indicate the state of a TCP packet. */ + +#define NX_DRIVER_TX_DONE ((ULONG)0xDDDDDDDD) /* Driver has sent the TCP packet */ +#define NX_PACKET_READY ((ULONG)0xBBBBBBBB) /* Packet is ready for retrieval */ + + + +/* Define packet pool management function prototypes. */ + +UINT _nx_packet_allocate(NX_PACKET_POOL *pool_ptr, NX_PACKET **packet_ptr, + ULONG packet_type, ULONG wait_option); +UINT _nx_packet_copy(NX_PACKET *packet_ptr, NX_PACKET **new_packet_ptr, + NX_PACKET_POOL *pool_ptr, ULONG wait_option); +UINT _nx_packet_data_append(NX_PACKET *packet_ptr, VOID *data_start, ULONG data_size, + NX_PACKET_POOL *pool_ptr, ULONG wait_option); +UINT _nx_packet_data_extract_offset(NX_PACKET *packet_ptr, ULONG offset, VOID *buffer_start, + ULONG buffer_length, ULONG *bytes_copied); +UINT _nx_packet_data_retrieve(NX_PACKET *packet_ptr, VOID *buffer_start, ULONG *bytes_copied); +UINT _nx_packet_length_get(NX_PACKET *packet_ptr, ULONG *length); +UINT _nx_packet_pool_create(NX_PACKET_POOL *pool_ptr, CHAR *name, ULONG payload_size, + VOID *memory_ptr, ULONG memory_size); +UINT _nx_packet_pool_delete(NX_PACKET_POOL *pool_ptr); +UINT _nx_packet_pool_info_get(NX_PACKET_POOL *pool_ptr, ULONG *total_packets, ULONG *free_packets, + ULONG *empty_pool_requests, ULONG *empty_pool_suspensions, + ULONG *invalid_packet_releases); +UINT _nx_packet_release(NX_PACKET *packet_ptr); +UINT _nx_packet_transmit_release(NX_PACKET *packet_ptr); +VOID _nx_packet_pool_cleanup(TX_THREAD *thread_ptr NX_CLEANUP_PARAMETER); +VOID _nx_packet_pool_initialize(VOID); + + +/* Define error checking shells for API services. These are only referenced by the + application. */ + +UINT _nxe_packet_allocate(NX_PACKET_POOL *pool_ptr, NX_PACKET **packet_ptr, + ULONG packet_type, ULONG wait_option); +UINT _nxe_packet_copy(NX_PACKET *packet_ptr, NX_PACKET **new_packet_ptr, + NX_PACKET_POOL *pool_ptr, ULONG wait_option); +UINT _nxe_packet_data_append(NX_PACKET *packet_ptr, VOID *data_start, ULONG data_size, + NX_PACKET_POOL *pool_ptr, ULONG wait_option); +UINT _nxe_packet_data_extract_offset(NX_PACKET *packet_ptr, ULONG offset, VOID *buffer_start, + ULONG buffer_length, ULONG *bytes_copied); +UINT _nxe_packet_data_retrieve(NX_PACKET *packet_ptr, VOID *buffer_start, ULONG *bytes_copied); +UINT _nxe_packet_length_get(NX_PACKET *packet_ptr, ULONG *length); +UINT _nxe_packet_pool_create(NX_PACKET_POOL *pool_ptr, CHAR *name, ULONG payload_size, + VOID *memory_ptr, ULONG memory_size, UINT pool_control_block_size); +UINT _nxe_packet_pool_delete(NX_PACKET_POOL *pool_ptr); +UINT _nxe_packet_pool_info_get(NX_PACKET_POOL *pool_ptr, ULONG *total_packets, ULONG *free_packets, + ULONG *empty_pool_requests, ULONG *empty_pool_suspensions, + ULONG *invalid_packet_releases); +UINT _nxe_packet_release(NX_PACKET **packet_ptr_ptr); +UINT _nxe_packet_transmit_release(NX_PACKET **packet_ptr_ptr); + + +/* Packet pool management component data declarations follow. */ + +/* Determine if the initialization function of this component is including + this file. If so, make the data definitions really happen. Otherwise, + make them extern so other functions in the component can access them. */ + +#ifdef NX_PACKET_POOL_INIT +#define PACKET_POOL_DECLARE +#else +#define PACKET_POOL_DECLARE extern +#endif + + +/* Define the head pointer of the created packet pool list. */ + +PACKET_POOL_DECLARE NX_PACKET_POOL *_nx_packet_pool_created_ptr; + + +/* Define the variable that holds the number of created packet pools. */ + +PACKET_POOL_DECLARE ULONG _nx_packet_pool_created_count; + + + +#endif + diff --git a/common/inc/nx_rarp.h b/common/inc/nx_rarp.h new file mode 100644 index 0000000..9ffee61 --- /dev/null +++ b/common/inc/nx_rarp.h @@ -0,0 +1,115 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Reverse Address Resolution Protocol (RARP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* COMPONENT DEFINITION RELEASE */ +/* */ +/* nx_rarp.h PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file defines the NetX Reverse Address Resolution Protocol */ +/* 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_RARP_H +#define NX_RARP_H + + +/* Define RARP Message format. This will get encapsulated by an Ethernet frame + as well. The Ethernet frame will typically have a 6-byte Ethernet destination + address, a 6-byte Ethernet source address, and a 2-byte Ethernet Frame type, + which is 0x8035. Regular IP frames have a frame type of 0x0800. + + Byte offset Size Meaning + + 0 2 Hardware type (1 for Ethernet) + 2 2 Protocol type (0x0800 for IP) + 4 1 Number of bytes for hardware address (6 for Ethernet) + 5 1 Number of bytes for IP address (4 for IP) + 6 2 Operation, ARP request is 1, ARP reply is 2 + 8 6 Sender's Ethernet Address + 14 4 Sender's IP Address + 18 6 Target Ethernet Address + 24 4 Target IP Address + */ + +#define NX_RARP_HARDWARE_TYPE ((ULONG)0x0001) +#define NX_RARP_PROTOCOL_TYPE ((ULONG)0x0800) +#define NX_RARP_HARDWARE_SIZE ((ULONG)0x06) +#define NX_RARP_PROTOCOL_SIZE ((ULONG)0x04) +#define NX_RARP_OPTION_REQUEST ((ULONG)0x0003) +#define NX_RARP_OPTION_RESPONSE ((ULONG)0x0004) +#define NX_RARP_MESSAGE_SIZE 28 + + +/* Define RARP function prototypes. */ + +VOID _nx_rarp_initialize(VOID); + +UINT _nx_rarp_enable(NX_IP *ip_ptr); +UINT _nx_rarp_disable(NX_IP *ip_ptr); +UINT _nx_rarp_info_get(NX_IP *ip_ptr, ULONG *rarp_requests_sent, ULONG *rarp_responses_received, + ULONG *rarp_invalid_messages); +VOID _nx_rarp_packet_send(NX_IP *ip_ptr); +VOID _nx_rarp_packet_receive(NX_IP *ip_ptr, NX_PACKET *packet_ptr); +VOID _nx_rarp_packet_deferred_receive(NX_IP *ip_ptr, NX_PACKET *packet_ptr); +VOID _nx_rarp_periodic_update(NX_IP *ip_ptr); +VOID _nx_rarp_queue_process(NX_IP *ip_ptr); + + +/* Define error checking shells for RARP services. These are only referenced by the + application. */ + +UINT _nxe_rarp_enable(NX_IP *ip_ptr); +UINT _nxe_rarp_disable(NX_IP *ip_ptr); +UINT _nxe_rarp_info_get(NX_IP *ip_ptr, ULONG *rarp_requests_sent, ULONG *rarp_responses_received, + ULONG *rarp_invalid_messages); + +/* RARP management component data declarations follow. */ + +/* Determine if the initialization function of this component is including + this file. If so, make the data definitions really happen. Otherwise, + make them extern so other functions in the component can access them. */ + +#ifdef NX_RARP_INIT +#define RARP_DECLARE +#else +#define RARP_DECLARE extern +#endif + +#endif + diff --git a/common/inc/nx_system.h b/common/inc/nx_system.h new file mode 100644 index 0000000..be25e34 --- /dev/null +++ b/common/inc/nx_system.h @@ -0,0 +1,152 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** System Management (System) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* COMPONENT DEFINITION RELEASE */ +/* */ +/* nx_system.h PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file defines the NetX system management 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_SYS_H +#define NX_SYS_H + + + +/* Define system management function prototypes. */ + +VOID _nx_system_initialize(VOID); + + +/* Define error checking shells for API services. These are only referenced by the + application. */ + +/* System management component data declarations follow. */ + +/* Determine if the initialization function of this component is including + this file. If so, make the data definitions really happen. Otherwise, + make them extern so other functions in the component can access them. */ + +#ifdef NX_SYSTEM_INIT +#define SYSTEM_DECLARE +#else +#define SYSTEM_DECLARE extern +#endif + + +/* Define the global NetX build options variables. These variables contain a bit + map representing how the NetX library was built. The following are the bit + field definitions: + + _nx_system_build_options_1: + + Bit(s) Meaning + + 31 NX_LITTLE_ENDIAN + 30 NX_DISABLE_ARP_AUTO_ENTRY + 29 NX_ENABLE_TCP_KEEPALIVE + 28 NX_TCP_IMMEDIATE_ACK + 27 NX_DRIVER_DEFERRED_PROCESSING + 26 NX_DISABLE_FRAGMENTATION + 25 NX_DISABLE_IP_RX_CHECKSUM + 24 NX_DISABLE_IP_TX_CHECKSUM + 23 NX_DISABLE_TCP_RX_CHECKSUM + 22 NX_DISABLE_TCP_TX_CHECKSUM + 21 NX_DISABLE_RESET_DISCONNECT + 20 NX_DISABLE_RX_SIZE_CHECKING + 19 NX_DISABLE_ARP_INFO + 18 NX_DISABLE_IP_INFO + 17 NX_DISABLE_ICMP_INFO + 16 NX_DISABLE_IGMP_INFO + 15 NX_DISABLE_PACKET_INFO + 14 NX_DISABLE_RARP_INFO + 13 NX_DISABLE_TCP_INFO + 12 NX_DISABLE_UDP_INFO + 3-0 NX_TCP_RETRY_SHIFT + + _nx_system_build_options_2: + + Bit(s) Meaning + + 31-16 NX_IP_PERIODIC_RATE + 15-8 NX_ARP_EXPIRATION_RATE + 7-0 NX_ARP_UPDATE_RATE + + _nx_system_build_options_3: + + Bit(s) Meaning + + 31-24 NX_TCP_ACK_TIMER_RATE + 23-16 NX_TCP_FAST_TIMER_RATE + 15-8 NX_TCP_TRANSMIT_TIMER_RATE + 7-0 NX_TCP_KEEPALIVE_RETRY + + _nx_system_build_options_4: + + Bit(s) Meaning + + 31-16 NX_TCP_KEEPALIVE_INITIAL + 15-8 NX_ARP_MAXIMUM_RETRIES + 7-4 NX_ARP_MAX_QUEUE_DEPTH + 3-0 NX_TCP_KEEPALIVE_RETRIES + + _nx_system_build_options_5: + + Bit(s) Meaning + + 31-24 NX_MAX_MULTICAST_GROUPS + 23-16 NX_MAX_LISTEN_REQUESTS + 15-8 NX_TCP_MAXIMUM_RETRIES + 7-0 NX_TCP_MAXIMUM_TX_QUEUE + + Note that values greater than the value that can be represented in the build options + bit field are represented as all ones in the bit field. For example, if NX_TCP_ACK_TIMER_RATE + is 256, the value in the bits 31-24 of _nx_system_build_options_3 is 0xFF, which is 255 + decimal. */ + +SYSTEM_DECLARE ULONG _nx_system_build_options_1; +SYSTEM_DECLARE ULONG _nx_system_build_options_2; +SYSTEM_DECLARE ULONG _nx_system_build_options_3; +SYSTEM_DECLARE ULONG _nx_system_build_options_4; +SYSTEM_DECLARE ULONG _nx_system_build_options_5; + + +#endif + diff --git a/common/inc/nx_tcp.h b/common/inc/nx_tcp.h new file mode 100644 index 0000000..effd854 --- /dev/null +++ b/common/inc/nx_tcp.h @@ -0,0 +1,446 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* COMPONENT DEFINITION RELEASE */ +/* */ +/* nx_tcp.h PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file defines the NetX Transmission Control Protocol 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_TCP_H +#define NX_TCP_H + + +/* Define TCP constants. */ + +#define NX_TCP_ID ((ULONG)0x54435020) + + +/* Define the TCP header typical size. */ + +#define NX_TCP_HEADER_SIZE ((ULONG)0x50000000) /* Typical 5 word TCP header */ +#define NX_TCP_SYN_HEADER ((ULONG)0x70000000) /* SYN header with MSS option */ +#define NX_TCP_HEADER_MASK ((ULONG)0xF0000000) /* TCP header size mask */ +#define NX_TCP_HEADER_SHIFT 28 /* Shift down to pickup length */ + + +/* Define the TCP header control fields. */ + +#define NX_TCP_CONTROL_MASK ((ULONG)0x00170000) /* ACK, RST, SYN, and FIN bits */ +#define NX_TCP_URG_BIT ((ULONG)0x00200000) /* Urgent data bit */ +#define NX_TCP_ACK_BIT ((ULONG)0x00100000) /* Acknowledgement bit */ +#define NX_TCP_PSH_BIT ((ULONG)0x00080000) /* Push bit */ +#define NX_TCP_RST_BIT ((ULONG)0x00040000) /* Reset bit */ +#define NX_TCP_SYN_BIT ((ULONG)0x00020000) /* Sequence bit */ +#define NX_TCP_FIN_BIT ((ULONG)0x00010000) /* Finish bit */ + + +/* Define the MSS option for the TCP header. */ + +#define NX_TCP_MSS_OPTION ((ULONG)0x02040000) /* Maximum Segment Size option, 32 bits */ +#define NX_TCP_RWIN_OPTION ((ULONG)0x03030000) /* 24 bits, so NOP, 0x3, 0x3, scale value */ +#define NX_TCP_MSS_SIZE 1460 /* Maximum Segment Size */ +#define NX_TCP_OPTION_END ((ULONG)0x00000000) /* NOPs and end of TCP options */ +#define NX_TCP_EOL_KIND 0x00 /* EOL option kind */ +#define NX_TCP_NOP_KIND 0x01 /* NOP option kind */ +#define NX_TCP_MSS_KIND 0x02 /* MSS option kind */ +#define NX_TCP_RWIN_KIND 0x03 + + +/* Define constants for the optional TCP keepalive Timer. To enable this + feature, the TCP source must be compiled with NX_ENABLE_TCP_KEEPALIVE + defined. */ + +#ifndef NX_TCP_KEEPALIVE_INITIAL +#define NX_TCP_KEEPALIVE_INITIAL 7200 /* Number of seconds for initial */ +#endif /* keepalive expiration, the */ +/* default is 2 hours (120 min)*/ +#ifndef NX_TCP_KEEPALIVE_RETRY +#define NX_TCP_KEEPALIVE_RETRY 75 /* After initial expiration, */ +#endif /* retry every 75 seconds */ + +#ifndef NX_TCP_KEEPALIVE_RETRIES +#define NX_TCP_KEEPALIVE_RETRIES 10 /* Retry a maximum of 10 times */ +#endif + +#ifndef NX_TCP_MAXIMUM_TX_QUEUE +#define NX_TCP_MAXIMUM_TX_QUEUE 20 /* Maximum number of transmit */ +#endif /* packets queued */ + +#ifndef NX_TCP_MAXIMUM_RETRIES +#define NX_TCP_MAXIMUM_RETRIES 10 /* Maximum number of transmit */ +#endif /* retries allowed */ + +#ifndef NX_TCP_RETRY_SHIFT +#define NX_TCP_RETRY_SHIFT 0 /* Shift that is applied to */ +#endif /* last timeout for back off, */ + /* i.e. a value of zero means */ + /* constant timeouts, a value */ + /* of 1 causes each successive */ + /* be multiplied by two, etc. */ + + + +/* Define the rate for the TCP fast periodic timer. This timer is used to process + delayed ACKs and packet re-transmission. Hence, it must have greater resolution + than the 200ms delayed ACK requirement. By default, the fast periodic timer is + setup on a 100ms periodic. The number supplied is used to divide the + NX_IP_PERIODIC_RATE value to actually derive the ticks. Dividing + by 10 yields a 100ms base periodic. */ + +#ifndef NX_TCP_FAST_TIMER_RATE +#define NX_TCP_FAST_TIMER_RATE 10 +#endif + + +/* Define the rate for the TCP delayed ACK timer, which by default is 200ms. The + number supplied is used to divide the NX_IP_PERIODIC_RATE value to + actually derive the ticks. Dividing by 5 yields a 200ms periodic. */ + +#ifndef NX_TCP_ACK_TIMER_RATE +#define NX_TCP_ACK_TIMER_RATE 5 +#endif + +/* Define the rate for the TCP retransmit timer, which by default is set to + one second. The number supplied is used to divide the NX_IP_PERIODIC_RATE + value to actually derive the ticks. Dividing by 1 yields a 1 second periodic. */ + +#ifndef NX_TCP_TRANSMIT_TIMER_RATE +#define NX_TCP_TRANSMIT_TIMER_RATE 1 +#endif + + +/* Define Basic TCP packet header data type. This will be used to + build new TCP packets and to examine incoming packets into NetX. */ + +typedef struct NX_TCP_HEADER_STRUCT +{ + + /* Define the first 32-bit word of the TCP header. This word contains + the following information: + + bits 31-16 TCP 16-bit source port number + bits 15-0 TCP 16-bit destination port number + */ + ULONG nx_tcp_header_word_0; + + /* Define the second word of the TCP header. This word contains + the following information: + + bits 31-0 TCP 32-bit sequence number + */ + ULONG nx_tcp_sequence_number; + + /* Define the third word of the TCP header. This word contains + the following information: + + bits 31-0 TCP 32-bit acknowledgment number + */ + ULONG nx_tcp_acknowledgment_number; + + /* Define the fourth 32-bit word of the TCP header. This word contains + the following information: + + bits 31-28 TCP 4-bit header length + bits 27-22 TCP 6-bit reserved field + bit 21 TCP Urgent bit (URG) + bit 20 TCP Acknowledgement bit (ACK) + bit 19 TCP Push bit (PSH) + bit 18 TCP Reset connection bit (RST) + bit 17 TCP Synchronize sequence numbers bit (SYN) + bit 16 TCP Sender has reached the end of its byte stream (FIN) + bits 15-0 TCP 16-bit window size + */ + ULONG nx_tcp_header_word_3; + + /* Define the fifth 32-bit word of the TCP header. This word contains + the following information: + + bits 31-16 TCP 16-bit TCP checksum + bits 15-0 TCP 16-bit TCP urgent pointer + */ + ULONG nx_tcp_header_word_4; +} NX_TCP_HEADER; + + +/* Define TCP SYN packet header data type. This will be used during the + initial connection requests for NetX. */ + +typedef struct NX_TCP_SYN_STRUCT +{ + + /* Define the first 32-bit word of the TCP header. This word contains + the following information: + + bits 31-16 TCP 16-bit source port number + bits 15-0 TCP 16-bit destination port number + */ + ULONG nx_tcp_header_word_0; + + /* Define the second word of the TCP header. This word contains + the following information: + + bits 31-0 TCP 32-bit sequence number + */ + ULONG nx_tcp_sequence_number; + + /* Define the third word of the TCP header. This word contains + the following information: + + bits 31-0 TCP 32-bit acknowledgment number + */ + ULONG nx_tcp_acknowledgment_number; + + /* Define the fourth 32-bit word of the TCP header. This word contains + the following information: + + bits 31-28 TCP 4-bit header length + bits 27-22 TCP 6-bit reserved field + bit 21 TCP Urgent bit (URG) + bit 20 TCP Acknowledgement bit (ACK) + bit 19 TCP Push bit (PSH) + bit 18 TCP Reset connection bit (RST) + bit 17 TCP Synchronize sequence numbers bit (SYN) + bit 16 TCP Sender has reached the end of its byte stream (FIN) + bits 15-0 TCP 16-bit window size + */ + ULONG nx_tcp_header_word_3; + + /* Define the fifth 32-bit word of the TCP header. This word contains + the following information: + + bits 31-16 TCP 16-bit TCP checksum + bits 15-0 TCP 16-bit TCP urgent pointer + */ + ULONG nx_tcp_header_word_4; + + /* Define the first option word of the TCP SYN header. This word contains + the MSS option type and the MSS itself. */ + ULONG nx_tcp_option_word_1; + + /* Define the second option word of the TCP SYN header. This word contains + window scaling if enabled. Otherwise it signals the end of the option list. */ + ULONG nx_tcp_option_word_2; +} NX_TCP_SYN; + + +/* Define TCP component API function prototypes. */ + +UINT _nx_tcp_client_socket_bind(NX_TCP_SOCKET *socket_ptr, UINT port, ULONG wait_option); +UINT _nx_tcp_client_socket_connect(NX_TCP_SOCKET *socket_ptr, ULONG server_ip, UINT server_port, ULONG wait_option); +UINT _nx_tcp_client_socket_port_get(NX_TCP_SOCKET *socket_ptr, UINT *port_ptr); +UINT _nx_tcp_client_socket_unbind(NX_TCP_SOCKET *socket_ptr); +UINT _nx_tcp_enable(NX_IP *ip_ptr); +UINT _nx_tcp_free_port_find(NX_IP *ip_ptr, UINT port, UINT *free_port_ptr); +UINT _nx_tcp_info_get(NX_IP *ip_ptr, ULONG *tcp_packets_sent, ULONG *tcp_bytes_sent, + ULONG *tcp_packets_received, ULONG *tcp_bytes_received, + ULONG *tcp_invalid_packets, ULONG *tcp_receive_packets_dropped, + ULONG *tcp_checksum_errors, ULONG *tcp_connections, + ULONG *tcp_disconnections, ULONG *tcp_connections_dropped, + ULONG *tcp_retransmit_packets); +UINT _nx_tcp_server_socket_accept(NX_TCP_SOCKET *socket_ptr, ULONG wait_option); +UINT _nx_tcp_server_socket_listen(NX_IP *ip_ptr, UINT port, NX_TCP_SOCKET *socket_ptr, UINT listen_queue_size, + VOID (*tcp_listen_callback)(NX_TCP_SOCKET *socket_ptr, UINT port)); +UINT _nx_tcp_server_socket_relisten(NX_IP *ip_ptr, UINT port, NX_TCP_SOCKET *socket_ptr); +UINT _nx_tcp_server_socket_unaccept(NX_TCP_SOCKET *socket_ptr); +UINT _nx_tcp_server_socket_unlisten(NX_IP *ip_ptr, UINT port); +UINT _nx_tcp_socket_create(NX_IP *ip_ptr, NX_TCP_SOCKET *socket_ptr, CHAR *name, + ULONG type_of_service, ULONG fragment, UINT time_to_live, ULONG window_size, + VOID (*tcp_urgent_data_callback)(NX_TCP_SOCKET *socket_ptr), + VOID (*tcp_disconnect_callback)(NX_TCP_SOCKET *socket_ptr)); +UINT _nx_tcp_socket_delete(NX_TCP_SOCKET *socket_ptr); +UINT _nx_tcp_socket_disconnect(NX_TCP_SOCKET *socket_ptr, ULONG wait_option); +UINT _nx_tcp_socket_info_get(NX_TCP_SOCKET *socket_ptr, ULONG *tcp_packets_sent, ULONG *tcp_bytes_sent, + ULONG *tcp_packets_received, ULONG *tcp_bytes_received, + ULONG *tcp_retransmit_packets, ULONG *tcp_packets_queued, + ULONG *tcp_checksum_errors, ULONG *tcp_socket_state, + ULONG *tcp_transmit_queue_depth, ULONG *tcp_transmit_window, + ULONG *tcp_receive_window); +UINT _nx_tcp_socket_peer_info_get(NX_TCP_SOCKET *socket_ptr, ULONG *peer_ip_address, + ULONG *peer_port); + +UINT _nx_tcp_socket_mss_get(NX_TCP_SOCKET *socket_ptr, ULONG *mss); +UINT _nx_tcp_socket_mss_peer_get(NX_TCP_SOCKET *socket_ptr, ULONG *peer_mss); +UINT _nx_tcp_socket_mss_set(NX_TCP_SOCKET *socket_ptr, ULONG mss); +UINT _nx_tcp_socket_receive(NX_TCP_SOCKET *socket_ptr, NX_PACKET **packet_ptr, ULONG wait_option); +UINT _nx_tcp_socket_receive_notify(NX_TCP_SOCKET *socket_ptr, + VOID (*tcp_receive_notify)(NX_TCP_SOCKET *socket_ptr)); +UINT _nx_tcp_socket_window_update_notify_set(NX_TCP_SOCKET *socket_ptr, + VOID (*tcp_windows_update_notify)(NX_TCP_SOCKET *socket_ptr)); +UINT _nx_tcp_socket_send(NX_TCP_SOCKET *socket_ptr, NX_PACKET *packet_ptr, ULONG wait_option); +UINT _nx_tcp_socket_state_wait(NX_TCP_SOCKET *socket_ptr, UINT desired_state, ULONG wait_option); + +UINT _nx_tcp_socket_transmit_configure(NX_TCP_SOCKET *socket_ptr, ULONG max_queue_depth, ULONG timeout, + ULONG max_retries, ULONG timeout_shift); +UINT _nx_tcp_socket_establish_notify(NX_TCP_SOCKET *socket_ptr, VOID (*tcp_establish_notify)(NX_TCP_SOCKET *socket_ptr)); +UINT _nx_tcp_socket_disconnect_complete_notify(NX_TCP_SOCKET *socket_ptr, VOID (*tcp_disconnect_complete_notify)(NX_TCP_SOCKET *socket_ptr)); +UINT _nx_tcp_socket_timed_wait_callback(NX_TCP_SOCKET *socket_ptr, VOID (*tcp_timed_wait_callback)(NX_TCP_SOCKET *socket_ptr)); + +UINT _nx_tcp_socket_bytes_available(NX_TCP_SOCKET *, ULONG *); +UINT _nx_tcp_socket_peer_info_get(NX_TCP_SOCKET *, ULONG *, ULONG *); + + +/* Define TCP component internal function prototypes. */ + +ULONG _nx_tcp_checksum(NX_PACKET *packet_ptr, ULONG source_address, ULONG destination_address); +VOID _nx_tcp_cleanup_deferred(TX_THREAD *thread_ptr NX_CLEANUP_PARAMETER); +VOID _nx_tcp_client_bind_cleanup(TX_THREAD *thread_ptr NX_CLEANUP_PARAMETER); +VOID _nx_tcp_deferred_cleanup_check(NX_IP *ip_ptr); +VOID _nx_tcp_fast_periodic_processing(NX_IP *ip_ptr); +VOID _nx_tcp_fast_periodic_timer_entry(ULONG ip_address); +VOID _nx_tcp_socket_retransmit(NX_IP *ip_ptr, NX_TCP_SOCKET *socket_ptr, UINT need_fast_retransmit); +VOID _nx_tcp_connect_cleanup(TX_THREAD *thread_ptr NX_CLEANUP_PARAMETER); +VOID _nx_tcp_disconnect_cleanup(TX_THREAD *thread_ptr NX_CLEANUP_PARAMETER); +VOID _nx_tcp_initialize(VOID); +UINT _nx_tcp_mss_option_get(UCHAR *option_ptr, ULONG option_area_size, ULONG *mss); +UINT _nx_tcp_window_scaling_option_get(UCHAR *option_ptr, ULONG option_area_size, ULONG *window_scale); +VOID _nx_tcp_no_connection_reset(NX_IP *ip_ptr, NX_PACKET *packet_ptr, NX_TCP_HEADER *tcp_header_ptr); +VOID _nx_tcp_packet_process(NX_IP *ip_ptr, NX_PACKET *packet_ptr); +VOID _nx_tcp_packet_receive(NX_IP *ip_ptr, NX_PACKET *packet_ptr); +VOID _nx_tcp_packet_send_ack(NX_TCP_SOCKET *socket_ptr, ULONG tx_sequence); +VOID _nx_tcp_packet_send_fin(NX_TCP_SOCKET *socket_ptr, ULONG tx_sequence); +VOID _nx_tcp_packet_send_rst(NX_TCP_SOCKET *socket_ptr, NX_TCP_HEADER *header_ptr); +VOID _nx_tcp_packet_send_syn(NX_TCP_SOCKET *socket_ptr, ULONG tx_sequence); +VOID _nx_tcp_periodic_processing(NX_IP *ip_ptr); +VOID _nx_tcp_queue_process(NX_IP *ip_ptr); +VOID _nx_tcp_receive_cleanup(TX_THREAD *thread_ptr NX_CLEANUP_PARAMETER); +VOID _nx_tcp_socket_connection_reset(NX_TCP_SOCKET *socket_ptr); +VOID _nx_tcp_socket_packet_process(NX_TCP_SOCKET *socket_ptr, NX_PACKET *packet_ptr); +VOID _nx_tcp_socket_receive_queue_flush(NX_TCP_SOCKET *socket_ptr); +VOID _nx_tcp_socket_state_ack_check(NX_TCP_SOCKET *socket_ptr, NX_TCP_HEADER *tcp_header_ptr); +VOID _nx_tcp_socket_state_closing(NX_TCP_SOCKET *socket_ptr, NX_TCP_HEADER *tcp_header_ptr); +UINT _nx_tcp_socket_state_data_check(NX_TCP_SOCKET *socket_ptr, NX_PACKET *packet_ptr); +VOID _nx_tcp_socket_state_established(NX_TCP_SOCKET *socket_ptr, NX_TCP_HEADER *tcp_header_ptr); +VOID _nx_tcp_socket_state_fin_wait1(NX_TCP_SOCKET *socket_ptr, NX_TCP_HEADER *tcp_header_ptr); +VOID _nx_tcp_socket_state_fin_wait2(NX_TCP_SOCKET *socket_ptr, NX_TCP_HEADER *tcp_header_ptr); +VOID _nx_tcp_socket_state_last_ack(NX_TCP_SOCKET *socket_ptr, NX_TCP_HEADER *tcp_header_ptr); +VOID _nx_tcp_socket_state_syn_sent(NX_TCP_SOCKET *socket_ptr, NX_TCP_HEADER *tcp_header_ptr); +VOID _nx_tcp_socket_state_syn_received(NX_TCP_SOCKET *socket_ptr, NX_TCP_HEADER *tcp_header_ptr); +VOID _nx_tcp_socket_state_transmit_check(NX_TCP_SOCKET *socket_ptr); +VOID _nx_tcp_socket_thread_resume(TX_THREAD **suspension_list_head, UINT status); +VOID _nx_tcp_socket_thread_suspend(TX_THREAD **suspension_list_head, VOID (*suspend_cleanup)(TX_THREAD *NX_CLEANUP_PARAMETER), NX_TCP_SOCKET *socket_ptr, TX_MUTEX *mutex_ptr, ULONG wait_option); +VOID _nx_tcp_socket_transmit_queue_flush(NX_TCP_SOCKET *socket_ptr); +VOID _nx_tcp_transmit_cleanup(TX_THREAD *thread_ptr NX_CLEANUP_PARAMETER); + + +/* Define error checking shells for TCP API services. These are only referenced by the + application. */ + +UINT _nxe_tcp_client_socket_bind(NX_TCP_SOCKET *socket_ptr, UINT port, ULONG wait_option); +UINT _nxe_tcp_client_socket_connect(NX_TCP_SOCKET *socket_ptr, ULONG server_ip, UINT server_port, ULONG wait_option); +UINT _nxe_tcp_client_socket_port_get(NX_TCP_SOCKET *socket_ptr, UINT *port_ptr); +UINT _nxe_tcp_client_socket_unbind(NX_TCP_SOCKET *socket_ptr); +UINT _nxe_tcp_enable(NX_IP *ip_ptr); +UINT _nxe_tcp_free_port_find(NX_IP *ip_ptr, UINT port, UINT *free_port_ptr); +UINT _nxe_tcp_info_get(NX_IP *ip_ptr, ULONG *tcp_packets_sent, ULONG *tcp_bytes_sent, + ULONG *tcp_packets_received, ULONG *tcp_bytes_received, + ULONG *tcp_invalid_packets, ULONG *tcp_receive_packets_dropped, + ULONG *tcp_checksum_errors, ULONG *tcp_connections, + ULONG *tcp_disconnections, ULONG *tcp_connections_dropped, + ULONG *tcp_retransmit_packets); +UINT _nxe_tcp_server_socket_accept(NX_TCP_SOCKET *socket_ptr, ULONG wait_option); +UINT _nxe_tcp_server_socket_listen(NX_IP *ip_ptr, UINT port, NX_TCP_SOCKET *socket_ptr, UINT listen_queue_size, + VOID (*tcp_listen_callback)(NX_TCP_SOCKET *socket_ptr, UINT port)); +UINT _nxe_tcp_server_socket_relisten(NX_IP *ip_ptr, UINT port, NX_TCP_SOCKET *socket_ptr); +UINT _nxe_tcp_server_socket_unaccept(NX_TCP_SOCKET *socket_ptr); +UINT _nxe_tcp_server_socket_unlisten(NX_IP *ip_ptr, UINT port); +UINT _nxe_tcp_socket_create(NX_IP *ip_ptr, NX_TCP_SOCKET *socket_ptr, CHAR *name, + ULONG type_of_service, ULONG fragment, UINT time_to_live, ULONG window_size, + VOID (*tcp_urgent_data_callback)(NX_TCP_SOCKET *socket_ptr), + VOID (*tcp_disconnect_callback)(NX_TCP_SOCKET *socket_ptr), + UINT tcp_socket_size); +UINT _nxe_tcp_socket_delete(NX_TCP_SOCKET *socket_ptr); +UINT _nxe_tcp_socket_disconnect(NX_TCP_SOCKET *socket_ptr, ULONG wait_option); +UINT _nxe_tcp_socket_info_get(NX_TCP_SOCKET *socket_ptr, ULONG *tcp_packets_sent, ULONG *tcp_bytes_sent, + ULONG *tcp_packets_received, ULONG *tcp_bytes_received, + ULONG *tcp_retransmit_packets, ULONG *tcp_packets_queued, + ULONG *tcp_checksum_errors, ULONG *tcp_socket_state, + ULONG *tcp_transmit_queue_depth, ULONG *tcp_transmit_window, + ULONG *tcp_receive_window); +UINT _nxe_tcp_socket_mss_get(NX_TCP_SOCKET *socket_ptr, ULONG *mss); +UINT _nxe_tcp_socket_mss_peer_get(NX_TCP_SOCKET *socket_ptr, ULONG *peer_mss); +UINT _nxe_tcp_socket_mss_set(NX_TCP_SOCKET *socket_ptr, ULONG mss); +UINT _nxe_tcp_socket_receive(NX_TCP_SOCKET *socket_ptr, NX_PACKET **packet_ptr, ULONG wait_option); +UINT _nxe_tcp_socket_receive_notify(NX_TCP_SOCKET *socket_ptr, + VOID (*tcp_receive_notify)(NX_TCP_SOCKET *socket_ptr)); +UINT _nxe_tcp_socket_window_update_notify_set(NX_TCP_SOCKET *socket_ptr, + VOID (*tcp_windows_update_notify)(NX_TCP_SOCKET *socket_ptr)); +UINT _nxe_tcp_socket_send(NX_TCP_SOCKET *socket_ptr, NX_PACKET **packet_ptr_ptr, ULONG wait_option); +UINT _nxe_tcp_socket_state_wait(NX_TCP_SOCKET *socket_ptr, UINT desired_state, ULONG wait_option); +UINT _nxe_tcp_socket_transmit_configure(NX_TCP_SOCKET *socket_ptr, ULONG max_queue_depth, ULONG timeout, + ULONG max_retries, ULONG timeout_shift); + +UINT _nxe_tcp_socket_bytes_available(NX_TCP_SOCKET *, ULONG *); +UINT _nxe_tcp_socket_peer_info_get(NX_TCP_SOCKET *, ULONG *, ULONG *); +UINT _nxe_tcp_socket_establish_notify(NX_TCP_SOCKET *socket_ptr, VOID (*tcp_establish_notify)(NX_TCP_SOCKET *socket_ptr)); +UINT _nxe_tcp_socket_disconnect_complete_notify(NX_TCP_SOCKET *socket_ptr, VOID (*tcp_disconnect_complete_notify)(NX_TCP_SOCKET *socket_ptr)); +UINT _nxe_tcp_socket_timed_wait_callback(NX_TCP_SOCKET *socket_ptr, VOID (*tcp_timed_wait_callback)(NX_TCP_SOCKET *socket_ptr)); + + +/* TCP component data declarations follow. */ + +/* Determine if the initialization function of this component is including + this file. If so, make the data definitions really happen. Otherwise, + make them extern so other functions in the component can access them. */ + +#ifdef NX_TCP_INIT +#define TCP_DECLARE +#else +#define TCP_DECLARE extern +#endif + +/* Define global data for the TCP component. */ + +/* Define the actual number of ticks for the fast periodic timer. */ + +TCP_DECLARE ULONG _nx_tcp_fast_timer_rate; + +/* Define the actual number of ticks for the delayed ACK timer. */ + +TCP_DECLARE ULONG _nx_tcp_ack_timer_rate; + +/* Define the actual number of ticks for the retransmit timer. */ + +TCP_DECLARE ULONG _nx_tcp_transmit_timer_rate; + + +#endif + diff --git a/common/inc/nx_udp.h b/common/inc/nx_udp.h new file mode 100644 index 0000000..453d07a --- /dev/null +++ b/common/inc/nx_udp.h @@ -0,0 +1,167 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** User Datagram Protocol (UDP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* COMPONENT DEFINITION RELEASE */ +/* */ +/* nx_udp.h PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file defines the NetX User Datagram Protocol (UDP) 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_UDP_H +#define NX_UDP_H + + +/* Define UDP constants. */ + +#define NX_UDP_ID ((ULONG)0x55445020) + +#ifndef NX_UDP_DEBUG_LOG_SIZE +#define NX_UDP_DEBUG_LOG_SIZE 100 /* Maximum size of optional log */ +#endif + + +/* Define Basic UDP packet header data type. This will be used to + build new UDP packets and to examine incoming packets into NetX. */ + +typedef struct NX_UDP_HEADER_STRUCT +{ + + /* Define the first 32-bit word of the UDP header. This word contains + the following information: + + bits 31-16 UDP 16-bit source port number + bits 15-0 UDP 16-bit destination port number + */ + ULONG nx_udp_header_word_0; + + /* Define the second and final word of the UDP header. This word contains + the following information: + + bits 31-16 UDP 16-bit UDP length (including 8 header bytes) + bits 15-0 UDP 16-bit checksum (including header and pseudo IP header) + */ + ULONG nx_udp_header_word_1; +} NX_UDP_HEADER; + + +/* Define UDP component function prototypes. */ + +UINT _nx_udp_enable(NX_IP *ip_ptr); +UINT _nx_udp_free_port_find(NX_IP *ip_ptr, UINT port, UINT *free_port_ptr); +UINT _nx_udp_info_get(NX_IP *ip_ptr, ULONG *udp_packets_sent, ULONG *udp_bytes_sent, + ULONG *udp_packets_received, ULONG *udp_bytes_received, + ULONG *udp_invalid_packets, ULONG *udp_receive_packets_dropped, + ULONG *udp_checksum_errors); +UINT _nx_udp_socket_bind(NX_UDP_SOCKET *socket_ptr, UINT port, ULONG wait_option); +UINT _nx_udp_socket_checksum_disable(NX_UDP_SOCKET *socket_ptr); +UINT _nx_udp_socket_checksum_enable(NX_UDP_SOCKET *socket_ptr); +UINT _nx_udp_socket_create(NX_IP *ip_ptr, NX_UDP_SOCKET *socket_ptr, CHAR *name, + ULONG type_of_service, ULONG fragment, UINT time_to_live, ULONG queue_maximum); +UINT _nx_udp_socket_delete(NX_UDP_SOCKET *socket_ptr); +UINT _nx_udp_socket_info_get(NX_UDP_SOCKET *socket_ptr, ULONG *udp_packets_sent, ULONG *udp_bytes_sent, + ULONG *udp_packets_received, ULONG *udp_bytes_received, ULONG *udp_packets_queued, + ULONG *udp_receive_packets_dropped, ULONG *udp_checksum_errors); +UINT _nx_udp_socket_interface_send(NX_UDP_SOCKET *socket_ptr, NX_PACKET *packet_ptr, ULONG ip_address, UINT port, UINT interface_index); +UINT _nx_udp_socket_bytes_available(NX_UDP_SOCKET *socket_ptr, ULONG *bytes_available); +UINT _nx_udp_socket_port_get(NX_UDP_SOCKET *socket_ptr, UINT *port_ptr); +UINT _nx_udp_socket_receive(NX_UDP_SOCKET *socket_ptr, NX_PACKET **packet_ptr, + ULONG wait_option); +UINT _nx_udp_socket_receive_notify(NX_UDP_SOCKET *socket_ptr, + VOID (*udp_receive_notify)(NX_UDP_SOCKET *socket_ptr)); +UINT _nx_udp_socket_send(NX_UDP_SOCKET *socket_ptr, NX_PACKET *packet_ptr, + ULONG ip_address, UINT port); +UINT _nx_udp_socket_unbind(NX_UDP_SOCKET *socket_ptr); +UINT _nx_udp_source_extract(NX_PACKET *packet_ptr, ULONG *ip_address, UINT *port); +UINT _nx_udp_packet_info_extract(NX_PACKET *packet_ptr, ULONG *ip_address, + UINT *protocol, UINT *port, UINT *interface_index); +VOID _nx_udp_initialize(VOID); +VOID _nx_udp_bind_cleanup(TX_THREAD *thread_ptr NX_CLEANUP_PARAMETER); +VOID _nx_udp_packet_receive(NX_IP *ip_ptr, NX_PACKET *packet_ptr); +VOID _nx_udp_receive_cleanup(TX_THREAD *thread_ptr NX_CLEANUP_PARAMETER); + + +/* Define error checking shells for API services. These are only referenced by the + application. */ + +UINT _nxe_udp_enable(NX_IP *ip_ptr); +UINT _nxe_udp_free_port_find(NX_IP *ip_ptr, UINT port, UINT *free_port_ptr); +UINT _nxe_udp_info_get(NX_IP *ip_ptr, ULONG *udp_packets_sent, ULONG *udp_bytes_sent, + ULONG *udp_packets_received, ULONG *udp_bytes_received, + ULONG *udp_invalid_packets, ULONG *udp_receive_packets_dropped, + ULONG *udp_checksum_errors); +UINT _nxe_udp_socket_bind(NX_UDP_SOCKET *socket_ptr, UINT port, ULONG wait_option); +UINT _nxe_udp_socket_checksum_disable(NX_UDP_SOCKET *socket_ptr); +UINT _nxe_udp_socket_checksum_enable(NX_UDP_SOCKET *socket_ptr); +UINT _nxe_udp_socket_create(NX_IP *ip_ptr, NX_UDP_SOCKET *socket_ptr, CHAR *name, + ULONG type_of_service, ULONG fragment, UINT time_to_live, ULONG queue_maximum, UINT udp_socket_size); +UINT _nxe_udp_socket_delete(NX_UDP_SOCKET *socket_ptr); +UINT _nxe_udp_socket_info_get(NX_UDP_SOCKET *socket_ptr, ULONG *udp_packets_sent, ULONG *udp_bytes_sent, + ULONG *udp_packets_received, ULONG *udp_bytes_received, ULONG *udp_packets_queued, + ULONG *udp_receive_packets_dropped, ULONG *udp_checksum_errors); +UINT _nxe_udp_socket_interface_send(NX_UDP_SOCKET *socket_ptr, NX_PACKET **packet_ptr_ptr, ULONG ip_address, UINT port, UINT interface_index); +UINT _nxe_udp_socket_bytes_available(NX_UDP_SOCKET *socket_ptr, ULONG *bytes_available); +UINT _nxe_udp_socket_port_get(NX_UDP_SOCKET *socket_ptr, UINT *port_ptr); +UINT _nxe_udp_socket_receive(NX_UDP_SOCKET *socket_ptr, NX_PACKET **packet_ptr, + ULONG wait_option); +UINT _nxe_udp_socket_receive_notify(NX_UDP_SOCKET *socket_ptr, + VOID (*udp_receive_notify)(NX_UDP_SOCKET *socket_ptr)); +UINT _nxe_udp_socket_send(NX_UDP_SOCKET *socket_ptr, NX_PACKET **packet_ptr_ptr, + ULONG ip_address, UINT port); +UINT _nxe_udp_socket_unbind(NX_UDP_SOCKET *socket_ptr); +UINT _nxe_udp_source_extract(NX_PACKET *packet_ptr, ULONG *ip_address, UINT *port); +UINT _nxe_udp_packet_info_extract(NX_PACKET *packet_ptr, ULONG *ip_address, + UINT *protocol, UINT *port, UINT *interface_index); + + +/* UDP component data declarations follow. */ + +/* Determine if the initialization function of this component is including + this file. If so, make the data definitions really happen. Otherwise, + make them extern so other functions in the component can access them. */ + +#ifdef NX_UDP_INIT +#define UDP_DECLARE +#else +#define UDP_DECLARE extern +#endif + +#endif + diff --git a/common/inc/nx_user_sample.h b/common/inc/nx_user_sample.h new file mode 100644 index 0000000..29c40f6 --- /dev/null +++ b/common/inc/nx_user_sample.h @@ -0,0 +1,484 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** User Specific */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* PORT SPECIFIC C INFORMATION RELEASE */ +/* */ +/* nx_user.h PORTABLE C */ +/* 6.0 */ +/* */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file contains user defines for configuring NetX in specific */ +/* ways. This file will have an effect only if the application and */ +/* NetX library are built with NX_INCLUDE_USER_DEFINE_FILE defined. */ +/* Note that all the defines in this file may also be made on the */ +/* command line when building NetX library and application objects. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +#ifndef NX_USER_H +#define NX_USER_H + + +/* Define various build options for the NetX port. The application should either make changes + here by commenting or un-commenting the conditional compilation defined OR supply the defines + though the compiler's equivalent of the -D option. */ + + +/* Override various options with default values already assigned in nx_api.h or nx_port.h. Please + also refer to nx_port.h for descriptions on each of these options. */ + +/* Defined, this option bypasses the basic NetX error checking. This define is typically used + after the application is fully debugged. */ + +/* +#define NX_DISABLE_ERROR_CHECKING +*/ + +/* Defined, this option enables IP static routing feature. By default IP static routing + feature is not compiled in. */ +/* +#define NX_ENABLE_IP_STATIC_ROUTING +*/ + +/* This define specifies the size of the physical packet header. The default value is 16 (based on + a typical 16-byte Ethernet header). */ + +/* +#define NX_PHYSICAL_HEADER 16 +*/ + + +/* This define specifies the size of the physical packet trailer and is typically used to reserve storage + for things like Ethernet CRCs, etc. */ + +/* +#define NX_PHYSICAL_TRAILER 4 +*/ + +/* This defines specifies the number of ThreadX timer ticks in one second. The default value is based + on ThreadX timer interrupt. */ +/* +#ifdef TX_TIMER_TICKS_PER_SECOND +#define NX_IP_PERIODIC_RATE TX_TIMER_TICKS_PER_SECOND +#else +#define NX_IP_PERIODIC_RATE 100 +#endif +*/ + +/* When defines, ARP reply is sent when address conflict occurs. */ +/* +#define NX_ARP_DEFEND_BY_REPLY +*/ + +/* To use the ARP collision hander to check for invalid ARP messages + matching existing entries in the table (man in the middle attack), + enable this feature. */ +/* +#define NX_ENABLE_ARP_MAC_CHANGE_NOTIFICATION +*/ + +/* This define specifies the number of seconds ARP entries remain valid. The default value of 0 disables + aging of ARP entries. */ + +/* +#define NX_ARP_EXPIRATION_RATE 0 +*/ + + +/* This define specifies the number of seconds between ARP retries. The default value is 10, which represents + 10 seconds. */ + +/* +#define NX_ARP_UPDATE_RATE 10 +*/ + + +/* This define specifies how the number of system ticks (NX_IP_PERIODIC_RATE) is divided to calculate the + timer rate for the TCP delayed ACK processing. The default value is 5, which represents 200ms. */ + +/* +#define NX_TCP_ACK_TIMER_RATE 5 +*/ + + +/* This define specifies how the number of system ticks (NX_IP_PERIODIC_RATE) is divided to calculate the + fast TCP timer rate. The fast TCP timer is used to drive various TCP timers, including the delayed ACK + timer. The default value is 10, which represents 100ms. */ + +/* +#define NX_TCP_FAST_TIMER_RATE 10 +*/ + + +/* This define specifies how the number of system ticks (NX_IP_PERIODIC_RATE) is divided to calculate the + timer rate for the TCP transmit retry processing. The default value is 1, which represents 1 second. */ + +/* +#define NX_TCP_TRANSMIT_TIMER_RATE 1 +*/ + + +/* This define specifies how many seconds of inactivity before the keepalive timer activates. The default + value is 7200, which represents 2 hours. */ + +/* +#define NX_TCP_KEEPALIVE_INITIAL 7200 +*/ + + +/* This define specifies how many seconds between retries of the keepalive timer assuming the other side + of the connection is not responding. The default value is 75, which represents 75 seconds between + retries. */ + +/* +#define NX_TCP_KEEPALIVE_RETRY 75 +*/ + + +/* This define specifies the maximum number of ARP retries made without an ARP response. The default + value is 18. */ + +/* +#define NX_ARP_MAXIMUM_RETRIES 18 +*/ + + +/* This defines specifies the maximum number of packets that can be queued while waiting for an ARP + response. The default value is 4. */ + +/* +#define NX_ARP_MAX_QUEUE_DEPTH 4 +*/ + + +/* Defined, this option disables entering ARP request information in the ARP cache. */ + +/* +#define NX_DISABLE_ARP_AUTO_ENTRY +*/ + + +/* This define specifies the maximum number of multicast groups that can be joined. The default value is + 7. */ + +/* +#define NX_MAX_MULTICAST_GROUPS 7 +*/ + + +/* This define specifies the maximum number of TCP server listen requests. The default value is 10. */ + +/* +#define NX_MAX_LISTEN_REQUESTS 10 +*/ + + +/* Defined, this option enables the optional TCP keepalive timer. */ + +/* +#define NX_ENABLE_TCP_KEEPALIVE +*/ + + +/* Defined, this option enables the TCP window scaling feature. (RFC 1323). Default disabled. */ +/* +#define NX_ENABLE_TCP_WINDOW_SCALING +*/ + + + +/* Defined, this option enables the optional TCP immediate ACK response processing. */ + +/* +#define NX_TCP_IMMEDIATE_ACK +*/ + +/* This define specifies the number of TCP packets to receive before sending an ACK. */ +/* The default value is 2: ack every 2 packets. */ +/* +#define NX_TCP_ACK_EVERY_N_PACKETS 2 +*/ + +/* Automatically define NX_TCP_ACK_EVERY_N_PACKETS to 1 if NX_TCP_IMMEDIATE_ACK is defined. + This is needed for backward compatibility. */ +#if (defined(NX_TCP_IMMEDIATE_ACK) && !defined(NX_TCP_ACK_EVERY_N_PACKETS)) +#define NX_TCP_ACK_EVERY_N_PACKETS 1 +#endif + + +/* This define specifies how many transmit retires are allowed before the connection is deemed broken. + The default value is 10. */ + +/* +#define NX_TCP_MAXIMUM_RETRIES 10 +*/ + + +/* This define specifies the maximum depth of the TCP transmit queue before TCP send requests are + suspended or rejected. The default value is 20, which means that a maximum of 20 packets can be in + the transmit queue at any given time. */ + +/* +#define NX_TCP_MAXIMUM_TX_QUEUE 20 +*/ + + +/* This define specifies how the retransmit timeout period changes between successive retries. If this + value is 0, the initial retransmit timeout is the same as subsequent retransmit timeouts. If this + value is 1, each successive retransmit is twice as long. The default value is 0. */ + +/* +#define NX_TCP_RETRY_SHIFT 0 +*/ + + +/* This define specifies how many keepalive retries are allowed before the connection is deemed broken. + The default value is 10. */ + +/* +#define NX_TCP_KEEPALIVE_RETRIES 10 +*/ + + +/* Defined, this option enables deferred driver packet handling. This allows the driver to place a raw + packet on the IP instance and have the driver's real processing routine called from the NetX internal + IP helper thread. */ + +/* +#define NX_DRIVER_DEFERRED_PROCESSING +*/ + + +/* Defined, this option disables NetX support on the 127.0.0.1 loopback interface. + 127.0.0.1 loopback interface is enabled by default. Uncomment out the follow code to disable + the loopback interface. */ +/* +#define NX_DISABLE_LOOPBACK_INTERFACE +*/ + +/* This option defines the number of physical network interfaces to support. Default is one*/ +/* +#define NX_MAX_PHYSICAL_INTERFACES 1 +*/ + +/* Defined, this option disables all IP fragmentation logic. */ + +/* +#define NX_DISABLE_FRAGMENTATION +*/ + + +/* Defined, this option disables checksum logic on received IP packets. This is useful if the link-layer + has reliable checksum or CRC logic. */ + +/* +#define NX_DISABLE_IP_RX_CHECKSUM +*/ + + +/* Defined, this option disables checksum logic on transmitted IP packets. */ + +/* +#define NX_DISABLE_IP_TX_CHECKSUM +*/ + + +/* Defined, this option disables checksum logic on received TCP packets. */ + +/* +#define NX_DISABLE_TCP_RX_CHECKSUM +*/ + + +/* Defined, this option disables checksum logic on transmitted TCP packets. */ + +/* +#define NX_DISABLE_TCP_TX_CHECKSUM +*/ + +/* Defined, this option disables checksum logic on received UDP packets. */ + +/* +#define NX_DISABLE_UDP_RX_CHECKSUM +*/ + + +/* Defined, this option disables checksum logic on transmitted UDP packets. */ + +/* +#define NX_DISABLE_UDP_TX_CHECKSUM +*/ + + +/* Defined, this option disables checksum logic on received ICMP packets. */ +/* +#define NX_DISABLE_ICMP_RX_CHECKSUM +*/ + + +/* Defined, this option disables checksum logic on transmitted ICMP packets. */ +/* +#define NX_DISABLE_ICMP_TX_CHECKSUM +*/ + + +/* Defined, this option disables the reset processing during disconnect when the timeout value is + specified as NX_NO_WAIT. */ + +/* +#define NX_DISABLE_RESET_DISCONNECT +*/ + +/* Defined, this option disables the addition size checking on received packets. */ + +/* +#define NX_DISABLE_RX_SIZE_CHECKING +*/ + + +/* Defined, ARP information gathering is disabled. */ + +/* +#define NX_DISABLE_ARP_INFO +*/ + + +/* Defined, IP information gathering is disabled. */ + +/* +#define NX_DISABLE_IP_INFO +*/ + + +/* Defined, ICMP information gathering is disabled. */ + +/* +#define NX_DISABLE_ICMP_INFO +*/ + +/* Defined, IGMP v2 support is disabled. By default NetX + is built with IGMPv2 enabled . By uncommenting this option, + NetX reverts back to IGMPv1 only. */ +/* +#define NX_DISABLE_IGMPV2 +*/ + +/* Defined, IGMP information gathering is disabled. */ + +/* +#define NX_DISABLE_IGMP_INFO +*/ + + +/* Defined, packet information gathering is disabled. */ + +/* +#define NX_DISABLE_PACKET_INFO +*/ + + +/* Defined, RARP information gathering is disabled. */ + +/* +#define NX_DISABLE_RARP_INFO +*/ + + +/* Defined, TCP information gathering is disabled. */ + +/* +#define NX_DISABLE_TCP_INFO +*/ + + +/* Defined, UDP information gathering is disabled. */ + +/* +#define NX_DISABLE_UDP_INFO +*/ + + +/* Defined, extended notify support is enabled. This feature adds additional callback/notify services + to NetX API for notifying the host of socket events, such as TCP connection and disconnect + completion. The default is that the extended notify feature is enabled. */ +/* +#define NX_ENABLE_EXTENDED_NOTIFY_SUPPORT +*/ + + +/* Defined, NX_PACKET structure is padded for alignment purpose. The default is no padding. */ +/* +#define NX_PACKET_HEADER_PAD +#define NX_PACKET_HEADER_PAD_SIZE 1 +*/ + +/* If defined, the incoming SYN packet (connection request) is checked for a minimum acceptable + MSS for the host to accept the connection. The default minimum should be based on the host + application packet pool payload, socket transmit queue depth and relevant application specific parameters. +#define NX_ENABLE_TCP_MSS_CHECKING +#define NX_TCP_MSS_MINIMUM 128 +*/ + +/* Defined, the source address of incoming packet is checked. The default is disabled. */ +/* +#define NX_ENABLE_SOURCE_ADDRESS_CHECK +*/ + +/* Define the ARP defend interval. The default value is 10 seconds. */ +/* +#define NX_ARP_DEFEND_INTERVAL 10 +*/ + +/* To limit the number of out of order packets stored to the TCP receive queue and prevent + possible packet pool depletion, define this to a non zero value: + +#define NX_TCP_MAX_OUT_OF_ORDER_PACKETS 8 +*/ + +/* Defined, the destination address of ICMP packet is checked. The default is disabled. + An ICMP Echo Request destined to an IP broadcast or IP multicast address will be silently discarded. +*/ +/* +#define NX_ENABLE_ICMP_ADDRESS_CHECK +*/ + +/* Define the max string length. The default value is 1024. */ +/* +#define NX_MAX_STRING_LENGTH 1024 +*/ + +#endif + diff --git a/common/src/nx_arp_announce_send.c b/common/src/nx_arp_announce_send.c new file mode 100644 index 0000000..aecf1ad --- /dev/null +++ b/common/src/nx_arp_announce_send.c @@ -0,0 +1,162 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Address Resolution Protocol (ARP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_arp.h" +#include "nx_packet.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_arp_announce_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function builds an ARP Announce packet and calls the associated*/ +/* driver to send it out on the specified network interface. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP instance */ +/* interface_index IP Interface Index */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* NX_NO_PACKET No packet available to send */ +/* */ +/* CALLS */ +/* */ +/* _nx_packet_allocate Allocate a packet for the */ +/* ARP Announce */ +/* [ip_link_driver] User supplied link driver */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_arp_announce_send(NX_IP *ip_ptr, UINT interface_index) +{ + +NX_INTERFACE *nx_interface; +NX_PACKET *request_ptr; +ULONG *message_ptr; +NX_IP_DRIVER driver_request; + + + /* Allocate a packet to build the ARP Announce message in. */ + if (_nx_packet_allocate(ip_ptr -> nx_ip_default_packet_pool, &request_ptr, (NX_PHYSICAL_HEADER + NX_ARP_MESSAGE_SIZE), NX_NO_WAIT)) + { + + /* Error getting packet, so just get out! */ + return(NX_NO_PACKET); + } + + /* Get mutex protection. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Set nx_interface. */ + nx_interface = &(ip_ptr -> nx_ip_interface[interface_index]); + + /* Stamp the packet with the outgoing interface information. */ + request_ptr -> nx_packet_ip_interface = nx_interface; + +#ifndef NX_DISABLE_ARP_INFO + /* Increment the ARP requests sent count. */ + ip_ptr -> nx_ip_arp_requests_sent++; +#endif + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_ARP_REQUEST_SEND, ip_ptr, nx_interface -> nx_interface_ip_address, request_ptr, 0, NX_TRACE_INTERNAL_EVENTS, 0, 0); + + /* Build the ARP Announce packet. */ + + /* Setup the size of the ARP message. */ + request_ptr -> nx_packet_length = NX_ARP_MESSAGE_SIZE; + + /* Setup the prepend pointer. */ + request_ptr -> nx_packet_prepend_ptr -= NX_ARP_MESSAGE_SIZE; + + /* Setup the pointer to the message area. */ + message_ptr = (ULONG *)request_ptr -> nx_packet_prepend_ptr; + + /* Write the Hardware type into the message. */ + *message_ptr = (ULONG)(NX_ARP_HARDWARE_TYPE << 16) | (NX_ARP_PROTOCOL_TYPE); + *(message_ptr + 1) = (ULONG)(NX_ARP_HARDWARE_SIZE << 24) | (NX_ARP_PROTOCOL_SIZE << 16) | + NX_ARP_OPTION_REQUEST; + *(message_ptr + 2) = (ULONG)(nx_interface -> nx_interface_physical_address_msw << 16) | + (nx_interface -> nx_interface_physical_address_lsw >> 16); + *(message_ptr + 3) = (ULONG)(nx_interface -> nx_interface_physical_address_lsw << 16) | + (nx_interface -> nx_interface_ip_address >> 16); + *(message_ptr + 4) = (ULONG)(nx_interface -> nx_interface_ip_address << 16); + *(message_ptr + 5) = (ULONG)0; + *(message_ptr + 6) = (ULONG)nx_interface -> nx_interface_ip_address; + + /* Endian swapping logic. If NX_LITTLE_ENDIAN is specified, these macros will + swap the endian of the ARP message. */ + NX_CHANGE_ULONG_ENDIAN(*(message_ptr)); + NX_CHANGE_ULONG_ENDIAN(*(message_ptr + 1)); + NX_CHANGE_ULONG_ENDIAN(*(message_ptr + 2)); + NX_CHANGE_ULONG_ENDIAN(*(message_ptr + 3)); + NX_CHANGE_ULONG_ENDIAN(*(message_ptr + 4)); + NX_CHANGE_ULONG_ENDIAN(*(message_ptr + 5)); + NX_CHANGE_ULONG_ENDIAN(*(message_ptr + 6)); + + /* Set up the driver request. */ + driver_request.nx_ip_driver_ptr = ip_ptr; + driver_request.nx_ip_driver_command = NX_LINK_ARP_SEND; + driver_request.nx_ip_driver_packet = request_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 = nx_interface; + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_IO_DRIVER_ARP_SEND, ip_ptr, request_ptr, request_ptr -> nx_packet_length, 0, NX_TRACE_INTERNAL_EVENTS, 0, 0); + + /* Send the ARP Announce packet to the driver. */ + (nx_interface -> nx_interface_link_driver_entry)(&driver_request); + + /* Release mutex protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return a successful completion. */ + return(NX_SUCCESS); +} + diff --git a/common/src/nx_arp_dynamic_entries_invalidate.c b/common/src/nx_arp_dynamic_entries_invalidate.c new file mode 100644 index 0000000..86df09f --- /dev/null +++ b/common/src/nx_arp_dynamic_entries_invalidate.c @@ -0,0 +1,202 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Address Resolution Protocol (ARP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_arp.h" +#include "nx_ip.h" +#include "nx_packet.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_arp_dynamic_entries_invalidate PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function invalidates all ARP dynamic entries currently in */ +/* the ARP cache. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP instance pointer */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Obtain protection mutex */ +/* tx_mutex_put Release protection mutex */ +/* _nx_packet_transmit_release Release queued packet */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_arp_dynamic_entries_invalidate(NX_IP *ip_ptr) +{ + +TX_INTERRUPT_SAVE_AREA +NX_ARP *arp_entry; +NX_ARP *last_arp_entry; +NX_PACKET *packet_ptr; +NX_PACKET *next_packet_ptr; + + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_ARP_DYNAMIC_ENTRIES_INVALIDATE, ip_ptr, ip_ptr -> nx_ip_arp_dynamic_active_count, 0, 0, NX_TRACE_ARP_EVENTS, 0, 0) + + /* Obtain protection on this IP instance for access into the ARP dynamic + list. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Setup pointers to the starting and ending ARP entries in the dynamic list. */ + arp_entry = ip_ptr -> nx_ip_arp_dynamic_list; + if (arp_entry) + { + last_arp_entry = arp_entry -> nx_arp_pool_previous; + } + else + { + last_arp_entry = NX_NULL; + } + + /* Walk through the dynamic ARP list until there are no more active entries. */ + while ((arp_entry) && (ip_ptr -> nx_ip_arp_dynamic_active_count)) + { + + /* Yes there is one or more dynamic entries. */ + + /* Determine if this ARP entry is already active. */ + if (arp_entry -> nx_arp_active_list_head) + { + + /* Remove this dynamic ARP entry from the associated list. */ + + /* Disable interrupts. */ + TX_DISABLE + + /* Determine if this is the only ARP entry on the list. */ + if (arp_entry == arp_entry -> nx_arp_active_next) + { + + /* Remove the entry from the list. */ + *(arp_entry -> nx_arp_active_list_head) = NX_NULL; + } + else + { + + /* Remove the entry from a list of more than one entry. */ + + /* Update the list head pointer. */ + if (*(arp_entry -> nx_arp_active_list_head) == arp_entry) + { + *(arp_entry -> nx_arp_active_list_head) = arp_entry -> nx_arp_active_next; + } + + /* Update the links of the adjacent ARP entries. */ + (arp_entry -> nx_arp_active_next) -> nx_arp_active_previous = + arp_entry -> nx_arp_active_previous; + (arp_entry -> nx_arp_active_previous) -> nx_arp_active_next = + arp_entry -> nx_arp_active_next; + } + + /* No longer active, clear the active list head. */ + arp_entry -> nx_arp_active_list_head = NX_NULL; + + /* Decrease the number of active ARP entries. */ + ip_ptr -> nx_ip_arp_dynamic_active_count--; + + /* Pickup the queued packets head pointer. */ + next_packet_ptr = arp_entry -> nx_arp_packets_waiting; + + /* Clear the queued packets head pointer. */ + arp_entry -> nx_arp_packets_waiting = NX_NULL; + + /* Restore interrupts. */ + TX_RESTORE + + /* Loop to remove all queued packets. */ + while (next_packet_ptr) + { + + /* Pickup the packet pointer at the head of the queue. */ + packet_ptr = next_packet_ptr; + + /* Move to the next packet in the queue. */ + next_packet_ptr = next_packet_ptr -> nx_packet_queue_next; + + /* Clear the next packet queue pointer. */ + packet_ptr -> nx_packet_queue_next = NX_NULL; + +#ifndef NX_DISABLE_IP_INFO + + /* Increment the IP send packets dropped count. */ + ip_ptr -> nx_ip_send_packets_dropped++; +#endif + + /* Release the packet that was queued from the previous ARP entry. */ + _nx_packet_transmit_release(packet_ptr); + } + } + + /* Determine if we are at the end of the dynamic list. */ + if (arp_entry -> nx_arp_pool_next != last_arp_entry) + { + + /* No, simply move to the next dynamic entry. */ + arp_entry = arp_entry -> nx_arp_pool_next; + } + else + { + + /* Yes, we are at the end of the dynamic list, break out of the loop. */ + break; + } + } + + /* Release the mutex. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return successful status to the caller. */ + return(NX_SUCCESS); +} + diff --git a/common/src/nx_arp_dynamic_entry_set.c b/common/src/nx_arp_dynamic_entry_set.c new file mode 100644 index 0000000..619853f --- /dev/null +++ b/common/src/nx_arp_dynamic_entry_set.c @@ -0,0 +1,306 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Address Resolution Protocol (ARP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_arp.h" +#include "nx_ip.h" +#include "nx_packet.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_arp_dynamic_entry_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function allocates an ARP dynamic entry for the application */ +/* and assigns the specified IP to hardware mapping. If the specified */ +/* hardware address is zero, an actual ARP request will be sent out. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP instance pointer */ +/* ip_address IP Address to bind to */ +/* physical_msw Physical address MSW */ +/* physical_lsw Physical address LSW */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_arp_entry_allocate Allocate an ARP entry */ +/* _nx_arp_packet_send Send ARP request */ +/* _nx_packet_transmit_release Release ARP queued packet */ +/* tx_mutex_get Obtain protection mutex */ +/* tx_mutex_put Release protection mutex */ +/* _nx_ip_route_find Find suitable outgoing */ +/* interface */ +/* (nx_ip_fragment_processing) Fragment processing */ +/* (ip_link_driver) User supplied link driver */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_arp_dynamic_entry_set(NX_IP *ip_ptr, ULONG ip_address, + ULONG physical_msw, ULONG physical_lsw) +{ + +TX_INTERRUPT_SAVE_AREA +NX_ARP *arp_ptr; +NX_ARP *search_ptr; +NX_ARP *arp_list_head; +UINT index; +UINT status; +NX_IP_DRIVER driver_request; +NX_PACKET *queued_list_head; +NX_PACKET *packet_ptr; +NX_INTERFACE *nx_interface = NX_NULL; +ULONG next_hop_address = 0; + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_ARP_DYNAMIC_ENTRY_SET, ip_ptr, ip_address, physical_msw, physical_lsw, NX_TRACE_ARP_EVENTS, 0, 0) + + /* Make sure the destination address is directly accessible. */ + if ((_nx_ip_route_find(ip_ptr, ip_address, &nx_interface, &next_hop_address) != NX_SUCCESS) || + (next_hop_address != ip_address)) + { + + return(NX_IP_ADDRESS_ERROR); + } + + + /* Obtain protection on this IP instance for access into the ARP dynamic + list. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Calculate the hash index for the specified IP address. */ + index = (UINT)((ip_address + (ip_address >> 8)) & NX_ROUTE_TABLE_MASK); + + /* Pickup the head pointer of the ARP entries for this IP instance. */ + arp_list_head = ip_ptr -> nx_ip_arp_table[index]; + + /* Search the ARP list for the same IP address. */ + search_ptr = arp_list_head; + arp_ptr = NX_NULL; + while (search_ptr) + { + + /* Determine if there is a duplicate IP address. */ + if (search_ptr -> nx_arp_ip_address == ip_address) + { + + /* Yes, the IP address matches, setup the ARP entry pointer. */ + arp_ptr = search_ptr; + + /* Get out of the loop. */ + break; + } + + /* Move to the next entry in the active list. */ + search_ptr = search_ptr -> nx_arp_active_next; + + /* Determine if the search pointer is back at the head of + the list. */ + if (search_ptr == arp_list_head) + { + + /* End of the ARP list, end the search. */ + break; + } + } + + /* Determine if we didn't find an ARP entry and need to allocate a new + dynamic entry. */ + if (arp_ptr == NX_NULL) + { + + /* No matching IP address in the ARP cache. */ + + /* Allocate a dynamic ARP entry. */ + status = _nx_arp_entry_allocate(ip_ptr, &(ip_ptr -> nx_ip_arp_table[index])); + + /* Determine if an error occurred. */ + if (status != NX_SUCCESS) + { + + /* Release the mutex. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return the error status. */ + return(status); + } + + /* Otherwise, setup a pointer to the new ARP entry. The newly allocated + ARP entry was allocated at the end of the ARP list so it should be + referenced using the previous pointer from the list head. */ + 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 = ip_address; + arp_ptr -> nx_arp_physical_address_msw = physical_msw; + arp_ptr -> nx_arp_physical_address_lsw = physical_lsw; + arp_ptr -> nx_arp_retries = 0; + arp_ptr -> nx_arp_entry_next_update = NX_ARP_EXPIRATION_RATE; + arp_ptr -> nx_arp_ip_interface = nx_interface; + + /* Determine if a physical address was supplied. */ + if ((physical_msw | physical_lsw) == 0) + { + + /* Since there isn't physical mapping, change the update rate + for possible ARP retries. */ + arp_ptr -> nx_arp_entry_next_update = NX_ARP_UPDATE_RATE; + + + /* The physical address was not specified so send an + ARP request for the selected IP address. */ + _nx_arp_packet_send(ip_ptr, ip_address, nx_interface); + + /* Release the protection on the ARP list. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return status to the caller. */ + return(NX_SUCCESS); + } + else + { + + /* A physical address was supplied. */ + + /* Initialize the queued list head to NULL. */ + queued_list_head = NX_NULL; + + /* Determine if this ARP entry has a packet queued up for + sending. */ + + /* Disable interrupts before checking. */ + TX_DISABLE + + /* Look at the ARP packet queue pointer. */ + if (arp_ptr -> nx_arp_packets_waiting) + { + + /* Pickup the packet pointer and clear the ARP queue pointer. */ + queued_list_head = arp_ptr -> nx_arp_packets_waiting; + arp_ptr -> nx_arp_packets_waiting = NX_NULL; + } + + /* Restore previous interrupt posture. */ + TX_RESTORE + + /* Are there any packets queued to send? */ + while (queued_list_head) + { + + /* Pickup the first entry on the list. */ + packet_ptr = queued_list_head; + + /* Move to the next entry on the ARP packet queue. */ + queued_list_head = queued_list_head -> nx_packet_queue_next; + + /* Clear the packet's queue next pointer. */ + packet_ptr -> nx_packet_queue_next = NX_NULL; + + packet_ptr -> nx_packet_ip_interface = nx_interface; + + /* Build the driver request packet. */ + driver_request.nx_ip_driver_physical_address_msw = physical_msw; + driver_request.nx_ip_driver_physical_address_lsw = physical_lsw; + 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_ip_interface; + + /* Determine if fragmentation is needed. */ + if (packet_ptr -> nx_packet_length > packet_ptr -> nx_packet_ip_interface -> 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); + } + } + else + { + +#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_IP_HEADER); +#endif + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_IO_DRIVER_PACKET_SEND, ip_ptr, packet_ptr, packet_ptr -> nx_packet_length, 0, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + /* Send the queued IP packet out on the network via the attached driver. */ + (packet_ptr -> nx_packet_ip_interface -> nx_interface_link_driver_entry) (&driver_request); + } + } + + /* Release the protection on the ARP list. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return status to the caller. */ + return(NX_SUCCESS); + } +} + diff --git a/common/src/nx_arp_enable.c b/common/src/nx_arp_enable.c new file mode 100644 index 0000000..a4cf8d2 --- /dev/null +++ b/common/src/nx_arp_enable.c @@ -0,0 +1,150 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Address Resolution Protocol (ARP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_arp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_arp_enable PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function enables the ARP management component for the */ +/* specified IP instance. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP instance pointer */ +/* arp_cache_memory Start of ARP cache memory */ +/* arp_cache_size Size in bytes of cache memory */ +/* */ +/* 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_arp_enable(NX_IP *ip_ptr, VOID *arp_cache_memory, ULONG arp_cache_size) +{ + +ULONG i; +ULONG arp_entries; +NX_ARP *entry_ptr; + + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_ARP_ENABLE, ip_ptr, arp_cache_memory, arp_cache_size, 0, NX_TRACE_ARP_EVENTS, 0, 0) + + /* Clear the entire ARP cache. */ + memset((void *)arp_cache_memory, 0, arp_cache_size); + + /* Pickup starting address of ARP entry array. */ + entry_ptr = (NX_ARP *)arp_cache_memory; + + /* Determine how many ARP entries will fit in this cache area. */ + arp_entries = arp_cache_size / sizeof(NX_ARP); + + /* Setup the list head pointers in the IP instance. At first all ARP + entries are associated with the dynamic ARP list. The static ARP list + is NULL until static ARP entry calls are made. */ + ip_ptr -> nx_ip_arp_static_list = NX_NULL; + ip_ptr -> nx_ip_arp_dynamic_list = entry_ptr; + + /* Initialize the forward pointers of available ARP entries. */ + for (i = 0; i < (arp_entries - 1); i++) + { + /* Setup each entry to point to the next entry. */ + entry_ptr -> nx_arp_pool_next = entry_ptr + 1; + entry_ptr++; + } + + /* The entry now points to the last entry in the ARP array. Set its + next pointer to the first entry. */ + entry_ptr -> nx_arp_pool_next = (NX_ARP *)arp_cache_memory; + + /* Initialize the backward pointers of available ARP entries. */ + for (i = 0; i < (arp_entries - 1); i++) + { + /* Setup each entry to point to the previous entry. */ + entry_ptr -> nx_arp_pool_previous = entry_ptr - 1; + entry_ptr--; + } + + /* The entry now points to the first entry, set the previous pointer + to the last entry. */ + entry_ptr -> nx_arp_pool_previous = (entry_ptr + (arp_entries - 1)); + + /* At this point, everything is okay in the ARP enable call.. populate the + information in the IP structure. */ + + /* Setup the list head pointers in the IP instance. At first all ARP + entries are associated with the dynamic ARP list. The static ARP list + is NULL until static ARP entry calls are made. */ + ip_ptr -> nx_ip_arp_static_list = NX_NULL; + ip_ptr -> nx_ip_arp_dynamic_list = (NX_ARP *)arp_cache_memory; + + /* Store the initial ARP cache information in the IP control block. */ + ip_ptr -> nx_ip_arp_cache_memory = arp_cache_memory; + ip_ptr -> nx_ip_arp_total_entries = arp_entries; + + /* Setup the ARP periodic update routine. */ + ip_ptr -> nx_ip_arp_periodic_update = _nx_arp_periodic_update; + + /* Setup the ARP queue process routine. */ + ip_ptr -> nx_ip_arp_queue_process = _nx_arp_queue_process; + + /* Setup the ARP send packet routine. */ + ip_ptr -> nx_ip_arp_packet_send = _nx_arp_packet_send; + + /* Setup the ARP allocate service request pointer. */ + ip_ptr -> nx_ip_arp_allocate = _nx_arp_entry_allocate; + + /* Return successful completion. */ + return(NX_SUCCESS); +} + diff --git a/common/src/nx_arp_entry_allocate.c b/common/src/nx_arp_entry_allocate.c new file mode 100644 index 0000000..2a203e4 --- /dev/null +++ b/common/src/nx_arp_entry_allocate.c @@ -0,0 +1,230 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Address Resolution Protocol (ARP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_arp.h" +#include "nx_ip.h" +#include "nx_packet.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_arp_entry_allocate PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function allocates an ARP entry for a specific new IP */ +/* destination. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP instance pointer */ +/* arp_list_ptr List head of where to place */ +/* the newly allocated ARP */ +/* entry */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_packet_transmit_release Release queued packet */ +/* */ +/* CALLED BY */ +/* */ +/* NetX Source Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_arp_entry_allocate(NX_IP *ip_ptr, NX_ARP **arp_list_ptr) +{ + +TX_INTERRUPT_SAVE_AREA +NX_ARP *arp_entry; +UINT status; +NX_PACKET *packet_ptr; +NX_PACKET *next_packet_ptr; + + + /* Determine if there is an ARP entry available in the dynamic list. */ + if (ip_ptr -> nx_ip_arp_dynamic_list) + { + + /* Yes there are one or more free entries. */ + + /* Pickup pointer to last used dynamic ARP entry. */ + arp_entry = (ip_ptr -> nx_ip_arp_dynamic_list) -> nx_arp_pool_previous; + + /* Determine if this ARP entry is already active. */ + if (arp_entry -> nx_arp_active_list_head) + { + + /* Remove this dynamic ARP entry from the associated list. */ + + /* Disable interrupts. */ + TX_DISABLE + + /* Determine if this is the only ARP entry on the list. */ + if (arp_entry == arp_entry -> nx_arp_active_next) + { + + /* Remove the entry from the list. */ + *(arp_entry -> nx_arp_active_list_head) = NX_NULL; + } + else + { + + /* Remove the entry from a list of more than one entry. */ + + /* Update the list head pointer. */ + if (*(arp_entry -> nx_arp_active_list_head) == arp_entry) + { + *(arp_entry -> nx_arp_active_list_head) = arp_entry -> nx_arp_active_next; + } + + /* Update the links of the adjacent ARP entries. */ + (arp_entry -> nx_arp_active_next) -> nx_arp_active_previous = + arp_entry -> nx_arp_active_previous; + (arp_entry -> nx_arp_active_previous) -> nx_arp_active_next = + arp_entry -> nx_arp_active_next; + } + + /* Decrease the number of active ARP entries. */ + ip_ptr -> nx_ip_arp_dynamic_active_count--; + + /* Pickup the queued packets head pointer. */ + next_packet_ptr = arp_entry -> nx_arp_packets_waiting; + + /* Clear the queued packets head pointer. */ + arp_entry -> nx_arp_packets_waiting = NX_NULL; + + /* Restore interrupts. */ + TX_RESTORE + + /* Loop to remove all queued packets. */ + while (next_packet_ptr) + { + + /* Pickup the packet pointer at the head of the queue. */ + packet_ptr = next_packet_ptr; + + /* Move to the next packet in the queue. */ + next_packet_ptr = next_packet_ptr -> nx_packet_queue_next; + + /* Clear the next packet queue pointer. */ + packet_ptr -> nx_packet_queue_next = NX_NULL; + +#ifndef NX_DISABLE_IP_INFO + + /* Increment the IP send packets dropped count. */ + ip_ptr -> nx_ip_send_packets_dropped++; +#endif + + /* Release the packet that was queued from the previous ARP entry. */ + _nx_packet_transmit_release(packet_ptr); + } + } + + /* Link the ARP entry at the head of the IP list. */ + + /* Determine if the ARP entry is being added to an empty list. */ + if (*arp_list_ptr) + { + + /* Add the ARP entry to the beginning of the nonempty ARP + list. */ + arp_entry -> nx_arp_active_list_head = arp_list_ptr; + arp_entry -> nx_arp_active_next = *arp_list_ptr; + arp_entry -> nx_arp_active_previous = (*arp_list_ptr) -> nx_arp_active_previous; + (arp_entry -> nx_arp_active_previous) -> nx_arp_active_next = arp_entry; + (*arp_list_ptr) -> nx_arp_active_previous = arp_entry; + } + else + { + + /* Empty list, just put the ARP entry at the beginning. */ + arp_entry -> nx_arp_active_list_head = arp_list_ptr; + arp_entry -> nx_arp_active_next = arp_entry; + arp_entry -> nx_arp_active_previous = arp_entry; + + /* Now setup the list head. */ + *arp_list_ptr = arp_entry; + } + + /* Move this ARP entry to the front of the general ARP dynamic entry pool. */ + if (arp_entry != ip_ptr -> nx_ip_arp_dynamic_list) + { + + /* The current ARP entry is not at the front of the list, so it + must be moved. */ + + /* Link up the neighbors first. */ + (arp_entry -> nx_arp_pool_next) -> nx_arp_pool_previous = + arp_entry -> nx_arp_pool_previous; + (arp_entry -> nx_arp_pool_previous) -> nx_arp_pool_next = + arp_entry -> nx_arp_pool_next; + + /* Now link this ARP entry to the head of the list. */ + arp_entry -> nx_arp_pool_next = ip_ptr -> nx_ip_arp_dynamic_list; + arp_entry -> nx_arp_pool_previous = (arp_entry -> nx_arp_pool_next) -> nx_arp_pool_previous; + (arp_entry -> nx_arp_pool_previous) -> nx_arp_pool_next = arp_entry; + (arp_entry -> nx_arp_pool_next) -> nx_arp_pool_previous = arp_entry; + + /* Now set the list head to this ARP entry. */ + ip_ptr -> nx_ip_arp_dynamic_list = arp_entry; + } + + /* Increment the number of active dynamic entries. */ + ip_ptr -> nx_ip_arp_dynamic_active_count++; + + /* Setup a successful status return. */ + status = NX_SUCCESS; + } + else + { + + /* No more ARP entries are available, all the ARP entries must be + allocated on the static list. */ + status = NX_NO_MORE_ENTRIES; + } + + /* Return status to the caller. */ + return(status); +} + diff --git a/common/src/nx_arp_gratuitous_send.c b/common/src/nx_arp_gratuitous_send.c new file mode 100644 index 0000000..10edaf7 --- /dev/null +++ b/common/src/nx_arp_gratuitous_send.c @@ -0,0 +1,107 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Address Resolution Protocol (ARP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_arp.h" +#include "nx_packet.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_arp_gratuitous_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function builds a Gratuitous ARP packet and calls the */ +/* associated driver to send it out on all attached interfaces. */ +/* If a response is received at a later time, the supplied response */ +/* handler is called. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP instance */ +/* response_handler Pointer to function to handle */ +/* Gratuitous ARP response */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_arp_announce_send Send ARP announce */ +/* tx_mutex_get Get protection mutex */ +/* tx_mutex_put Put protection mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_arp_gratuitous_send(NX_IP *ip_ptr, VOID (*response_handler)(NX_IP *ip_ptr, NX_PACKET *packet_ptr)) +{ + +ULONG i; + + /* Get mutex protection. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Save the response handler in the IP structure. */ + ip_ptr -> nx_ip_arp_gratuitous_response_handler = response_handler; + + /* Release mutex protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + for (i = 0; i < NX_MAX_PHYSICAL_INTERFACES; i++) + { + + /* Skip the entry the IP address is invalid */ + if (ip_ptr -> nx_ip_interface[i].nx_interface_ip_address == 0) + { + continue; + } + + /* Send ARP announce. */ + _nx_arp_announce_send(ip_ptr, i); + } + + /* Return a successful completion. */ + return(NX_SUCCESS); +} + diff --git a/common/src/nx_arp_hardware_address_find.c b/common/src/nx_arp_hardware_address_find.c new file mode 100644 index 0000000..0593053 --- /dev/null +++ b/common/src/nx_arp_hardware_address_find.c @@ -0,0 +1,213 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Address Resolution Protocol (ARP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_arp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_arp_hardware_address_find PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function searches for the specified IP address in the ARP */ +/* lists. If found, the associated hardware address is returned. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP instance pointer */ +/* ip_address IP Address to search for */ +/* physical_msw Physical address MSW pointer */ +/* physical_lsw Physical address LSW pointer */ +/* */ +/* 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_arp_hardware_address_find(NX_IP *ip_ptr, ULONG ip_address, + ULONG *physical_msw, ULONG *physical_lsw) +{ + +NX_ARP *arp_entry; +ULONG count; + +#ifdef TX_ENABLE_EVENT_TRACE +TX_TRACE_BUFFER_ENTRY *trace_event; +ULONG trace_timestamp; +#endif + + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_ARP_HARDWARE_ADDRESS_FIND, ip_ptr, ip_address, 0, 0, NX_TRACE_ARP_EVENTS, &trace_event, &trace_timestamp) + + /* Obtain protection on this IP instance for access into the ARP static + list. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Search the static list for a matching IP and hardware mapping. */ + arp_entry = ip_ptr -> nx_ip_arp_static_list; + while (arp_entry) + { + + /* Determine if we have a match. */ + if ((arp_entry -> nx_arp_ip_address == ip_address) && + (arp_entry -> nx_arp_physical_address_msw | arp_entry -> nx_arp_physical_address_lsw)) + { + + /* Yes, we have found the ARP entry we are looking for. */ + break; + } + else + { + + /* Determine if we are at the end of the list. */ + if (arp_entry -> nx_arp_pool_next == ip_ptr -> nx_ip_arp_static_list) + { + + /* Set the arp_entry to NULL to signify nothing was found and get + out of the search loop. */ + arp_entry = NX_NULL; + break; + } + else + { + + /* Just move to the next ARP entry on the static list. */ + arp_entry = arp_entry -> nx_arp_pool_next; + } + } + } + + /* Determine if an entry has been found. If so, we are finished and it needs to be + returned to the caller. */ + if (arp_entry) + { + + /* Store the hardware address in the return fields. */ + *physical_msw = arp_entry -> nx_arp_physical_address_msw; + *physical_lsw = arp_entry -> nx_arp_physical_address_lsw; + + /* Update the trace event with the status. */ + NX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, NX_TRACE_ARP_HARDWARE_ADDRESS_FIND, 0, 0, *physical_msw, *physical_lsw) + + /* Release the protection on the ARP list. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return status to the caller. */ + return(NX_SUCCESS); + } + + /* Otherwise, we need to search the ARP dynamic list for a match. */ + arp_entry = ip_ptr -> nx_ip_arp_dynamic_list; + count = 1; + while (arp_entry) + { + + /* Determine if we have a match. */ + if ((arp_entry -> nx_arp_ip_address == ip_address) && + (arp_entry -> nx_arp_physical_address_msw | arp_entry -> nx_arp_physical_address_lsw)) + { + + /* Yes, we have found the ARP entry we are looking for. */ + break; + } + else + { + + /* Determine if we are at the end of the list of active ARP entries. */ + if (count >= ip_ptr -> nx_ip_arp_dynamic_active_count) + { + + /* Set the arp_entry to NULL to signify nothing was found and get + out of the search loop. */ + arp_entry = NX_NULL; + break; + } + else + { + + /* Just move to the next ARP entry on the dynamic list. */ + arp_entry = arp_entry -> nx_arp_pool_next; + + /* Increment the active count. */ + count++; + } + } + } + + /* Determine if an entry has been found. If so, we are finished and it needs to be + returned to the caller. */ + if (arp_entry) + { + + /* Store the hardware address in the return fields. */ + *physical_msw = arp_entry -> nx_arp_physical_address_msw; + *physical_lsw = arp_entry -> nx_arp_physical_address_lsw; + + /* Update the trace event with the status. */ + NX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, NX_TRACE_ARP_HARDWARE_ADDRESS_FIND, 0, 0, *physical_msw, *physical_lsw) + + /* Release the protection on the ARP list. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return status to the caller. */ + return(NX_SUCCESS); + } + else + { + + /* Release the protection on the ARP list. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return status to the caller. */ + return(NX_ENTRY_NOT_FOUND); + } +} + diff --git a/common/src/nx_arp_info_get.c b/common/src/nx_arp_info_get.c new file mode 100644 index 0000000..08f11c7 --- /dev/null +++ b/common/src/nx_arp_info_get.c @@ -0,0 +1,170 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Address Resolution Protocol (ARP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_arp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_arp_info_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function obtains ARP information for the specified IP */ +/* instance. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP instance pointer */ +/* arp_requests_sent Destination for number of ARP */ +/* requests sent */ +/* arp_requests_received Destination for number of ARP */ +/* requests received */ +/* arp_responses_sent Destination for number of ARP */ +/* responses sent */ +/* arp_responses_received Destination for number of ARP */ +/* responses received */ +/* arp_dynamic_entries Destination for number of ARP */ +/* dynamic entries */ +/* arp_static_entries Destination for number of ARP */ +/* static entries */ +/* arp_aged_entries Destination for number of ARP */ +/* aged entries */ +/* arp_invalid_messages Destination for number of ARP */ +/* invalid messages */ +/* */ +/* 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_arp_info_get(NX_IP *ip_ptr, ULONG *arp_requests_sent, ULONG *arp_requests_received, + ULONG *arp_responses_sent, ULONG *arp_responses_received, + ULONG *arp_dynamic_entries, ULONG *arp_static_entries, + ULONG *arp_aged_entries, ULONG *arp_invalid_messages) +{ + + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_ARP_INFO_GET, ip_ptr, ip_ptr -> nx_ip_arp_requests_sent, ip_ptr -> nx_ip_arp_responses_received, ip_ptr -> nx_ip_arp_requests_received, NX_TRACE_ARP_EVENTS, 0, 0) + + /* Obtain protection on this IP instance. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Determine if ARP requests sent is wanted. */ + if (arp_requests_sent) + { + + /* Return the number of ARP requests sent by this IP instance. */ + *arp_requests_sent = ip_ptr -> nx_ip_arp_requests_sent; + } + + /* Determine if ARP requests received is wanted. */ + if (arp_requests_received) + { + + /* Return the number of ARP requests received by this IP instance. */ + *arp_requests_received = ip_ptr -> nx_ip_arp_requests_received; + } + + /* Determine if ARP responses sent is wanted. */ + if (arp_responses_sent) + { + + /* Return the number of ARP responses sent by this IP instance. */ + *arp_responses_sent = ip_ptr -> nx_ip_arp_responses_sent; + } + + /* Determine if ARP responses received is wanted. */ + if (arp_responses_received) + { + + /* Return the number of ARP responses received by this IP instance. */ + *arp_responses_received = ip_ptr -> nx_ip_arp_responses_received; + } + + /* Determine if ARP dynamic entries is wanted. */ + if (arp_dynamic_entries) + { + + /* Return the number of ARP dynamic entries in this IP instance. */ + *arp_dynamic_entries = ip_ptr -> nx_ip_arp_dynamic_active_count; + } + + /* Determine if ARP static entries is wanted. */ + if (arp_static_entries) + { + + /* Return the number of ARP static entries in this IP instance. */ + *arp_static_entries = ip_ptr -> nx_ip_arp_static_entries; + } + + /* Determine if ARP aged entries is wanted. */ + if (arp_aged_entries) + { + + /* Return the number of ARP aged entries by this IP instance. */ + *arp_aged_entries = ip_ptr -> nx_ip_arp_aged_entries; + } + + /* Determine if ARP invalid messages is wanted. */ + if (arp_invalid_messages) + { + + /* Return the number of ARP invalid messages handled by this IP instance. */ + *arp_invalid_messages = ip_ptr -> nx_ip_arp_invalid_messages; + } + + /* Release the protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return status to the caller. */ + return(NX_SUCCESS); +} + diff --git a/common/src/nx_arp_ip_address_find.c b/common/src/nx_arp_ip_address_find.c new file mode 100644 index 0000000..1ca0bb7 --- /dev/null +++ b/common/src/nx_arp_ip_address_find.c @@ -0,0 +1,211 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Address Resolution Protocol (ARP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_arp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_arp_ip_address_find PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function searches for the specified hardware address in the */ +/* ARP lists. If found, the associated IP address is returned. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP instance pointer */ +/* ip_address IP Address return pointer */ +/* physical_msw Physical address MSW */ +/* physical_lsw Physical address LSW */ +/* */ +/* 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_arp_ip_address_find(NX_IP *ip_ptr, ULONG *ip_address, + ULONG physical_msw, ULONG physical_lsw) +{ + +NX_ARP *arp_entry; +ULONG count; + +#ifdef TX_ENABLE_EVENT_TRACE +TX_TRACE_BUFFER_ENTRY *trace_event; +ULONG trace_timestamp; +#endif + + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_ARP_IP_ADDRESS_FIND, ip_ptr, 0, physical_msw, physical_lsw, NX_TRACE_ARP_EVENTS, &trace_event, &trace_timestamp) + + /* Obtain protection on this IP instance for access into the ARP static + list. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Search the static list for matching hardware mapping. */ + arp_entry = ip_ptr -> nx_ip_arp_static_list; + while (arp_entry) + { + + /* Determine if we have a hardware address match. */ + if ((arp_entry -> nx_arp_physical_address_msw == physical_msw) && + (arp_entry -> nx_arp_physical_address_lsw == physical_lsw)) + { + + /* Yes, we have found the ARP entry we are looking for. */ + break; + } + else + { + + /* Determine if we are at the end of the list. */ + if (arp_entry -> nx_arp_pool_next == ip_ptr -> nx_ip_arp_static_list) + { + + /* Set the arp_entry to NULL to signify nothing was found and get + out of the search loop. */ + arp_entry = NX_NULL; + break; + } + else + { + + /* Just move to the next ARP entry on the static list. */ + arp_entry = arp_entry -> nx_arp_pool_next; + } + } + } + + /* Determine if an entry has been found. If so, we are finished and it needs to be + returned to the caller. */ + if (arp_entry) + { + + /* Store the IP address in the return field. */ + *ip_address = arp_entry -> nx_arp_ip_address; + + /* Update the trace event with the status. */ + NX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, NX_TRACE_ARP_IP_ADDRESS_FIND, 0, *ip_address, 0, 0) + + /* Release the protection on the ARP list. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return status to the caller. */ + return(NX_SUCCESS); + } + + /* Otherwise, we need to search the ARP dynamic list for a match. */ + arp_entry = ip_ptr -> nx_ip_arp_dynamic_list; + count = 1; + while (arp_entry) + { + + /* Determine if we have a hardware address match. */ + if ((arp_entry -> nx_arp_physical_address_msw == physical_msw) && + (arp_entry -> nx_arp_physical_address_lsw == physical_lsw)) + { + + /* Yes, we have found the ARP entry we are looking for. */ + break; + } + else + { + + /* Determine if we are at the end of the list of active ARP entries. */ + if (count >= ip_ptr -> nx_ip_arp_dynamic_active_count) + { + + /* Set the arp_entry to NULL to signify nothing was found and get + out of the search loop. */ + arp_entry = NX_NULL; + break; + } + else + { + + /* Just move to the next ARP entry on the dynamic list. */ + arp_entry = arp_entry -> nx_arp_pool_next; + + /* Increment the active count. */ + count++; + } + } + } + + /* Determine if an entry has been found. If so, we are finished and it needs to be + returned to the caller. */ + if (arp_entry) + { + + /* Store the IP address in the return fields. */ + *ip_address = arp_entry -> nx_arp_ip_address; + + /* Update the trace event with the status. */ + NX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, NX_TRACE_ARP_IP_ADDRESS_FIND, 0, *ip_address, 0, 0) + + /* Release the protection on the ARP list. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return status to the caller. */ + return(NX_SUCCESS); + } + else + { + + /* Release the protection on the ARP list. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return status to the caller. */ + return(NX_ENTRY_NOT_FOUND); + } +} + diff --git a/common/src/nx_arp_packet_deferred_receive.c b/common/src/nx_arp_packet_deferred_receive.c new file mode 100644 index 0000000..929e6de --- /dev/null +++ b/common/src/nx_arp_packet_deferred_receive.c @@ -0,0 +1,134 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Address Resolution Protocol (ARP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_packet.h" +#include "nx_arp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_arp_packet_deferred_receive PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function receives an ARP packet from the link driver (usually */ +/* the link driver's input ISR) and places it in the deferred receive */ +/* ARP packet queue. This moves the minimal receive ARP packet */ +/* processing from the ISR to the IP helper thread. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP control block */ +/* packet_ptr Pointer to packet to send */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* tx_event_flags_set Wakeup IP helper thread */ +/* */ +/* CALLED BY */ +/* */ +/* Application I/O Driver */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_arp_packet_deferred_receive(NX_IP *ip_ptr, NX_PACKET *packet_ptr) +{ + +TX_INTERRUPT_SAVE_AREA + + + /* Disable interrupts. */ + TX_DISABLE + + /* Check to see if ARP is enabled on this IP instance. */ + if (!ip_ptr -> nx_ip_arp_queue_process) + { + + /* ARP is not enabled. */ + +#ifndef NX_DISABLE_ARP_INFO + /* Increment the ARP invalid messages count... */ + ip_ptr -> nx_ip_arp_invalid_messages++; +#endif + + /* Restore interrupts. */ + TX_RESTORE + + /* Since ARP is not enabled, just release the packet. */ + _nx_packet_release(packet_ptr); + + /* Return to caller. */ + return; + } + + /* Check to see if the ARP deferred processing queue is empty. */ + if (ip_ptr -> nx_ip_arp_deferred_received_packet_head) + { + + /* Not empty, just place the packet at the end of the ARP deferred queue. */ + (ip_ptr -> nx_ip_arp_deferred_received_packet_tail) -> nx_packet_queue_next = packet_ptr; + packet_ptr -> nx_packet_queue_next = NX_NULL; + ip_ptr -> nx_ip_arp_deferred_received_packet_tail = packet_ptr; + + /* Restore interrupts. */ + TX_RESTORE + } + else + { + + /* Empty ARP deferred receive processing queue. Just setup the head pointers and + set the event flags to ensure the IP helper thread looks at the ARP deferred + processing queue. */ + ip_ptr -> nx_ip_arp_deferred_received_packet_head = packet_ptr; + ip_ptr -> nx_ip_arp_deferred_received_packet_tail = packet_ptr; + packet_ptr -> nx_packet_queue_next = NX_NULL; + + /* Restore interrupts. */ + TX_RESTORE + + /* Wakeup IP helper thread to process the ARP deferred receive. */ + tx_event_flags_set(&(ip_ptr -> nx_ip_events), NX_IP_ARP_REC_EVENT, TX_OR); + } +} + diff --git a/common/src/nx_arp_packet_receive.c b/common/src/nx_arp_packet_receive.c new file mode 100644 index 0000000..6fee9ac --- /dev/null +++ b/common/src/nx_arp_packet_receive.c @@ -0,0 +1,630 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Address Resolution Protocol (ARP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_arp.h" +#include "nx_ip.h" +#include "nx_packet.h" + + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_arp_packet_receive PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes the reception of both the ARP request and */ +/* the ARP response. ARP requests are filled in and sent out as ARP */ +/* responses. ARP responses received are used to update this IP's */ +/* ARP cache and dequeue and send any waiting packet. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP instance */ +/* packet_ptr Received ARP packet */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_packet_release Release the ARP request */ +/* _nx_packet_transmit_release Release ARP queued packet */ +/* (nx_ip_arp_allocate) ARP entry allocate call */ +/* (nx_ip_arp_gratuitous_response_handler) ARP gratuitous response */ +/* (nx_ip_fragment_processing) Fragment processing */ +/* (ip_link_driver) User supplied link driver */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_arp_queue_process ARP receive queue processing */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_arp_packet_receive(NX_IP *ip_ptr, NX_PACKET *packet_ptr) +{ + +TX_INTERRUPT_SAVE_AREA + +ULONG *message_ptr; +ULONG sender_physical_msw; +ULONG sender_physical_lsw; +ULONG sender_ip; +ULONG target_ip; +UINT message_type; +UINT i; +ULONG index = 0; +UCHAR consumed = NX_FALSE; +NX_ARP *arp_ptr; +NX_IP_DRIVER driver_request; +NX_PACKET *queued_list_head; +NX_INTERFACE *interface_ptr; + + +#ifndef NX_DISABLE_RX_SIZE_CHECKING + /* Determine if the packet length is valid. */ + if (packet_ptr -> nx_packet_length < NX_ARP_MESSAGE_SIZE) + { + + /* Invalid ARP message. Release the packet and return. */ + +#ifndef NX_DISABLE_ARP_INFO + /* Increment the ARP invalid messages count. */ + ip_ptr -> nx_ip_arp_invalid_messages++; +#endif + + /* Invalid ARP message. Just release the packet. */ + _nx_packet_release(packet_ptr); + + /* Return to caller. */ + return; + } +#endif /* NX_DISABLE_RX_SIZE_CHECKING */ + + /* Setup a pointer to the ARP message. */ + message_ptr = (ULONG *)packet_ptr -> nx_packet_prepend_ptr; + + /* Endian swapping logic. If NX_LITTLE_ENDIAN is specified, these macros will + swap the endian of the ARP message. */ + NX_CHANGE_ULONG_ENDIAN(*(message_ptr + 1)); + NX_CHANGE_ULONG_ENDIAN(*(message_ptr + 2)); + NX_CHANGE_ULONG_ENDIAN(*(message_ptr + 3)); + NX_CHANGE_ULONG_ENDIAN(*(message_ptr + 4)); + NX_CHANGE_ULONG_ENDIAN(*(message_ptr + 5)); + NX_CHANGE_ULONG_ENDIAN(*(message_ptr + 6)); + + /* Pickup the ARP message type. */ + message_type = (UINT)(*(message_ptr + 1) & 0xFFFF); + + /* Check packet incoming interface. If the interface filed is not set, stamp it with + the first physical interface. */ + if (packet_ptr -> nx_packet_ip_interface == NX_NULL) + { + packet_ptr -> nx_packet_ip_interface = &ip_ptr -> nx_ip_interface[0]; + } + interface_ptr = packet_ptr -> nx_packet_ip_interface; + + + /* Determine if the ARP message type is valid. */ + if ((message_type != NX_ARP_OPTION_REQUEST) && (message_type != NX_ARP_OPTION_RESPONSE)) + { + + /* Invalid ARP message. Release the packet and return. */ + +#ifndef NX_DISABLE_ARP_INFO + /* Increment the ARP invalid messages count. */ + ip_ptr -> nx_ip_arp_invalid_messages++; +#endif + + /* Invalid ARP message. Just release the packet. */ + _nx_packet_release(packet_ptr); + + /* Return to caller. */ + return; + } + + /* Pickup the sender's physical address from the message. */ + sender_physical_msw = (*(message_ptr + 2) >> 16); + sender_physical_lsw = (*(message_ptr + 2) << 16) | (*(message_ptr + 3) >> 16); + sender_ip = (*(message_ptr + 3) << 16) | (*(message_ptr + 4) >> 16); + target_ip = *(message_ptr + 6); + + /* Determine if it is an IP address conflict when IP address probing. */ + if ((interface_ptr -> nx_interface_ip_address == 0) && + (interface_ptr -> nx_interface_ip_probe_address != 0) && + ((sender_ip == interface_ptr -> nx_interface_ip_probe_address) || + ((sender_ip == 0) && (target_ip == interface_ptr -> nx_interface_ip_probe_address)))) + { + + /* Make sure the sender physical address is not ours. */ + if ((sender_physical_msw != interface_ptr -> nx_interface_physical_address_msw) || + (sender_physical_lsw != interface_ptr -> nx_interface_physical_address_lsw)) + { + + /* Determine if there is a a IP address conflict notify handler. */ + if (interface_ptr -> nx_interface_ip_conflict_notify_handler) + { + + /* Find the index number of this interface. */ + for (i = 0; i < NX_MAX_PHYSICAL_INTERFACES; i++) + { + if (interface_ptr == &(ip_ptr -> nx_ip_interface[i])) + { + + /* A IP address conflict is present, call the notification handler. */ + (interface_ptr -> nx_interface_ip_conflict_notify_handler)(ip_ptr, i, interface_ptr -> nx_interface_ip_probe_address, + sender_physical_msw, sender_physical_lsw); + break; + } + } + } + } + + /* Release the packet. */ + _nx_packet_release(packet_ptr); + + return; + } + + /* Determine if it is an address conflict packet after set the IP address. */ + if ((sender_ip != 0) && (sender_ip == (packet_ptr -> nx_packet_ip_interface -> nx_interface_ip_address))) + { + + + /* Is it sent from other devices? */ + if ((sender_physical_msw != packet_ptr -> nx_packet_ip_interface -> nx_interface_physical_address_msw) || + (sender_physical_lsw != packet_ptr -> nx_packet_ip_interface -> nx_interface_physical_address_lsw)) + { + + /* Yes it is. */ + if (packet_ptr -> nx_packet_ip_interface -> nx_interface_arp_defend_timeout == 0) + { + + /* Set defend timeout. */ + packet_ptr -> nx_packet_ip_interface -> nx_interface_arp_defend_timeout = NX_ARP_DEFEND_INTERVAL; + + /* Send the announcement. */ + _nx_arp_packet_send(ip_ptr, sender_ip, packet_ptr -> nx_packet_ip_interface); + } + + /* Determine if there is a a IP address conflict notify handler. */ + if (interface_ptr -> nx_interface_ip_conflict_notify_handler) + { + + /* Find the index number of this interface. */ + for (i = 0; i < NX_MAX_PHYSICAL_INTERFACES; i++) + { + if (interface_ptr == &(ip_ptr -> nx_ip_interface[i])) + { + + /* A IP address conflict is present, call the notification handler. */ + (interface_ptr -> nx_interface_ip_conflict_notify_handler)(ip_ptr, i, interface_ptr -> nx_interface_ip_probe_address, + sender_physical_msw, sender_physical_lsw); + break; + } + } + } + + /* This is likely in response to our previous gratuitous ARP from another entity on the + network has the same IP address. */ + + /* Determine if there is a gratuitous ARP response handler. */ + if (ip_ptr -> nx_ip_arp_gratuitous_response_handler) + { + + /* Yes, call the gratuitous ARP response handler. Note that it is responsible + for releasing the packet! */ + (ip_ptr -> nx_ip_arp_gratuitous_response_handler)(ip_ptr, packet_ptr); + + return; + } + +#ifdef NX_ARP_DEFEND_BY_REPLY + +#ifndef NX_DISABLE_ARP_INFO + /* Increment the ARP responses sent count. */ + ip_ptr -> nx_ip_arp_responses_sent++; +#endif + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_ARP_RESPONSE_SEND, ip_ptr, sender_ip, packet_ptr, 0, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + /* Set the ARP message type to ARP response. */ + * (message_ptr + 1) = (*(message_ptr + 1) & 0xFFFF0000) | NX_ARP_OPTION_RESPONSE; + + /* Now fill in the new source and destination information for the ARP response. */ + *(message_ptr + 2) = (ULONG)(packet_ptr -> nx_packet_ip_interface -> nx_interface_physical_address_msw << 16) | + (packet_ptr -> nx_packet_ip_interface -> nx_interface_physical_address_lsw >> 16); + *(message_ptr + 3) = (ULONG)(packet_ptr -> nx_packet_ip_interface -> nx_interface_physical_address_lsw << 16) | + (packet_ptr -> nx_packet_ip_interface -> nx_interface_ip_address >> 16); + *(message_ptr + 4) = (ULONG)(packet_ptr -> nx_packet_ip_interface -> nx_interface_ip_address << 16); + *(message_ptr + 5) = (ULONG)0; + *(message_ptr + 6) = (ULONG)0; + + /* Endian swapping logic. If NX_LITTLE_ENDIAN is specified, these macros will + swap the endian of the ARP message. */ + NX_CHANGE_ULONG_ENDIAN(*(message_ptr + 1)); + NX_CHANGE_ULONG_ENDIAN(*(message_ptr + 2)); + NX_CHANGE_ULONG_ENDIAN(*(message_ptr + 3)); + NX_CHANGE_ULONG_ENDIAN(*(message_ptr + 4)); + NX_CHANGE_ULONG_ENDIAN(*(message_ptr + 5)); + NX_CHANGE_ULONG_ENDIAN(*(message_ptr + 6)); + + /* Make sure the packet length is set properly. */ + packet_ptr -> nx_packet_length = NX_ARP_MESSAGE_SIZE; + + /* Setup the append pointer, since the received ARP packet can be padded + with unnecessary bytes. */ + packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + NX_ARP_MESSAGE_SIZE; + + /* Send the ARP request to the driver. */ + driver_request.nx_ip_driver_ptr = ip_ptr; + driver_request.nx_ip_driver_command = NX_LINK_ARP_RESPONSE_SEND; + 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_ip_interface; + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_IO_DRIVER_ARP_RESPONSE_SEND, ip_ptr, packet_ptr, packet_ptr -> nx_packet_length, 0, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + /* No need to update packet_ptr -> nx_packet_ip_interface. When responding to an ARP request, use the same interface where the request was received. */ + + (packet_ptr -> nx_packet_ip_interface -> nx_interface_link_driver_entry) (&driver_request); + + return; +#endif /* NX_ARP_DEFEND_BY_REPLY */ + } + + /* Release the conflict packet. */ + _nx_packet_release(packet_ptr); + + return; + } + + /* Determine what type of ARP message this is. Note that ARP requests must + also specify this IP instance's IP address. */ + if ((message_type == NX_ARP_OPTION_REQUEST) && (*(message_ptr + 6) == (packet_ptr -> nx_packet_ip_interface -> nx_interface_ip_address))) + { + +#ifndef NX_DISABLE_ARP_INFO + + /* Increment the ARP requests received count. */ + ip_ptr -> nx_ip_arp_requests_received++; + + /* Increment the ARP responses sent count. */ + ip_ptr -> nx_ip_arp_responses_sent++; +#endif + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_ARP_REQUEST_RECEIVE, ip_ptr, sender_ip, packet_ptr, 0, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_ARP_RESPONSE_SEND, ip_ptr, sender_ip, packet_ptr, 0, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + /* Set the ARP message type to ARP response. */ + * (message_ptr + 1) = (*(message_ptr + 1) & 0xFFFF0000) | NX_ARP_OPTION_RESPONSE; + + /* Now fill in the new source and destination information for the ARP response. */ + *(message_ptr + 2) = (ULONG)(packet_ptr -> nx_packet_ip_interface -> nx_interface_physical_address_msw << 16) | + (packet_ptr -> nx_packet_ip_interface -> nx_interface_physical_address_lsw >> 16); + *(message_ptr + 3) = (ULONG)(packet_ptr -> nx_packet_ip_interface -> nx_interface_physical_address_lsw << 16) | + (packet_ptr -> nx_packet_ip_interface -> nx_interface_ip_address >> 16); + *(message_ptr + 4) = (ULONG)(packet_ptr -> nx_packet_ip_interface -> nx_interface_ip_address << 16) | sender_physical_msw; + *(message_ptr + 5) = (ULONG)sender_physical_lsw; + *(message_ptr + 6) = (ULONG)sender_ip; + + /* Endian swapping logic. If NX_LITTLE_ENDIAN is specified, these macros will + swap the endian of the ARP message. */ + NX_CHANGE_ULONG_ENDIAN(*(message_ptr + 1)); + NX_CHANGE_ULONG_ENDIAN(*(message_ptr + 2)); + NX_CHANGE_ULONG_ENDIAN(*(message_ptr + 3)); + NX_CHANGE_ULONG_ENDIAN(*(message_ptr + 4)); + NX_CHANGE_ULONG_ENDIAN(*(message_ptr + 5)); + NX_CHANGE_ULONG_ENDIAN(*(message_ptr + 6)); + + /* Make sure the packet length is set properly. */ + packet_ptr -> nx_packet_length = NX_ARP_MESSAGE_SIZE; + + /* Setup the append pointer, since the received ARP packet can be padded + with unnecessary bytes. */ + packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr + NX_ARP_MESSAGE_SIZE; + + /* Send the ARP request to the driver. */ + driver_request.nx_ip_driver_ptr = ip_ptr; + driver_request.nx_ip_driver_command = NX_LINK_ARP_RESPONSE_SEND; + driver_request.nx_ip_driver_packet = packet_ptr; + driver_request.nx_ip_driver_physical_address_msw = sender_physical_msw; + driver_request.nx_ip_driver_physical_address_lsw = sender_physical_lsw; + driver_request.nx_ip_driver_interface = packet_ptr -> nx_packet_ip_interface; + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_IO_DRIVER_ARP_RESPONSE_SEND, ip_ptr, packet_ptr, packet_ptr -> nx_packet_length, 0, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + /* No need to update packet_ptr -> nx_packet_ip_interface. When responding to an ARP request, use the same interface where the request was received. */ + + (packet_ptr -> nx_packet_ip_interface -> nx_interface_link_driver_entry) (&driver_request); + + /* Set the consumed as NX_TRUE, do not need to release the packet. */ + consumed = NX_TRUE; + } + else + { + + /* We have a response to a previous ARP request or Gratuitous ARP from another network entity. */ + +#ifndef NX_DISABLE_ARP_INFO + + /* Check for the message type to see which counter to increment. */ + if (message_type == NX_ARP_OPTION_REQUEST) + { + + /* Increment the ARP requests received count. */ + ip_ptr -> nx_ip_arp_requests_received++; + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_ARP_REQUEST_RECEIVE, ip_ptr, sender_ip, packet_ptr, 0, NX_TRACE_INTERNAL_EVENTS, 0, 0) + } + else + { + + /* Increment the ARP responses received count. */ + ip_ptr -> nx_ip_arp_responses_received++; + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_ARP_RESPONSE_RECEIVE, ip_ptr, sender_ip, packet_ptr, 0, NX_TRACE_INTERNAL_EVENTS, 0, 0) + } +#endif + } + + /* In either case, search the ARP cache to update any entry that matches the sender's IP + address. */ + + /* Set the queue list pointer to NULL. */ + queued_list_head = NX_NULL; + + /* Now we need to search through the active ARP list for the IP address + to see if there is a matching entry. */ + + /* Ignore anything from any ARP packet with a zero sender IP address. */ + if (sender_ip == 0) + { + arp_ptr = NX_NULL; + } + else + { + + /* Calculate the hash index for the sender IP address. */ + index = (UINT)((sender_ip + (sender_ip >> 8)) & NX_ROUTE_TABLE_MASK); + + /* 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 == sender_ip) + { + +#ifdef NX_ENABLE_ARP_MAC_CHANGE_NOTIFICATION + + /* Determine if there is a ARP collision notify handler. */ + if (ip_ptr -> nx_ip_arp_collision_notify_response_handler) + { + + /* Now check if the machine address is stored in our ARP cache. */ + if ((arp_ptr -> nx_arp_physical_address_msw != 0) || (arp_ptr -> nx_arp_physical_address_lsw != 0)) + { + + /* Now check if its machine address is different from what is in our ARP cache. */ + if ((arp_ptr -> nx_arp_physical_address_msw != sender_physical_msw) || + (arp_ptr -> nx_arp_physical_address_lsw != sender_physical_lsw)) + { + + /* A collision is present with the mapping in our ARP table. Call the notification handler. + Note: the application must release the packet. */ + (ip_ptr -> nx_ip_arp_collision_notify_response_handler)((void *)packet_ptr); + + /* We're done. NetX does not respond or do any further processing.*/ + return; + } + } + } +#endif /* NX_ENABLE_ARP_MAC_CHANGE_NOTIFICATION */ + + /* No need to update the static ARP entry. */ + if (arp_ptr -> nx_arp_route_static) + { + break; + } + + /* Save the physical address found in this ARP response. */ + arp_ptr -> nx_arp_physical_address_msw = sender_physical_msw; + arp_ptr -> nx_arp_physical_address_lsw = sender_physical_lsw; + + /* Set the update rate to the expiration rate since we now have an ARP + response. */ + arp_ptr -> nx_arp_entry_next_update = NX_ARP_EXPIRATION_RATE; + + /* Reset the retry counter for this ARP entry. */ + arp_ptr -> nx_arp_retries = 0; + + /* Stamp the interface that is attached to this neighbor node. */ + arp_ptr -> nx_arp_ip_interface = interface_ptr; + + /* Determine if this ARP entry has a packet queued up for + sending. */ + + /* Disable interrupts before checking. */ + TX_DISABLE + + /* Look at the ARP packet queue pointer. */ + if (arp_ptr -> nx_arp_packets_waiting) + { + + /* Pickup the packet pointer and clear the ARP queue pointer. */ + queued_list_head = arp_ptr -> nx_arp_packets_waiting; + arp_ptr -> nx_arp_packets_waiting = NX_NULL; + } + + /* Restore previous interrupt posture. */ + TX_RESTORE + + /* 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 have a packet to release. */ + if (consumed == NX_FALSE) + { + _nx_packet_release(packet_ptr); + } + +#ifndef NX_DISABLE_ARP_AUTO_ENTRY + + /* Determine if anything was found. Ignore ARP messages with a zero IP sender address. */ + if ((arp_ptr == NX_NULL) && (sender_ip != 0)) + { + + /* Calculate the hash index for the sender IP address. */ + index = (UINT)((sender_ip + (sender_ip >> 8)) & NX_ROUTE_TABLE_MASK); + + /* Allocate a new ARP entry in advance of the need to send to the IP + address. */ + if (((ip_ptr -> nx_ip_arp_allocate)(ip_ptr, &(ip_ptr -> nx_ip_arp_table[index]))) == NX_SUCCESS) + { + + /* 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 = sender_ip; + arp_ptr -> nx_arp_physical_address_msw = sender_physical_msw; + arp_ptr -> nx_arp_physical_address_lsw = sender_physical_lsw; + arp_ptr -> nx_arp_entry_next_update = NX_ARP_EXPIRATION_RATE; + arp_ptr -> nx_arp_retries = 0; + arp_ptr -> nx_arp_ip_interface = interface_ptr; + } + } +#endif /* NX_DISABLE_ARP_AUTO_ENTRY */ + + /* Are there any packets queued to send? */ + while (queued_list_head) + { + + /* Pickup the first entry on the list. */ + packet_ptr = queued_list_head; + + /* Move to the next entry on the ARP packet queue. */ + queued_list_head = queued_list_head -> nx_packet_queue_next; + + /* Clear the packet's queue next pointer. */ + packet_ptr -> nx_packet_queue_next = NX_NULL; + + /* Build the driver request packet. */ + driver_request.nx_ip_driver_physical_address_msw = sender_physical_msw; + driver_request.nx_ip_driver_physical_address_lsw = sender_physical_lsw; + 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_ip_interface; + + /* Determine if fragmentation is needed. */ + if (packet_ptr -> nx_packet_length > packet_ptr -> nx_packet_ip_interface -> 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); + } + } + else + { + +#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_IP_HEADER); +#endif + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_IO_DRIVER_PACKET_SEND, ip_ptr, packet_ptr, packet_ptr -> nx_packet_length, 0, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + /* Send the queued IP packet out on the network via the attached driver. */ + (packet_ptr -> nx_packet_ip_interface -> nx_interface_link_driver_entry) (&driver_request); + } + } +} + diff --git a/common/src/nx_arp_packet_send.c b/common/src/nx_arp_packet_send.c new file mode 100644 index 0000000..4c69456 --- /dev/null +++ b/common/src/nx_arp_packet_send.c @@ -0,0 +1,152 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Address Resolution Protocol (ARP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_arp.h" +#include "nx_packet.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_arp_packet_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function builds an ARP packet and calls the associated driver */ +/* to send it out on the network on the specified interface. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP instance */ +/* destination_ip Destination IP address */ +/* nx_interface Network interface to send */ +/* packet out on */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_packet_allocate Allocate a packet for the */ +/* ARP request */ +/* (ip_link_driver) User supplied link driver */ +/* */ +/* CALLED BY */ +/* */ +/* nx_arp_dynamic_entry_set Add dynamic entry to ARP cache*/ +/* nx_arp_enable Enable ARP for the IP task */ +/* nx_arp_periodic_update Handle periodic ARP tasks */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_arp_packet_send(NX_IP *ip_ptr, ULONG destination_ip, NX_INTERFACE *nx_interface) +{ + +NX_PACKET *request_ptr; +ULONG *message_ptr; +NX_IP_DRIVER driver_request; + + + /* Allocate a packet to build the ARP message in. */ + if (_nx_packet_allocate(ip_ptr -> nx_ip_default_packet_pool, &request_ptr, (NX_PHYSICAL_HEADER + NX_ARP_MESSAGE_SIZE), NX_NO_WAIT)) + { + + /* Error getting packet, so just get out! */ + return; + } + + /* Stamp the packet with the outgoing interface information. */ + request_ptr -> nx_packet_ip_interface = nx_interface; + +#ifndef NX_DISABLE_ARP_INFO + /* Increment the ARP requests sent count. */ + ip_ptr -> nx_ip_arp_requests_sent++; +#endif + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_ARP_REQUEST_SEND, ip_ptr, destination_ip, request_ptr, 0, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + + /* Build the ARP request packet. */ + + /* Setup the size of the ARP message. */ + request_ptr -> nx_packet_length = NX_ARP_MESSAGE_SIZE; + + /* Setup the prepend pointer. */ + request_ptr -> nx_packet_prepend_ptr -= NX_ARP_MESSAGE_SIZE; + + /* Setup the pointer to the message area. */ + message_ptr = (ULONG *)request_ptr -> nx_packet_prepend_ptr; + + /* Write the Hardware type into the message. */ + *message_ptr = (ULONG)(NX_ARP_HARDWARE_TYPE << 16) | (NX_ARP_PROTOCOL_TYPE); + *(message_ptr + 1) = (ULONG)(NX_ARP_HARDWARE_SIZE << 24) | (NX_ARP_PROTOCOL_SIZE << 16) | + NX_ARP_OPTION_REQUEST; + *(message_ptr + 2) = (ULONG)(request_ptr -> nx_packet_ip_interface -> nx_interface_physical_address_msw << 16) | + (request_ptr -> nx_packet_ip_interface -> nx_interface_physical_address_lsw >> 16); + *(message_ptr + 3) = (ULONG)(request_ptr -> nx_packet_ip_interface -> nx_interface_physical_address_lsw << 16) | + (request_ptr -> nx_packet_ip_interface -> nx_interface_ip_address >> 16); + *(message_ptr + 4) = (ULONG)(request_ptr -> nx_packet_ip_interface -> nx_interface_ip_address << 16); + *(message_ptr + 5) = (ULONG)0; + *(message_ptr + 6) = (ULONG)destination_ip; + + /* Endian swapping logic. If NX_LITTLE_ENDIAN is specified, these macros will + swap the endian of the ARP message. */ + NX_CHANGE_ULONG_ENDIAN(*(message_ptr)); + NX_CHANGE_ULONG_ENDIAN(*(message_ptr + 1)); + NX_CHANGE_ULONG_ENDIAN(*(message_ptr + 2)); + NX_CHANGE_ULONG_ENDIAN(*(message_ptr + 3)); + NX_CHANGE_ULONG_ENDIAN(*(message_ptr + 4)); + NX_CHANGE_ULONG_ENDIAN(*(message_ptr + 5)); + NX_CHANGE_ULONG_ENDIAN(*(message_ptr + 6)); + + /* Send the ARP request to the driver. */ + driver_request.nx_ip_driver_ptr = ip_ptr; + driver_request.nx_ip_driver_command = NX_LINK_ARP_SEND; + driver_request.nx_ip_driver_packet = request_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 = nx_interface; + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_IO_DRIVER_ARP_SEND, ip_ptr, request_ptr, request_ptr -> nx_packet_length, 0, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + (nx_interface -> nx_interface_link_driver_entry) (&driver_request); +} + diff --git a/common/src/nx_arp_periodic_update.c b/common/src/nx_arp_periodic_update.c new file mode 100644 index 0000000..fcd8978 --- /dev/null +++ b/common/src/nx_arp_periodic_update.c @@ -0,0 +1,273 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Address Resolution Protocol (ARP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_arp.h" +#include "nx_packet.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_arp_periodic_update PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes ARP periodic update requests by walking */ +/* through the dynamic ARP list to see if another ARP request needs to */ +/* sent. */ +/* */ +/* INPUT */ +/* */ +/* ip_address IP address in a ULONG */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_arp_packet_send Send periodic ARP request out */ +/* _nx_packet_transmit_release Release queued packet */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ip_thread_entry IP helper thread */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_arp_periodic_update(NX_IP *ip_ptr) +{ + +TX_INTERRUPT_SAVE_AREA + +ULONG i; +NX_ARP *arp_entry; +NX_PACKET *packet_ptr; +NX_PACKET *next_packet_ptr; + + + /* Pickup pointer to ARP dynamic list. */ + arp_entry = ip_ptr -> nx_ip_arp_dynamic_list; + + /* Loop through the active ARP entries to see if they need updating. */ + for (i = 0; i < ip_ptr -> nx_ip_arp_dynamic_active_count; i++) + { + + /* Check this ARP entry to see if it need updating. */ + if (arp_entry -> nx_arp_entry_next_update) + { + + /* Decrement the next update field. */ + arp_entry -> nx_arp_entry_next_update--; + + /* Determine if an ARP expiration is present. */ + if (!arp_entry -> nx_arp_entry_next_update) + { + + /* Yes, an ARP expiration is present. */ + + /* Determine if an ARP expiration is present. */ + if (arp_entry -> nx_arp_retries == NX_ARP_MAXIMUM_RETRIES) + { + + /* The number of retries has been exceeded. The entry is removed + from the active list and any queued packet is released. */ + + /* Disable interrupts. */ + TX_DISABLE + + /* This ARP entry has expired, remove it from the active ARP list. Check to make + sure it is still active. */ + if (arp_entry -> nx_arp_active_list_head) + { + + /* Determine if this is the only ARP entry on the list. */ + if (arp_entry == arp_entry -> nx_arp_active_next) + { + + /* Remove the entry from the list. */ + *(arp_entry -> nx_arp_active_list_head) = NX_NULL; + } + else + { + + /* Remove the entry from a list of more than one entry. */ + + /* Update the list head pointer. */ + if (*(arp_entry -> nx_arp_active_list_head) == arp_entry) + { + *(arp_entry -> nx_arp_active_list_head) = arp_entry -> nx_arp_active_next; + } + + /* Update the links of the adjacent ARP entries. */ + (arp_entry -> nx_arp_active_next) -> nx_arp_active_previous = + arp_entry -> nx_arp_active_previous; + (arp_entry -> nx_arp_active_previous) -> nx_arp_active_next = + arp_entry -> nx_arp_active_next; + } + + /* Decrease the number of active ARP entries. */ + ip_ptr -> nx_ip_arp_dynamic_active_count--; + + /* Clear the active head pointer. */ + arp_entry -> nx_arp_active_list_head = NX_NULL; + } + + /* Remove from its current position in the dynamic list. */ + + /* Determine if this is the only ARP entry on the dynamic list. */ + if (arp_entry == arp_entry -> nx_arp_pool_next) + { + + /* Remove the sole entry from the dynamic list head. */ + ip_ptr -> nx_ip_arp_dynamic_list = NX_NULL; + } + else + { + + /* Remove the entry from a list of more than one entry. */ + + /* Update the links of the adjacent ARP dynamic pool entries. */ + (arp_entry -> nx_arp_pool_next) -> nx_arp_pool_previous = + arp_entry -> nx_arp_pool_previous; + (arp_entry -> nx_arp_pool_previous) -> nx_arp_pool_next = + arp_entry -> nx_arp_pool_next; + + /* Update the list head pointer. */ + if (ip_ptr -> nx_ip_arp_dynamic_list == arp_entry) + { + ip_ptr -> nx_ip_arp_dynamic_list = arp_entry -> nx_arp_pool_next; + } + } + + /* Place the ARP entry at the end of the dynamic ARP pool, which is where new + ARP requests are allocated from. */ + + /* Determine if the dynamic ARP pool is empty. */ + if (ip_ptr -> nx_ip_arp_dynamic_list) + { + + /* Dynamic list is not empty, add ARP entry to the end of the list. */ + arp_entry -> nx_arp_pool_next = + ip_ptr -> nx_ip_arp_dynamic_list; + arp_entry -> nx_arp_pool_previous = + (ip_ptr -> nx_ip_arp_dynamic_list) -> nx_arp_pool_previous; + ((ip_ptr -> nx_ip_arp_dynamic_list) -> nx_arp_pool_previous) -> nx_arp_pool_next = + arp_entry; + (ip_ptr -> nx_ip_arp_dynamic_list) -> nx_arp_pool_previous = arp_entry; + } + else + { + + /* Dynamic list was empty, just place it at the head of the dynamic list. */ + ip_ptr -> nx_ip_arp_dynamic_list = arp_entry; + arp_entry -> nx_arp_pool_next = arp_entry; + arp_entry -> nx_arp_pool_previous = arp_entry; + } + + /* Pickup the queued packets head pointer. */ + next_packet_ptr = arp_entry -> nx_arp_packets_waiting; + + /* Clear the queued packets head pointer. */ + arp_entry -> nx_arp_packets_waiting = NX_NULL; + + /* Restore interrupts. */ + TX_RESTORE + + /* Loop to remove all queued packets. */ + while (next_packet_ptr) + { + + /* Pickup the packet pointer at the head of the queue. */ + packet_ptr = next_packet_ptr; + + /* Move to the next packet in the queue. */ + next_packet_ptr = next_packet_ptr -> nx_packet_queue_next; + + /* Clear the next packet queue pointer. */ + packet_ptr -> nx_packet_queue_next = NX_NULL; + +#ifndef NX_DISABLE_IP_INFO + + /* Increment the IP send packets dropped count. */ + ip_ptr -> nx_ip_send_packets_dropped++; +#endif + + /* Release the packet that was queued for the expired ARP entry. */ + _nx_packet_transmit_release(packet_ptr); + } + } + else + { + + /* We haven't yet had a response to this ARP request so send it again! */ + + /* Increment the ARP retry counter. */ + arp_entry -> nx_arp_retries++; + + /* Setup the ARP update rate to the maximum value again. */ + arp_entry -> nx_arp_entry_next_update = NX_ARP_UPDATE_RATE; + + /* Send the ARP request out. */ + _nx_arp_packet_send(ip_ptr, arp_entry -> nx_arp_ip_address, arp_entry -> nx_arp_ip_interface); + } + } + } + + /* Move to the next ARP entry. */ + arp_entry = arp_entry -> nx_arp_pool_next; + } + + /* Reduce the defend timeout of interfaces. */ + for (i = 0; i < NX_MAX_PHYSICAL_INTERFACES; i++) + { + if (ip_ptr -> nx_ip_interface[i].nx_interface_valid == NX_FALSE) + { + continue; + } + + if (ip_ptr -> nx_ip_interface[i].nx_interface_arp_defend_timeout == 0) + { + continue; + } + + ip_ptr -> nx_ip_interface[i].nx_interface_arp_defend_timeout--; + } +} + diff --git a/common/src/nx_arp_probe_send.c b/common/src/nx_arp_probe_send.c new file mode 100644 index 0000000..4cb63ad --- /dev/null +++ b/common/src/nx_arp_probe_send.c @@ -0,0 +1,165 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Address Resolution Protocol (ARP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_arp.h" +#include "nx_packet.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_arp_probe_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function builds an ARP Probe packet and calls the associated */ +/* driver to send it out on the specified network interface. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP instance */ +/* interface_index IP Interface Index */ +/* probe_address Probe address */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* NX_NO_PACKET No packet available to send */ +/* */ +/* CALLS */ +/* */ +/* _nx_packet_allocate Allocate a packet for the */ +/* ARP Probe */ +/* [ip_link_driver] User supplied link driver */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_arp_probe_send(NX_IP *ip_ptr, UINT interface_index, ULONG probe_address) +{ + +NX_INTERFACE *nx_interface; +NX_PACKET *request_ptr; +ULONG *message_ptr; +NX_IP_DRIVER driver_request; + + + /* Allocate a packet to build the ARP Probe message in. */ + if (_nx_packet_allocate(ip_ptr -> nx_ip_default_packet_pool, &request_ptr, (NX_PHYSICAL_HEADER + NX_ARP_MESSAGE_SIZE), NX_NO_WAIT)) + { + + /* Error getting packet, so just get out! */ + return(NX_NO_PACKET); + } + + /* Get mutex protection. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Set nx_interface. */ + nx_interface = &(ip_ptr -> nx_ip_interface[interface_index]); + + /* Store the probe address. */ + nx_interface -> nx_interface_ip_probe_address = probe_address; + + /* Stamp the packet with the outgoing interface information. */ + request_ptr -> nx_packet_ip_interface = nx_interface; + +#ifndef NX_DISABLE_ARP_INFO + /* Increment the ARP requests sent count. */ + ip_ptr -> nx_ip_arp_requests_sent++; +#endif + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_ARP_REQUEST_SEND, ip_ptr, probe_address, request_ptr, 0, NX_TRACE_INTERNAL_EVENTS, 0, 0); + + /* Build the ARP Probe packet. */ + + /* Setup the size of the ARP message. */ + request_ptr -> nx_packet_length = NX_ARP_MESSAGE_SIZE; + + /* Setup the prepend pointer. */ + request_ptr -> nx_packet_prepend_ptr -= NX_ARP_MESSAGE_SIZE; + + /* Setup the pointer to the message area. */ + message_ptr = (ULONG *)request_ptr -> nx_packet_prepend_ptr; + + /* Write the Hardware type into the message. */ + *message_ptr = (ULONG)(NX_ARP_HARDWARE_TYPE << 16) | (NX_ARP_PROTOCOL_TYPE); + *(message_ptr + 1) = (ULONG)(NX_ARP_HARDWARE_SIZE << 24) | (NX_ARP_PROTOCOL_SIZE << 16) | + NX_ARP_OPTION_REQUEST; + *(message_ptr + 2) = (ULONG)(nx_interface -> nx_interface_physical_address_msw << 16) | + (nx_interface -> nx_interface_physical_address_lsw >> 16); + *(message_ptr + 3) = (ULONG)(nx_interface -> nx_interface_physical_address_lsw << 16); + *(message_ptr + 4) = (ULONG)0; + *(message_ptr + 5) = (ULONG)0; + *(message_ptr + 6) = (ULONG)probe_address; + + /* Endian swapping logic. If NX_LITTLE_ENDIAN is specified, these macros will + swap the endian of the ARP message. */ + NX_CHANGE_ULONG_ENDIAN(*(message_ptr)); + NX_CHANGE_ULONG_ENDIAN(*(message_ptr + 1)); + NX_CHANGE_ULONG_ENDIAN(*(message_ptr + 2)); + NX_CHANGE_ULONG_ENDIAN(*(message_ptr + 3)); + NX_CHANGE_ULONG_ENDIAN(*(message_ptr + 4)); + NX_CHANGE_ULONG_ENDIAN(*(message_ptr + 5)); + NX_CHANGE_ULONG_ENDIAN(*(message_ptr + 6)); + + /* Set up the driver request. */ + driver_request.nx_ip_driver_ptr = ip_ptr; + driver_request.nx_ip_driver_command = NX_LINK_ARP_SEND; + driver_request.nx_ip_driver_packet = request_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 = nx_interface; + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_IO_DRIVER_ARP_SEND, ip_ptr, request_ptr, request_ptr -> nx_packet_length, 0, NX_TRACE_INTERNAL_EVENTS, 0, 0); + + /* Send the ARP Probe packet to the driver. */ + (nx_interface -> nx_interface_link_driver_entry)(&driver_request); + + /* Release mutex protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return a successful completion. */ + return(NX_SUCCESS); +} + diff --git a/common/src/nx_arp_queue_process.c b/common/src/nx_arp_queue_process.c new file mode 100644 index 0000000..ff5b116 --- /dev/null +++ b/common/src/nx_arp_queue_process.c @@ -0,0 +1,108 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Address Resolution Protocol (ARP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_arp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_arp_queue_process PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes the received ARP messages on the ARP */ +/* queue placed there by nx_arp_deferred_receive. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP instance */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_arp_packet_receive Process received ARP packet */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ip_thread_entry IP helper thread */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_arp_queue_process(NX_IP *ip_ptr) +{ + +TX_INTERRUPT_SAVE_AREA + +NX_PACKET *packet_ptr; + + + /* Loop to process all ARP deferred packet requests. */ + while (ip_ptr -> nx_ip_arp_deferred_received_packet_head) + { + + /* Remove the first packet and process it! */ + + /* Disable interrupts. */ + TX_DISABLE + + /* Pickup the first packet. */ + packet_ptr = ip_ptr -> nx_ip_arp_deferred_received_packet_head; + + /* Move the head pointer to the next packet. */ + ip_ptr -> nx_ip_arp_deferred_received_packet_head = packet_ptr -> nx_packet_queue_next; + + /* Check for end of ARP deferred processing queue. */ + if (ip_ptr -> nx_ip_arp_deferred_received_packet_head == NX_NULL) + { + + /* Yes, the ARP deferred queue is empty. Set the tail pointer to NULL. */ + ip_ptr -> nx_ip_arp_deferred_received_packet_tail = NX_NULL; + } + + /* Restore interrupts. */ + TX_RESTORE + + /* Call the actual ARP packet receive function. */ + _nx_arp_packet_receive(ip_ptr, packet_ptr); + } +} + diff --git a/common/src/nx_arp_static_entries_delete.c b/common/src/nx_arp_static_entries_delete.c new file mode 100644 index 0000000..37b781e --- /dev/null +++ b/common/src/nx_arp_static_entries_delete.c @@ -0,0 +1,127 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Address Resolution Protocol (ARP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_arp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_arp_static_entries_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function deletes all ARP static entries currently in */ +/* the ARP cache. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP instance pointer */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Obtain protection mutex */ +/* tx_mutex_put Release protection mutex */ +/* _nx_arp_static_entry_delete Delete a static entry */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_arp_static_entries_delete(NX_IP *ip_ptr) +{ + +NX_ARP *arp_entry; +UINT status; + +#ifdef TX_ENABLE_EVENT_TRACE +TX_TRACE_BUFFER_ENTRY *trace_event; +ULONG trace_timestamp; +ULONG deleted_count = 0; +#endif + + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_ARP_STATIC_ENTRIES_DELETE, ip_ptr, 0, 0, 0, NX_TRACE_ARP_EVENTS, &trace_event, &trace_timestamp) + + /* Obtain protection on this IP instance for access into the ARP static + list. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Traverse the static list until it is exhausted. */ + do + { + + /* Pickup the head of the list. */ + arp_entry = ip_ptr -> nx_ip_arp_static_list; + + /* Determine if the list is exhausted. */ + if (arp_entry == NX_NULL) + { + break; + } + + /* Otherwise, delete the static entry delete routine. Note that the delete routine + will modify the list head pointer used above. */ + status = _nx_arp_static_entry_delete(ip_ptr, arp_entry -> nx_arp_ip_address, + arp_entry -> nx_arp_physical_address_msw, + arp_entry -> nx_arp_physical_address_lsw); + +#ifdef TX_ENABLE_EVENT_TRACE + + /* Increment the deleted count. */ + deleted_count++; +#endif + } while (status == NX_SUCCESS); + + /* Update the trace event with the status. */ + NX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, NX_TRACE_ARP_STATIC_ENTRIES_DELETE, 0, deleted_count, 0, 0) + + /* Release the mutex. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return status to the caller. */ + return(NX_SUCCESS); +} + diff --git a/common/src/nx_arp_static_entry_create.c b/common/src/nx_arp_static_entry_create.c new file mode 100644 index 0000000..d875b1f --- /dev/null +++ b/common/src/nx_arp_static_entry_create.c @@ -0,0 +1,309 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Address Resolution Protocol (ARP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_arp.h" +#include "nx_ip.h" +#include "nx_packet.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_arp_static_entry_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function dynamically allocates an ARP entry for the application*/ +/* to make a static IP to hardware mapping. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP instance pointer */ +/* ip_address IP Address to bind to */ +/* physical_msw Physical address MSW */ +/* physical_lsw Physical address LSW */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_packet_transmit_release Release queued packet */ +/* _nx_ip_route_find Find suitable outgoing */ +/* 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_arp_static_entry_create(NX_IP *ip_ptr, ULONG ip_address, + ULONG physical_msw, ULONG physical_lsw) +{ + +TX_INTERRUPT_SAVE_AREA +NX_ARP *arp_entry; +NX_ARP **arp_list_ptr; +UINT index; +UINT status; +NX_PACKET *packet_ptr; +NX_PACKET *next_packet_ptr = NX_NULL; +NX_INTERFACE *nx_interface; +ULONG next_hop_address; + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_ARP_STATIC_ENTRY_CREATE, ip_ptr, ip_address, physical_msw, physical_lsw, NX_TRACE_ARP_EVENTS, 0, 0) + + /* Make sure the destination address is directly accessible. */ + if ((_nx_ip_route_find(ip_ptr, ip_address, &nx_interface, &next_hop_address) != NX_SUCCESS) || + (next_hop_address != ip_address)) + { + + return(NX_IP_ADDRESS_ERROR); + } + + /* Obtain protection on this IP instance for access into the ARP dynamic + list. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Determine if there is an ARP entry available in the dynamic list. */ + if (ip_ptr -> nx_ip_arp_dynamic_list) + { + + /* Yes there are one or more free entries. */ + +#ifndef NX_DISABLE_ARP_INFO + /* Increment the ARP static entry count. */ + ip_ptr -> nx_ip_arp_static_entries++; +#endif + + /* Disable interrupts. */ + TX_DISABLE + + /* Pickup pointer to last used dynamic ARP entry, which is also the oldest or least + recently used. */ + arp_entry = (ip_ptr -> nx_ip_arp_dynamic_list) -> nx_arp_pool_previous; + + /* Determine if this ARP entry is already active. */ + if (arp_entry -> nx_arp_active_list_head) + { + + /* Remove this dynamic ARP entry from the associated list. */ + + /* Determine if this is the only ARP entry on the list. */ + if (arp_entry == arp_entry -> nx_arp_active_next) + { + + /* Remove the entry from the list. */ + *(arp_entry -> nx_arp_active_list_head) = NX_NULL; + } + else + { + + /* Remove the entry from a list of more than one entry. */ + + /* Update the list head pointer. */ + if (*(arp_entry -> nx_arp_active_list_head) == arp_entry) + { + *(arp_entry -> nx_arp_active_list_head) = arp_entry -> nx_arp_active_next; + } + + /* Update the links of the adjacent ARP entries. */ + (arp_entry -> nx_arp_active_next) -> nx_arp_active_previous = + arp_entry -> nx_arp_active_previous; + (arp_entry -> nx_arp_active_previous) -> nx_arp_active_next = + arp_entry -> nx_arp_active_next; + } + + /* Decrease the number of active ARP entries. */ + ip_ptr -> nx_ip_arp_dynamic_active_count--; + + /* Pickup the queued packets head pointer. */ + next_packet_ptr = arp_entry -> nx_arp_packets_waiting; + + /* Clear the queued packets head pointer. */ + arp_entry -> nx_arp_packets_waiting = NX_NULL; + } + + /* Remove this entry from the ARP dynamic list. */ + + /* Determine if this is the only ARP entry on the dynamic list. */ + if (arp_entry == arp_entry -> nx_arp_pool_next) + { + + /* Remove the sole entry from the dynamic list head. */ + ip_ptr -> nx_ip_arp_dynamic_list = NX_NULL; + } + else + { + + /* Remove the entry from a list of more than one entry. */ + + /* Update the links of the adjacent ARP dynamic pool entries. */ + (arp_entry -> nx_arp_pool_next) -> nx_arp_pool_previous = + arp_entry -> nx_arp_pool_previous; + (arp_entry -> nx_arp_pool_previous) -> nx_arp_pool_next = + arp_entry -> nx_arp_pool_next; + + /* Update the list head pointer. */ + if (ip_ptr -> nx_ip_arp_dynamic_list == arp_entry) + { + ip_ptr -> nx_ip_arp_dynamic_list = arp_entry -> nx_arp_pool_next; + } + } + + /* Restore interrupts briefly. */ + TX_RESTORE + + /* Loop to remove all queued packets. */ + while (next_packet_ptr) + { + + /* Pickup the packet pointer at the head of the queue. */ + packet_ptr = next_packet_ptr; + + /* Move to the next packet in the queue. */ + next_packet_ptr = next_packet_ptr -> nx_packet_queue_next; + + /* Clear the next packet queue pointer. */ + packet_ptr -> nx_packet_queue_next = NX_NULL; + +#ifndef NX_DISABLE_IP_INFO + + /* Increment the IP send packets dropped count. */ + ip_ptr -> nx_ip_send_packets_dropped++; +#endif + + /* Release the packet that was queued from the removed ARP entry. */ + _nx_packet_transmit_release(packet_ptr); + } + + /* Calculate the hash index for the IP address. */ + index = (UINT)((ip_address + (ip_address >> 8)) & NX_ROUTE_TABLE_MASK); + + /* Indicate the entry does not need updating. */ + arp_entry -> nx_arp_entry_next_update = 0; + + /* Place the important information in the ARP structure. */ + arp_entry -> nx_arp_route_static = NX_TRUE; + arp_entry -> nx_arp_ip_address = ip_address; + arp_entry -> nx_arp_physical_address_msw = physical_msw; + arp_entry -> nx_arp_physical_address_lsw = physical_lsw; + arp_entry -> nx_arp_ip_interface = nx_interface; + + /* Setup the active ARP list head. */ + arp_list_ptr = &(ip_ptr -> nx_ip_arp_table[index]); + + /* Disable interrupts. */ + TX_DISABLE + + /* Add the entry to the ARP static list. */ + + /* Determine if the ARP static list is empty. */ + if (ip_ptr -> nx_ip_arp_static_list == NX_NULL) + { + + /* Just place this single ARP entry on the list. */ + arp_entry -> nx_arp_pool_next = arp_entry; + arp_entry -> nx_arp_pool_previous = arp_entry; + ip_ptr -> nx_ip_arp_static_list = arp_entry; + } + else + { + + /* Add to the end of the ARP static list. */ + arp_entry -> nx_arp_pool_next = + ip_ptr -> nx_ip_arp_static_list; + arp_entry -> nx_arp_pool_previous = + (ip_ptr -> nx_ip_arp_static_list) -> nx_arp_pool_previous; + ((ip_ptr -> nx_ip_arp_static_list) -> nx_arp_pool_previous) -> nx_arp_pool_next = + arp_entry; + (ip_ptr -> nx_ip_arp_static_list) -> nx_arp_pool_previous = arp_entry; + } + + /* Link the ARP entry at the head of the active ARP list. */ + + /* Determine if the ARP entry is being added to an empty list. */ + if (*arp_list_ptr) + { + + /* Add the ARP entry to the beginning of the nonempty ARP + list. */ + arp_entry -> nx_arp_active_list_head = arp_list_ptr; + arp_entry -> nx_arp_active_next = *arp_list_ptr; + arp_entry -> nx_arp_active_previous = (*arp_list_ptr) -> nx_arp_active_previous; + (arp_entry -> nx_arp_active_previous) -> nx_arp_active_next = arp_entry; + (*arp_list_ptr) -> nx_arp_active_previous = arp_entry; + } + else + { + + /* Empty list, just put the ARP entry at the beginning. */ + arp_entry -> nx_arp_active_list_head = arp_list_ptr; + arp_entry -> nx_arp_active_next = arp_entry; + arp_entry -> nx_arp_active_previous = arp_entry; + + /* Now setup the list head. */ + *arp_list_ptr = arp_entry; + } + + /* Restore interrupts. */ + TX_RESTORE + + /* Setup a successful status return. */ + status = NX_SUCCESS; + } + else + { + + /* No more ARP entries are available, all the ARP entries must be + allocated on the static list. */ + status = NX_NO_MORE_ENTRIES; + } + + /* Release the protection on the ARP list. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return status to the caller. */ + return(status); +} + diff --git a/common/src/nx_arp_static_entry_delete.c b/common/src/nx_arp_static_entry_delete.c new file mode 100644 index 0000000..74a3a87 --- /dev/null +++ b/common/src/nx_arp_static_entry_delete.c @@ -0,0 +1,259 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Address Resolution Protocol (ARP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_arp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_arp_static_entry_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function removes a previously setup static IP to hardware */ +/* mapping and returns the associated ARP entry back to the dynamic */ +/* ARP pool. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP instance pointer */ +/* ip_address IP Address binding to delete */ +/* physical_msw Physical address MSW */ +/* physical_lsw Physical address LSW */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Obtain protection mutex */ +/* tx_mutex_put Release protection mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* _nx_arp_static_entries_delete Delete all static entries */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_arp_static_entry_delete(NX_IP *ip_ptr, ULONG ip_address, + ULONG physical_msw, ULONG physical_lsw) +{ + +TX_INTERRUPT_SAVE_AREA + +NX_ARP *arp_entry; +UINT status; + + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_ARP_STATIC_ENTRY_DELETE, ip_ptr, ip_address, physical_msw, physical_lsw, NX_TRACE_ARP_EVENTS, 0, 0) + + /* Obtain protection on this IP instance for access into the ARP static + list. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Search the static list for a matching IP and hardware mapping. */ + arp_entry = ip_ptr -> nx_ip_arp_static_list; + while (arp_entry) + { + + /* Determine if we have a match. */ + if ((arp_entry -> nx_arp_ip_address == ip_address) && + (arp_entry -> nx_arp_physical_address_msw == physical_msw) && + (arp_entry -> nx_arp_physical_address_lsw == physical_lsw)) + { + + /* Yes, we have found the ARP entry we are looking for. */ + break; + } + else + { + + /* Determine if we are at the end of the list. */ + if (arp_entry -> nx_arp_pool_next == ip_ptr -> nx_ip_arp_static_list) + { + + /* Set the arp_entry to NULL to signify nothing was found and get + out of the search loop. */ + arp_entry = NX_NULL; + break; + } + else + { + + /* Just move to the next ARP entry on the static list. */ + arp_entry = arp_entry -> nx_arp_pool_next; + } + } + } + + /* At this point the ARP entry pointer determines whether or not anything was found + on the static list. */ + if (arp_entry) + { + + /* The static entry was found. It needs to be unlinked from the active + list and the static list and re-linked to the end of the dynamic list. */ + +#ifndef NX_DISABLE_ARP_INFO + /* Decrement the ARP static entry count. */ + ip_ptr -> nx_ip_arp_static_entries--; +#endif + + /* Disable interrupts temporarily. */ + TX_DISABLE + + /* Determine if this ARP entry is already active. */ + if (arp_entry -> nx_arp_active_list_head) + { + + /* Remove this dynamic ARP entry from the associated list. */ + + /* Determine if this is the only ARP entry on the list. */ + if (arp_entry == arp_entry -> nx_arp_active_next) + { + + /* Remove the entry from the list. */ + *(arp_entry -> nx_arp_active_list_head) = NX_NULL; + } + else + { + + /* Remove the entry from a list of more than one entry. */ + + /* Update the list head pointer. */ + if (*(arp_entry -> nx_arp_active_list_head) == arp_entry) + { + *(arp_entry -> nx_arp_active_list_head) = arp_entry -> nx_arp_active_next; + } + + /* Update the links of the adjacent ARP entries. */ + (arp_entry -> nx_arp_active_next) -> nx_arp_active_previous = + arp_entry -> nx_arp_active_previous; + (arp_entry -> nx_arp_active_previous) -> nx_arp_active_next = + arp_entry -> nx_arp_active_next; + } + } + + /* Remove this entry from the static ARP list. */ + + /* Determine if this is the only ARP entry on the static list. */ + if (arp_entry == arp_entry -> nx_arp_pool_next) + { + + /* Remove the sole entry from the static list head. */ + ip_ptr -> nx_ip_arp_static_list = NX_NULL; + } + else + { + + /* Remove the entry from a list of more than one entry. */ + + /* Update the links of the adjacent ARP dynamic pool entries. */ + (arp_entry -> nx_arp_pool_next) -> nx_arp_pool_previous = + arp_entry -> nx_arp_pool_previous; + (arp_entry -> nx_arp_pool_previous) -> nx_arp_pool_next = + arp_entry -> nx_arp_pool_next; + + /* Update the list head pointer. */ + if (ip_ptr -> nx_ip_arp_static_list == arp_entry) + { + ip_ptr -> nx_ip_arp_static_list = arp_entry -> nx_arp_pool_next; + } + } + + /* Restore interrupts briefly. */ + TX_RESTORE + + /* Clear the fields that indicate the ARP entry is a static entry and make sure + it is viewed as inactive in preparation for returning it to the dynamic ARP + pool. */ + arp_entry -> nx_arp_route_static = NX_FALSE; + arp_entry -> nx_arp_active_list_head = NX_NULL; + + /* Disable interrupts again. */ + TX_DISABLE + + /* Place the ARP entry at the end of the dynamic ARP pool, which is where new + ARP requests are allocated from. */ + + /* Determine if the dynamic ARP pool is empty. */ + if (ip_ptr -> nx_ip_arp_dynamic_list) + { + + /* Dynamic list is not empty, add former static ARP entry to the end of the list. */ + arp_entry -> nx_arp_pool_next = + ip_ptr -> nx_ip_arp_dynamic_list; + arp_entry -> nx_arp_pool_previous = + (ip_ptr -> nx_ip_arp_dynamic_list) -> nx_arp_pool_previous; + ((ip_ptr -> nx_ip_arp_dynamic_list) -> nx_arp_pool_previous) -> nx_arp_pool_next = + arp_entry; + (ip_ptr -> nx_ip_arp_dynamic_list) -> nx_arp_pool_previous = arp_entry; + } + else + { + + /* Dynamic list was empty, just place it at the head of the dynamic list. */ + ip_ptr -> nx_ip_arp_dynamic_list = arp_entry; + arp_entry -> nx_arp_pool_next = arp_entry; + arp_entry -> nx_arp_pool_previous = arp_entry; + } + + /* Restore interrupts. */ + TX_RESTORE + + /* Setup the return status. */ + status = NX_SUCCESS; + } + else + { + + /* Indicate the entry was not found. */ + status = NX_ENTRY_NOT_FOUND; + } + + /* Release the protection on the ARP list. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return status to the caller. */ + return(status); +} + diff --git a/common/src/nx_icmp_checksum_compute.c b/common/src/nx_icmp_checksum_compute.c new file mode 100644 index 0000000..87d82dc --- /dev/null +++ b/common/src/nx_icmp_checksum_compute.c @@ -0,0 +1,182 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Control Message Protocol (ICMP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_icmp.h" + +#if (!defined(NX_DISABLE_ICMP_TX_CHECKSUM) || !defined(NX_DISABLE_ICMP_RX_CHECKSUM)) +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_icmp_checksum_compute PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function computes the ICMP checksum from the supplied packet */ +/* pointer. */ +/* */ +/* INPUT */ +/* */ +/* packet_ptr Pointer to packet */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* ICMP routines */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +ULONG _nx_icmp_checksum_compute(NX_PACKET *packet_ptr) +{ + +ULONG checksum = 0; +ULONG long_temp; +USHORT short_temp; +ULONG length; +UCHAR *word_ptr; +NX_PACKET *current_packet; + + + /* Setup the length of the packet checksum. */ + length = packet_ptr -> nx_packet_length; + + /* Determine if we need to add a padding byte. */ + if (((length / sizeof(USHORT)) * sizeof(USHORT)) != length) + { + + /* We have single byte alignment and we need two byte alignment. */ + length++; + + /* Determine if there is a last packet pointer. */ + if (packet_ptr -> nx_packet_last) + { + + /* Multi-packet message, add a zero byte at the end. */ + *((packet_ptr -> nx_packet_last) -> nx_packet_append_ptr) = 0; + } + else + { + + /* Write a zero byte at the end of the first and only packet. */ + *(packet_ptr -> nx_packet_append_ptr) = 0; + } + } + + /* Setup the pointer to the start of the packet. */ + word_ptr = (UCHAR *)packet_ptr -> nx_packet_prepend_ptr; + + /* Initialize the current packet to the input packet pointer. */ + current_packet = packet_ptr; + + /* Loop to calculate the packet's checksum. */ + while (length) + { + + /* Determine if there is at least one ULONG left. */ + if ((UINT)(current_packet -> nx_packet_append_ptr - word_ptr) >= sizeof(ULONG)) + { + + /* Pickup a whole ULONG. */ + long_temp = *((ULONG *)word_ptr); + + /* Endian swapping logic. If NX_LITTLE_ENDIAN is specified, these macros will + swap the endian of the ICMP word. */ + NX_CHANGE_ULONG_ENDIAN(long_temp); + + /* Add upper 16-bits into checksum. */ + checksum = checksum + (long_temp >> NX_SHIFT_BY_16); + + /* Add lower 16-bits into checksum. */ + checksum = checksum + (long_temp & NX_LOWER_16_MASK); + + /* Move the word pointer and decrease the length. */ + word_ptr = word_ptr + sizeof(ULONG); + length = length - sizeof(ULONG); + } + else + { + + /* Pickup the 16-bit word. */ + short_temp = *((USHORT *)word_ptr); + + /* Endian swapping logic. If NX_LITTLE_ENDIAN is specified, these macros will + swap the endian of the ICMP word. */ + NX_CHANGE_USHORT_ENDIAN(short_temp); + + /* Add next 16-bit word into checksum. */ + checksum = checksum + short_temp; + + /* Move the word pointer and decrease the length. */ + word_ptr = word_ptr + sizeof(USHORT); + length = length - sizeof(USHORT); + } + + /* Determine if we are at the end of the current packet. */ + if ((word_ptr >= (UCHAR *)current_packet -> nx_packet_append_ptr) && + (current_packet -> nx_packet_next)) + { + + /* We have crossed the packet boundary. Move to the next packet + structure. */ + current_packet = current_packet -> nx_packet_next; + + /* Setup the new word pointer. */ + word_ptr = (UCHAR *)current_packet -> nx_packet_prepend_ptr; + } + } + + /* Add in the carry bits into the checksum. */ + checksum = (checksum >> NX_SHIFT_BY_16) + (checksum & NX_LOWER_16_MASK); + + /* Do it again in case previous operation generates an overflow. */ + checksum = (checksum >> NX_SHIFT_BY_16) + (checksum & NX_LOWER_16_MASK); + + /* Mask off the upper 16-bits. */ + checksum = checksum & NX_LOWER_16_MASK; + + /* Return the computed checksum. */ + return(checksum); +} +#endif + diff --git a/common/src/nx_icmp_cleanup.c b/common/src/nx_icmp_cleanup.c new file mode 100644 index 0000000..48b918a --- /dev/null +++ b/common/src/nx_icmp_cleanup.c @@ -0,0 +1,168 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Control Message Protocol (ICMP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "tx_thread.h" +#include "nx_icmp.h" +#include "nx_ip.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_icmp_cleanup PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes ICMP ping timeout and thread terminate */ +/* actions that require the IP/ICMP 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 */ +/* */ +/* _nx_ip_delete Delete IP instance */ +/* _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_icmp_cleanup(TX_THREAD *thread_ptr NX_CLEANUP_PARAMETER) +{ + +TX_INTERRUPT_SAVE_AREA + +NX_IP *ip_ptr; + + NX_CLEANUP_EXTENSION + + /* Setup pointer to IP control block. */ + ip_ptr = (NX_IP *)thread_ptr -> tx_thread_suspend_control_block; + + /* Disable interrupts to remove the suspended thread from the packet pool. */ + TX_DISABLE + + /* Determine if the cleanup is still required. */ + if ((thread_ptr -> tx_thread_suspend_cleanup) && (ip_ptr) && + (ip_ptr -> nx_ip_id == NX_IP_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. */ + ip_ptr -> nx_ip_icmp_ping_suspension_list = TX_NULL; + } + else + { + + /* At least one more thread is on the same suspension list. */ + + /* Update the list head pointer. */ + if (ip_ptr -> nx_ip_icmp_ping_suspension_list == thread_ptr) + { + ip_ptr -> nx_ip_icmp_ping_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. */ + ip_ptr -> nx_ip_icmp_ping_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 IP ping message. Setup return error status and + resume the thread. */ + + /* Setup return status. */ + thread_ptr -> tx_thread_suspend_status = NX_NO_RESPONSE; + +#ifndef NX_DISABLE_ICMP_INFO + /* Increment the ICMP timeout count. */ + ip_ptr -> nx_ip_ping_timeouts++; +#endif + + /* 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 +} + diff --git a/common/src/nx_icmp_enable.c b/common/src/nx_icmp_enable.c new file mode 100644 index 0000000..450919f --- /dev/null +++ b/common/src/nx_icmp_enable.c @@ -0,0 +1,85 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Control Message Protocol (ICMP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_icmp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_icmp_enable PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function enables the ICMP management component for the */ +/* specified IP instance. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP instance pointer */ +/* */ +/* 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_icmp_enable(NX_IP *ip_ptr) +{ + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_ICMP_ENABLE, ip_ptr, 0, 0, 0, NX_TRACE_ICMP_EVENTS, 0, 0) + + /* Setup the ICMP packet queue processing routine. */ + ip_ptr -> nx_ip_icmp_queue_process = _nx_icmp_queue_process; + + /* Setup the ICMP packet receiving routine, thereby enabling ICMP traffic. */ + ip_ptr -> nx_ip_icmp_packet_receive = _nx_icmp_packet_receive; + + /* Return a successful status! */ + return(NX_SUCCESS); +} + diff --git a/common/src/nx_icmp_info_get.c b/common/src/nx_icmp_info_get.c new file mode 100644 index 0000000..90b6426 --- /dev/null +++ b/common/src/nx_icmp_info_get.c @@ -0,0 +1,149 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Control Message Protocol (ICMP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_icmp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_icmp_info_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves the selected ICMP information for the */ +/* caller. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP instance */ +/* pings_sent Destination for number of */ +/* pings sent */ +/* ping_timeouts Destination for number of */ +/* ping timeouts */ +/* ping_threads_suspended Destination for number of */ +/* threads suspended on pings */ +/* ping_responses_received Destination for number of */ +/* ping responses received */ +/* icmp_checksum_errors Destination for number of */ +/* ICMP checksum errors */ +/* icmp_unhandled_messages Destination for number of */ +/* unhandled ICMP messages */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* 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_icmp_info_get(NX_IP *ip_ptr, ULONG *pings_sent, ULONG *ping_timeouts, + ULONG *ping_threads_suspended, ULONG *ping_responses_received, + ULONG *icmp_checksum_errors, ULONG *icmp_unhandled_messages) +{ + + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_ICMP_INFO_GET, ip_ptr, ip_ptr -> nx_ip_pings_sent, ip_ptr -> nx_ip_ping_responses_received, ip_ptr -> nx_ip_pings_received, NX_TRACE_ICMP_EVENTS, 0, 0) + + /* Obtain protection on this IP instance. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Determine if pings sent is wanted. */ + if (pings_sent) + { + + /* Return the number of pings sent by this IP instance. */ + *pings_sent = ip_ptr -> nx_ip_pings_sent; + } + + /* Determine if ping timeouts is wanted. */ + if (ping_timeouts) + { + + /* Return the number of ping timeouts by this IP instance. */ + *ping_timeouts = ip_ptr -> nx_ip_ping_timeouts; + } + + /* Determine if ping threads suspended is wanted. */ + if (ping_threads_suspended) + { + + /* Return the number of ping threads suspended by this IP instance. */ + *ping_threads_suspended = ip_ptr -> nx_ip_ping_threads_suspended; + } + + /* Determine if ping responses received is wanted. */ + if (ping_responses_received) + { + + /* Return the number of ping responses received by this IP instance. */ + *ping_responses_received = ip_ptr -> nx_ip_ping_responses_received; + } + + /* Determine if ICMP checksum errors is wanted. */ + if (icmp_checksum_errors) + { + + /* Return the number of ICMP checksum errors detected by this IP instance. */ + *icmp_checksum_errors = ip_ptr -> nx_ip_icmp_checksum_errors; + } + + /* Determine if ICMP unhandled messages is wanted. */ + if (icmp_unhandled_messages) + { + + /* Return the number of ICMP unhandled messages by this IP instance. */ + *icmp_unhandled_messages = ip_ptr -> nx_ip_icmp_unhandled_messages; + } + + /* Release protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return a successful status. */ + return(NX_SUCCESS); +} + diff --git a/common/src/nx_icmp_packet_process.c b/common/src/nx_icmp_packet_process.c new file mode 100644 index 0000000..d8a8d6a --- /dev/null +++ b/common/src/nx_icmp_packet_process.c @@ -0,0 +1,340 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Control Message Protocol (ICMP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "tx_thread.h" +#include "nx_packet.h" +#include "nx_ip.h" +#include "nx_icmp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_icmp_packet_process PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes the ICMP received packet and lifts any */ +/* associated threads suspended on it. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP control block */ +/* packet_ptr ICMP packet pointer */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_icmp_checksum_compute Computer ICMP checksum */ +/* _nx_ip_packet_send Send ICMP packet out */ +/* _nx_packet_release Packet release function */ +/* _tx_thread_system_resume Resume suspended thread */ +/* _tx_thread_system_preempt_check Check for preemption */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_icmp_packet_receive ICMP packet receive */ +/* _nx_icmp_queue_process ICMP packet queue processing */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_icmp_packet_process(NX_IP *ip_ptr, NX_PACKET *packet_ptr) +{ + +TX_INTERRUPT_SAVE_AREA + +NX_ICMP_HEADER *header_ptr; +TX_THREAD *thread_ptr; +ULONG suspended; +ULONG *message_ptr; +ULONG message_type; +ULONG sequence_num; + +#if (!defined(NX_DISABLE_ICMP_TX_CHECKSUM) || !defined(NX_DISABLE_ICMP_RX_CHECKSUM)) +ULONG checksum; +#endif + + /* Point to the ICMP message header. */ + header_ptr = (NX_ICMP_HEADER *)packet_ptr -> nx_packet_prepend_ptr; + +#ifndef NX_DISABLE_ICMP_RX_CHECKSUM + /* Calculate the ICMP message checksum. */ + checksum = _nx_icmp_checksum_compute(packet_ptr); + checksum = ~checksum & NX_LOWER_16_MASK; + + /* Determine if the checksum is valid. */ + if (checksum) + { + +#ifndef NX_DISABLE_ICMP_INFO + + /* Increment the ICMP invalid packet error. */ + ip_ptr -> nx_ip_icmp_invalid_packets++; + + /* Increment the ICMP checksum error count. */ + ip_ptr -> nx_ip_icmp_checksum_errors++; +#endif + + /* Nope, the checksum is invalid. Toss this ICMP packet out. */ + _nx_packet_release(packet_ptr); + + return; + } +#endif + /* If NX_LITTLE_ENDIAN is defined, the header needs to be swapped + so we can examine the ICMP message type. */ + NX_CHANGE_ULONG_ENDIAN(header_ptr -> nx_icmp_header_word_0); + + /* Pickup the ICMP message type. */ + message_type = (header_ptr -> nx_icmp_header_word_0) >> 24; + + /* Is the message an Echo Reply? */ + if (message_type == NX_ICMP_ECHO_REPLY_TYPE) + { + +#ifndef NX_DISABLE_ICMP_INFO + + /* Increment the ICMP responses received count. */ + ip_ptr -> nx_ip_ping_responses_received++; +#endif + + /* If NX_LITTLE_ENDIAN is defined, the second word of the header + needs to be swapped back so we can examine the ICMP sequence number. */ + NX_CHANGE_ULONG_ENDIAN(header_ptr -> nx_icmp_header_word_1); + + /* Pickup sequence number. */ + sequence_num = (header_ptr -> nx_icmp_header_word_1) & NX_LOWER_16_MASK; + + /* Disable interrupts. */ + TX_DISABLE + + /* Pickup the head pointer and the suspended count. */ + thread_ptr = ip_ptr -> nx_ip_icmp_ping_suspension_list; + suspended = ip_ptr -> nx_ip_icmp_ping_suspended_count; + + /* Temporarily disable preemption. */ + _tx_thread_preempt_disable++; + + /* Restore interrupts. */ + TX_RESTORE + + /* Search through the suspended threads waiting for a ECHO (ping) response + in an attempt to find a matching sequence number. */ + while (suspended--) + { + + /* Determine if the sequence number matches a suspended thread. */ + if (thread_ptr -> tx_thread_suspend_info == sequence_num) + { + + /* Disable interrupts. */ + TX_DISABLE + + /* 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. */ + ip_ptr -> nx_ip_icmp_ping_suspension_list = NX_NULL; + } + else + { + + /* At least one more thread is on the same expiration list. */ + + /* Update the list head pointer. */ + if (ip_ptr -> nx_ip_icmp_ping_suspension_list == thread_ptr) + { + ip_ptr -> nx_ip_icmp_ping_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. */ + ip_ptr -> nx_ip_icmp_ping_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++; + + /* Restore interrupts. */ + TX_RESTORE + + /* Adjust this packet to remove the ICMP header that is still in front of + the response message. */ + packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - sizeof(NX_ICMP_HEADER); + packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr + sizeof(NX_ICMP_HEADER); + + /* Return this block pointer to the suspended thread waiting for + a block. */ + *((NX_PACKET **)thread_ptr -> tx_thread_additional_suspend_info) = packet_ptr; + + /* Clear packet pointer so we don't try to release it below. */ + packet_ptr = NX_NULL; + + /* Put return status into the thread control block. */ + thread_ptr -> tx_thread_suspend_status = NX_SUCCESS; + + /* Resume thread. */ + _tx_thread_system_resume(thread_ptr); + + /* Get out of the loop. */ + break; + } + else + { + /* Just move to the next suspended thread. */ + thread_ptr = thread_ptr -> tx_thread_suspended_next; + } + } + + /* Determine if no match was made and we just have to release the packet. */ + if (packet_ptr) + { + + /* Yes, just release the packet. */ + _nx_packet_release(packet_ptr); + } + + /* Disable interrupts. */ + TX_DISABLE + + /* Release preemption disable. */ + _tx_thread_preempt_disable--; + + /* Restore interrupts. */ + TX_RESTORE + + /* Check for preemption. */ + _tx_thread_system_preempt_check(); + } + else if (message_type == NX_ICMP_ECHO_REQUEST_TYPE) + { + +#ifndef NX_DISABLE_ICMP_INFO + /* Increment the ICMP pings received count. */ + ip_ptr -> nx_ip_pings_received++; +#endif + + /* Change the type to Echo Reply and send back the message to the caller. */ + header_ptr -> nx_icmp_header_word_0 = NX_ICMP_ECHO_REPLY_TYPE << 24; + +#ifndef NX_DISABLE_ICMP_TX_CHECKSUM + /* If NX_LITTLE_ENDIAN is defined, the header need to be swapped back + to match the data area. */ + NX_CHANGE_ULONG_ENDIAN(header_ptr -> nx_icmp_header_word_0); + + /* Compute the checksum of the Echo Reply. */ + checksum = _nx_icmp_checksum_compute(packet_ptr); + + /* If NX_LITTLE_ENDIAN is defined, the header need to be swapped back + so we insert the checksum. */ + NX_CHANGE_ULONG_ENDIAN(header_ptr -> nx_icmp_header_word_0); + + /* Store the checksum. */ + header_ptr -> nx_icmp_header_word_0 = header_ptr -> nx_icmp_header_word_0 | (~checksum & NX_LOWER_16_MASK); +#endif + /* If NX_LITTLE_ENDIAN is defined, the header need to be swapped back + for output. */ + NX_CHANGE_ULONG_ENDIAN(header_ptr -> nx_icmp_header_word_0); + + /* Pickup the return IP address. */ + message_ptr = (ULONG *)packet_ptr -> nx_packet_prepend_ptr; + + /* Figure out the best interface to send the ICMP packet on. */ + if (_nx_ip_route_find(ip_ptr, *(message_ptr - 2), &packet_ptr -> nx_packet_ip_interface, + &packet_ptr -> nx_packet_next_hop_address) != NX_SUCCESS) + { + + /* Not a valid interface available. */ + _nx_packet_release(packet_ptr); + + return; + } + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_ICMP_RECEIVE, ip_ptr, *(message_ptr - 2), packet_ptr, 0, NX_TRACE_INTERNAL_EVENTS, 0, 0) + +#ifndef NX_DISABLE_ICMP_INFO + /* Increment the ICMP pings responded to count. */ + ip_ptr -> nx_ip_pings_responded_to++; +#endif + + /* Send the ICMP packet to the IP component. */ + _nx_ip_packet_send(ip_ptr, packet_ptr, *(message_ptr - 2), + NX_IP_NORMAL, NX_IP_TIME_TO_LIVE, NX_IP_ICMP, NX_FRAGMENT_OKAY); + } + else + { + +#ifndef NX_DISABLE_ICMP_INFO + + /* Increment the ICMP unhandled message count. */ + ip_ptr -> nx_ip_icmp_unhandled_messages++; +#endif + +#ifdef TX_ENABLE_EVENT_TRACE + + /* Pickup the return IP address. */ + message_ptr = (ULONG *)packet_ptr -> nx_packet_prepend_ptr; +#endif + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_ICMP_RECEIVE, ip_ptr, *(message_ptr - 2), packet_ptr, 0, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + /* Unhandled ICMP message, just release it. */ + _nx_packet_release(packet_ptr); + } + + return; +} + diff --git a/common/src/nx_icmp_packet_receive.c b/common/src/nx_icmp_packet_receive.c new file mode 100644 index 0000000..d606f79 --- /dev/null +++ b/common/src/nx_icmp_packet_receive.c @@ -0,0 +1,193 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Control Message Protocol (ICMP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_icmp.h" +#include "nx_packet.h" +#include "tx_thread.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_icmp_packet_receive PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function receives an ICMP packet from the IP receive */ +/* processing. If this routine is called from an ISR, it simply */ +/* places the new message on the ICMP message queue, and wakes up the */ +/* IP processing thread. If this routine is called from the IP helper */ +/* thread, then the ICMP message is processed directly. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP control block */ +/* packet_ptr Pointer to packet to send */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_icmp_packet_process Process ICMP packet */ +/* tx_event_flags_set Set event flags for IP helper */ +/* thread */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ip_packet_receive Dispatch received IP packets */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_icmp_packet_receive(NX_IP *ip_ptr, NX_PACKET *packet_ptr) +{ + +TX_INTERRUPT_SAVE_AREA + +#ifdef NX_ENABLE_ICMP_ADDRESS_CHECK +NX_IP_HEADER *ip_header_ptr; +NX_INTERFACE *interface_ptr; +#endif /* NX_ENABLE_ICMP_ADDRESS_CHECK */ + +#ifndef NX_DISABLE_ICMP_INFO + + /* Increment the ICMP total messages received counter. */ + ip_ptr -> nx_ip_icmp_total_messages_received++; +#endif + +#ifndef NX_DISABLE_RX_SIZE_CHECKING + + /* Check for valid packet length. */ + if (packet_ptr -> nx_packet_length < sizeof(NX_ICMP_HEADER)) + { + +#ifndef NX_DISABLE_ICMP_INFO + + /* Increment the ICMP invalid packet error. */ + ip_ptr -> nx_ip_icmp_invalid_packets++; +#endif + + /* Invalid packet length, just release it. */ + _nx_packet_release(packet_ptr); + + /* The function is complete, just return! */ + return; + } +#endif + +#ifdef NX_ENABLE_ICMP_ADDRESS_CHECK + + /* An ICMP Echo Request destined to an IP broadcast or IP multicast address + MAY be silently discarded. + RFC 1122, Section 3.2.2.6, Page42. */ + + /* Pickup the IP header and interface. */ + ip_header_ptr = (NX_IP_HEADER *)(packet_ptr -> nx_packet_prepend_ptr - sizeof(NX_IP_HEADER)); + interface_ptr = packet_ptr -> nx_packet_ip_interface; + + if ( + /* Check for Multicast address */ + ((ip_header_ptr -> nx_ip_header_destination_ip & NX_IP_CLASS_D_MASK) == NX_IP_CLASS_D_TYPE) || + /* Check for subnet-directed broadcast */ + (((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))) || + /* Check for local subnet address */ + (ip_header_ptr -> nx_ip_header_destination_ip == interface_ptr -> nx_interface_ip_network) || + /* Check for limited broadcast */ + (ip_header_ptr -> nx_ip_header_destination_ip == NX_IP_LIMITED_BROADCAST) + ) + { + +#ifndef NX_DISABLE_ICMP_INFO + + /* Increment the ICMP invalid packet error. */ + ip_ptr -> nx_ip_icmp_invalid_packets++; +#endif + + /* Invalid packet length, just release it. */ + _nx_packet_release(packet_ptr); + + /* The function is complete, just return! */ + return; + } +#endif /* NX_ENABLE_ICMP_ADDRESS_CHECK */ + + /* Determine if this routine is being called from an ISR. */ + if (TX_THREAD_GET_SYSTEM_STATE()) + { + + /* If non-zero, we are in an ISR. Just place the message on the + ICMP message queue and wakeup the IP helper thread. */ + + /* Disable interrupts. */ + TX_DISABLE + + /* Add the packet to the ICMP message queue. */ + if (ip_ptr -> nx_ip_icmp_queue_head) + { + + /* Link the current packet to the list head. */ + packet_ptr -> nx_packet_queue_next = ip_ptr -> nx_ip_icmp_queue_head; + } + else + { + + /* Empty queue, add to the head of the ICMP message queue. */ + packet_ptr -> nx_packet_queue_next = NX_NULL; + } + + /* Update the queue head pointer. */ + ip_ptr -> nx_ip_icmp_queue_head = packet_ptr; + + /* Restore interrupts. */ + TX_RESTORE + + /* Wakeup IP thread for processing one or more messages in the ICMP queue. */ + tx_event_flags_set(&(ip_ptr -> nx_ip_events), NX_IP_ICMP_EVENT, TX_OR); + } + else + { + + /* The IP message was deferred, so this routine is called from the IP helper + thread and thus may call the ICMP processing directly. */ + _nx_icmp_packet_process(ip_ptr, packet_ptr); + } +} + diff --git a/common/src/nx_icmp_ping.c b/common/src/nx_icmp_ping.c new file mode 100644 index 0000000..2ace746 --- /dev/null +++ b/common/src/nx_icmp_ping.c @@ -0,0 +1,307 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Control Message Protocol (ICMP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_icmp.h" +#include "nx_packet.h" +#include "nx_ip.h" +#include "tx_thread.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_icmp_ping PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function builds an ICMP ping request packet and calls the */ +/* associated driver to send it out on the network. The function will */ +/* then suspend for the specified time waiting for the ICMP ping */ +/* response. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP instance */ +/* ip_address IP address to ping */ +/* data_ptr User Data pointer */ +/* data_size Size of User Data */ +/* response_ptr Pointer to Response Packet */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_icmp_checksum_compute Computer ICMP checksum */ +/* _nx_ip_packet_send IP packet send function */ +/* _nx_ip_route_find Find a suitable outgoing */ +/* interface. */ +/* _nx_packet_allocate Allocate a packet for the */ +/* ICMP ping request */ +/* _nx_packet_release Release packet on error */ +/* tx_mutex_get Obtain protection mutex */ +/* tx_mutex_put Release protection mutex */ +/* _tx_thread_system_suspend Suspend thread */ +/* _tx_thread_system_preempt_check Check for preemption */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_icmp_ping(NX_IP *ip_ptr, ULONG ip_address, + CHAR *data_ptr, ULONG data_size, + NX_PACKET **response_ptr, ULONG wait_option) +{ + +TX_INTERRUPT_SAVE_AREA + +UINT status; +NX_PACKET *request_ptr; +NX_ICMP_HEADER *header_ptr; +ULONG sequence; +TX_THREAD *thread_ptr; + +#ifndef NX_DISABLE_ICMP_TX_CHECKSUM +ULONG checksum; +#endif + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_ICMP_PING, ip_ptr, ip_address, data_ptr, data_size, NX_TRACE_ICMP_EVENTS, 0, 0) + + /* Clear the destination pointer. */ + * response_ptr = NX_NULL; + + /* Allocate a packet to place the ICMP echo request message in. */ + status = _nx_packet_allocate(ip_ptr -> nx_ip_default_packet_pool, &request_ptr, NX_ICMP_PACKET, wait_option); + if (status) + { + + /* Error getting packet, so just get out! */ + return(status); + } + + /* Determine if the size of the data and the ICMP header is larger than + the packet payload area. */ + if ((data_size + NX_ICMP_HEADER_SIZE) > (ULONG)(request_ptr -> nx_packet_data_end - request_ptr -> nx_packet_append_ptr)) + { + + /* Release the packet. */ + _nx_packet_release(request_ptr); + + /* Error, the data area is too big for the default packet payload. */ + return(NX_OVERFLOW); + } + + /* Find a suitable interface for sending the ping packet. */ + if (_nx_ip_route_find(ip_ptr, ip_address, &request_ptr -> nx_packet_ip_interface, &request_ptr -> nx_packet_next_hop_address) != NX_SUCCESS) + { + + /* Release the packet. */ + _nx_packet_release(request_ptr); + + return(NX_IP_ADDRESS_ERROR); + } + +#ifndef NX_DISABLE_ICMP_INFO + /* Increment the ICMP ping count. */ + ip_ptr -> nx_ip_pings_sent++; +#endif + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_ICMP_SEND, ip_ptr, ip_address, request_ptr, (((ULONG)NX_ICMP_ECHO_REQUEST_TYPE) << 24), NX_TRACE_INTERNAL_EVENTS, 0, 0) + + /* Calculate the ICMP echo request message size and store it in the + packet header. */ + request_ptr -> nx_packet_length = data_size + NX_ICMP_HEADER_SIZE; + + /* Setup the append pointer to the end of the message. */ + request_ptr -> nx_packet_append_ptr = request_ptr -> nx_packet_prepend_ptr + (data_size + NX_ICMP_HEADER_SIZE); + + /* Build the ICMP request packet. */ + + /* Setup the pointer to the message area. */ + header_ptr = (NX_ICMP_HEADER *)request_ptr -> nx_packet_prepend_ptr; + + /* Write the ICMP type into the message. Use the lower 16-bits of the IP address for + the ICMP identifier. */ + header_ptr -> nx_icmp_header_word_0 = (ULONG)(NX_ICMP_ECHO_REQUEST_TYPE << 24); + sequence = (ip_ptr -> nx_ip_icmp_sequence++ & NX_LOWER_16_MASK); + header_ptr -> nx_icmp_header_word_1 = (ULONG)(request_ptr -> nx_packet_ip_interface -> nx_interface_ip_address << 16) | sequence; + + /* Copy the data into the packet payload area. */ + memcpy(request_ptr -> nx_packet_prepend_ptr + sizeof(NX_ICMP_HEADER), data_ptr, data_size); + + /* If NX_LITTLE_ENDIAN is defined, the headers need to be swapped to match + that of the data area. */ + NX_CHANGE_ULONG_ENDIAN(header_ptr -> nx_icmp_header_word_0); + NX_CHANGE_ULONG_ENDIAN(header_ptr -> nx_icmp_header_word_1); + +#ifndef NX_DISABLE_ICMP_TX_CHECKSUM + /* Compute the checksum of the ICMP packet. */ + checksum = _nx_icmp_checksum_compute(request_ptr); + + /* If NX_LITTLE_ENDIAN is defined, the headers need to be swapped back so + we can place the checksum in the ICMP header. */ + NX_CHANGE_ULONG_ENDIAN(header_ptr -> nx_icmp_header_word_0); + + /* Place the checksum into the first header word. */ + header_ptr -> nx_icmp_header_word_0 = header_ptr -> nx_icmp_header_word_0 | (~checksum & NX_LOWER_16_MASK); + + /* If NX_LITTLE_ENDIAN is defined, the first header word needs to be swapped + back. */ + NX_CHANGE_ULONG_ENDIAN(header_ptr -> nx_icmp_header_word_0); +#endif + /* Obtain the IP internal mutex to prevent against possible suspension later in the + call to IP packet send. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + + /* Disable interrupts. */ + TX_DISABLE + + /* Temporarily disable preemption. */ + _tx_thread_preempt_disable++; + + /* Pickup thread pointer. */ + thread_ptr = _tx_thread_current_ptr; + + /* Determine if the request specifies suspension. */ + if (wait_option) + { + + /* Prepare for suspension of this thread. */ + + /* Setup cleanup routine pointer. */ + thread_ptr -> tx_thread_suspend_cleanup = _nx_icmp_cleanup; + + thread_ptr -> tx_thread_suspend_status = NX_NO_RESPONSE; + + /* Setup cleanup information, i.e. this pool control + block. */ + thread_ptr -> tx_thread_suspend_control_block = (void *)ip_ptr; + + /* Save the return packet pointer address as well. */ + thread_ptr -> tx_thread_additional_suspend_info = (void *)response_ptr; + + /* Save the sequence number so this can be matched up with an ICMP + response later. */ + thread_ptr -> tx_thread_suspend_info = sequence; + + /* Setup suspension list. */ + if (ip_ptr -> nx_ip_icmp_ping_suspension_list) + { + + /* This list is not NULL, add current thread to the end. */ + thread_ptr -> tx_thread_suspended_next = + ip_ptr -> nx_ip_icmp_ping_suspension_list; + thread_ptr -> tx_thread_suspended_previous = + (ip_ptr -> nx_ip_icmp_ping_suspension_list) -> tx_thread_suspended_previous; + ((ip_ptr -> nx_ip_icmp_ping_suspension_list) -> tx_thread_suspended_previous) -> tx_thread_suspended_next = + thread_ptr; + (ip_ptr -> nx_ip_icmp_ping_suspension_list) -> tx_thread_suspended_previous = thread_ptr; + } + else + { + + /* No other threads are suspended. Setup the head pointer and + just setup this threads pointers to itself. */ + ip_ptr -> nx_ip_icmp_ping_suspension_list = thread_ptr; + thread_ptr -> tx_thread_suspended_next = thread_ptr; + thread_ptr -> tx_thread_suspended_previous = thread_ptr; + } + + /* Increment the suspended thread count. */ + ip_ptr -> nx_ip_icmp_ping_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; + + /* Save the timeout value. */ + thread_ptr -> tx_thread_timer.tx_timer_internal_remaining_ticks = wait_option; + } + + /* Restore interrupts. */ + TX_RESTORE + + /* Send the ICMP packet to the IP component. */ + _nx_ip_packet_send(ip_ptr, request_ptr, ip_address, + NX_IP_NORMAL, NX_IP_TIME_TO_LIVE, NX_IP_ICMP, NX_FRAGMENT_OKAY); + + /* If wait option is requested, suspend the thread. */ + if (wait_option) + { + + /* Release the protection on the ARP list. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Call actual thread suspension routine. */ + _tx_thread_system_suspend(thread_ptr); + + /* Return the status from the thread control block. */ + return(thread_ptr -> tx_thread_suspend_status); + } + else + { + + /* Disable interrupts. */ + TX_DISABLE + + /* Release preemption disable. */ + _tx_thread_preempt_disable--; + + /* Restore interrupts. */ + TX_RESTORE + + /* Release the protection mutex. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Check for preemption. */ + _tx_thread_system_preempt_check(); + + /* Immediate return, return error completion. */ + return(NX_NO_RESPONSE); + } +} + diff --git a/common/src/nx_icmp_queue_process.c b/common/src/nx_icmp_queue_process.c new file mode 100644 index 0000000..8d19d5a --- /dev/null +++ b/common/src/nx_icmp_queue_process.c @@ -0,0 +1,106 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Control Message Protocol (ICMP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "tx_thread.h" +#include "nx_packet.h" +#include "nx_ip.h" +#include "nx_icmp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_icmp_queue_process PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes the ICMP receive packet queue. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP control block */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_icmp_packet_process Process ICMP packet */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ip_thread_entry IP helper thread processing */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_icmp_queue_process(NX_IP *ip_ptr) +{ + +TX_INTERRUPT_SAVE_AREA + +NX_PACKET *queue_head; +NX_PACKET *packet_ptr; + + + /* Disable interrupts. */ + TX_DISABLE + + /* Remove the ICMP message queue from the IP structure. */ + queue_head = ip_ptr -> nx_ip_icmp_queue_head; + ip_ptr -> nx_ip_icmp_queue_head = NX_NULL; + + /* Restore interrupts. */ + TX_RESTORE + + /* Walk through the entire ICMP message queue and process packets + one by one. */ + while (queue_head) + { + + /* Pickup the first queued ICMP message and remove it from the + ICMP queue. */ + packet_ptr = queue_head; + queue_head = queue_head -> nx_packet_queue_next; + packet_ptr -> nx_packet_queue_next = NX_NULL; + + /* Process the packet. */ + _nx_icmp_packet_process(ip_ptr, packet_ptr); + } +} + diff --git a/common/src/nx_igmp_enable.c b/common/src/nx_igmp_enable.c new file mode 100644 index 0000000..dfc724e --- /dev/null +++ b/common/src/nx_igmp_enable.c @@ -0,0 +1,102 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Group Management Protocol (IGMP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_igmp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_igmp_enable PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function enables the IGMP management component for the */ +/* specified IP instance. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP instance pointer */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_event_flags_set Set deferred IGMP enable */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_igmp_enable(NX_IP *ip_ptr) +{ + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_IGMP_ENABLE, ip_ptr, 0, 0, 0, NX_TRACE_IGMP_EVENTS, 0, 0) + + +#ifndef NX_DISABLE_IGMPV2 + + /* Set the IGMP protocol to the default version supported by NetX, IGMPv2. */ + + ip_ptr -> nx_ip_igmp_router_version = NX_IGMP_HOST_VERSION_2; + +#endif + + /* Setup the IGMP packet receive routine, which enables the IGMP component. */ + ip_ptr -> nx_ip_igmp_packet_receive = _nx_igmp_packet_receive; + + /* Setup the IGMP periodic processing routine, which enables the IGMP component. */ + ip_ptr -> nx_ip_igmp_periodic_processing = _nx_igmp_periodic_processing; + + /* Setup the IGMP queue processing routine, which processes deferred IGMP + requests. */ + ip_ptr -> nx_ip_igmp_queue_process = _nx_igmp_queue_process; + + /* Wakeup IP helper thread to process the IGMP deferred enable. */ + tx_event_flags_set(&(ip_ptr -> nx_ip_events), NX_IP_IGMP_ENABLE_EVENT, TX_OR); + + /* Return a successful status! */ + return(NX_SUCCESS); +} + diff --git a/common/src/nx_igmp_info_get.c b/common/src/nx_igmp_info_get.c new file mode 100644 index 0000000..74e47d8 --- /dev/null +++ b/common/src/nx_igmp_info_get.c @@ -0,0 +1,128 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Group Management Protocol (IGMP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_igmp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_igmp_info_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves various IGMP information associated with */ +/* the specified IP instance. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP instance pointer */ +/* igmp_reports_sent Destination for the number */ +/* of IGMP reports sent */ +/* igmp_queries_received Destination for the number */ +/* of IGMP queries received */ +/* igmp_checksum_errors Destination for the number */ +/* of IGMP checksum errors */ +/* current_groups_joined Destination for the number */ +/* of IGMP multicast groups */ +/* currently joined */ +/* */ +/* 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_igmp_info_get(NX_IP *ip_ptr, ULONG *igmp_reports_sent, ULONG *igmp_queries_received, + ULONG *igmp_checksum_errors, ULONG *current_groups_joined) +{ + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_IGMP_INFO_GET, ip_ptr, ip_ptr -> nx_ip_igmp_reports_sent, ip_ptr -> nx_ip_igmp_queries_received, ip_ptr -> nx_ip_igmp_groups_joined, NX_TRACE_IGMP_EVENTS, 0, 0) + + /* Obtain protection on this IP instance. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Determine if IGMP reports sent is wanted. */ + if (igmp_reports_sent) + { + + /* Return the number of IGMP reports sent by this IP instance. */ + *igmp_reports_sent = ip_ptr -> nx_ip_igmp_reports_sent; + } + + /* Determine if IGMP queries received is wanted. */ + if (igmp_queries_received) + { + + /* Return the number of IGMP queries received by this IP instance. */ + *igmp_queries_received = ip_ptr -> nx_ip_igmp_queries_received; + } + + /* Determine if IGMP checksum errors is wanted. */ + if (igmp_checksum_errors) + { + + /* Return the number of IGMP checksum errors by this IP instance. */ + *igmp_checksum_errors = ip_ptr -> nx_ip_igmp_checksum_errors; + } + + /* Determine if the number of IGMP multicast groups joined is wanted. */ + if (current_groups_joined) + { + + /* Return the number of IGMP multicast groups joined is wanted. */ + *current_groups_joined = ip_ptr -> nx_ip_igmp_groups_joined; + } + + /* Release the protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return a successful status! */ + return(NX_SUCCESS); +} + diff --git a/common/src/nx_igmp_interface_report_send.c b/common/src/nx_igmp_interface_report_send.c new file mode 100644 index 0000000..4ad1d28 --- /dev/null +++ b/common/src/nx_igmp_interface_report_send.c @@ -0,0 +1,226 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Group Management Protocol (IGMP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_igmp.h" +#include "nx_ip.h" +#include "nx_packet.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_igmp_interface_report_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function builds and sends an IGMP report. If it is a JOIN */ +/* report, the IP nx_igmp_reports_sent statistic is incremented. */ +/* */ +/* Note: An IGMPv1 host does not send a LEAVE message. The caller in */ +/* that case, _nx_igmp_multicast_interface_leave_internal, checks the */ +/* IGMP host version and only calls this function for IGMPv2 hosts. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP instance pointer */ +/* group_address Multicast group to join */ +/* interface_index Index to the interface */ +/* is_joining Indicate if joining or leaving*/ +/* NX_TRUE = send join report */ +/* NX_FALSE = send leave report*/ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_ENTRY_NOT_FOUND Entry not in multicast table */ +/* */ +/* CALLS */ +/* */ +/* _nx_ip_packet_send Send packet from the IP layer */ +/* _nx_packet_allocate Allocate a packet for report */ +/* tx_mutex_get Obtain protection mutex */ +/* tx_mutex_put Release protection mutex */ +/* */ +/* CALLED BY */ +/* */ +/* nx_igmp_periodic_processing Performs periodic IGMP tasks */ +/* nx_igmp_multicast_leave Processes a LEAVE report for */ +/* transmission to all routers */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_igmp_interface_report_send(NX_IP *ip_ptr, ULONG group_address, UINT interface_index, UINT is_joining) +{ + +UINT status; +ULONG checksum; +ULONG temp; +NX_PACKET *packet_ptr; +NX_IGMP_HEADER *header_ptr; + + /* Obtain the IP mutex so we can search the multicast join list. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Build an IGMP host response packet and send it! */ + + /* Allocate an packet to place the IGMP host response message in. */ + status = _nx_packet_allocate(ip_ptr -> nx_ip_default_packet_pool, &packet_ptr, (ULONG)(NX_IGMP_PACKET + NX_IGMP_HEADER_SIZE), TX_NO_WAIT); + + /* Check for error. */ + if (status) + { + + /* Packet allocation failed. Release the mutex and return error status. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + return(status); + } + + /* Prepare an IGMP response and send on the "all hosts" multicast + address. */ + +#ifndef NX_DISABLE_IGMP_INFO + /* Increment the IGMP reports sent count. */ + if (is_joining == NX_TRUE) + { + ip_ptr -> nx_ip_igmp_reports_sent++; + } +#endif + + /* Calculate the IGMP response message size and store it in the + packet header. */ + /*lint -e{644} suppress variable might not be initialized, since "packet_ptr" was initialized as long as status is NX_SUCCESS. */ + packet_ptr -> nx_packet_length = NX_IGMP_HEADER_SIZE; + + /* Setup the prepend pointer. */ + packet_ptr -> nx_packet_prepend_ptr -= NX_IGMP_HEADER_SIZE; + + packet_ptr -> nx_packet_ip_interface = &(ip_ptr -> nx_ip_interface[interface_index]); + + /* Build the IGMP host response packet. */ + + /* Setup the pointer to the message area. */ + /*lint -e{927} -e{826} suppress cast of pointer to pointer, since it is necessary */ + header_ptr = (NX_IGMP_HEADER *)packet_ptr -> nx_packet_prepend_ptr; + +#ifndef NX_DISABLE_IGMPV2 + + /* Build the IGMPv2 response message. */ + + /* Is the router using IGMPv1? */ + if (ip_ptr -> nx_ip_igmp_router_version == NX_IGMP_HOST_VERSION_1) + { +#endif /* NX_DISABLE_IGMPV2 */ + + /* Yes; Set the header fields with the max response time + zero and the version/type 0x12. */ + header_ptr -> nx_igmp_header_word_0 = (ULONG)(NX_IGMP_VERSION | NX_IGMP_HOST_RESPONSE_TYPE); + header_ptr -> nx_igmp_header_word_1 = group_address; +#ifndef NX_DISABLE_IGMPV2 + } + /* The router is running the IGMPv2 (or higher) protocol. */ + else + { + + /* Indicate if the report is a join or leave report. */ + if (is_joining) + { + + header_ptr -> nx_igmp_header_word_0 = (ULONG)(NX_IGMP_HOST_V2_JOIN_TYPE); + } + else + { + header_ptr -> nx_igmp_header_word_0 = (ULONG)(NX_IGMP_HOST_V2_LEAVE_TYPE); + } + + header_ptr -> nx_igmp_header_word_1 = group_address; + } +#endif /* NX_DISABLE_IGMPV2 */ + + /* Calculate the checksum. */ + temp = header_ptr -> nx_igmp_header_word_0; + checksum = (temp >> NX_SHIFT_BY_16); + checksum += (temp & NX_LOWER_16_MASK); + temp = header_ptr -> nx_igmp_header_word_1; + checksum += (temp >> NX_SHIFT_BY_16); + checksum += (temp & NX_LOWER_16_MASK); + + /* Add in the carry bits into the checksum. */ + checksum = (checksum >> NX_SHIFT_BY_16) + (checksum & NX_LOWER_16_MASK); + + /* Do it again in case previous operation generates an overflow. */ + checksum = (checksum >> NX_SHIFT_BY_16) + (checksum & NX_LOWER_16_MASK); + + /* Place the checksum into the first header word. */ + header_ptr -> nx_igmp_header_word_0 = header_ptr -> nx_igmp_header_word_0 | (~checksum & NX_LOWER_16_MASK); + + /* If NX_LITTLE_ENDIAN is defined, the headers need to be swapped. */ + NX_CHANGE_ULONG_ENDIAN(header_ptr -> nx_igmp_header_word_0); + NX_CHANGE_ULONG_ENDIAN(header_ptr -> nx_igmp_header_word_1); + + /* Note that because this is a class D/multicast address we can set next hop + for sending this IGMP message directly. */ + + /* Send the IGMP response packet out! */ + if (is_joining == NX_TRUE) + { + + packet_ptr -> nx_packet_next_hop_address = group_address; + + /* For JOIN reports, set the packet destination to the group address. */ + _nx_ip_packet_send(ip_ptr, packet_ptr, + group_address, + NX_IP_NORMAL, NX_IGMP_TTL, NX_IP_IGMP, NX_FRAGMENT_OKAY); + } + else + { + + packet_ptr -> nx_packet_next_hop_address = NX_ALL_ROUTERS_ADDRESS; + + /* For LEAVE reports, set the destination to ALL ROUTERS as per RFC 2236 Section 3 page 4.*/ + _nx_ip_packet_send(ip_ptr, packet_ptr, + NX_ALL_ROUTERS_ADDRESS, + NX_IP_NORMAL, NX_IGMP_TTL, NX_IP_IGMP, NX_FRAGMENT_OKAY); + } + + /* Release the protection over the IP instance. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + return NX_SUCCESS; +} + diff --git a/common/src/nx_igmp_loopback_disable.c b/common/src/nx_igmp_loopback_disable.c new file mode 100644 index 0000000..e2d8470 --- /dev/null +++ b/common/src/nx_igmp_loopback_disable.c @@ -0,0 +1,83 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Group Management Protocol (IGMP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_igmp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_igmp_loopback_disable PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function disables loopback for all subsequent IGMP groups */ +/* joined by the host. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP instance pointer */ +/* */ +/* 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_igmp_loopback_disable(NX_IP *ip_ptr) +{ + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_IGMP_LOOPBACK_DISABLE, ip_ptr, 0, 0, 0, NX_TRACE_IGMP_EVENTS, 0, 0) + + /* Clear the global IGMP loopback flag. All subsequent IGMP group join + requests will have loopback disabled. */ + ip_ptr -> nx_ip_igmp_global_loopback_enable = NX_FALSE; + + /* Return a successful status! */ + return(NX_SUCCESS); +} + diff --git a/common/src/nx_igmp_loopback_enable.c b/common/src/nx_igmp_loopback_enable.c new file mode 100644 index 0000000..cbdef70 --- /dev/null +++ b/common/src/nx_igmp_loopback_enable.c @@ -0,0 +1,83 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Group Management Protocol (IGMP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_igmp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_igmp_loopback_enable PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function enables loopback for all subsequent IGMP groups */ +/* joined by the host. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP instance pointer */ +/* */ +/* 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_igmp_loopback_enable(NX_IP *ip_ptr) +{ + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_IGMP_LOOPBACK_ENABLE, ip_ptr, 0, 0, 0, NX_TRACE_IGMP_EVENTS, 0, 0) + + /* Set the global IGMP loopback flag. All subsequent IGMP group join + requests will have loopback enabled. */ + ip_ptr -> nx_ip_igmp_global_loopback_enable = NX_TRUE; + + /* Return a successful status! */ + return(NX_SUCCESS); +} + diff --git a/common/src/nx_igmp_multicast_check.c b/common/src/nx_igmp_multicast_check.c new file mode 100644 index 0000000..65a2a27 --- /dev/null +++ b/common/src/nx_igmp_multicast_check.c @@ -0,0 +1,104 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Group Management Protocol (IGMP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_igmp.h" + + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_igmp_multicast_check PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks the list of joined multicast addresses to see */ +/* if the incoming address matches. If the specified group is */ +/* "all hosts" or if a match is found, NX_TRUE is returned to the */ +/* caller. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP instance pointer */ +/* group Multicast group IP address */ +/* */ +/* OUTPUT */ +/* */ +/* NX_TRUE If a match is found */ +/* NX_FALSE Otherwise */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ip_packet_receive Raw IP packet receive */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_igmp_multicast_check(NX_IP *ip_ptr, ULONG group, NX_INTERFACE *nx_interface) +{ + +UINT i; +ULONG *join_list_ptr; + + + /* Check for "all hosts" group. We always assume all hosts membership. */ + if (group == NX_ALL_HOSTS_ADDRESS) + { + return(NX_TRUE); + } + + /* Loop through the IP multicast join list to find the matching group that is being + responded to by another host on this same network. */ + join_list_ptr = &(ip_ptr -> nx_ip_igmp_join_list[0]); + for (i = 0; i < NX_MAX_MULTICAST_GROUPS; i++) + { + + /* Check for a match. */ + if ((*join_list_ptr++ == group) && (nx_interface == ip_ptr -> nx_ip_igmp_join_interface_list[i])) + { + return(NX_TRUE); + } + } + + /* Otherwise, we have searched the entire list, return false. */ + return(NX_FALSE); +} + diff --git a/common/src/nx_igmp_multicast_interface_join.c b/common/src/nx_igmp_multicast_interface_join.c new file mode 100644 index 0000000..6bfc575 --- /dev/null +++ b/common/src/nx_igmp_multicast_interface_join.c @@ -0,0 +1,181 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Group Management Protocol (IGMP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_igmp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_igmp_multicast_interface_join PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function handles the request to join the specified multicast */ +/* group on a specified network interface. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP instance pointer */ +/* group_address Multicast group to join */ +/* nx_interface_index Index to the NetX interface */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Obtain protection mutex */ +/* tx_mutex_put Release protection mutex */ +/* (ip_link_driver) Associated IP link driver */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_igmp_multicast_interface_join(NX_IP *ip_ptr, ULONG group_address, UINT nx_interface_index) +{ + +UINT i; +UINT first_free; +ULONG *join_list_ptr; +NX_IP_DRIVER driver_request; +NX_INTERFACE *nx_interface; + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_IGMP_MULTICAST_JOIN, ip_ptr, group_address, nx_interface_index, 0, NX_TRACE_IGMP_EVENTS, 0, 0) + + /* Obtain the IP mutex so we can search the multicast join list. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + + nx_interface = &ip_ptr -> nx_ip_interface[nx_interface_index]; + + /* Search the multicast join list for either the same group request. */ + first_free = NX_MAX_MULTICAST_GROUPS; + join_list_ptr = &(ip_ptr -> nx_ip_igmp_join_list[0]); + for (i = 0; i < NX_MAX_MULTICAST_GROUPS; i++) + { + + /* Determine if the specified entry is already in the multicast join list. */ + if (*join_list_ptr == group_address) + { + + /* Yes, we have found the same entry. The only thing required in this + case is to increment the join count and return. */ + ip_ptr -> nx_ip_igmp_join_count[i]++; + + /* Release the IP protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return success! */ + return(NX_SUCCESS); + } + + /* Check for an empty entry. */ + if ((*join_list_ptr == 0) && (first_free == NX_MAX_MULTICAST_GROUPS)) + { + + /* Remember the first free entry. */ + first_free = i; + } + + /* Move to the next entry in the join list. */ + join_list_ptr++; + } + + /* At this point, we have a new entry. First, check to see if there is an available + entry. */ + if (first_free == NX_MAX_MULTICAST_GROUPS) + { + + /* Release the protection of the IP instance. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return an error code to indicate there are no more group addresses + available. */ + return(NX_NO_MORE_ENTRIES); + } + + /* Register the new multicast group with the underlying driver to + ensure that there is room for the new group at the hardware level. */ + driver_request.nx_ip_driver_ptr = ip_ptr; + driver_request.nx_ip_driver_command = NX_LINK_MULTICAST_JOIN; + driver_request.nx_ip_driver_physical_address_msw = NX_IP_MULTICAST_UPPER; + driver_request.nx_ip_driver_physical_address_lsw = NX_IP_MULTICAST_LOWER | (group_address & NX_IP_MULTICAST_MASK); + driver_request.nx_ip_driver_interface = nx_interface; + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_IO_DRIVER_MULTICAST_JOIN, ip_ptr, 0, 0, 0, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + (nx_interface -> nx_interface_link_driver_entry) (&driver_request); + + /* Check the return driver status. */ + if (driver_request.nx_ip_driver_status != NX_SUCCESS) + { + + /* Release the protection of the IP instance. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return an error code to indicate there are no more group addresses + available. */ + return(NX_NO_MORE_ENTRIES); + } + + /* Set it up in the IP control structures. */ + ip_ptr -> nx_ip_igmp_join_list[first_free] = group_address; + ip_ptr -> nx_ip_igmp_join_interface_list[first_free] = nx_interface; + ip_ptr -> nx_ip_igmp_join_count[first_free] = 1; + ip_ptr -> nx_ip_igmp_update_time[first_free] = 1; /* Update on next IGMP periodic */ + ip_ptr -> nx_ip_igmp_group_loopback_enable[first_free] = ip_ptr -> nx_ip_igmp_global_loopback_enable; + +#ifndef NX_DISABLE_IGMP_INFO + /* Increment the IGMP groups joined count. */ + ip_ptr -> nx_ip_igmp_groups_joined++; +#endif + + /* Release the protection over the IP instance. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return a successful status! */ + return(NX_SUCCESS); +} + diff --git a/common/src/nx_igmp_multicast_join.c b/common/src/nx_igmp_multicast_join.c new file mode 100644 index 0000000..d6eb5fb --- /dev/null +++ b/common/src/nx_igmp_multicast_join.c @@ -0,0 +1,77 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Group Management Protocol (IGMP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_igmp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_igmp_multicast_join PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function handles the request to join the specified multicast */ +/* group. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP instance pointer */ +/* group_address Multicast group to join */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_igmp_multicast_interface_join Join Multicast group */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_igmp_multicast_join(NX_IP *ip_ptr, ULONG group_address) +{ + + /* Default to interface 0. */ + return(_nx_igmp_multicast_interface_join(ip_ptr, group_address, 0)); +} + diff --git a/common/src/nx_igmp_multicast_leave.c b/common/src/nx_igmp_multicast_leave.c new file mode 100644 index 0000000..3caaf65 --- /dev/null +++ b/common/src/nx_igmp_multicast_leave.c @@ -0,0 +1,188 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Group Management Protocol (IGMP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_igmp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_igmp_multicast_leave PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function handles the request to leave the specified multicast */ +/* group. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP instance pointer */ +/* group_address Multicast group to leave */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Obtain protection mutex */ +/* tx_mutex_put Release protection mutex */ +/* (ip_link_driver) Associated IP link driver */ +/* nx_igmp_interface_report_send Send IGMP group report */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_igmp_multicast_leave(NX_IP *ip_ptr, ULONG group_address) +{ + +UINT i; +#ifndef NX_DISABLE_IGMPV2 +UINT interface_index = 0; +#endif +ULONG *join_list_ptr; +NX_IP_DRIVER driver_request; + + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_IGMP_MULTICAST_LEAVE, ip_ptr, group_address, 0, 0, NX_TRACE_IGMP_EVENTS, 0, 0) + + /* Obtain the IP mutex so we can search the multicast join list. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Search the multicast join list for either the same group request. */ + join_list_ptr = &(ip_ptr -> nx_ip_igmp_join_list[0]); + + for (i = 0; i < NX_MAX_MULTICAST_GROUPS; i++) + { + + /* Determine if the specified entry is present. */ + if (*join_list_ptr == group_address) + { + + /* Yes, we have found the same entry. */ +#ifndef NX_DISABLE_IGMPV2 + UINT index; + NX_INTERFACE *nx_interface = ip_ptr -> nx_ip_igmp_join_interface_list[i]; +#endif + /* Decrease the join count. */ + ip_ptr -> nx_ip_igmp_join_count[i]--; + + /* Determine if there are no other join requests. */ + if (ip_ptr -> nx_ip_igmp_join_count[i] == 0) + { + + /* Clear the group join value. */ + *join_list_ptr = 0; + + /* Un-register the new multicast group with the underlying driver. */ + driver_request.nx_ip_driver_ptr = ip_ptr; + driver_request.nx_ip_driver_command = NX_LINK_MULTICAST_LEAVE; + driver_request.nx_ip_driver_physical_address_msw = NX_IP_MULTICAST_UPPER; + driver_request.nx_ip_driver_physical_address_lsw = NX_IP_MULTICAST_LOWER | (group_address & NX_IP_MULTICAST_MASK); + driver_request.nx_ip_driver_interface = ip_ptr -> nx_ip_igmp_join_interface_list[i]; + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_IO_DRIVER_MULTICAST_LEAVE, ip_ptr, 0, 0, 0, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + (ip_ptr -> nx_ip_igmp_join_interface_list[i] -> nx_interface_link_driver_entry) (&driver_request); + +#ifdef NX_DISABLE_IGMPV2 + /* Clear the interface entry for version IGMPv1. We don't need it anymore. */ + ip_ptr -> nx_ip_igmp_join_interface_list[i] = NX_NULL; +#endif + +#ifndef NX_DISABLE_IGMP_INFO + /* Decrement the IGMP groups joined count. */ + ip_ptr -> nx_ip_igmp_groups_joined--; +#endif + +#ifndef NX_DISABLE_IGMPV2 + + /* IGMPv2 hosts should send a leave group message. IGMPv1 + hosts do not. */ + if (ip_ptr -> nx_ip_igmp_router_version == NX_IGMP_HOST_VERSION_1) + { + + /* Release the IP protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return success! */ + return(NX_SUCCESS); + } + + /* Find the interface for this group address. */ + for (index = 0; index < NX_MAX_PHYSICAL_INTERFACES; index++) + { + + if (nx_interface == &(ip_ptr -> nx_ip_interface[index])) + { + /* Found it. */ + interface_index = index; + + break; + } + } + + /* Build and send the leave report packet. */ + _nx_igmp_interface_report_send(ip_ptr, group_address, interface_index, NX_FALSE); + +#endif /* NX_DISABLE_IGMPV2 */ + } + + /* Release the IP protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return success! */ + return(NX_SUCCESS); + } + + /* Move to the next entry in the join list. */ + join_list_ptr++; + } + + /* The group address was not found in the multicast join list. + Release the protection of the IP instance and quit. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return an error code. */ + return(NX_ENTRY_NOT_FOUND); +} + diff --git a/common/src/nx_igmp_packet_process.c b/common/src/nx_igmp_packet_process.c new file mode 100644 index 0000000..aa2527e --- /dev/null +++ b/common/src/nx_igmp_packet_process.c @@ -0,0 +1,360 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Group Management Protocol (IGMP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_packet.h" +#include "nx_igmp.h" + + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_igmp_packet_process PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function handles reception of IGMP packets on the "all hosts" */ +/* multicast address. There are basically two types of IGMP packets */ +/* that will arrive. Routers send IGMP query messages while hosts send*/ +/* IGMP responses (join requests). If an IGMP join request for a group */ +/* address this host belongs to is received, that will cancel sending */ +/* a join request by this host. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP instance pointer */ +/* packet_ptr IGMP packet pointer */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_packet_release Release IGMP packet */ +/* tx_time_get Get current time */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_igmp_packet_receive IGMP packet receive */ +/* _nx_igmp_queue_process IGMP queue processing */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_igmp_packet_process(NX_IP *ip_ptr, NX_PACKET *packet_ptr) +{ + +UINT i; +ULONG update_time; +NX_IGMP_HEADER *header_ptr; +USHORT max_update_time; +UCHAR *word_ptr; +NX_PACKET *current_packet; +ULONG checksum; +ULONG long_temp; +USHORT short_temp; +ULONG length; + + /* Setup a pointer to the IGMP packet header. */ + header_ptr = (NX_IGMP_HEADER *)packet_ptr -> nx_packet_prepend_ptr; + + /* First verify the checksum is correct. */ + checksum = 0; + + /* Setup the length of the packet checksum. */ + length = packet_ptr -> nx_packet_length; + + /* Determine if we need to add a padding byte. */ + if (((length / sizeof(USHORT)) * sizeof(USHORT)) != length) + { + + /* We have single byte alignment and we need two byte alignment. */ + length++; + + /* Determine if there is a last packet pointer. */ + if (packet_ptr -> nx_packet_last) + { + + /* Multi-packet message, add a zero byte at the end. */ + *((packet_ptr -> nx_packet_last) -> nx_packet_append_ptr) = 0; + } + else + { + + /* Write a zero byte at the end of the first and only packet. */ + *(packet_ptr -> nx_packet_append_ptr) = 0; + } + } + + /* Setup the pointer to the start of the packet. */ + word_ptr = (UCHAR *)packet_ptr -> nx_packet_prepend_ptr; + + /* Initialize the current packet to the input packet pointer. */ + current_packet = packet_ptr; + + /* Loop to calculate the packet's checksum. */ + while (length) + { + + /* Determine if there is at least one ULONG left. */ + if ((UINT)(current_packet -> nx_packet_append_ptr - word_ptr) >= sizeof(ULONG)) + { + + /* Pickup a whole ULONG. */ + long_temp = *((ULONG *)word_ptr); + + /* Add upper 16-bits into checksum. */ + checksum = checksum + (long_temp >> NX_SHIFT_BY_16); + + /* Check for carry bits. */ + if (checksum & NX_CARRY_BIT) + { + checksum = (checksum & NX_LOWER_16_MASK) + 1; + } + + /* Add lower 16-bits into checksum. */ + checksum = checksum + (long_temp & NX_LOWER_16_MASK); + + /* Check for carry bits. */ + + if (checksum & NX_CARRY_BIT) + { + checksum = (checksum & NX_LOWER_16_MASK) + 1; + } + + /* Move the word pointer and decrease the length. */ + word_ptr = word_ptr + sizeof(ULONG); + length = length - sizeof(ULONG); + } + else + { + + /* Pickup the 16-bit word. */ + short_temp = *((USHORT *)word_ptr); + + /* Add next 16-bit word into checksum. */ + checksum = checksum + short_temp; + + /* Check for carry bits. */ + if (checksum & NX_CARRY_BIT) + { + checksum = (checksum & NX_LOWER_16_MASK) + 1; + } + + /* Move the word pointer and decrease the length. */ + word_ptr = word_ptr + sizeof(USHORT); + length = length - sizeof(USHORT); + } + + /* Determine if we are at the end of the current packet. */ + if ((word_ptr >= (UCHAR *)current_packet -> nx_packet_append_ptr) && + (current_packet -> nx_packet_next)) + { + + /* We have crossed the packet boundary. Move to the next packet + structure. */ + current_packet = current_packet -> nx_packet_next; + + /* Setup the new word pointer. */ + word_ptr = (UCHAR *)current_packet -> nx_packet_prepend_ptr; + } + } + + checksum = ~checksum & NX_LOWER_16_MASK; + + /* Determine if the checksum is valid. */ + if (checksum) + { + + /* It is not. By RFC requirements we should not accept this packet. */ + + /* Increment the IGMP invalid packet error. */ + ip_ptr -> nx_ip_igmp_invalid_packets++; + + /* Increment the IGMP checksum error count. */ + ip_ptr -> nx_ip_igmp_checksum_errors++; + + /* Toss this IGMP packet out. */ + + _nx_packet_release(packet_ptr); + return; + } + + /* Swap the IGMP headers back to host byte order for the checksum + calculation. */ + NX_CHANGE_ULONG_ENDIAN(header_ptr -> nx_igmp_header_word_0); + NX_CHANGE_ULONG_ENDIAN(header_ptr -> nx_igmp_header_word_1); + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_IGMP_RECEIVE, ip_ptr, *(((ULONG *)packet_ptr -> nx_packet_prepend_ptr) - 2), packet_ptr, header_ptr -> nx_igmp_header_word_0, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + /* Determine the type of IGMP message received. Note that an IGMPv1 host will respond + to an IGMPv2 general query but not process the maximum response time field. */ + if ((header_ptr -> nx_igmp_header_word_0 & NX_IGMP_TYPE_MASK) == NX_IGMP_ROUTER_QUERY_TYPE) + { + +#ifndef NX_DISABLE_IGMP_INFO + /* Increment the IGMP queries received count. */ + ip_ptr -> nx_ip_igmp_queries_received++; +#endif + + /* Set the max response time recommended by RFC 1112 set by host in seconds. In a + IGMPv2 network, the router may set a different max time in its IGMP membership queries. */ + max_update_time = NX_IGMP_MAX_UPDATE_TIME; + +#ifndef NX_DISABLE_IGMPV2 + + /* Determine the IGMP version the sender (router) is using. */ + + /* Is the max response time non zero? */ + if ((header_ptr -> nx_igmp_header_word_0 & NX_IGMP_MAX_RESP_TIME_MASK) != NX_NULL) + { + /* Yes, this must be an IGMPv2 router. */ + ip_ptr -> nx_ip_igmp_router_version = NX_IGMP_HOST_VERSION_2; + } + else + { + /* No; IGMPv1 requires setting this field to zero. */ + ip_ptr -> nx_ip_igmp_router_version = NX_IGMP_HOST_VERSION_1; + } + + /* Is this packet from an IGMPv2 router? */ + if (ip_ptr -> nx_ip_igmp_router_version == NX_IGMP_HOST_VERSION_2) + { + + /* Yes; parse the max response time from the IGMP header. */ + max_update_time = (USHORT)(((header_ptr -> nx_igmp_header_word_0 & NX_IGMP_MAX_RESP_TIME_MASK) >> 16) & 0x000000FF); + + /* Convert from tenths of a second to seconds. */ + max_update_time /= 10; + } +#endif + + /* Then generate a random update time initially in timer ticks for the delay. */ + update_time = tx_time_get() & 0xF; + + /* Check we have a valid non zero update time that does not exceed the + maximum response time. */ + if ((update_time > max_update_time) || (update_time == NX_NULL)) + { + + /* If not, wrap the update time back to one second. */ + update_time = 1; + } + + /* Loop through the multicast join list and assign an arbitrary timeout to + respond between 1 and maximum response time for each group. */ + for (i = 0; i < NX_MAX_MULTICAST_GROUPS; i++) + { + + /* Is there a group address in this slot? */ + if (ip_ptr -> nx_ip_igmp_join_list[i] == NX_NULL) + { + + /* No, skip doing further processing. */ + continue; + } + + /* Does the group address in the header match our join list? */ + if ((ip_ptr -> nx_ip_igmp_join_list[i] != header_ptr -> nx_igmp_header_word_1) && + /* or is this a general membership query? */ + (header_ptr -> nx_igmp_header_word_1 != NX_NULL)) + { + + /* No; so no need to update the timer, skip to the next group in the host list. */ + continue; + } + + /* Is the current host group running timer less than the max delay? */ + if ((ip_ptr -> nx_ip_igmp_update_time[i] < max_update_time) && + (ip_ptr -> nx_ip_igmp_update_time[i] != NX_NULL)) + { + + /* Yes; Let the current timer timeout. Skip to the next group. */ + continue; + } + + /* Set the timeout for this multicast group. */ + ip_ptr -> nx_ip_igmp_update_time[i] = update_time; + + /* Then increment the update time for the next host group so the update/expiration times + are separated by one second. This avoids bursts of IGMP reports to the server. */ + update_time++; + + /* Check after each multicast group that we have not exceeded the maximum response time. */ + if (update_time > max_update_time) + { + + /* We have, so wrap the update time back to one. */ + update_time = 1; + } + } + } +#ifndef NX_DISABLE_IGMPV2 + + /* Is this another IGMPv1 host's join request? */ + else if (((header_ptr -> nx_igmp_header_word_0 & NX_IGMP_TYPE_MASK) == NX_IGMP_HOST_RESPONSE_TYPE) || + /* ...Or another IGMPv2 host's join request? */ + ((header_ptr -> nx_igmp_header_word_0 & NX_IGMPV2_TYPE_MASK) == NX_IGMP_HOST_V2_JOIN_TYPE)) +#else + + /* Is this another IGMPv1 host's join request? */ + else if ((header_ptr -> nx_igmp_header_word_0 & NX_IGMP_TYPE_MASK) == NX_IGMP_HOST_RESPONSE_TYPE) +#endif + { + + /* Yes; Loop through the host multicast join list to find a match. */ + for (i = 0; i < NX_MAX_MULTICAST_GROUPS; i++) + { + + /* Compare the group address in the header with the host list. Is this a match? */ + if (ip_ptr -> nx_ip_igmp_join_list[i] == header_ptr -> nx_igmp_header_word_1) + { + + /* Yes; Clear the update time. This will cancel sending a join + request for the same multicast group. */ + ip_ptr -> nx_ip_igmp_update_time[i] = 0; + break; + } + } + } + + /* Release the IGMP packet. */ + _nx_packet_release(packet_ptr); +} + diff --git a/common/src/nx_igmp_packet_receive.c b/common/src/nx_igmp_packet_receive.c new file mode 100644 index 0000000..d853b85 --- /dev/null +++ b/common/src/nx_igmp_packet_receive.c @@ -0,0 +1,146 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Group Management Protocol (IGMP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_packet.h" +#include "nx_igmp.h" +#include "nx_ip.h" +#include "tx_thread.h" + + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_igmp_packet_receive PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function handles reception of IGMP packets on the "all hosts" */ +/* multicast address. If this routine is called from an ISR, the */ +/* IGMP packet is queued. Otherwise, if this routine is called from */ +/* the IP helper thread, the processing of the IGMP packet is called */ +/* directly. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP instance pointer */ +/* packet_ptr IGMP packet pointer */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_igmp_packet_process Process the IGMP packet */ +/* tx_event_flags_set Set event flags for IP helper */ +/* thread */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ip_packet_receive Raw IP packet receive */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_igmp_packet_receive(NX_IP *ip_ptr, NX_PACKET *packet_ptr) +{ + +TX_INTERRUPT_SAVE_AREA + + +#ifndef NX_DISABLE_RX_SIZE_CHECKING + + /* Check for valid packet length. */ + if (packet_ptr -> nx_packet_length < sizeof(NX_IGMP_HEADER)) + { + +#ifndef NX_DISABLE_IGMP_INFO + /* Increment the IGMP invalid packet error. */ + ip_ptr -> nx_ip_igmp_invalid_packets++; +#endif + + /* Invalid packet length, just release it. */ + _nx_packet_release(packet_ptr); + + /* The function is complete, just return! */ + return; + } +#endif + + /* Determine if this routine is being called from an ISR. */ + if (TX_THREAD_GET_SYSTEM_STATE()) + { + + /* If non-zero, we are in an ISR. Just place the message on the + IGMP message queue and wakeup the IP helper thread. */ + + /* Disable interrupts. */ + TX_DISABLE + + /* Add the packet to the IGMP message queue. */ + if (ip_ptr -> nx_ip_igmp_queue_head) + { + + /* Link the current packet to the list head. */ + packet_ptr -> nx_packet_queue_next = ip_ptr -> nx_ip_igmp_queue_head; + } + else + { + + /* Empty queue, add to the head of the IGMP message queue. */ + packet_ptr -> nx_packet_queue_next = NX_NULL; + } + + /* Update the queue head pointer. */ + ip_ptr -> nx_ip_igmp_queue_head = packet_ptr; + + /* Restore interrupts. */ + TX_RESTORE + + /* Wakeup IP thread for processing one or more messages in the IGMP queue. */ + tx_event_flags_set(&(ip_ptr -> nx_ip_events), NX_IP_IGMP_EVENT, TX_OR); + } + else + { + + /* The IP message was deferred, so this routine is called from the IP helper + thread and thus may call the IGMP processing directly. */ + _nx_igmp_packet_process(ip_ptr, packet_ptr); + } +} + diff --git a/common/src/nx_igmp_periodic_processing.c b/common/src/nx_igmp_periodic_processing.c new file mode 100644 index 0000000..ad3f77c --- /dev/null +++ b/common/src/nx_igmp_periodic_processing.c @@ -0,0 +1,155 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Group Management Protocol (IGMP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_igmp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_igmp_periodic_processing PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function handles the sending of periodic processing of IGMP */ +/* messages. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP instance pointer */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* nx_igmp_interface_report_send Send IGMP group report */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ip_thread_entry IP helper thread */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_igmp_periodic_processing(NX_IP *ip_ptr) +{ + +UINT i; +UINT status; +UINT interface_index = 0; +ULONG *join_list_ptr; +UINT sent_count = 0; + + + /* Search the multicast join list for pending IGMP responses. */ + join_list_ptr = &(ip_ptr -> nx_ip_igmp_join_list[0]); + for (i = 0; i < NX_MAX_MULTICAST_GROUPS; i++) + { + + /* Determine if the specified entry is active. */ + if (*join_list_ptr) + { + + /* Now determine if a response is pending. */ + if (ip_ptr -> nx_ip_igmp_update_time[i] > 0) + { + + /* Yes, it is active. Decrement and check for expiration. */ + + /* We don't want to decrement a join group if we cannot send it. Check + if we've already sent a packet on this periodic. */ + if (sent_count > 0) + { + + /* We have. So only decrement groups with a update time > 1. */ + if (ip_ptr -> nx_ip_igmp_update_time[i] > 1) + { + + /* Ok to decrement. */ + ip_ptr -> nx_ip_igmp_update_time[i]--; + } + + /* Else don't decrement because we cannot send on this periodic; we've already sent out a packet. */ + } + else + { + + /* No packets sent out yet. Ok to decrement this group. */ + ip_ptr -> nx_ip_igmp_update_time[i]--; + } + + /* Has time expired and have we not sent an IGMP report in this period? */ + if ((ip_ptr -> nx_ip_igmp_update_time[i] == 0) && (sent_count == 0)) + { + + /* Time has expired and we have not yet sent a packet out on this periodic. */ + + UINT index; + NX_INTERFACE *nx_interface = ip_ptr -> nx_ip_igmp_join_interface_list[i]; + + /* We need to find the interface this group address is on. */ + for (index = 0; index < NX_MAX_PHYSICAL_INTERFACES; index++) + { + + if (nx_interface == &(ip_ptr -> nx_ip_interface[index])) + { + /* Found it. */ + interface_index = index; + + break; + } + } + + /* Build a IGMP host response packet for a join report and send it! */ + status = _nx_igmp_interface_report_send(ip_ptr, *join_list_ptr, interface_index, NX_TRUE); + + if (status == NX_SUCCESS) + { + /* Update the sent count. Only one report sent per IP periodic. */ + sent_count++; + } + } + } + } + + /* Move to the next entry in the join list. */ + join_list_ptr++; + } +} + diff --git a/common/src/nx_igmp_queue_process.c b/common/src/nx_igmp_queue_process.c new file mode 100644 index 0000000..5964576 --- /dev/null +++ b/common/src/nx_igmp_queue_process.c @@ -0,0 +1,103 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Group Management Protocol (IGMP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_igmp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_igmp_queue_process PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes the IGMP receive packet queue. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP control block */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_igmp_packet_process Process IGMP packet */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ip_thread_entry IP helper thread processing */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_igmp_queue_process(NX_IP *ip_ptr) +{ + +TX_INTERRUPT_SAVE_AREA + +NX_PACKET *queue_head; +NX_PACKET *packet_ptr; + + + /* Disable interrupts. */ + TX_DISABLE + + /* Remove the IGMP message queue from the IP structure. */ + queue_head = ip_ptr -> nx_ip_igmp_queue_head; + ip_ptr -> nx_ip_igmp_queue_head = NX_NULL; + + /* Restore interrupts. */ + TX_RESTORE + + /* Walk through the entire IGMP message queue and process packets + one by one. */ + while (queue_head) + { + + /* Pickup the first queue IGMP message and remove it from the + IGMP queue. */ + packet_ptr = queue_head; + queue_head = queue_head -> nx_packet_queue_next; + packet_ptr -> nx_packet_queue_next = NX_NULL; + + /* Process the packet. */ + _nx_igmp_packet_process(ip_ptr, packet_ptr); + } +} + diff --git a/common/src/nx_ip_address_change_notify.c b/common/src/nx_ip_address_change_notify.c new file mode 100644 index 0000000..3e0dad4 --- /dev/null +++ b/common/src/nx_ip_address_change_notify.c @@ -0,0 +1,96 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "tx_thread.h" +#include "nx_ip.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ip_address_change_notify PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function registers an application callback routine that NetX */ +/* calls whenever the IP address is changed. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP control block pointer */ +/* ip_address_change_notify Application callback function */ +/* additional_info Optional additional information */ +/* for the 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_ip_address_change_notify(NX_IP *ip_ptr, VOID (*ip_address_change_notify)(NX_IP *, VOID *), VOID *additional_info) +{ + +TX_INTERRUPT_SAVE_AREA + + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_IP_ADDRESS_CHANGE_NOTIFY, ip_ptr, ip_address_change_notify, additional_info, 0, NX_TRACE_IP_EVENTS, 0, 0) + + /* Disable interrupts. */ + TX_DISABLE + + /* Setup the IP address change callback function and the additional information pointers. */ + ip_ptr -> nx_ip_address_change_notify = ip_address_change_notify; + ip_ptr -> nx_ip_address_change_notify_additional_info = additional_info; + + /* Restore interrupts. */ + TX_RESTORE + + /* Return completion status. */ + return(NX_SUCCESS); +} + diff --git a/common/src/nx_ip_address_get.c b/common/src/nx_ip_address_get.c new file mode 100644 index 0000000..34139e4 --- /dev/null +++ b/common/src/nx_ip_address_get.c @@ -0,0 +1,95 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ip_address_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves the IP address and the network mask and */ +/* returns them to the caller. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP control block pointer */ +/* ip_address Pointer to IP address */ +/* network_mask Pointer to network mask */ +/* */ +/* 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_ip_address_get(NX_IP *ip_ptr, ULONG *ip_address, ULONG *network_mask) +{ +TX_INTERRUPT_SAVE_AREA + + + /* Disable interrupts. */ + TX_DISABLE + + /* Pickup the IP address and the network mask. */ + *ip_address = ip_ptr -> nx_ip_interface[0].nx_interface_ip_address; + *network_mask = ip_ptr -> nx_ip_interface[0].nx_interface_ip_network_mask; + + /* Restore interrupts. */ + TX_RESTORE + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_IP_ADDRESS_GET, ip_ptr, ip_ptr -> nx_ip_interface[0].nx_interface_ip_address, + ip_ptr -> nx_ip_interface[0].nx_interface_ip_network_mask, 0, NX_TRACE_IP_EVENTS, 0, 0) + + + /* Return completion status. */ + return(NX_SUCCESS); +} + diff --git a/common/src/nx_ip_address_set.c b/common/src/nx_ip_address_set.c new file mode 100644 index 0000000..598c838 --- /dev/null +++ b/common/src/nx_ip_address_set.c @@ -0,0 +1,126 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "tx_thread.h" +#include "nx_ip.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ip_address_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets the IP address and the network mask for the */ +/* supplied IP instance. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP control block pointer */ +/* ip_address IP address */ +/* network_mask Network mask */ +/* */ +/* 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_ip_address_set(NX_IP *ip_ptr, ULONG ip_address, ULONG network_mask) +{ + +TX_INTERRUPT_SAVE_AREA + +VOID (*address_change_notify)(NX_IP *, VOID *); +VOID *additional_info; +ULONG previous_ip_address; +ULONG previous_network_mask; + + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_IP_ADDRESS_SET, ip_ptr, ip_address, network_mask, 0, NX_TRACE_IP_EVENTS, 0, 0) + + /* Disable interrupts. */ + TX_DISABLE + + /* Save previous IP address and network mask. */ + previous_ip_address = ip_ptr -> nx_ip_interface[0].nx_interface_ip_address; + previous_network_mask = ip_ptr -> nx_ip_interface[0].nx_interface_ip_network_mask; + + /* Pickup the current notification callback and additional information pointers. */ + address_change_notify = ip_ptr -> nx_ip_address_change_notify; + additional_info = ip_ptr -> nx_ip_address_change_notify_additional_info; + + /* Setup the IP address and the network mask. */ + ip_ptr -> nx_ip_interface[0].nx_interface_ip_address = ip_address; + ip_ptr -> nx_ip_interface[0].nx_interface_ip_network_mask = network_mask; + ip_ptr -> nx_ip_interface[0].nx_interface_ip_network = ip_address & network_mask; + + /* Ensure the RARP function is disabled. */ + ip_ptr -> nx_ip_rarp_periodic_update = NX_NULL; + ip_ptr -> nx_ip_rarp_queue_process = NX_NULL; + + /* Restore interrupts. */ + TX_RESTORE + + /* Determine if the application should be notified of the IP address and/or + network mask change. */ + if ((address_change_notify) && + ((ip_address != previous_ip_address) || (network_mask != previous_network_mask))) + { + + /* Yes, call the application's IP address change notify function. */ + (address_change_notify)(ip_ptr, additional_info); + } + + /* Initialize the ARP defend timeout. */ + ip_ptr -> nx_ip_interface[0].nx_interface_arp_defend_timeout = 0; + + /* Return completion status. */ + return(NX_SUCCESS); +} + diff --git a/common/src/nx_ip_create.c b/common/src/nx_ip_create.c new file mode 100644 index 0000000..7c8ca9d --- /dev/null +++ b/common/src/nx_ip_create.c @@ -0,0 +1,270 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_packet.h" +#include "nx_system.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ip_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates an Internet Protocol instance, including */ +/* setting up all appropriate data structures and calling the supplied */ +/* link driver for initialization of the physical interface. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP control block */ +/* name Name of this IP instance */ +/* ip_address Internet address for this IP */ +/* network_mask Network mask for IP address */ +/* default_pool Default packet pool */ +/* ip_link_driver User supplied IP link driver */ +/* memory_ptr Pointer memory area for IP */ +/* memory_size Size of IP memory area */ +/* priority Priority of IP helper thread */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_event_flags_create Create IP event flags */ +/* tx_event_flags_delete Delete IP event flags */ +/* tx_mutex_create Create IP protection mutex */ +/* tx_mutex_delete Delete IP protection mutex */ +/* tx_thread_create Create IP helper thread */ +/* tx_timer_create Create IP periodic timer */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ip_create(NX_IP *ip_ptr, CHAR *name, ULONG ip_address, ULONG network_mask, + NX_PACKET_POOL *default_pool, VOID (*ip_link_driver)(struct NX_IP_DRIVER_STRUCT *), + VOID *memory_ptr, ULONG memory_size, UINT priority) +{ + +TX_INTERRUPT_SAVE_AREA + +NX_IP *tail_ptr; + + + /* Reference the version ID and option words to ensure they are linked in. */ + if ((_nx_system_build_options_1 | _nx_system_build_options_2 | _nx_system_build_options_3 | + _nx_system_build_options_4 | _nx_system_build_options_5 | (ULONG)_nx_version_id[0]) == 0) + { + + /* We should never get here! */ + return(NX_NOT_IMPLEMENTED); + } + + /* Initialize the IP control block to zero. */ + memset((void *)ip_ptr, 0, sizeof(NX_IP)); + + + ip_ptr -> nx_ip_interface[0].nx_interface_valid = 1; + /* Save the IP address. */ + ip_ptr -> nx_ip_interface[0].nx_interface_ip_address = ip_address; + + /* Save the network mask. */ + ip_ptr -> nx_ip_interface[0].nx_interface_ip_network_mask = network_mask; + + /* Derive the network bits of this IP address. */ + ip_ptr -> nx_ip_interface[0].nx_interface_ip_network = ip_address & network_mask; + + /* Setup the link driver address. */ + ip_ptr -> nx_ip_interface[0].nx_interface_link_driver_entry = ip_link_driver; + + /* Set the device interface name to "PRI". */ + ip_ptr -> nx_ip_interface[0].nx_interface_name = "PRI"; + + /* Store the IP instance into the interface structure. */ + ip_ptr -> nx_ip_interface[0].nx_interface_ip_instance = ip_ptr; + + /* Initialize the ARP defend timeout. */ + ip_ptr -> nx_ip_interface[0].nx_interface_arp_defend_timeout = 0; + + +#ifndef NX_DISABLE_LOOPBACK_INTERFACE + + /* Set the IP instance. */ + ip_ptr -> nx_ip_interface[NX_LOOPBACK_INTERFACE].nx_interface_ip_instance = ip_ptr; + + /* Set the Loopback interface name. */ + ip_ptr -> nx_ip_interface[NX_LOOPBACK_INTERFACE].nx_interface_name = "Internal IP Loopback"; + + + /* Mark the loopback interface as valid. */ + ip_ptr -> nx_ip_interface[NX_LOOPBACK_INTERFACE].nx_interface_valid = 1; + + /* Set the loopback interface address. */ + ip_ptr -> nx_ip_interface[NX_LOOPBACK_INTERFACE].nx_interface_ip_address = 0x7F000001; + ip_ptr -> nx_ip_interface[NX_LOOPBACK_INTERFACE].nx_interface_ip_network_mask = 0xFF000000; + ip_ptr -> nx_ip_interface[NX_LOOPBACK_INTERFACE].nx_interface_ip_network = 0x7F000000; + + /* Loopback interface is a special case. Therefore no dedicated link driver needed. */ + ip_ptr -> nx_ip_interface[NX_LOOPBACK_INTERFACE].nx_interface_link_driver_entry = NX_NULL; + + /* Loopback interface does not need IP/MAC address mapping. */ + ip_ptr -> nx_ip_interface[NX_LOOPBACK_INTERFACE].nx_interface_address_mapping_needed = 0; + + /* There is actually no MTU limit for the loopback interface. */ + ip_ptr -> nx_ip_interface[NX_LOOPBACK_INTERFACE].nx_interface_ip_mtu_size = 65535; + + /* Mark the loopback interface as LINK UP */ + ip_ptr -> nx_ip_interface[NX_LOOPBACK_INTERFACE].nx_interface_link_up = 1; +#endif /* !NX_DISABLE_LOOPBACK_INTERFACE */ + + /* Save the supplied IP name. */ + ip_ptr -> nx_ip_name = name; + + /* Set the initial IP packet ID. */ + ip_ptr -> nx_ip_packet_id = NX_INIT_PACKET_ID; + + /* Setup the default packet pool for this IP instance. */ + ip_ptr -> nx_ip_default_packet_pool = default_pool; + + /* Create the internal IP protection mutex. */ + if (tx_mutex_create(&(ip_ptr -> nx_ip_protection), name, TX_NO_INHERIT)) + { + return(NX_IP_INTERNAL_ERROR); + } + + /* Create the internal IP event flag object. */ + if (tx_event_flags_create(&(ip_ptr -> nx_ip_events), name)) + { + /* Delete the internal mutex. */ + tx_mutex_delete(&(ip_ptr -> nx_ip_protection)); + + /* Return an error. */ + return(NX_IP_INTERNAL_ERROR); + } + + /* Create the internal IP thread for handling more processing intensive + duties. */ + if (tx_thread_create(&(ip_ptr -> nx_ip_thread), name, _nx_ip_thread_entry, (ULONG)ip_ptr, + memory_ptr, memory_size, priority, priority, 1, TX_AUTO_START)) + { + + /* Delete the event flag group. */ + tx_event_flags_delete(&(ip_ptr -> nx_ip_events)); + + /* Delete the internal mutex. */ + tx_mutex_delete(&(ip_ptr -> nx_ip_protection)); + + /* Return an error. */ + return(NX_IP_INTERNAL_ERROR); + } + + /* Create the periodic timer for this IP instance. */ + if (tx_timer_create(&(ip_ptr -> nx_ip_periodic_timer), name, + _nx_ip_periodic_timer_entry, (ULONG)ip_ptr, + NX_IP_PERIODIC_RATE, NX_IP_PERIODIC_RATE, TX_AUTO_ACTIVATE)) + { + + /* Delete the event flag group. */ + tx_event_flags_delete(&(ip_ptr -> nx_ip_events)); + + /* Delete the internal mutex. */ + tx_mutex_delete(&(ip_ptr -> nx_ip_protection)); + + /* Terminate and delete helper thread. */ + tx_thread_terminate(&(ip_ptr -> nx_ip_thread)); + tx_thread_delete(&(ip_ptr -> nx_ip_thread)); + + /* Return an error. */ + return(NX_IP_INTERNAL_ERROR); + } + + /* If trace is enabled, register this object. */ + NX_TRACE_OBJECT_REGISTER(NX_TRACE_OBJECT_TYPE_IP, ip_ptr, name, memory_ptr, memory_size) + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_IP_CREATE, ip_ptr, ip_address, network_mask, default_pool, NX_TRACE_IP_EVENTS, 0, 0) + + /* Otherwise, the IP initialization was successful. Place the + IP control block on the list of created IP instances. */ + TX_DISABLE + + /* Load the IP ID field in the IP control block. */ + ip_ptr -> nx_ip_id = NX_IP_ID; + + /* Place the new IP control block on the list of created IPs. First, + check for an empty list. */ + if (_nx_ip_created_ptr) + { + + /* Pickup tail pointer. */ + tail_ptr = _nx_ip_created_ptr -> nx_ip_created_previous; + + /* Place the new IP control block in the list. */ + _nx_ip_created_ptr -> nx_ip_created_previous = ip_ptr; + tail_ptr -> nx_ip_created_next = ip_ptr; + + /* Setup this IP's created links. */ + ip_ptr -> nx_ip_created_previous = tail_ptr; + ip_ptr -> nx_ip_created_next = _nx_ip_created_ptr; + } + else + { + + /* The created IP list is empty. Add IP control block to empty list. */ + _nx_ip_created_ptr = ip_ptr; + ip_ptr -> nx_ip_created_next = ip_ptr; + ip_ptr -> nx_ip_created_previous = ip_ptr; + } + + /* Increment the created IP counter. */ + _nx_ip_created_count++; + + /* Restore previous interrupt posture. */ + TX_RESTORE + + /* Return success to the caller. */ + return(NX_SUCCESS); +} + diff --git a/common/src/nx_ip_deferred_link_status_process.c b/common/src/nx_ip_deferred_link_status_process.c new file mode 100644 index 0000000..888a800 --- /dev/null +++ b/common/src/nx_ip_deferred_link_status_process.c @@ -0,0 +1,102 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + +/* Include necessary system files. */ +#include "nx_api.h" +#include "nx_ip.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ip_diferred_link_status_process PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes link status change event. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP control block */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* link_driver_entry Link driver */ +/* */ +/* CALLED BY */ +/* */ +/* nx_ip_thread_entry */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_ip_deferred_link_status_process(NX_IP *ip_ptr) +{ + +UINT i; +NX_IP_DRIVER driver_request; +ULONG link_up; + + if (ip_ptr -> nx_ip_link_status_change_callback == NX_NULL) + { + + /* Callback function is not set. */ + return; + } + + for (i = 0; i < NX_MAX_PHYSICAL_INTERFACES; i++) + { + if ((ip_ptr -> nx_ip_interface[i].nx_interface_valid) && + (ip_ptr -> nx_ip_interface[i].nx_interface_link_status_change)) + { + + /* Reset the flag. */ + ip_ptr -> nx_ip_interface[i].nx_interface_link_status_change = NX_FALSE; + + driver_request.nx_ip_driver_ptr = ip_ptr; + driver_request.nx_ip_driver_command = NX_LINK_GET_STATUS; + driver_request.nx_ip_driver_interface = &(ip_ptr -> nx_ip_interface[i]); + driver_request.nx_ip_driver_return_ptr = &link_up; + + (ip_ptr -> nx_ip_interface[i].nx_interface_link_driver_entry)(&driver_request); + + /* Invoke the callback function. */ + ip_ptr -> nx_ip_link_status_change_callback(ip_ptr, i, link_up); + } + } +} + diff --git a/common/src/nx_ip_delete.c b/common/src/nx_ip_delete.c new file mode 100644 index 0000000..091a40f --- /dev/null +++ b/common/src/nx_ip_delete.c @@ -0,0 +1,336 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "tx_thread.h" +#include "nx_ip.h" +#include "nx_icmp.h" +#include "nx_packet.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ip_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function deletes an Internet Protocol instance, including */ +/* calling the associated driver with a link disable request. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP control block */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ip_delete_queue_clear Clear a packet queue */ +/* _nx_ip_raw_packet_cleanup Cleanup raw packet suspension */ +/* _nx_icmp_cleanup Cleanup for ICMP packets */ +/* _nx_ip_fragment_disable Disable fragment processing */ +/* tx_mutex_delete Delete IP protection mutex */ +/* tx_mutex_get Get protection mutex */ +/* tx_mutex_put Put protection mutex */ +/* tx_thread_terminate Terminate IP helper thread */ +/* tx_event_flags_delete Delete IP event flags */ +/* tx_thread_delete Delete IP helper thread */ +/* _tx_thread_system_preempt_check Check for preemption */ +/* tx_timer_deactivate Deactivate IP-ARP timer */ +/* tx_timer_delete Delete IP-ARP timer */ +/* (ip_link_driver) User supplied link driver */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ip_delete(NX_IP *ip_ptr) +{ + +TX_INTERRUPT_SAVE_AREA + +NX_IP_DRIVER driver_request; +NX_PACKET *raw_packet_head; +NX_PACKET *deferred_head; +NX_PACKET *icmp_queue_head; +NX_PACKET *igmp_queue_head; +NX_PACKET *tcp_queue_head; +NX_PACKET *arp_queue_head; +NX_PACKET *rarp_queue_head; +UINT i; + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_IP_DELETE, ip_ptr, 0, 0, 0, NX_TRACE_IP_EVENTS, 0, 0) + + /* Get mutex protection. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + + /* Determine if the IP instance has any sockets bound to it. */ + if ((ip_ptr -> nx_ip_udp_created_sockets_count) || (ip_ptr -> nx_ip_tcp_created_sockets_count)) + { + + /* Still sockets bound to this IP instance. They must all be deleted prior + to deleting the IP instance. Release the mutex and return + an error code. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + return(NX_SOCKETS_BOUND); + } + + /* Call through every link driver to disable the link. */ + for (i = 0; i < NX_MAX_PHYSICAL_INTERFACES; i++) + { + + /* Skip the invalid entries. */ + if (!(ip_ptr -> nx_ip_interface[i].nx_interface_valid)) + { + continue; + } + + driver_request.nx_ip_driver_ptr = ip_ptr; + driver_request.nx_ip_driver_command = NX_LINK_DISABLE; + driver_request.nx_ip_driver_interface = &(ip_ptr -> nx_ip_interface[i]); + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_IO_DRIVER_LINK_DISABLE, ip_ptr, 0, 0, 0, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + (ip_ptr -> nx_ip_interface[i].nx_interface_link_driver_entry) (&driver_request); + + /* Call the link driver to uninitialize. */ + driver_request.nx_ip_driver_ptr = ip_ptr; + driver_request.nx_ip_driver_command = NX_LINK_UNINITIALIZE; + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_IO_DRIVER_UNINITIALIZE, ip_ptr, 0, 0, 0, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + (ip_ptr -> nx_ip_interface[i].nx_interface_link_driver_entry) (&driver_request); + } + + /* Disable interrupts. */ + TX_DISABLE + + /* Remove the IP instance from the created list. */ + + /* See if the IP instance is the only one on the list. */ + if (ip_ptr == ip_ptr -> nx_ip_created_next) + { + + /* Only created IP instance, just set the created list to NULL. */ + _nx_ip_created_ptr = TX_NULL; + } + else + { + + /* Otherwise, not the only created IP, link-up the neighbors. */ + (ip_ptr -> nx_ip_created_next) -> nx_ip_created_previous = + ip_ptr -> nx_ip_created_previous; + (ip_ptr -> nx_ip_created_previous) -> nx_ip_created_next = + ip_ptr -> nx_ip_created_next; + + /* See if we have to update the created list head pointer. */ + if (_nx_ip_created_ptr == ip_ptr) + { + + /* Yes, move the head pointer to the next link. */ + _nx_ip_created_ptr = ip_ptr -> nx_ip_created_next; + } + } + + /* Decrement the IP created counter. */ + _nx_ip_created_count--; + + /* Temporarily disable preemption. */ + _tx_thread_preempt_disable++; + + /* Release any raw packets queued up. */ + raw_packet_head = ip_ptr -> nx_ip_raw_received_packet_head; + ip_ptr -> nx_ip_raw_received_packet_head = NX_NULL; + ip_ptr -> nx_ip_raw_received_packet_tail = NX_NULL; + ip_ptr -> nx_ip_raw_received_packet_count = 0; + + /* Release all deferred IP packets. */ + deferred_head = ip_ptr -> nx_ip_deferred_received_packet_head; + ip_ptr -> nx_ip_deferred_received_packet_head = NX_NULL; + ip_ptr -> nx_ip_deferred_received_packet_tail = NX_NULL; + + /* Release all queued ICMP packets. */ + icmp_queue_head = ip_ptr -> nx_ip_icmp_queue_head; + ip_ptr -> nx_ip_icmp_queue_head = NX_NULL; + + /* Release all queued IGMP packets. */ + igmp_queue_head = ip_ptr -> nx_ip_igmp_queue_head; + ip_ptr -> nx_ip_igmp_queue_head = NX_NULL; + + /* Release all queued TCP packets. */ + tcp_queue_head = ip_ptr -> nx_ip_tcp_queue_head; + ip_ptr -> nx_ip_tcp_queue_head = NX_NULL; + ip_ptr -> nx_ip_tcp_queue_tail = NX_NULL; + + /* Release all queued ARP packets. */ + arp_queue_head = ip_ptr -> nx_ip_arp_deferred_received_packet_head; + ip_ptr -> nx_ip_arp_deferred_received_packet_head = NX_NULL; + ip_ptr -> nx_ip_arp_deferred_received_packet_tail = NX_NULL; + + /* Release all queued RARP packets. */ + rarp_queue_head = ip_ptr -> nx_ip_rarp_deferred_received_packet_head; + ip_ptr -> nx_ip_rarp_deferred_received_packet_head = NX_NULL; + ip_ptr -> nx_ip_rarp_deferred_received_packet_tail = NX_NULL; + + /* Restore interrupts. */ + TX_RESTORE + + /* Release mutex protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Deactivate and delete the IP periodic timer. */ + tx_timer_deactivate(&(ip_ptr -> nx_ip_periodic_timer)); + tx_timer_delete(&(ip_ptr -> nx_ip_periodic_timer)); + + /* Determine if TCP is enabled. */ + if (ip_ptr -> nx_ip_tcp_packet_receive) + { + + /* Yes, TCP is enabled. Deactivate and delete the TCP fast periodic timer. */ + tx_timer_deactivate(&(ip_ptr -> nx_ip_tcp_fast_periodic_timer)); + tx_timer_delete(&(ip_ptr -> nx_ip_tcp_fast_periodic_timer)); + } + + /* Terminate the internal IP thread. */ + tx_thread_terminate(&(ip_ptr -> nx_ip_thread)); + + /* Delete the internal IP protection mutex. */ + tx_mutex_delete(&(ip_ptr -> nx_ip_protection)); + + /* Delete the internal IP event flag object. */ + tx_event_flags_delete(&(ip_ptr -> nx_ip_events)); + + /* Delete the internal IP thread for handling more processing intensive + duties. */ + tx_thread_delete(&(ip_ptr -> nx_ip_thread)); + + /* Release any raw packets queued up. */ + if (raw_packet_head) + { + _nx_ip_delete_queue_clear(raw_packet_head); + } + + /* Release any deferred IP packets. */ + if (deferred_head) + { + _nx_ip_delete_queue_clear(deferred_head); + } + + /* Release any queued ICMP packets. */ + if (icmp_queue_head) + { + _nx_ip_delete_queue_clear(icmp_queue_head); + } + + /* Release any queued IGMP packets. */ + if (igmp_queue_head) + { + _nx_ip_delete_queue_clear(igmp_queue_head); + } + + /* Release any queued TCP packets. */ + if (tcp_queue_head) + { + _nx_ip_delete_queue_clear(tcp_queue_head); + } + + /* Release any queued ARP packets. */ + if (arp_queue_head) + { + _nx_ip_delete_queue_clear(arp_queue_head); + } + + /* Release any queued RARP packets. */ + if (rarp_queue_head) + { + _nx_ip_delete_queue_clear(rarp_queue_head); + } + + /* Lift any suspension on RAW IP packet receives. */ + while (ip_ptr -> nx_ip_raw_packet_suspension_list) + { + + /* Release the suspended thread. */ + _nx_ip_raw_packet_cleanup(ip_ptr -> nx_ip_raw_packet_suspension_list NX_CLEANUP_ARGUMENT); + } + + /* Lift any suspension on ICMP ping requests. */ + while (ip_ptr -> nx_ip_icmp_ping_suspension_list) + { + + /* Release the suspended thread. */ + _nx_icmp_cleanup(ip_ptr -> nx_ip_icmp_ping_suspension_list NX_CLEANUP_ARGUMENT); + } + + /* Determine if fragment processing was enabled. */ + if (ip_ptr -> nx_ip_fragment_processing) + { + + /* Yes, disable fragment processing, which will release all outstanding + fragmented packets. */ + _nx_ip_fragment_disable(ip_ptr); + } + + /* Clear the IP ID to make it invalid. */ + ip_ptr -> nx_ip_id = 0; + + /* Disable interrupts. */ + TX_DISABLE + + /* Restore preemption. */ + _tx_thread_preempt_disable--; + + /* Restore interrupts. */ + TX_RESTORE + + /* Check for preemption. */ + _tx_thread_system_preempt_check(); + + /* Return success to the caller. */ + return(NX_SUCCESS); +} + diff --git a/common/src/nx_ip_delete_queue_clear.c b/common/src/nx_ip_delete_queue_clear.c new file mode 100644 index 0000000..44511dd --- /dev/null +++ b/common/src/nx_ip_delete_queue_clear.c @@ -0,0 +1,94 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_packet.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ip_delete_queue_clear PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function releases all packets in a packet queue. */ +/* */ +/* INPUT */ +/* */ +/* head_ptr Pointer to head of queue */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_packet_release Release data packet */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_ip_delete_queue_clear(NX_PACKET *head_ptr) +{ + +NX_PACKET *next_packet; +NX_PACKET *current_packet; + + + /* Setup next packet to queue head. */ + next_packet = head_ptr; + + /* Release any raw IP 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); + } +} + diff --git a/common/src/nx_ip_driver_deferred_enable.c b/common/src/nx_ip_driver_deferred_enable.c new file mode 100644 index 0000000..f7f522b --- /dev/null +++ b/common/src/nx_ip_driver_deferred_enable.c @@ -0,0 +1,98 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ip_driver_deferred_enable PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function enabled the deferred driver packet processing */ +/* in NetX. The supplied driver packet handler is called from the */ +/* IP helper thread to fully process a received driver packet. The */ +/* driver's receive packet processing only makes a call to the */ +/* _nx_ip_driver_deferred_receive processing from the ISR. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP control block */ +/* driver_deferred_packet_handler Function pointer to driver's */ +/* deferred packet handling */ +/* routine */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Driver Initialization */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_ip_driver_deferred_enable(NX_IP *ip_ptr, VOID (*driver_deferred_packet_handler)(NX_IP *ip_ptr, NX_PACKET *packet_ptr)) +{ + +#ifdef NX_DRIVER_DEFERRED_PROCESSING +TX_INTERRUPT_SAVE_AREA + + /* Disable interrupts. */ + TX_DISABLE + + /* Initialize the deferred packet queue to be empty */ + ip_ptr -> nx_ip_driver_deferred_packet_head = NX_NULL; + ip_ptr -> nx_ip_driver_deferred_packet_tail = NX_NULL; + + /* Setup the driver's deferred packet processing routine */ + ip_ptr -> nx_ip_driver_deferred_packet_handler = driver_deferred_packet_handler; + + TX_RESTORE +#else + NX_PARAMETER_NOT_USED(ip_ptr); + NX_PARAMETER_NOT_USED(driver_deferred_packet_handler); +#endif +} + diff --git a/common/src/nx_ip_driver_deferred_processing.c b/common/src/nx_ip_driver_deferred_processing.c new file mode 100644 index 0000000..f464d01 --- /dev/null +++ b/common/src/nx_ip_driver_deferred_processing.c @@ -0,0 +1,83 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ip_driver_deferred_processing PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function causes the driver to be called from the IP helper */ +/* thread in order to finish some deferred processing. A typical */ +/* example of this is the transmit complete interrupt. Instead of */ +/* loading the packet inside the transmit complete interrupt, the */ +/* driver can setup some internal variables and call this routine */ +/* to be called subsequently from the IP helper thread to finish */ +/* the transmit complete interrupt processing. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP control block */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* tx_event_flags_set Set event flags to wake IP */ +/* helper thread */ +/* */ +/* CALLED BY */ +/* */ +/* Application Driver */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_ip_driver_deferred_processing(NX_IP *ip_ptr) +{ + + /* Set event flags to wake the IP helper thread, which will in turn + call the driver with the NX_LINK_DEFERRED_PROCESSING command. */ + tx_event_flags_set(&(ip_ptr -> nx_ip_events), NX_IP_DRIVER_DEFERRED_EVENT, TX_OR); +} + diff --git a/common/src/nx_ip_driver_deferred_receive.c b/common/src/nx_ip_driver_deferred_receive.c new file mode 100644 index 0000000..54f066c --- /dev/null +++ b/common/src/nx_ip_driver_deferred_receive.c @@ -0,0 +1,118 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_packet.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ip_driver_deferred_receive PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function places the supplied packet on the driver's deferred */ +/* receive queue. It will be processed later during subsequent */ +/* execution of the IP helper thread by calling the driver's deferred */ +/* handling routine. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP control block */ +/* packet_ptr Raw receive packet */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Driver Receive ISR */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_ip_driver_deferred_receive(NX_IP *ip_ptr, NX_PACKET *packet_ptr) +{ + +#ifdef NX_DRIVER_DEFERRED_PROCESSING +TX_INTERRUPT_SAVE_AREA + + /* Disable interrupts. */ + TX_DISABLE + + /* Add the packet to the end of the driver queue for processing */ + packet_ptr -> nx_packet_queue_next = NX_NULL; + if (ip_ptr -> nx_ip_driver_deferred_packet_head == NX_NULL) + { + + /* The queue is empty, set both the first and last packet + pointers to the new packet */ + ip_ptr -> nx_ip_driver_deferred_packet_head = packet_ptr; + ip_ptr -> nx_ip_driver_deferred_packet_tail = packet_ptr; + + /* Restore interrupts. */ + TX_RESTORE + + /* Wakeup IP helper thread to process the packet. */ + tx_event_flags_set(&(ip_ptr -> nx_ip_events), NX_IP_DRIVER_PACKET_EVENT, TX_OR); + } + else + { + + /* The queue is not empty, simply add the packet to the end of the queue. */ + (ip_ptr -> nx_ip_driver_deferred_packet_tail) -> nx_packet_queue_next = packet_ptr; + ip_ptr -> nx_ip_driver_deferred_packet_tail = packet_ptr; + + /* Restore interrupts. */ + TX_RESTORE + } + +#else + + NX_PARAMETER_NOT_USED(ip_ptr); + + /* No deferred packet processing, just release the packet. */ + _nx_packet_release(packet_ptr); +#endif +} + diff --git a/common/src/nx_ip_driver_direct_command.c b/common/src/nx_ip_driver_direct_command.c new file mode 100644 index 0000000..5de79ad --- /dev/null +++ b/common/src/nx_ip_driver_direct_command.c @@ -0,0 +1,108 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ip_driver_direct_command PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function provides the application with direct access to the */ +/* IP's link-level driver. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP instance */ +/* command Driver command (NX_LINK_*) */ +/* return_value_ptr Pointer to place return values*/ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Get protection mutex */ +/* tx_mutex_put Put protection mutex */ +/* (ip_link_driver) User supplied link driver */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ip_driver_direct_command(NX_IP *ip_ptr, UINT command, ULONG *return_value_ptr) +{ + +NX_IP_DRIVER driver_request; + +#ifdef TX_ENABLE_EVENT_TRACE +TX_TRACE_BUFFER_ENTRY *trace_event; +ULONG trace_timestamp; +#endif + + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_IP_DRIVER_DIRECT_COMMAND, ip_ptr, command, 0, 0, NX_TRACE_IP_EVENTS, &trace_event, &trace_timestamp) + + /* Get mutex protection. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Build the driver request structure. */ + driver_request.nx_ip_driver_ptr = ip_ptr; + driver_request.nx_ip_driver_command = command; + driver_request.nx_ip_driver_return_ptr = return_value_ptr; + driver_request.nx_ip_driver_interface = &(ip_ptr -> nx_ip_interface[0]); + + (ip_ptr -> nx_ip_interface[0].nx_interface_link_driver_entry)(&driver_request); + + /* Release mutex protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Update the trace event with the status. */ + NX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, NX_TRACE_IP_DRIVER_DIRECT_COMMAND, 0, 0, driver_request.nx_ip_driver_status, 0) + + /* Return status to the caller. */ + return(driver_request.nx_ip_driver_status); +} + diff --git a/common/src/nx_ip_driver_interface_direct_command.c b/common/src/nx_ip_driver_interface_direct_command.c new file mode 100644 index 0000000..d26751f --- /dev/null +++ b/common/src/nx_ip_driver_interface_direct_command.c @@ -0,0 +1,108 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ip_driver_interface_direct_command PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function provides the application with direct access to */ +/* the specific IP's link-level driver. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP instance */ +/* command Driver command (NX_LINK_*) */ +/* interface_index Index to the interface */ +/* return_value_ptr Pointer to place return values*/ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Get protection mutex */ +/* tx_mutex_put Put protection mutex */ +/* (ip_link_driver) User supplied link driver */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ip_driver_interface_direct_command(NX_IP *ip_ptr, UINT command, UINT interface_index, ULONG *return_value_ptr) +{ + +NX_IP_DRIVER driver_request; + +#ifdef TX_ENABLE_EVENT_TRACE +TX_TRACE_BUFFER_ENTRY *trace_event; +ULONG trace_timestamp; +#endif + + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_IP_DRIVER_DIRECT_COMMAND, ip_ptr, command, 0, 0, NX_TRACE_IP_EVENTS, &trace_event, &trace_timestamp) + + /* Get mutex protection. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Build the driver request structure. */ + driver_request.nx_ip_driver_ptr = ip_ptr; + driver_request.nx_ip_driver_command = command; + driver_request.nx_ip_driver_return_ptr = return_value_ptr; + driver_request.nx_ip_driver_interface = &(ip_ptr -> nx_ip_interface[interface_index]); + (ip_ptr -> nx_ip_interface[interface_index].nx_interface_link_driver_entry)(&driver_request); + + /* Release mutex protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Update the trace event with the status. */ + NX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, NX_TRACE_IP_DRIVER_DIRECT_COMMAND, 0, 0, driver_request.nx_ip_driver_status, 0) + + /* Return status to the caller. */ + return(driver_request.nx_ip_driver_status); +} + diff --git a/common/src/nx_ip_driver_link_status_event.c b/common/src/nx_ip_driver_link_status_event.c new file mode 100644 index 0000000..609e73f --- /dev/null +++ b/common/src/nx_ip_driver_link_status_event.c @@ -0,0 +1,85 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ip_driver_link_status_event PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function deferrs link status event from ISR to the IP helper */ +/* thread. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP control block */ +/* interface_index Index of interface */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* tx_event_flags_set Wakeup IP helper thread */ +/* */ +/* CALLED BY */ +/* */ +/* Application I/O Driver */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_ip_driver_link_status_event(NX_IP *ip_ptr, UINT interface_index) +{ +TX_INTERRUPT_SAVE_AREA + + /* Disable interrupts. */ + TX_DISABLE + + /* Mark link status changed. */ + ip_ptr -> nx_ip_interface[interface_index].nx_interface_link_status_change = NX_TRUE; + + /* Wakeup IP helper thread to process the link status event. */ + tx_event_flags_set(&(ip_ptr -> nx_ip_events), NX_IP_LINK_STATUS_EVENT, TX_OR); + + /* Restore interrupts. */ + TX_RESTORE +} + diff --git a/common/src/nx_ip_forward_packet_process.c b/common/src/nx_ip_forward_packet_process.c new file mode 100644 index 0000000..4fe2cab --- /dev/null +++ b/common/src/nx_ip_forward_packet_process.c @@ -0,0 +1,97 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ip_packet_receive PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function attempts to forward the IP packet to the destination */ +/* IP by using the NetX send packet routine. Note that the IP header */ +/* is still intact prior to the packet. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP control block */ +/* packet_ptr Pointer to packet to forward */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_ip_packet_send Send IP packet */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ip_packet_receive Receive IP packet */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_ip_forward_packet_process(NX_IP *ip_ptr, NX_PACKET *packet_ptr) +{ + +NX_IP_HEADER *ip_header_ptr; + + + /* The NetX IP forwarding consists of simply sending the same packet out through + the internal send routine. Applications may choose to modify this code or + replace the nx_ip_forward_packet_process pointer in the IP structure to point + at an application-specific routine for forwarding. */ + + /* It's assumed that the IP header is still present in front of the packet. Position + backwards to access it. */ + ip_header_ptr = (NX_IP_HEADER *)(packet_ptr -> nx_packet_prepend_ptr - sizeof(NX_IP_HEADER)); + + /* Call the IP send routine to forward the packet. */ + _nx_ip_packet_send(ip_ptr, packet_ptr, ip_header_ptr -> nx_ip_header_destination_ip, + (ip_header_ptr -> nx_ip_header_word_0 & NX_IP_TOS_MASK), + (ip_header_ptr -> nx_ip_header_word_2 & NX_IP_TIME_TO_LIVE_MASK) >> NX_IP_TIME_TO_LIVE_SHIFT, + (ip_header_ptr -> nx_ip_header_word_2 & NX_IP_PROTOCOL_MASK), + (ip_header_ptr -> nx_ip_header_word_1 & NX_DONT_FRAGMENT)); + + /* Return to caller. */ + return; +} + diff --git a/common/src/nx_ip_forwarding_disable.c b/common/src/nx_ip_forwarding_disable.c new file mode 100644 index 0000000..8b23b1e --- /dev/null +++ b/common/src/nx_ip_forwarding_disable.c @@ -0,0 +1,91 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ip_forwarding_disable PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function disables the IP forwarding by clearing the forward */ +/* processing function pointer in the specified IP instance. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP instance */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ip_forwarding_disable(NX_IP *ip_ptr) +{ + +TX_INTERRUPT_SAVE_AREA + + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_IP_FORWARDING_DISABLE, ip_ptr, 0, 0, 0, NX_TRACE_IP_EVENTS, 0, 0) + + /* Disable interrupts temporarily. */ + TX_DISABLE + + /* Clear the IP forwarding processing routine pointer. */ + ip_ptr -> nx_ip_forward_packet_process = NX_NULL; + + /* Restore interrupts. */ + TX_RESTORE + + /* Return success to the caller. */ + return(NX_SUCCESS); +} + diff --git a/common/src/nx_ip_forwarding_enable.c b/common/src/nx_ip_forwarding_enable.c new file mode 100644 index 0000000..197ece6 --- /dev/null +++ b/common/src/nx_ip_forwarding_enable.c @@ -0,0 +1,91 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ip_forwarding_enable PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function enables the IP forwarding by setting up the forward */ +/* processing function pointer in the specified IP instance. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP instance */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ip_forwarding_enable(NX_IP *ip_ptr) +{ + +TX_INTERRUPT_SAVE_AREA + + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_IP_FORWARDING_ENABLE, ip_ptr, 0, 0, 0, NX_TRACE_IP_EVENTS, 0, 0) + + /* Disable interrupts temporarily. */ + TX_DISABLE + + /* Setup the IP forwarding processing routine pointer. */ + ip_ptr -> nx_ip_forward_packet_process = _nx_ip_forward_packet_process; + + /* Restore interrupts. */ + TX_RESTORE + + /* Return success to the caller. */ + return(NX_SUCCESS); +} + diff --git a/common/src/nx_ip_fragment_assembly.c b/common/src/nx_ip_fragment_assembly.c new file mode 100644 index 0000000..04f081b --- /dev/null +++ b/common/src/nx_ip_fragment_assembly.c @@ -0,0 +1,481 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_packet.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ip_fragment_assemble PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes the received fragment queue and attempts to */ +/* reassemble fragmented IP datagrams. Once a datagram is reassembled */ +/* it is dispatched to the appropriate component. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP instance */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_packet_release Release packet */ +/* (ip_tcp_packet_receive) Receive a TCP packet */ +/* (ip_udp_packet_receive) Receive a UDP packet */ +/* (ip_icmp_packet_receive) Receive a ICMP packet */ +/* (ip_igmp_packet_receive) Receive a IGMP packet */ +/* (ip_raw_ip_raw_packet_processing) Process a Raw IP packet */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_ip_fragment_assembly(NX_IP *ip_ptr) +{ +TX_INTERRUPT_SAVE_AREA + +NX_PACKET *new_fragment_head; +NX_PACKET *current_fragment; +NX_PACKET *previous_fragment = NX_NULL; +NX_PACKET *fragment_head; +NX_PACKET *search_ptr; +NX_PACKET *previous_ptr; +NX_PACKET *found_ptr; +NX_IP_HEADER *search_header; +NX_IP_HEADER *current_header; +ULONG current_id; +ULONG current_offset; +ULONG protocol; +UCHAR incomplete; + + + /* Disable interrupts. */ + TX_DISABLE + + /* Remove the packets from the incoming IP fragment queue. */ + new_fragment_head = ip_ptr -> nx_ip_received_fragment_head; + ip_ptr -> nx_ip_received_fragment_head = NX_NULL; + ip_ptr -> nx_ip_received_fragment_tail = NX_NULL; + + /* Restore interrupts. */ + TX_RESTORE + + /* Process each IP packet in the received IP fragment queue. */ + while (new_fragment_head) + { + + /* Setup the current fragment pointer. */ + current_fragment = new_fragment_head; + + /* Move the head pointer. */ + new_fragment_head = new_fragment_head -> nx_packet_queue_next; + + /* Setup header pointer for this packet. */ + current_header = (NX_IP_HEADER *)current_fragment -> nx_packet_prepend_ptr; + + /* Pickup the ID of this fragment. */ + current_id = (current_header -> nx_ip_header_word_1 >> NX_SHIFT_BY_16); + + /* Set the found pointer to NULL. */ + found_ptr = NX_NULL; + + /* Does the assembly list have anything in it? */ + if (ip_ptr -> nx_ip_fragment_assembly_head) + { + + /* Yes, we need to search the assembly queue to see if this fragment belongs + to another fragment. */ + search_ptr = ip_ptr -> nx_ip_fragment_assembly_head; + previous_fragment = NX_NULL; + while (search_ptr) + { + + /* Setup a pointer to the IP header of the packet in the assembly list. */ + search_header = (NX_IP_HEADER *)search_ptr -> nx_packet_prepend_ptr; + + /* Determine if the IP header fields match. RFC 791 Section 3.2 recommends that packet + fragments be compared for source IP, destination IP, protocol and IP header ID. */ + if ((current_id == (search_header -> nx_ip_header_word_1 >> NX_SHIFT_BY_16)) && + ((search_header -> nx_ip_header_word_2 & NX_IP_PROTOCOL_MASK) == + (current_header -> nx_ip_header_word_2 & NX_IP_PROTOCOL_MASK)) && + (search_header -> nx_ip_header_source_ip == current_header -> nx_ip_header_source_ip) && + (search_header -> nx_ip_header_destination_ip == current_header -> nx_ip_header_destination_ip)) + { + + /* Yes, we found a match, just set the found_ptr and get out of + this loop! */ + found_ptr = search_ptr; + break; + } + + /* Remember the previous pointer. */ + previous_fragment = search_ptr; + + /* Move to the next IP fragment in the re-assembly queue. */ + search_ptr = search_ptr -> nx_packet_queue_next; + } + } + + /* Was another IP packet fragment found? */ + if (found_ptr) + { + + /* Save the fragment head pointer. */ + fragment_head = found_ptr; + + /* Pickup the offset of the new IP fragment. */ + current_offset = current_header -> nx_ip_header_word_1 & NX_IP_OFFSET_MASK; + + /* Another packet fragment was found... find the proper place in the list + for this packet and check for complete re-assembly. */ + + /* Setup the previous pointer. Note that the search pointer still points + to the first fragment in the list. */ + previous_ptr = NX_NULL; + search_ptr = found_ptr; + + /* Loop to walk through the fragment list. */ + do + { + + /* Pickup a pointer to the IP header of the fragment. */ + search_header = (NX_IP_HEADER *)search_ptr -> nx_packet_prepend_ptr; + + /* Determine if the incoming IP fragment goes before this packet. */ + if (current_offset < (search_header -> nx_ip_header_word_1 & NX_IP_OFFSET_MASK)) + { + + /* Yes, break out of the loop and insert the current packet. */ + break; + } + + /* Otherwise, move the search and previous pointers to the next fragment in the + chain. */ + previous_ptr = search_ptr; + search_ptr = search_ptr -> nx_packet_fragment_next; + } while (search_ptr); + + /* At this point, the previous pointer determines where to place the new fragment. */ + if (previous_ptr) + { + + /* Add new fragment after the previous ptr. */ + current_fragment -> nx_packet_fragment_next = previous_ptr -> nx_packet_fragment_next; + previous_ptr -> nx_packet_fragment_next = current_fragment; + } + else + { + + /* This packet needs to be inserted at the front of the fragment chain. */ + current_fragment -> nx_packet_queue_next = fragment_head -> nx_packet_queue_next; + current_fragment -> nx_packet_fragment_next = fragment_head; + if (previous_fragment) + { + + /* We need to link up a different IP packet fragment chain that is in + front of this one on the re-assembly queue. */ + previous_fragment -> nx_packet_queue_next = current_fragment; + } + else + { + + /* Nothing prior to this IP fragment chain, we need to just change the + list header. */ + ip_ptr -> nx_ip_fragment_assembly_head = current_fragment; + + /* Clear the timeout fragment pointer. */ + ip_ptr -> nx_ip_timeout_fragment = NX_NULL; + } + + /* Determine if we need to adjust the tail pointer. */ + if (fragment_head == ip_ptr -> nx_ip_fragment_assembly_tail) + { + + /* Setup the new tail pointer. */ + ip_ptr -> nx_ip_fragment_assembly_tail = current_fragment; + } + + /* Setup the new fragment head. */ + fragment_head = current_fragment; + } + + /* At this point, the new IP fragment is in its proper place on the re-assembly + list. We now need to walk the list and determine if all the fragments are + present. */ + + /* Setup the search pointer to the fragment head. */ + search_ptr = fragment_head; + + /* Set the current expected offset to 0. */ + current_offset = 0; + + /* Loop through the packet chain to see if all the fragments have + arrived. */ + incomplete = 0; + do + { + + /* Build the IP header pointer. */ + search_header = (NX_IP_HEADER *)search_ptr -> nx_packet_prepend_ptr; + + /* Check for the expected current offset. */ + if (current_offset != (search_header -> nx_ip_header_word_1 & NX_IP_OFFSET_MASK)) + { + + /* There are still more fragments necessary to reassemble this packet + so just return. */ + incomplete = 1; + break; + } + + /* Calculate the next expected offset. */ + current_offset = current_offset + + ((search_header -> nx_ip_header_word_0 & NX_LOWER_16_MASK) - sizeof(NX_IP_HEADER)) / NX_IP_ALIGN_FRAGS; + + /* Move the search pointer forward to the next fragment. */ + search_ptr = search_ptr -> nx_packet_fragment_next; + } while (search_ptr); + + if (incomplete) + { + continue; + } + + /* At this point the search header points to the last fragment in the chain. In + order for the packet to be complete, the "more fragments" bit in its IP header + must be clear. */ + if (search_header -> nx_ip_header_word_1 & NX_IP_MORE_FRAGMENT) + { + + /* There are still more fragments necessary to re-assembly this packet + so just return. */ + continue; + } + + /* If we get here, the necessary fragments to reassemble the packet + are indeed available. We now need to loop through the packet and reassemble + it. */ + search_ptr = fragment_head -> nx_packet_fragment_next; + + /* Loop through the fragments and assemble the IP fragment. */ + while (search_ptr) + { + + /* Accumulate the new length into the head packet. */ + fragment_head -> nx_packet_length = fragment_head -> nx_packet_length + + search_ptr -> nx_packet_length - sizeof(NX_IP_HEADER); + + /* Position past the IP header in the subsequent packets. */ + search_ptr -> nx_packet_prepend_ptr = search_ptr -> nx_packet_prepend_ptr + + sizeof(NX_IP_HEADER); + + /* Link the addition fragment to the head fragment. */ + if (fragment_head -> nx_packet_last) + { + (fragment_head -> nx_packet_last) -> nx_packet_next = search_ptr; + } + else + { + fragment_head -> nx_packet_next = search_ptr; + } + if (search_ptr -> nx_packet_last) + { + fragment_head -> nx_packet_last = search_ptr -> nx_packet_last; + } + else + { + fragment_head -> nx_packet_last = search_ptr; + } + + /* Move to the next fragment in the chain. */ + search_ptr = search_ptr -> nx_packet_fragment_next; + } + + /* The packet is now reassembled under the fragment head pointer. It must now + be removed from the re-assembly list. */ + if (previous_fragment) + { + + /* Remove the fragment from a position other than the head of the assembly list. */ + previous_fragment -> nx_packet_queue_next = fragment_head -> nx_packet_queue_next; + } + else + { + + /* Modify the head of the re-assembly list. */ + ip_ptr -> nx_ip_fragment_assembly_head = fragment_head -> nx_packet_queue_next; + + /* Clear the timeout fragment pointer since we are removing the first + fragment (the oldest) on the assembly list. */ + ip_ptr -> nx_ip_timeout_fragment = NX_NULL; + } + + /* Determine if we need to adjust the tail pointer. */ + if (fragment_head == ip_ptr -> nx_ip_fragment_assembly_tail) + { + + /* Setup the new tail pointer. */ + ip_ptr -> nx_ip_fragment_assembly_tail = previous_fragment; + } + + /* We are now ready to dispatch this packet just like the normal IP receive packet + processing. */ + + /* Build a pointer to the IP header. */ + current_header = (NX_IP_HEADER *)fragment_head -> nx_packet_prepend_ptr; + + /* Determine what protocol the current IP datagram is. */ + protocol = current_header -> nx_ip_header_word_2 & NX_IP_PROTOCOL_MASK; + + /* Remove the IP header from the packet. */ + fragment_head -> nx_packet_prepend_ptr = fragment_head -> nx_packet_prepend_ptr + sizeof(NX_IP_HEADER); + + /* Adjust the length. */ + fragment_head -> nx_packet_length = fragment_head -> nx_packet_length - sizeof(NX_IP_HEADER); + +#ifndef NX_DISABLE_IP_INFO + + /* Increment the number of packets reassembled. */ + ip_ptr -> nx_ip_packets_reassembled++; + + /* Increment the number of packets delivered. */ + ip_ptr -> nx_ip_total_packets_delivered++; + + /* Increment the IP packet bytes received (not including the header). */ + ip_ptr -> nx_ip_total_bytes_received += fragment_head -> nx_packet_length; +#endif + + /* Determine if RAW IP is supported. */ + if (ip_ptr -> nx_ip_raw_ip_processing) + { + + /* Call the raw IP packet processing routine. */ + (ip_ptr -> nx_ip_raw_ip_processing)(ip_ptr, fragment_head); + } + + /* Dispatch the protocol... Have we found a UDP packet? */ + else if ((protocol == NX_IP_UDP) && (ip_ptr -> nx_ip_udp_packet_receive)) + { + + /* Yes, a UDP packet is present, dispatch to the appropriate UDP handler + if present. */ + (ip_ptr -> nx_ip_udp_packet_receive)(ip_ptr, fragment_head); + } + /* Is a TCP packet present? */ + else if ((protocol == NX_IP_TCP) && (ip_ptr -> nx_ip_tcp_packet_receive)) + { + + /* Yes, a TCP packet is present, dispatch to the appropriate TCP handler + if present. */ + (ip_ptr -> nx_ip_tcp_packet_receive)(ip_ptr, fragment_head); + } + /* Is a ICMP packet present? */ + else if ((protocol == NX_IP_ICMP) && (ip_ptr -> nx_ip_icmp_packet_receive)) + { + + /* Yes, a ICMP packet is present, dispatch to the appropriate ICMP handler + if present. */ + (ip_ptr -> nx_ip_icmp_packet_receive)(ip_ptr, fragment_head); + } + else if ((protocol == NX_IP_IGMP) && (ip_ptr -> nx_ip_igmp_packet_receive)) + { + + /* Yes, a IGMP packet is present, dispatch to the appropriate ICMP handler + if present. */ + (ip_ptr -> nx_ip_igmp_packet_receive)(ip_ptr, fragment_head); + } + else + { + +#ifndef NX_DISABLE_IP_INFO + + /* Decrement the number of packets delivered. */ + ip_ptr -> nx_ip_total_packets_delivered--; + + /* Decrement the IP packet bytes received (not including the header). */ + ip_ptr -> nx_ip_total_bytes_received -= fragment_head -> nx_packet_length; + + /* Increment the IP unknown protocol count. */ + ip_ptr -> nx_ip_unknown_protocols_received++; + + /* Increment the IP receive packets dropped count. */ + ip_ptr -> nx_ip_receive_packets_dropped++; +#endif + + /* Toss the IP packet since we don't know what to do with it! */ + _nx_packet_release(fragment_head); + } + } + else + { + + /* No other packet was found on the re-assembly list so this packet must be the + first one of a new IP packet. Just add it to the end of the assembly queue. */ + if (ip_ptr -> nx_ip_fragment_assembly_head) + { + + /* Re-assembly list is not empty. Just place this IP packet at the + end of the IP fragment assembly list. */ + ip_ptr -> nx_ip_fragment_assembly_tail -> nx_packet_queue_next = current_fragment; + ip_ptr -> nx_ip_fragment_assembly_tail = current_fragment; + current_fragment -> nx_packet_queue_next = NX_NULL; + current_fragment -> nx_packet_fragment_next = NX_NULL; + } + else + { + + /* First IP fragment on the assembly list. Setup the head and tail pointers to + this packet. */ + ip_ptr -> nx_ip_fragment_assembly_head = current_fragment; + ip_ptr -> nx_ip_fragment_assembly_tail = current_fragment; + current_fragment -> nx_packet_queue_next = NX_NULL; + current_fragment -> nx_packet_fragment_next = NX_NULL; + } + } + } +} + diff --git a/common/src/nx_ip_fragment_disable.c b/common/src/nx_ip_fragment_disable.c new file mode 100644 index 0000000..1aba42b --- /dev/null +++ b/common/src/nx_ip_fragment_disable.c @@ -0,0 +1,157 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_packet.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ip_fragment_disable PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function disables IP fragment assembly processing and releases */ +/* all partial fragments being assembled. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP instance */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_packet_release Release packet */ +/* tx_mutex_get Get protection mutex */ +/* tx_mutex_put Put protection mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ip_fragment_disable(NX_IP *ip_ptr) +{ + +TX_INTERRUPT_SAVE_AREA + +NX_PACKET *new_fragment_head; +NX_PACKET *assemble_head; +NX_PACKET *next_packet; +NX_PACKET *release_packet; + + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_IP_FRAGMENT_DISABLE, ip_ptr, 0, 0, 0, NX_TRACE_IP_EVENTS, 0, 0) + + /* Get mutex protection. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Disable interrupts temporarily. */ + TX_DISABLE + + /* Clear the IP fragment processing routine pointer. */ + ip_ptr -> nx_ip_fragment_processing = NX_NULL; + + /* Clear the IP fragment assembly routine pointer. */ + ip_ptr -> nx_ip_fragment_assembly = NX_NULL; + + /* Clear the IP fragment timeout routine pointer. */ + ip_ptr -> nx_ip_fragment_timeout_check = NX_NULL; + + /* Pickup the fragment list pointer. */ + new_fragment_head = ip_ptr -> nx_ip_received_fragment_head; + assemble_head = ip_ptr -> nx_ip_fragment_assembly_head; + + /* Clear the IP structure lists. */ + ip_ptr -> nx_ip_received_fragment_head = NX_NULL; + ip_ptr -> nx_ip_received_fragment_tail = NX_NULL; + ip_ptr -> nx_ip_fragment_assembly_head = NX_NULL; + ip_ptr -> nx_ip_fragment_assembly_tail = NX_NULL; + + /* Restore interrupts. */ + TX_RESTORE + + /* Release mutex protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Now walk through the receive and assembly lists to free the packets. */ + next_packet = new_fragment_head; + while (next_packet) + { + + /* Set the release packet to this packet. */ + release_packet = next_packet; + + /* Move next packet to the next in the list. */ + next_packet = next_packet -> nx_packet_queue_next; + + /* Release the current packet. */ + _nx_packet_release(release_packet); + } + + /* Now walk through the assemble list and release all packets. */ + while (assemble_head) + { + + /* Walk through the list of packets being assembled for this packet and release them. */ + next_packet = assemble_head; + assemble_head = next_packet -> nx_packet_queue_next; + while (next_packet) + { + + /* Set the release packet to this packet. */ + release_packet = next_packet; + + /* Move next packet to the next in the list. */ + next_packet = next_packet -> nx_packet_fragment_next; + + /* Release the current packet. */ + _nx_packet_release(release_packet); + } + } + + /* Return success to the caller. */ + return(NX_SUCCESS); +} + diff --git a/common/src/nx_ip_fragment_enable.c b/common/src/nx_ip_fragment_enable.c new file mode 100644 index 0000000..1d5f1d5 --- /dev/null +++ b/common/src/nx_ip_fragment_enable.c @@ -0,0 +1,98 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ip_fragment_enable PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function enables the IP fragment processing by setting up the */ +/* function pointers responsible for fragmenting and unfragmenting IP */ +/* packets. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP instance */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ip_fragment_enable(NX_IP *ip_ptr) +{ + +TX_INTERRUPT_SAVE_AREA + + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_IP_FRAGMENT_ENABLE, ip_ptr, 0, 0, 0, NX_TRACE_IP_EVENTS, 0, 0) + + /* Disable interrupts temporarily. */ + TX_DISABLE + + /* Setup the IP fragment processing routine pointer. */ + ip_ptr -> nx_ip_fragment_processing = _nx_ip_fragment_packet; + + /* Setup the IP fragment assembly routine pointer. */ + ip_ptr -> nx_ip_fragment_assembly = _nx_ip_fragment_assembly; + + /* Setup the IP fragment timeout routine pointer. */ + ip_ptr -> nx_ip_fragment_timeout_check = _nx_ip_fragment_timeout_check; + + /* Restore interrupts. */ + TX_RESTORE + + /* Return success to the caller. */ + return(NX_SUCCESS); +} + diff --git a/common/src/nx_ip_fragment_packet.c b/common/src/nx_ip_fragment_packet.c new file mode 100644 index 0000000..7b7e607 --- /dev/null +++ b/common/src/nx_ip_fragment_packet.c @@ -0,0 +1,351 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_packet.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ip_fragment_packet PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function breaks the supplied packet into fragments and sends */ +/* them out through the associated IP driver. This function uses the */ +/* already built IP header and driver request structure for each */ +/* packet fragment. */ +/* */ +/* INPUT */ +/* */ +/* driver_req_ptr Pointer to driver request */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_packet_allocate Allocate packet for fragment */ +/* _nx_packet_transmit_release Transmit packet release */ +/* (ip_link_driver) User supplied link driver */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_arp_packet_receive Received ARP packet processing*/ +/* _nx_ip_packet_send Send an IP packet */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_ip_fragment_packet(struct NX_IP_DRIVER_STRUCT *driver_req_ptr) +{ + +UINT status; +#ifndef NX_DISABLE_IP_TX_CHECKSUM +ULONG checksum; +ULONG temp; +#endif /* NX_DISABLE_IP_TX_CHECKSUM */ +UCHAR *source_ptr; +ULONG remaining_bytes; +ULONG fragment_size; +ULONG copy_size; +ULONG copy_remaining_size; +ULONG fragment_offset = 0; +NX_IP_DRIVER driver_request; +NX_PACKET *source_packet; +NX_PACKET *fragment_packet; +NX_IP_HEADER *source_header_ptr; +NX_IP_HEADER *fragment_header_ptr; +NX_IP *ip_ptr; + + + /* Setup the local driver request packet that will be used for each + fragment. There will be a unique packet pointer for each request, but + otherwise all the other fields will remain constant. */ + driver_request = *driver_req_ptr; + + /* Setup the IP pointer. */ + ip_ptr = driver_req_ptr -> nx_ip_driver_ptr; + +#ifndef NX_DISABLE_IP_INFO + + /* Increment the total number of fragment requests. */ + ip_ptr -> nx_ip_total_fragment_requests++; +#endif + + /* Pickup the source packet pointer. */ + source_packet = driver_req_ptr -> nx_ip_driver_packet; + + /* Build a pointer to the source IP header. */ + source_header_ptr = (NX_IP_HEADER *)source_packet -> nx_packet_prepend_ptr; + + /* Endian swapping logic. If NX_LITTLE_ENDIAN is specified, these macros will + swap the endian of the IP header. */ + NX_CHANGE_ULONG_ENDIAN(source_header_ptr -> nx_ip_header_word_0); + NX_CHANGE_ULONG_ENDIAN(source_header_ptr -> nx_ip_header_word_1); + NX_CHANGE_ULONG_ENDIAN(source_header_ptr -> nx_ip_header_word_2); + NX_CHANGE_ULONG_ENDIAN(source_header_ptr -> nx_ip_header_source_ip); + NX_CHANGE_ULONG_ENDIAN(source_header_ptr -> nx_ip_header_destination_ip); + + /* Pickup the length of the packet and the starting pointer. */ + remaining_bytes = source_packet -> nx_packet_length - sizeof(NX_IP_HEADER); + source_ptr = source_packet -> nx_packet_prepend_ptr + sizeof(NX_IP_HEADER); + + /* Derive the fragment size. */ + fragment_size = source_packet -> nx_packet_ip_interface -> nx_interface_ip_mtu_size - sizeof(NX_IP_HEADER); + fragment_size = (fragment_size / NX_IP_ALIGN_FRAGS) * NX_IP_ALIGN_FRAGS; + + /* Loop to break the source packet into fragments and send each out through + the associated driver. */ + while (remaining_bytes) + { + /* Allocate a packet from the default packet pool. */ + status = _nx_packet_allocate(ip_ptr -> nx_ip_default_packet_pool, &fragment_packet, NX_IP_PACKET, TX_NO_WAIT); + + /* Determine if there is a packet available. */ + if (status) + { + +#ifndef NX_DISABLE_IP_INFO + + /* Increment the fragment failure count. */ + ip_ptr -> nx_ip_fragment_failures++; + + /* 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 + + /* Error, not enough packets to perform the fragmentation... release the + source packet and return. */ + _nx_packet_transmit_release(driver_req_ptr -> nx_ip_driver_packet); + return; + } + + /* Set the proper interface. */ + fragment_packet -> nx_packet_ip_interface = driver_req_ptr -> nx_ip_driver_packet -> nx_packet_ip_interface; + + /* Calculate the size of this fragment. */ + if (remaining_bytes > fragment_size) + { + copy_remaining_size = fragment_size; + remaining_bytes -= fragment_size; + } + else + { + copy_remaining_size = remaining_bytes; + remaining_bytes = 0; + } + + /* Copy data. */ + while (copy_remaining_size) + { + + /* We need to copy the remaining bytes into the new packet and then move to the next + packet. */ + if (copy_remaining_size > (ULONG)(source_packet -> nx_packet_append_ptr - source_ptr)) + { + copy_size = (ULONG)(source_packet -> nx_packet_append_ptr - source_ptr); + } + else + { + copy_size = copy_remaining_size; + } + + status = _nx_packet_data_append(fragment_packet, source_ptr, copy_size, ip_ptr -> nx_ip_default_packet_pool, NX_NO_WAIT); + + /* Determine if there is a packet available. */ + if (status) + { + +#ifndef NX_DISABLE_IP_INFO + + /* Increment the fragment failure count. */ + ip_ptr -> nx_ip_fragment_failures++; + + /* 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 + + /* Error, not enough packets to perform the fragmentation... release the + source packet and return. */ + _nx_packet_transmit_release(driver_req_ptr -> nx_ip_driver_packet); + _nx_packet_release(fragment_packet); + return; + } + + /* Reduce the remaining size. */ + copy_remaining_size -= copy_size; + + if (copy_size == (UINT)(source_packet -> nx_packet_append_ptr - source_ptr)) + { + + /* Move to the next physical packet in the source message. */ + /* Determine if there is a next packet. */ + if (source_packet -> nx_packet_next) + { + + /* Move to the next physical packet in the source message. */ + source_packet = source_packet -> nx_packet_next; + + /* Setup new source pointer. */ + source_ptr = source_packet -> nx_packet_prepend_ptr; + } + else if (remaining_bytes) + { + + /* Error, no next packet but current packet is exhausted and there are + remaining bytes. */ + +#ifndef NX_DISABLE_IP_INFO + + /* Increment the invalid transmit packet count. */ + ip_ptr -> nx_ip_invalid_transmit_packets++; + + /* Increment the fragment failures count. */ + ip_ptr -> nx_ip_fragment_failures++; +#endif + + /* Error, not enough packets to perform the fragmentation... release the + source packet and return. */ + _nx_packet_transmit_release(driver_req_ptr -> nx_ip_driver_packet); + _nx_packet_release(fragment_packet); + return; + } + } + else + { + + /* Copy finished. */ + source_ptr += copy_size; + } + } + + /* Setup the fragment packet pointers. */ + fragment_packet -> nx_packet_prepend_ptr = fragment_packet -> nx_packet_prepend_ptr - sizeof(NX_IP_HEADER); + fragment_packet -> nx_packet_length += sizeof(NX_IP_HEADER); + + /* Setup the fragment's IP header. */ + fragment_header_ptr = (NX_IP_HEADER *)fragment_packet -> nx_packet_prepend_ptr; + + /* Setup the new IP header. */ + fragment_header_ptr -> nx_ip_header_word_0 = (source_header_ptr -> nx_ip_header_word_0 & ~NX_LOWER_16_MASK) | fragment_packet -> nx_packet_length; + fragment_header_ptr -> nx_ip_header_word_1 = source_header_ptr -> nx_ip_header_word_1 | (fragment_offset / 8); + fragment_header_ptr -> nx_ip_header_word_2 = source_header_ptr -> nx_ip_header_word_2 & ~NX_LOWER_16_MASK; + fragment_header_ptr -> nx_ip_header_source_ip = source_header_ptr -> nx_ip_header_source_ip; + fragment_header_ptr -> nx_ip_header_destination_ip = source_header_ptr -> nx_ip_header_destination_ip; + + /* Determine if this is the last fragment. */ + if (remaining_bytes) + { + + /* Not the last fragment, so set the more fragments bit. */ + fragment_header_ptr -> nx_ip_header_word_1 = fragment_header_ptr -> nx_ip_header_word_1 | NX_IP_MORE_FRAGMENT; + } + +#ifndef NX_DISABLE_IP_TX_CHECKSUM + + /* Build the IP checksum for this fragment. */ + temp = fragment_header_ptr -> nx_ip_header_word_0; + checksum = (temp >> NX_SHIFT_BY_16) + (temp & NX_LOWER_16_MASK); + temp = fragment_header_ptr -> nx_ip_header_word_1; + checksum += (temp >> NX_SHIFT_BY_16) + (temp & NX_LOWER_16_MASK); + temp = fragment_header_ptr -> nx_ip_header_word_2; + checksum += (temp >> NX_SHIFT_BY_16); + temp = fragment_header_ptr -> nx_ip_header_source_ip; + checksum += (temp >> NX_SHIFT_BY_16) + (temp & NX_LOWER_16_MASK); + temp = fragment_header_ptr -> nx_ip_header_destination_ip; + checksum += (temp >> NX_SHIFT_BY_16) + (temp & NX_LOWER_16_MASK); + + /* Add in the carry bits into the checksum. */ + checksum = (checksum >> NX_SHIFT_BY_16) + (checksum & NX_LOWER_16_MASK); + + /* Do it again in case previous operation generates an overflow. */ + checksum = (checksum >> NX_SHIFT_BY_16) + (checksum & NX_LOWER_16_MASK); + + /* Now store the checksum in the IP fragment header. */ + fragment_header_ptr -> nx_ip_header_word_2 = fragment_header_ptr -> nx_ip_header_word_2 | (NX_LOWER_16_MASK & (~checksum)); +#endif /* NX_DISABLE_IP_TX_CHECKSUM */ + + /* Endian swapping logic. If NX_LITTLE_ENDIAN is specified, these macros will + swap the endian of the IP header. */ + NX_CHANGE_ULONG_ENDIAN(fragment_header_ptr -> nx_ip_header_word_0); + NX_CHANGE_ULONG_ENDIAN(fragment_header_ptr -> nx_ip_header_word_1); + NX_CHANGE_ULONG_ENDIAN(fragment_header_ptr -> nx_ip_header_word_2); + NX_CHANGE_ULONG_ENDIAN(fragment_header_ptr -> nx_ip_header_source_ip); + NX_CHANGE_ULONG_ENDIAN(fragment_header_ptr -> nx_ip_header_destination_ip); + +#ifndef NX_DISABLE_IP_INFO + /* Increment the IP fragments sent count. */ + ip_ptr -> nx_ip_total_fragments_sent++; + + /* 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 += fragment_packet -> nx_packet_length - sizeof(NX_IP_HEADER); +#endif + + /* Send the packet to the associated driver for output. */ + driver_request.nx_ip_driver_packet = fragment_packet; + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_IO_DRIVER_PACKET_SEND, ip_ptr, fragment_packet, fragment_packet -> nx_packet_length, 0, NX_TRACE_INTERNAL_EVENTS, 0, 0); + + (fragment_packet -> nx_packet_ip_interface -> nx_interface_link_driver_entry)(&driver_request); + + /* Increase offset. */ + fragment_offset += fragment_size; + } + +#ifndef NX_DISABLE_IP_INFO + + /* Increment the total number of successful fragment requests. */ + ip_ptr -> nx_ip_successful_fragment_requests++; +#endif + + /* The original packet has been sent out in fragments... release it! */ + _nx_packet_transmit_release(driver_req_ptr -> nx_ip_driver_packet); +} + diff --git a/common/src/nx_ip_fragment_timeout_check.c b/common/src/nx_ip_fragment_timeout_check.c new file mode 100644 index 0000000..27fb5b8 --- /dev/null +++ b/common/src/nx_ip_fragment_timeout_check.c @@ -0,0 +1,136 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_packet.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ip_fragment_timeout_check PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for timeout conditions on the first fragment */ +/* in the IP re-assembly list. If the head pointer is the same */ +/* between execution of this routine the head fragment is deleted and */ +/* its packets are released. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP instance */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_packet_release Release packet */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_ip_fragment_timeout_check(NX_IP *ip_ptr) +{ + +NX_PACKET *fragment; +NX_PACKET *next_fragment; + + + /* Determine if the head packet is still there. */ + if ((ip_ptr -> nx_ip_timeout_fragment) && + (ip_ptr -> nx_ip_timeout_fragment == ip_ptr -> nx_ip_fragment_assembly_head)) + { + + /* Save the head fragment pointer. */ + fragment = ip_ptr -> nx_ip_fragment_assembly_head; + + /* Yes, we need to remove this fragment from the assembly queue and release it. */ + ip_ptr -> nx_ip_fragment_assembly_head = fragment -> nx_packet_queue_next; + + /* Determine if we need to modify the fragment assembly tail pointer. */ + if (ip_ptr -> nx_ip_fragment_assembly_tail == fragment) + { + + /* If the tail pointer is the same, then the list is really empty now so + just set the tail pointer to NULL. */ + ip_ptr -> nx_ip_fragment_assembly_tail = NX_NULL; + } + +#ifndef NX_DISABLE_IP_INFO + + /* Increment the re-assembly failures count. */ + ip_ptr -> nx_ip_reassembly_failures++; +#endif + + /* Walk the chain of fragments for this fragment re-assembly. */ + do + { + +#ifndef NX_DISABLE_IP_INFO + + /* Increment the IP receive packets dropped count. */ + ip_ptr -> nx_ip_receive_packets_dropped++; +#endif + + /* Pickup the next fragment. */ + next_fragment = fragment -> nx_packet_fragment_next; + + /* Release this fragment. */ + _nx_packet_release(fragment); + + /* Reassign the fragment pointer. */ + fragment = next_fragment; + } while (fragment); + + /* Set the timeout fragment head to NULL so the next fragment gets a full timeout. */ + ip_ptr -> nx_ip_timeout_fragment = NX_NULL; + } + else + { + + /* Assign the fragment head to the timeout pointer. */ + ip_ptr -> nx_ip_timeout_fragment = ip_ptr -> nx_ip_fragment_assembly_head; + } +} + diff --git a/common/src/nx_ip_gateway_address_set.c b/common/src/nx_ip_gateway_address_set.c new file mode 100644 index 0000000..005c361 --- /dev/null +++ b/common/src/nx_ip_gateway_address_set.c @@ -0,0 +1,161 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_arp.h" +#include "nx_ip.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ip_gateway_address_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function finds the correct interface for the supplied ip */ +/* address and applies that interface and the supplied gateway address */ +/* as the IP task gateway for sending IP packets with addresses not in */ +/* the local network. */ +/* */ +/* Note 1: if the gateway address is zero, the IP gateway address and */ +/* gateway interface pointer are set to null. */ +/* */ +/* Note 2: For a gateway address is non zero, the IP gateway address */ +/* and gateway interface pointer must be non null, or this function */ +/* will return an error status. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP control block pointer */ +/* ip_address Gateway IP address */ +/* */ +/* 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_ip_gateway_address_set(NX_IP *ip_ptr, ULONG ip_address) +{ + +int i; +TX_INTERRUPT_SAVE_AREA +NX_INTERFACE *nx_ip_interface = NX_NULL; + + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_IP_GATEWAY_ADDRESS_SET, ip_ptr, ip_address, 0, 0, NX_TRACE_IP_EVENTS, 0, 0) + + /* Obtain the IP internal mutex so the Gateway IP address can be setup. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Determine if the caller is trying to clear the IP gateway. */ + if (ip_address == 0x0) + { + + /* They are. Ok to clear gateway and gateway interface. */ + + /* Disable interrupts. */ + TX_DISABLE + + ip_ptr -> nx_ip_gateway_address = 0x0; + ip_ptr -> nx_ip_gateway_interface = NX_NULL; + + /* Restore interrupts. */ + TX_RESTORE + + /* Unlock the mutex, and return success status. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + return(NX_SUCCESS); + } + + /* Loop through all the interfaces to find the one for the input gateway address. */ + for (i = 0; i < NX_MAX_IP_INTERFACES; i++) + { + + /* Must be a valid interface. Match the network subnet of the interface and input address. */ + if ((ip_ptr -> nx_ip_interface[i].nx_interface_valid) && + ((ip_address & (ip_ptr -> nx_ip_interface[i].nx_interface_ip_network_mask)) == + ip_ptr -> nx_ip_interface[i].nx_interface_ip_network)) + { + + /* This is the interface for the gateway. */ + nx_ip_interface = &(ip_ptr -> nx_ip_interface[i]); + + /* Break out of the search. */ + break; + } + } + + /* Check if we found an interface. */ + if (nx_ip_interface == NX_NULL) + { + + /* None found. Unlock the mutex, and return the error status. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + return(NX_IP_ADDRESS_ERROR); + } + + /* Disable interrupts. */ + TX_DISABLE + + /* Setup the gateway address and interface for the IP task. */ + ip_ptr -> nx_ip_gateway_address = ip_address; + ip_ptr -> nx_ip_gateway_interface = nx_ip_interface; + + /* Restore interrupts. */ + TX_RESTORE + + /* Release the protection mutex. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return completion status. */ + return(NX_SUCCESS); +} + diff --git a/common/src/nx_ip_info_get.c b/common/src/nx_ip_info_get.c new file mode 100644 index 0000000..da3ca68 --- /dev/null +++ b/common/src/nx_ip_info_get.c @@ -0,0 +1,190 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ip_info_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves information about the specified IP */ +/* instance. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP instance */ +/* ip_total_packets_sent Destination for number of */ +/* packets sent */ +/* ip_total_bytes_sent Destination for number of */ +/* bytes sent */ +/* ip_total_packets_received Destination for number of */ +/* packets received */ +/* ip_total_bytes_received Destination for number of */ +/* bytes received */ +/* ip_invalid_packets Destination for number of */ +/* invalid packets */ +/* ip_receive_packets_dropped Destination for number of */ +/* packets dropped */ +/* ip_receive_checksum_errors Destination for number of */ +/* checksum errors */ +/* ip_send_packets_dropped Destination for number of */ +/* send packets dropped */ +/* ip_total_fragments_sent Destination for number of */ +/* fragments sent */ +/* ip_total_fragments_received Destination for number of */ +/* fragments received */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Obtain 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_ip_info_get(NX_IP *ip_ptr, ULONG *ip_total_packets_sent, ULONG *ip_total_bytes_sent, + ULONG *ip_total_packets_received, ULONG *ip_total_bytes_received, + ULONG *ip_invalid_packets, ULONG *ip_receive_packets_dropped, + ULONG *ip_receive_checksum_errors, ULONG *ip_send_packets_dropped, + ULONG *ip_total_fragments_sent, ULONG *ip_total_fragments_received) +{ + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_IP_INFO_GET, ip_ptr, ip_ptr -> nx_ip_total_bytes_sent, ip_ptr -> nx_ip_total_bytes_received, ip_ptr -> nx_ip_receive_packets_dropped, NX_TRACE_IP_EVENTS, 0, 0) + + /* Obtain protection on this IP instance. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Determine if IP total packets sent is wanted. */ + if (ip_total_packets_sent) + { + + /* Return the number of IP total packets sent by this IP instance. */ + *ip_total_packets_sent = ip_ptr -> nx_ip_total_packets_sent; + } + + /* Determine if IP total bytes sent is wanted. */ + if (ip_total_bytes_sent) + { + + /* Return the number of IP total bytes sent by this IP instance. */ + *ip_total_bytes_sent = ip_ptr -> nx_ip_total_bytes_sent; + } + + /* Determine if IP total packets received is wanted. */ + if (ip_total_packets_received) + { + + /* Return the number of IP total packets received by this IP instance. */ + *ip_total_packets_received = ip_ptr -> nx_ip_total_packets_received; + } + + /* Determine if IP total bytes received is wanted. */ + if (ip_total_bytes_received) + { + + /* Return the number of IP total bytes received by this IP instance. */ + *ip_total_bytes_received = ip_ptr -> nx_ip_total_bytes_received; + } + + /* Determine if IP invalid packets is wanted. */ + if (ip_invalid_packets) + { + + /* Return the number of IP invalid packets received by this IP instance. */ + *ip_invalid_packets = ip_ptr -> nx_ip_invalid_packets; + } + + /* Determine if IP receive packets dropped is wanted. */ + if (ip_receive_packets_dropped) + { + + /* Return the number of IP receive packets dropped by this IP instance. */ + *ip_receive_packets_dropped = ip_ptr -> nx_ip_receive_packets_dropped; + } + + /* Determine if IP receive checksum errors is wanted. */ + if (ip_receive_checksum_errors) + { + + /* Return the number of IP receive checksum errors by this IP instance. */ + *ip_receive_checksum_errors = ip_ptr -> nx_ip_receive_checksum_errors; + } + + /* Determine if IP send packets dropped is wanted. */ + if (ip_send_packets_dropped) + { + + /* Return the number of IP send packets dropped by this IP instance. */ + *ip_send_packets_dropped = ip_ptr -> nx_ip_send_packets_dropped; + } + + /* Determine if IP total fragments sent is wanted. */ + if (ip_total_fragments_sent) + { + + /* Return the number of IP total fragments sent by this IP instance. */ + *ip_total_fragments_sent = ip_ptr -> nx_ip_total_fragments_sent; + } + + /* Determine if IP total fragments received is wanted. */ + if (ip_total_fragments_received) + { + + /* Return the number of IP total fragments received by this IP instance. */ + *ip_total_fragments_received = ip_ptr -> nx_ip_total_fragments_received; + } + + /* Release the protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return success to the caller. */ + return(NX_SUCCESS); +} + diff --git a/common/src/nx_ip_initialize.c b/common/src/nx_ip_initialize.c new file mode 100644 index 0000000..be183b0 --- /dev/null +++ b/common/src/nx_ip_initialize.c @@ -0,0 +1,83 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Locate NetX IP data in this file. */ + +#define NX_IP_INIT + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_packet.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ip_initialize PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function initializes the various control data structures for */ +/* the Internet Protocol component. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_system_initialize System initialization */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_ip_initialize(VOID) +{ + + /* Initialize the created IP instance variables. */ + _nx_ip_created_ptr = NX_NULL; + _nx_ip_created_count = 0; +} + diff --git a/common/src/nx_ip_interface_address_get.c b/common/src/nx_ip_interface_address_get.c new file mode 100644 index 0000000..3e7e026 --- /dev/null +++ b/common/src/nx_ip_interface_address_get.c @@ -0,0 +1,107 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ip_interface_address_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves the IP address and the network mask and */ +/* returns them to the caller. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP control block pointer */ +/* interface_index IP Interface Index */ +/* ip_address Pointer to interface IP address */ +/* network_mask Pointer to interface network mask */ +/* */ +/* 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_ip_interface_address_get(NX_IP *ip_ptr, ULONG interface_index, ULONG *ip_address, ULONG *network_mask) +{ +TX_INTERRUPT_SAVE_AREA + + + /* Check for valid interface ID */ + if (interface_index >= NX_MAX_PHYSICAL_INTERFACES) + { + return(NX_INVALID_INTERFACE); + } + + /* Check for interface being valid. */ + if (!ip_ptr -> nx_ip_interface[interface_index].nx_interface_valid) + { + return(NX_INVALID_INTERFACE); + } + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_IP_ADDRESS_GET, ip_ptr, ip_ptr -> nx_ip_interface[interface_index].nx_interface_ip_address, + ip_ptr -> nx_ip_interface[interface_index].nx_interface_ip_network_mask, 0, NX_TRACE_IP_EVENTS, 0, 0) + + /* Disable interrupts. */ + TX_DISABLE + + /* Pickup the IP address and the network mask. */ + *ip_address = ip_ptr -> nx_ip_interface[interface_index].nx_interface_ip_address; + *network_mask = ip_ptr -> nx_ip_interface[interface_index].nx_interface_ip_network_mask; + + /* Restore interrupts. */ + TX_RESTORE + + /* Return completion status. */ + return(NX_SUCCESS); +} + diff --git a/common/src/nx_ip_interface_address_set.c b/common/src/nx_ip_interface_address_set.c new file mode 100644 index 0000000..c22f8a5 --- /dev/null +++ b/common/src/nx_ip_interface_address_set.c @@ -0,0 +1,141 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "tx_thread.h" +#include "nx_ip.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ip_interface_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets the IP address and the network mask for the */ +/* supplied IP instance. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP control block pointer */ +/* interface_index IP Interface Index */ +/* ip_address IP address */ +/* network_mask Network mask */ +/* */ +/* 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_ip_interface_address_set(NX_IP *ip_ptr, ULONG interface_index, ULONG ip_address, ULONG network_mask) +{ + +TX_INTERRUPT_SAVE_AREA + +VOID (*address_change_notify)(NX_IP *, VOID *); +VOID *additional_info; +ULONG previous_ip_address; +ULONG previous_network_mask; + + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_IP_ADDRESS_SET, ip_ptr, ip_address, network_mask, 0, NX_TRACE_IP_EVENTS, 0, 0) + + + /* Check for valid interface ID */ + if (interface_index >= NX_MAX_PHYSICAL_INTERFACES) + { + return(NX_INVALID_INTERFACE); + } + + /* Check for interface being valid. */ + if (!ip_ptr -> nx_ip_interface[interface_index].nx_interface_valid) + { + return(NX_INVALID_INTERFACE); + } + + + /* Disable interrupts. */ + TX_DISABLE + + /* Save previous IP address and network mask. */ + previous_ip_address = ip_ptr -> nx_ip_interface[interface_index].nx_interface_ip_address; + previous_network_mask = ip_ptr -> nx_ip_interface[interface_index].nx_interface_ip_network_mask; + + /* Pickup the current notification callback and additional information pointers. */ + address_change_notify = ip_ptr -> nx_ip_address_change_notify; + additional_info = ip_ptr -> nx_ip_address_change_notify_additional_info; + + /* Setup the IP address and the network mask. */ + ip_ptr -> nx_ip_interface[interface_index].nx_interface_ip_address = ip_address; + ip_ptr -> nx_ip_interface[interface_index].nx_interface_ip_network_mask = network_mask; + ip_ptr -> nx_ip_interface[interface_index].nx_interface_ip_network = ip_address & network_mask; + + /* Ensure the RARP function is disabled. */ + ip_ptr -> nx_ip_rarp_periodic_update = NX_NULL; + ip_ptr -> nx_ip_rarp_queue_process = NX_NULL; + + /* Restore interrupts. */ + TX_RESTORE + + /* Determine if the application should be notified of the IP address and/or + network mask change. */ + if ((address_change_notify) && + ((ip_address != previous_ip_address) || (network_mask != previous_network_mask))) + { + + /* Yes, call the application's IP address change notify function. */ + (address_change_notify)(ip_ptr, additional_info); + } + + /* Initialize the ARP defend timeout. */ + ip_ptr -> nx_ip_interface[interface_index].nx_interface_arp_defend_timeout = 0; + + /* Return completion status. */ + return(NX_SUCCESS); +} + diff --git a/common/src/nx_ip_interface_attach.c b/common/src/nx_ip_interface_attach.c new file mode 100644 index 0000000..ea8c378 --- /dev/null +++ b/common/src/nx_ip_interface_attach.c @@ -0,0 +1,176 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" + + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ip_interface_attach PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function attaches a physical network interface to the IP */ +/* instance, initializes and enables the driver. */ +/* */ +/* Note that the priority of this function is determined by the IP */ +/* create service. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr_value Pointer to IP control block */ +/* interface_name Name of this interface */ +/* ip_address IP Address, in host byte order*/ +/* network_mask Network Mask, in host byte */ +/* order */ +/* ip_link_driver User supplied link driver */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Obtain protection mutex */ +/* tx_mutex_put Release protection mutex */ +/* (ip_link_driver) User supplied link driver */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ip_interface_attach(NX_IP *ip_ptr, CHAR *interface_name, ULONG ip_address, ULONG network_mask, VOID (*ip_link_driver)(struct NX_IP_DRIVER_STRUCT *)) +{ + +int i; +NX_INTERFACE *nx_interface = NX_NULL; +NX_IP_DRIVER driver_request; + + + /* This function must be called within the system initialization + after nx_ip_create, before nx ip thread runs. */ + for (i = 0; i < NX_MAX_PHYSICAL_INTERFACES; i++) + { + + nx_interface = &(ip_ptr -> nx_ip_interface[i]); + + if (!(nx_interface -> nx_interface_valid)) + { + /* Find a valid entry. */ + break; + } + } + + if ((nx_interface == NX_NULL) || (i == NX_MAX_PHYSICAL_INTERFACES)) + { + /* No more free entry. return. */ + return(NX_NO_MORE_ENTRIES); + } + + /* Obtain the IP internal mutex before calling the driver. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Mark the entry as valid. */ + nx_interface -> nx_interface_valid = NX_TRUE; + + /* Fill in the interface information. */ + nx_interface -> nx_interface_ip_address = ip_address; + nx_interface -> nx_interface_ip_network_mask = network_mask; + nx_interface -> nx_interface_ip_network = ip_address & network_mask; + nx_interface -> nx_interface_link_driver_entry = ip_link_driver; + nx_interface -> nx_interface_ip_instance = ip_ptr; + + nx_interface -> nx_interface_name = interface_name; + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_IP_INTERFACE_ATTACH, ip_ptr, ip_address, i, 0, NX_TRACE_IP_EVENTS, 0, 0) + + /* If the IP thread is already running, this service needs to go through the rest of the initializeation process. */ + if (ip_ptr -> nx_ip_initialize_done == NX_TRUE) + { + + /* First 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 = &(ip_ptr -> nx_ip_interface[i]); + (ip_ptr -> nx_ip_interface[i].nx_interface_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; + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_IO_DRIVER_INITIALIZE, ip_ptr, 0, 0, 0, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + /* + When an IP instance is created, the first interface (nx_ip_interface[0]) is configured using parameters + provided in the IP create call. + + When IP thread runs, it invokes the 1st interface link driver for link initialization. + */ + (ip_ptr -> nx_ip_interface[i].nx_interface_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; + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_IO_DRIVER_LINK_ENABLE, ip_ptr, 0, 0, 0, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + (ip_ptr -> nx_ip_interface[i].nx_interface_link_driver_entry) (&driver_request); + } + + /* Release the IP internal mutex. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + + /* All done. Return. */ + return(NX_SUCCESS); +} + diff --git a/common/src/nx_ip_interface_info_get.c b/common/src/nx_ip_interface_info_get.c new file mode 100644 index 0000000..8d3fb91 --- /dev/null +++ b/common/src/nx_ip_interface_info_get.c @@ -0,0 +1,133 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ip_interface_info_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves information related to a specified */ +/* interface */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP control block pointer */ +/* interface_index Interface ID to query. */ +/* interface_name Name of the interface */ +/* ip_address Pointer to Interface IP address */ +/* in host byte order */ +/* network_mask Pointer to network mask */ +/* destination, in host byte order */ +/* mtu_size Pointer to storage space for MTU */ +/* physical_address_msw Pointer to storage space for */ +/* device phsyical address, MSW */ +/* physical_address_lsw Pointer to storage space for */ +/* device phsyical address, LSW */ +/* */ +/* 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_ip_interface_info_get(NX_IP *ip_ptr, UINT interface_index, CHAR **interface_name, + ULONG *ip_address, ULONG *network_mask, ULONG *mtu_size, + ULONG *physical_address_msw, ULONG *physical_address_lsw) +{ +NX_INTERFACE *nx_interface; + + nx_interface = &(ip_ptr -> nx_ip_interface[interface_index]); + + if (!nx_interface -> nx_interface_valid) + { + return(NX_INVALID_INTERFACE); + } + + if (interface_name) + { + *interface_name = nx_interface -> nx_interface_name; + } + + if (ip_address) + { + *ip_address = nx_interface -> nx_interface_ip_address; + } + + if (network_mask) + { + *network_mask = nx_interface -> nx_interface_ip_network_mask; + } + + if (mtu_size) + { + *mtu_size = nx_interface -> nx_interface_ip_mtu_size; + } + + if (physical_address_msw) + { + *physical_address_msw = nx_interface -> nx_interface_physical_address_msw; + } + + if (physical_address_lsw) + { + *physical_address_lsw = nx_interface -> nx_interface_physical_address_lsw; + } + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_IP_INTERFACE_INFO_GET, ip_ptr, nx_interface -> nx_interface_ip_address, + nx_interface -> nx_interface_physical_address_msw, nx_interface -> nx_interface_physical_address_lsw, + NX_TRACE_IP_EVENTS, 0, 0) + + + return(NX_SUCCESS); +} + diff --git a/common/src/nx_ip_interface_status_check.c b/common/src/nx_ip_interface_status_check.c new file mode 100644 index 0000000..7ac17ba --- /dev/null +++ b/common/src/nx_ip_interface_status_check.c @@ -0,0 +1,320 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" + + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ip_interface_status_check PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function polls the specified interface for the link state using*/ +/* thread sleep for the necessary conditions n the IP instance. Where */ +/* the requested status exists only at the IP instance, for example */ +/* NX_IP_INITIALIZE_DONE this service supplies the IP setting for that */ +/* status. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP instance */ +/* interface_indes Index into IP interface list */ +/* needed_status Status needed request */ +/* actual_status Pointer to return status area */ +/* wait_option Maximum suspension time */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* (ip_link_driver) User supplied link driver */ +/* tx_mutex_get Get protection mutex */ +/* tx_mutex_put Put protection mutex */ +/* tx_thread_sleep Sleep until events are */ +/* satisfied */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ip_interface_status_check(NX_IP *ip_ptr, UINT interface_index, ULONG needed_status, + ULONG *actual_status, ULONG wait_option) +{ + +ULONG current_status; +NX_IP_DRIVER driver_request; +ULONG return_value; + +#ifdef TX_ENABLE_EVENT_TRACE +TX_TRACE_BUFFER_ENTRY *trace_event; +ULONG trace_timestamp; +#endif + + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_IP_STATUS_CHECK, ip_ptr, needed_status, 0, wait_option, NX_TRACE_IP_EVENTS, &trace_event, &trace_timestamp) + + /* Loop to keep checking for the proper status bits. */ + do + { + + /* Clear the current status. */ + current_status = 0; + + /* Process according to the status option specified. */ + + if (needed_status & NX_IP_INITIALIZE_DONE) + { + + /* Check for initialization complete. */ + if (ip_ptr -> nx_ip_initialize_done) + { + + /* Yes, set the appropriate bit in the current status. */ + current_status = current_status | NX_IP_INITIALIZE_DONE; + } + } + + if (needed_status & NX_IP_ADDRESS_RESOLVED) + { + + /* Check for a non-zero IP address. */ + if (ip_ptr -> nx_ip_interface[interface_index].nx_interface_ip_address) + { + + /* Yes, set the appropriate bit in the current status. */ + current_status = current_status | NX_IP_ADDRESS_RESOLVED; + } + } + + if (needed_status & NX_IP_LINK_ENABLED) + { + + /* Get mutex protection. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Build the driver request structure. */ + driver_request.nx_ip_driver_ptr = ip_ptr; + driver_request.nx_ip_driver_command = NX_LINK_GET_STATUS; + driver_request.nx_ip_driver_return_ptr = &return_value; + driver_request.nx_ip_driver_interface = &(ip_ptr -> nx_ip_interface[interface_index]); + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_IO_DRIVER_GET_STATUS, ip_ptr, 0, 0, 0, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + /* Call link level driver. */ + (ip_ptr -> nx_ip_interface[interface_index].nx_interface_link_driver_entry) (&driver_request); + + /* Check for a link up condition. */ + if (ip_ptr -> nx_ip_interface[interface_index].nx_interface_link_up) + { + + /* Yes, set the appropriate bit in the current status. */ + current_status = current_status | NX_IP_LINK_ENABLED; + } + + /* Release mutex protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + } + + if (needed_status & NX_IP_ARP_ENABLED) + { + + /* Check for ARP being enabled. */ + if (ip_ptr -> nx_ip_arp_periodic_update) + { + /* Yes, set the appropriate bit in the current status. */ + current_status = current_status | NX_IP_ARP_ENABLED; + } + } + + if (needed_status & NX_IP_UDP_ENABLED) + { + + /* Check for UDP being enabled. */ + if (ip_ptr -> nx_ip_udp_packet_receive) + { + /* Yes, set the appropriate bit in the current status. */ + current_status = current_status | NX_IP_UDP_ENABLED; + } + } + + if (needed_status & NX_IP_TCP_ENABLED) + { + + /* Check for TCP being enabled. */ + if (ip_ptr -> nx_ip_tcp_packet_receive) + { + /* Yes, set the appropriate bit in the current status. */ + current_status = current_status | NX_IP_TCP_ENABLED; + } + } + + if (needed_status & NX_IP_IGMP_ENABLED) + { + + /* Check for IGMP being enabled. */ + if (ip_ptr -> nx_ip_igmp_packet_receive) + { + /* Yes, set the appropriate bit in the current status. */ + current_status = current_status | NX_IP_IGMP_ENABLED; + } + } + + if (needed_status & NX_IP_RARP_COMPLETE) + { + + /* This is effectively the same as the IP address resolved... */ + + /* Check for a non-zero IP address. */ + if (ip_ptr -> nx_ip_interface[interface_index].nx_interface_ip_address) + { + + /* Yes, set the appropriate bit in the current status. */ + current_status = current_status | NX_IP_RARP_COMPLETE; + } + } + + if (needed_status & NX_IP_INTERFACE_LINK_ENABLED) + { + + /* Get mutex protection. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Build the driver request structure. */ + driver_request.nx_ip_driver_ptr = ip_ptr; + driver_request.nx_ip_driver_command = NX_LINK_GET_STATUS; + driver_request.nx_ip_driver_return_ptr = &return_value; + driver_request.nx_ip_driver_interface = &(ip_ptr -> nx_ip_interface[interface_index]); + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_IO_DRIVER_GET_STATUS, ip_ptr, 0, 0, 0, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + /* Call link level driver. */ + (ip_ptr -> nx_ip_interface[interface_index].nx_interface_link_driver_entry) (&driver_request); + + /* If the driver does not recognize this keyword, we fall back to reading the IP link status.*/ + if (driver_request.nx_ip_driver_status != NX_SUCCESS) + { + if (driver_request.nx_ip_driver_status == NX_UNHANDLED_COMMAND) + { + if (ip_ptr -> nx_ip_interface[interface_index].nx_interface_link_up) + { + current_status = current_status | NX_IP_INTERFACE_LINK_ENABLED; + } + } + } + else + { + /* Check for a link up condition. */ + if (return_value == NX_TRUE) + { + + /* Yes, set the appropriate bit in the current status. */ + current_status = current_status | NX_IP_INTERFACE_LINK_ENABLED; + } + } + + /* Release mutex protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + } + + /* Determine if current status is the same. If so, break out + of this polling loop. */ + if (current_status == needed_status) + { + break; + } + + /* Check for suspension request. */ + if (wait_option) + { + + /* Decrease the wait time and sleep. */ + wait_option--; + + /* Sleep for a tick and check again. */ + tx_thread_sleep(NX_IP_STATUS_CHECK_WAIT_TIME); + } + else + { + + /* Get out of the loop. */ + break; + } + + /* Check for a valid ip structure. */ + if (ip_ptr -> nx_ip_id != NX_IP_ID) + { + + /* Clear the return status bits. */ + *actual_status = 0; + + /* Return an error indicating the IP pointer is no longer valid. */ + return(NX_PTR_ERROR); + } + } while (NX_FOREVER); + + /* Place the current status in the return destination. */ + *actual_status = current_status; + + /* Update the trace event with the status. */ + NX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, NX_TRACE_IP_STATUS_CHECK, 0, 0, current_status, 0) + + /* Determine what status to return. */ + if (needed_status == current_status) + { + + /* Return a success. */ + return(NX_SUCCESS); + } + else + { + + /* Return an error. */ + return(NX_NOT_SUCCESSFUL); + } +} + diff --git a/common/src/nx_ip_link_status_change_notify_set.c b/common/src/nx_ip_link_status_change_notify_set.c new file mode 100644 index 0000000..5454003 --- /dev/null +++ b/common/src/nx_ip_link_status_change_notify_set.c @@ -0,0 +1,90 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ip_link_status_change_notify_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function configures the link status change notify callback */ +/* function specified by the application. */ +/* */ +/* If a NULL pointer is supplied, the link status change notify */ +/* callback feature is disabled. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP instance */ +/* link_status_change_notify Routine to call when link */ +/* staus is changed */ +/* */ +/* OUTPUT */ +/* */ +/* 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_ip_link_status_change_notify_set(NX_IP *ip_ptr, VOID (*link_status_change_notify)(NX_IP *ip_ptr, UINT interface_index, UINT link_up)) +{ +TX_INTERRUPT_SAVE_AREA + + /* Disable interrupts. */ + TX_DISABLE + + /* Setup the link status change callback function pointer. */ + ip_ptr -> nx_ip_link_status_change_callback = link_status_change_notify; + + /* Restore interrupts. */ + TX_RESTORE + + /* Return successful completion. */ + return(NX_SUCCESS); +} + diff --git a/common/src/nx_ip_loopback_send.c b/common/src/nx_ip_loopback_send.c new file mode 100644 index 0000000..4f38e94 --- /dev/null +++ b/common/src/nx_ip_loopback_send.c @@ -0,0 +1,120 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_packet.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ip_loopback_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function prepends an IP header and sends an IP packet to the */ +/* appropriate link driver. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP control block */ +/* packet_ptr Pointer to packet to send */ +/* packet_release Whether or not to release */ +/* the original packet */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_ip_packet_deferred_receive Receive loopback packet */ +/* _nx_packet_copy Copy packet for loopback */ +/* _nx_packet_transmit_release Release transmit packet */ +/* */ +/* CALLED BY */ +/* */ +/* NetX Source Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_ip_loopback_send(NX_IP *ip_ptr, NX_PACKET *packet_ptr, UINT packet_release) +{ + +NX_PACKET *packet_copy; + + /* 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_IP_HEADER); +#endif + + /* Send the packet to this IP's receive processing queue 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 + + if (packet_release) + { + /* Release the transmit packet. */ + _nx_packet_transmit_release(packet_ptr); + } + + + return; +} + diff --git a/common/src/nx_ip_packet_deferred_receive.c b/common/src/nx_ip_packet_deferred_receive.c new file mode 100644 index 0000000..4d19aff --- /dev/null +++ b/common/src/nx_ip_packet_deferred_receive.c @@ -0,0 +1,111 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ip_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 IP helper thread. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP control block */ +/* packet_ptr Pointer to packet to send */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* tx_event_flags_set Set events for IP thread */ +/* */ +/* CALLED BY */ +/* */ +/* Application I/O Driver */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_ip_packet_deferred_receive(NX_IP *ip_ptr, NX_PACKET *packet_ptr) +{ + +TX_INTERRUPT_SAVE_AREA + + + /* Disable interrupts. */ + TX_DISABLE + + /* Check to see if the deferred processing queue is empty. */ + if (ip_ptr -> nx_ip_deferred_received_packet_head) + { + + /* Not empty, just place the packet at the end of the queue. */ + (ip_ptr -> nx_ip_deferred_received_packet_tail) -> nx_packet_queue_next = packet_ptr; + packet_ptr -> nx_packet_queue_next = NX_NULL; + ip_ptr -> nx_ip_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 IP helper thread looks at the deferred processing + queue. */ + ip_ptr -> nx_ip_deferred_received_packet_head = packet_ptr; + ip_ptr -> nx_ip_deferred_received_packet_tail = packet_ptr; + packet_ptr -> nx_packet_queue_next = NX_NULL; + + /* Restore interrupts. */ + TX_RESTORE + + /* Wakeup IP helper thread to process the IP deferred receive. */ + tx_event_flags_set(&(ip_ptr -> nx_ip_events), NX_IP_RECEIVE_EVENT, TX_OR); + } +} + diff --git a/common/src/nx_ip_packet_receive.c b/common/src/nx_ip_packet_receive.c new file mode 100644 index 0000000..6944cc2 --- /dev/null +++ b/common/src/nx_ip_packet_receive.c @@ -0,0 +1,785 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_igmp.h" +#include "nx_packet.h" +#include "nx_udp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ip_packet_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 either processes it or places it in a */ +/* deferred processing queue, depending on the complexity of the */ +/* packet. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP control block */ +/* packet_ptr Pointer to packet to send */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* (ip_tcp_packet_receive) Receive a TCP packet */ +/* (ip_udp_packet_receive) Receive a UDP packet */ +/* (ip_icmp_packet_receive) Receive a ICMP packet */ +/* (ip_igmp_packet_receive) Receive a IGMP packet */ +/* (ip_raw_ip_raw_packet_processing) Process a Raw IP packet */ +/* (nx_ip_forward_packet_process) Forward IP packet */ +/* _nx_igmp_multicast_check Check for Multicast match */ +/* _nx_packet_release Packet release function */ +/* tx_event_flags_set Set events for IP thread */ +/* */ +/* CALLED BY */ +/* */ +/* Application I/O Driver */ +/* _nx_ip_packet_send IP loopback packet send */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_ip_packet_receive(NX_IP *ip_ptr, NX_PACKET *packet_ptr) +{ + +TX_INTERRUPT_SAVE_AREA +NX_PACKET *before_last_packet; +NX_PACKET *last_packet; +NX_IP_HEADER *ip_header_ptr; +ULONG *word_ptr; +ULONG ip_header_length; +ULONG protocol; +ULONG delta; +UCHAR drop_packet = 0; +NX_UDP_HEADER *udp_header_ptr; +UINT dest_port; +#ifndef NX_DISABLE_IP_RX_CHECKSUM +ULONG ip_option_words; +ULONG checksum; +ULONG temp; +#endif /* NX_DISABLE_IP_RX_CHECKSUM */ + + +#ifndef NX_DISABLE_IP_INFO + + /* Increment the IP packet count. */ + ip_ptr -> nx_ip_total_packets_received++; +#endif + + /* If packet_ptr -> nx_packet_ip_interface is not set, stamp the packet with interface[0]. + Legacy Ethernet drivers do not stamp incoming packets. */ + if (packet_ptr -> nx_packet_ip_interface == NX_NULL) + { + packet_ptr -> nx_packet_ip_interface = &(ip_ptr -> nx_ip_interface[0]); + } + + /* It's assumed that the IP link driver has positioned the top pointer in the + packet to the start of the IP address... so that's where we will start. */ + ip_header_ptr = (NX_IP_HEADER *)packet_ptr -> nx_packet_prepend_ptr; + +#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_IN)) != NX_SUCCESS) + { + + /* Drop the packet. */ + _nx_packet_release(packet_ptr); + return; + } + } +#endif /* NX_ENABLE_IP_PACKET_FILTER */ + + /* 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); + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_IP_RECEIVE, ip_ptr, ip_header_ptr -> nx_ip_header_source_ip, packet_ptr, packet_ptr -> nx_packet_length, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + /* Make sure the IP length matches the packet length. Some Ethernet devices + add padding to small packets, which results in a discrepancy between the + packet length and the IP header length. */ + if (packet_ptr -> nx_packet_length != (ip_header_ptr -> nx_ip_header_word_0 & NX_LOWER_16_MASK)) + { + + /* Determine if the packet length is less than the size reported in the IP header. */ + if (packet_ptr -> nx_packet_length < (ip_header_ptr -> nx_ip_header_word_0 & NX_LOWER_16_MASK)) + { + + /* Packet is too small! */ + +#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); + + /* The function is complete, just return! */ + return; + } + + /* Calculate the difference in the length. */ + delta = packet_ptr -> nx_packet_length - (ip_header_ptr -> nx_ip_header_word_0 & NX_LOWER_16_MASK); + + /* Adjust the packet length. */ + packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - delta; + + /* Adjust the append pointer. */ + + /* 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. */ + 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. */ + 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); + } + } + } + + /* Get IP header length. */ + ip_header_length = (ip_header_ptr -> nx_ip_header_word_0 & NX_IP_LENGTH_MASK) >> 24; + + /* Check for minimal packet length. The check is done after the endian swapping + since the compiler may possibly be able to optimize the lookup of + "nx_packet_length" and therefore reduce the amount of work performing these + size checks. The endian logic is okay since packets must always have + payloads greater than the IP header in size. */ + if ((packet_ptr -> nx_packet_length <= (ip_header_length << 2)) || + (ip_header_length < NX_IP_NORMAL_LENGTH)) + { + + /* Packet is too small! */ + +#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); + + /* The function is complete, just return! */ + return; + } + +#ifndef NX_DISABLE_RX_SIZE_CHECKING +#endif /* NX_DISABLE_RX_SIZE_CHECKING */ + +#ifndef NX_DISABLE_IP_RX_CHECKSUM + + /* Perform a checksum on the packet header. */ + temp = ip_header_ptr -> nx_ip_header_word_0; + checksum = (temp >> NX_SHIFT_BY_16) + (temp & NX_LOWER_16_MASK); + temp = ip_header_ptr -> nx_ip_header_word_1; + checksum += (temp >> NX_SHIFT_BY_16) + (temp & NX_LOWER_16_MASK); + temp = ip_header_ptr -> nx_ip_header_word_2; + checksum += (temp >> NX_SHIFT_BY_16) + (temp & NX_LOWER_16_MASK); + temp = ip_header_ptr -> nx_ip_header_source_ip; + checksum += (temp >> NX_SHIFT_BY_16) + (temp & NX_LOWER_16_MASK); + temp = ip_header_ptr -> nx_ip_header_destination_ip; + checksum += (temp >> NX_SHIFT_BY_16) + (temp & NX_LOWER_16_MASK); + + /* Add in the carry bits into the checksum. */ + checksum = (checksum >> NX_SHIFT_BY_16) + (checksum & NX_LOWER_16_MASK); + + /* Do it again in case previous operation generates an overflow. */ + checksum = (checksum >> NX_SHIFT_BY_16) + (checksum & NX_LOWER_16_MASK); + + /* Take the one's complement. */ + checksum = NX_LOWER_16_MASK & ~checksum; + + /* Determine if the checksum is valid. */ + if (checksum) + { + + /* Check for IP options before we give up on the packet. */ + /* Setup a pointer to the first option word. */ + word_ptr = ((ULONG *)((VOID *)ip_header_ptr)) + NX_IP_NORMAL_LENGTH; + + /* Determine if there are options in the IP header that make the length greater + than the default length. */ + if (ip_header_length > NX_IP_NORMAL_LENGTH) + { + + /* IP header with options is present. */ + + /* Un-complement the checksum. */ + checksum = ~checksum & NX_LOWER_16_MASK; + + /* Calculate the number of option words. */ + ip_option_words = ip_header_length - NX_IP_NORMAL_LENGTH; + + /* Loop to adjust the checksum. */ + do + { + + /* Endian swapping logic. If NX_LITTLE_ENDIAN is specified, this macro + will swap the endian of the IP header option word. */ + NX_CHANGE_ULONG_ENDIAN(*word_ptr); + + /* Add this word to the checksum. */ + temp = *word_ptr; + checksum += (temp >> NX_SHIFT_BY_16); + checksum += (NX_LOWER_16_MASK & temp); + + /* Move the option word pointer and decrement the number of option words. */ + word_ptr++; + ip_option_words--; + } while (ip_option_words); + + /* Add in the carry bits into the checksum. */ + checksum = (checksum >> NX_SHIFT_BY_16) + (checksum & NX_LOWER_16_MASK); + + /* Do it again in case previous operation generates an overflow. */ + checksum = (checksum >> NX_SHIFT_BY_16) + (checksum & NX_LOWER_16_MASK); + + /* Perform the one's complement on the checksum again. */ + checksum = NX_LOWER_16_MASK & ~checksum; + } + + /* Check the checksum again. */ + if (checksum) + { + +#ifndef NX_DISABLE_IP_INFO + + /* Increment the IP invalid packet error. */ + ip_ptr -> nx_ip_invalid_packets++; + + /* Increment the IP checksum error. */ + ip_ptr -> nx_ip_receive_checksum_errors++; + + /* Increment the IP receive packets dropped count. */ + ip_ptr -> nx_ip_receive_packets_dropped++; +#endif + + /* Checksum error, just release it. */ + _nx_packet_release(packet_ptr); + + /* The function is complete, just return! */ + return; + } + else + { + + /* If the packet checksum is okay, make sure the source and destination IP + addresses are placed immediately before the next protocol layer. */ + + /* Build a pointer to what will be the last word of the IP header after we + remove the IP options. Basically, all we have to do is move it backwards + since it was setup previously. */ + word_ptr--; + + /* Move the destination IP. */ + *word_ptr-- = ip_header_ptr -> nx_ip_header_destination_ip; + *word_ptr-- = ip_header_ptr -> nx_ip_header_source_ip; + *word_ptr-- = ip_header_ptr -> nx_ip_header_word_2; + *word_ptr-- = ip_header_ptr -> nx_ip_header_word_1; + *word_ptr = (ip_header_ptr -> nx_ip_header_word_0 & ~NX_IP_LENGTH_MASK) | + NX_IP_VERSION; + + /* Update the ip_header_ptr and the packet and the packet prepend pointer + and length. */ + ip_header_ptr = (NX_IP_HEADER *)((VOID *)word_ptr); + packet_ptr -> nx_packet_prepend_ptr = (UCHAR *)word_ptr; + packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - + ((ip_header_length - NX_IP_NORMAL_LENGTH) * sizeof(ULONG)); + } + } +#else + + /* IP receive checksum processing is disabled... just check for and remove if + necessary the IP option words. */ + + /* Check for IP options before we process the packet. */ + + /* Determine if there are options in the IP header that make the length greater + than the default length. */ + if (ip_header_length > NX_IP_NORMAL_LENGTH) + { + + /* Setup a pointer to the last option word. */ + word_ptr = ((ULONG *)ip_header_ptr) + ip_header_length - 1; + + /* Remove the option words prior to handling the IP header. */ + *word_ptr-- = ip_header_ptr -> nx_ip_header_destination_ip; + *word_ptr-- = ip_header_ptr -> nx_ip_header_source_ip; + *word_ptr-- = ip_header_ptr -> nx_ip_header_word_2; + *word_ptr-- = ip_header_ptr -> nx_ip_header_word_1; + *word_ptr = (ip_header_ptr -> nx_ip_header_word_0 & ~NX_IP_LENGTH_MASK) | + NX_IP_VERSION; + + /* Update the ip_header_ptr and the packet and the packet prepend pointer + and length. */ + ip_header_ptr = (NX_IP_HEADER *)word_ptr; + packet_ptr -> nx_packet_prepend_ptr = (UCHAR *)word_ptr; + packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - + ((ip_header_length - NX_IP_NORMAL_LENGTH) * sizeof(ULONG)); + } +#endif + +#ifdef NX_ENABLE_SOURCE_ADDRESS_CHECK + /* Check whether source address is valid. */ + /* Section 3.2.1.3, page 30, RFC 1122. */ + if (packet_ptr -> nx_packet_ip_interface -> nx_interface_address_mapping_needed == NX_TRUE) + { + if (((ip_header_ptr -> nx_ip_header_source_ip & ~(packet_ptr -> nx_packet_ip_interface -> nx_interface_ip_network_mask)) == ~(packet_ptr -> nx_packet_ip_interface -> nx_interface_ip_network_mask)) || + (((ip_header_ptr -> nx_ip_header_source_ip & ~(packet_ptr -> nx_packet_ip_interface -> nx_interface_ip_network_mask)) == 0) && + (ip_header_ptr -> nx_ip_header_source_ip != 0)) || + ((ip_header_ptr -> nx_ip_header_source_ip & NX_IP_CLASS_D_MASK) == NX_IP_CLASS_D_TYPE)) + { + +#ifndef NX_DISABLE_IP_INFO + + /* Increment the IP invalid address error. */ + ip_ptr -> nx_ip_invalid_receive_address++; + + /* Increment the IP receive packets dropped count. */ + ip_ptr -> nx_ip_receive_packets_dropped++; +#endif + + /* Toss the IP packet since we don't know what to do with it! */ + _nx_packet_release(packet_ptr); + + /* Return to caller. */ + return; + } + } +#endif /* NX_ENABLE_SOURCE_ADDRESS_CHECK */ + + /* Determine if the IP datagram is for this IP address or a broadcast IP on this + network. */ + if ((ip_header_ptr -> nx_ip_header_destination_ip == packet_ptr -> nx_packet_ip_interface -> nx_interface_ip_address) || + + /* Check for incoming IP address of zero. Incoming IP address of zero should + be received regardless of our current IP address. */ + (ip_header_ptr -> nx_ip_header_destination_ip == 0) || + + /* Check for IP broadcast. */ + (((ip_header_ptr -> nx_ip_header_destination_ip & packet_ptr -> nx_packet_ip_interface -> nx_interface_ip_network_mask) == + packet_ptr -> nx_packet_ip_interface -> nx_interface_ip_network) && + ((ip_header_ptr -> nx_ip_header_destination_ip & ~(packet_ptr -> nx_packet_ip_interface -> nx_interface_ip_network_mask)) == + ~(packet_ptr -> nx_packet_ip_interface -> nx_interface_ip_network_mask))) || + + /* Check for limited broadcast. */ + (ip_header_ptr -> nx_ip_header_destination_ip == NX_IP_LIMITED_BROADCAST) || + + /* 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)) || + + /* Check for valid Multicast address. */ + (_nx_igmp_multicast_check(ip_ptr, ip_header_ptr -> nx_ip_header_destination_ip, packet_ptr -> nx_packet_ip_interface))) + { + + /* Determine if this packet is fragmented. If so, place it on the deferred processing + queue. The input packet will then be processed by an IP system thread. */ + if (ip_header_ptr -> nx_ip_header_word_1 & NX_IP_FRAGMENT_MASK) + { + +#ifndef NX_DISABLE_IP_INFO + + /* Increment the IP receive fragments count. */ + ip_ptr -> nx_ip_total_fragments_received++; +#endif + + /* Yes, the incoming IP header is fragmented. Check to see if IP fragmenting + has been enabled. */ + if (ip_ptr -> nx_ip_fragment_assembly) + { + + /* Yes, fragmenting is available. Place the packet on the incoming + fragment queue. */ + + /* Disable interrupts. */ + TX_DISABLE + + /* Determine if the queue is empty. */ + if (ip_ptr -> nx_ip_received_fragment_head) + { + + /* Raw receive queue is not empty, add this packet to the end of + the queue. */ + (ip_ptr -> nx_ip_received_fragment_tail) -> nx_packet_queue_next = packet_ptr; + packet_ptr -> nx_packet_queue_next = NX_NULL; + ip_ptr -> nx_ip_received_fragment_tail = packet_ptr; + } + else + { + + /* Raw receive queue is empty. Just setup the head and tail pointers + to point to this packet. */ + ip_ptr -> nx_ip_received_fragment_head = packet_ptr; + ip_ptr -> nx_ip_received_fragment_tail = packet_ptr; + packet_ptr -> nx_packet_queue_next = NX_NULL; + } + + /* Restore interrupts. */ + TX_RESTORE + + /* Wakeup IP helper thread to process the IP fragment re-assembly. */ + tx_event_flags_set(&(ip_ptr -> nx_ip_events), NX_IP_UNFRAG_EVENT, TX_OR); + } + else + { + +#ifndef NX_DISABLE_IP_INFO + + /* Increment the IP receive packets dropped count. */ + ip_ptr -> nx_ip_receive_packets_dropped++; +#endif + + /* Fragmentation has not been enabled, toss the packet! */ + _nx_packet_release(packet_ptr); + } + + /* In all cases, receive processing is finished. Return to caller. */ + return; + } + + /* Determine what protocol the current IP datagram is. */ + protocol = ip_header_ptr -> nx_ip_header_word_2 & NX_IP_PROTOCOL_MASK; + + /* Remove the IP header from the packet. */ + packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr + sizeof(NX_IP_HEADER); + + /* Adjust the length. */ + packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - sizeof(NX_IP_HEADER); + +#ifndef NX_DISABLE_IP_INFO + + /* Increment the number of packets delivered. */ + ip_ptr -> nx_ip_total_packets_delivered++; + + /* Increment the IP packet bytes received (not including the header). */ + ip_ptr -> nx_ip_total_bytes_received += packet_ptr -> nx_packet_length; +#endif + + /* Dispatch the protocol... Have we found a UDP packet? */ + if (protocol == NX_IP_UDP) + { + + if (ip_ptr -> nx_ip_udp_packet_receive) + { + + /* Yes, dispatch it to the appropriate UDP handler if present. */ + (ip_ptr -> nx_ip_udp_packet_receive)(ip_ptr, packet_ptr); + + return; + } + + /* UDP is not enabled. */ + drop_packet = 1; + } + /* Is a TCP packet present? */ + else if (protocol == NX_IP_TCP) + { + if (ip_ptr -> nx_ip_tcp_packet_receive) + { + + /* Yes, dispatch it to the appropriate TCP handler if present. */ + (ip_ptr -> nx_ip_tcp_packet_receive)(ip_ptr, packet_ptr); + + return; + } + + /* TCP is not enabled. */ + drop_packet = 1; + } + /* Is a ICMP packet present? */ + else if (protocol == NX_IP_ICMP) + { + if (ip_ptr -> nx_ip_icmp_packet_receive) + { + + /* Yes, dispatch it to the appropriate ICMP handler if present. */ + (ip_ptr -> nx_ip_icmp_packet_receive)(ip_ptr, packet_ptr); + + return; + } + + /* ICMP is not enabled. */ + drop_packet = 1; + } + else if (protocol == NX_IP_IGMP) + { + if (ip_ptr -> nx_ip_igmp_packet_receive) + { + + /* Yes, dispatch it to the appropriate IGMP handler if present. */ + (ip_ptr -> nx_ip_igmp_packet_receive)(ip_ptr, packet_ptr); + + return; + } + + /* IGMP is not enabled. */ + drop_packet = 1; + } + /* No protocol found so far. Determine if RAW IP is supported. */ + if (ip_ptr -> nx_ip_raw_ip_processing && (drop_packet == 0)) + { + + /* Yes it is. Call the raw IP packet processing routine. */ + (ip_ptr -> nx_ip_raw_ip_processing)(ip_ptr, packet_ptr); + + /* Done, return to caller. */ + return; + } + else + { + +#ifndef NX_DISABLE_IP_INFO + + /* Decrement the number of packets delivered. */ + ip_ptr -> nx_ip_total_packets_delivered--; + + /* Decrement the IP packet bytes received (not including the header). */ + ip_ptr -> nx_ip_total_bytes_received -= packet_ptr -> nx_packet_length; + + /* Increment the IP unknown protocol count. */ + ip_ptr -> nx_ip_unknown_protocols_received++; + + /* Increment the IP receive packets dropped count. */ + ip_ptr -> nx_ip_receive_packets_dropped++; +#endif + + /* Toss the IP packet since we don't know what to do with it! */ + _nx_packet_release(packet_ptr); + + /* Return to caller. */ + return; + } + } + /* Does this IP interface define another forward packet handler other + than the NAT packet handler? */ + else if (ip_ptr -> nx_ip_forward_packet_process) + { + +#ifndef NX_DISABLE_IP_INFO + + /* Increment the IP packets forwarded counter. */ + ip_ptr -> nx_ip_packets_forwarded++; +#endif + + /* The packet is not for this IP instance so call the + forward IP packet processing routine. */ + (ip_ptr -> nx_ip_forward_packet_process)(ip_ptr, packet_ptr); + } + /* Try to receive the DHCP message before release this packet. + NetX should recieve the unicast DHCP message when interface IP address is zero. */ + + /* Check if this IP interface has IP address. */ + else if (packet_ptr -> nx_packet_ip_interface -> nx_interface_ip_address == 0) + { + + /* Determine what protocol the current IP datagram is. */ + protocol = ip_header_ptr -> nx_ip_header_word_2 & NX_IP_PROTOCOL_MASK; + + /* Check if this packet is UDP message. */ + if (protocol == NX_IP_UDP) + { + + /* Remove the IP header from the packet. */ + packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr + sizeof(NX_IP_HEADER); + + /* Adjust the length. */ + packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - sizeof(NX_IP_HEADER); + +#ifndef NX_DISABLE_IP_INFO + + /* Increment the number of packets delivered. */ + ip_ptr -> nx_ip_total_packets_delivered++; + + /* Increment the IP packet bytes received (not including the header). */ + ip_ptr -> nx_ip_total_bytes_received += packet_ptr -> nx_packet_length; +#endif + + /* Pickup the pointer to the head of the UDP packet. */ + udp_header_ptr = (NX_UDP_HEADER *)packet_ptr -> nx_packet_prepend_ptr; + + /* 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); + + /* Pickup the destination UDP port. */ + dest_port = (UINT)(udp_header_ptr -> nx_udp_header_word_0 & NX_LOWER_16_MASK); + + /* 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); + + /* Check if this packet is DHCP message. */ + if (dest_port == 68) + { + if (ip_ptr -> nx_ip_udp_packet_receive) + { + + /* Yes, dispatch it to the appropriate UDP handler if present. */ + (ip_ptr -> nx_ip_udp_packet_receive)(ip_ptr, packet_ptr); + + return; + } + } + } + +#ifndef NX_DISABLE_IP_INFO + + /* Decrement the number of packets delivered. */ + ip_ptr -> nx_ip_total_packets_delivered--; + + /* Decrement the IP packet bytes received (not including the header). */ + ip_ptr -> nx_ip_total_bytes_received -= packet_ptr -> nx_packet_length; + + /* Increment the IP invalid address error. */ + ip_ptr -> nx_ip_invalid_receive_address++; + + /* Increment the IP receive packets dropped count. */ + ip_ptr -> nx_ip_receive_packets_dropped++; +#endif + + /* Toss the IP packet since we don't know what to do with it! */ + _nx_packet_release(packet_ptr); + + /* Return to caller. */ + return; + } + else + { + +#ifndef NX_DISABLE_IP_INFO + + /* Increment the IP invalid address error. */ + ip_ptr -> nx_ip_invalid_receive_address++; + + /* Increment the IP receive packets dropped count. */ + ip_ptr -> nx_ip_receive_packets_dropped++; +#endif + + /* Toss the IP packet since we don't know what to do with it! */ + _nx_packet_release(packet_ptr); + + /* Return to caller. */ + return; + } +} + diff --git a/common/src/nx_ip_packet_send.c b/common/src/nx_ip_packet_send.c new file mode 100644 index 0000000..f93323c --- /dev/null +++ b/common/src/nx_ip_packet_send.c @@ -0,0 +1,876 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_packet.h" +#include "nx_igmp.h" +#include "nx_arp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ip_packet_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function prepends an IP header and sends an IP packet to the */ +/* appropriate link driver. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP control block */ +/* packet_ptr Pointer to packet to send */ +/* destination_ip Destination IP address */ +/* type_of_service Type of service for packet */ +/* time_to_live Time to live value for packet */ +/* protocol Protocol being encapsulated */ +/* fragment Don't fragment bit */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_packet_copy Copy packet for loopback */ +/* _nx_packet_transmit_release Release transmit packet */ +/* _nx_ip_loopback_send Send packet via the LB driver */ +/* (nx_ip_fragment_processing) Fragment processing */ +/* (ip_link_driver) User supplied link driver */ +/* */ +/* CALLED BY */ +/* */ +/* NetX Source Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +VOID _nx_ip_packet_send(NX_IP *ip_ptr, NX_PACKET *packet_ptr, + ULONG destination_ip, ULONG type_of_service, ULONG time_to_live, ULONG protocol, ULONG fragment) +{ + +TX_INTERRUPT_SAVE_AREA +NX_IP_DRIVER driver_request; +NX_IP_HEADER *ip_header_ptr; + +#ifndef NX_DISABLE_IP_TX_CHECKSUM +ULONG checksum; +ULONG temp; +#endif /* !NX_DISABLE_IP_TX_CHECKSUM */ +UINT index; +NX_ARP *arp_ptr; +NX_PACKET *last_packet; +NX_PACKET *remove_packet; +UINT queued_count; + + +#ifndef NX_DISABLE_IP_INFO + + /* Increment the total send requests counter. */ + ip_ptr -> nx_ip_total_packet_send_requests++; +#endif /* !NX_DISABLE_IP_INFO */ + + /* 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 - sizeof(NX_IP_HEADER); + + /* Increase the packet length. */ + packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length + sizeof(NX_IP_HEADER); + + /* Make sure the packet interface or next hop (e.g. gateway) is set. */ + if ((packet_ptr -> nx_packet_ip_interface == NX_NULL) || (packet_ptr -> nx_packet_next_hop_address == 0)) + { + +#ifndef NX_DISABLE_IP_INFO + + /* Increment the IP invalid packet error. */ + ip_ptr -> nx_ip_invalid_transmit_packets++; +#endif /* !NX_DISABLE_IP_INFO */ + + /* Release the packet. Note that at this point the prepend_ptr points to the beginning of the IP header. */ + _nx_packet_transmit_release(packet_ptr); + + /* Return... nothing more can be done! */ + return; + } + + /* If the IP header won't fit, return an error. */ + if (packet_ptr -> nx_packet_prepend_ptr < packet_ptr -> nx_packet_data_start) + { + +#ifndef NX_DISABLE_IP_INFO + + /* Increment the IP invalid packet error. */ + ip_ptr -> nx_ip_invalid_transmit_packets++; +#endif /* !NX_DISABLE_IP_INFO */ + + /* Release the packet. Note that at this point the prepend_ptr points to the beginning of the IP header. */ + _nx_packet_transmit_release(packet_ptr); + + /* Return... nothing more can be done! */ + return; + } + + /* Build the IP header. */ + + /* Setup the IP header pointer. */ + ip_header_ptr = (NX_IP_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 | 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) | fragment; + + /* Build the third 32-bit word of the IP header. */ + ip_header_ptr -> nx_ip_header_word_2 = ((time_to_live << NX_IP_TIME_TO_LIVE_SHIFT) | protocol); + + /* Place the source IP address in the IP header. */ + ip_header_ptr -> nx_ip_header_source_ip = packet_ptr -> nx_packet_ip_interface -> nx_interface_ip_address; + + /* Place the destination IP address in the IP header. */ + ip_header_ptr -> nx_ip_header_destination_ip = destination_ip; + +#ifndef NX_DISABLE_IP_TX_CHECKSUM + + /* Build the IP header checksum. */ + temp = ip_header_ptr -> nx_ip_header_word_0; + checksum = (temp >> NX_SHIFT_BY_16) + (temp & NX_LOWER_16_MASK); + temp = ip_header_ptr -> nx_ip_header_word_1; + checksum += (temp >> NX_SHIFT_BY_16) + (temp & NX_LOWER_16_MASK); + temp = ip_header_ptr -> nx_ip_header_word_2; + checksum += (temp >> NX_SHIFT_BY_16); + temp = ip_header_ptr -> nx_ip_header_source_ip; + checksum += (temp >> NX_SHIFT_BY_16) + (temp & NX_LOWER_16_MASK); + temp = ip_header_ptr -> nx_ip_header_destination_ip; + checksum += (temp >> NX_SHIFT_BY_16) + (temp & NX_LOWER_16_MASK); + + /* Add in the carry bits into the checksum. */ + checksum = (checksum >> NX_SHIFT_BY_16) + (checksum & NX_LOWER_16_MASK); + + /* Do it again in case previous operation generates an overflow. */ + checksum = (checksum >> NX_SHIFT_BY_16) + (checksum & NX_LOWER_16_MASK); + + /* Now store the checksum in the IP header. */ + ip_header_ptr -> nx_ip_header_word_2 = ip_header_ptr -> nx_ip_header_word_2 | (NX_LOWER_16_MASK & (~checksum)); +#endif /* !NX_DISABLE_IP_TX_CHECKSUM */ + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_IP_SEND, ip_ptr, destination_ip, packet_ptr, packet_ptr -> nx_packet_length, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + /* 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_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) + { + + /* Drop the packet. */ + _nx_packet_transmit_release(packet_ptr); + return; + } + } +#endif /* NX_ENABLE_IP_PACKET_FILTER */ + + /* Take care of the loopback case. */ + if ((destination_ip == packet_ptr -> nx_packet_ip_interface -> nx_interface_ip_address) || + ((destination_ip >= NX_IP_LOOPBACK_FIRST) && (destination_ip <= NX_IP_LOOPBACK_LAST))) + { + /* Send the packet via the loopback driver, and release the original + packet after loopback send. */ + _nx_ip_loopback_send(ip_ptr, packet_ptr, NX_TRUE); + + return; + } + + /* Determine if physical mapping is needed by the link driver. */ + if (packet_ptr -> nx_packet_ip_interface -> nx_interface_address_mapping_needed) + { + + /* Yes, Check for broadcast address. */ + + /* Determine if an IP limited or directed broadcast is requested. */ + if ((destination_ip == NX_IP_LIMITED_BROADCAST) || + (((destination_ip & packet_ptr -> nx_packet_ip_interface -> nx_interface_ip_network_mask) == packet_ptr -> nx_packet_ip_interface -> nx_interface_ip_network) && + ((destination_ip & ~(packet_ptr -> nx_packet_ip_interface -> nx_interface_ip_network_mask)) == ~(packet_ptr -> nx_packet_ip_interface -> nx_interface_ip_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_ip_interface; +#ifndef NX_DISABLE_FRAGMENTATION + /* Determine if fragmentation is needed. */ + if ((packet_ptr -> nx_packet_length) > (packet_ptr -> nx_packet_ip_interface -> 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 /* !NX_DISABLE_IP_INFO */ + + /* Just release the packet. */ + _nx_packet_transmit_release(packet_ptr); + } + + /* In either case, this packet send is complete, just return. */ + return; + } +#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_IP_HEADER); +#endif /* !NX_DISABLE_IP_INFO */ + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_IO_DRIVER_PACKET_SEND, ip_ptr, packet_ptr, packet_ptr -> nx_packet_length, 0, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + /* Broadcast packet. */ + (packet_ptr -> nx_packet_ip_interface -> nx_interface_link_driver_entry) (&driver_request); + + 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_ip_interface; + + /* Determine if the group was joined by this IP instance, and requested a packet via its loopback interface. */ + index = 0; + while (index < NX_MAX_MULTICAST_GROUPS) + { + + /* Determine if the destination address matches the requested address. */ + if (ip_ptr -> nx_ip_igmp_join_list[index] == destination_ip) + { + + /* Yes, break the loop! */ + break; + } + + /* Increment the join list index. */ + index++; + } + if (index < NX_MAX_MULTICAST_GROUPS) + { + + /* Determine if the group has loopback enabled. */ + if (ip_ptr -> nx_ip_igmp_group_loopback_enable[index]) + { + + /* + Yes, loopback is enabled! Send the packet via + the loopback interface, and do not release the + original packet so it can be transmitted via a physical + interface later on. + */ + _nx_ip_loopback_send(ip_ptr, packet_ptr, NX_FALSE); + } + } + + /* 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_ip_interface; + +#ifndef NX_DISABLE_FRAGMENTATION + /* Determine if fragmentation is needed. */ + if (packet_ptr -> nx_packet_length > packet_ptr -> nx_packet_ip_interface -> 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 /* !NX_DISABLE_IP_INFO */ + /* Just release the packet. */ + _nx_packet_transmit_release(packet_ptr); + } + + /* In either case, this packet send is complete, just return. */ + return; + } +#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_IP_HEADER); +#endif /* !NX_DISABLE_IP_INFO */ + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_IO_DRIVER_PACKET_SEND, ip_ptr, packet_ptr, packet_ptr -> nx_packet_length, 0, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + /* Send the IP packet out on the network via the attached driver. */ + (packet_ptr -> nx_packet_ip_interface -> nx_interface_link_driver_entry) (&driver_request); + + /* Done processing Multicast packet. Return to caller. */ + return; + } + + /* If we get here, the packet destination is a unicast address. */ + destination_ip = packet_ptr -> nx_packet_next_hop_address; + + /* 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_ROUTE_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; + driver_request.nx_ip_driver_interface = packet_ptr -> nx_packet_ip_interface; + + /* 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; + +#ifndef NX_DISABLE_FRAGMENTATION + /* Determine if fragmentation is needed. */ + if (packet_ptr -> nx_packet_length > packet_ptr -> nx_packet_ip_interface -> 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 /* !NX_DISABLE_IP_INFO */ + + /* Just release the packet. */ + _nx_packet_transmit_release(packet_ptr); + } + + /* In either case, this packet send is complete, just return. */ + return; + } +#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_IP_HEADER); +#endif /* !NX_DISABLE_IP_INFO */ + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_IO_DRIVER_PACKET_SEND, ip_ptr, packet_ptr, packet_ptr -> nx_packet_length, 0, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + /* Send the IP packet out on the network via the attached driver. */ + (packet_ptr -> nx_packet_ip_interface -> nx_interface_link_driver_entry) (&driver_request); + + /* Return to caller. */ + return; + } + else + { + + /* No physical mapping available. Set 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 = 1; + while (last_packet -> nx_packet_queue_next) + { + + /* Increment the queued count. */ + queued_count++; + + /* Yes, 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 /* !NX_DISABLE_IP_INFO */ + } + + /* 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_ip_interface; + +#ifndef NX_DISABLE_FRAGMENTATION + /* Determine if fragmentation is needed. */ + if (packet_ptr -> nx_packet_length > packet_ptr -> nx_packet_ip_interface -> 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 /* !NX_DISABLE_IP_INFO */ + + /* Just release the packet. */ + _nx_packet_transmit_release(packet_ptr); + } + + /* In either case, this packet send is complete, just return. */ + return; + } +#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_IP_HEADER); +#endif /* !NX_DISABLE_IP_INFO */ + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_IO_DRIVER_PACKET_SEND, ip_ptr, packet_ptr, packet_ptr -> nx_packet_length, 0, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + /* Send the IP packet out on the network via the attached driver. */ + (packet_ptr -> nx_packet_ip_interface -> 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 = 1; + while (last_packet -> nx_packet_queue_next) + { + + /* Increment the queued count. */ + queued_count++; + + /* Yes, 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 /* !NX_DISABLE_IP_INFO */ + } + + /* 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])))) + { + + /* 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 /* !NX_DISABLE_IP_INFO */ + + /* 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_UPDATE_RATE; + arp_ptr -> nx_arp_retries = 0; + arp_ptr -> nx_arp_ip_interface = packet_ptr -> nx_packet_ip_interface; + + /* 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_ip_interface); + return; + } + } + } + else + { + + /* This IP interface does not require any IP-to-physical mapping. */ + + /* 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_ip_interface; + +#ifndef NX_DISABLE_FRAGMENTATION + /* Determine if fragmentation is needed. */ + if (packet_ptr -> nx_packet_length > packet_ptr -> nx_packet_ip_interface -> 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 /* !NX_DISABLE_IP_INFO */ + + /* Just release the packet. */ + _nx_packet_transmit_release(packet_ptr); + } + + /* In either case, this packet send is complete, just return. */ + return; + } +#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_IP_HEADER); +#endif /* !NX_DISABLE_IP_INFO */ + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_IO_DRIVER_PACKET_SEND, ip_ptr, packet_ptr, packet_ptr -> nx_packet_length, 0, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + /* No mapping driver. Just send the packet out! */ + (packet_ptr -> nx_packet_ip_interface -> nx_interface_link_driver_entry) (&driver_request); + } +} + diff --git a/common/src/nx_ip_periodic_timer_entry.c b/common/src/nx_ip_periodic_timer_entry.c new file mode 100644 index 0000000..d6d2483 --- /dev/null +++ b/common/src/nx_ip_periodic_timer_entry.c @@ -0,0 +1,85 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ip_periodic_timer_entry PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function handles waking up the IP helper thread on a periodic */ +/* basis. Periodic IP processing includes ARP requests, IP fragment */ +/* timeouts, and TCP timeouts. All of which are driven from this */ +/* single periodic timer. */ +/* */ +/* INPUT */ +/* */ +/* ip_address IP address in a ULONG */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* tx_event_flags_set Set event flags to wakeup */ +/* IP helper thread */ +/* */ +/* CALLED BY */ +/* */ +/* ThreadX system timer thread */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_ip_periodic_timer_entry(ULONG ip_address) +{ + +NX_IP *ip_ptr; + + + /* Convert input parameter to an IP pointer. */ + ip_ptr = (NX_IP *)ip_address; + + /* Wakeup this IP's helper thread. */ + tx_event_flags_set(&(ip_ptr -> nx_ip_events), NX_IP_PERIODIC_EVENT, TX_OR); +} + diff --git a/common/src/nx_ip_raw_packet_cleanup.c b/common/src/nx_ip_raw_packet_cleanup.c new file mode 100644 index 0000000..20b8ebb --- /dev/null +++ b/common/src/nx_ip_raw_packet_cleanup.c @@ -0,0 +1,160 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "tx_thread.h" +#include "nx_ip.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ip_raw_packet_cleanup PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes raw packet receive timeout and thread */ +/* terminate actions that require the IP data structures to be */ +/* cleaned up to remove the suspended thread. */ +/* */ +/* INPUT */ +/* */ +/* thread_ptr Pointer to suspended thread's */ +/* control block */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _tx_thread_system_resume Resume thread service */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ip_delete Delete IP instance */ +/* _nx_ip_raw_packet_disable Disable raw packet processing */ +/* _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_ip_raw_packet_cleanup(TX_THREAD *thread_ptr NX_CLEANUP_PARAMETER) +{ + +TX_INTERRUPT_SAVE_AREA + +NX_IP *ip_ptr; /* Working IP pointer */ + + NX_CLEANUP_EXTENSION + + /* Setup pointer to the IP control block. */ + ip_ptr = (NX_IP *)thread_ptr -> tx_thread_suspend_control_block; + + /* Disable interrupts to remove the suspended thread from the block pool. */ + TX_DISABLE + + /* Determine if the cleanup is still required. */ + if ((thread_ptr -> tx_thread_suspend_cleanup) && (ip_ptr) && + (ip_ptr -> nx_ip_id == NX_IP_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. */ + ip_ptr -> nx_ip_raw_packet_suspension_list = TX_NULL; + } + else + { + + /* At least one more thread is on the same suspension list. */ + + /* Update the list head pointer. */ + ip_ptr -> nx_ip_raw_packet_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. */ + ip_ptr -> nx_ip_raw_packet_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 packet pool. Setup return error status and + resume the thread. */ + + /* Setup return status. */ + thread_ptr -> tx_thread_suspend_status = NX_NO_PACKET; + + /* 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 +} + diff --git a/common/src/nx_ip_raw_packet_disable.c b/common/src/nx_ip_raw_packet_disable.c new file mode 100644 index 0000000..8d90545 --- /dev/null +++ b/common/src/nx_ip_raw_packet_disable.c @@ -0,0 +1,150 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "tx_thread.h" +#include "nx_ip.h" +#include "nx_packet.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ip_raw_packet_disable PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function disables raw IP packet sending and receiving. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP control block */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_packet_release Release data packet */ +/* _nx_ip_raw_packet_cleanup Release suspended threads */ +/* _tx_thread_system_preempt_check Check for preemption */ +/* tx_mutex_get Get protection mutex */ +/* tx_mutex_put Put protection mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ip_raw_packet_disable(NX_IP *ip_ptr) +{ + +TX_INTERRUPT_SAVE_AREA + +NX_PACKET *current_packet; +NX_PACKET *next_packet; + + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_IP_RAW_PACKET_DISABLE, ip_ptr, 0, 0, 0, NX_TRACE_IP_EVENTS, 0, 0) + + /* Get mutex protection. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Disable interrupts. */ + TX_DISABLE + + /* Disable raw IP packet sending/receiving. */ + ip_ptr -> nx_ip_raw_ip_processing = NX_NULL; + + /* Pickup the head pointer to any raw IP packets queued up. */ + next_packet = ip_ptr -> nx_ip_raw_received_packet_head; + + /* Clear the head and tail pointers. */ + ip_ptr -> nx_ip_raw_received_packet_head = NX_NULL; + ip_ptr -> nx_ip_raw_received_packet_tail = NX_NULL; + ip_ptr -> nx_ip_raw_received_packet_count = 0; + + /* Temporarily disable preemption. */ + _tx_thread_preempt_disable++; + + /* Restore interrupts. */ + TX_RESTORE + + /* Loop to release any queued up raw IP packets. */ + 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); + } + + /* Lift any suspension on RAW IP packet receives. */ + while (ip_ptr -> nx_ip_raw_packet_suspension_list) + { + + /* Release the suspended thread. */ + _nx_ip_raw_packet_cleanup(ip_ptr -> nx_ip_raw_packet_suspension_list NX_CLEANUP_ARGUMENT); + } + + /* Release mutex protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Disable interrupts. */ + TX_DISABLE + + /* Restore preemption. */ + _tx_thread_preempt_disable--; + + /* Restore interrupts. */ + TX_RESTORE + + /* Check for preemption. */ + _tx_thread_system_preempt_check(); + + /* Return a successful status! */ + return(NX_SUCCESS); +} + diff --git a/common/src/nx_ip_raw_packet_enable.c b/common/src/nx_ip_raw_packet_enable.c new file mode 100644 index 0000000..6eeb573 --- /dev/null +++ b/common/src/nx_ip_raw_packet_enable.c @@ -0,0 +1,83 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ip_raw_packet_enable PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets the function pointer to enable raw IP packet */ +/* sending and receiving. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP control block */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ip_raw_packet_enable(NX_IP *ip_ptr) +{ + + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_IP_RAW_PACKET_ENABLE, ip_ptr, 0, 0, 0, NX_TRACE_IP_EVENTS, 0, 0) + + /* Enable raw IP packet sending/receiving. */ + ip_ptr -> nx_ip_raw_ip_processing = _nx_ip_raw_packet_processing; + + /* Return a successful status! */ + return(NX_SUCCESS); +} + diff --git a/common/src/nx_ip_raw_packet_interface_send.c b/common/src/nx_ip_raw_packet_interface_send.c new file mode 100644 index 0000000..514b14b --- /dev/null +++ b/common/src/nx_ip_raw_packet_interface_send.c @@ -0,0 +1,123 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_packet.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ip_raw_packet_interface_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sends a raw IP packet through the specified IP */ +/* interface. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP control block */ +/* packet_ptr Pointer to packet to send */ +/* destination_ip Destination IP address */ +/* interface_index Network interface to use */ +/* type_of_service Type of service for packet */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_ip_packet_send Core IP packet send service */ +/* nx_ip_route_find Find a suitable outgoing */ +/* interface. */ +/* tx_mutex_get Get protection mutex */ +/* tx_mutex_put Put protection mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ip_raw_packet_interface_send(NX_IP *ip_ptr, NX_PACKET *packet_ptr, + ULONG destination_ip, UINT interface_index, ULONG type_of_service) +{ + + + /* Determine if raw IP packet sending/receiving is enabled. */ + if (ip_ptr -> nx_ip_raw_ip_processing) + { + + /* Store interface information into the packet structure. */ + packet_ptr -> nx_packet_ip_interface = &(ip_ptr -> nx_ip_interface[interface_index]); + + /* Get mutex protection. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Figure out a suitable outgoing interface. */ + if (_nx_ip_route_find(ip_ptr, destination_ip, &packet_ptr -> nx_packet_ip_interface, &packet_ptr -> nx_packet_next_hop_address) != NX_SUCCESS) + { + + /* Release the protection on the ARP list. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + return(NX_IP_ADDRESS_ERROR); + } + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_IP_RAW_PACKET_SEND, ip_ptr, packet_ptr, destination_ip, type_of_service, NX_TRACE_IP_EVENTS, 0, 0) + + /* Yes, raw packet sending and receiving is enabled send packet! */ + _nx_ip_packet_send(ip_ptr, packet_ptr, destination_ip, type_of_service, NX_IP_TIME_TO_LIVE, NX_IP_UDP, NX_FRAGMENT_OKAY); + + /* Release mutex protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return a successful status! */ + return(NX_SUCCESS); + } + else + { + + /* Return an error. */ + return(NX_NOT_ENABLED); + } +} + diff --git a/common/src/nx_ip_raw_packet_processing.c b/common/src/nx_ip_raw_packet_processing.c new file mode 100644 index 0000000..bd92c3a --- /dev/null +++ b/common/src/nx_ip_raw_packet_processing.c @@ -0,0 +1,175 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "tx_thread.h" +#include "nx_ip.h" +#include "nx_packet.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ip_raw_packet_processing PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes a received raw IP packet from the */ +/* _nx_ip_packet_receive function and either queues it or gives it to */ +/* the first suspended thread waiting for a raw IP packet. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP control block */ +/* packet_ptr Pointer to packet to send */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _tx_thread_system_resume Resume suspended thread */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ip_packet_receive Packet receive processing */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_ip_raw_packet_processing(NX_IP *ip_ptr, NX_PACKET *packet_ptr) +{ + +TX_INTERRUPT_SAVE_AREA +TX_THREAD *thread_ptr; + + + + /* Determine if there is a thread waiting for the IP packet. If so, just + give the packet to the waiting thread. */ + thread_ptr = ip_ptr -> nx_ip_raw_packet_suspension_list; + if (thread_ptr) + { + + /* Disable interrupts. */ + TX_DISABLE + + /* Yes, a thread is suspended on the raw IP packet queue. */ + + /* 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. */ + ip_ptr -> nx_ip_raw_packet_suspension_list = NX_NULL; + } + else + { + + /* At least one more thread is on the same expiration list. */ + + /* Update the list head pointer. */ + ip_ptr -> nx_ip_raw_packet_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. */ + ip_ptr -> nx_ip_raw_packet_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++; + + /* Restore interrupts. */ + TX_RESTORE + + /* Return this packet pointer to the suspended thread waiting for + a block. */ + *((NX_PACKET **)thread_ptr -> tx_thread_additional_suspend_info) = packet_ptr; + + /* Put return status into the thread control block. */ + thread_ptr -> tx_thread_suspend_status = NX_SUCCESS; + + /* Resume thread. */ + _tx_thread_system_resume(thread_ptr); + } + else + { + + /* Disable interrupts. */ + TX_DISABLE + + /* Otherwise, queue the raw IP packet in a FIFO manner on the raw packet list. */ + + /* Clear the next packet pointer. */ + packet_ptr -> nx_packet_queue_next = NX_NULL; + + /* Determine if the queue is empty. */ + if (ip_ptr -> nx_ip_raw_received_packet_tail) + { + + /* List is not empty, place the raw packet at the end of the raw packet list. */ + (ip_ptr -> nx_ip_raw_received_packet_tail) -> nx_packet_queue_next = packet_ptr; + ip_ptr -> nx_ip_raw_received_packet_tail = packet_ptr; + } + else + { + + /* This is the first entry on the queue so set the head and tail pointers. */ + ip_ptr -> nx_ip_raw_received_packet_head = packet_ptr; + ip_ptr -> nx_ip_raw_received_packet_tail = packet_ptr; + } + + /* Increment the raw packet received count. */ + ip_ptr -> nx_ip_raw_received_packet_count++; + + /* Restore interrupts. */ + TX_RESTORE + } +} + diff --git a/common/src/nx_ip_raw_packet_receive.c b/common/src/nx_ip_raw_packet_receive.c new file mode 100644 index 0000000..be1dc38 --- /dev/null +++ b/common/src/nx_ip_raw_packet_receive.c @@ -0,0 +1,212 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "tx_thread.h" +#include "nx_ip.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ip_raw_packet_receive PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves the first packet from the received raw */ +/* packet list and returns it to the caller. If no packet is present */ +/* the routine may optionally suspend waiting on the list for a */ +/* packet. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP control block pointer */ +/* packet_ptr Pointer to return allocated */ +/* packet */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _tx_thread_system_suspend Suspend thread */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ip_raw_packet_receive(NX_IP *ip_ptr, NX_PACKET **packet_ptr, ULONG wait_option) +{ +TX_INTERRUPT_SAVE_AREA + +UINT status; /* Return status */ +TX_THREAD *thread_ptr; /* Working thread pointer */ +NX_PACKET *work_ptr; /* Working packet pointer */ + +#ifdef TX_ENABLE_EVENT_TRACE +TX_TRACE_BUFFER_ENTRY *trace_event; +ULONG trace_timestamp; +#endif + + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_IP_RAW_PACKET_RECEIVE, ip_ptr, 0, wait_option, 0, NX_TRACE_IP_EVENTS, &trace_event, &trace_timestamp) + + /* Disable interrupts to get a packet from the pool. */ + TX_DISABLE + + /* Determine if there is an available packet. */ + if (ip_ptr -> nx_ip_raw_received_packet_count) + { + + /* Yes, a packet is available. Decrement the raw packet receive count. */ + ip_ptr -> nx_ip_raw_received_packet_count--; + + /* Pickup the first raw packet pointer. */ + work_ptr = ip_ptr -> nx_ip_raw_received_packet_head; + + /* Modify the available list to point at the next packet in the pool. */ + ip_ptr -> nx_ip_raw_received_packet_head = work_ptr -> nx_packet_queue_next; + + /* Determine if the tail pointer points to the same packet. */ + if (ip_ptr -> nx_ip_raw_received_packet_tail == work_ptr) + { + + /* Yes, just set tail pointer to NULL since we must be at the end of the queue. */ + ip_ptr -> nx_ip_raw_received_packet_tail = NX_NULL; + } + + /* Place the raw packet pointer in the return destination. */ + *packet_ptr = work_ptr; + + /* Update the trace event with the status. */ + NX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, NX_TRACE_IP_RAW_PACKET_RECEIVE, 0, *packet_ptr, 0, 0) + + /* Set status to success. */ + status = NX_SUCCESS; + } + else + { + + /* Determine if the request specifies suspension. */ + if (wait_option) + { + + /* Prepare for suspension of this thread. */ + + /* Pickup thread pointer. */ + thread_ptr = _tx_thread_current_ptr; + + /* Setup cleanup routine pointer. */ + thread_ptr -> tx_thread_suspend_cleanup = _nx_ip_raw_packet_cleanup; + + /* Setup cleanup information, i.e. this IP control + block. */ + thread_ptr -> tx_thread_suspend_control_block = (void *)ip_ptr; + + /* Save the return packet pointer address as well. */ + thread_ptr -> tx_thread_additional_suspend_info = (void *)packet_ptr; + + /* Setup suspension list. */ + if (ip_ptr -> nx_ip_raw_packet_suspension_list) + { + + /* This list is not NULL, add current thread to the end. */ + thread_ptr -> tx_thread_suspended_next = + ip_ptr -> nx_ip_raw_packet_suspension_list; + thread_ptr -> tx_thread_suspended_previous = + (ip_ptr -> nx_ip_raw_packet_suspension_list) -> tx_thread_suspended_previous; + ((ip_ptr -> nx_ip_raw_packet_suspension_list) -> tx_thread_suspended_previous) -> tx_thread_suspended_next = + thread_ptr; + (ip_ptr -> nx_ip_raw_packet_suspension_list) -> tx_thread_suspended_previous = thread_ptr; + } + else + { + + /* No other threads are suspended. Setup the head pointer and + just setup this threads pointers to itself. */ + ip_ptr -> nx_ip_raw_packet_suspension_list = thread_ptr; + thread_ptr -> tx_thread_suspended_next = thread_ptr; + thread_ptr -> tx_thread_suspended_previous = thread_ptr; + } + + /* Increment the suspended thread count. */ + ip_ptr -> nx_ip_raw_packet_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); + + /* Update the trace event with the status. */ + NX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, NX_TRACE_IP_RAW_PACKET_RECEIVE, 0, *packet_ptr, 0, 0) + + /* Return the completion status. */ + return(thread_ptr -> tx_thread_suspend_status); + } + else + { + + /* Immediate return, return error completion. */ + status = NX_NO_PACKET; + } + } + + /* Restore interrupts. */ + TX_RESTORE + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nx_ip_raw_packet_send.c b/common/src/nx_ip_raw_packet_send.c new file mode 100644 index 0000000..6d34f35 --- /dev/null +++ b/common/src/nx_ip_raw_packet_send.c @@ -0,0 +1,119 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_packet.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ip_raw_packet_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sends a raw IP packet through the specified IP */ +/* interface. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP control block */ +/* packet_ptr Pointer to packet to send */ +/* destination_ip Destination IP address */ +/* type_of_service Type of service for packet */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_ip_packet_send Core IP packet send service */ +/* nx_ip_route_find Find a suitable outgoing */ +/* interface. */ +/* tx_mutex_get Get protection mutex */ +/* tx_mutex_put Put protection mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ip_raw_packet_send(NX_IP *ip_ptr, NX_PACKET *packet_ptr, + ULONG destination_ip, ULONG type_of_service) +{ + + + /* Determine if raw IP packet sending/receiving is enabled. */ + if (ip_ptr -> nx_ip_raw_ip_processing) + { + + /* Get mutex protection. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Figure out a suitable outgoing interface. */ + if (_nx_ip_route_find(ip_ptr, destination_ip, &packet_ptr -> nx_packet_ip_interface, &packet_ptr -> nx_packet_next_hop_address) != NX_SUCCESS) + { + + /* Release the protection on the ARP list. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + return(NX_IP_ADDRESS_ERROR); + } + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_IP_RAW_PACKET_SEND, ip_ptr, packet_ptr, destination_ip, type_of_service, NX_TRACE_IP_EVENTS, 0, 0) + + /* Yes, raw packet sending and receiving is enabled send packet! */ + _nx_ip_packet_send(ip_ptr, packet_ptr, destination_ip, type_of_service, NX_IP_TIME_TO_LIVE, NX_IP_RAW, NX_FRAGMENT_OKAY); + + /* Release mutex protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return a successful status! */ + return(NX_SUCCESS); + } + else + { + + /* Return an error. */ + return(NX_NOT_ENABLED); + } +} + diff --git a/common/src/nx_ip_route_find.c b/common/src/nx_ip_route_find.c new file mode 100644 index 0000000..cdecef5 --- /dev/null +++ b/common/src/nx_ip_route_find.c @@ -0,0 +1,185 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ip_route_find PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function finds an outgoing interface and the next hop address */ +/* for a given destination address. Caller may also set desired */ +/* interface information in nx_ip_interface parameter. For Multicast */ +/* or limited broadcast, this routine uses primary interface if */ +/* a hint was not set by the caller. For directed broadcast or */ +/* unicast destination, the hint is ignored and the proper outgoing */ +/* interface is selected. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IN Pointer to IP instance */ +/* destination_address IN Destination Address */ +/* nx_ip_interface OUT Interface to use, must point */ +/* to valid storage space. */ +/* next_hop_address OUT IP address for the next hop, */ +/* must point to valid storage */ +/* space. */ +/* */ +/* OUTPUT */ +/* */ +/* status Operation was successful */ +/* or not. */ +/* CALLS */ +/* */ +/* [nx_ip_find_route_process] Search the static routing */ +/* table. */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_arp_dynamic_entry_set.c ARP entry set */ +/* _nx_icmp_ping Transmit ICMP echo request */ +/* _nx_ip_packet_send IP packet transmit */ +/* _nx_tcp_client_socket_connect TCP Client socket connection */ +/* _nx_udp_socket_send UDP packet send */ +/* */ +/* NOTE: */ +/* */ +/* None */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +ULONG _nx_ip_route_find(NX_IP *ip_ptr, ULONG destination_address, NX_INTERFACE **nx_ip_interface, ULONG *next_hop_address) +{ + +NX_INTERFACE *nx_interface; +ULONG i; + + /* Determine whether or not destination_address is multicast or directed broadcast. */ + if (((destination_address & NX_IP_CLASS_D_MASK) == NX_IP_CLASS_D_TYPE) || + (destination_address == NX_IP_LIMITED_BROADCAST)) + { + *next_hop_address = destination_address; + /* If caller did not set the nx_ip_interface value, use + the primary interface for transmission. */ + if (*nx_ip_interface == NX_NULL) + { + *nx_ip_interface = &(ip_ptr -> nx_ip_interface[0]); + } + + return(NX_SUCCESS); + } + + + +#ifdef NX_ENABLE_IP_STATIC_ROUTING + + + /* Search through the routing table, check whether the entry exists or not. */ + for (i = 0; i < ip_ptr -> nx_ip_routing_table_entry_count; i++) + { + if (ip_ptr -> nx_ip_routing_table[i].nx_ip_routing_entry_destination_ip == (destination_address & ip_ptr -> nx_ip_routing_table[i].nx_ip_routing_entry_net_mask)) + { + *nx_ip_interface = ip_ptr -> nx_ip_routing_table[i].nx_ip_routing_entry_ip_interface; + *next_hop_address = ip_ptr -> nx_ip_routing_table[i].nx_ip_routing_entry_next_hop_address; + + return(NX_SUCCESS); + } + } + +#endif /* NX_ENABLE_IP_STATIC_ROUTING */ + + + /* Search through the interfaces associated with the IP instance, + check whether the entry exists or not. */ + for (i = 0; i < NX_MAX_IP_INTERFACES; i++) + { + + nx_interface = &(ip_ptr -> nx_ip_interface[i]); + + /* Does the interface network address match the interface network in the IP table? */ + if ((nx_interface -> nx_interface_valid) && + ((nx_interface -> nx_interface_ip_network_mask & destination_address) == nx_interface -> nx_interface_ip_network)) + { + + /* Yes it does; Is an interface is supplied by the caller? */ + if (*nx_ip_interface == NX_NULL) + { + + /* No, so set it here based on matching IP network address. */ + *nx_ip_interface = nx_interface; + } + + *next_hop_address = destination_address; + return(NX_SUCCESS); + } + } + + /* Match loopback interface, if loopback is enabled. */ +#ifndef NX_DISABLE_LOOPBACK_INTERFACE + if (destination_address == IP_ADDRESS(127, 0, 0, 1)) + { + *nx_ip_interface = &(ip_ptr -> nx_ip_interface[NX_LOOPBACK_INTERFACE]); + *next_hop_address = IP_ADDRESS(127, 0, 0, 1); + + return(NX_SUCCESS); + } + +#endif /* !NX_DISABLE_LOOPBACK_INTERFACE */ + + /* The destination is not directly attached to one of the local interfaces. + Use the default gateway. */ + + if ((ip_ptr -> nx_ip_gateway_address) && (ip_ptr -> nx_ip_gateway_interface)) + { + *next_hop_address = ip_ptr -> nx_ip_gateway_address; + *nx_ip_interface = ip_ptr -> nx_ip_gateway_interface; + + return(NX_SUCCESS); + } + + /* Cannot find a proper way to transmit this packet. + Report failure. */ + + return(NX_IP_ADDRESS_ERROR); +} + diff --git a/common/src/nx_ip_static_route_add.c b/common/src/nx_ip_static_route_add.c new file mode 100644 index 0000000..647e8ba --- /dev/null +++ b/common/src/nx_ip_static_route_add.c @@ -0,0 +1,220 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifndef NX_SOURCE_CODE +#define NX_SOURCE_CODE +#endif + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ip_static_route_add PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function adds a static routing entry to the routing table. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP instance */ +/* network_address Network address, in host byte */ +/* order. */ +/* net_mask Network Mask, in host byte */ +/* order. */ +/* next_hop Next Hop address, in host */ +/* byte order. */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_IP_ADDRESS_ERROR Invalid address input */ +/* NX_OVERFLOW Static routing table full */ +/* NX_NOT_SUPPORTED Static routing not enabled */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get */ +/* tx_mutex_put */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* NOTE: */ +/* */ +/* next hop address must be on the local network. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ip_static_route_add(NX_IP *ip_ptr, ULONG network_address, + ULONG net_mask, ULONG next_hop) +{ + +#ifdef NX_ENABLE_IP_STATIC_ROUTING + +ULONG i; +NX_INTERFACE *nx_ip_interface = NX_NULL; + + + /* Obtain the IP mutex so we can manipulate the internal routing table. */ + /* This routine does not need to be protected by mask off interrupt + because it cannot be invoked from ISR. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Make sure next hop is on one of the interfaces. */ + for (i = 0; i < NX_MAX_IP_INTERFACES; i++) + { + + if (ip_ptr -> nx_ip_interface[i].nx_interface_valid && + ((next_hop & (ip_ptr -> nx_ip_interface[i].nx_interface_ip_network_mask)) == ip_ptr -> nx_ip_interface[i].nx_interface_ip_network)) + { + + nx_ip_interface = &(ip_ptr -> nx_ip_interface[i]); + + /* Break out of the for loop */ + break; + } + } + + /* If no matching interface, return the error status. */ + if (nx_ip_interface == NX_NULL) + { + + /* Unlock the mutex, and return the error status. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + return(NX_IP_ADDRESS_ERROR); + } + + /* Obtain the network address, based on the specified netmask. */ + network_address = network_address & net_mask; + + /* Search through the routing table, check whether the same entry exists. */ + for (i = 0; i < ip_ptr -> nx_ip_routing_table_entry_count; i++) + { + + if (ip_ptr -> nx_ip_routing_table[i].nx_ip_routing_entry_destination_ip == network_address && + ip_ptr -> nx_ip_routing_table[i].nx_ip_routing_entry_net_mask == net_mask) + { + + /* Found the sdeviceame entry: only need to update the next hop field */ + ip_ptr -> nx_ip_routing_table[i].nx_ip_routing_entry_next_hop_address = next_hop; + + /* Update the interface. */ + ip_ptr -> nx_ip_routing_table[i].nx_ip_routing_entry_ip_interface = nx_ip_interface; + + /* All done. Unlock the mutex, and return */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + return(NX_SUCCESS); + } + + /* The more top (MSB) bits are set, the a greater numerical value of the network address, + and the smaller the corresponding network (fewer bits for host IP addresses). + This search gives preference to smaller networks (more top bits set) over + larger networks. */ + if (ip_ptr -> nx_ip_routing_table[i].nx_ip_routing_entry_net_mask <= net_mask) + { + + LONG j; + + /* Check whether the table is full. */ + if (ip_ptr -> nx_ip_routing_table_entry_count == NX_IP_ROUTING_TABLE_SIZE) + { + + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + return NX_OVERFLOW; + } + + /* The entry pointed to by "i" is a larger network (smaller net mask + value). The new entry needs to be inserted before "i". + + To do so, we need to make room for the new entry, by shifting entries i and + after down one slot. */ + + for (j = (LONG)(ip_ptr -> nx_ip_routing_table_entry_count - 1); j >= (LONG)i; j--) + { + + ip_ptr -> nx_ip_routing_table[j + 1].nx_ip_routing_entry_destination_ip = + ip_ptr -> nx_ip_routing_table[j].nx_ip_routing_entry_destination_ip; + ip_ptr -> nx_ip_routing_table[j + 1].nx_ip_routing_entry_net_mask = + ip_ptr -> nx_ip_routing_table[j].nx_ip_routing_entry_net_mask; + ip_ptr -> nx_ip_routing_table[j + 1].nx_ip_routing_entry_next_hop_address = + ip_ptr -> nx_ip_routing_table[j].nx_ip_routing_entry_next_hop_address; + ip_ptr -> nx_ip_routing_table[j + 1].nx_ip_routing_entry_ip_interface = + ip_ptr -> nx_ip_routing_table[j].nx_ip_routing_entry_ip_interface; + } + break; + } + } + + /* Check whether the table is full. */ + if (i == NX_IP_ROUTING_TABLE_SIZE) + { + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + return(NX_OVERFLOW); + } + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_IP_STATIC_ROUTE_ADD, ip_ptr, network_address, net_mask, next_hop, NX_TRACE_IP_EVENTS, 0, 0); + + ip_ptr -> nx_ip_routing_table[i].nx_ip_routing_entry_destination_ip = network_address; + ip_ptr -> nx_ip_routing_table[i].nx_ip_routing_entry_net_mask = net_mask; + ip_ptr -> nx_ip_routing_table[i].nx_ip_routing_entry_next_hop_address = next_hop; + ip_ptr -> nx_ip_routing_table[i].nx_ip_routing_entry_ip_interface = nx_ip_interface; + + ip_ptr -> nx_ip_routing_table_entry_count++; + + /* Unlock the mutex. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return success to the caller. */ + return(NX_SUCCESS); + +#else /* !NX_ENABLE_IP_STATIC_ROUTING */ + NX_PARAMETER_NOT_USED(ip_ptr); + NX_PARAMETER_NOT_USED(network_address); + NX_PARAMETER_NOT_USED(net_mask); + NX_PARAMETER_NOT_USED(next_hop); + + return(NX_NOT_SUPPORTED); +#endif /* NX_ENABLE_IP_STATIC_ROUTING */ +} + diff --git a/common/src/nx_ip_static_route_delete.c b/common/src/nx_ip_static_route_delete.c new file mode 100644 index 0000000..a4c014b --- /dev/null +++ b/common/src/nx_ip_static_route_delete.c @@ -0,0 +1,165 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifndef NX_SOURCE_CODE +#define NX_SOURCE_CODE +#endif + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ip_static_route_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function deletes static routing entry from the routing table. */ +/* If static routing is not enabled, an error status is returned. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP instance */ +/* network_address network address, in host byte */ +/* order. */ +/* net_mask Network Mask, in host byte */ +/* order. */ +/* */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_NOT_SUPPORTED Static routing not enabled */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get */ +/* tx_mutex_put */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* NOTE: */ +/* */ +/* None */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ip_static_route_delete(NX_IP *ip_ptr, ULONG network_address, ULONG net_mask) +{ + + +#ifdef NX_ENABLE_IP_STATIC_ROUTING + +ULONG i; +UINT found_match = NX_FALSE; +UINT status = NX_NOT_SUCCESSFUL; + + + network_address = network_address & net_mask; + + /* Obtain the IP mutex so we can manipulate the internal routing table. */ + /* This routine does not need to be protected by mask off interrupt + because it cannot be invoked from ISR. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_IP_STATIC_ROUTE_DELETE, ip_ptr, network_address, net_mask, 0, NX_TRACE_IP_EVENTS, 0, 0); + + /* Check whether the table is empty. */ + if (ip_ptr -> nx_ip_routing_table_entry_count == 0) + { + + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + return NX_SUCCESS; + } + + /* Search through the routing table, check whether the same entry exists. */ + for (i = 0; i < ip_ptr -> nx_ip_routing_table_entry_count; i++) + { + + if ((ip_ptr -> nx_ip_routing_table[i].nx_ip_routing_entry_destination_ip == network_address) && + (ip_ptr -> nx_ip_routing_table[i].nx_ip_routing_entry_net_mask == net_mask)) + { + + ULONG j; + + /* Found the entry. */ + found_match = NX_TRUE; + + /* If the entry is not the last one, we need to shift to the + reset of the table to fill the hole. */ + for (j = i; j < ip_ptr -> nx_ip_routing_table_entry_count; j++) + { + + ip_ptr -> nx_ip_routing_table[j].nx_ip_routing_entry_destination_ip = ip_ptr -> nx_ip_routing_table[j + 1].nx_ip_routing_entry_destination_ip; + ip_ptr -> nx_ip_routing_table[j].nx_ip_routing_entry_net_mask = ip_ptr -> nx_ip_routing_table[j + 1].nx_ip_routing_entry_net_mask; + ip_ptr -> nx_ip_routing_table[j].nx_ip_routing_entry_next_hop_address = ip_ptr -> nx_ip_routing_table[j + 1].nx_ip_routing_entry_next_hop_address; + } + ip_ptr -> nx_ip_routing_table[j - 1].nx_ip_routing_entry_destination_ip = 0; + ip_ptr -> nx_ip_routing_table[j - 1].nx_ip_routing_entry_net_mask = 0; + ip_ptr -> nx_ip_routing_table[j - 1].nx_ip_routing_entry_next_hop_address = 0; + + break; + } + } + + /* Don't forget to decrease table count if we were + able to delete the requested static route. */ + if (found_match) + { + + ip_ptr -> nx_ip_routing_table_entry_count--; + + /* Indicate successful deletion. */ + status = NX_SUCCESS; + } + + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return outcome status to the caller. */ + return status; +#else /* !NX_ENABLE_IP_STATIC_ROUTING */ + NX_PARAMETER_NOT_USED(ip_ptr); + NX_PARAMETER_NOT_USED(network_address); + NX_PARAMETER_NOT_USED(net_mask); + + return(NX_NOT_SUPPORTED); +#endif /* NX_ENABLE_IP_STATIC_ROUTING */ +} + diff --git a/common/src/nx_ip_status_check.c b/common/src/nx_ip_status_check.c new file mode 100644 index 0000000..8431874 --- /dev/null +++ b/common/src/nx_ip_status_check.c @@ -0,0 +1,84 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ip_status_check PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function polls using thread sleep for the necessary conditions */ +/* in the IP instance. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP instance */ +/* needed_status Status needed request */ +/* actual_status Pointer to return status area */ +/* wait_option Maximum suspension time */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* (ip_link_driver) User supplied link driver */ +/* tx_mutex_get Get protection mutex */ +/* tx_mutex_put Put protection mutex */ +/* tx_thread_sleep Sleep until events are */ +/* satisfied */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_ip_status_check(NX_IP *ip_ptr, ULONG needed_status, ULONG *actual_status, + ULONG wait_option) +{ + + /* Call nx_ip_interface_status_check to perform the status check. */ + return(_nx_ip_interface_status_check(ip_ptr, 0, needed_status, actual_status, wait_option)); +} + diff --git a/common/src/nx_ip_thread_entry.c b/common/src/nx_ip_thread_entry.c new file mode 100644 index 0000000..f23b6bd --- /dev/null +++ b/common/src/nx_ip_thread_entry.c @@ -0,0 +1,454 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_packet.h" +#include "nx_arp.h" +#include "nx_icmp.h" +#include "nx_igmp.h" +#include "nx_tcp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ip_thread_entry PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is the entry point for each IP's helper thread. The */ +/* IP helper thread is responsible for periodic ARP requests, */ +/* reassembling fragmented IP messages, and helping with TCP */ +/* protocol. */ +/* */ +/* Note that the priority of this function is determined by the IP */ +/* create service. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr_value Pointer to IP 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_ip_driver_deferred_packet_handler)Optional deferred packet */ +/* processing routine */ +/* _nx_ip_packet_receive IP receive packet processing */ +/* (nx_arp_queue_process) ARP receive queue processing */ +/* (nx_ip_arp_periodic_update) ARP periodic update processing*/ +/* (nx_ip_rarp_periodic_update) RARP periodic processing */ +/* (nx_ip_fragment_assembly) IP fragment processing */ +/* (nx_ip_fragment_timeout_check) Fragment timeout checking */ +/* (nx_ip_icmp_queue_process) ICMP message queue processing */ +/* (nx_ip_igmp_queue_process) IGMP message queue processing */ +/* (nx_ip_igmp_periodic_processing) IGMP periodic processing */ +/* (nx_ip_tcp_queue_process) TCP message queue processing */ +/* (nx_ip_tcp_periodic_processing) TCP periodic processing */ +/* (nx_tcp_deferred_cleanup_check) TCP deferred cleanup check */ +/* (ip_link_driver) User supplied link driver */ +/* */ +/* CALLED BY */ +/* */ +/* ThreadX Scheduler */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_ip_thread_entry(ULONG ip_ptr_value) +{ + +TX_INTERRUPT_SAVE_AREA + +NX_IP_DRIVER driver_request; +NX_IP *ip_ptr; +ULONG ip_events; +NX_PACKET *packet_ptr; +UINT i; +ULONG foo; + + + /* Setup IP pointer from the input value. */ + ip_ptr = (NX_IP *)ip_ptr_value; + + /* Obtain the IP internal mutex before calling the driver. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + + /* Set the IP initialization done flag to true. */ + ip_ptr -> nx_ip_initialize_done = NX_TRUE; + + /* Loop through all physical interfaces to initialize and enable the hardware. */ + for (i = 0; i < NX_MAX_PHYSICAL_INTERFACES; i++) + { + + /* Is this a valid interface with a link driver associated with it? */ + if ((ip_ptr -> nx_ip_interface[i].nx_interface_valid) && (ip_ptr -> nx_ip_interface[i].nx_interface_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 = &(ip_ptr -> nx_ip_interface[i]); + (ip_ptr -> nx_ip_interface[i].nx_interface_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; + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_IO_DRIVER_INITIALIZE, ip_ptr, 0, 0, 0, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + /* + When an IP instance is created, the first interface (nx_ip_interface[0]) is configured using parameters + provided in the IP create call. + + When IP thread runs, it invokes the first interface link driver for link initialization. + */ + (ip_ptr -> nx_ip_interface[i].nx_interface_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; + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_IO_DRIVER_LINK_ENABLE, ip_ptr, 0, 0, 0, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + (ip_ptr -> nx_ip_interface[i].nx_interface_link_driver_entry) (&driver_request); + } + } + + /* Loop indefinately and process events for this IP instance. */ + while (1) + { + + /* Release the IP internal mutex. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Pickup IP event flags. */ + tx_event_flags_get(&(ip_ptr -> nx_ip_events), NX_IP_ALL_EVENTS, TX_OR_CLEAR, &ip_events, TX_WAIT_FOREVER); + + /* Obtain the IP internal mutex before processing the IP event. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + +#ifdef NX_DRIVER_DEFERRED_PROCESSING + /* Check for any packets deferred by the Driver. */ + if (ip_events & NX_IP_DRIVER_PACKET_EVENT) + { + + /* Loop to process all deferred packet requests. */ + while (ip_ptr -> nx_ip_driver_deferred_packet_head) + { + /* Remove the first packet and process it! */ + + /* Disable interrupts. */ + TX_DISABLE + + /* Pickup the first packet. */ + packet_ptr = ip_ptr -> nx_ip_driver_deferred_packet_head; + + /* Move the head pointer to the next packet. */ + ip_ptr -> nx_ip_driver_deferred_packet_head = packet_ptr -> nx_packet_queue_next; + + /* Check for end of deferred processing queue. */ + if (ip_ptr -> nx_ip_driver_deferred_packet_head == NX_NULL) + { + + /* Yes, the queue is empty. Set the tail pointer to NULL. */ + ip_ptr -> nx_ip_driver_deferred_packet_tail = NX_NULL; + } + + /* Restore interrupts. */ + TX_RESTORE + + /* make sure that there is a deferred processing function */ + if (ip_ptr -> nx_ip_driver_deferred_packet_handler) + { + /* Call the actual Deferred packet processing function. */ + (ip_ptr -> nx_ip_driver_deferred_packet_handler)(ip_ptr, packet_ptr); + } + } + + /* Determine if there is anything else to do in the loop. */ + ip_events = ip_events & ~(NX_IP_DRIVER_PACKET_EVENT); + if (!ip_events) + { + continue; + } + } +#endif + + /* Check for an IP receive packet event. */ + if (ip_events & NX_IP_RECEIVE_EVENT) + { + + /* Loop to process all deferred packet requests. */ + while (ip_ptr -> nx_ip_deferred_received_packet_head) + { + + /* Remove the first packet and process it! */ + + /* Disable interrupts. */ + TX_DISABLE + + /* Pickup the first packet. */ + packet_ptr = ip_ptr -> nx_ip_deferred_received_packet_head; + + /* Move the head pointer to the next packet. */ + ip_ptr -> nx_ip_deferred_received_packet_head = packet_ptr -> nx_packet_queue_next; + + /* Check for end of deferred processing queue. */ + if (ip_ptr -> nx_ip_deferred_received_packet_head == NX_NULL) + { + + /* Yes, the queue is empty. Set the tail pointer to NULL. */ + ip_ptr -> nx_ip_deferred_received_packet_tail = NX_NULL; + } + + /* Restore interrupts. */ + TX_RESTORE + + /* Call the actual IP packet receive function. */ + _nx_ip_packet_receive(ip_ptr, packet_ptr); + } + + /* Determine if there is anything else to do in the loop. */ + ip_events = ip_events & ~(NX_IP_RECEIVE_EVENT); + if (!ip_events) + { + continue; + } + } + + /* Check for a TCP message event. */ + if (ip_events & NX_IP_TCP_EVENT) + { + + /* Process the TCP packet queue. */ + (ip_ptr -> nx_ip_tcp_queue_process)(ip_ptr); + + /* Determine if there is anything else to do in the loop. */ + ip_events = ip_events & ~(NX_IP_TCP_EVENT); + if (!ip_events) + { + continue; + } + } + + /* Check for a fast TCP event. */ + if ((ip_events & NX_IP_TCP_FAST_EVENT) && (ip_ptr -> nx_ip_tcp_fast_periodic_processing)) + { + + /* Process the fast TCP processing. */ + (ip_ptr -> nx_ip_tcp_fast_periodic_processing)(ip_ptr); + + /* Determine if there is anything else to do in the loop. */ + ip_events = ip_events & ~(NX_IP_TCP_FAST_EVENT); + + if (!ip_events) + { + continue; + } + } + + /* Check for a periodic events. */ + if (ip_events & NX_IP_PERIODIC_EVENT) + { + + /* Process the ARP periodic update, if ARP has been enabled. */ + if (ip_ptr -> nx_ip_arp_periodic_update) + { + (ip_ptr -> nx_ip_arp_periodic_update)(ip_ptr); + } + + /* Process the RARP periodic update, if RARP has been enabled. */ + if (ip_ptr -> nx_ip_rarp_periodic_update) + { + (ip_ptr -> nx_ip_rarp_periodic_update)(ip_ptr); + } + +#ifndef NX_DISABLE_FRAGMENTATION + /* Process IP fragmentation timeouts, if IP fragmenting has been + enabled. */ + if (ip_ptr -> nx_ip_fragment_timeout_check) + { + (ip_ptr -> nx_ip_fragment_timeout_check)(ip_ptr); + } +#endif + /* Process IGMP periodic events, if IGMP has been enabled. */ + if (ip_ptr -> nx_ip_igmp_periodic_processing) + { + (ip_ptr -> nx_ip_igmp_periodic_processing)(ip_ptr); + } + + /* Process TCP periodic events, if TCP has been enabled. */ + if (ip_ptr -> nx_ip_tcp_periodic_processing) + { + (ip_ptr -> nx_ip_tcp_periodic_processing)(ip_ptr); + } + + /* Determine if there is anything else to do in the loop. */ + ip_events = ip_events & ~(NX_IP_PERIODIC_EVENT); + + if (!ip_events) + { + continue; + } + } + + /* Check for an ARP receive packet event. */ + if ((ip_events & NX_IP_ARP_REC_EVENT) && (ip_ptr -> nx_ip_arp_queue_process)) + { + + /* Process the ARP queue. */ + (ip_ptr -> nx_ip_arp_queue_process)(ip_ptr); + } + + /* Check for an RARP receive packet event. */ + if ((ip_events & NX_IP_RARP_REC_EVENT) && (ip_ptr -> nx_ip_rarp_queue_process)) + { + + /* Process the RARP queue. */ + (ip_ptr -> nx_ip_rarp_queue_process)(ip_ptr); + } +#ifndef NX_DISABLE_FRAGMENTATION + /* Check for an IP unfragment event. */ + if (ip_events & NX_IP_UNFRAG_EVENT) + { + + /* Process the IP fragment reassemble. */ + (ip_ptr -> nx_ip_fragment_assembly)(ip_ptr); + } +#endif + + /* Check for an ICMP message event. */ + if (ip_events & NX_IP_ICMP_EVENT) + { + + /* Process the ICMP packet queue. */ + (ip_ptr -> nx_ip_icmp_queue_process)(ip_ptr); + } + + /* Check for an IGMP message event. */ + if (ip_events & NX_IP_IGMP_EVENT) + { + + /* Process the ICMP packet queue. */ + (ip_ptr -> nx_ip_igmp_queue_process)(ip_ptr); + } + + /* Check for an IGMP enable event. */ + if (ip_events & NX_IP_IGMP_ENABLE_EVENT) + { + + /* Call the associated driver for this IP instance to register the "all hosts" + multicast address. */ + for (i = 0; i < NX_MAX_PHYSICAL_INTERFACES; i++) + { + /* Enable the hardware for IGMP for all valid interfaces. */ + if (ip_ptr -> nx_ip_interface[i].nx_interface_valid) + { + driver_request.nx_ip_driver_ptr = ip_ptr; + driver_request.nx_ip_driver_command = NX_LINK_MULTICAST_JOIN; + driver_request.nx_ip_driver_physical_address_msw = NX_IP_MULTICAST_UPPER; + driver_request.nx_ip_driver_physical_address_lsw = NX_IP_MULTICAST_LOWER | (NX_ALL_HOSTS_ADDRESS & NX_IP_MULTICAST_MASK); + driver_request.nx_ip_driver_interface = &(ip_ptr -> nx_ip_interface[i]); + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_IO_DRIVER_MULTICAST_JOIN, ip_ptr, 0, 0, 0, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + (ip_ptr -> nx_ip_interface[0].nx_interface_link_driver_entry) (&driver_request); + } + } + } + + /* Check for a deferred processing request from the driver. */ + if (ip_events & NX_IP_DRIVER_DEFERRED_EVENT) + { + + int index; + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_IO_DRIVER_DEFERRED_PROCESSING, ip_ptr, 0, 0, 0, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + /* Go through each valid interface. */ + for (index = 0; index < NX_MAX_PHYSICAL_INTERFACES; index++) + { + if (ip_ptr -> nx_ip_interface[index].nx_interface_valid) + { + + /* Yes, there is a deferred processing event from the driver. The only valid information + fields are the IP pointer and the command. */ + driver_request.nx_ip_driver_ptr = ip_ptr; + driver_request.nx_ip_driver_command = NX_LINK_DEFERRED_PROCESSING; + driver_request.nx_ip_driver_interface = &(ip_ptr -> nx_ip_interface[index]); + driver_request.nx_ip_driver_return_ptr = &foo; + + (ip_ptr -> nx_ip_interface[index].nx_interface_link_driver_entry)(&driver_request); + } + } + } + + /* Check for a deferred TCP cleanup processing request from the driver. */ + if (ip_events & NX_IP_TCP_CLEANUP_DEFERRED) + { + + /* Yes, there is a deferred cleanup processing event. Call the TCP deferred cleanup + processing function. */ + (ip_ptr -> nx_tcp_deferred_cleanup_check)(ip_ptr); + } + + /* Check for a link status change request from the driver. */ + if (ip_events & NX_IP_LINK_STATUS_EVENT) + { + + /* Yes, there is a link status change event. Call the deferred link status processing function. */ + _nx_ip_deferred_link_status_process(ip_ptr); + } + } +} + diff --git a/common/src/nx_packet_allocate.c b/common/src/nx_packet_allocate.c new file mode 100644 index 0000000..b8a9ff1 --- /dev/null +++ b/common/src/nx_packet_allocate.c @@ -0,0 +1,240 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Packet Pool Management (Packet) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "tx_thread.h" +#include "nx_packet.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_packet_allocate PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function allocates the first packet from the specified packet */ +/* pool. */ +/* */ +/* INPUT */ +/* */ +/* pool_ptr Pool to allocate packet from */ +/* packet_ptr Pointer to place allocated */ +/* packet pointer */ +/* packet_type Type of packet to allocate */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _tx_thread_system_suspend Suspend thread */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_packet_allocate(NX_PACKET_POOL *pool_ptr, NX_PACKET **packet_ptr, + ULONG packet_type, ULONG wait_option) +{ +TX_INTERRUPT_SAVE_AREA + +UINT status; /* Return status */ +TX_THREAD *thread_ptr; /* Working thread pointer */ +NX_PACKET *work_ptr; /* Working packet pointer */ + +#ifdef TX_ENABLE_EVENT_TRACE +TX_TRACE_BUFFER_ENTRY *trace_event; +ULONG trace_timestamp; +#endif + + + /* Make sure the packet_type does not go beyond nx_packet_data_end. */ + if (pool_ptr -> nx_packet_pool_payload_size < packet_type) + { + return(NX_INVALID_PARAMETERS); + } + + /* Set the return pointer to NULL initially. */ + *packet_ptr = NX_NULL; + + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_PACKET_ALLOCATE, pool_ptr, 0, packet_type, pool_ptr -> nx_packet_pool_available, NX_TRACE_PACKET_EVENTS, &trace_event, &trace_timestamp) + + /* Disable interrupts to get a packet from the pool. */ + TX_DISABLE + + /* Determine if there is an available packet. */ + if (pool_ptr -> nx_packet_pool_available) + { + + /* Yes, a packet is available. Decrement the available count. */ + pool_ptr -> nx_packet_pool_available--; + + /* Pickup the current packet pointer. */ + work_ptr = pool_ptr -> nx_packet_pool_available_list; + + /* Modify the available list to point at the next packet in the pool. */ + pool_ptr -> nx_packet_pool_available_list = work_ptr -> nx_packet_next; + + /* Setup various fields for this packet. */ + work_ptr -> nx_packet_next = NX_NULL; + work_ptr -> nx_packet_queue_next = NX_NULL; + work_ptr -> nx_packet_last = NX_NULL; + work_ptr -> nx_packet_length = 0; + work_ptr -> nx_packet_prepend_ptr = work_ptr -> nx_packet_data_start + packet_type; + work_ptr -> nx_packet_append_ptr = work_ptr -> nx_packet_prepend_ptr; + work_ptr -> nx_packet_ip_interface = NX_NULL; + work_ptr -> nx_packet_next_hop_address = NX_NULL; + /* Set the TCP queue to the value that indicates it has been allocated. */ + work_ptr -> nx_packet_tcp_queue_next = (NX_PACKET *)NX_PACKET_ALLOCATED; + + /* Place the new packet pointer in the return destination. */ + *packet_ptr = work_ptr; + + /* Set status to success. */ + status = NX_SUCCESS; + } + else + { + +#ifndef NX_DISABLE_PACKET_INFO + /* Increment the packet pool empty request count. */ + pool_ptr -> nx_packet_pool_empty_requests++; +#endif + + /* Determine if the request specifies suspension. */ + if (wait_option) + { + + /* Prepare for suspension of this thread. */ + +#ifndef NX_DISABLE_PACKET_INFO + /* Increment the packet pool empty request suspension count. */ + pool_ptr -> nx_packet_pool_empty_suspensions++; +#endif + + /* Pickup thread pointer. */ + thread_ptr = _tx_thread_current_ptr; + + /* Setup cleanup routine pointer. */ + thread_ptr -> tx_thread_suspend_cleanup = _nx_packet_pool_cleanup; + + /* Setup cleanup information, i.e. this pool control + block. */ + thread_ptr -> tx_thread_suspend_control_block = (void *)pool_ptr; + + /* Save the return packet pointer address as well. */ + thread_ptr -> tx_thread_additional_suspend_info = (void *)packet_ptr; + + /* Save the packet type (or prepend offset) so this can be added + after a new packet becomes available. */ + thread_ptr -> tx_thread_suspend_info = packet_type; + + /* Setup suspension list. */ + if (pool_ptr -> nx_packet_pool_suspension_list) + { + + /* This list is not NULL, add current thread to the end. */ + thread_ptr -> tx_thread_suspended_next = + pool_ptr -> nx_packet_pool_suspension_list; + thread_ptr -> tx_thread_suspended_previous = + (pool_ptr -> nx_packet_pool_suspension_list) -> tx_thread_suspended_previous; + ((pool_ptr -> nx_packet_pool_suspension_list) -> tx_thread_suspended_previous) -> tx_thread_suspended_next = + thread_ptr; + (pool_ptr -> nx_packet_pool_suspension_list) -> tx_thread_suspended_previous = thread_ptr; + } + else + { + + /* No other threads are suspended. Setup the head pointer and + just setup this threads pointers to itself. */ + pool_ptr -> nx_packet_pool_suspension_list = thread_ptr; + thread_ptr -> tx_thread_suspended_next = thread_ptr; + thread_ptr -> tx_thread_suspended_previous = thread_ptr; + } + + /* Increment the suspended thread count. */ + pool_ptr -> nx_packet_pool_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); + + /* Update the trace event with the status. */ + NX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, NX_TRACE_PACKET_ALLOCATE, 0, *packet_ptr, 0, 0) + + /* Return the completion status. */ + return(thread_ptr -> tx_thread_suspend_status); + } + else + { + + /* Immediate return, return error completion. */ + status = NX_NO_PACKET; + } + } + + /* Restore interrupts. */ + TX_RESTORE + + /* Update the trace event with the status. */ + NX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, NX_TRACE_PACKET_ALLOCATE, 0, *packet_ptr, 0, 0) + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nx_packet_copy.c b/common/src/nx_packet_copy.c new file mode 100644 index 0000000..23936a4 --- /dev/null +++ b/common/src/nx_packet_copy.c @@ -0,0 +1,175 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Packet Pool Management (Packet) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_packet.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_packet_copy PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function copies the specified packet into one or more packets */ +/* allocated from the specified packet pool. */ +/* */ +/* INPUT */ +/* */ +/* packet_ptr Pointer to source packet */ +/* new_packet_ptr Pointer for return packet */ +/* pool_ptr Pointer to packet pool to use */ +/* for new packet(s) */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_packet_allocate Allocate data packet */ +/* _nx_packet_data_append Packet data append service */ +/* _nx_packet_release Release data packet */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_packet_copy(NX_PACKET *packet_ptr, NX_PACKET **new_packet_ptr, + NX_PACKET_POOL *pool_ptr, ULONG wait_option) +{ + +NX_PACKET *work_ptr; /* Working packet pointer */ +NX_PACKET *source_ptr; /* Source packet pointer */ +ULONG size; /* Packet data size */ +UINT status; /* Return status */ + +#ifdef TX_ENABLE_EVENT_TRACE +TX_TRACE_BUFFER_ENTRY *trace_event; +ULONG trace_timestamp; +#endif + + + /* Default the return packet pointer to NULL. */ + *new_packet_ptr = NX_NULL; + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_PACKET_COPY, packet_ptr, 0, pool_ptr, wait_option, NX_TRACE_PACKET_EVENTS, &trace_event, &trace_timestamp) + + /* Determine if there is anything to copy. */ + if (!packet_ptr -> nx_packet_length) + { + + /* Empty source packet, return an error. */ + return(NX_INVALID_PACKET); + } + + /* Allocate a new packet from the default packet pool supplied. */ + status = _nx_packet_allocate(pool_ptr, &work_ptr, + (ULONG)(packet_ptr -> nx_packet_prepend_ptr - packet_ptr -> nx_packet_data_start), wait_option); + + /* Determine if the packet was not allocated. */ + if (status != NX_SUCCESS) + { + + /* Return the error code from the packet allocate routine. */ + return(status); + } + + /* Copy the packet interface information. */ + work_ptr -> nx_packet_ip_interface = packet_ptr -> nx_packet_ip_interface; + + /* Copy the packet next hop address */ + work_ptr -> nx_packet_next_hop_address = packet_ptr -> nx_packet_next_hop_address; + + /* Save the source packet pointer. */ + source_ptr = packet_ptr; + + /* Loop to copy the original packet's data. */ + do + { + + /* Calculate this packet's data size. */ + size = (ULONG)(packet_ptr -> nx_packet_append_ptr - packet_ptr -> nx_packet_prepend_ptr); + + /* Copy the data from the source packet into the new packet using + the data append feature. */ + status = _nx_packet_data_append(work_ptr, packet_ptr -> nx_packet_prepend_ptr, size, pool_ptr, wait_option); + + /* Determine if there was an error in the data append. */ + if (status != NX_SUCCESS) + { + + /* An error is present, release the new packet. */ + _nx_packet_release(work_ptr); + + /* Return the error code from the packet data append service. */ + return(status); + } + + /* Move to the next packet in the packet chain. */ + packet_ptr = packet_ptr -> nx_packet_next; + } while (packet_ptr); + + /* Determine if the packet copy was successful. */ + if (source_ptr -> nx_packet_length != work_ptr -> nx_packet_length) + { + + /* An error is present, release the new packet. */ + _nx_packet_release(work_ptr); + + /* Return an error code. */ + return(NX_INVALID_PACKET); + } + else + { + + /* Everything is okay, return the new packet pointer. */ + *new_packet_ptr = work_ptr; + + /* Update the trace event with the status. */ + NX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, NX_TRACE_PACKET_COPY, 0, work_ptr, 0, 0) + + /* Return success status. */ + return(NX_SUCCESS); + } +} + diff --git a/common/src/nx_packet_data_append.c b/common/src/nx_packet_data_append.c new file mode 100644 index 0000000..e31fc55 --- /dev/null +++ b/common/src/nx_packet_data_append.c @@ -0,0 +1,260 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Packet Pool Management (Packet) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_packet.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_packet_data_append PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function copies the specified data to the end of the specified */ +/* packet. Additional packets are allocated from the specified pool */ +/* if needed. */ +/* */ +/* INPUT */ +/* */ +/* packet_ptr Pointer to packet to append to*/ +/* data_start Pointer to start of the data */ +/* data_size Number of bytes to append */ +/* pool_ptr Pool to allocate packet from */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_packet_allocate Allocate data packet */ +/* _nx_packet_release Release data packet */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_packet_data_append(NX_PACKET *packet_ptr, VOID *data_start, ULONG data_size, + NX_PACKET_POOL *pool_ptr, ULONG wait_option) +{ + +UINT status; /* Return status */ +ULONG available_bytes; /* Number of available bytes */ +ULONG copy_size; /* Size for each memory copy */ +UCHAR *source_ptr; /* Buffer source pointer */ +NX_PACKET *work_ptr; /* Working packet pointer */ +NX_PACKET *new_list_ptr; /* Head of new list pointer */ +NX_PACKET *last_packet = NX_NULL; /* Last supplied packet */ + + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_PACKET_DATA_APPEND, packet_ptr, data_start, data_size, pool_ptr, NX_TRACE_PACKET_EVENTS, 0, 0) + + /* Calculate the number of bytes available at the end of the supplied packet. */ + if (packet_ptr -> nx_packet_last) + { + + /* More than one packet. Walk the packet chain starting at the last packet + to calculate the remaining bytes. */ + available_bytes = 0; + work_ptr = packet_ptr -> nx_packet_last; + do + { + + /* Calculate the available bytes in this packet. */ + available_bytes = available_bytes + (ULONG)(work_ptr -> nx_packet_data_end - work_ptr -> nx_packet_append_ptr); + + /* Remember the last packet. */ + last_packet = work_ptr; + + /* Move to the next packet. There typically won't be another packet, but just in + case the logic is here for it! */ + work_ptr = work_ptr -> nx_packet_next; + } while (work_ptr); + } + else + { + + /* Just calculate the number of bytes available in the first packet. */ + available_bytes = (ULONG)(packet_ptr -> nx_packet_data_end - packet_ptr -> nx_packet_append_ptr); + } + + /* Determine if any new packets are required to satisfy this request. */ + if (available_bytes < data_size) + { + + /* Setup a temporary head pointer. */ + new_list_ptr = NX_NULL; + + /* Loop to pickup enough packets to complete the append request. */ + while (available_bytes < data_size) + { + + /* Allocate a new packet. */ + status = _nx_packet_allocate(pool_ptr, &work_ptr, 0, wait_option); + + /* Determine if an error is present. */ + if (status) + { + + /* Yes, an error is present. */ + + /* First release any packets that have been allocated so far. */ + while (new_list_ptr) + { + /* Prepare to release the packet. */ + work_ptr = new_list_ptr; + new_list_ptr = new_list_ptr -> nx_packet_next; + + /* Release the packet. */ + _nx_packet_release(work_ptr); + } + + /* Return the error status to the caller of this service. */ + return(status); + } + + /* No error is present. Link the new packet to the temporary list being built. */ + if (new_list_ptr) + { + + /* Determine if there is already more than one packet on the list. */ + if (new_list_ptr -> nx_packet_last) + { + + /* Yes, link up the last packet to the new packet and update the + last pointer. */ + (new_list_ptr -> nx_packet_last) -> nx_packet_next = work_ptr; + new_list_ptr -> nx_packet_last = work_ptr; + } + else + { + + /* Second packet allocated. Just setup the last and next in the + head pointer. */ + new_list_ptr -> nx_packet_last = work_ptr; + new_list_ptr -> nx_packet_next = work_ptr; + } + } + else + { + + /* Just setup the temporary list head. */ + new_list_ptr = work_ptr; + } + + /* Adjust the number of available bytes according to how much space + is in the new packet. */ + available_bytes = available_bytes + (ULONG)(work_ptr -> nx_packet_data_end - work_ptr -> nx_packet_append_ptr); + } + + /* At this point, all the necessary packets have been allocated and are present + on the temporary list. We need to link this new list to the end of the supplied + packet. */ + if (last_packet) + { + + /* Already more than one packet. Add the new packet list to the end. */ + last_packet -> nx_packet_next = new_list_ptr; + } + else + { + + /* Link the new packet list to the head packet. */ + packet_ptr -> nx_packet_next = new_list_ptr; + } + + /* Clear the last packet that was used to maintain the new list. */ + new_list_ptr -> nx_packet_last = NX_NULL; + } + + /* Setup the new data length in the packet. */ + packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length + data_size; + + /* Now copy the supplied data buffer at the end of the packet. */ + source_ptr = (UCHAR *)data_start; + if (packet_ptr -> nx_packet_last) + { + work_ptr = packet_ptr -> nx_packet_last; + } + else + { + work_ptr = packet_ptr; + } + while (data_size) + { + + /* Determine the amount of memory to copy. */ + if (data_size < (ULONG)(work_ptr -> nx_packet_data_end - work_ptr -> nx_packet_append_ptr)) + { + copy_size = data_size; + } + else + { + copy_size = (ULONG)(work_ptr -> nx_packet_data_end - work_ptr -> nx_packet_append_ptr); + } + + /* Copy the data into the current packet buffer. */ + memcpy(work_ptr -> nx_packet_append_ptr, source_ptr, copy_size); + + /* Adjust the remaining data size. */ + data_size = data_size - copy_size; + + /* Update this packets append pointer. */ + work_ptr -> nx_packet_append_ptr = work_ptr -> nx_packet_append_ptr + copy_size; + + /* Any more data left to append? */ + if (data_size) + { + + /* Yes, there is more to move. Update the source pointer, move the work pointer + to the next packet in the chain and update the last packet pointer. */ + source_ptr = source_ptr + copy_size; + work_ptr = work_ptr -> nx_packet_next; + packet_ptr -> nx_packet_last = work_ptr; + } + } + + /* Return successful status. */ + return(NX_SUCCESS); +} + diff --git a/common/src/nx_packet_data_extract_offset.c b/common/src/nx_packet_data_extract_offset.c new file mode 100644 index 0000000..10615d2 --- /dev/null +++ b/common/src/nx_packet_data_extract_offset.c @@ -0,0 +1,199 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_packet.h" + + +/**************************************************************************/ +/* */ +/* 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. If an empty packet (no data) is */ +/* received, zero bytes are copied, and the function returns without */ +/* errors. */ +/* */ +/* This service does not modify packet internal state information. The */ +/* data being extracted is still available in the original packet for */ +/* consumption again. */ +/* */ +/* INPUT */ +/* */ +/* packet_ptr Pointer to the source packet */ +/* offset Offset from start of data */ +/* 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 */ +/* */ +/**************************************************************************/ +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; +ULONG packet_fragment_length; +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; + while (working_packet_ptr) + { + + packet_fragment_length = (ULONG)(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; + } + + /* 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; + } + + /* Loop to copy bytes from packet(s). */ + while (working_packet_ptr && remaining_bytes) + { + + /* Calculate bytes to copy. */ + bytes_to_copy = (ULONG)(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; + + /* 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; + } + } + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_PACKET_DATA_EXTRACT_OFFSET, packet_ptr, buffer_length, *bytes_copied, 0, NX_TRACE_PACKET_EVENTS, 0, 0); + + /* Return successful completion. */ + return(NX_SUCCESS); +} + diff --git a/common/src/nx_packet_data_retrieve.c b/common/src/nx_packet_data_retrieve.c new file mode 100644 index 0000000..77b2e39 --- /dev/null +++ b/common/src/nx_packet_data_retrieve.c @@ -0,0 +1,137 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Packet Pool Management (Packet) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_packet.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_packet_data_retrieve 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. */ +/* */ +/* INPUT */ +/* */ +/* packet_ptr Pointer to the source packet */ +/* buffer_start Pointer to destination area */ +/* 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 */ +/* */ +/**************************************************************************/ +UINT _nx_packet_data_retrieve(NX_PACKET *packet_ptr, VOID *buffer_start, ULONG *bytes_copied) +{ + +ULONG remaining_bytes; +UCHAR *source_ptr; +UCHAR *destination_ptr; + + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_PACKET_DATA_RETRIEVE, packet_ptr, buffer_start, bytes_copied, 0, NX_TRACE_PACKET_EVENTS, 0, 0) + + /* Setup the destination pointer. */ + destination_ptr = buffer_start; + + /* Pickup the amount of bytes to copy. */ + *bytes_copied = packet_ptr -> nx_packet_length; + + /* Setup the remaining bytes. */ + remaining_bytes = packet_ptr -> nx_packet_length; + + /* Loop to copy bytes from packet(s). */ + while (packet_ptr) + { + + /* Setup loop to copy from this packet. */ + source_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Copy bytes from this packet. */ + while (remaining_bytes) + { + + /* Determine if we are at the end of the packet's buffer. */ + if (source_ptr == packet_ptr -> nx_packet_append_ptr) + { + + /* Yes, get out of this inner loop. */ + break; + } + + /* Copy byte and increment both pointers. */ + *destination_ptr++ = *source_ptr++; + + /* Decrement the remaining bytes to copy. */ + remaining_bytes--; + } + + /* Move to next packet. */ + packet_ptr = packet_ptr -> nx_packet_next; + } + + /* Determine if the packet chain was valid. */ + if (remaining_bytes) + { + + /* Invalid packet chain. Calculate the actual number of bytes + copied. */ + *bytes_copied = *bytes_copied - remaining_bytes; + + /* Return an error. */ + return(NX_INVALID_PACKET); + } + + /* Return successful completion. */ + return(NX_SUCCESS); +} + diff --git a/common/src/nx_packet_length_get.c b/common/src/nx_packet_length_get.c new file mode 100644 index 0000000..b8b3d6f --- /dev/null +++ b/common/src/nx_packet_length_get.c @@ -0,0 +1,82 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Packet Pool Management (Packet) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_packet.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_packet_length_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function returns the length of the supplied packet. */ +/* */ +/* INPUT */ +/* */ +/* packet_ptr Pointer of packet */ +/* length Destination for the length */ +/* */ +/* 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_packet_length_get(NX_PACKET *packet_ptr, ULONG *length) +{ + + /* Return the length of the packet. */ + *length = packet_ptr -> nx_packet_length; + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_PACKET_LENGTH_GET, packet_ptr, *length, 0, 0, NX_TRACE_PACKET_EVENTS, 0, 0) + + /* Return completion status. */ + return(NX_SUCCESS); +} + diff --git a/common/src/nx_packet_pool_cleanup.c b/common/src/nx_packet_pool_cleanup.c new file mode 100644 index 0000000..f47a3a3 --- /dev/null +++ b/common/src/nx_packet_pool_cleanup.c @@ -0,0 +1,161 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Packet Pool Management (Packet) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "tx_thread.h" +#include "nx_packet.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_packet_pool_cleanup PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes packet allocate timeout and thread terminate*/ +/* actions that require the packet pool 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_packet_pool_cleanup(TX_THREAD *thread_ptr NX_CLEANUP_PARAMETER) +{ + +TX_INTERRUPT_SAVE_AREA + +NX_PACKET_POOL *pool_ptr; /* Working packet pool pointer */ + + NX_CLEANUP_EXTENSION + + /* Setup pointer to packet pool control block. */ + pool_ptr = (NX_PACKET_POOL *)thread_ptr -> tx_thread_suspend_control_block; + + /* Disable interrupts to remove the suspended thread from the packet pool. */ + TX_DISABLE + + /* Determine if the cleanup is still required. */ + if ((thread_ptr -> tx_thread_suspend_cleanup) && (pool_ptr) && + (pool_ptr -> nx_packet_pool_id == NX_PACKET_POOL_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. */ + pool_ptr -> nx_packet_pool_suspension_list = TX_NULL; + } + else + { + + /* At least one more thread is on the same suspension list. */ + + /* Update the list head pointer if necessary. */ + if (pool_ptr -> nx_packet_pool_suspension_list == thread_ptr) + { + pool_ptr -> nx_packet_pool_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. */ + pool_ptr -> nx_packet_pool_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 packet pool. Setup return error status and + resume the thread. */ + + /* Setup return status. */ + thread_ptr -> tx_thread_suspend_status = NX_NO_PACKET; + + /* 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 +} + diff --git a/common/src/nx_packet_pool_create.c b/common/src/nx_packet_pool_create.c new file mode 100644 index 0000000..ea1b2a9 --- /dev/null +++ b/common/src/nx_packet_pool_create.c @@ -0,0 +1,209 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Packet Pool Management (Packet) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_packet.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_packet_pool_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates a pool of fixed-size packets within the */ +/* specified memory area. */ +/* */ +/* INPUT */ +/* */ +/* pool_ptr Packet Pool control block */ +/* name_ptr Packet Pool string pointer */ +/* payload_size Size of packet payload */ +/* pool_start Starting address of pool */ +/* pool_size Number of bytes in pool */ +/* */ +/* OUTPUT */ +/* */ +/* status Return status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_packet_pool_create(NX_PACKET_POOL *pool_ptr, CHAR *name_ptr, ULONG payload_size, + VOID *pool_start, ULONG pool_size) +{ + +TX_INTERRUPT_SAVE_AREA + +NX_PACKET_POOL *tail_ptr; /* Working packet pool pointer */ +ULONG packets; /* Number of packets in pool */ +ULONG original_payload_size; /* Original payload size */ +CHAR *packet_ptr; /* Working packet pointer */ +CHAR *next_packet_ptr; /* Next packet pointer */ +CHAR *end_of_pool; /* End of pool area */ + + + /* Save the original payload size. */ + original_payload_size = payload_size; + + /* Round the packet size up to something that is evenly divisible by + an ULONG. This helps guarantee proper alignment. */ + payload_size = ((payload_size + sizeof(ULONG) - 1) / sizeof(ULONG)) * sizeof(ULONG); + + /* Round the pool size down to something that is evenly divisible by + an ULONG. */ + pool_size = (pool_size / sizeof(ULONG)) * sizeof(ULONG); + + /* Setup the basic packet pool fields. */ + pool_ptr -> nx_packet_pool_name = name_ptr; + pool_ptr -> nx_packet_pool_suspension_list = TX_NULL; + pool_ptr -> nx_packet_pool_suspended_count = 0; + pool_ptr -> nx_packet_pool_start = (CHAR *)pool_start; + pool_ptr -> nx_packet_pool_size = pool_size; + pool_ptr -> nx_packet_pool_payload_size = original_payload_size; + + /* Calculate the end of the pool's memory area. */ + end_of_pool = ((CHAR *)pool_start) + pool_size; + + /* Walk through the pool area, setting up the available packet list. */ + packets = 0; + packet_ptr = (CHAR *)pool_start; + next_packet_ptr = packet_ptr + (payload_size + sizeof(NX_PACKET)); + while (next_packet_ptr <= end_of_pool) + { + + /* Yes, we have another packet. Increment the packet count. */ + packets++; + + /* Setup the link to the next packet. */ + ((NX_PACKET *)packet_ptr) -> nx_packet_next = (NX_PACKET *)next_packet_ptr; + + /* Remember that this packet pool is the owner. */ + ((NX_PACKET *)packet_ptr) -> nx_packet_pool_owner = pool_ptr; + + /* Clear the next packet pointer. */ + ((NX_PACKET *)packet_ptr) -> nx_packet_queue_next = (NX_PACKET *)NX_NULL; + + /* Mark the packet as free. */ + ((NX_PACKET *)packet_ptr) -> nx_packet_tcp_queue_next = (NX_PACKET *)NX_PACKET_FREE; + + /* Setup the packet data pointers. */ + ((NX_PACKET *)packet_ptr) -> nx_packet_data_start = (UCHAR *)(packet_ptr + sizeof(NX_PACKET)); + ((NX_PACKET *)packet_ptr) -> nx_packet_data_end = (UCHAR *)(packet_ptr + sizeof(NX_PACKET) + original_payload_size); + + /* Advance to the next packet. */ + packet_ptr = next_packet_ptr; + + /* Update the next packet pointer. */ + next_packet_ptr = packet_ptr + (payload_size + sizeof(NX_PACKET)); + } + + /* Backup to the last packet in the pool. */ + packet_ptr = packet_ptr - (payload_size + sizeof(NX_PACKET)); + + /* Set the last packet's forward pointer to NULL. */ + ((NX_PACKET *)packet_ptr) -> nx_packet_next = NX_NULL; + + /* Save the remaining information in the pool control packet. */ + pool_ptr -> nx_packet_pool_available = packets; + pool_ptr -> nx_packet_pool_total = packets; + + /* Quickly check to make sure at least one packet is in the pool. */ + if (packets) + { + pool_ptr -> nx_packet_pool_available_list = (NX_PACKET *)pool_start; + } + else + { + pool_ptr -> nx_packet_pool_available_list = TX_NULL; + } + + /* If trace is enabled, register this object. */ + NX_TRACE_OBJECT_REGISTER(NX_TRACE_OBJECT_TYPE_PACKET_POOL, pool_ptr, name_ptr, payload_size, packets) + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_PACKET_POOL_CREATE, pool_ptr, payload_size, pool_start, pool_size, NX_TRACE_PACKET_EVENTS, 0, 0) + + /* Disable interrupts to place the packet pool on the created list. */ + TX_DISABLE + + /* Setup the packet pool ID to make it valid. */ + pool_ptr -> nx_packet_pool_id = NX_PACKET_POOL_ID; + + /* Place the packet pool on the list of created packet pools. First, + check for an empty list. */ + if (_nx_packet_pool_created_ptr) + { + + /* Pickup tail pointer. */ + tail_ptr = _nx_packet_pool_created_ptr -> nx_packet_pool_created_previous; + + /* Place the new packet pool in the list. */ + _nx_packet_pool_created_ptr -> nx_packet_pool_created_previous = pool_ptr; + tail_ptr -> nx_packet_pool_created_next = pool_ptr; + + /* Setup this packet pool's created links. */ + pool_ptr -> nx_packet_pool_created_previous = tail_ptr; + pool_ptr -> nx_packet_pool_created_next = _nx_packet_pool_created_ptr; + } + else + { + + /* The created packet pool list is empty. Add packet pool to empty list. */ + _nx_packet_pool_created_ptr = pool_ptr; + pool_ptr -> nx_packet_pool_created_next = pool_ptr; + pool_ptr -> nx_packet_pool_created_previous = pool_ptr; + } + + /* Increment the number of packet pools created. */ + _nx_packet_pool_created_count++; + + /* Restore interrupts. */ + TX_RESTORE + + /* Return NX_SUCCESS. */ + return(NX_SUCCESS); +} + diff --git a/common/src/nx_packet_pool_delete.c b/common/src/nx_packet_pool_delete.c new file mode 100644 index 0000000..a85005a --- /dev/null +++ b/common/src/nx_packet_pool_delete.c @@ -0,0 +1,172 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Packet Pool Management (Packet) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_packet.h" +#include "tx_thread.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_packet_pool_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function deletes a previously created packet pool. */ +/* */ +/* INPUT */ +/* */ +/* pool_ptr Packet pool control block */ +/* pointer */ +/* */ +/* OUTPUT */ +/* */ +/* status Return status */ +/* */ +/* CALLS */ +/* */ +/* _tx_thread_system_resume Resume threads suspended */ +/* _tx_thread_system_preempt_check Check for preemption */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_packet_pool_delete(NX_PACKET_POOL *pool_ptr) +{ + +TX_INTERRUPT_SAVE_AREA + +TX_THREAD *thread_ptr; /* Working thread pointer */ + + + /* Disable interrupts to remove the packet pool from the created list. */ + TX_DISABLE + + /* Decrement the number of packet pools created. */ + _nx_packet_pool_created_count--; + + /* Clear the packet pool ID to make it invalid. */ + pool_ptr -> nx_packet_pool_id = 0; + + /* See if the packet pool only one on the list. */ + if (pool_ptr == pool_ptr -> nx_packet_pool_created_next) + { + + /* Only created packet pool, just set the created list to NULL. */ + _nx_packet_pool_created_ptr = NX_NULL; + } + else + { + + /* Link-up the neighbors. */ + (pool_ptr -> nx_packet_pool_created_next) -> nx_packet_pool_created_previous = + pool_ptr -> nx_packet_pool_created_previous; + (pool_ptr -> nx_packet_pool_created_previous) -> nx_packet_pool_created_next = + pool_ptr -> nx_packet_pool_created_next; + + /* See if we have to update the created list head pointer. */ + if (_nx_packet_pool_created_ptr == pool_ptr) + { + + /* Yes, move the head pointer to the next link. */ + _nx_packet_pool_created_ptr = pool_ptr -> nx_packet_pool_created_next; + } + } + + /* Temporarily disable preemption. */ + _tx_thread_preempt_disable++; + + /* Restore interrupts. */ + TX_RESTORE + + /* Walk through the packet pool suspension list to resume any and all + threads suspended on this packet pool. */ + thread_ptr = pool_ptr -> nx_packet_pool_suspension_list; + while (pool_ptr -> nx_packet_pool_suspended_count) + { + /* Lockout interrupts. */ + TX_DISABLE + + /* Clear the cleanup pointer, this prevents the timeout from doing + anything. */ + thread_ptr -> tx_thread_suspend_cleanup = TX_NULL; + + /* Temporarily disable preemption again. */ + _tx_thread_preempt_disable++; + + /* Restore interrupts. */ + TX_RESTORE + + /* Set the return status in the thread to NX_POOL_DELETED. */ + thread_ptr -> tx_thread_suspend_status = NX_POOL_DELETED; + + /* Move the thread pointer ahead. */ + thread_ptr = thread_ptr -> tx_thread_suspended_next; + + /* Resume the thread. */ + _tx_thread_system_resume(thread_ptr -> tx_thread_suspended_previous); + + /* Decrease the suspended count. */ + pool_ptr -> nx_packet_pool_suspended_count--; + } + + /* Disable interrupts. */ + TX_DISABLE + + /* Release previous preempt disable. */ + _tx_thread_preempt_disable--; + + /* Restore interrupts. */ + TX_RESTORE + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_PACKET_POOL_DELETE, pool_ptr, 0, 0, 0, NX_TRACE_PACKET_EVENTS, 0, 0) + + /* If trace is enabled, unregister this object. */ + NX_TRACE_OBJECT_UNREGISTER(pool_ptr) + + /* Check for preemption. */ + _tx_thread_system_preempt_check(); + + /* Return NX_SUCCESS. */ + return(NX_SUCCESS); +} + diff --git a/common/src/nx_packet_pool_info_get.c b/common/src/nx_packet_pool_info_get.c new file mode 100644 index 0000000..c2b4187 --- /dev/null +++ b/common/src/nx_packet_pool_info_get.c @@ -0,0 +1,136 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Packet Pool Management (Packet) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_packet.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_packet_pool_info_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves information about the specified packet */ +/* pool. */ +/* */ +/* INPUT */ +/* */ +/* pool_ptr Pool to get information from */ +/* total_packets Destination for total packets */ +/* free_packets Destination for free packets */ +/* empty_pool_requests Destination for empty requests*/ +/* empty_pool_suspensions Destination for empty */ +/* suspensions */ +/* invalid_packet_releases Destination for invalid packet*/ +/* release requests */ +/* */ +/* 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_packet_pool_info_get(NX_PACKET_POOL *pool_ptr, ULONG *total_packets, ULONG *free_packets, + ULONG *empty_pool_requests, ULONG *empty_pool_suspensions, + ULONG *invalid_packet_releases) +{ +TX_INTERRUPT_SAVE_AREA + + + /* Disable interrupts to get packet pool information. */ + TX_DISABLE + + /* Determine if pool total packets is wanted. */ + if (total_packets) + { + + /* Return the number of total packets in this pool. */ + *total_packets = pool_ptr -> nx_packet_pool_total; + } + + /* Determine if pool free packets is wanted. */ + if (free_packets) + { + + /* Return the number of free packets in this pool. */ + *free_packets = pool_ptr -> nx_packet_pool_available; + } + + /* Determine if empty pool requests is wanted. */ + if (empty_pool_requests) + { + + /* Return the number of empty pool requests made in this pool. */ + *empty_pool_requests = pool_ptr -> nx_packet_pool_empty_requests; + } + + /* Determine if empty pool suspensions is wanted. */ + if (empty_pool_suspensions) + { + + /* Return the number of empty pool suspensions made in this pool. */ + *empty_pool_suspensions = pool_ptr -> nx_packet_pool_empty_suspensions; + } + + /* Determine if invalid packet releases is wanted. */ + if (invalid_packet_releases) + { + + /* Return the number of invalid packet releases made in this pool. */ + *invalid_packet_releases = pool_ptr -> nx_packet_pool_invalid_releases; + } + + /* Restore interrupts. */ + TX_RESTORE + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_PACKET_POOL_INFO_GET, pool_ptr, pool_ptr -> nx_packet_pool_total, pool_ptr -> nx_packet_pool_available, pool_ptr -> nx_packet_pool_empty_requests, NX_TRACE_PACKET_EVENTS, 0, 0) + + /* Return completion status. */ + return(NX_SUCCESS); +} + diff --git a/common/src/nx_packet_pool_initialize.c b/common/src/nx_packet_pool_initialize.c new file mode 100644 index 0000000..0495ac8 --- /dev/null +++ b/common/src/nx_packet_pool_initialize.c @@ -0,0 +1,82 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Packet Pool Management (Packet) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Locate NetX global Packet Pool Component data in this file. */ + +#define NX_PACKET_POOL_INIT + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_packet.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_packet_pool_initialize PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function initializes the packet pool management component. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_system_initialize System initialization */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_packet_pool_initialize(VOID) +{ + + /* Initialize the head pointer of the created packet pools list and the + number of packet pools created. */ + _nx_packet_pool_created_ptr = NX_NULL; + _nx_packet_pool_created_count = 0; +} + diff --git a/common/src/nx_packet_release.c b/common/src/nx_packet_release.c new file mode 100644 index 0000000..51fd3f9 --- /dev/null +++ b/common/src/nx_packet_release.c @@ -0,0 +1,211 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Packet Pool Management (Packet) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "tx_thread.h" +#include "nx_packet.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_packet_release PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function releases the packet chain back to the appropriate */ +/* packet pools. */ +/* */ +/* INPUT */ +/* */ +/* packet_ptr Pointer of packet to release */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _tx_thread_system_resume Resume suspended thread */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_packet_release(NX_PACKET *packet_ptr) +{ + +TX_INTERRUPT_SAVE_AREA + +NX_PACKET_POOL *pool_ptr; /* Pool pointer */ +TX_THREAD *thread_ptr; /* Working thread pointer */ +NX_PACKET *next_packet; /* Working block pointer */ + + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_PACKET_RELEASE, packet_ptr, packet_ptr -> nx_packet_tcp_queue_next, (packet_ptr -> nx_packet_pool_owner) -> nx_packet_pool_available, 0, NX_TRACE_PACKET_EVENTS, 0, 0) + + /* Loop to free all packets chained together, not assuming they are + from the same pool. */ + while (packet_ptr) + { + + /* Check to see if the packet is releasable. */ + if (packet_ptr -> nx_packet_tcp_queue_next != ((NX_PACKET *)NX_PACKET_ALLOCATED)) + { + +#ifndef NX_DISABLE_PACKET_INFO + /* Pickup the pool pointer. */ + pool_ptr = packet_ptr -> nx_packet_pool_owner; + + /* Check for a good pool pointer... error must be the packet! */ + if ((pool_ptr) && (pool_ptr -> nx_packet_pool_id == NX_PACKET_POOL_ID)) + { + + /* Increment the packet pool invalid release error count. */ + pool_ptr -> nx_packet_pool_invalid_releases++; + } +#endif + + /* Return an error indicating the packet could not be released. */ + return(NX_PTR_ERROR); + } + /* End of packet check. */ + + /* Pickup the next packet. */ + next_packet = packet_ptr -> nx_packet_next; + + /* Disable interrupts to put this packet back in the packet pool. */ + TX_DISABLE + + /* Pickup the pool pointer. */ + pool_ptr = packet_ptr -> nx_packet_pool_owner; + + /* Determine if there are any threads suspended on the block pool. */ + thread_ptr = pool_ptr -> nx_packet_pool_suspension_list; + 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. */ + pool_ptr -> nx_packet_pool_suspension_list = NX_NULL; + } + else + { + + /* At least one more thread is on the same expiration list. */ + + /* Update the list head pointer. */ + pool_ptr -> nx_packet_pool_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. */ + pool_ptr -> nx_packet_pool_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++; + + /* Restore interrupts. */ + TX_RESTORE + + /* Adjust this packet to look just like a new packet. */ + packet_ptr -> nx_packet_next = NX_NULL; + packet_ptr -> nx_packet_queue_next = NX_NULL; + packet_ptr -> nx_packet_last = NX_NULL; + packet_ptr -> nx_packet_length = 0; + packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_data_start + (thread_ptr -> tx_thread_suspend_info); + packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Return this block pointer to the suspended thread waiting for + a block. */ + *((NX_PACKET **)thread_ptr -> tx_thread_additional_suspend_info) = packet_ptr; + + /* Put return status into the thread control block. */ + thread_ptr -> tx_thread_suspend_status = NX_SUCCESS; + + /* Resume thread. */ + _tx_thread_system_resume(thread_ptr); + } + else + { + + /* No thread is suspended for a memory block. */ + + /* Mark the packet as free. */ + packet_ptr -> nx_packet_tcp_queue_next = (NX_PACKET *)NX_PACKET_FREE; + + /* Put the packet back in the available list. */ + packet_ptr -> nx_packet_next = pool_ptr -> nx_packet_pool_available_list; + + /* Adjust the head pointer. */ + pool_ptr -> nx_packet_pool_available_list = packet_ptr; + + /* Increment the count of available blocks. */ + pool_ptr -> nx_packet_pool_available++; + + /* Restore interrupts. */ + TX_RESTORE + } + + /* Move to the next packet in the list. */ + packet_ptr = next_packet; + } + + /* Return completion status. */ + return(NX_SUCCESS); +} + diff --git a/common/src/nx_packet_transmit_release.c b/common/src/nx_packet_transmit_release.c new file mode 100644 index 0000000..6a7ac91 --- /dev/null +++ b/common/src/nx_packet_transmit_release.c @@ -0,0 +1,120 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Packet Pool Management (Packet) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_packet.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_packet_transmit_release PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function releases a transmitted packet chain back to the */ +/* appropriate packet pool. If the packet is a TCP packet, it is */ +/* simply marked as completed. The actual release is deferred to */ +/* the TCP component. */ +/* */ +/* INPUT */ +/* */ +/* packet_ptr Pointer of packet to release */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_packet_release Release packet back to pool */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_packet_transmit_release(NX_PACKET *packet_ptr) +{ + +TX_INTERRUPT_SAVE_AREA + +UINT status; + + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_PACKET_TRANSMIT_RELEASE, packet_ptr, packet_ptr -> nx_packet_tcp_queue_next, (packet_ptr -> nx_packet_pool_owner) -> nx_packet_pool_available, 0, NX_TRACE_PACKET_EVENTS, 0, 0) + + /* Disable interrupts temporarily. */ + TX_DISABLE + + /* Determine if the packet is a queued TCP data packet. Such packets cannot be released + immediately, since they may need to be resent. */ + if ((packet_ptr -> nx_packet_tcp_queue_next != ((NX_PACKET *)NX_PACKET_ALLOCATED)) && + (packet_ptr -> nx_packet_tcp_queue_next != ((NX_PACKET *)NX_PACKET_FREE))) + { + + /* Yes, this is indeed a TCP packet. Just mark this with the NX_DRIVER_TX_DONE + value to let the TCP layer know it is no longer queued up. */ + packet_ptr -> nx_packet_queue_next = (NX_PACKET *)NX_DRIVER_TX_DONE; + + /* Remove the IP header and adjust the length. */ + packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr + sizeof(NX_IP_HEADER); + packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - sizeof(NX_IP_HEADER); + + /* Restore interrupts. */ + TX_RESTORE + + /* Return success. */ + status = NX_SUCCESS; + } + else + { + + /* Restore interrupts. */ + TX_RESTORE + + /* Call the actual packet release function. */ + status = _nx_packet_release(packet_ptr); + } + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nx_ram_network_driver.c b/common/src/nx_ram_network_driver.c new file mode 100644 index 0000000..137d80c --- /dev/null +++ b/common/src/nx_ram_network_driver.c @@ -0,0 +1,730 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** RAM Network (RAM) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/* Include necessary system files. */ + +#include "nx_api.h" + + +#define NX_LINK_MTU 8096 + + +/* Define Ethernet address format. This is prepended to the incoming IP + and ARP/RARP messages. The frame beginning is 14 bytes, but for speed + purposes, we are going to assume there are 16 bytes free in front of the + prepend pointer and that the prepend pointer is 32-bit aligned. + + Byte Offset Size Meaning + + 0 6 Destination Ethernet Address + 6 6 Source Ethernet Address + 12 2 Ethernet Frame Type, where: + + 0x0800 -> IP Datagram + 0x0806 -> ARP Request/Reply + 0x0835 -> RARP request reply + + 42 18 Padding on ARP and RARP messages only. */ + +#define NX_ETHERNET_IP 0x0800 +#define NX_ETHERNET_ARP 0x0806 +#define NX_ETHERNET_RARP 0x8035 +#define NX_ETHERNET_SIZE 14 + +/* For the simulated ethernet driver, physical addresses are allocated starting + at the preset value and then incremented before the next allocation. */ + +ULONG simulated_address_msw = 0x1122; +ULONG simulated_address_lsw = 0x33445566; + + +/* Define driver prototypes. */ + +VOID _nx_ram_network_driver(NX_IP_DRIVER *driver_req_ptr); +void _nx_ram_network_driver_output(NX_IP *ip_ptr, NX_PACKET *packet_ptr, UINT device_instance_id); +void _nx_ram_network_driver_receive(NX_IP *ip_ptr, NX_PACKET *packet_ptr, UINT device_instance_id); + +#define NX_MAX_RAM_INTERFACES 4 + + +typedef struct _nx_ram_network_driver_instance_type +{ + UINT nx_ram_network_driver_in_use; + + UINT nx_ram_network_driver_id; + + NX_INTERFACE *nx_ram_driver_interface_ptr; + + NX_IP *nx_ram_driver_ip_ptr; + + ULONG nx_ram_driver_simulated_address_msw; + ULONG nx_ram_driver_simulated_address_lsw; +} _nx_ram_network_driver_instance_type; + +static _nx_ram_network_driver_instance_type nx_ram_driver[NX_MAX_RAM_INTERFACES]; + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ram_network_driver PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function acts as a virtual network for testing the NetX source */ +/* and driver concepts. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP protocol block */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_ram_network_driver_output Send physical packet out */ +/* */ +/* CALLED BY */ +/* */ +/* NetX IP processing */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_ram_network_driver(NX_IP_DRIVER *driver_req_ptr) +{ +UINT i = 0; +NX_IP *ip_ptr; +NX_PACKET *packet_ptr; +ULONG *ethernet_frame_ptr; +NX_INTERFACE *interface_ptr; + + + /* Setup the IP pointer from the driver request. */ + ip_ptr = driver_req_ptr -> nx_ip_driver_ptr; + + /* Default to successful return. */ + driver_req_ptr -> nx_ip_driver_status = NX_SUCCESS; + + /* Setup interface pointer. */ + interface_ptr = driver_req_ptr -> nx_ip_driver_interface; + + + /* Find out the driver instance if the driver command is not ATTACH. */ + if (driver_req_ptr -> nx_ip_driver_command != NX_LINK_INTERFACE_ATTACH) + { + for (i = 0; i < NX_MAX_RAM_INTERFACES; i++) + { + if (nx_ram_driver[i].nx_ram_network_driver_in_use == 0) + { + continue; + } + + if (nx_ram_driver[i].nx_ram_driver_ip_ptr != ip_ptr) + { + continue; + } + + if (nx_ram_driver[i].nx_ram_driver_interface_ptr != driver_req_ptr -> nx_ip_driver_interface) + { + continue; + } + else + { + break; + } + } + + if (i == NX_MAX_RAM_INTERFACES) + { + driver_req_ptr -> nx_ip_driver_status = NX_INVALID_INTERFACE; + return; + } + } + + + /* Process according to the driver request type in the IP control + block. */ + switch (driver_req_ptr -> nx_ip_driver_command) + { + + case NX_LINK_INTERFACE_ATTACH: + { + + /* Find an available driver instance to attach the interface. */ + for (i = 0; i < NX_MAX_RAM_INTERFACES; i++) + { + if (nx_ram_driver[i].nx_ram_network_driver_in_use == 0) + { + break; + } + } + /* An available entry is found. */ + if (i < NX_MAX_RAM_INTERFACES) + { + /* Set the IN USE flag.*/ + nx_ram_driver[i].nx_ram_network_driver_in_use = 1; + + nx_ram_driver[i].nx_ram_network_driver_id = i; + + /* Record the interface attached to the IP instance. */ + nx_ram_driver[i].nx_ram_driver_interface_ptr = driver_req_ptr -> nx_ip_driver_interface; + + /* Record the IP instance. */ + nx_ram_driver[i].nx_ram_driver_ip_ptr = ip_ptr; + + nx_ram_driver[i].nx_ram_driver_simulated_address_msw = simulated_address_msw; + nx_ram_driver[i].nx_ram_driver_simulated_address_lsw = simulated_address_lsw + i; + } + else + { + driver_req_ptr -> nx_ip_driver_status = NX_INVALID_INTERFACE; + } + + break; + } + + case NX_LINK_INITIALIZE: + { + + /* Process driver initialization. */ +#ifdef NX_DEBUG + printf("NetX RAM Driver Initialization - %s\n", ip_ptr -> nx_ip_name); + printf(" IP Address =%08X\n", ip_ptr -> nx_ip_address); +#endif + + /* Setup the link maximum transfer unit. Note that the MTU should + take into account the physical header needs and alignment + requirements. For example, we are going to report actual + MTU less the ethernet header and 2 bytes to keep alignment. */ + interface_ptr -> nx_interface_ip_mtu_size = (NX_LINK_MTU - NX_ETHERNET_SIZE - 2); + + /* Setup the physical address of this IP instance. Increment the + physical address lsw to simulate multiple nodes on the + ethernet. */ + interface_ptr -> nx_interface_physical_address_msw = nx_ram_driver[i].nx_ram_driver_simulated_address_msw; + interface_ptr -> nx_interface_physical_address_lsw = nx_ram_driver[i].nx_ram_driver_simulated_address_lsw; + + /* Indicate to the IP software that IP to physical mapping + is required. */ + interface_ptr -> nx_interface_address_mapping_needed = NX_TRUE; + + break; + } + + case NX_LINK_UNINITIALIZE: + { + + /* Zero out the driver instance. */ + memset(&(nx_ram_driver[i]), 0, sizeof(_nx_ram_network_driver_instance_type)); + + break; + } + + case NX_LINK_ENABLE: + { + + /* Process driver link enable. */ + + /* In the RAM driver, just set the enabled flag. */ + interface_ptr -> nx_interface_link_up = NX_TRUE; + +#ifdef NX_DEBUG + printf("NetX RAM Driver Link Enabled - %s\n", ip_ptr -> nx_ip_name); +#endif + break; + } + + case NX_LINK_DISABLE: + { + + /* Process driver link disable. */ + + /* In the RAM driver, just clear the enabled flag. */ + interface_ptr -> nx_interface_link_up = NX_FALSE; + +#ifdef NX_DEBUG + printf("NetX RAM Driver Link Disabled - %s\n", ip_ptr -> nx_ip_name); +#endif + break; + } + + case NX_LINK_PACKET_SEND: + case NX_LINK_PACKET_BROADCAST: + case NX_LINK_ARP_SEND: + case NX_LINK_ARP_RESPONSE_SEND: + case NX_LINK_RARP_SEND: + { + + /* Process driver send packet. */ + + /* Place the ethernet frame at the front of the packet. */ + packet_ptr = driver_req_ptr -> nx_ip_driver_packet; + + /* Adjust the prepend pointer. */ + packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr - NX_ETHERNET_SIZE; + + /* Adjust the packet length. */ + packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length + NX_ETHERNET_SIZE; + + /* Setup the ethernet frame pointer to build the ethernet frame. Backup another 2 + bytes to get 32-bit word alignment. */ + ethernet_frame_ptr = (ULONG *)(packet_ptr -> nx_packet_prepend_ptr - 2); + + /* Build the ethernet frame. */ + *ethernet_frame_ptr = driver_req_ptr -> nx_ip_driver_physical_address_msw; + *(ethernet_frame_ptr + 1) = driver_req_ptr -> nx_ip_driver_physical_address_lsw; + *(ethernet_frame_ptr + 2) = (interface_ptr -> nx_interface_physical_address_msw << 16) | + (interface_ptr -> nx_interface_physical_address_lsw >> 16); + *(ethernet_frame_ptr + 3) = (interface_ptr -> nx_interface_physical_address_lsw << 16); + + if (driver_req_ptr -> nx_ip_driver_command == NX_LINK_ARP_SEND) + { + *(ethernet_frame_ptr + 3) |= NX_ETHERNET_ARP; + } + else if (driver_req_ptr -> nx_ip_driver_command == NX_LINK_ARP_RESPONSE_SEND) + { + *(ethernet_frame_ptr + 3) |= NX_ETHERNET_ARP; + } + else if (driver_req_ptr -> nx_ip_driver_command == NX_LINK_RARP_SEND) + { + *(ethernet_frame_ptr + 3) |= NX_ETHERNET_RARP; + } + else + { + *(ethernet_frame_ptr + 3) |= NX_ETHERNET_IP; + } + + + /* Endian swapping if NX_LITTLE_ENDIAN is defined. */ + NX_CHANGE_ULONG_ENDIAN(*(ethernet_frame_ptr)); + NX_CHANGE_ULONG_ENDIAN(*(ethernet_frame_ptr + 1)); + NX_CHANGE_ULONG_ENDIAN(*(ethernet_frame_ptr + 2)); + NX_CHANGE_ULONG_ENDIAN(*(ethernet_frame_ptr + 3)); +#ifdef NX_DEBUG_PACKET + printf("NetX RAM Driver Packet Send - %s\n", ip_ptr -> nx_ip_name); +#endif + _nx_ram_network_driver_output(ip_ptr, packet_ptr, i); + break; + } + + case NX_LINK_MULTICAST_JOIN: + { + + /* For real ethernet devices the hardware registers that support IP multicast + need to be searched for an open entry. If found, the multicast ethernet + address contained in the driver request structure + (nx_ip_driver_physical_address_msw & nx_ip_driver_physical_address_lsw) + needs to be loaded into ethernet chip. If no free entries are found, + an NX_NO_MORE_ENTRIES error should be returned to the caller. */ + break; + } + + case NX_LINK_MULTICAST_LEAVE: + { + + /* For real ethernet devices the hardware registers that support IP multicast + need to be searched for a matching entry. If found, the multicast ethernet + address should be cleared in the hardware so that a new entry may use it + on the next join operation. */ + break; + } + + case NX_LINK_GET_STATUS: + { + + /* Return the link status in the supplied return pointer. */ + *(driver_req_ptr -> nx_ip_driver_return_ptr) = ip_ptr -> nx_ip_interface[0].nx_interface_link_up; + break; + } + + case NX_LINK_GET_SPEED: + { + + /* Return the link's line speed in the supplied return pointer. Unsupported feature. */ + *(driver_req_ptr -> nx_ip_driver_return_ptr) = 0; + break; + } + + case NX_LINK_GET_DUPLEX_TYPE: + { + + /* Return the link's line speed in the supplied return pointer. Unsupported feature. */ + *(driver_req_ptr -> nx_ip_driver_return_ptr) = 0; + break; + } + + case NX_LINK_GET_ERROR_COUNT: + { + + /* Return the link's line speed in the supplied return pointer. Unsupported feature. */ + *(driver_req_ptr -> nx_ip_driver_return_ptr) = 0; + break; + } + + case NX_LINK_GET_RX_COUNT: + { + + /* Return the link's line speed in the supplied return pointer. Unsupported feature. */ + *(driver_req_ptr -> nx_ip_driver_return_ptr) = 0; + break; + } + + case NX_LINK_GET_TX_COUNT: + { + + /* Return the link's line speed in the supplied return pointer. Unsupported feature. */ + *(driver_req_ptr -> nx_ip_driver_return_ptr) = 0; + break; + } + + case NX_LINK_GET_ALLOC_ERRORS: + { + + /* Return the link's line speed in the supplied return pointer. Unsupported feature. */ + *(driver_req_ptr -> nx_ip_driver_return_ptr) = 0; + break; + } + + case NX_LINK_DEFERRED_PROCESSING: + { + + /* Driver defined deferred processing... this is typically used to defer interrupt + processing to the thread level. In this driver, nothing is done here! */ + break; + } + + default: + { + + /* Invalid driver request. */ + + /* Return the unhandled command status. */ + driver_req_ptr -> nx_ip_driver_status = NX_UNHANDLED_COMMAND; + +#ifdef NX_DEBUG + printf("NetX RAM Driver Received invalid request - %s\n", ip_ptr -> nx_ip_name); +#endif + } + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ram_network_driver_output PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function simply sends the packet to the IP instance on the */ +/* created IP list that matches the physical destination specified in */ +/* the Ethernet packet. In a real hardware setting, this routine */ +/* would simply put the packet out on the wire. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP protocol block */ +/* packet_ptr Packet pointer */ +/* device_instance_id The interface from which the */ +/* packet was sent. */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_copy Copy a packet */ +/* nx_packet_transmit_release Release a packet */ +/* _nx_ram_network_driver_receive RAM driver receive processing */ +/* */ +/* CALLED BY */ +/* */ +/* NetX IP processing */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +void _nx_ram_network_driver_output(NX_IP *ip_ptr, NX_PACKET *packet_ptr, UINT device_instance_id) +{ + +NX_IP *next_ip; +NX_PACKET *packet_copy; +ULONG destination_address_msw; +ULONG destination_address_lsw; +UINT old_threshold; +UINT i; + +#ifdef NX_DEBUG_PACKET +UCHAR *ptr; +UINT j; + + ptr = packet_ptr -> nx_packet_prepend_ptr; + printf("Ethernet Packet: "); + for (j = 0; j < 6; j++) + { + printf("%02X", *ptr++); + } + printf(" "); + for (j = 0; j < 6; j++) + { + printf("%02X", *ptr++); + } + printf(" %02X", *ptr++); + printf("%02X ", *ptr++); + + i = 0; + for (j = 0; j < (packet_ptr -> nx_packet_length - NX_ETHERNET_SIZE); j++) + { + printf("%02X", *ptr++); + i++; + if (i > 3) + { + i = 0; + printf(" "); + } + } + printf("\n"); + + +#endif + + /* Pickup the destination IP address from the packet_ptr. */ + destination_address_msw = (ULONG)*(packet_ptr -> nx_packet_prepend_ptr); + destination_address_msw = (destination_address_msw << 8) | (ULONG)*(packet_ptr -> nx_packet_prepend_ptr + 1); + destination_address_lsw = (ULONG)*(packet_ptr -> nx_packet_prepend_ptr + 2); + destination_address_lsw = (destination_address_lsw << 8) | (ULONG)*(packet_ptr -> nx_packet_prepend_ptr + 3); + destination_address_lsw = (destination_address_lsw << 8) | (ULONG)*(packet_ptr -> nx_packet_prepend_ptr + 4); + destination_address_lsw = (destination_address_lsw << 8) | (ULONG)*(packet_ptr -> nx_packet_prepend_ptr + 5); + + + /* Disable preemption. */ + tx_thread_preemption_change(tx_thread_identify(), 0, &old_threshold); + + /* Loop through all instances of created IPs to see who gets the packet. */ + next_ip = ip_ptr -> nx_ip_created_next; + + for (i = 0; i < NX_MAX_RAM_INTERFACES; i++) + { + + /* Skip the interface from which the packet was sent. */ + if (i == device_instance_id) + { + continue; + } + + /* Skip the instance that has not been initialized. */ + if (nx_ram_driver[i].nx_ram_network_driver_in_use == 0) + { + continue; + } + + + /* If the destination MAC address is broadcast or the destination matches the interface MAC, + accept the packet. */ + if (((destination_address_msw == ((ULONG)0x0000FFFF)) && (destination_address_lsw == ((ULONG)0xFFFFFFFF))) || + ((destination_address_msw == nx_ram_driver[i].nx_ram_driver_simulated_address_msw) && + (destination_address_lsw == nx_ram_driver[i].nx_ram_driver_simulated_address_lsw))) + { + /* Make a copy of packet for the forwarding. */ + if (nx_packet_copy(packet_ptr, &packet_copy, next_ip -> nx_ip_default_packet_pool, NX_NO_WAIT)) + { + + /* Remove the Ethernet header. */ + packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr + NX_ETHERNET_SIZE; + + /* Adjust the packet length. */ + packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - NX_ETHERNET_SIZE; + + /* Error, no point in continuing, just release the packet. */ + nx_packet_transmit_release(packet_ptr); + return; + } + + _nx_ram_network_driver_receive(next_ip, packet_copy, i); + } + } + + /* Remove the Ethernet header. In real hardware environments, this is typically + done after a transmit complete interrupt. */ + packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr + NX_ETHERNET_SIZE; + + /* Adjust the packet length. */ + packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - NX_ETHERNET_SIZE; + + /* Now that the Ethernet frame has been removed, release the packet. */ + nx_packet_transmit_release(packet_ptr); + + /* Restore preemption. */ + tx_thread_preemption_change(tx_thread_identify(), old_threshold, &old_threshold); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_ram_network_driver_receive PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processing incoming packets. In the RAM network */ +/* driver, the incoming packets are coming from the RAM driver output */ +/* routine. In real hardware settings, this routine would be called */ +/* from the receive packet ISR. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP protocol block */ +/* packet_ptr Packet pointer */ +/* device_instance_id The device ID the packet is */ +/* destined for */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_ip_packet_receive IP receive packet processing */ +/* _nx_ip_packet_deferred_receive IP deferred receive packet */ +/* processing */ +/* _nx_arp_packet_deferred_receive ARP receive processing */ +/* _nx_rarp_packet_deferred_receive RARP receive processing */ +/* nx_packet_release Packet release */ +/* */ +/* CALLED BY */ +/* */ +/* NetX IP processing */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +void _nx_ram_network_driver_receive(NX_IP *ip_ptr, NX_PACKET *packet_ptr, UINT device_instance_id) +{ + +UINT packet_type; + + /* Pickup the packet header to determine where the packet needs to be + sent. */ + packet_type = (((UINT)(*(packet_ptr -> nx_packet_prepend_ptr + 12))) << 8) | + ((UINT)(*(packet_ptr -> nx_packet_prepend_ptr + 13))); + + + /* Setup interface pointer. */ + packet_ptr -> nx_packet_ip_interface = nx_ram_driver[device_instance_id].nx_ram_driver_interface_ptr; + + + /* Route the incoming packet according to its ethernet type. */ + if (packet_type == NX_ETHERNET_IP) + { + + /* Note: The length reported by some Ethernet hardware includes bytes after the packet + as well as the Ethernet header. In some cases, the actual packet length after the + Ethernet header should be derived from the length in the IP header (lower 16 bits of + the first 32-bit word). */ + + /* Clean off the Ethernet header. */ + packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr + NX_ETHERNET_SIZE; + + /* Adjust the packet length. */ + packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - NX_ETHERNET_SIZE; + + /* Route to the ip receive function. */ +#ifdef NX_DEBUG_PACKET + printf("NetX RAM Driver IP Packet Receive - %s\n", ip_ptr -> nx_ip_name); +#endif + +#ifdef NX_DIRECT_ISR_CALL + _nx_ip_packet_receive(ip_ptr, packet_ptr); +#else + _nx_ip_packet_deferred_receive(ip_ptr, packet_ptr); +#endif + } + else if (packet_type == NX_ETHERNET_ARP) + { + + /* Clean off the Ethernet header. */ + packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr + NX_ETHERNET_SIZE; + + /* Adjust the packet length. */ + packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - NX_ETHERNET_SIZE; + + /* Route to the ARP receive function. */ +#ifdef NX_DEBUG + printf("NetX RAM Driver ARP Receive - %s\n", ip_ptr -> nx_ip_name); +#endif + _nx_arp_packet_deferred_receive(ip_ptr, packet_ptr); + } + else if (packet_type == NX_ETHERNET_RARP) + { + + /* Clean off the Ethernet header. */ + packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr + NX_ETHERNET_SIZE; + + /* Adjust the packet length. */ + packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - NX_ETHERNET_SIZE; + + /* Route to the RARP receive function. */ +#ifdef NX_DEBUG + printf("NetX RAM Driver RARP Receive - %s\n", ip_ptr -> nx_ip_name); +#endif + _nx_rarp_packet_deferred_receive(ip_ptr, packet_ptr); + } + else + { + + /* Invalid ethernet header... release the packet. */ + nx_packet_release(packet_ptr); + } +} + diff --git a/common/src/nx_rarp_disable.c b/common/src/nx_rarp_disable.c new file mode 100644 index 0000000..a5f0b0f --- /dev/null +++ b/common/src/nx_rarp_disable.c @@ -0,0 +1,107 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Reverse Address Resolution Protocol (RARP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_rarp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_rarp_disable PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function disables the RARP management component for the */ +/* specified IP instance. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP instance pointer */ +/* */ +/* 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_rarp_disable(NX_IP *ip_ptr) +{ + +TX_INTERRUPT_SAVE_AREA + + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_RARP_DISABLE, ip_ptr, 0, 0, 0, NX_TRACE_RARP_EVENTS, 0, 0) + + /* Disable interrupts. */ + TX_DISABLE + + /* Check to see if RARP is enabled. */ + if (!ip_ptr -> nx_ip_rarp_periodic_update) + { + + /* Error, IP instance already has RARP disabled. */ + + /* Restore interrupts. */ + TX_RESTORE + + /* Return to caller. */ + return(NX_NOT_ENABLED); + } + + /* Clear the RARP periodic update routine. */ + ip_ptr -> nx_ip_rarp_periodic_update = NX_NULL; + + /* Clear the RARP queue process routine. */ + ip_ptr -> nx_ip_rarp_queue_process = NX_NULL; + + /* Restore interrupts. */ + TX_RESTORE + + /* Return successful completion. */ + return(NX_SUCCESS); +} + diff --git a/common/src/nx_rarp_enable.c b/common/src/nx_rarp_enable.c new file mode 100644 index 0000000..c4b92f0 --- /dev/null +++ b/common/src/nx_rarp_enable.c @@ -0,0 +1,133 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Reverse Address Resolution Protocol (RARP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_rarp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_rarp_enable PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function enables the RARP management component for the */ +/* specified IP instance. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP instance pointer */ +/* */ +/* 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_rarp_enable(NX_IP *ip_ptr) +{ + +TX_INTERRUPT_SAVE_AREA + +UINT i, rarp_enable; + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_RARP_ENABLE, ip_ptr, 0, 0, 0, NX_TRACE_RARP_EVENTS, 0, 0) + + /* Disable interrupts. */ + TX_DISABLE + + /* Initialize the outcome to cancelling RARP enable. */ + rarp_enable = NX_FALSE; + + /* Loop through all the interfaces. */ + for (i = 0; i < NX_MAX_IP_INTERFACES; i++) + { + + /* Does this interface need a valid IP address? */ + if (ip_ptr -> nx_ip_interface[i].nx_interface_ip_address == 0) + { + + /* Yes, reset to the flag to enable RARP. */ + rarp_enable = NX_TRUE; + break; + } + } + + if (rarp_enable == NX_FALSE) + { + /* Error, all host interfaces already have a valid IP address (non-zero). */ + + /* Restore interrupts. */ + TX_RESTORE + + /* Return to caller. */ + return(NX_IP_ADDRESS_ERROR); + } + + /* Check to see if RARP has been enabled already. */ + if (ip_ptr -> nx_ip_rarp_periodic_update) + { + + /* Error, IP instance already has RARP enabled. */ + + /* Restore interrupts. */ + TX_RESTORE + + /* Return to caller. */ + return(NX_ALREADY_ENABLED); + } + + /* Setup the RARP periodic update routine. */ + ip_ptr -> nx_ip_rarp_periodic_update = _nx_rarp_periodic_update; + + /* Restore interrupts. */ + TX_RESTORE + + /* Return successful completion. */ + return(NX_SUCCESS); +} + diff --git a/common/src/nx_rarp_info_get.c b/common/src/nx_rarp_info_get.c new file mode 100644 index 0000000..ca2b667 --- /dev/null +++ b/common/src/nx_rarp_info_get.c @@ -0,0 +1,120 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Reverse Address Resolution Protocol (RARP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_rarp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_rarp_info_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function obtains RARP information for the specified IP */ +/* instance. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP instance pointer */ +/* rarp_requests_sent Destination for the number of */ +/* RARP requests sent */ +/* rarp_responses_received Destination for the number of */ +/* RARP responses received */ +/* rarp_invalid_messages Destination for the number of */ +/* RARP invalid messages (or */ +/* unhandled) */ +/* */ +/* 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_rarp_info_get(NX_IP *ip_ptr, ULONG *rarp_requests_sent, ULONG *rarp_responses_received, + ULONG *rarp_invalid_messages) +{ + +TX_INTERRUPT_SAVE_AREA + + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_RARP_INFO_GET, ip_ptr, ip_ptr -> nx_ip_rarp_requests_sent, ip_ptr -> nx_ip_rarp_responses_received, ip_ptr -> nx_ip_rarp_invalid_messages, NX_TRACE_RARP_EVENTS, 0, 0) + + /* Disable interrupts. */ + TX_DISABLE + + /* Determine if RARP requests sent is wanted. */ + if (rarp_requests_sent) + { + + /* Return the number of RARP requests sent by this IP instance. */ + *rarp_requests_sent = ip_ptr -> nx_ip_rarp_requests_sent; + } + + /* Determine if RARP responses received is wanted. */ + if (rarp_responses_received) + { + + /* Return the number of RARP responses received by this IP instance. */ + *rarp_responses_received = ip_ptr -> nx_ip_rarp_responses_received; + } + + /* Determine if RARP invalid (or unhandled) messages is wanted. */ + if (rarp_invalid_messages) + { + + /* Return the number of RARP invalid messages received by this IP instance. */ + *rarp_invalid_messages = ip_ptr -> nx_ip_rarp_invalid_messages; + } + + /* Restore interrupts. */ + TX_RESTORE + + /* Return successful completion. */ + return(NX_SUCCESS); +} + diff --git a/common/src/nx_rarp_packet_deferred_receive.c b/common/src/nx_rarp_packet_deferred_receive.c new file mode 100644 index 0000000..f4cbdd4 --- /dev/null +++ b/common/src/nx_rarp_packet_deferred_receive.c @@ -0,0 +1,134 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Reverse Address Resolution Protocol (RARP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_packet.h" +#include "nx_rarp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_rarp_packet_deferred_receive PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function receives an RARP packet from the link driver (usually */ +/* the link driver's input ISR) and places it in the deferred receive */ +/* RARP packet queue. This moves the minimal receive RARP packet */ +/* processing from the ISR to the IP helper thread. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP control block */ +/* packet_ptr Pointer to packet to send */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* tx_event_flags_set Wakeup IP helper thread */ +/* */ +/* CALLED BY */ +/* */ +/* Application I/O Driver */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_rarp_packet_deferred_receive(NX_IP *ip_ptr, NX_PACKET *packet_ptr) +{ + +TX_INTERRUPT_SAVE_AREA + + + /* Disable interrupts. */ + TX_DISABLE + + /* Check to see if RARP is enabled on this IP instance. */ + if (!ip_ptr -> nx_ip_rarp_queue_process) + { + + /* RARP is not enabled. */ + +#ifndef NX_DISABLE_RARP_INFO + /* Increment the RARP invalid messages count... */ + ip_ptr -> nx_ip_rarp_invalid_messages++; +#endif + + /* Restore interrupts. */ + TX_RESTORE + + /* Since RARP is not enabled, just release the packet. */ + _nx_packet_release(packet_ptr); + + /* Return to caller. */ + return; + } + + /* Check to see if the RARP deferred processing queue is empty. */ + if (ip_ptr -> nx_ip_rarp_deferred_received_packet_head) + { + + /* Not empty, just place the packet at the end of the RARP deferred queue. */ + (ip_ptr -> nx_ip_rarp_deferred_received_packet_tail) -> nx_packet_queue_next = packet_ptr; + packet_ptr -> nx_packet_queue_next = NX_NULL; + ip_ptr -> nx_ip_rarp_deferred_received_packet_tail = packet_ptr; + + /* Restore interrupts. */ + TX_RESTORE + } + else + { + + /* Empty RARP deferred receive processing queue. Just setup the head pointers and + set the event flags to ensure the IP helper thread looks at the RARP deferred + processing queue. */ + ip_ptr -> nx_ip_rarp_deferred_received_packet_head = packet_ptr; + ip_ptr -> nx_ip_rarp_deferred_received_packet_tail = packet_ptr; + packet_ptr -> nx_packet_queue_next = NX_NULL; + + /* Restore interrupts. */ + TX_RESTORE + + /* Wakeup IP helper thread to process the RARP deferred receive. */ + tx_event_flags_set(&(ip_ptr -> nx_ip_events), NX_IP_RARP_REC_EVENT, TX_OR); + } +} + diff --git a/common/src/nx_rarp_packet_receive.c b/common/src/nx_rarp_packet_receive.c new file mode 100644 index 0000000..7608d6c --- /dev/null +++ b/common/src/nx_rarp_packet_receive.c @@ -0,0 +1,219 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Reverse Address Resolution Protocol (RARP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_rarp.h" +#include "nx_packet.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_rarp_packet_receive PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes the reception of both the RARP request and */ +/* the RARP response. RARP responses received are used to setup the */ +/* the IP address of this IP instance. Once the IP address is setup, */ +/* RARP is automatically disabled. RARP requests are discarded */ +/* at present time. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP instance */ +/* packet_ptr Received RARP packet */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_packet_release Release the RARP request */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_rarp_queue_process RARP receive queue processing */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_rarp_packet_receive(NX_IP *ip_ptr, NX_PACKET *packet_ptr) +{ + +TX_INTERRUPT_SAVE_AREA + +ULONG *message_ptr; +UINT i, continue_RARP; +VOID (*address_change_notify)(NX_IP *, VOID *) = NX_NULL; +VOID *additional_info = NX_NULL; + + +#ifndef NX_DISABLE_RX_SIZE_CHECKING + /* Determine if the packet length is valid. */ + if (packet_ptr -> nx_packet_length < NX_RARP_MESSAGE_SIZE) + { + +#ifndef NX_DISABLE_RARP_INFO + /* Increment the RARP invalid messages count... At least until RARP server + logic is added. */ + ip_ptr -> nx_ip_rarp_invalid_messages++; +#endif + + /* Just release the packet. */ + _nx_packet_release(packet_ptr); + + /* Return to caller. */ + return; + } +#endif /* NX_DISABLE_RX_SIZE_CHECKING */ + + /* Setup a pointer to the RARP message. */ + message_ptr = (ULONG *)packet_ptr -> nx_packet_prepend_ptr; + + /* Endian swapping logic. If NX_LITTLE_ENDIAN is specified, these macros will + swap the endian of the RARP message. */ + NX_CHANGE_ULONG_ENDIAN(*(message_ptr + 1)); + NX_CHANGE_ULONG_ENDIAN(*(message_ptr + 2)); + NX_CHANGE_ULONG_ENDIAN(*(message_ptr + 3)); + NX_CHANGE_ULONG_ENDIAN(*(message_ptr + 4)); + NX_CHANGE_ULONG_ENDIAN(*(message_ptr + 5)); + NX_CHANGE_ULONG_ENDIAN(*(message_ptr + 6)); + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_RARP_RECEIVE, ip_ptr, *(message_ptr + 6), packet_ptr, *(message_ptr + 1), NX_TRACE_INTERNAL_EVENTS, 0, 0) + + /* Determine what type of RARP message this is. Note that RARP requests must + also specify this IP instance's IP address. */ + if ((*(message_ptr + 1) & 0xFFFF) == NX_RARP_OPTION_REQUEST) + { + +#ifndef NX_DISABLE_RARP_INFO + /* Increment the RARP invalid messages count... At least until RARP server + logic is added. */ + ip_ptr -> nx_ip_rarp_invalid_messages++; +#endif + + /* Just release the packet. */ + _nx_packet_release(packet_ptr); + } + else if ((*(message_ptr + 1) & 0xFFFF) == NX_RARP_OPTION_RESPONSE) + { + + /* We have a response to a previous RARP request. */ + +#ifndef NX_DISABLE_ARP_INFO + /* Increment the RARP responses received count. */ + ip_ptr -> nx_ip_rarp_responses_received++; +#endif + + /* Disable Interrupts. */ + TX_DISABLE + + /* Determine if the target IP address is non-zero. */ + if (*(message_ptr + 6) && (packet_ptr -> nx_packet_ip_interface -> nx_interface_ip_address == 0)) + { + + /* Pickup the current notification callback and additional information pointers. */ + address_change_notify = ip_ptr -> nx_ip_address_change_notify; + additional_info = ip_ptr -> nx_ip_address_change_notify_additional_info; + + /* Set the IP address of this network interface to the target + IP address in the RARP response. */ + packet_ptr -> nx_packet_ip_interface -> nx_interface_ip_address = *(message_ptr + 6); + + /* Check if we need to continue periodic RARP requests. */ + + /* Set a flag initialized to discontinue RARP. */ + continue_RARP = NX_FALSE; + + /* Loop through all interfaces. */ + for (i = 0; i < NX_MAX_PHYSICAL_INTERFACES; i++) + { + + /* Skip the invalid interface entry. */ + if (ip_ptr -> nx_ip_interface[i].nx_interface_valid == 0) + { + continue; + } + + /* Look for any interfaces still without a valid IP address. */ + if (ip_ptr -> nx_ip_interface[i].nx_interface_ip_address == 0) + { + + /* Set the flag to continue RARP requests. */ + continue_RARP = NX_TRUE; + break; + } + } + + /* Do we need to continue with periodic RARP requests? */ + if (continue_RARP == NX_FALSE) + { + /* No, Disable the RARP activity now that we have all valid IP addresses. */ + ip_ptr -> nx_ip_rarp_periodic_update = NX_NULL; + ip_ptr -> nx_ip_rarp_queue_process = NX_NULL; + } + } + /* Restore interrupts. */ + TX_RESTORE + + /* Release the RARP response packet. */ + _nx_packet_release(packet_ptr); + } + else + { + +#ifndef NX_DISABLE_RARP_INFO + /* Increment the RARP invalid messages count. */ + ip_ptr -> nx_ip_rarp_invalid_messages++; +#endif + + /* Invalid RARP message. Just release the packet. */ + _nx_packet_release(packet_ptr); + } + + /* Determine if the application should be notified of the IP address change. */ + if (address_change_notify != NX_NULL) + { + /* Yes, call the application's IP address change notify function. */ + (address_change_notify)(ip_ptr, additional_info); + } + + return; +} + diff --git a/common/src/nx_rarp_packet_send.c b/common/src/nx_rarp_packet_send.c new file mode 100644 index 0000000..4b05d05 --- /dev/null +++ b/common/src/nx_rarp_packet_send.c @@ -0,0 +1,162 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Reverse Address Resolution Protocol (RARP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_rarp.h" +#include "nx_packet.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_rarp_packet_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function builds an RARP packet for each interface on the host */ +/* without a valid IP address and calls the associated driver to send */ +/* to send it out on its network interface. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP instance */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_packet_allocate Allocate a packet for the */ +/* RARP request */ +/* (ip_link_driver) User supplied link driver */ +/* */ +/* CALLED BY */ +/* */ +/* NetX Source Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_rarp_packet_send(NX_IP *ip_ptr) +{ + +NX_PACKET *request_ptr; +ULONG *message_ptr; +NX_IP_DRIVER driver_request; +ULONG i; + + + /* Determine which interfaces to send RARP packets out from (e.g. do not have IP addresses). */ + for (i = 0; i < NX_MAX_IP_INTERFACES; i++) + { + + /* Skip this interface if it is not initialized yet. */ + if (ip_ptr -> nx_ip_interface[i].nx_interface_valid == 0) + { + continue; + } + + /* If the interface has a valid address, skip it. */ + if (ip_ptr -> nx_ip_interface[i].nx_interface_ip_address != 0) + { + continue; + } + + /* Allocate a packet to build the RARP message in. */ + if (_nx_packet_allocate(ip_ptr -> nx_ip_default_packet_pool, &request_ptr, (NX_PHYSICAL_HEADER + NX_RARP_MESSAGE_SIZE), NX_NO_WAIT)) + { + + /* Error getting packet, so just get out! */ + return; + } + +#ifndef NX_DISABLE_RARP_INFO + /* Increment the RARP requests sent count. */ + ip_ptr -> nx_ip_rarp_requests_sent++; +#endif + request_ptr -> nx_packet_ip_interface = &(ip_ptr -> nx_ip_interface[i]); + /* Build the RARP request packet. */ + + /* Setup the size of the RARP message. */ + request_ptr -> nx_packet_length = NX_RARP_MESSAGE_SIZE; + + /* Setup the prepend pointer. */ + request_ptr -> nx_packet_prepend_ptr -= NX_RARP_MESSAGE_SIZE; + + /* Setup the pointer to the message area. */ + message_ptr = (ULONG *)request_ptr -> nx_packet_prepend_ptr; + + /* Write the Hardware type into the message. */ + *message_ptr = (ULONG)(NX_RARP_HARDWARE_TYPE << 16) | (NX_RARP_PROTOCOL_TYPE); + *(message_ptr + 1) = (ULONG)(NX_RARP_HARDWARE_SIZE << 24) | (NX_RARP_PROTOCOL_SIZE << 16) | + NX_RARP_OPTION_REQUEST; + *(message_ptr + 2) = (ULONG)(request_ptr -> nx_packet_ip_interface -> nx_interface_physical_address_msw << 16) | + (request_ptr -> nx_packet_ip_interface -> nx_interface_physical_address_lsw >> 16); + *(message_ptr + 3) = (ULONG)(request_ptr -> nx_packet_ip_interface -> nx_interface_physical_address_lsw << 16); + *(message_ptr + 4) = (ULONG)(request_ptr -> nx_packet_ip_interface -> nx_interface_physical_address_msw & NX_LOWER_16_MASK); + *(message_ptr + 5) = (ULONG)(request_ptr -> nx_packet_ip_interface -> nx_interface_physical_address_lsw); + *(message_ptr + 6) = (ULONG)0; + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_RARP_SEND, ip_ptr, 0, request_ptr, *(message_ptr + 1), NX_TRACE_INTERNAL_EVENTS, 0, 0) + + /* Endian swapping logic. If NX_LITTLE_ENDIAN is specified, these macros will swap the endian of the RARP message. */ + NX_CHANGE_ULONG_ENDIAN(*(message_ptr)); + NX_CHANGE_ULONG_ENDIAN(*(message_ptr + 1)); + NX_CHANGE_ULONG_ENDIAN(*(message_ptr + 2)); + NX_CHANGE_ULONG_ENDIAN(*(message_ptr + 3)); + NX_CHANGE_ULONG_ENDIAN(*(message_ptr + 4)); + NX_CHANGE_ULONG_ENDIAN(*(message_ptr + 5)); + NX_CHANGE_ULONG_ENDIAN(*(message_ptr + 6)); + + /* Send the RARP request to the driver. */ + driver_request.nx_ip_driver_ptr = ip_ptr; + driver_request.nx_ip_driver_command = NX_LINK_RARP_SEND; + driver_request.nx_ip_driver_packet = request_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 = request_ptr -> nx_packet_ip_interface; + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_IO_DRIVER_RARP_SEND, ip_ptr, request_ptr, request_ptr -> nx_packet_length, 0, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + (request_ptr -> nx_packet_ip_interface -> nx_interface_link_driver_entry) (&driver_request); + } + + return; +} + diff --git a/common/src/nx_rarp_periodic_update.c b/common/src/nx_rarp_periodic_update.c new file mode 100644 index 0000000..a10fff7 --- /dev/null +++ b/common/src/nx_rarp_periodic_update.c @@ -0,0 +1,80 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Reverse Address Resolution Protocol (RARP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_rarp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_rarp_periodic_update PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function simply initiates another RARP request. When an */ +/* RARP response is received with our IP address, RARP (including */ +/* this periodic update routine) is disabled. */ +/* */ +/* INPUT */ +/* */ +/* ip_address IP address in a ULONG */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_rarp_packet_send Send periodic ARP request out */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ip_thread_entry IP helper thread */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_rarp_periodic_update(NX_IP *ip_ptr) +{ + + /* Send RARP message out. */ + _nx_rarp_packet_send(ip_ptr); + + /* Setup the RARP queue process routine. */ + ip_ptr -> nx_ip_rarp_queue_process = _nx_rarp_queue_process; +} + diff --git a/common/src/nx_rarp_queue_process.c b/common/src/nx_rarp_queue_process.c new file mode 100644 index 0000000..44f17f2 --- /dev/null +++ b/common/src/nx_rarp_queue_process.c @@ -0,0 +1,108 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Reverse Address Resolution Protocol (RARP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_rarp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_rarp_queue_process PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes the received RARP messages on the RARP */ +/* queue placed there by nx_rarp_deferred_receive. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP instance */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_rarp_packet_receive Process received RARP packet */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ip_thread_entry IP helper thread */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_rarp_queue_process(NX_IP *ip_ptr) +{ + +TX_INTERRUPT_SAVE_AREA + +NX_PACKET *packet_ptr; + + + /* Loop to process all RARP deferred packet requests. */ + while (ip_ptr -> nx_ip_rarp_deferred_received_packet_head) + { + + /* Remove the first packet and process it! */ + + /* Disable interrupts. */ + TX_DISABLE + + /* Pickup the first packet. */ + packet_ptr = ip_ptr -> nx_ip_rarp_deferred_received_packet_head; + + /* Move the head pointer to the next packet. */ + ip_ptr -> nx_ip_rarp_deferred_received_packet_head = packet_ptr -> nx_packet_queue_next; + + /* Check for end of RARP deferred processing queue. */ + if (ip_ptr -> nx_ip_rarp_deferred_received_packet_head == NX_NULL) + { + + /* Yes, the RARP deferred queue is empty. Set the tail pointer to NULL. */ + ip_ptr -> nx_ip_rarp_deferred_received_packet_tail = NX_NULL; + } + + /* Restore interrupts. */ + TX_RESTORE + + /* Call the actual RARP packet receive function. */ + _nx_rarp_packet_receive(ip_ptr, packet_ptr); + } +} + diff --git a/common/src/nx_system_initialize.c b/common/src/nx_system_initialize.c new file mode 100644 index 0000000..c84e6bd --- /dev/null +++ b/common/src/nx_system_initialize.c @@ -0,0 +1,305 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** System Management (System) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Locate NetX system data in this file. */ + +#define NX_SYSTEM_INIT + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_system.h" +#include "nx_packet.h" +#include "nx_arp.h" +#include "nx_rarp.h" +#include "nx_ip.h" +#include "nx_udp.h" +#include "nx_icmp.h" +#include "nx_igmp.h" +#include "nx_tcp.h" + + +#ifdef TX_ENABLE_EVENT_TRACE +#include "tx_trace.h" +#endif + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_system_initialize PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function initializes the various components and system data */ +/* structures. */ +/* */ +/* INPUT */ +/* */ +/* pool_start Packet pool starting address */ +/* pool_size Packet pool size in bytes */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_packet_pool_initialize Initialize Packet Pool */ +/* component */ +/* _nx_ip_initialize Initialize IP component */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_system_initialize(VOID) +{ + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_SYSTEM_INITIALIZE, 0, 0, 0, 0, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + /* Call the packet pool initialization component for NetX. */ + _nx_packet_pool_initialize(); + + /* Call the IP component initialization. */ + _nx_ip_initialize(); + + /* Setup the build options variables. */ + _nx_system_build_options_1 = 0 +#ifdef NX_LITTLE_ENDIAN + | (((ULONG) 1) << 31) +#endif +#ifdef NX_DISABLE_ARP_AUTO_ENTRY + | (((ULONG) 1) << 30) +#endif +#ifdef NX_ENABLE_TCP_KEEPALIVE + | (((ULONG) 1) << 29) +#endif +#ifdef NX_TCP_IMMEDIATE_ACK + | (((ULONG) 1) << 28) +#endif +#ifdef NX_DRIVER_DEFERRED_PROCESSING + | (((ULONG) 1) << 27) +#endif +#ifdef NX_DISABLE_FRAGMENTATION + | (((ULONG) 1) << 26) +#endif +#ifdef NX_DISABLE_IP_RX_CHECKSUM + | (((ULONG) 1) << 25) +#endif +#ifdef NX_DISABLE_IP_TX_CHECKSUM + | (((ULONG) 1) << 24) +#endif +#ifdef NX_DISABLE_TCP_RX_CHECKSUM + | (((ULONG) 1) << 23) +#endif +#ifdef NX_DISABLE_TCP_TX_CHECKSUM + | (((ULONG) 1) << 22) +#endif +#ifdef NX_DISABLE_RESET_DISCONNECT + | (((ULONG) 1) << 21) +#endif +#ifdef NX_DISABLE_RX_SIZE_CHECKING + | (((ULONG) 1) << 20) +#endif +#ifdef NX_DISABLE_ARP_INFO + | (((ULONG) 1) << 19) +#endif +#ifdef NX_DISABLE_IP_INFO + | (((ULONG) 1) << 18) +#endif +#ifdef NX_DISABLE_ICMP_INFO + | (((ULONG) 1) << 17) +#endif +#ifdef NX_DISABLE_IGMP_INFO + | (((ULONG) 1) << 16) +#endif +#ifdef NX_DISABLE_PACKET_INFO + | (((ULONG) 1) << 15) +#endif +#ifdef NX_DISABLE_RARP_INFO + | (((ULONG) 1) << 14) +#endif +#ifdef NX_DISABLE_TCP_INFO + | (((ULONG) 1) << 13) +#endif +#ifdef NX_DISABLE_UDP_INFO + | (((ULONG) 1) << 12) +#endif + ; + + /* Add the retry shift value to the options. */ + if (NX_TCP_RETRY_SHIFT > 0xF) + { + _nx_system_build_options_1 |= 0xF; + } + else + { + _nx_system_build_options_1 |= NX_TCP_RETRY_SHIFT; + } + + /* Setup second option word. */ + if (NX_IP_PERIODIC_RATE > 0xFFFFUL) + { + _nx_system_build_options_2 = ((ULONG)0xFFFF0000); + } + else + { + _nx_system_build_options_2 = ((ULONG)NX_IP_PERIODIC_RATE) << 16; + } + if (NX_ARP_EXPIRATION_RATE > 0xFF) + { + _nx_system_build_options_2 |= ((ULONG)0xFF) << 8; + } + else + { + _nx_system_build_options_2 |= ((ULONG)NX_ARP_EXPIRATION_RATE) << 8; + } + if (NX_ARP_UPDATE_RATE > 0xFF) + { + _nx_system_build_options_2 |= ((ULONG)0xFF); + } + else + { + _nx_system_build_options_2 |= ((ULONG)NX_ARP_UPDATE_RATE); + } + + /* Setup third option word. */ + if (NX_TCP_ACK_TIMER_RATE > 0xFF) + { + _nx_system_build_options_3 = ((ULONG)0xFF000000); + } + else + { + _nx_system_build_options_3 = ((ULONG)NX_TCP_ACK_TIMER_RATE) << 24; + } + if (NX_TCP_FAST_TIMER_RATE > 0xFF) + { + _nx_system_build_options_3 |= ((ULONG)0xFF) << 16; + } + else + { + _nx_system_build_options_3 |= ((ULONG)NX_TCP_FAST_TIMER_RATE) << 16; + } + if (NX_TCP_TRANSMIT_TIMER_RATE > 0xFF) + { + _nx_system_build_options_3 |= ((ULONG)0xFF) << 8; + } + else + { + _nx_system_build_options_3 |= ((ULONG)NX_TCP_TRANSMIT_TIMER_RATE) << 8; + } + if (NX_TCP_KEEPALIVE_RETRY > 0xFF) + { + _nx_system_build_options_3 |= ((ULONG)0xFF); + } + else + { + _nx_system_build_options_3 |= ((ULONG)NX_TCP_KEEPALIVE_RETRY); + } + + /* Setup the fourth option word. */ + if (NX_TCP_KEEPALIVE_INITIAL > 0xFFFFUL) + { + _nx_system_build_options_4 = ((ULONG)0xFFFF0000); + } + else + { + _nx_system_build_options_4 = ((ULONG)NX_TCP_KEEPALIVE_INITIAL) << 16; + } + if (NX_ARP_MAXIMUM_RETRIES > 0xFF) + { + _nx_system_build_options_4 |= ((ULONG)0xFF) << 8; + } + else + { + _nx_system_build_options_4 |= ((ULONG)NX_ARP_MAXIMUM_RETRIES) << 8; + } + if (NX_ARP_MAX_QUEUE_DEPTH > 0xF) + { + _nx_system_build_options_4 |= ((ULONG)0xF) << 4; + } + else + { + _nx_system_build_options_4 |= ((ULONG)NX_ARP_MAX_QUEUE_DEPTH) << 4; + } + if (NX_TCP_KEEPALIVE_RETRIES > 0xF) + { + _nx_system_build_options_4 |= ((ULONG)0xF); + } + else + { + _nx_system_build_options_4 |= ((ULONG)NX_TCP_KEEPALIVE_RETRIES); + } + + /* Setup the fifth option word. */ + if (NX_MAX_MULTICAST_GROUPS > 0xFF) + { + _nx_system_build_options_5 = ((ULONG)0xFF000000); + } + else + { + _nx_system_build_options_5 = ((ULONG)NX_MAX_MULTICAST_GROUPS) << 24; + } + if (NX_MAX_LISTEN_REQUESTS > 0xFF) + { + _nx_system_build_options_5 |= ((ULONG)0xFF) << 16; + } + else + { + _nx_system_build_options_5 |= ((ULONG)NX_MAX_LISTEN_REQUESTS) << 16; + } + if (NX_TCP_MAXIMUM_RETRIES > 0xFF) + { + _nx_system_build_options_5 |= ((ULONG)0xFF) << 8; + } + else + { + _nx_system_build_options_5 |= ((ULONG)NX_TCP_MAXIMUM_RETRIES) << 8; + } + if (NX_TCP_MAXIMUM_TX_QUEUE > 0xFF) + { + _nx_system_build_options_5 |= ((ULONG)0xFF); + } + else + { + _nx_system_build_options_5 |= ((ULONG)NX_TCP_MAXIMUM_TX_QUEUE); + } +} + diff --git a/common/src/nx_tcp_checksum.c b/common/src/nx_tcp_checksum.c new file mode 100644 index 0000000..90543d0 --- /dev/null +++ b/common/src/nx_tcp_checksum.c @@ -0,0 +1,197 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_tcp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcp_checksum PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function computes the checksum of a TCP packet. It is used */ +/* for calculating new TCP packets as well as verifying that new */ +/* packets are okay. */ +/* */ +/* INPUT */ +/* */ +/* packet_ptr Pointer to TCP packet */ +/* source_ip Source IP address */ +/* destination_ip Destination IP address */ +/* */ +/* OUTPUT */ +/* */ +/* checksum Computed checksum */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_tcp_packet_process Packet receive processing */ +/* _nx_tcp_packet_send_ack Send ACK message */ +/* _nx_tcp_packet_send_fin Send FIN message */ +/* _nx_tcp_packet_send_syn Send SYN message */ +/* _nx_tcp_socket_send Socket send packet */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +ULONG _nx_tcp_checksum(NX_PACKET *packet_ptr, ULONG source_address, ULONG destination_address) +{ + +ULONG checksum; +NX_PACKET *current_packet; +ULONG temp; +ULONG length; +ULONG packet_length; +ULONG adjusted_packet_length; +UCHAR *word_ptr; +UCHAR *pad_ptr; + + + /* First calculate the checksum of the pseudo TCP header that includes the source IP + address, destination IP address, protocol word, and the TCP length. */ + checksum = (source_address >> NX_SHIFT_BY_16); + checksum += (source_address & NX_LOWER_16_MASK); + checksum += (destination_address >> NX_SHIFT_BY_16); + checksum += (destination_address & NX_LOWER_16_MASK); + checksum += (NX_IP_TCP >> NX_SHIFT_BY_16); + checksum += packet_ptr -> nx_packet_length; + + /* Setup the length of the packet checksum. */ + length = packet_ptr -> nx_packet_length; + + /* Initialize the current packet to the input packet pointer. */ + current_packet = packet_ptr; + + /* Loop to calculate the packet's checksum. */ + while (length) + { + + /* Calculate the current packet length. */ + packet_length = (ULONG)(current_packet -> nx_packet_append_ptr - current_packet -> nx_packet_prepend_ptr); + + /* Make the adjusted packet length evenly divisible by sizeof(ULONG). */ + adjusted_packet_length = ((packet_length + (sizeof(ULONG) - 1)) / sizeof(ULONG)) * sizeof(ULONG); + + /* Determine if we need to add padding bytes. */ + if (packet_length < adjusted_packet_length) + { + + /* Calculate how many bytes we need to zero at the end of the packet. */ + temp = adjusted_packet_length - packet_length; + + /* Setup temporary pointer to the current packet's append pointer. */ + pad_ptr = current_packet -> nx_packet_append_ptr; + + /* Loop to pad current packet with 0s so we don't have to worry about a partial last word. */ + while (temp) + { + + /* Check for the end of the packet. */ + if (pad_ptr >= current_packet -> nx_packet_data_end) + { + break; + } + + /* Write a 0. */ + *pad_ptr++ = 0; + + /* Decrease the pad count. */ + temp--; + } + } + + /* Setup the pointer to the start of the packet. */ + word_ptr = (UCHAR *)current_packet -> nx_packet_prepend_ptr; + + /* Now loop through the current packet to compute the checksum on this packet. */ + while (adjusted_packet_length) + { + + /* Pickup a whole ULONG. */ + temp = *((ULONG *)word_ptr); + + /* Endian swapping logic. If NX_LITTLE_ENDIAN is specified, these macros will + swap the endian of the long word in the message. */ + NX_CHANGE_ULONG_ENDIAN(temp); + + /* Add upper 16-bits into checksum. */ + checksum = checksum + (temp >> NX_SHIFT_BY_16); + + /* Add lower 16-bits into checksum. */ + checksum = checksum + (temp & NX_LOWER_16_MASK); + + /* Move the word pointer and decrease the length. */ + word_ptr = word_ptr + sizeof(ULONG); + adjusted_packet_length = adjusted_packet_length - sizeof(ULONG); + } + + /* Adjust the checksum length. */ + length = length - packet_length; + + /* Determine if we are at the end of the current packet. */ + if ((length) && (word_ptr >= (UCHAR *)current_packet -> nx_packet_append_ptr) && + (current_packet -> nx_packet_next)) + { + + /* We have crossed the packet boundary. Move to the next packet + structure. */ + current_packet = current_packet -> nx_packet_next; + + /* Setup the new word pointer. */ + word_ptr = (UCHAR *)current_packet -> nx_packet_prepend_ptr; + } + } + + /* Add in the carry bits into the checksum. */ + checksum = (checksum >> NX_SHIFT_BY_16) + (checksum & NX_LOWER_16_MASK); + + /* Do it again in case previous operation generates an overflow */ + checksum = (checksum >> NX_SHIFT_BY_16) + (checksum & NX_LOWER_16_MASK); + + /* Perform the one's complement operation on the checksum. */ + checksum = NX_LOWER_16_MASK & ~checksum; + + /* Return the checksum. */ + return(checksum); +} + diff --git a/common/src/nx_tcp_cleanup_deferred.c b/common/src/nx_tcp_cleanup_deferred.c new file mode 100644 index 0000000..edd1bf7 --- /dev/null +++ b/common/src/nx_tcp_cleanup_deferred.c @@ -0,0 +1,84 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_tcp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcp_cleanup_deferred PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function doesn't do anything and is simply used to indicate */ +/* that the appropriate cleanup routine as been deferred. This happens */ +/* as a result of the cleanup routine being called from timeout */ +/* processing, which takes place in the system timer thread or in an */ +/* ISR context - neither of which can obtain the IP mutex protection */ +/* and thus needs to be deferred. */ +/* */ +/* INPUT */ +/* */ +/* thread_ptr Pointer to suspended thread's */ +/* control block */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* None */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_tcp_cleanup_deferred(TX_THREAD *thread_ptr NX_CLEANUP_PARAMETER) +{ + + NX_PARAMETER_NOT_USED(thread_ptr); + + NX_CLEANUP_EXTENSION + + /* This function is never called... so do nothing! */ +} + diff --git a/common/src/nx_tcp_client_bind_cleanup.c b/common/src/nx_tcp_client_bind_cleanup.c new file mode 100644 index 0000000..0bbe90f --- /dev/null +++ b/common/src/nx_tcp_client_bind_cleanup.c @@ -0,0 +1,212 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "tx_thread.h" +#include "tx_timer.h" +#include "nx_ip.h" +#include "nx_tcp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcp_client_bind_cleanup PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes TCP bind timeout and thread terminate */ +/* actions that require the TCP socket 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 */ +/* */ +/* _nx_tcp_deferred_cleanup_check Deferred cleanup processing */ +/* _nx_tcp_client_socket_unbind Socket unbind processing */ +/* _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_tcp_client_bind_cleanup(TX_THREAD *thread_ptr NX_CLEANUP_PARAMETER) +{ + +TX_INTERRUPT_SAVE_AREA + +NX_IP *ip_ptr; +NX_TCP_SOCKET *socket_ptr; /* Working socket pointer */ +NX_TCP_SOCKET *owning_socket_ptr; /* Socket owning the port */ + + NX_CLEANUP_EXTENSION + + /* Disable interrupts to remove the suspended thread from the TCP socket. */ + TX_DISABLE + + /* Setup pointer to TCP socket control block. */ + socket_ptr = (NX_TCP_SOCKET *)thread_ptr -> tx_thread_suspend_control_block; + + /* 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 NetX IP thread. */ + + /* Under interrupt protection, see if the suspension is still in effect. */ + if ((thread_ptr -> tx_thread_suspend_cleanup) && (socket_ptr) && (socket_ptr -> nx_tcp_socket_id == NX_TCP_ID)) + { + + /* Yes, change the suspend cleanup routine to indicate the cleanup is deferred. */ + thread_ptr -> tx_thread_suspend_cleanup = _nx_tcp_cleanup_deferred; + + /* Pickup the IP pointer. */ + ip_ptr = socket_ptr -> nx_tcp_socket_ip_ptr; + + /* Restore interrupts. */ + TX_RESTORE + + /* Set the deferred cleanup flag for the IP thread. */ + tx_event_flags_set(&(ip_ptr -> nx_ip_events), NX_IP_TCP_CLEANUP_DEFERRED, TX_OR); + + /* Return to caller. */ + return; + } + else + { + + /* Restore interrupts. */ + TX_RESTORE + + /* Return to caller. */ + return; + } + } + + /* Determine if the cleanup is still required. */ + if ((thread_ptr -> tx_thread_suspend_cleanup) && (socket_ptr) && + (socket_ptr -> nx_tcp_socket_id == NX_TCP_ID)) + { + + /* Yes, we still have thread suspension! */ + + /* Clear the socket bind in progress flag. */ + socket_ptr -> nx_tcp_socket_bind_in_progress = NX_NULL; + + /* Clear the suspension cleanup flag. */ + thread_ptr -> tx_thread_suspend_cleanup = TX_NULL; + + /* Pickup the socket owning the port. This pointer was + saved in the bind processing prior to suspension. */ + owning_socket_ptr = socket_ptr -> nx_tcp_socket_bound_previous; + + /* 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. */ + owning_socket_ptr -> nx_tcp_socket_bind_suspension_list = NX_NULL; + } + else + { + + /* At least one more thread is on the same suspension list. */ + + /* Update the list head pointer. */ + owning_socket_ptr -> nx_tcp_socket_bind_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. */ + owning_socket_ptr -> nx_tcp_socket_bind_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 TCP socket. Setup return error status and + resume the thread. */ + + /* Setup return status. */ + thread_ptr -> tx_thread_suspend_status = NX_PORT_UNAVAILABLE; + + /* 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 +} + diff --git a/common/src/nx_tcp_client_socket_bind.c b/common/src/nx_tcp_client_socket_bind.c new file mode 100644 index 0000000..6a6602a --- /dev/null +++ b/common/src/nx_tcp_client_socket_bind.c @@ -0,0 +1,231 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_tcp.h" +#include "tx_thread.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcp_client_socket_bind PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function binds the TCP socket structure to a specific TCP */ +/* port. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to TCP socket */ +/* port 16-bit TCP port number */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_tcp_free_port_find Find free TCP port */ +/* _nx_tcp_socket_thread_suspend Suspend thread */ +/* 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_tcp_client_socket_bind(NX_TCP_SOCKET *socket_ptr, UINT port, ULONG wait_option) +{ +TX_INTERRUPT_SAVE_AREA + +UINT index; +NX_IP *ip_ptr; +NX_TCP_SOCKET *search_ptr; +NX_TCP_SOCKET *end_ptr; + + + /* Setup the pointer to the associated IP instance. */ + ip_ptr = socket_ptr -> nx_tcp_socket_ip_ptr; + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_TCP_CLIENT_SOCKET_BIND, ip_ptr, socket_ptr, port, wait_option, NX_TRACE_TCP_EVENTS, 0, 0) + + /* Obtain the IP mutex so we can figure out whether or not the port has already + been bound to. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Determine if the socket has already been bound to port or if a socket bind is + already pending from another thread. */ + if ((socket_ptr -> nx_tcp_socket_bound_next) || + (socket_ptr -> nx_tcp_socket_bind_in_progress)) + { + + /* Release the protection mutex. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return an already bound error code. */ + return(NX_ALREADY_BOUND); + } + + /* Determine if the port needs to be allocated. */ + if (port == NX_ANY_PORT) + { + + /* Call the find routine to allocate a TCP port. */ + port = NX_SEARCH_PORT_START + (UINT)(NX_RAND() % ((NX_MAX_PORT + 1) - NX_SEARCH_PORT_START)); + if (_nx_tcp_free_port_find(ip_ptr, port, &port) != NX_SUCCESS) + { + + /* Release the protection mutex. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* There was no free port, return an error code. */ + return(NX_NO_FREE_PORTS); + } + } + + /* Save the port number in the TCP socket structure. */ + socket_ptr -> nx_tcp_socket_port = port; + + /* 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. */ + search_ptr = ip_ptr -> nx_ip_tcp_port_table[index]; + + /* Determine if we need to perform a list search. */ + if (search_ptr) + { + + /* Walk through the circular list of TCP sockets that are already + bound. */ + end_ptr = search_ptr; + do + { + + /* Determine if this entry is the same as the requested port. */ + if (search_ptr -> nx_tcp_socket_port == port) + { + + /* Yes, the port has already been allocated. */ + break; + } + + /* Move to the next entry in the list. */ + search_ptr = search_ptr -> nx_tcp_socket_bound_next; + } while (search_ptr != end_ptr); + } + + /* Now determine if the port is available. */ + if ((search_ptr == NX_NULL) || (search_ptr -> nx_tcp_socket_port != port)) + { + + /* Place this TCP socket structure on the list of bound ports. */ + + /* Disable interrupts. */ + TX_DISABLE + + /* Determine if the list is NULL. */ + if (search_ptr) + { + + /* There are already sockets on this list... just add this one + to the end. */ + 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; + } + else + { + + /* Nothing is on the TCP port list. Add this TCP socket to an + empty list. */ + socket_ptr -> nx_tcp_socket_bound_next = socket_ptr; + socket_ptr -> nx_tcp_socket_bound_previous = socket_ptr; + ip_ptr -> nx_ip_tcp_port_table[index] = socket_ptr; + } + + /* Restore interrupts. */ + TX_RESTORE + + /* Release the mutex protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return success to the caller. */ + return(NX_SUCCESS); + } + else if (wait_option) + { + + /* Prepare for suspension of this thread. */ + + /* Increment the suspended thread count. */ + search_ptr -> nx_tcp_socket_bind_suspended_count++; + + /* Set the socket bind in progress flag (thread pointer). */ + socket_ptr -> nx_tcp_socket_bind_in_progress = _tx_thread_current_ptr; + + /* Also remember the socket that has bound to the port, since the thread + is going to be suspended on that socket. */ + socket_ptr -> nx_tcp_socket_bound_previous = search_ptr; + + /* Suspend the thread on this socket's connection attempt. */ + _nx_tcp_socket_thread_suspend(&(search_ptr -> nx_tcp_socket_bind_suspension_list), _nx_tcp_client_bind_cleanup, socket_ptr, &(ip_ptr -> nx_ip_protection), wait_option); + + /* Return the completion status. */ + return(_tx_thread_current_ptr -> tx_thread_suspend_status); + } + else + { + + /* Release the IP protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return the port unavailable error. */ + return(NX_PORT_UNAVAILABLE); + } +} + diff --git a/common/src/nx_tcp_client_socket_connect.c b/common/src/nx_tcp_client_socket_connect.c new file mode 100644 index 0000000..0b9cd15 --- /dev/null +++ b/common/src/nx_tcp_client_socket_connect.c @@ -0,0 +1,281 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_tcp.h" +#include "tx_thread.h" +#include "nx_ip.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcp_client_socket_connect PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function handles the connect request for the supplied socket. */ +/* If bound and not connected, this function will send the first SYN */ +/* message to the specified server to initiate the connection process. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to TCP client socket */ +/* server_ip IP address of server */ +/* server_port Port number of server */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_tcp_socket_thread_suspend Suspend thread for connection */ +/* _nx_tcp_packet_send_syn Send SYN packet */ +/* _nx_ip_route_find Find a suitable outgoing */ +/* interface. */ +/* tx_mutex_get Obtain protection */ +/* tx_mutex_put Release protection */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_tcp_client_socket_connect(NX_TCP_SOCKET *socket_ptr, ULONG server_ip, UINT server_port, ULONG wait_option) +{ + +NX_IP *ip_ptr; +NX_INTERFACE *outgoing_interface; + + + outgoing_interface = NX_NULL; + /* Setup IP pointer. */ + ip_ptr = socket_ptr -> nx_tcp_socket_ip_ptr; + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_TCP_CLIENT_SOCKET_CONNECT, ip_ptr, socket_ptr, server_ip, server_port, NX_TRACE_TCP_EVENTS, 0, 0) + + /* Obtain the IP mutex so we initiate the connect. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Determine if the socket has already been bound to port or if a socket bind is + already pending from another thread. */ + if (!socket_ptr -> nx_tcp_socket_bound_next) + { + + /* Release protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return a not bound error code. */ + return(NX_NOT_BOUND); + } + + /* Determine if the socket is in a pre-connection state. */ + if (socket_ptr -> nx_tcp_socket_state != NX_TCP_CLOSED) + { + + /* Release protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return a not closed error code. */ + return(NX_NOT_CLOSED); + } + + /* + Find out a suitable outgoing interface and the next hop address if the destination is not + directly attached to the local interface. Since TCP must operate on unicast address, + there is no need to pass in a "hint" for outgoing interface. + */ + + if (_nx_ip_route_find(ip_ptr, server_ip, &outgoing_interface, &socket_ptr -> nx_tcp_socket_next_hop_address) != NX_SUCCESS) + { + /* Release protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return an IP address error code. */ + return(NX_IP_ADDRESS_ERROR); + } + + +#ifndef NX_DISABLE_TCP_INFO + + /* Increment the active connections count. */ + ip_ptr -> nx_ip_tcp_active_connections++; + + /* Increment the TCP connections count. */ + ip_ptr -> nx_ip_tcp_connections++; +#endif + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_TCP_STATE_CHANGE, ip_ptr, socket_ptr, socket_ptr -> nx_tcp_socket_state, NX_TCP_SYN_SENT, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + /* Move the TCP state to Sequence Sent, the next state of an active open. */ + socket_ptr -> nx_tcp_socket_state = NX_TCP_SYN_SENT; + + /* Save the server port and server IP address. */ + socket_ptr -> nx_tcp_socket_connect_ip = server_ip; + socket_ptr -> nx_tcp_socket_connect_port = server_port; + + /* Initialize the maximum segment size based on the interface MTU. */ + if (outgoing_interface -> nx_interface_ip_mtu_size < (sizeof(NX_IP_HEADER) + sizeof(NX_TCP_HEADER))) + { + /* Interface MTU size is smaller than IP and TCP header size. Invalid interface! */ + +#ifndef NX_DISABLE_TCP_INFO + + /* Reduce the active connections count. */ + ip_ptr -> nx_ip_tcp_active_connections--; + + /* Reduce the TCP connections count. */ + ip_ptr -> nx_ip_tcp_connections--; +#endif + + /* Restore the socket state. */ + socket_ptr -> nx_tcp_socket_state = NX_TCP_CLOSED; + + /* Reset server port and server IP address. */ + socket_ptr -> nx_tcp_socket_connect_ip = 0; + socket_ptr -> nx_tcp_socket_connect_port = 0; + + /* Reset the next_hop_address information. */ + socket_ptr -> nx_tcp_socket_next_hop_address = 0; + + /* Release protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + + /* Return an IP address error code. */ + return(NX_INVALID_INTERFACE); + } + + socket_ptr -> nx_tcp_socket_connect_interface = outgoing_interface; + + /* Setup the initial sequence number. */ + if (socket_ptr -> nx_tcp_socket_tx_sequence == 0) + { + socket_ptr -> nx_tcp_socket_tx_sequence = (((ULONG)NX_RAND()) << NX_SHIFT_BY_16) | ((ULONG)NX_RAND()); + } + else + { + socket_ptr -> nx_tcp_socket_tx_sequence = socket_ptr -> nx_tcp_socket_tx_sequence + ((ULONG)(((ULONG)0x10000))) + ((ULONG)NX_RAND()); + } + + /* Ensure the rx window size logic is reset. */ + socket_ptr -> nx_tcp_socket_rx_window_current = socket_ptr -> nx_tcp_socket_rx_window_default; + socket_ptr -> nx_tcp_socket_rx_window_last_sent = socket_ptr -> nx_tcp_socket_rx_window_default; + + /* Clear the FIN received flag. */ + socket_ptr -> nx_tcp_socket_fin_received = NX_FALSE; + + /* Increment the sequence number. */ + socket_ptr -> nx_tcp_socket_tx_sequence++; + + /* Setup a timeout so the connection attempt can be sent again. */ + socket_ptr -> nx_tcp_socket_timeout = socket_ptr -> nx_tcp_socket_timeout_rate; + socket_ptr -> nx_tcp_socket_timeout_retries = 0; + + /* CLEANUP: Clean up any existing socket data before making a new connection. */ + socket_ptr -> nx_tcp_socket_tx_window_congestion = 0; + socket_ptr -> nx_tcp_socket_tx_outstanding_bytes = 0; + socket_ptr -> nx_tcp_socket_packets_sent = 0; + socket_ptr -> nx_tcp_socket_bytes_sent = 0; + socket_ptr -> nx_tcp_socket_packets_received = 0; + socket_ptr -> nx_tcp_socket_bytes_received = 0; + socket_ptr -> nx_tcp_socket_retransmit_packets = 0; + socket_ptr -> nx_tcp_socket_checksum_errors = 0; + socket_ptr -> nx_tcp_socket_transmit_sent_head = NX_NULL; + socket_ptr -> nx_tcp_socket_transmit_sent_tail = NX_NULL; + socket_ptr -> nx_tcp_socket_transmit_sent_count = 0; + socket_ptr -> nx_tcp_socket_receive_queue_count = 0; + socket_ptr -> nx_tcp_socket_receive_queue_head = NX_NULL; + socket_ptr -> nx_tcp_socket_receive_queue_tail = NX_NULL; + + /* Send the SYN message. */ + _nx_tcp_packet_send_syn(socket_ptr, (socket_ptr -> nx_tcp_socket_tx_sequence - 1)); + + /* Determine if the connection is complete. This can only happen in a connection + between ports on the same IP instance. */ + if (socket_ptr -> nx_tcp_socket_state == NX_TCP_ESTABLISHED) + { + + /* Release the protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return a successful status. */ + return(NX_SUCCESS); + } + + /* 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 != &(ip_ptr -> nx_ip_thread))) + { + + /* Suspend the thread on this socket's connection attempt. */ + _nx_tcp_socket_thread_suspend(&(socket_ptr -> nx_tcp_socket_connect_suspended_thread), _nx_tcp_connect_cleanup, socket_ptr, &(ip_ptr -> nx_ip_protection), wait_option); + + /* Check if the socket connection has failed. */ + if (_tx_thread_current_ptr -> tx_thread_suspend_status) + { + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_TCP_STATE_CHANGE, ip_ptr, socket_ptr, socket_ptr -> nx_tcp_socket_state, NX_TCP_CLOSED, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + /* Yes, socket connection has failed. Return to the + closed state so it can be tried again. */ + socket_ptr -> nx_tcp_socket_state = NX_TCP_CLOSED; + } + + /* 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(&(ip_ptr -> nx_ip_protection)); + + /* Return in-progress completion status. */ + return(NX_IN_PROGRESS); + } +} + diff --git a/common/src/nx_tcp_client_socket_port_get.c b/common/src/nx_tcp_client_socket_port_get.c new file mode 100644 index 0000000..6b1fb9a --- /dev/null +++ b/common/src/nx_tcp_client_socket_port_get.c @@ -0,0 +1,110 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_tcp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcp_client_socket_port_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves the bound port of the specified socket, */ +/* which is especially useful in situations where NX_ANY_PORT was */ +/* used to bind. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to TCP client socket */ +/* port_ptr Destination for port bound to */ +/* this socket */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Obtain protection */ +/* tx_mutex_put Release protection */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_tcp_client_socket_port_get(NX_TCP_SOCKET *socket_ptr, UINT *port_ptr) +{ + +NX_IP *ip_ptr; + + + /* Setup IP pointer. */ + ip_ptr = socket_ptr -> nx_tcp_socket_ip_ptr; + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_TCP_CLIENT_SOCKET_PORT_GET, ip_ptr, socket_ptr, socket_ptr -> nx_tcp_socket_port, 0, NX_TRACE_TCP_EVENTS, 0, 0) + + /* Obtain the IP mutex so we can examine the bound port. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Determine if the socket has already been bound to port or if a socket bind is + already pending from another thread. */ + if (!socket_ptr -> nx_tcp_socket_bound_next) + { + + /* Release protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return a not bound error code. */ + return(NX_NOT_BOUND); + } + + /* Return the port number from the socket. */ + *port_ptr = socket_ptr -> nx_tcp_socket_port; + + /* Release protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return successful completion status. */ + return(NX_SUCCESS); +} + diff --git a/common/src/nx_tcp_client_socket_unbind.c b/common/src/nx_tcp_client_socket_unbind.c new file mode 100644 index 0000000..8281f53 --- /dev/null +++ b/common/src/nx_tcp_client_socket_unbind.c @@ -0,0 +1,283 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_tcp.h" +#include "tx_thread.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcp_client_socket_unbind PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function unbinds the TCP client socket structure from the */ +/* previously bound TCP port. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to TCP client socket */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_tcp_client_bind_cleanup Remove and cleanup bind req */ +/* _nx_tcp_disconnect_cleanup Disconnect cleanup */ +/* _nx_tcp_socket_receive_queue_flush Release all received packets */ +/* _nx_tcp_socket_thread_resume Resume thread suspended on */ +/* port */ +/* 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_tcp_client_socket_unbind(NX_TCP_SOCKET *socket_ptr) +{ +TX_INTERRUPT_SAVE_AREA + +UINT index; +UINT port; +NX_IP *ip_ptr; +NX_TCP_SOCKET *new_socket_ptr; + + + /* Setup the pointer to the associated IP instance. */ + ip_ptr = socket_ptr -> nx_tcp_socket_ip_ptr; + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_TCP_CLIENT_SOCKET_UNBIND, ip_ptr, socket_ptr, 0, 0, NX_TRACE_TCP_EVENTS, 0, 0) + + /* Obtain the IP mutex so we can figure out whether or not the port has already + been bound to. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Determine if the socket is in a state of disconnect. */ + if (socket_ptr -> nx_tcp_socket_state >= NX_TCP_CLOSE_WAIT) + { + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_TCP_STATE_CHANGE, ip_ptr, socket_ptr, socket_ptr -> nx_tcp_socket_state, NX_TCP_CLOSED, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + /* Force to the final state of disconnect. */ + socket_ptr -> nx_tcp_socket_state = NX_TCP_CLOSED; + + /* Ensure the connect information is cleared. */ + socket_ptr -> nx_tcp_socket_connect_ip = 0; + socket_ptr -> nx_tcp_socket_connect_port = 0; + + /* This socket port is being removed from the listen list. Make sure there is no active socket timeout. */ + socket_ptr -> nx_tcp_socket_timeout = 0; + } + + /* Determine if the socket is still in the closed state. */ + if (socket_ptr -> nx_tcp_socket_state != NX_TCP_CLOSED) + { + + /* No, release the IP protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return an error code. */ + return(NX_NOT_CLOSED); + } + + /* Check for a thread suspended for disconnect processing to complete. */ + if (socket_ptr -> nx_tcp_socket_disconnect_suspended_thread) + { + + /* Call the disconnect thread suspension cleanup routine. */ + _nx_tcp_disconnect_cleanup(socket_ptr -> nx_tcp_socket_disconnect_suspended_thread NX_CLEANUP_ARGUMENT); + } + + /* Determine if the socket is bound to port. */ + if (!socket_ptr -> nx_tcp_socket_bound_next) + { + + /* Determine if there is a special condition for the socket not being in + a bound condition... i.e. the socket is in a pending-to-be-bound condition + in a call from a different thread. */ + if (socket_ptr -> nx_tcp_socket_bind_in_progress) + { + + /* Execute the bind suspension cleanup routine. */ + _nx_tcp_client_bind_cleanup(socket_ptr -> nx_tcp_socket_bind_in_progress NX_CLEANUP_ARGUMENT); + + /* Release the protection mutex. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return success. */ + return(NX_SUCCESS); + } + else + { + + /* Release the protection mutex. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return a not bound error code. */ + return(NX_NOT_BOUND); + } + } + + /* Otherwise, the socket is bound. We need to remove this socket from the + port and check for any other TCP socket bind requests that are queued. */ + + /* Pickup the port number in the TCP socket structure. */ + port = socket_ptr -> nx_tcp_socket_port; + + /* Calculate the hash index in the TCP port array of the associated IP instance. */ + index = (UINT)((port + (port >> 8)) & NX_TCP_PORT_TABLE_MASK); + + /* Disable interrupts while we unlink the current socket. */ + TX_DISABLE + + /* Determine if this is the only socket bound on this port list. */ + if (socket_ptr -> nx_tcp_socket_bound_next == socket_ptr) + { + + /* Yes, this is the only socket on the port list. */ + + /* Clear the list head pointer and the next pointer in the socket. */ + ip_ptr -> nx_ip_tcp_port_table[index] = NX_NULL; + socket_ptr -> nx_tcp_socket_bound_next = NX_NULL; + } + else + { + + /* Relink the neighbors of this TCP socket. */ + + /* Update the links of the adjacent sockets. */ + (socket_ptr -> nx_tcp_socket_bound_next) -> nx_tcp_socket_bound_previous = + socket_ptr -> nx_tcp_socket_bound_previous; + (socket_ptr -> nx_tcp_socket_bound_previous) -> nx_tcp_socket_bound_next = + socket_ptr -> nx_tcp_socket_bound_next; + + /* Determine if the head of the port list points to the socket being removed. + If so, we need to move the head pointer. */ + if (ip_ptr -> nx_ip_tcp_port_table[index] == socket_ptr) + { + + /* Yes, we need to move the port list head pointer. */ + ip_ptr -> nx_ip_tcp_port_table[index] = socket_ptr -> nx_tcp_socket_bound_next; + } + + /* Clear the next pointer in the socket to indicate it is no longer bound. */ + socket_ptr -> nx_tcp_socket_bound_next = NX_NULL; + } + + /* Restore interrupts. */ + TX_RESTORE + + /* The socket is off the bound list... we need to check for queued receive packets and + if found they need to be released. */ + if (socket_ptr -> nx_tcp_socket_receive_queue_count) + { + + /* Remove all packets on the socket's receive queue. */ + _nx_tcp_socket_receive_queue_flush(socket_ptr); + } + + /* Determine if there are any threads suspended on trying to bind to the + same port. */ + if (socket_ptr -> nx_tcp_socket_bind_suspension_list) + { + + /* Pickup the new socket structure to link to the port list. */ + new_socket_ptr = (NX_TCP_SOCKET *)(socket_ptr -> nx_tcp_socket_bind_suspension_list) -> tx_thread_suspend_control_block; + + /* Clear the new socket's bind in progress flag. */ + new_socket_ptr -> nx_tcp_socket_bind_in_progress = NX_NULL; + + /* Inherit the suspension list from the previously bound socket. Decrement the suspension count + early since this thread will be resumed and removed from the list later. */ + new_socket_ptr -> nx_tcp_socket_bind_suspension_list = + socket_ptr -> nx_tcp_socket_bind_suspension_list; + new_socket_ptr -> nx_tcp_socket_bind_suspended_count = socket_ptr -> nx_tcp_socket_bind_suspended_count - 1; + + /* Clear the original socket's information. */ + socket_ptr -> nx_tcp_socket_bind_suspension_list = NX_NULL; + socket_ptr -> nx_tcp_socket_bind_suspended_count = 0; + + /* Disable interrupts. */ + TX_DISABLE + + /* Link the new socket to the bound list. */ + if (ip_ptr -> nx_ip_tcp_port_table[index]) + { + + /* There are already sockets on this list... just add this one + to the end. */ + new_socket_ptr -> nx_tcp_socket_bound_next = + ip_ptr -> nx_ip_tcp_port_table[index]; + new_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 = + new_socket_ptr; + (ip_ptr -> nx_ip_tcp_port_table[index]) -> nx_tcp_socket_bound_previous = new_socket_ptr; + } + else + { + + /* Nothing is on the TCP port list. Add this TCP socket to an + empty list. */ + new_socket_ptr -> nx_tcp_socket_bound_next = new_socket_ptr; + new_socket_ptr -> nx_tcp_socket_bound_previous = new_socket_ptr; + ip_ptr -> nx_ip_tcp_port_table[index] = new_socket_ptr; + } + + /* Restore interrupts. */ + TX_RESTORE + + /* Resume the thread suspended on the bind call. */ + _nx_tcp_socket_thread_resume(&(new_socket_ptr -> nx_tcp_socket_bind_suspension_list), NX_SUCCESS); + } + + /* Release the protection mutex. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return success. */ + return(NX_SUCCESS); +} + diff --git a/common/src/nx_tcp_connect_cleanup.c b/common/src/nx_tcp_connect_cleanup.c new file mode 100644 index 0000000..3b4fc8b --- /dev/null +++ b/common/src/nx_tcp_connect_cleanup.c @@ -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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "tx_thread.h" +#include "tx_timer.h" +#include "nx_ip.h" +#include "nx_tcp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcp_connect_cleanup PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes TCP connect timeout and thread terminate */ +/* actions that require the TCP socket 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 */ +/* */ +/* _nx_tcp_deferred_cleanup_check Deferred cleanup processing */ +/* _nx_tcp_socket_connection_reset Socket reset processing */ +/* _nx_tcp_socket_disconnect Socket disconnect processing */ +/* _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_tcp_connect_cleanup(TX_THREAD *thread_ptr NX_CLEANUP_PARAMETER) +{ + +TX_INTERRUPT_SAVE_AREA + +NX_IP *ip_ptr; +NX_TCP_SOCKET *socket_ptr; /* Working socket pointer */ + + NX_CLEANUP_EXTENSION + + /* Disable interrupts. */ + TX_DISABLE + + /* Setup pointer to TCP socket control block. */ + socket_ptr = (NX_TCP_SOCKET *)thread_ptr -> tx_thread_suspend_control_block; + + /* Determine if the socket pointer is valid. */ + if ((!socket_ptr) || (socket_ptr -> nx_tcp_socket_id != NX_TCP_ID)) + { + + /* Restore interrupts. */ + TX_RESTORE + + return; + } + + /* Pickup the IP pointer. */ + ip_ptr = socket_ptr -> nx_tcp_socket_ip_ptr; + + + /* 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 NetX IP thread. */ + + /* Under interrupt protection, see if the suspension is still in effect. */ + if ((thread_ptr -> tx_thread_suspend_cleanup) && (socket_ptr) && (socket_ptr -> nx_tcp_socket_id == NX_TCP_ID)) + { + + /* Yes, change the suspend cleanup routine to indicate the cleanup is deferred. */ + thread_ptr -> tx_thread_suspend_cleanup = _nx_tcp_cleanup_deferred; + + /* Restore interrupts. */ + TX_RESTORE + + /* Set the deferred cleanup flag for the IP thread. */ + tx_event_flags_set(&(ip_ptr -> nx_ip_events), NX_IP_TCP_CLEANUP_DEFERRED, TX_OR); + + /* Return to caller. */ + return; + } + else + { + + /* Restore interrupts. */ + TX_RESTORE + + /* Return to caller. */ + return; + } + } + + /* Determine if the cleanup is still required. */ + if ((thread_ptr -> tx_thread_suspend_cleanup) && (socket_ptr) && (socket_ptr -> nx_tcp_socket_id == NX_TCP_ID)) + { + + /* Yes, we still have thread suspension! */ + + /* Clear the suspension cleanup flag. */ + thread_ptr -> tx_thread_suspend_cleanup = TX_NULL; + + /* Clear the suspension pointer. */ + socket_ptr -> nx_tcp_socket_connect_suspended_thread = NX_NULL; + + /* Clear the timeout. */ + socket_ptr -> nx_tcp_socket_timeout = 0; + + /* Return to the proper socket state. */ + if (socket_ptr -> nx_tcp_socket_client_type) + { + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_TCP_STATE_CHANGE, ip_ptr, socket_ptr, socket_ptr -> nx_tcp_socket_state, NX_TCP_CLOSED, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + /* Client socket, return to a CLOSED state. */ + socket_ptr -> nx_tcp_socket_state = NX_TCP_CLOSED; + } + else + { + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_TCP_STATE_CHANGE, ip_ptr, socket_ptr, socket_ptr -> nx_tcp_socket_state, NX_TCP_LISTEN_STATE, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + /* Server socket, return to LISTEN state. */ + socket_ptr -> nx_tcp_socket_state = NX_TCP_LISTEN_STATE; + + /* Move back the acknowledgment number just in case there is a retry. */ + socket_ptr -> nx_tcp_socket_rx_sequence--; + } + + /* 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 TCP socket. Setup return error status and + resume the thread. */ + + /* Setup return status. */ + thread_ptr -> tx_thread_suspend_status = NX_NOT_CONNECTED; + + /* 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 +} + diff --git a/common/src/nx_tcp_deferred_cleanup_check.c b/common/src/nx_tcp_deferred_cleanup_check.c new file mode 100644 index 0000000..9e2f015 --- /dev/null +++ b/common/src/nx_tcp_deferred_cleanup_check.c @@ -0,0 +1,203 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_tcp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcp_deferred_cleanup_check PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for deferred cleanup processing, which is the */ +/* case for all TCP socket timeout processing. This is done so that */ +/* mutex protection can be obtained prior to processing the timeout. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP control block */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_tcp_client_bind_cleanup Bind cleanup */ +/* _nx_tcp_connect_cleanup Connect cleanup */ +/* _nx_tcp_disconnect_cleanup Disconnect cleanup */ +/* _nx_tcp_receive_cleanup Receive cleanup */ +/* _nx_tcp_transmit_cleanup Transmit cleanup */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ip_thread_entry IP helper thread */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_tcp_deferred_cleanup_check(NX_IP *ip_ptr) +{ + +ULONG created_sockets; +ULONG suspended_threads; +NX_TCP_SOCKET *socket_ptr; +TX_THREAD *thread_ptr; + + + /* Pickup the first socket and the created count. */ + socket_ptr = ip_ptr -> nx_ip_tcp_created_sockets_ptr; + created_sockets = ip_ptr -> nx_ip_tcp_created_sockets_count; + + /* Loop through all created TCP sockets on the IP instance. */ + while (created_sockets--) + { + + /* Check the socket for deferred bind cleanup. */ + suspended_threads = socket_ptr -> nx_tcp_socket_bind_suspended_count; + if (suspended_threads) + { + + /* Pickup the socket pointer. */ + thread_ptr = socket_ptr -> nx_tcp_socket_bind_suspension_list; + + /* Loop through the suspended threads for the bind operation to determine if there + is a timeout. */ + do + { + + /* Determine if this thread has deferred the timeout processing. */ + if (thread_ptr -> tx_thread_suspend_cleanup == _nx_tcp_cleanup_deferred) + { + + /* Yes, call the cleanup routine again! */ + _nx_tcp_client_bind_cleanup(thread_ptr NX_CLEANUP_ARGUMENT); + } + + /* Move to next suspended thread. */ + thread_ptr = thread_ptr -> tx_thread_suspended_next; + } while (--suspended_threads); + } + + /* Check the socket for deferred connect cleanup. */ + thread_ptr = socket_ptr -> nx_tcp_socket_connect_suspended_thread; + if (thread_ptr) + { + + /* Determine if this thread has deferred the timeout processing. */ + if (thread_ptr -> tx_thread_suspend_cleanup == _nx_tcp_cleanup_deferred) + { + + /* Yes, call the cleanup routine again! */ + _nx_tcp_connect_cleanup(thread_ptr NX_CLEANUP_ARGUMENT); + } + } + + /* Check the socket for deferred disconnect cleanup. */ + thread_ptr = socket_ptr -> nx_tcp_socket_disconnect_suspended_thread; + if (thread_ptr) + { + + /* Determine if this thread has deferred the timeout processing. */ + if (thread_ptr -> tx_thread_suspend_cleanup == _nx_tcp_cleanup_deferred) + { + + /* Yes, call the cleanup routine again! */ + _nx_tcp_disconnect_cleanup(thread_ptr NX_CLEANUP_ARGUMENT); + } + } + + /* Check the socket for deferred receive cleanup. */ + suspended_threads = socket_ptr -> nx_tcp_socket_receive_suspended_count; + if (suspended_threads) + { + + /* Pickup the socket pointer. */ + thread_ptr = socket_ptr -> nx_tcp_socket_receive_suspension_list; + + /* Loop through the suspended threads for the receive operation to determine if there + is a timeout. */ + do + { + + /* Determine if this thread has deferred the timeout processing. */ + if (thread_ptr -> tx_thread_suspend_cleanup == _nx_tcp_cleanup_deferred) + { + + /* Yes, call the cleanup routine again! */ + _nx_tcp_receive_cleanup(thread_ptr NX_CLEANUP_ARGUMENT); + } + + /* Move to next suspended thread. */ + thread_ptr = thread_ptr -> tx_thread_suspended_next; + } while (--suspended_threads); + } + + /* Check the socket for deferred transmit cleanup. */ + suspended_threads = socket_ptr -> nx_tcp_socket_transmit_suspended_count; + if (suspended_threads) + { + + /* Pickup the socket pointer. */ + thread_ptr = socket_ptr -> nx_tcp_socket_transmit_suspension_list; + + /* Loop through the suspended threads for the transmit operation to determine if there + is a timeout. */ + do + { + + /* Determine if this thread has deferred the timeout processing. */ + if (thread_ptr -> tx_thread_suspend_cleanup == _nx_tcp_cleanup_deferred) + { + + /* Yes, call the cleanup routine again! */ + _nx_tcp_transmit_cleanup(thread_ptr NX_CLEANUP_ARGUMENT); + } + + /* Move to next suspended thread. */ + thread_ptr = thread_ptr -> tx_thread_suspended_next; + } while (--suspended_threads); + } + + /* Move to next created TCP socket. */ + socket_ptr = socket_ptr -> nx_tcp_socket_created_next; + } +} + diff --git a/common/src/nx_tcp_disconnect_cleanup.c b/common/src/nx_tcp_disconnect_cleanup.c new file mode 100644 index 0000000..2613ab9 --- /dev/null +++ b/common/src/nx_tcp_disconnect_cleanup.c @@ -0,0 +1,189 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "tx_thread.h" +#include "tx_timer.h" +#include "nx_ip.h" +#include "nx_tcp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcp_disconnect_cleanup PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes TCP disconnect timeout and thread terminate */ +/* actions that require the TCP socket 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 */ +/* */ +/* _nx_tcp_deferred_cleanup_check Deferred cleanup processing */ +/* _nx_tcp_client_socket_unbind Client socket unbind */ +/* _nx_tcp_socket_connection_reset Connection reset processing */ +/* _nx_tcp_socket_disconnect Socket disconnect */ +/* _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_tcp_disconnect_cleanup(TX_THREAD *thread_ptr NX_CLEANUP_PARAMETER) +{ + +TX_INTERRUPT_SAVE_AREA + +NX_IP *ip_ptr; +NX_TCP_SOCKET *socket_ptr; /* Working socket pointer */ + + NX_CLEANUP_EXTENSION + + /* Disable interrupts. */ + TX_DISABLE + + /* Setup pointer to TCP socket control block. */ + socket_ptr = (NX_TCP_SOCKET *)thread_ptr -> tx_thread_suspend_control_block; + + /* Determine if the socket pointer is valid. */ + if ((!socket_ptr) || (socket_ptr -> nx_tcp_socket_id != NX_TCP_ID)) + { + + /* 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 NetX IP thread. */ + + /* Under interrupt protection, see if the suspension is still in effect. */ + if ((thread_ptr -> tx_thread_suspend_cleanup) && (socket_ptr) && (socket_ptr -> nx_tcp_socket_id == NX_TCP_ID)) + { + + /* Yes, change the suspend cleanup routine to indicate the cleanup is deferred. */ + thread_ptr -> tx_thread_suspend_cleanup = _nx_tcp_cleanup_deferred; + + /* Pickup the IP pointer. */ + ip_ptr = socket_ptr -> nx_tcp_socket_ip_ptr; + + /* Restore interrupts. */ + TX_RESTORE + + /* Set the deferred cleanup flag for the IP thread. */ + tx_event_flags_set(&(ip_ptr -> nx_ip_events), NX_IP_TCP_CLEANUP_DEFERRED, TX_OR); + + /* Return to caller. */ + return; + } + else + { + + /* Restore interrupts. */ + TX_RESTORE + + /* Return to caller. */ + return; + } + } + + /* Determine if the cleanup is still required. */ + if ((thread_ptr -> tx_thread_suspend_cleanup) && (socket_ptr) && (socket_ptr -> nx_tcp_socket_id == NX_TCP_ID)) + { + + /* Yes, we still have thread suspension! */ + + /* Clear the suspension cleanup flag. */ + thread_ptr -> tx_thread_suspend_cleanup = TX_NULL; + + /* Clear the suspension pointer. */ + socket_ptr -> nx_tcp_socket_disconnect_suspended_thread = NX_NULL; + + /* 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 TCP socket. Setup return error status and + resume the thread. */ + + /* Setup return status. */ + thread_ptr -> tx_thread_suspend_status = NX_DISCONNECT_FAILED; + + /* 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 +} + diff --git a/common/src/nx_tcp_enable.c b/common/src/nx_tcp_enable.c new file mode 100644 index 0000000..22a9acc --- /dev/null +++ b/common/src/nx_tcp_enable.c @@ -0,0 +1,135 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_tcp.h" +#include "nx_system.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcp_enable PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function enables the TCP management component for the */ +/* specified IP instance. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP instance pointer */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_timer_create Create fast TCP timer */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_tcp_enable(NX_IP *ip_ptr) +{ + +UINT i; +struct NX_TCP_LISTEN_STRUCT *listen_ptr; + + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_TCP_ENABLE, ip_ptr, 0, 0, 0, NX_TRACE_TCP_EVENTS, 0, 0) + + /* Place all server listen request structures on the available list. */ + + /* Setup a pointer to the first listen. */ + listen_ptr = &(ip_ptr -> nx_ip_tcp_server_listen_reqs[0]); + + /* Setup the available listen requests head pointer. */ + ip_ptr -> nx_ip_tcp_available_listen_requests = listen_ptr; + + /* Loop through the listen requests and link them on the available list. */ + for (i = 0; i < NX_MAX_LISTEN_REQUESTS; i++) + { + + /* Link listen request to next listen request. */ + listen_ptr -> nx_tcp_listen_next = listen_ptr + 1; + + /* Determine if we need to move to the next listen request. */ + if (i < (NX_MAX_LISTEN_REQUESTS - 1)) + { + listen_ptr++; + } + } + + /* Make sure the last listen request has a NULL pointer. */ + listen_ptr -> nx_tcp_listen_next = NX_NULL; + + /* Set the TCP packet queue processing function. */ + ip_ptr -> nx_ip_tcp_queue_process = _nx_tcp_queue_process; + + /* Set the TCP periodic processing function. */ + ip_ptr -> nx_ip_tcp_periodic_processing = _nx_tcp_periodic_processing; + + /* Set the TCP fast periodic processing function. */ + ip_ptr -> nx_ip_tcp_fast_periodic_processing = _nx_tcp_fast_periodic_processing; + + /* Set the TCP deferred cleanup check function. */ + ip_ptr -> nx_tcp_deferred_cleanup_check = _nx_tcp_deferred_cleanup_check; + + /* Setup base timer variables. */ + _nx_tcp_fast_timer_rate = (NX_IP_PERIODIC_RATE + (NX_TCP_FAST_TIMER_RATE - 1)) / NX_TCP_FAST_TIMER_RATE; + _nx_tcp_ack_timer_rate = (NX_IP_PERIODIC_RATE + (NX_TCP_ACK_TIMER_RATE - 1)) / NX_TCP_ACK_TIMER_RATE; + _nx_tcp_transmit_timer_rate = (NX_IP_PERIODIC_RATE + (NX_TCP_TRANSMIT_TIMER_RATE - 1)) / NX_TCP_TRANSMIT_TIMER_RATE; + + /* Create the fast TCP timer. */ + tx_timer_create(&(ip_ptr -> nx_ip_tcp_fast_periodic_timer), ip_ptr -> nx_ip_name, + _nx_tcp_fast_periodic_timer_entry, (ULONG)ip_ptr, + _nx_tcp_fast_timer_rate, _nx_tcp_fast_timer_rate, TX_AUTO_ACTIVATE); + + /* Set the TCP packet receive function in the IP structure to indicate + we are ready to receive TCP packets. */ + ip_ptr -> nx_ip_tcp_packet_receive = _nx_tcp_packet_receive; + + /* Return successful completion. */ + return(NX_SUCCESS); +} + diff --git a/common/src/nx_tcp_fast_periodic_processing.c b/common/src/nx_tcp_fast_periodic_processing.c new file mode 100644 index 0000000..440c421 --- /dev/null +++ b/common/src/nx_tcp_fast_periodic_processing.c @@ -0,0 +1,200 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_packet.h" +#include "nx_tcp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcp_fast_periodic_processing PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes the fast periodic TCP processing for */ +/* sending delayed ACK messages for previous receive operations and */ +/* for re-transmitting packets that have not been ACKed by the other */ +/* side of the connection. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP control block */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_tcp_packet_send_ack Send a delayed ACK */ +/* _nx_tcp_packet_send_syn Send initial SYN again */ +/* _nx_tcp_socket_connection_reset Reset connection on timeout */ +/* _nx_tcp_socket_retransmit Retransmit packet */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ip_thread_entry IP helper thread */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_tcp_fast_periodic_processing(NX_IP *ip_ptr) +{ + +NX_TCP_SOCKET *socket_ptr; +ULONG sockets; +ULONG timer_rate; + + + /* Pickup this timer's periodic rate. */ + timer_rate = _nx_tcp_fast_timer_rate; + + /* Pickup the number of created TCP sockets. */ + sockets = ip_ptr -> nx_ip_tcp_created_sockets_count; + + /* Pickup the first socket. */ + socket_ptr = ip_ptr -> nx_ip_tcp_created_sockets_ptr; + + /* Loop through the created sockets. */ + while (sockets--) + { + + + + /* Determine if the socket is in an established or disconnect state and has delayed sending an ACK + from a previous receive packet event. */ + if ((socket_ptr -> nx_tcp_socket_state >= NX_TCP_ESTABLISHED) && + ((socket_ptr -> nx_tcp_socket_rx_sequence != socket_ptr -> nx_tcp_socket_rx_sequence_acked) || + (socket_ptr -> nx_tcp_socket_rx_window_last_sent < socket_ptr -> nx_tcp_socket_rx_window_current))) + { + + /* Determine if the ACK has expired. */ + if (socket_ptr -> nx_tcp_socket_delayed_ack_timeout <= timer_rate) + { + + /* Send the delayed ACK, which also resets the ACK timeout. */ + _nx_tcp_packet_send_ack(socket_ptr, socket_ptr -> nx_tcp_socket_tx_sequence); + } + else + { + + /* No, it hasn't expired yet. Just decrement it for now. */ + socket_ptr -> nx_tcp_socket_delayed_ack_timeout = + socket_ptr -> nx_tcp_socket_delayed_ack_timeout - timer_rate; + } + } + + + /* Determine if a timeout is active. */ + if (socket_ptr -> nx_tcp_socket_timeout) + { + + /* Yes, a timeout is active. Determine if it has expired. */ + if (socket_ptr -> nx_tcp_socket_timeout > timer_rate) + { + + /* No, it hasn't expired yet. Just decrement the timeout value. */ + socket_ptr -> nx_tcp_socket_timeout = socket_ptr -> nx_tcp_socket_timeout - timer_rate; + } + else if (socket_ptr -> nx_tcp_socket_timeout_retries >= socket_ptr -> nx_tcp_socket_timeout_max_retries) + { + + /* Number of retries has been exceeded. */ + + /* Close the socket via a connection reset. */ + _nx_tcp_socket_connection_reset(socket_ptr); + } + else if ((socket_ptr -> nx_tcp_socket_state == NX_TCP_SYN_SENT) || + (socket_ptr -> nx_tcp_socket_state == NX_TCP_SYN_RECEIVED)) + { + + /* Yes, the timeout on the SYN message has expired. */ + + /* Increment the retry counter. */ + socket_ptr -> nx_tcp_socket_timeout_retries++; + + /* Setup the next timeout. */ + socket_ptr -> nx_tcp_socket_timeout = + socket_ptr -> nx_tcp_socket_timeout_rate << + (socket_ptr -> nx_tcp_socket_timeout_retries * socket_ptr -> nx_tcp_socket_timeout_shift); + + /* Send the initial SYN message again. Adjust the sequence number before and + after to ensure the same sequence as the initial SYN. */ + _nx_tcp_packet_send_syn(socket_ptr, (socket_ptr -> nx_tcp_socket_tx_sequence - 1)); + } + /* Has the TCP timeout for transmit packet expired? */ + else if (socket_ptr -> nx_tcp_socket_transmit_sent_head) + { + + /* Update the transmit sequence that entered fast transmit. */ + socket_ptr -> nx_tcp_socket_tx_sequence_recover = socket_ptr -> nx_tcp_socket_tx_sequence - 1; + + /* Retransmit the packet. */ + _nx_tcp_socket_retransmit(ip_ptr, socket_ptr, NX_FALSE); + + /* Exit fast recovery procedure. */ + socket_ptr -> nx_tcp_socket_fast_recovery = NX_FALSE; + socket_ptr -> nx_tcp_socket_tx_window_congestion = socket_ptr -> nx_tcp_socket_tx_slow_start_threshold; + } + else if ((socket_ptr -> nx_tcp_socket_state == NX_TCP_FIN_WAIT_1) || + (socket_ptr -> nx_tcp_socket_state == NX_TCP_CLOSING) || + (socket_ptr -> nx_tcp_socket_state == NX_TCP_LAST_ACK)) + { + + /* We have a timeout condition on sending the FIN... so it needs to be + retried. */ + + /* Increment the retry counter. */ + socket_ptr -> nx_tcp_socket_timeout_retries++; + + /* Setup the next timeout. */ + socket_ptr -> nx_tcp_socket_timeout = + socket_ptr -> nx_tcp_socket_timeout_rate << + (socket_ptr -> nx_tcp_socket_timeout_retries * socket_ptr -> nx_tcp_socket_timeout_shift); + + /* Send another FIN packet. */ + _nx_tcp_packet_send_fin(socket_ptr, (socket_ptr -> nx_tcp_socket_tx_sequence - 1)); + } + } + + /* Move to the next TCP socket. */ + socket_ptr = socket_ptr -> nx_tcp_socket_created_next; + } +} + diff --git a/common/src/nx_tcp_fast_periodic_timer_entry.c b/common/src/nx_tcp_fast_periodic_timer_entry.c new file mode 100644 index 0000000..1fccdf0 --- /dev/null +++ b/common/src/nx_tcp_fast_periodic_timer_entry.c @@ -0,0 +1,85 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_tcp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcp_fast_periodic_timer_entry PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function handles waking up the IP helper thread on a periodic */ +/* basis for higher-frequency TCP events. This timer is enabled when */ +/* TCP is enabled. */ +/* */ +/* INPUT */ +/* */ +/* ip_address IP address in a ULONG */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* tx_event_flags_set Set event flags to wakeup */ +/* IP helper thread */ +/* */ +/* CALLED BY */ +/* */ +/* ThreadX system timer thread */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_tcp_fast_periodic_timer_entry(ULONG ip_address) +{ + +NX_IP *ip_ptr; + + + /* Convert input parameter to an IP pointer. */ + ip_ptr = (NX_IP *)ip_address; + + /* Wakeup this IP's helper thread. */ + tx_event_flags_set(&(ip_ptr -> nx_ip_events), NX_IP_TCP_FAST_EVENT, TX_OR); +} + diff --git a/common/src/nx_tcp_free_port_find.c b/common/src/nx_tcp_free_port_find.c new file mode 100644 index 0000000..835a34a --- /dev/null +++ b/common/src/nx_tcp_free_port_find.c @@ -0,0 +1,170 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_tcp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcp_free_port_find PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function finds the first available TCP port, starting from the */ +/* supplied port. If no available ports are found, an error is */ +/* returned. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP instance pointer */ +/* port Starting port */ +/* free_port_ptr Pointer to return free port */ +/* */ +/* 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_tcp_free_port_find(NX_IP *ip_ptr, UINT port, UINT *free_port_ptr) +{ + +UINT index; +UINT bound; +UINT starting_port; +NX_TCP_SOCKET *search_ptr; +NX_TCP_SOCKET *end_ptr; + +#ifdef TX_ENABLE_EVENT_TRACE +TX_TRACE_BUFFER_ENTRY *trace_event; +ULONG trace_timestamp; +#endif + + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_TCP_FREE_PORT_FIND, ip_ptr, port, 0, 0, NX_TRACE_TCP_EVENTS, &trace_event, &trace_timestamp) + + /* Save the original port. */ + starting_port = port; + + /* Loop through the TCP ports until a free entry is found. */ + do + { + + /* Calculate the hash index in the TCP port array of the associated IP instance. */ + index = (UINT)((port + (port >> 8)) & NX_TCP_PORT_TABLE_MASK); + + /* Obtain the IP mutex so we can figure out whether or not the port has already + been bound to. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Pickup the head of the TCP ports bound list. */ + search_ptr = ip_ptr -> nx_ip_tcp_port_table[index]; + + /* Set the bound flag to false. */ + bound = NX_FALSE; + + /* Determine if we need to perform a list search. */ + if (search_ptr) + { + + /* Walk through the circular list of TCP sockets that are already + bound. */ + end_ptr = search_ptr; + do + { + + /* Determine if this entry is the same as the requested port. */ + if (search_ptr -> nx_tcp_socket_port == port) + { + + /* Set the bound flag. */ + bound = NX_TRUE; + + /* Get out of the loop. */ + break; + } + + /* Move to the next entry in the list. */ + search_ptr = search_ptr -> nx_tcp_socket_bound_next; + } while (search_ptr != end_ptr); + } + + /* Release protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Determine if the port is available. */ + if (!bound) + { + + /* Setup the return port number. */ + *free_port_ptr = port; + + /* Update the trace event with the status. */ + NX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, NX_TRACE_TCP_FREE_PORT_FIND, 0, 0, port, 0) + + /* Return success. */ + return(NX_SUCCESS); + } + + /* Move to the next port. */ + port++; + + /* Determine if we need to wrap. */ + if (port > NX_MAX_PORT) + { + + /* Yes, we need to wrap around. */ + port = NX_SEARCH_PORT_START; + } + } while (starting_port != port); + + /* A free port was not found, return an error. */ + return(NX_NO_FREE_PORTS); +} + diff --git a/common/src/nx_tcp_info_get.c b/common/src/nx_tcp_info_get.c new file mode 100644 index 0000000..99e16b4 --- /dev/null +++ b/common/src/nx_tcp_info_get.c @@ -0,0 +1,201 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_tcp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcp_info_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves TCP information for the specified IP */ +/* instance. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to the IP instance */ +/* tcp_packets_sent Destination for number of */ +/* packets sent */ +/* tcp_bytes_sent Destination for number of */ +/* bytes sent */ +/* tcp_packets_received Destination for number of */ +/* packets received */ +/* tcp_bytes_received Destination for number of */ +/* bytes received */ +/* tcp_invalid_packets Destination for number of */ +/* invalid packets */ +/* tcp_receive_packets_dropped Destination for number of */ +/* receive packets dropped */ +/* tcp_checksum_errors Destination for number of */ +/* checksum errors */ +/* tcp_connections Destination for number of */ +/* connections */ +/* tcp_disconnections Destination for number of */ +/* disconnections */ +/* tcp_connections_dropped Destination for number of */ +/* connections dropped */ +/* tcp_retransmit_packets Destination for number of */ +/* retransmit packets */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Obtain protection */ +/* tx_mutex_put Release protection */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_tcp_info_get(NX_IP *ip_ptr, ULONG *tcp_packets_sent, ULONG *tcp_bytes_sent, + ULONG *tcp_packets_received, ULONG *tcp_bytes_received, + ULONG *tcp_invalid_packets, ULONG *tcp_receive_packets_dropped, + ULONG *tcp_checksum_errors, ULONG *tcp_connections, + ULONG *tcp_disconnections, ULONG *tcp_connections_dropped, + ULONG *tcp_retransmit_packets) +{ + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_TCP_INFO_GET, ip_ptr, ip_ptr -> nx_ip_tcp_bytes_sent, ip_ptr -> nx_ip_tcp_bytes_received, ip_ptr -> nx_ip_tcp_invalid_packets, NX_TRACE_TCP_EVENTS, 0, 0) + + /* Obtain the IP mutex so we can examine the bound port. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Determine if packets sent is wanted. */ + if (tcp_packets_sent) + { + + /* Return the number of packets sent by this IP instance. */ + *tcp_packets_sent = ip_ptr -> nx_ip_tcp_packets_sent; + } + + /* Determine if bytes sent is wanted. */ + if (tcp_bytes_sent) + { + + /* Return the number of bytes sent by this IP instance. */ + *tcp_bytes_sent = ip_ptr -> nx_ip_tcp_bytes_sent; + } + + /* Determine if packets received is wanted. */ + if (tcp_packets_received) + { + + /* Return the number of packets received by this IP instance. */ + *tcp_packets_received = ip_ptr -> nx_ip_tcp_packets_received; + } + + /* Determine if bytes received is wanted. */ + if (tcp_bytes_received) + { + + /* Return the number of bytes received by this IP instance. */ + *tcp_bytes_received = ip_ptr -> nx_ip_tcp_bytes_received; + } + + /* Determine if invalid packets is wanted. */ + if (tcp_invalid_packets) + { + + /* Return the number of invalid packets by this IP instance. */ + *tcp_invalid_packets = ip_ptr -> nx_ip_tcp_invalid_packets; + } + + /* Determine if receive packets dropped is wanted. */ + if (tcp_receive_packets_dropped) + { + + /* Return the number of receive packets dropped by this IP instance. */ + *tcp_receive_packets_dropped = ip_ptr -> nx_ip_tcp_receive_packets_dropped; + } + + /* Determine if checksum errors is wanted. */ + if (tcp_checksum_errors) + { + + /* Return the number of checksum errors by this IP instance. */ + *tcp_checksum_errors = ip_ptr -> nx_ip_tcp_checksum_errors; + } + + /* Determine if connections is wanted. */ + if (tcp_connections) + { + + /* Return the number of connections by this IP instance. */ + *tcp_connections = ip_ptr -> nx_ip_tcp_connections; + } + + /* Determine if disconnections is wanted. */ + if (tcp_disconnections) + { + + /* Return the number of disconnections by this IP instance. */ + *tcp_disconnections = ip_ptr -> nx_ip_tcp_disconnections; + } + + /* Determine if connections dropped is wanted. */ + if (tcp_connections_dropped) + { + + /* Return the number of connections dropped by this IP instance. */ + *tcp_connections_dropped = ip_ptr -> nx_ip_tcp_connections_dropped; + } + + /* Determine if retransmit packets is wanted. */ + if (tcp_retransmit_packets) + { + + /* Return the number of retransmit packets by this IP instance. */ + *tcp_retransmit_packets = ip_ptr -> nx_ip_tcp_retransmit_packets; + } + + /* Release protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return successful completion status. */ + return(NX_SUCCESS); +} + diff --git a/common/src/nx_tcp_initialize.c b/common/src/nx_tcp_initialize.c new file mode 100644 index 0000000..5c6d4aa --- /dev/null +++ b/common/src/nx_tcp_initialize.c @@ -0,0 +1,83 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Locate NetX global TCP Component data in this file. */ + +#define NX_TCP_INIT + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_tcp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcp_initialize PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function initializes the TCP management component. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* [_nx_tcp_debug_initialize] Optional debug log init */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_system_initialize System initialization */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_tcp_initialize(VOID) +{ + +#ifdef NX_TCP_ENABLE_DEBUG_LOG + + /* Debug logging specified, call the initialization function. */ + _nx_tcp_debug_initialize(); +#endif +} + diff --git a/common/src/nx_tcp_mss_option_get.c b/common/src/nx_tcp_mss_option_get.c new file mode 100644 index 0000000..62a52bf --- /dev/null +++ b/common/src/nx_tcp_mss_option_get.c @@ -0,0 +1,249 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_tcp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcp_mss_option_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function searches for the Maximum Segment Size (MSS) option. */ +/* If found, first check the option length, if option length is not */ +/* valid, it returns NX_FALSE to the caller, else it set the mss value */ +/* and returns NX_TRUE to the caller. Otherwise, NX_TRUE is returned. */ +/* */ +/* INPUT */ +/* */ +/* option_ptr Pointer to option area */ +/* option_area_size Size of option area */ +/* */ +/* OUTPUT */ +/* */ +/* NX_FALSE TCP option is invalid */ +/* NX_TRUE TCP option is valid */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_tcp_packet_process TCP packet processing */ +/* _nx_tcp_server_socket_relisten Socket relisten processing */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_tcp_mss_option_get(UCHAR *option_ptr, ULONG option_area_size, ULONG *mss) +{ + +ULONG option_length; + + + /* Initialize the value. */ + *mss = 0; + + /* Loop through the option area looking for the MSS. */ + while (option_area_size >= 4) + { + + /* Is the current character the MSS type? */ + if (*option_ptr == NX_TCP_MSS_KIND) + { + + /* Yes, we found it! */ + + /* Move the pointer forward by one. */ + option_ptr++; + + /* Check the option length, if option length is not equal to 4, return NX_FALSE. */ + if (*option_ptr++ != 4) + { + return(NX_FALSE); + } + + /* Build the mss size. */ + *mss = (ULONG)*option_ptr++; + + /* Get the LSB of the MSS. */ + *mss = (*mss << 8) | (ULONG)*option_ptr; + + /* Finished, get out of the loop! */ + break; + } + + /* Otherwise, process relative to the option type. */ + + /* Check for end of list. */ + if (*option_ptr == NX_TCP_EOL_KIND) + { + + /* Yes, end of list, get out! */ + break; + } + + /* Check for NOP. */ + if (*option_ptr++ == NX_TCP_NOP_KIND) + { + + /* One character option! */ + option_area_size--; + } + else + { + + /* Derive the option length. */ + option_length = ((ULONG)*option_ptr); + + /* Return when option length is invalid. */ + if (option_length == 0) + { + return(NX_FALSE); + } + + /* Move the option pointer forward. */ + option_ptr = option_ptr + option_length - 1; + + /* Determine if this is greater than the option area size. */ + if (option_length > option_area_size) + { + option_area_size = 0; + } + else + { + option_area_size = option_area_size - option_length; + } + } + } + + /* Return. */ + return(NX_TRUE); +} + + +#ifdef NX_ENABLE_TCP_WINDOW_SCALING + +UINT _nx_tcp_window_scaling_option_get(UCHAR *option_ptr, ULONG option_area_size, ULONG *window_scale) +{ + +ULONG option_length; + + + /* Set invalid window scaling, in case the SYN message does not contain Window Scaling feature. */ + *window_scale = 0xFF; + + /* Loop through the option area looking for the window scaling option. */ + while (option_area_size >= 3) + { + + /* Is the current character the window scaling type? */ + if (*option_ptr == NX_TCP_RWIN_KIND) + { + + /* Yes, we found it! */ + + /* Move the pointer forward by one. */ + option_ptr++; + + /* Check the option length, if option length is not equal to 3, return NX_FALSE. */ + if (*option_ptr++ != 3) + { + return(NX_FALSE); + } + + /* Get the window scale size. */ + *window_scale = (ULONG)*option_ptr; + + break; + } + + /* Otherwise, process relative to the option type. */ + + /* Check for end of list. */ + if (*option_ptr == NX_TCP_EOL_KIND) + { + + /* Yes, end of list, get out! */ + break; + } + + /* Check for NOP. */ + if (*option_ptr == NX_TCP_NOP_KIND) + { + /* One character option! Skip this option and move to the next entry. */ + option_ptr++; + + option_area_size--; + } + else + { + + /* Derive the option length. All options *fields* area 32-bits, + but the options themselves may be padded by NOP's. Determine + the option size based on alignment of the option ptr */ + option_length = *(option_ptr + 1); + + /* Return when option length is invalid. */ + if (option_length == 0) + { + return(NX_FALSE); + } + + /* Move the option pointer forward. */ + option_ptr = option_ptr + option_length; + + /* Determine if this is greater than the option area size. */ + if (option_length > option_area_size) + { + option_area_size = 0; + } + else + { + option_area_size = option_area_size - option_length; + } + } + } + + /* Return. */ + return(NX_TRUE); +} +#endif /* NX_ENABLE_TCP_WINDOW_SCALING */ + diff --git a/common/src/nx_tcp_no_connection_reset.c b/common/src/nx_tcp_no_connection_reset.c new file mode 100644 index 0000000..1c9efa8 --- /dev/null +++ b/common/src/nx_tcp_no_connection_reset.c @@ -0,0 +1,130 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_tcp.h" +#include "nx_packet.h" +#include "nx_ip.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcp_no_connection_reset PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sends a reset when there is no connection present, */ +/* which avoids the timeout processing on the other side of the */ +/* connection. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP control block */ +/* packet_ptr Pointer to packet to send */ +/* tcp_header_ptr TCP header */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_ip_route_find Find a suitable outgoing */ +/* interface. */ +/* _nx_tcp_packet_send_rst Send RST on no connection */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_tcp_packet_process TCP packet processing */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_tcp_no_connection_reset(NX_IP *ip_ptr, NX_PACKET *packet_ptr, NX_TCP_HEADER *tcp_header_ptr) +{ + +NX_TCP_SOCKET fake_socket; +ULONG *ip_header_ptr; +ULONG header_length; + + + /* Clear the fake socket first. */ + memset((void *)&fake_socket, 0, sizeof(NX_TCP_SOCKET)); + + /* Build a fake socket so we can send a reset TCP requests that are not valid. */ + fake_socket.nx_tcp_socket_ip_ptr = ip_ptr; + + /* Set the connection IP address. */ + ip_header_ptr = (ULONG *)packet_ptr -> nx_packet_prepend_ptr; + fake_socket.nx_tcp_socket_connect_ip = *(ip_header_ptr - 2); + + /* Set the time to live. */ + fake_socket.nx_tcp_socket_time_to_live = NX_IP_TIME_TO_LIVE; + + /* Assume the interface that receives the incoming packet is the best interface for sending responses. */ + fake_socket.nx_tcp_socket_connect_interface = packet_ptr -> nx_packet_ip_interface; + + /* Set the source port and destination port. */ + fake_socket.nx_tcp_socket_port = (UINT)(tcp_header_ptr -> nx_tcp_header_word_0 & NX_LOWER_16_MASK); + fake_socket.nx_tcp_socket_connect_port = (UINT)(tcp_header_ptr -> nx_tcp_header_word_0 >> NX_SHIFT_BY_16); + + /* Update the sequence number. */ + /* Get the header length. */ + header_length = (tcp_header_ptr -> nx_tcp_header_word_3 >> NX_TCP_HEADER_SHIFT) * sizeof(ULONG); + + /* Update sequence number to set the reset acknowledge number. */ + tcp_header_ptr -> nx_tcp_sequence_number += (packet_ptr -> nx_packet_length - header_length); + + /* Check the SYN bit. */ + if (tcp_header_ptr -> nx_tcp_header_word_3 & NX_TCP_SYN_BIT) + { + + /* Update sequence number to set the reset acknowledge number. */ + tcp_header_ptr -> nx_tcp_sequence_number++; + } + + /* Find outgoing interface and next hop info. */ + if (_nx_ip_route_find(ip_ptr, fake_socket.nx_tcp_socket_connect_ip, &fake_socket.nx_tcp_socket_connect_interface, + &fake_socket.nx_tcp_socket_next_hop_address) != NX_SUCCESS) + { + return; + } + + /* Send a RST to indicate the connection was not available. */ + _nx_tcp_packet_send_rst(&fake_socket, tcp_header_ptr); +} + diff --git a/common/src/nx_tcp_packet_process.c b/common/src/nx_tcp_packet_process.c new file mode 100644 index 0000000..74a4605 --- /dev/null +++ b/common/src/nx_tcp_packet_process.c @@ -0,0 +1,810 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_tcp.h" +#include "nx_packet.h" +#include "nx_ip.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcp_packet_process PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes an incoming TCP packet, which includes */ +/* matching the packet to an existing connection and dispatching to */ +/* the socket specific processing routine. If no connection is */ +/* found, this routine checks for a new connection request and if */ +/* found, processes it accordingly. If a reset packet is received, it */ +/* checks the queue for a previous connection request which needs to be*/ +/* removed. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP control block */ +/* packet_ptr Pointer to packet to send */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_packet_release Packet release function */ +/* _nx_tcp_checksum Calculate TCP packet checksum */ +/* _nx_tcp_mss_option_get Get peer MSS option */ +/* _nx_tcp_no_connection_reset Reset on no connection */ +/* _nx_tcp_packet_send_syn Send SYN message */ +/* _nx_tcp_socket_packet_process Socket specific packet */ +/* processing routine */ +/* (nx_tcp_listen_callback) Application listen callback */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_tcp_queue_process Process TCP packet queue */ +/* _nx_tcp_packet_receive Receive packet processing */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_tcp_packet_process(NX_IP *ip_ptr, NX_PACKET *packet_ptr) +{ + +UINT index; +UINT port; +ULONG *ip_header_ptr; +ULONG source_ip; +UINT source_port; +NX_TCP_SOCKET *socket_ptr; +NX_TCP_HEADER *tcp_header_ptr; +struct NX_TCP_LISTEN_STRUCT *listen_ptr; +VOID (*listen_callback)(NX_TCP_SOCKET *socket_ptr, UINT port); +ULONG option_words; +ULONG mss = 536; +ULONG queued_count; +NX_PACKET *queued_ptr; +ULONG queued_source_ip; +UINT queued_source_port; +UINT is_connection_packet_flag; +UINT is_valid_option_flag = NX_TRUE; +UINT status; + +#ifdef NX_ENABLE_TCP_WINDOW_SCALING +ULONG rwin_scale = 0xFF; +#endif /* NX_ENABLE_TCP_WINDOW_SCALING */ + + + /* Pickup the source IP address. */ + ip_header_ptr = (ULONG *)packet_ptr -> nx_packet_prepend_ptr; + source_ip = *(ip_header_ptr - 2); + +#ifndef NX_DISABLE_TCP_RX_CHECKSUM + + /* Calculate the checksum. */ + if (_nx_tcp_checksum(packet_ptr, source_ip, packet_ptr -> nx_packet_ip_interface -> nx_interface_ip_address)) + { + +#ifndef NX_DISABLE_TCP_INFO + + /* Increment the TCP invalid packet error count. */ + ip_ptr -> nx_ip_tcp_invalid_packets++; + + /* Increment the TCP packet checksum error count. */ + ip_ptr -> nx_ip_tcp_checksum_errors++; +#endif + + /* Checksum error, just release the packet. */ + _nx_packet_release(packet_ptr); + return; + } +#endif + + /* Pickup the pointer to the head of the TCP packet. */ + tcp_header_ptr = (NX_TCP_HEADER *)packet_ptr -> nx_packet_prepend_ptr; + + /* Endian swapping logic. If NX_LITTLE_ENDIAN is specified, these macros will + swap the endian of the TCP header. */ + 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); + + /* Determine if there are any option words... Note there are always 5 words in a TCP header. */ + option_words = (tcp_header_ptr -> nx_tcp_header_word_3 >> 28) - 5; + +#ifndef NX_DISABLE_RX_SIZE_CHECKING + /* Check for valid packet length. */ + if (((INT)option_words < 0) || (packet_ptr -> nx_packet_length < (option_words << 2))) + { + +#ifndef NX_DISABLE_TCP_INFO + /* Increment the TCP invalid packet error. */ + ip_ptr -> nx_ip_tcp_invalid_packets++; +#endif + + /* Invalid packet length, just release it. */ + _nx_packet_release(packet_ptr); + + /* The function is complete, just return! */ + return; + } +#endif + + if (option_words) + { + + /* Yes, there are one or more option words. */ + + /* Derive the Maximum Segment Size (MSS) in the option words. */ + status = _nx_tcp_mss_option_get((packet_ptr -> nx_packet_prepend_ptr + sizeof(NX_TCP_HEADER)), option_words * sizeof(ULONG), &mss); + + /* Check the status. if status is NX_FALSE, means Option Length is invalid. */ + if (status == NX_FALSE) + { + + /* The option is invalid. */ + is_valid_option_flag = NX_FALSE; + } + else + { + + /* Set the default MSS if the MSS value was not found. */ + if (mss == 0) + { + mss = 536; + } + } + +#ifdef NX_ENABLE_TCP_WINDOW_SCALING + status = _nx_tcp_window_scaling_option_get((packet_ptr -> nx_packet_prepend_ptr + sizeof(NX_TCP_HEADER)), option_words * sizeof(ULONG), &rwin_scale); + + /* Check the status. if status is NX_FALSE, means Option Length is invalid. */ + if (status == NX_FALSE) + { + is_valid_option_flag = NX_FALSE; + } +#endif /* NX_ENABLE_TCP_WINDOW_SCALING */ + } + + /* Pickup the destination TCP port. */ + port = (UINT)(tcp_header_ptr -> nx_tcp_header_word_0 & NX_LOWER_16_MASK); + + /* Pickup the source TCP port. */ + source_port = (UINT)(tcp_header_ptr -> nx_tcp_header_word_0 >> NX_SHIFT_BY_16); + + /* Calculate the hash index in the TCP port array of the associated IP instance. */ + index = (UINT)((port + (port >> 8)) & NX_TCP_PORT_TABLE_MASK); + + /* Search the bound sockets in this index for the particular port. */ + socket_ptr = ip_ptr -> nx_ip_tcp_port_table[index]; + + /* Determine if there are any sockets bound on this port index. */ + if (socket_ptr) + { + + /* Yes, loop to examine the list of bound ports on this index. */ + do + { + + /* Determine if the port has been found. */ + if ((socket_ptr -> nx_tcp_socket_port == port) && + (socket_ptr -> nx_tcp_socket_connect_ip == source_ip) && + (socket_ptr -> nx_tcp_socket_connect_port == source_port)) + { + + /* Yes, we have a match! */ + + /* Determine if we need to update the tcp port head pointer. This should + only be done if the found socket pointer is not the head pointer and + the mutex for this IP instance is available. */ + if (socket_ptr != ip_ptr -> nx_ip_tcp_port_table[index]) + { + + /* Move the port head pointer to this socket. */ + ip_ptr -> nx_ip_tcp_port_table[index] = socket_ptr; + } + + /* If this packet contains SYN */ + if (tcp_header_ptr -> nx_tcp_header_word_3 & NX_TCP_SYN_BIT) + { + /* Record the MSS value if it is present and the Otherwise use 536, as + outlined in RFC 1122 section 4.2.2.6. */ + + /* Yes, MSS was found store it! */ + socket_ptr -> nx_tcp_socket_peer_mss = mss; + + /* Compute the local MSS size based on the interface MTU size. */ + mss = packet_ptr -> nx_packet_ip_interface -> nx_interface_ip_mtu_size - sizeof(NX_TCP_HEADER) - sizeof(NX_IP_HEADER); + + /* Calculate sender MSS. */ + if (mss > socket_ptr -> nx_tcp_socket_peer_mss) + { + + /* Local MSS is larger than peer MSS. */ + mss = socket_ptr -> nx_tcp_socket_peer_mss; + } + + if ((mss > socket_ptr -> nx_tcp_socket_mss) && socket_ptr -> nx_tcp_socket_mss) + { + socket_ptr -> nx_tcp_socket_connect_mss = socket_ptr -> nx_tcp_socket_mss; + } + else + { + socket_ptr -> nx_tcp_socket_connect_mss = mss; + } + + /* Compute the SMSS * SMSS value, so later TCP module doesn't need to redo the multiplication. */ + socket_ptr -> nx_tcp_socket_connect_mss2 = + socket_ptr -> nx_tcp_socket_connect_mss * socket_ptr -> nx_tcp_socket_connect_mss; + + + +#ifdef NX_ENABLE_TCP_WINDOW_SCALING + /* + Simply record the peer's window scale value. When we move to the + ESTABLISHED state, we will set the peer window scale to 0 if the + peer does not support this feature. + */ + socket_ptr -> nx_tcp_snd_win_scale_value = rwin_scale; +#endif /* NX_ENABLE_TCP_WINDOW_SCALING */ + } + + + /* Process the packet within an existing TCP connection. */ + _nx_tcp_socket_packet_process(socket_ptr, packet_ptr); + + /* Get out of the search loop and this function! */ + return; + } + else + { + + /* Move to the next entry in the bound index. */ + socket_ptr = socket_ptr -> nx_tcp_socket_bound_next; + } + } while ((socket_ptr) && (socket_ptr != ip_ptr -> nx_ip_tcp_port_table[index])); + } + + /* At this point, we know there is not an existing TCP connection. */ + + /* If this packet contains the valid option. */ + if (is_valid_option_flag == NX_FALSE) + { + + /* Send RST message. + TCP MUST be prepared to handle an illegal option length (e.g., zero) without crashing; + a suggested procedure is to reset the connection and log the reason, outlined in RFC 1122, Section 4.2.2.5, Page85. */ + _nx_tcp_no_connection_reset(ip_ptr, packet_ptr, tcp_header_ptr); + + /* Not a connection request, just release the packet. */ + _nx_packet_release(packet_ptr); + + return; + } + +#ifdef NX_ENABLE_TCP_MSS_CHECKING + /* Optionally check for a user specified minimum MSS. The user application may choose to + define a minimum MSS value, and reject a TCP connection if peer MSS value does not + meet the minimum. */ + if (mss < NX_TCP_MSS_MINIMUM) + { + /* Handle this as an invalid connection request. */ + _nx_packet_release(packet_ptr); + + return; + } +#endif + + /* Determine if the packet is an initial connection request (only SYN bit set) + and that we have resources to handle a new client connection request. */ + + /* Initialize a check for connection related request to false. */ + is_connection_packet_flag = NX_FALSE; + + if ((tcp_header_ptr -> nx_tcp_header_word_3 & NX_TCP_SYN_BIT) && + (!(tcp_header_ptr -> nx_tcp_header_word_3 & NX_TCP_ACK_BIT)) && + (ip_ptr -> nx_ip_tcp_active_listen_requests)) + { + + /* The incoming SYN packet is a connection request. */ + is_connection_packet_flag = NX_TRUE; + } + else if ((tcp_header_ptr -> nx_tcp_header_word_3 & NX_TCP_RST_BIT) && + (ip_ptr -> nx_ip_tcp_active_listen_requests)) + { + + /* The incoming RST packet is related to a previous connection request. */ + is_connection_packet_flag = NX_TRUE; + } + + /* Handle new connection requests or RST packets cancelling existing (queued) connection requests */ + if (is_connection_packet_flag) + { + + /* Check for LAND attack packet. This is an incoming packet with matching + Source and Destination IP address, and matching source and destination port. */ + if ((source_ip == packet_ptr -> nx_packet_ip_interface -> nx_interface_ip_address) && + (source_port == port)) + { + + /* Bogus packet. Drop it! */ + +#ifndef NX_DISABLE_TCP_INFO + + /* Increment the TCP invalid packet error count. */ + ip_ptr -> nx_ip_tcp_invalid_packets++; +#endif /* NX_DISABLE_TCP_INFO */ + + /* Release the packet we will not process any further. */ + _nx_packet_release(packet_ptr); + return; + } + + /* Search all ports in listen mode for a match. */ + listen_ptr = ip_ptr -> nx_ip_tcp_active_listen_requests; + do + { + + /* Determine if this port is in a listen mode. */ + if (listen_ptr -> nx_tcp_listen_port == port) + { + +#ifndef NX_DISABLE_TCP_INFO + + /* Check for a RST (reset) bit set. */ + if (!(tcp_header_ptr -> nx_tcp_header_word_3 & NX_TCP_RST_BIT)) + { + + /* Increment the passive TCP connections count. */ + ip_ptr -> nx_ip_tcp_passive_connections++; + + /* Increment the TCP connections count. */ + ip_ptr -> nx_ip_tcp_connections++; + } + +#endif + + /* Okay, this port is in a listen mode. We now need to see if + there is an available socket for the new connection request + present. */ + if ((listen_ptr -> nx_tcp_listen_socket_ptr) && + ((tcp_header_ptr -> nx_tcp_header_word_3 & NX_TCP_RST_BIT) == NX_NULL)) + { + + /* Yes there is indeed a socket present. We now need to + fill in the appropriate info and call the server callback + routine. */ + + /* Allocate the supplied server socket. */ + socket_ptr = listen_ptr -> nx_tcp_listen_socket_ptr; + + +#ifndef NX_DISABLE_EXTENDED_NOTIFY_SUPPORT + /* If extended notify is enabled, call the syn_received notify function. + This user-supplied function decides whether or not this SYN request + should be accepted. */ + if (socket_ptr -> nx_tcp_socket_syn_received_notify) + { + if ((socket_ptr -> nx_tcp_socket_syn_received_notify)(socket_ptr, packet_ptr) != NX_TRUE) + { + /* Release the packet. */ + _nx_packet_release(packet_ptr); + + /* Finished processing, simply return! */ + return; + } + } +#endif /* NX_DISABLE_EXTENDED_NOTIFY_SUPPORT */ + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_TCP_SYN_RECEIVE, ip_ptr, socket_ptr, packet_ptr, tcp_header_ptr -> nx_tcp_sequence_number, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + /* Clear the server socket pointer in the listen request. If the + application wishes to honor more server connections on this port, + the application must call relisten with a new server socket + pointer. */ + listen_ptr -> nx_tcp_listen_socket_ptr = NX_NULL; + + /* Fill the socket in with the appropriate information. */ + socket_ptr -> nx_tcp_socket_connect_ip = source_ip; + socket_ptr -> nx_tcp_socket_connect_port = source_port; + socket_ptr -> nx_tcp_socket_rx_sequence = tcp_header_ptr -> nx_tcp_sequence_number; + socket_ptr -> nx_tcp_socket_connect_interface = packet_ptr -> nx_packet_ip_interface; + + if (_nx_ip_route_find(ip_ptr, source_ip, &socket_ptr -> nx_tcp_socket_connect_interface, + &socket_ptr -> nx_tcp_socket_next_hop_address) != NX_SUCCESS) + { + /* Cannot determine how to send packets to this TCP peer. Since we are able to + receive the syn, use the incoming interface, and send the packet out directly. */ + + socket_ptr -> nx_tcp_socket_next_hop_address = source_ip; + } + + /* Yes, MSS was found store it! */ + socket_ptr -> nx_tcp_socket_peer_mss = mss; + +#ifdef NX_ENABLE_TCP_WINDOW_SCALING + /* + Simply record the peer's window scale value. When we move to the + ESTABLISHED state, we will set the peer window scale to 0 if the + peer does not support this feature. + */ + socket_ptr -> nx_tcp_snd_win_scale_value = rwin_scale; +#endif /* NX_ENABLE_TCP_WINDOW_SCALING */ + + /* Set the initial slow start threshold to be the advertised window size. */ + socket_ptr -> nx_tcp_socket_tx_slow_start_threshold = socket_ptr -> nx_tcp_socket_tx_window_advertised; + + /* Slow start: setup initial window (IW) to be MSS, RFC 2581, 3.1 */ + socket_ptr -> nx_tcp_socket_tx_window_congestion = mss; + + /* Initialize the transmit outstanding byte count to zero. */ + socket_ptr -> nx_tcp_socket_tx_outstanding_bytes = 0; + + /* Calculate the hash index in the TCP port array of the associated IP instance. */ + index = (UINT)((port + (port >> 8)) & NX_TCP_PORT_TABLE_MASK); + + /* Determine if the list is NULL. */ + if (ip_ptr -> nx_ip_tcp_port_table[index]) + { + + /* There are already sockets on this list... just add this one + to the end. */ + 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; + } + else + { + + /* Nothing is on the TCP port list. Add this TCP socket to an + empty list. */ + socket_ptr -> nx_tcp_socket_bound_next = socket_ptr; + socket_ptr -> nx_tcp_socket_bound_previous = socket_ptr; + ip_ptr -> nx_ip_tcp_port_table[index] = socket_ptr; + } + + /* Pickup the listen callback function. */ + listen_callback = listen_ptr -> nx_tcp_listen_callback; + + /* Release the incoming packet. */ + _nx_packet_release(packet_ptr); + + /* Determine if an accept call with suspension has already been made + for this socket. If so, the SYN message needs to be sent from + here. */ + if (socket_ptr -> nx_tcp_socket_state == NX_TCP_SYN_RECEIVED) + { + + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_TCP_STATE_CHANGE, ip_ptr, socket_ptr, socket_ptr -> nx_tcp_socket_state, socket_ptr -> nx_tcp_socket_state, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + + /* The application is suspended on an accept call for this socket. + Simply send the SYN now and keep the thread suspended until the + other side completes the connection. */ + + /* Send the SYN message, but increment the ACK first. */ + socket_ptr -> nx_tcp_socket_rx_sequence++; + + /* Increment the sequence number for the SYN message. */ + socket_ptr -> nx_tcp_socket_tx_sequence++; + + /* Setup a timeout so the connection attempt can be sent again. */ + socket_ptr -> nx_tcp_socket_timeout = socket_ptr -> nx_tcp_socket_timeout_rate; + socket_ptr -> nx_tcp_socket_timeout_retries = 0; + + /* Send the SYN+ACK message. */ + _nx_tcp_packet_send_syn(socket_ptr, (socket_ptr -> nx_tcp_socket_tx_sequence - 1)); + } + + /* Determine if there is a listen callback function. */ + if (listen_callback) + { + /* Call the user's listen callback function. */ + (listen_callback)(socket_ptr, port); + } + + /* Finished processing, just return. */ + return; + } + else + { + + /* There is no server socket available for the new connection. */ + + /* Note: The application needs to call relisten on a socket to process queued + connection requests. */ + + /* Check for a RST (reset) bit set. */ + if (!(tcp_header_ptr -> nx_tcp_header_word_3 & NX_TCP_RST_BIT)) + { + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_TCP_SYN_RECEIVE, ip_ptr, NX_NULL, packet_ptr, tcp_header_ptr -> nx_tcp_sequence_number, NX_TRACE_INTERNAL_EVENTS, 0, 0) + } + + queued_count = listen_ptr -> nx_tcp_listen_queue_current; + queued_ptr = listen_ptr -> nx_tcp_listen_queue_head; + + /* Check for the same connection request already in the queue. If this is a RST packet + it will check for a previous connection which should be removed from the queue. */ + + /* Loop through the queued list. */ + while (queued_count--) + { + + /* Pickup the queued source port and source IP address to check for a match. */ + queued_source_ip = *(((ULONG *)queued_ptr -> nx_packet_prepend_ptr) - 2); + queued_source_port = (UINT)(*((ULONG *)queued_ptr -> nx_packet_prepend_ptr) >> NX_SHIFT_BY_16); + + /* Determine if this matches the current connection request. */ + if ((queued_source_ip == source_ip) && (queued_source_port == source_port)) + { + + /* Check for a RST (reset) bit set. */ + if (tcp_header_ptr -> nx_tcp_header_word_3 & NX_TCP_RST_BIT) + { + + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* This matches a previous connection request which needs to be removed from the listen queue. */ + + /* Are there are any connection requests on the queue? */ + if (listen_ptr -> nx_tcp_listen_queue_current == 0) + { + + /* No, put the TCP socket back in the listen structure. */ + listen_ptr -> nx_tcp_listen_socket_ptr = socket_ptr; + } + else + { + + /* Yes, we need to find the connection request in the queue. */ + NX_PACKET *current_packet_ptr, *prev_packet_ptr; + UINT found_connection_request = NX_FALSE; + + /* Start with the oldest one. */ + current_packet_ptr = listen_ptr -> nx_tcp_listen_queue_head; + + /* Remove the oldest connection request if it matches the current RST packet. */ + if (queued_ptr == listen_ptr -> nx_tcp_listen_queue_head) + { + + /* Reset the front (oldest) of the queue to the next request. */ + current_packet_ptr = listen_ptr -> nx_tcp_listen_queue_head; + listen_ptr -> nx_tcp_listen_queue_head = current_packet_ptr -> nx_packet_queue_next; + + /* Was there only one queue request e.g. head == tail? */ + if (current_packet_ptr == listen_ptr -> nx_tcp_listen_queue_tail) + { + + /* Yes, and now there are none. Set the queue to empty. */ + listen_ptr -> nx_tcp_listen_queue_tail = NX_NULL; + } + + found_connection_request = NX_TRUE; + } + else + { + + /* Check the rest of the connection requests. */ + + prev_packet_ptr = current_packet_ptr; + current_packet_ptr = current_packet_ptr -> nx_packet_queue_next; + + /* Loop through the queue to the most recent request or until we find a match. */ + while (current_packet_ptr) + { + + /* Do we have a match? */ + if (queued_ptr == current_packet_ptr) + { + + /* Yes, remove this one! */ + + /* Link around the request we are removing. */ + prev_packet_ptr -> nx_packet_queue_next = current_packet_ptr -> nx_packet_queue_next; + + /* Is the request being removed the tail (most recent connection?) */ + if (current_packet_ptr == listen_ptr -> nx_tcp_listen_queue_tail) + { + + /* Yes, set the previous connection request as the tail. */ + listen_ptr -> nx_tcp_listen_queue_tail = prev_packet_ptr; + } + + /* Make sure the most recent request null terminates the list. */ + listen_ptr -> nx_tcp_listen_queue_tail -> nx_packet_queue_next = NX_NULL; + + found_connection_request = NX_TRUE; + break; + } + + /* Not the connection request to remove. Check the next one, + and save the current connection request as the 'previous' one. */ + prev_packet_ptr = current_packet_ptr; + current_packet_ptr = current_packet_ptr -> nx_packet_queue_next; + } + } + + /* Verify we found the connection to remove. */ + if (found_connection_request == NX_TRUE) + { + + /* Release the connection request packet. */ + _nx_packet_release(current_packet_ptr); + + /* Update the listen queue. */ + listen_ptr -> nx_tcp_listen_queue_current--; + } + } + + /* Release the protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + } + +#ifndef NX_DISABLE_TCP_INFO + + /* Increment the TCP dropped packet count. */ + ip_ptr -> nx_ip_tcp_receive_packets_dropped++; +#endif + + /* Simply release the packet and return. */ + _nx_packet_release(packet_ptr); + + /* Return! */ + return; + } + + /* Move to next item in the queue. */ + queued_ptr = queued_ptr -> nx_packet_queue_next; + } + + /* No duplicate connection requests were found. */ + + /* Is this a RST packet? */ + if (tcp_header_ptr -> nx_tcp_header_word_3 & NX_TCP_RST_BIT) + { + /* Yes, so not a connection request. Do not place on the listen queue. */ + + /* Release the packet. */ + _nx_packet_release(packet_ptr); + + /* Return! */ + return; + } + + /* This is a valid connection request. Place this request on the listen queue. */ + + /* Set the next pointer of the packet to NULL. */ + packet_ptr -> nx_packet_queue_next = NX_NULL; + + /* Queue the new connection request. */ + if (listen_ptr -> nx_tcp_listen_queue_head) + { + + /* There is a connection request already queued, just link packet to tail. */ + (listen_ptr -> nx_tcp_listen_queue_tail) -> nx_packet_queue_next = packet_ptr; + } + else + { + + /* The queue is empty. Setup head pointer to the new packet. */ + listen_ptr -> nx_tcp_listen_queue_head = packet_ptr; + } + + /* Setup the tail pointer to the new packet and increment the queue count. */ + listen_ptr -> nx_tcp_listen_queue_tail = packet_ptr; + listen_ptr -> nx_tcp_listen_queue_current++; + + /* Determine if the queue depth has been exceeded. */ + if (listen_ptr -> nx_tcp_listen_queue_current > listen_ptr -> nx_tcp_listen_queue_maximum) + { + +#ifndef NX_DISABLE_TCP_INFO + + /* Increment the TCP connections dropped count. */ + ip_ptr -> nx_ip_tcp_connections_dropped++; + ip_ptr -> nx_ip_tcp_connections--; + + /* Increment the TCP dropped packet count. */ + ip_ptr -> nx_ip_tcp_receive_packets_dropped++; +#endif + + /* Save the head packet pointer, since this will be released below. */ + packet_ptr = listen_ptr -> nx_tcp_listen_queue_head; + + /* Remove the oldest packet from the queue. */ + listen_ptr -> nx_tcp_listen_queue_head = (listen_ptr -> nx_tcp_listen_queue_head) -> nx_packet_queue_next; + + /* Decrement the number of packets in the queue. */ + listen_ptr -> nx_tcp_listen_queue_current--; + + /* We have exceeded the number of connections that can be + queued for this port. */ + + /* Release the packet. */ + _nx_packet_release(packet_ptr); + } + + /* Finished processing, just return. */ + return; + } + } + + /* Move to the next listen request. */ + listen_ptr = listen_ptr -> nx_tcp_listen_next; + } while (listen_ptr != ip_ptr -> nx_ip_tcp_active_listen_requests); + } + +#ifndef NX_DISABLE_TCP_INFO + + /* Determine if a connection request is present. */ + if (tcp_header_ptr -> nx_tcp_header_word_3 & NX_TCP_SYN_BIT) + { + + /* Yes, increment the TCP connections dropped count. */ + ip_ptr -> nx_ip_tcp_connections_dropped++; + } + + /* Increment the TCP dropped packet count. */ + ip_ptr -> nx_ip_tcp_receive_packets_dropped++; +#endif + + /* Determine if a RST is present. If so, don't send a RST in response. */ + if (!(tcp_header_ptr -> nx_tcp_header_word_3 & NX_TCP_RST_BIT)) + { + + /* Non RST is present, send reset when no connection is present. */ + _nx_tcp_no_connection_reset(ip_ptr, packet_ptr, tcp_header_ptr); + } + + /* Not a connection request, just release the packet. */ + _nx_packet_release(packet_ptr); + return; +} + diff --git a/common/src/nx_tcp_packet_receive.c b/common/src/nx_tcp_packet_receive.c new file mode 100644 index 0000000..ed4b79f --- /dev/null +++ b/common/src/nx_tcp_packet_receive.c @@ -0,0 +1,153 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_packet.h" +#include "nx_tcp.h" +#include "tx_thread.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcp_packet_receive PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function receives a TCP packet from the IP receive */ +/* processing. If this routine is called from an ISR, it simply */ +/* places the new message on the TCP message queue, and wakes up the */ +/* IP processing thread. If this routine is called from the IP helper */ +/* thread, then the TCP message is processed directly. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP control block */ +/* packet_ptr Pointer to packet to send */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_tcp_packet_process Process TCP packet */ +/* tx_event_flags_set Set event flags for IP helper */ +/* thread */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ip_packet_receive Dispatch received IP packets */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_tcp_packet_receive(NX_IP *ip_ptr, NX_PACKET *packet_ptr) +{ + +TX_INTERRUPT_SAVE_AREA + + +#ifndef NX_DISABLE_RX_SIZE_CHECKING + + /* Check for valid packet length. */ + if (packet_ptr -> nx_packet_length < sizeof(NX_TCP_HEADER)) + { + +#ifndef NX_DISABLE_TCP_INFO + /* Increment the TCP invalid packet error. */ + ip_ptr -> nx_ip_tcp_invalid_packets++; +#endif + + /* Invalid packet length, just release it. */ + _nx_packet_release(packet_ptr); + + /* The function is complete, just return! */ + return; + } +#endif + + /* Determine if this routine is being called from an ISR. */ + if ((TX_THREAD_GET_SYSTEM_STATE()) || (&(ip_ptr -> nx_ip_thread) != _tx_thread_current_ptr)) + { + + /* If system state is non-zero, we are in an ISR. If the current thread is not the IP thread, + we need to prevent unnecessary recursion in loopback. Just place the message at the + end of the TCP message queue and wakeup the IP helper thread. */ + + /* Disable interrupts. */ + TX_DISABLE + + /* Add the packet to the TCP message queue. */ + if (ip_ptr -> nx_ip_tcp_queue_head) + { + + /* Link the current packet at the end of the queue. */ + (ip_ptr -> nx_ip_tcp_queue_tail) -> nx_packet_queue_next = packet_ptr; + ip_ptr -> nx_ip_tcp_queue_tail = packet_ptr; + packet_ptr -> nx_packet_queue_next = NX_NULL; + + /* Increment the count of incoming TCP packets queued. */ + ip_ptr -> nx_ip_tcp_received_packet_count++; + } + else + { + + /* Empty queue, add to the head of the TCP message queue. */ + ip_ptr -> nx_ip_tcp_queue_head = packet_ptr; + ip_ptr -> nx_ip_tcp_queue_tail = packet_ptr; + packet_ptr -> nx_packet_queue_next = NX_NULL; + + /* Set the initial count TCP packets queued. */ + ip_ptr -> nx_ip_tcp_received_packet_count = 1; + } + + /* Restore interrupts. */ + TX_RESTORE + + /* Wakeup IP thread for processing one or more messages in the TCP queue. */ + tx_event_flags_set(&(ip_ptr -> nx_ip_events), NX_IP_TCP_EVENT, TX_OR); + } + else + { + + /* The IP message was deferred, so this routine is called from the IP helper + thread and thus may call the TCP processing directly. */ + _nx_tcp_packet_process(ip_ptr, packet_ptr); + } +} + diff --git a/common/src/nx_tcp_packet_send_ack.c b/common/src/nx_tcp_packet_send_ack.c new file mode 100644 index 0000000..a10cc91 --- /dev/null +++ b/common/src/nx_tcp_packet_send_ack.c @@ -0,0 +1,162 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_packet.h" +#include "nx_tcp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcp_packet_send_ack PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sends an ACK from the specified socket. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to socket */ +/* tx_sequence Transmit sequence number */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_packet_allocate Allocate a packet */ +/* _nx_tcp_checksum Calculate TCP checksum */ +/* _nx_ip_packet_send Send IP packet */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_tcp_fast_periodic_processing Delayed ACK processing */ +/* _nx_tcp_periodic_processing Regular periodic processing */ +/* _nx_tcp_socket_receive Packet receive processing */ +/* _nx_tcp_socket_state_ack_check Socket state ACK processing */ +/* _nx_tcp_socket_state_data_check Socket state date processing */ +/* _nx_tcp_socket_state_established Socket state established */ +/* processing */ +/* _nx_tcp_socket_state_fin_wait2 Socket state FIN wait-2 */ +/* processing */ +/* _nx_tcp_socket_state_fin_wait1 Socket state FIN wait */ +/* processing */ +/* _nx_tcp_socket_state_syn_sent Socket state SYN sent */ +/* processing */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_tcp_packet_send_ack(NX_TCP_SOCKET *socket_ptr, ULONG tx_sequence) +{ + +NX_IP *ip_ptr; +NX_PACKET *packet_ptr; +NX_TCP_HEADER *tcp_header_ptr; +ULONG checksum; + + + /* Setup the IP pointer. */ + ip_ptr = socket_ptr -> nx_tcp_socket_ip_ptr; + + /* Allocate a packet for the ACK message. */ + if (_nx_packet_allocate(ip_ptr -> nx_ip_default_packet_pool, + &packet_ptr, NX_TCP_PACKET, NX_NO_WAIT) != NX_SUCCESS) + { + + /* Just give up and return. */ + return; + } + + /* The outgoing interface should have been stored in the socket structure. */ + packet_ptr -> nx_packet_ip_interface = socket_ptr -> nx_tcp_socket_connect_interface; + packet_ptr -> nx_packet_next_hop_address = socket_ptr -> nx_tcp_socket_next_hop_address; + /* Setup the packet payload pointers and length for a basic TCP packet. */ + packet_ptr -> nx_packet_prepend_ptr -= sizeof(NX_TCP_HEADER); + + /* Setup the packet length. */ + packet_ptr -> nx_packet_length = sizeof(NX_TCP_HEADER); + + /* Pickup the pointer to the head of the TCP packet. */ + tcp_header_ptr = (NX_TCP_HEADER *)packet_ptr -> nx_packet_prepend_ptr; + + /* Build the ACK request in the TCP header. */ + tcp_header_ptr -> nx_tcp_header_word_0 = (((ULONG)(socket_ptr -> nx_tcp_socket_port)) << NX_SHIFT_BY_16) | (ULONG)socket_ptr -> nx_tcp_socket_connect_port; + tcp_header_ptr -> nx_tcp_sequence_number = tx_sequence; + tcp_header_ptr -> nx_tcp_acknowledgment_number = socket_ptr -> nx_tcp_socket_rx_sequence; +#ifdef NX_ENABLE_TCP_WINDOW_SCALING + tcp_header_ptr -> nx_tcp_header_word_3 = NX_TCP_HEADER_SIZE | NX_TCP_ACK_BIT | (socket_ptr -> nx_tcp_socket_rx_window_current >> socket_ptr -> nx_tcp_rcv_win_scale_value); + +#else /* !NX_ENABLE_TCP_WINDOW_SCALING */ + tcp_header_ptr -> nx_tcp_header_word_3 = NX_TCP_HEADER_SIZE | NX_TCP_ACK_BIT | (socket_ptr -> nx_tcp_socket_rx_window_current); +#endif /* NX_ENABLE_TCP_WINDOW_SCALING */ + tcp_header_ptr -> nx_tcp_header_word_4 = 0; + + /* Remember the last ACKed sequence and the last reported window size. */ + socket_ptr -> nx_tcp_socket_rx_sequence_acked = socket_ptr -> nx_tcp_socket_rx_sequence; + socket_ptr -> nx_tcp_socket_rx_window_last_sent = socket_ptr -> nx_tcp_socket_rx_window_current; + + /* Setup a new delayed ACK timeout. */ + socket_ptr -> nx_tcp_socket_delayed_ack_timeout = _nx_tcp_ack_timer_rate; + + /* Endian swapping logic. If NX_LITTLE_ENDIAN is specified, these macros will + swap the endian of the TCP header. */ + 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); + + /* Calculate the TCP checksum. */ +#ifndef NX_DISABLE_TCP_TX_CHECKSUM + checksum = _nx_tcp_checksum(packet_ptr, packet_ptr -> nx_packet_ip_interface -> nx_interface_ip_address, socket_ptr -> nx_tcp_socket_connect_ip); +#else + checksum = 0; +#endif + + /* Move the checksum into header. */ + NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_header_word_4); + tcp_header_ptr -> nx_tcp_header_word_4 = (checksum << NX_SHIFT_BY_16); + NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_header_word_4); + + /* Send the TCP packet to the IP component. */ + _nx_ip_packet_send(ip_ptr, packet_ptr, socket_ptr -> nx_tcp_socket_connect_ip, + socket_ptr -> nx_tcp_socket_type_of_service, socket_ptr -> nx_tcp_socket_time_to_live, NX_IP_TCP, socket_ptr -> nx_tcp_socket_fragment_enable); +} + diff --git a/common/src/nx_tcp_packet_send_fin.c b/common/src/nx_tcp_packet_send_fin.c new file mode 100644 index 0000000..9e6ff2b --- /dev/null +++ b/common/src/nx_tcp_packet_send_fin.c @@ -0,0 +1,151 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_packet.h" +#include "nx_tcp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcp_packet_send_fin PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sends a FIN from the specified socket. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to socket */ +/* tx_sequence Transmit sequence number */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_packet_allocate Allocate a packet */ +/* _nx_tcp_checksum Calculate TCP checksum */ +/* _nx_ip_packet_send Send IP packet */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_tcp_socket_disconnect Socket disconnect processing */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_tcp_packet_send_fin(NX_TCP_SOCKET *socket_ptr, ULONG tx_sequence) +{ + +NX_IP *ip_ptr; +NX_PACKET *packet_ptr; +NX_TCP_HEADER *tcp_header_ptr; +ULONG checksum; + + + /* Setup the IP pointer. */ + ip_ptr = socket_ptr -> nx_tcp_socket_ip_ptr; + + /* Allocate a packet for the FIN message. */ + if (_nx_packet_allocate(ip_ptr -> nx_ip_default_packet_pool, + &packet_ptr, NX_TCP_PACKET, NX_NO_WAIT) != NX_SUCCESS) + { + + /* Just give up and return. */ + return; + } + + /* The outgoing interface should have been stored in the socket structure. */ + packet_ptr -> nx_packet_ip_interface = socket_ptr -> nx_tcp_socket_connect_interface; + packet_ptr -> nx_packet_next_hop_address = socket_ptr -> nx_tcp_socket_next_hop_address; + + /* Setup the packet payload pointers and length for a basic TCP packet. */ + packet_ptr -> nx_packet_prepend_ptr -= sizeof(NX_TCP_HEADER); + + /* Setup the packet length. */ + packet_ptr -> nx_packet_length = sizeof(NX_TCP_HEADER); + + /* Pickup the pointer to the head of the TCP packet. */ + tcp_header_ptr = (NX_TCP_HEADER *)packet_ptr -> nx_packet_prepend_ptr; + + /* Build the FIN request in the TCP header. */ + tcp_header_ptr -> nx_tcp_header_word_0 = (((ULONG)(socket_ptr -> nx_tcp_socket_port)) << NX_SHIFT_BY_16) | (ULONG)socket_ptr -> nx_tcp_socket_connect_port; + tcp_header_ptr -> nx_tcp_sequence_number = tx_sequence; + tcp_header_ptr -> nx_tcp_acknowledgment_number = socket_ptr -> nx_tcp_socket_rx_sequence; +#ifdef NX_ENABLE_TCP_WINDOW_SCALING + tcp_header_ptr -> nx_tcp_header_word_3 = NX_TCP_HEADER_SIZE | NX_TCP_FIN_BIT | NX_TCP_ACK_BIT | (socket_ptr -> nx_tcp_socket_rx_window_current >> socket_ptr -> nx_tcp_rcv_win_scale_value); +#else /* NX_ENABLE_TCP_WINDOW_SCALING */ + tcp_header_ptr -> nx_tcp_header_word_3 = NX_TCP_HEADER_SIZE | NX_TCP_FIN_BIT | NX_TCP_ACK_BIT | (socket_ptr -> nx_tcp_socket_rx_window_current); +#endif /* NX_ENABLE_TCP_WINDOW_SCALING */ + tcp_header_ptr -> nx_tcp_header_word_4 = 0; + + /* Remember the last ACKed sequence and the last reported window size. */ + socket_ptr -> nx_tcp_socket_rx_sequence_acked = socket_ptr -> nx_tcp_socket_rx_sequence; + socket_ptr -> nx_tcp_socket_rx_window_last_sent = socket_ptr -> nx_tcp_socket_rx_window_current; + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_TCP_FIN_SEND, ip_ptr, socket_ptr, packet_ptr, tx_sequence, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + /* Endian swapping logic. If NX_LITTLE_ENDIAN is specified, these macros will + swap the endian of the TCP header. */ + 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); + + /* Calculate the TCP checksum. */ +#ifndef NX_DISABLE_TCP_TX_CHECKSUM + checksum = _nx_tcp_checksum(packet_ptr, packet_ptr -> nx_packet_ip_interface -> nx_interface_ip_address, socket_ptr -> nx_tcp_socket_connect_ip); +#else + checksum = 0; +#endif + + + /* Move the checksum into header. */ + NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_header_word_4); + tcp_header_ptr -> nx_tcp_header_word_4 = (checksum << NX_SHIFT_BY_16); + NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_header_word_4); + + /* Send the TCP packet to the IP component. */ + _nx_ip_packet_send(ip_ptr, packet_ptr, socket_ptr -> nx_tcp_socket_connect_ip, + socket_ptr -> nx_tcp_socket_type_of_service, socket_ptr -> nx_tcp_socket_time_to_live, NX_IP_TCP, socket_ptr -> nx_tcp_socket_fragment_enable); +} + diff --git a/common/src/nx_tcp_packet_send_rst.c b/common/src/nx_tcp_packet_send_rst.c new file mode 100644 index 0000000..f6cf73c --- /dev/null +++ b/common/src/nx_tcp_packet_send_rst.c @@ -0,0 +1,185 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_packet.h" +#include "nx_tcp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcp_packet_send_rst PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sends a RST from the specified socket. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to socket */ +/* header_ptr Pointer to received header */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_packet_allocate Allocate a packet */ +/* _nx_tcp_checksum Calculate TCP checksum */ +/* _nx_ip_packet_send Send IP packet */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_tcp_no_connection_reset No connection reset processing*/ +/* _nx_tcp_socket_disconnect Disconnect processing */ +/* _nx_tcp_socket_state_syn_received Socket SYN received processing*/ +/* _nx_tcp_socket_state_syn_sent Socket SYN sent processing */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_tcp_packet_send_rst(NX_TCP_SOCKET *socket_ptr, NX_TCP_HEADER *header_ptr) +{ + +NX_IP *ip_ptr; +NX_PACKET *packet_ptr; +NX_TCP_HEADER *tcp_header_ptr; +ULONG checksum; + + + /* Setup the IP pointer. */ + ip_ptr = socket_ptr -> nx_tcp_socket_ip_ptr; + + /* Allocate a packet for the RST message. */ + if (_nx_packet_allocate(ip_ptr -> nx_ip_default_packet_pool, + &packet_ptr, NX_TCP_PACKET, NX_NO_WAIT) != NX_SUCCESS) + { + + /* Just give up and return. */ + return; + } + + /* The outgoing interface should have been stored in the socket structure. */ + packet_ptr -> nx_packet_ip_interface = socket_ptr -> nx_tcp_socket_connect_interface; + packet_ptr -> nx_packet_next_hop_address = socket_ptr -> nx_tcp_socket_next_hop_address; + +#ifndef NX_DISABLE_TCP_INFO + + /* Increment the resets sent count. */ + ip_ptr -> nx_ip_tcp_resets_sent++; +#endif + + /* Setup the packet payload pointers and length for a basic TCP packet. */ + packet_ptr -> nx_packet_prepend_ptr -= sizeof(NX_TCP_HEADER); + + /* Setup the packet length. */ + packet_ptr -> nx_packet_length = sizeof(NX_TCP_HEADER); + + /* Pickup the pointer to the head of the TCP packet. */ + tcp_header_ptr = (NX_TCP_HEADER *)packet_ptr -> nx_packet_prepend_ptr; + + /* Build the RST request in the TCP header. */ + tcp_header_ptr -> nx_tcp_header_word_0 = (((ULONG)(socket_ptr -> nx_tcp_socket_port)) << NX_SHIFT_BY_16) | (ULONG)socket_ptr -> nx_tcp_socket_connect_port; + + /* According to RFC 793, the RST packet is set up based on if the incoming packet has the ACK bit set. */ + /* If the incoming segment has an ACK field, the reset takes its sequence number from the ACK field of the segment, + otherwise the reset has sequence number zero and the ACK field is set to the sum of the sequence number and segment length of the incoming segment. */ + + /* Check for the ACK bit in the incoming TCP header. */ + if (header_ptr -> nx_tcp_header_word_3 & NX_TCP_ACK_BIT) + { + + /* Assign the acknowledgment number. */ + tcp_header_ptr -> nx_tcp_sequence_number = header_ptr -> nx_tcp_acknowledgment_number; + + /* Set the ack number. */ + tcp_header_ptr -> nx_tcp_acknowledgment_number = 0; + + /* Set the header size and CTL bits. */ + tcp_header_ptr -> nx_tcp_header_word_3 = NX_TCP_HEADER_SIZE | NX_TCP_RST_BIT; + } + else + { + + /* Assign the sequence number. */ + tcp_header_ptr -> nx_tcp_sequence_number = 0; + + /* Set the acknowledgment number as sequence number, since the sequence_number has been updated in upper layer function(such as: _nx_tcp_no_connection_reset). */ + tcp_header_ptr -> nx_tcp_acknowledgment_number = header_ptr -> nx_tcp_sequence_number; + + /* Set the header size and CTL bits. */ + tcp_header_ptr -> nx_tcp_header_word_3 = NX_TCP_HEADER_SIZE | NX_TCP_RST_BIT | NX_TCP_ACK_BIT; + } + +#ifdef NX_ENABLE_TCP_WINDOW_SCALING + tcp_header_ptr -> nx_tcp_header_word_3 |= (socket_ptr -> nx_tcp_socket_rx_window_current >> socket_ptr -> nx_tcp_rcv_win_scale_value); +#else /* !NX_ENABLE_TCP_WINDOW_SCALING */ + tcp_header_ptr -> nx_tcp_header_word_3 |= (socket_ptr -> nx_tcp_socket_rx_window_current); +#endif /* NX_ENABLE_TCP_WINDOW_SCALING */ + + tcp_header_ptr -> nx_tcp_header_word_4 = 0; + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_TCP_RESET_SEND, ip_ptr, socket_ptr, packet_ptr, header_ptr -> nx_tcp_acknowledgment_number, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + /* Endian swapping logic. If NX_LITTLE_ENDIAN is specified, these macros will + swap the endian of the TCP header. */ + 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); + + /* Calculate the TCP checksum. */ +#ifndef NX_DISABLE_TCP_TX_CHECKSUM + checksum = _nx_tcp_checksum(packet_ptr, packet_ptr -> nx_packet_ip_interface -> nx_interface_ip_address, socket_ptr -> nx_tcp_socket_connect_ip); +#else + checksum = 0; +#endif + + /* Move the checksum into header. */ + NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_header_word_4); + tcp_header_ptr -> nx_tcp_header_word_4 = (checksum << NX_SHIFT_BY_16); + NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_header_word_4); + + /* Send the TCP packet to the IP component. */ + _nx_ip_packet_send(ip_ptr, packet_ptr, socket_ptr -> nx_tcp_socket_connect_ip, + socket_ptr -> nx_tcp_socket_type_of_service, socket_ptr -> nx_tcp_socket_time_to_live, NX_IP_TCP, socket_ptr -> nx_tcp_socket_fragment_enable); +} + diff --git a/common/src/nx_tcp_packet_send_syn.c b/common/src/nx_tcp_packet_send_syn.c new file mode 100644 index 0000000..ef3b331 --- /dev/null +++ b/common/src/nx_tcp_packet_send_syn.c @@ -0,0 +1,259 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_tcp.h" +#include "nx_packet.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcp_packet_send_syn PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sends a SYN from the specified socket. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to socket */ +/* tx_sequence Transmit sequence number */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_packet_allocate Allocate a packet */ +/* _nx_tcp_checksum Calculate TCP checksum */ +/* _nx_ip_packet_send Send IP packet */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_tcp_client_socket_connect Client connect processing */ +/* _nx_tcp_periodic_processing Connection retry processing */ +/* _nx_tcp_packet_process Server connect response */ +/* processing */ +/* _nx_tcp_server_socket_accept Server socket accept */ +/* processing */ +/* _nx_tcp_socket_state_syn_sent Socket SYN sent processing */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_tcp_packet_send_syn(NX_TCP_SOCKET *socket_ptr, ULONG tx_sequence) +{ + +NX_IP *ip_ptr; +NX_PACKET *packet_ptr; +NX_TCP_SYN *tcp_header_ptr; +ULONG checksum; +ULONG option_word2 = NX_TCP_OPTION_END; +ULONG mss; +#ifdef NX_ENABLE_TCP_WINDOW_SCALING +UINT include_window_scaling = NX_FALSE; +UINT scale_factor; +#endif /* NX_ENABLE_TCP_WINDOW_SCALING */ + + /* Setup the IP pointer. */ + ip_ptr = socket_ptr -> nx_tcp_socket_ip_ptr; + + /* Allocate a packet for the SYN message. */ + if (_nx_packet_allocate(ip_ptr -> nx_ip_default_packet_pool, + &packet_ptr, (ULONG)(NX_IP_PACKET + sizeof(NX_TCP_SYN)), NX_NO_WAIT) != NX_SUCCESS) + { + + /* Just give up and return. */ + return; + } + + /* The outgoing interface should have been stored in the socket structure. */ + packet_ptr -> nx_packet_ip_interface = socket_ptr -> nx_tcp_socket_connect_interface; + packet_ptr -> nx_packet_next_hop_address = socket_ptr -> nx_tcp_socket_next_hop_address; + + /* Setup the packet payload pointers and length for a basic TCP packet. */ + packet_ptr -> nx_packet_prepend_ptr -= sizeof(NX_TCP_SYN); + + /* Setup the packet length. */ + packet_ptr -> nx_packet_length = sizeof(NX_TCP_SYN); + + /* Pickup the pointer to the head of the TCP packet. */ + tcp_header_ptr = (NX_TCP_SYN *)packet_ptr -> nx_packet_prepend_ptr; + + /* Build the SYN request in the TCP header. */ + tcp_header_ptr -> nx_tcp_header_word_0 = (((ULONG)(socket_ptr -> nx_tcp_socket_port)) << NX_SHIFT_BY_16) | (ULONG)socket_ptr -> nx_tcp_socket_connect_port; + tcp_header_ptr -> nx_tcp_sequence_number = tx_sequence; + + if (socket_ptr -> nx_tcp_socket_rx_window_current > 65535) + { + tcp_header_ptr -> nx_tcp_header_word_3 = NX_TCP_SYN_HEADER | NX_TCP_SYN_BIT | 65535; + } + else + { + tcp_header_ptr -> nx_tcp_header_word_3 = NX_TCP_SYN_HEADER | NX_TCP_SYN_BIT | (socket_ptr -> nx_tcp_socket_rx_window_current); + } + /* Determine if we are responding to a SYN or sending the initial SYN. */ + if (socket_ptr -> nx_tcp_socket_state == NX_TCP_SYN_SENT) + { + + /* This is the initial SYN. Set just the SYN bit and make the acknowledgement field zero. */ + tcp_header_ptr -> nx_tcp_acknowledgment_number = 0; + } + else + { + + /* This is the SYN in response to a client SYN... so it has a valid acknowledgment field. */ + tcp_header_ptr -> nx_tcp_acknowledgment_number = socket_ptr -> nx_tcp_socket_rx_sequence; + tcp_header_ptr -> nx_tcp_header_word_3 |= NX_TCP_ACK_BIT; + } + +#ifdef NX_ENABLE_TCP_WINDOW_SCALING + + /* Include window scaling option if we initiates the SYN, or the peer supports Window Scaling. */ + if (socket_ptr -> nx_tcp_socket_state == NX_TCP_SYN_SENT) + { + include_window_scaling = NX_TRUE; + } + else if (socket_ptr -> nx_tcp_snd_win_scale_value != 0xFF) + { + include_window_scaling = NX_TRUE; + } + + if (include_window_scaling) + { + + /* Sets the window scaling option. */ + option_word2 = NX_TCP_RWIN_OPTION; + + /* Compute the window scaling factor */ + for (scale_factor = 0; scale_factor < 15; scale_factor++) + { + + if ((socket_ptr -> nx_tcp_socket_rx_window_current >> scale_factor) < 65536) + { + break; + } + } + + if (scale_factor == 15) + { + scale_factor = 14; + } + + option_word2 |= scale_factor << 8; + + socket_ptr -> nx_tcp_rcv_win_scale_value = scale_factor; + } + +#endif /* NX_ENABLE_TCP_WINDOW_SCALING */ + + mss = socket_ptr -> nx_tcp_socket_connect_interface -> nx_interface_ip_mtu_size - sizeof(NX_IP_HEADER) - sizeof(NX_TCP_HEADER); + + mss &= 0x0000FFFFUL; + + if ((socket_ptr -> nx_tcp_socket_mss < mss) && socket_ptr -> nx_tcp_socket_mss) + { + + /* Use the custom MSS. */ + mss = socket_ptr -> nx_tcp_socket_mss; + } + + if (socket_ptr -> nx_tcp_socket_state == NX_TCP_SYN_RECEIVED) + { + + /* Update the connect MSS for TCP server socket. */ + if (mss < socket_ptr -> nx_tcp_socket_peer_mss) + { + socket_ptr -> nx_tcp_socket_connect_mss = mss; + } + else + { + socket_ptr -> nx_tcp_socket_connect_mss = socket_ptr -> nx_tcp_socket_peer_mss; + } + + /* Compute the SMSS * SMSS value, so later TCP module doesn't need to redo the multiplication. */ + socket_ptr -> nx_tcp_socket_connect_mss2 = + socket_ptr -> nx_tcp_socket_connect_mss * socket_ptr -> nx_tcp_socket_connect_mss; + } + + /* Build the remainder of the TCP header. */ + tcp_header_ptr -> nx_tcp_header_word_4 = 0; + tcp_header_ptr -> nx_tcp_option_word_1 = NX_TCP_MSS_OPTION | mss; + tcp_header_ptr -> nx_tcp_option_word_2 = option_word2; + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_TCP_SYN_SEND, ip_ptr, socket_ptr, packet_ptr, tx_sequence, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + /* Endian swapping logic. If NX_LITTLE_ENDIAN is specified, these macros will + swap the endian of the TCP header. */ + 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); + NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_option_word_1); + NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_option_word_2); + + /* Calculate the TCP checksum. */ +#ifndef NX_DISABLE_TCP_TX_CHECKSUM + checksum = _nx_tcp_checksum(packet_ptr, packet_ptr -> nx_packet_ip_interface -> nx_interface_ip_address, socket_ptr -> nx_tcp_socket_connect_ip); +#else + checksum = 0; +#endif + + /* Move the checksum into header. */ + NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_header_word_4); + tcp_header_ptr -> nx_tcp_header_word_4 = (checksum << NX_SHIFT_BY_16); + NX_CHANGE_ULONG_ENDIAN(tcp_header_ptr -> nx_tcp_header_word_4); + + /* Send the TCP packet to the IP component. */ + _nx_ip_packet_send(ip_ptr, packet_ptr, socket_ptr -> nx_tcp_socket_connect_ip, + socket_ptr -> nx_tcp_socket_type_of_service, socket_ptr -> nx_tcp_socket_time_to_live, NX_IP_TCP, socket_ptr -> nx_tcp_socket_fragment_enable); + + /* Initialize recover sequence and previous cumulative acknowledgment. */ + socket_ptr -> nx_tcp_socket_tx_sequence_recover = tx_sequence; + socket_ptr -> nx_tcp_socket_previous_highest_ack = tx_sequence; + + /* Reset duplicated ack received. */ + socket_ptr -> nx_tcp_socket_duplicated_ack_received = 0; + + /* Reset fast recovery stage. */ + socket_ptr -> nx_tcp_socket_fast_recovery = NX_FALSE; +} + diff --git a/common/src/nx_tcp_periodic_processing.c b/common/src/nx_tcp_periodic_processing.c new file mode 100644 index 0000000..f7ae587 --- /dev/null +++ b/common/src/nx_tcp_periodic_processing.c @@ -0,0 +1,156 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_packet.h" +#include "nx_tcp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcp_periodic_processing PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes periodic TCP processing for detecting */ +/* TCP transmit timeouts. If a transmit timeout occurs, the packet */ +/* is simply resent and a new timeout is setup. */ +/* */ +/* Note this requires that NX_ENABLE_TCP_KEEPALIVE is enabled when the */ +/* NetX library is built. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP control block */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_tcp_packet_send_ack Send ACK probe message */ +/* _nx_tcp_socket_connection_reset Reset the connection */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ip_thread_entry IP helper thread */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_tcp_periodic_processing(NX_IP *ip_ptr) +{ +#ifdef NX_ENABLE_TCP_KEEPALIVE + +NX_TCP_SOCKET *socket_ptr; +ULONG sockets; +UINT keepalive_enabled = NX_FALSE; + + + /* Pickup the number of created TCP sockets. */ + sockets = ip_ptr -> nx_ip_tcp_created_sockets_count; + + /* Pickup the first socket. */ + socket_ptr = ip_ptr -> nx_ip_tcp_created_sockets_ptr; + + /* Get the keepalive status of the current socket. */ + if (socket_ptr) + { + keepalive_enabled = socket_ptr -> nx_tcp_socket_keepalive_enabled; + } + + /* Loop through the created sockets. */ + while (sockets--) + { + + /* Is keep alive enabled on this socket? */ + if (keepalive_enabled) + { + + /* Yes; check for the socket having a TCP Keepalive timer active. */ + if ((socket_ptr -> nx_tcp_socket_state == NX_TCP_ESTABLISHED) && (socket_ptr -> nx_tcp_socket_keepalive_timeout)) + { + + /* Decrement the socket's keepalive timeout timer. */ + socket_ptr -> nx_tcp_socket_keepalive_timeout--; + + /* Determine if the keepalive timeout has expired. */ + if (!socket_ptr -> nx_tcp_socket_keepalive_timeout) + { + + /* Yes, the timeout has expired. Increment the retries and + determine if there are any retries left. */ + socket_ptr -> nx_tcp_socket_keepalive_retries++; + if (socket_ptr -> nx_tcp_socket_keepalive_retries < NX_TCP_KEEPALIVE_RETRIES) + { + + /* Yes, there are more retries left. Set the next timeout expiration + to the retry time instead of the initial time. */ + socket_ptr -> nx_tcp_socket_keepalive_timeout = NX_TCP_KEEPALIVE_RETRY; + + /* Send Keepalive ACK probe to see if the other side of the connection + is still there. We need to decrement the ACK number first for the + probe message and then restore the value immediately after the ACK + is sent. */ + _nx_tcp_packet_send_ack(socket_ptr, (socket_ptr -> nx_tcp_socket_tx_sequence - 1)); + } + else + { + + /* The Keepalive timer retries have failed, enter a CLOSED state + via the reset processing. */ + _nx_tcp_socket_connection_reset(socket_ptr); + } + } + } + } + + /* Move to the next TCP socket. */ + socket_ptr = socket_ptr -> nx_tcp_socket_created_next; + + /* Get the socket's keep alive status. */ + keepalive_enabled = socket_ptr -> nx_tcp_socket_keepalive_enabled; + } + + return; +#else + NX_PARAMETER_NOT_USED(ip_ptr); +#endif +} + diff --git a/common/src/nx_tcp_queue_process.c b/common/src/nx_tcp_queue_process.c new file mode 100644 index 0000000..f5d0249 --- /dev/null +++ b/common/src/nx_tcp_queue_process.c @@ -0,0 +1,105 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_tcp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcp_queue_process PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes the TCP receive packet queue. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP control block */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_tcp_packet_process Process TCP packet */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ip_thread_entry IP helper thread processing */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_tcp_queue_process(NX_IP *ip_ptr) +{ + +TX_INTERRUPT_SAVE_AREA + +NX_PACKET *queue_head; +NX_PACKET *packet_ptr; + + + /* Disable interrupts. */ + TX_DISABLE + + /* Remove the TCP message queue from the IP structure. */ + queue_head = ip_ptr -> nx_ip_tcp_queue_head; + ip_ptr -> nx_ip_tcp_queue_head = NX_NULL; + ip_ptr -> nx_ip_tcp_queue_tail = NX_NULL; + ip_ptr -> nx_ip_tcp_received_packet_count = 0; + + /* Restore interrupts. */ + TX_RESTORE + + /* Walk through the entire TCP message queue and process packets + one by one. */ + while (queue_head) + { + + /* Pickup the first queue TCP message and remove it from the + TCP queue. */ + packet_ptr = queue_head; + queue_head = queue_head -> nx_packet_queue_next; + packet_ptr -> nx_packet_queue_next = NX_NULL; + + /* Process the packet. */ + _nx_tcp_packet_process(ip_ptr, packet_ptr); + } +} + diff --git a/common/src/nx_tcp_receive_cleanup.c b/common/src/nx_tcp_receive_cleanup.c new file mode 100644 index 0000000..70f3d9c --- /dev/null +++ b/common/src/nx_tcp_receive_cleanup.c @@ -0,0 +1,225 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "tx_thread.h" +#include "tx_timer.h" +#include "nx_ip.h" +#include "nx_tcp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcp_receive_cleanup PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes TCP receive timeout and thread terminate */ +/* actions that require the TCP socket 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 */ +/* */ +/* _nx_tcp_deferred_cleanup_check Deferred cleanup processing */ +/* _nx_tcp_socket_connection_reset Socket reset connection */ +/* _nx_tcp_socket_disconnect Socket disconnect */ +/* _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_tcp_receive_cleanup(TX_THREAD *thread_ptr NX_CLEANUP_PARAMETER) +{ + +TX_INTERRUPT_SAVE_AREA + +NX_IP *ip_ptr; +NX_TCP_SOCKET *socket_ptr; /* Working socket pointer */ + + NX_CLEANUP_EXTENSION + + /* Disable interrupts. */ + TX_DISABLE + + /* Setup pointer to TCP socket control block. */ + socket_ptr = (NX_TCP_SOCKET *)thread_ptr -> tx_thread_suspend_control_block; + + /* Determine if the socket pointer is valid. */ + if ((!socket_ptr) || (socket_ptr -> nx_tcp_socket_id != NX_TCP_ID)) + { + + /* 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 NetX IP thread. */ + + /* Under interrupt protection, see if the suspension is still in effect. */ + if ((thread_ptr -> tx_thread_suspend_cleanup) && (socket_ptr) && (socket_ptr -> nx_tcp_socket_id == NX_TCP_ID)) + { + + /* Yes, change the suspend cleanup routine to indicate the cleanup is deferred. */ + thread_ptr -> tx_thread_suspend_cleanup = _nx_tcp_cleanup_deferred; + + /* Pickup the IP pointer. */ + ip_ptr = socket_ptr -> nx_tcp_socket_ip_ptr; + + /* Restore interrupts. */ + TX_RESTORE + + /* Set the deferred cleanup flag for the IP thread. */ + tx_event_flags_set(&(ip_ptr -> nx_ip_events), NX_IP_TCP_CLEANUP_DEFERRED, TX_OR); + + /* Return to caller. */ + return; + } + else + { + + /* Restore interrupts. */ + TX_RESTORE + + /* Return to caller. */ + return; + } + } + + /* Determine if the cleanup is still required. */ + if ((thread_ptr -> tx_thread_suspend_cleanup) && (socket_ptr) && (socket_ptr -> nx_tcp_socket_id == NX_TCP_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. */ + socket_ptr -> nx_tcp_socket_receive_suspension_list = NX_NULL; + } + else + { + + /* At least one more thread is on the same suspension list. */ + + /* Update the list head pointer. */ + socket_ptr -> nx_tcp_socket_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. */ + socket_ptr -> nx_tcp_socket_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 TCP socket. Setup return error status and + resume the thread. */ + + /* Determine which receive error is present. */ + if (socket_ptr -> nx_tcp_socket_state != NX_TCP_ESTABLISHED) + { + + /* This socket is no longer connected. */ + thread_ptr -> tx_thread_suspend_status = NX_NOT_CONNECTED; + } + else + { + + /* Setup return status. */ + thread_ptr -> tx_thread_suspend_status = NX_NO_PACKET; + } + + /* 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 +} + diff --git a/common/src/nx_tcp_server_socket_accept.c b/common/src/nx_tcp_server_socket_accept.c new file mode 100644 index 0000000..eed733f --- /dev/null +++ b/common/src/nx_tcp_server_socket_accept.c @@ -0,0 +1,229 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_tcp.h" +#include "tx_thread.h" + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcp_server_socket_accept PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets up the server socket after an active connection */ +/* request was received. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to new TCP socket */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_tcp_packet_send_syn Send SYN message */ +/* _nx_tcp_socket_thread_suspend Suspend thread for connection */ +/* tx_mutex_get Obtain a protection mutex */ +/* tx_mutex_put Release a protection mutex */ +/* rand Random number for sequence */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_tcp_server_socket_accept(NX_TCP_SOCKET *socket_ptr, ULONG wait_option) +{ + +NX_IP *ip_ptr; + + + /* Pickup the associated IP structure. */ + ip_ptr = socket_ptr -> nx_tcp_socket_ip_ptr; + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_TCP_SERVER_SOCKET_ACCEPT, ip_ptr, socket_ptr, wait_option, socket_ptr -> nx_tcp_socket_state, NX_TRACE_TCP_EVENTS, 0, 0) + + /* Check if the socket has already made a connection, return successful outcome to accept(). */ + if (socket_ptr -> nx_tcp_socket_state == NX_TCP_ESTABLISHED) + { + return(NX_SUCCESS); + } + + /* Determine if the socket is still in the listen state or has sent a SYN packet out already + from a previous accept() call on this socket. */ + if ((socket_ptr -> nx_tcp_socket_state != NX_TCP_LISTEN_STATE) && (socket_ptr -> nx_tcp_socket_state != NX_TCP_SYN_RECEIVED)) + { + + /* Socket has either been closed or in the process of closing*/ + return(NX_NOT_LISTEN_STATE); + } + + + /* Obtain the IP mutex so we can initiate accept processing for this socket. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + if (socket_ptr -> nx_tcp_socket_state == NX_TCP_LISTEN_STATE) + { + + /* Setup the initial sequence number. */ + if (socket_ptr -> nx_tcp_socket_tx_sequence == 0) + { + socket_ptr -> nx_tcp_socket_tx_sequence = (((ULONG)NX_RAND()) << NX_SHIFT_BY_16) | ((ULONG)NX_RAND()); + } + else + { + socket_ptr -> nx_tcp_socket_tx_sequence = socket_ptr -> nx_tcp_socket_tx_sequence + ((ULONG)(((ULONG)0x10000))) + ((ULONG)NX_RAND()); + } + + /* Ensure the rx window size logic is reset. */ + socket_ptr -> nx_tcp_socket_rx_window_current = socket_ptr -> nx_tcp_socket_rx_window_default; + socket_ptr -> nx_tcp_socket_rx_window_last_sent = socket_ptr -> nx_tcp_socket_rx_window_default; + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_TCP_STATE_CHANGE, ip_ptr, socket_ptr, socket_ptr -> nx_tcp_socket_state, NX_TCP_SYN_RECEIVED, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + /* Move the TCP state to Sequence Received, the next state of a passive open. */ + socket_ptr -> nx_tcp_socket_state = NX_TCP_SYN_RECEIVED; + + /* Clear the FIN received flag. */ + socket_ptr -> nx_tcp_socket_fin_received = NX_FALSE; + + /* Determine if the listen command has completed. This can be detected by checking + to see if the socket is bound. If it is bound and still in the listen state, then + we know that this service is being called after a client connection request was + received. */ + if (socket_ptr -> nx_tcp_socket_bound_next) + { + + /* Send a SYN message back to establish the connection, but increment the ACK first. */ + socket_ptr -> nx_tcp_socket_rx_sequence++; + + /* Increment the sequence number. */ + socket_ptr -> nx_tcp_socket_tx_sequence++; + + /* Setup a timeout so the connection attempt can be sent again. */ + socket_ptr -> nx_tcp_socket_timeout = socket_ptr -> nx_tcp_socket_timeout_rate; + socket_ptr -> nx_tcp_socket_timeout_retries = 0; + + /* CLEANUP: Clean up any existing socket data before making a new connection. */ + socket_ptr -> nx_tcp_socket_tx_window_congestion = 0; + socket_ptr -> nx_tcp_socket_tx_outstanding_bytes = 0; + socket_ptr -> nx_tcp_socket_packets_sent = 0; + socket_ptr -> nx_tcp_socket_bytes_sent = 0; + socket_ptr -> nx_tcp_socket_packets_received = 0; + socket_ptr -> nx_tcp_socket_bytes_received = 0; + socket_ptr -> nx_tcp_socket_retransmit_packets = 0; + socket_ptr -> nx_tcp_socket_checksum_errors = 0; + socket_ptr -> nx_tcp_socket_transmit_sent_head = NX_NULL; + socket_ptr -> nx_tcp_socket_transmit_sent_tail = NX_NULL; + socket_ptr -> nx_tcp_socket_transmit_sent_count = 0; + socket_ptr -> nx_tcp_socket_receive_queue_count = 0; + socket_ptr -> nx_tcp_socket_receive_queue_head = NX_NULL; + socket_ptr -> nx_tcp_socket_receive_queue_tail = NX_NULL; + + + /* Send the SYN+ACK message. */ + _nx_tcp_packet_send_syn(socket_ptr, (socket_ptr -> nx_tcp_socket_tx_sequence - 1)); + } + else + { + + /* This socket is not bound. Make sure there is no active timeout. */ + socket_ptr -> nx_tcp_socket_timeout = 0; + } + } + + /* Determine if the connection is complete. This can only happen in a connection + between ports on the same IP instance. */ + if (socket_ptr -> nx_tcp_socket_state == NX_TCP_ESTABLISHED) + { + + /* Release the protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return a successful status. */ + return(NX_SUCCESS); + } + + /* Determine if the wait option is specified. If so, suspend the calling thread. + Otherwise, return an in progress status. */ + if ((wait_option) && (_tx_thread_current_ptr != &(ip_ptr -> nx_ip_thread))) + { + + /* Suspend the thread on this socket's receive queue. */ + _nx_tcp_socket_thread_suspend(&(socket_ptr -> nx_tcp_socket_connect_suspended_thread), _nx_tcp_connect_cleanup, + socket_ptr, &(ip_ptr -> nx_ip_protection), wait_option); + + /* Check if the socket connection has failed. */ + if (_tx_thread_current_ptr -> tx_thread_suspend_status) + { + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_TCP_STATE_CHANGE, ip_ptr, socket_ptr, socket_ptr -> nx_tcp_socket_state, NX_TCP_LISTEN_STATE, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + /* Yes, socket connection has failed. Return to the + listen state so it can be tried again. */ + socket_ptr -> nx_tcp_socket_state = NX_TCP_LISTEN_STATE; + + /* Make sure the socket time out is cleared. */ + socket_ptr -> nx_tcp_socket_timeout = 0; + } + + /* If not, just return the status. */ + 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(&(ip_ptr -> nx_ip_protection)); + + /* Return in-progress completion status. */ + return(NX_IN_PROGRESS); + } +} + diff --git a/common/src/nx_tcp_server_socket_listen.c b/common/src/nx_tcp_server_socket_listen.c new file mode 100644 index 0000000..90ba343 --- /dev/null +++ b/common/src/nx_tcp_server_socket_listen.c @@ -0,0 +1,216 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_tcp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcp_server_socket_listen PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function registers a listen request and a server socket for */ +/* the specified TCP port. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP instance */ +/* port TCP port number */ +/* socket_ptr Server socket pointer */ +/* listen_queue_size Maximum number of connections */ +/* that can be queued */ +/* tcp_listen_callback Callback routine when a */ +/* connect request arrives */ +/* */ +/* 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_tcp_server_socket_listen(NX_IP *ip_ptr, UINT port, NX_TCP_SOCKET *socket_ptr, UINT listen_queue_size, + VOID (*tcp_listen_callback)(NX_TCP_SOCKET *socket_ptr, UINT port)) +{ + +struct NX_TCP_LISTEN_STRUCT *listen_ptr; +struct NX_TCP_LISTEN_STRUCT *tail_ptr; + + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_TCP_SERVER_SOCKET_LISTEN, ip_ptr, port, socket_ptr, listen_queue_size, NX_TRACE_TCP_EVENTS, 0, 0) + + /* Obtain the IP protection. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Determine if the server socket is in a proper state. */ + if (socket_ptr -> nx_tcp_socket_state != NX_TCP_CLOSED) + { + + /* Release the protection mutex. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return the not closed error code. */ + return(NX_NOT_CLOSED); + } + + /* Determine if the server socket has already been bound to port or if a socket bind is + already pending from another thread. */ + if ((socket_ptr -> nx_tcp_socket_bound_next) || + (socket_ptr -> nx_tcp_socket_bind_in_progress)) + { + + /* Release the protection mutex. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return an already bound error code. */ + return(NX_ALREADY_BOUND); + } + + /* Clean connected interface. */ + socket_ptr -> nx_tcp_socket_connect_interface = NX_NULL; + + /* Search through the active listen requests to see if there is already + one active. */ + listen_ptr = ip_ptr -> nx_ip_tcp_active_listen_requests; + if (listen_ptr) + { + + /* Search the active listen requests for this port. */ + do + { + + /* Determine if there is another listen request for the same port. */ + if (listen_ptr -> nx_tcp_listen_port == port) + { + + /* This is a duplicate request, return an error. */ + + /* Release the protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return the error code. */ + return(NX_DUPLICATE_LISTEN); + } + + /* Move to the next listen request. */ + listen_ptr = listen_ptr -> nx_tcp_listen_next; + } while (listen_ptr != ip_ptr -> nx_ip_tcp_active_listen_requests); + } + + /* Okay, we have a new listen request. */ + + /* Determine if there is an available listen structure. */ + if (!ip_ptr -> nx_ip_tcp_available_listen_requests) + { + + /* No listen structures available, release the protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return a maximum listen error code. */ + return(NX_MAX_LISTEN); + } + + /* Remove the first available listen request from the available list. */ + listen_ptr = ip_ptr -> nx_ip_tcp_available_listen_requests; + ip_ptr -> nx_ip_tcp_available_listen_requests = listen_ptr -> nx_tcp_listen_next; + + /* Setup the listen structure with the port and callback info. */ + listen_ptr -> nx_tcp_listen_port = port; + listen_ptr -> nx_tcp_listen_callback = tcp_listen_callback; + listen_ptr -> nx_tcp_listen_socket_ptr = socket_ptr; + + /* Setup the listen queue information. */ + listen_ptr -> nx_tcp_listen_queue_maximum = listen_queue_size; + listen_ptr -> nx_tcp_listen_queue_current = 0; + listen_ptr -> nx_tcp_listen_queue_head = NX_NULL; + listen_ptr -> nx_tcp_listen_queue_tail = NX_NULL; + + /* Indicate this socket is a server socket. */ + socket_ptr -> nx_tcp_socket_client_type = NX_FALSE; + + /* Move to the listen state. */ + socket_ptr -> nx_tcp_socket_state = NX_TCP_LISTEN_STATE; + + /* This socket should not have an active timeout yet. */ + socket_ptr -> nx_tcp_socket_timeout = 0; + + /* Remember what port is associated for this socket. */ + socket_ptr -> nx_tcp_socket_port = port; + + /* Link the listen request on the active list. */ + if (ip_ptr -> nx_ip_tcp_active_listen_requests) + { + + /* Nonempty list. Pickup tail pointer. */ + tail_ptr = (ip_ptr -> nx_ip_tcp_active_listen_requests) -> nx_tcp_listen_previous; + + /* Place the new listen request in the list. */ + (ip_ptr -> nx_ip_tcp_active_listen_requests) -> nx_tcp_listen_previous = listen_ptr; + tail_ptr -> nx_tcp_listen_next = listen_ptr; + + /* Setup this listen request's links. */ + listen_ptr -> nx_tcp_listen_previous = tail_ptr; + listen_ptr -> nx_tcp_listen_next = ip_ptr -> nx_ip_tcp_active_listen_requests; + } + else + { + + /* The active listen list is empty. Add listen request to an empty list. */ + ip_ptr -> nx_ip_tcp_active_listen_requests = listen_ptr; + listen_ptr -> nx_tcp_listen_previous = listen_ptr; + listen_ptr -> nx_tcp_listen_next = listen_ptr; + } + + /* Successful listen request, release the protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return success. */ + return(NX_SUCCESS); +} + diff --git a/common/src/nx_tcp_server_socket_relisten.c b/common/src/nx_tcp_server_socket_relisten.c new file mode 100644 index 0000000..012bdba --- /dev/null +++ b/common/src/nx_tcp_server_socket_relisten.c @@ -0,0 +1,337 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_tcp.h" +#include "nx_packet.h" +#include "nx_ip.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcp_server_socket_relisten PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function registers another server socket for an existing */ +/* listen request on the specified TCP port. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP instance */ +/* port TCP port number */ +/* socket_ptr Server socket pointer */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_packet_release Release packet */ +/* 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_tcp_server_socket_relisten(NX_IP *ip_ptr, UINT port, NX_TCP_SOCKET *socket_ptr) +{ + +UINT index; +struct NX_TCP_LISTEN_STRUCT *listen_ptr; +NX_PACKET *packet_ptr; +NX_TCP_HEADER *tcp_header_ptr; +ULONG *ip_header_ptr; +ULONG source_ip; +UINT source_port; +ULONG mss = 536; +ULONG option_words; +#ifdef NX_ENABLE_TCP_WINDOW_SCALING +ULONG rwin_scale; +#endif /* NX_ENABLE_TCP_WINDOW_SCALING */ +VOID (*listen_callback)(NX_TCP_SOCKET *socket_ptr, UINT port); + + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_TCP_SERVER_SOCKET_RELISTEN, ip_ptr, port, socket_ptr, socket_ptr -> nx_tcp_socket_state, NX_TRACE_TCP_EVENTS, 0, 0) + + /* Obtain the IP protection. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Determine if the server socket is in a proper state. */ + if (socket_ptr -> nx_tcp_socket_state != NX_TCP_CLOSED) + { + + /* Release the protection mutex. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return the not closed error code. */ + return(NX_NOT_CLOSED); + } + + /* Determine if the server socket has already been bound to port or if a socket bind is + already pending from another thread. */ + if ((socket_ptr -> nx_tcp_socket_bound_next) || + (socket_ptr -> nx_tcp_socket_bind_in_progress)) + { + + /* Release the protection mutex. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return an already bound error code. */ + return(NX_ALREADY_BOUND); + } + + /* Search through the active listen requests to see if there is already + one active. */ + listen_ptr = ip_ptr -> nx_ip_tcp_active_listen_requests; + if (listen_ptr) + { + + /* Search the active listen requests for this port. */ + do + { + + /* Determine if there is another listen request for the same port. */ + if ((listen_ptr -> nx_tcp_listen_port == port) && + (!listen_ptr -> nx_tcp_listen_socket_ptr)) + { + + /* Yes, a listen request was found for this port, with an empty + socket designation. */ + + /* Determine if there are any connection requests queued up. */ + if (!listen_ptr -> nx_tcp_listen_queue_current) + { + + /* Nothing is queued up, so simply store the new socket + in the listen structure. */ + + /* Place this socket in the listen structure. */ + listen_ptr -> nx_tcp_listen_socket_ptr = socket_ptr; + + /* Indicate this socket is a server socket. */ + socket_ptr -> nx_tcp_socket_client_type = NX_FALSE; + + /* Clean connected interface. */ + socket_ptr -> nx_tcp_socket_connect_interface = NX_NULL; + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_TCP_STATE_CHANGE, ip_ptr, socket_ptr, socket_ptr -> nx_tcp_socket_state, NX_TCP_LISTEN_STATE, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + /* Move to the listen state. */ + socket_ptr -> nx_tcp_socket_state = NX_TCP_LISTEN_STATE; + + /* This socket should not have an active timeout. */ + socket_ptr -> nx_tcp_socket_timeout = 0; + + /* Remember what port is associated for this socket. */ + socket_ptr -> nx_tcp_socket_port = port; + + /* Release the protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return success. */ + return(NX_SUCCESS); + } + else + { + + /* There is one or more connection requests queued up. Remove + the first (oldest) connection request and setup the current + socket. */ + + /* First, remove the first queued connection request. */ + packet_ptr = listen_ptr -> nx_tcp_listen_queue_head; + listen_ptr -> nx_tcp_listen_queue_head = packet_ptr -> nx_packet_queue_next; + + /* Determine if the tail needs to be adjusted. */ + if (packet_ptr == listen_ptr -> nx_tcp_listen_queue_tail) + { + listen_ptr -> nx_tcp_listen_queue_tail = NX_NULL; + } + + /* Decrease the total number of connections queued. */ + listen_ptr -> nx_tcp_listen_queue_current--; + + /* Pickup the source IP address. */ + ip_header_ptr = (ULONG *)packet_ptr -> nx_packet_prepend_ptr; + source_ip = *(ip_header_ptr - 2); + + /* Setup the TCP header pointer. */ + tcp_header_ptr = (NX_TCP_HEADER *)packet_ptr -> nx_packet_prepend_ptr; + + /* If this packet contains SYN */ + if (tcp_header_ptr -> nx_tcp_header_word_3 & NX_TCP_SYN_BIT) + { + /* Determine if there are any option words... Note there are always 5 words in a TCP header. */ + option_words = (tcp_header_ptr -> nx_tcp_header_word_3 >> 28) - 5; + if (option_words > 0) + { + + /* Yes, there are one or more option words. */ + + /* Derive the Maximum Segment Size (MSS) in the option words. */ + _nx_tcp_mss_option_get((packet_ptr -> nx_packet_prepend_ptr + sizeof(NX_TCP_HEADER)), option_words * sizeof(ULONG), &mss); + +#ifdef NX_ENABLE_TCP_WINDOW_SCALING + _nx_tcp_window_scaling_option_get((packet_ptr -> nx_packet_prepend_ptr + sizeof(NX_TCP_HEADER)), option_words * sizeof(ULONG), &rwin_scale); +#endif /* NX_ENABLE_TCP_WINDOW_SCALING */ + } + } + + /* Set MSS to 536 if the MSS value was not found. */ + if (!mss) + { + mss = 536; + } + + /* Pickup the source TCP port. */ + source_port = (UINT)(tcp_header_ptr -> nx_tcp_header_word_0 >> NX_SHIFT_BY_16); + + /* Fill the socket in with the appropriate information. */ + socket_ptr -> nx_tcp_socket_connect_ip = source_ip; + socket_ptr -> nx_tcp_socket_connect_port = source_port; + socket_ptr -> nx_tcp_socket_rx_sequence = tcp_header_ptr -> nx_tcp_sequence_number; + + socket_ptr -> nx_tcp_socket_connect_interface = packet_ptr -> nx_packet_ip_interface; + + /* Indicate this socket is a server socket. */ + socket_ptr -> nx_tcp_socket_client_type = NX_FALSE; + + if (_nx_ip_route_find(ip_ptr, source_ip, &socket_ptr -> nx_tcp_socket_connect_interface, + &socket_ptr -> nx_tcp_socket_next_hop_address) != NX_SUCCESS) + { + /* Cannot determine how to send packets to this TCP peer. Since we are able to + receive the syn, use the incoming interface, and send the packet out directly. */ + + socket_ptr -> nx_tcp_socket_connect_interface = packet_ptr -> nx_packet_ip_interface; + socket_ptr -> nx_tcp_socket_next_hop_address = source_ip; + } + + socket_ptr -> nx_tcp_socket_peer_mss = mss; + +#ifdef NX_ENABLE_TCP_WINDOW_SCALING + /* + Simply record the peer's window scale value. When we move to the + ESTABLISHED state, we will set the peer window scale to 0 if the + peer does not support this feature. + */ + socket_ptr -> nx_tcp_snd_win_scale_value = rwin_scale; +#endif /* NX_ENABLE_TCP_WINDOW_SCALING */ + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_TCP_STATE_CHANGE, ip_ptr, socket_ptr, socket_ptr -> nx_tcp_socket_state, NX_TCP_LISTEN_STATE, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + /* Move to the listen state. */ + socket_ptr -> nx_tcp_socket_state = NX_TCP_LISTEN_STATE; + + /* This socket should not have an active timeout. */ + socket_ptr -> nx_tcp_socket_timeout = 0; + + /* Remember what port is associated for this socket. */ + socket_ptr -> nx_tcp_socket_port = port; + + /* Calculate the hash index in the TCP port array of the associated IP instance. */ + index = (UINT)((port + (port >> 8)) & NX_TCP_PORT_TABLE_MASK); + + /* Determine if the list is NULL. */ + if (ip_ptr -> nx_ip_tcp_port_table[index]) + { + + /* There are already sockets on this list... just add this one + to the end. */ + 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; + } + else + { + + /* Nothing is on the TCP port list. Add this TCP socket to an + empty list. */ + socket_ptr -> nx_tcp_socket_bound_next = socket_ptr; + socket_ptr -> nx_tcp_socket_bound_previous = socket_ptr; + ip_ptr -> nx_ip_tcp_port_table[index] = socket_ptr; + } + + /* Pickup the listen callback routine. */ + listen_callback = listen_ptr -> nx_tcp_listen_callback; + + /* Release protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Determine if there is a listen callback function. */ + if (listen_callback) + { + + /* Call the user's listen callback function. */ + (listen_callback)(socket_ptr, port); + } + + /* Release the incoming packet. */ + _nx_packet_release(packet_ptr); + + /* Return a connection pending status so the caller knows + that a new connection request is already underway. This + is also a successful status. */ + return(NX_CONNECTION_PENDING); + } + } + + /* Move to the next listen request. */ + listen_ptr = listen_ptr -> nx_tcp_listen_next; + } while (listen_ptr != ip_ptr -> nx_ip_tcp_active_listen_requests); + } + + + /* Successful listen request, release the protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return an invalid relisten - nothing. */ + return(NX_INVALID_RELISTEN); +} + diff --git a/common/src/nx_tcp_server_socket_unaccept.c b/common/src/nx_tcp_server_socket_unaccept.c new file mode 100644 index 0000000..0a9462d --- /dev/null +++ b/common/src/nx_tcp_server_socket_unaccept.c @@ -0,0 +1,224 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_tcp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcp_server_socket_unaccept PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function removes the server socket from association with the */ +/* port receiving an earlier passive connection. It is left in a */ +/* state identical to the state after it was created. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to new TCP socket */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_tcp_socket_receive_queue_flush Release all receive packets */ +/* tx_mutex_get Obtain a protection mutex */ +/* tx_mutex_put Release a protection mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_tcp_server_socket_unaccept(NX_TCP_SOCKET *socket_ptr) +{ + +struct NX_TCP_LISTEN_STRUCT *listen_ptr; +NX_IP *ip_ptr; +UINT index; +UINT port; + + + /* Pickup the associated IP structure. */ + ip_ptr = socket_ptr -> nx_tcp_socket_ip_ptr; + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_TCP_SERVER_SOCKET_UNACCEPT, ip_ptr, socket_ptr, socket_ptr -> nx_tcp_socket_state, 0, NX_TRACE_TCP_EVENTS, 0, 0) + + /* Obtain the IP mutex so we can access the IP and socket data structures. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Determine if the socket is in a state of disconnect. */ + if ((socket_ptr -> nx_tcp_socket_state >= NX_TCP_CLOSE_WAIT) || + ((socket_ptr -> nx_tcp_socket_state == NX_TCP_CLOSED) && (socket_ptr -> nx_tcp_socket_bound_next))) + { + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_TCP_STATE_CHANGE, ip_ptr, socket_ptr, socket_ptr -> nx_tcp_socket_state, NX_TCP_LISTEN_STATE, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + /* Force to the listen state. */ + socket_ptr -> nx_tcp_socket_state = NX_TCP_LISTEN_STATE; + + /* Ensure the connect information is cleared. */ + socket_ptr -> nx_tcp_socket_connect_ip = 0; + socket_ptr -> nx_tcp_socket_connect_port = 0; + + /* This socket should not have an active timeout. */ + socket_ptr -> nx_tcp_socket_timeout = 0; + } + + /* Determine if the socket is in the listen state now. */ + if (socket_ptr -> nx_tcp_socket_state != NX_TCP_LISTEN_STATE) + { + + /* Release the IP protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return an error code. */ + return(NX_NOT_LISTEN_STATE); + } + + /* Check for a thread suspended for disconnect processing to complete. */ + if (socket_ptr -> nx_tcp_socket_disconnect_suspended_thread) + { + + /* Call the disconnect thread suspension cleanup routine. */ + _nx_tcp_disconnect_cleanup(socket_ptr -> nx_tcp_socket_disconnect_suspended_thread NX_CLEANUP_ARGUMENT); + } + + /* Remove the TCP socket form the associated port. */ + + /* Pickup the port number in the TCP socket structure. */ + port = socket_ptr -> nx_tcp_socket_port; + + /* Calculate the hash index in the TCP port array of the associated IP instance. */ + index = (UINT)((port + (port >> 8)) & NX_TCP_PORT_TABLE_MASK); + + /* Determine if this is the only socket bound on this port list. */ + if (socket_ptr -> nx_tcp_socket_bound_next == socket_ptr) + { + + /* Yes, this is the only socket on the port list. */ + + /* Clear the list head pointer and the next pointer in the socket. */ + ip_ptr -> nx_ip_tcp_port_table[index] = NX_NULL; + socket_ptr -> nx_tcp_socket_bound_next = NX_NULL; + } + else if (socket_ptr -> nx_tcp_socket_bound_next) + { + + /* Relink the neighbors of this TCP socket. */ + + /* Update the links of the adjacent sockets. */ + (socket_ptr -> nx_tcp_socket_bound_next) -> nx_tcp_socket_bound_previous = + socket_ptr -> nx_tcp_socket_bound_previous; + (socket_ptr -> nx_tcp_socket_bound_previous) -> nx_tcp_socket_bound_next = + socket_ptr -> nx_tcp_socket_bound_next; + + /* Determine if the head of the port list points to the socket being removed. + If so, we need to move the head pointer. */ + if (ip_ptr -> nx_ip_tcp_port_table[index] == socket_ptr) + { + + /* Yes, we need to move the port list head pointer. */ + ip_ptr -> nx_ip_tcp_port_table[index] = socket_ptr -> nx_tcp_socket_bound_next; + } + + /* Clear the next pointer in the socket to indicate it is no longer bound. */ + socket_ptr -> nx_tcp_socket_bound_next = NX_NULL; + } + else + { + + /* Not bound, so search through the active listen requests to see if this + socket is an active listen socket. */ + listen_ptr = ip_ptr -> nx_ip_tcp_active_listen_requests; + if (listen_ptr) + { + + /* Search the active listen requests for this port. */ + do + { + + /* Determine if we are releasing a socket that is listening. */ + if (listen_ptr -> nx_tcp_listen_socket_ptr == socket_ptr) + { + + /* Remove the socket from the listener. A relisten will be required to receive another + connection. */ + listen_ptr -> nx_tcp_listen_socket_ptr = NX_NULL; + break; + } + + /* Move to the next listen request. */ + listen_ptr = listen_ptr -> nx_tcp_listen_next; + } while (listen_ptr != ip_ptr -> nx_ip_tcp_active_listen_requests); + } + } + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_TCP_STATE_CHANGE, ip_ptr, socket_ptr, socket_ptr -> nx_tcp_socket_state, NX_TCP_CLOSED, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + /* Adjust the socket back to default states. */ + socket_ptr -> nx_tcp_socket_state = NX_TCP_CLOSED; + socket_ptr -> nx_tcp_socket_client_type = NX_TRUE; + + /* This socket should not have an active timeout. */ + socket_ptr -> nx_tcp_socket_timeout = 0; + + /* The socket is off the bound list... we need to check for queued receive packets and + if found they need to be released. */ + if (socket_ptr -> nx_tcp_socket_receive_queue_count) + { + + /* Release queued receive packets. */ + _nx_tcp_socket_receive_queue_flush(socket_ptr); + } + + /* Release the IP protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return success. */ + return(NX_SUCCESS); +} + diff --git a/common/src/nx_tcp_server_socket_unlisten.c b/common/src/nx_tcp_server_socket_unlisten.c new file mode 100644 index 0000000..d6db2d7 --- /dev/null +++ b/common/src/nx_tcp_server_socket_unlisten.c @@ -0,0 +1,208 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_tcp.h" +#include "nx_packet.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcp_server_socket_unlisten PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function removes a previous listen request for the specified */ +/* TCP port. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP instance */ +/* port TCP port number */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_packet_release Release queued connection */ +/* 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_tcp_server_socket_unlisten(NX_IP *ip_ptr, UINT port) +{ + +NX_TCP_SOCKET *socket_ptr; +NX_PACKET *packet_ptr; +NX_PACKET *next_packet_ptr; +ULONG queue_count; +struct NX_TCP_LISTEN_STRUCT *listen_ptr; + + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_TCP_SERVER_SOCKET_UNLISTEN, ip_ptr, port, 0, 0, NX_TRACE_TCP_EVENTS, 0, 0) + + /* Obtain the IP protection. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Search through the active listen requests to see if we can find + one for this port. */ + listen_ptr = ip_ptr -> nx_ip_tcp_active_listen_requests; + if (listen_ptr) + { + + /* Search the active listen requests for this port. */ + do + { + + /* Determine if there is a listen request for the specified port. */ + if (listen_ptr -> nx_tcp_listen_port == port) + { + + /* Unlink the listen structure from the active listen requests. */ + + /* See if the listen structure is the only one on the list. */ + if (listen_ptr == listen_ptr -> nx_tcp_listen_next) + { + + /* Only active listen, just set the active list to NULL. */ + ip_ptr -> nx_ip_tcp_active_listen_requests = NX_NULL; + } + else + { + + /* Link-up the neighbors. */ + (listen_ptr -> nx_tcp_listen_next) -> nx_tcp_listen_previous = + listen_ptr -> nx_tcp_listen_previous; + (listen_ptr -> nx_tcp_listen_previous) -> nx_tcp_listen_next = + listen_ptr -> nx_tcp_listen_next; + + /* See if we have to update the active list head pointer. */ + if (ip_ptr -> nx_ip_tcp_active_listen_requests == listen_ptr) + { + + /* Yes, move the head pointer to the next link. */ + ip_ptr -> nx_ip_tcp_active_listen_requests = listen_ptr -> nx_tcp_listen_next; + } + } + + /* Add the listen request back to the available list. */ + listen_ptr -> nx_tcp_listen_next = ip_ptr -> nx_ip_tcp_available_listen_requests; + ip_ptr -> nx_ip_tcp_available_listen_requests = listen_ptr; + + /* Pickup the socket for the listen request. */ + socket_ptr = listen_ptr -> nx_tcp_listen_socket_ptr; + + /* Determine if there was a socket dedicated for listening. */ + if (socket_ptr) + { + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_TCP_STATE_CHANGE, ip_ptr, socket_ptr, socket_ptr -> nx_tcp_socket_state, NX_TCP_CLOSED, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + /* Yes, change the state of the socket back to closed. */ + socket_ptr -> nx_tcp_socket_state = NX_TCP_CLOSED; + + /* This socket should not have an active timeout. */ + socket_ptr -> nx_tcp_socket_timeout = 0; + + /* Indicate this socket is a client socket, since this is the + default condition after it is created. */ + socket_ptr -> nx_tcp_socket_client_type = NX_TRUE; + + /* Clear the socket pointer in the listen structure. */ + listen_ptr -> nx_tcp_listen_socket_ptr = NX_NULL; + } + else + { + + /* Check for queued connection requests, if found, release + them all. */ + queue_count = listen_ptr -> nx_tcp_listen_queue_current; + packet_ptr = listen_ptr -> nx_tcp_listen_queue_head; + + /* Clear the listen connection queue pointers. */ + packet_ptr = listen_ptr -> nx_tcp_listen_queue_head; + listen_ptr -> nx_tcp_listen_queue_head = NX_NULL; + listen_ptr -> nx_tcp_listen_queue_tail = NX_NULL; + + /* Clear the listen connection count as well. */ + listen_ptr -> nx_tcp_listen_queue_current = 0; + + /* Loop through and release the packets representing queued + connections. */ + while (queue_count--) + { + + /* Save the next pointer. */ + next_packet_ptr = packet_ptr -> nx_packet_queue_next; + + /* Release the packet. */ + _nx_packet_release(packet_ptr); + + /* Move to the next packet. */ + packet_ptr = next_packet_ptr; + } + } + + /* Release the protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return success! */ + return(NX_SUCCESS); + } + + /* Move to the next listen request. */ + listen_ptr = listen_ptr -> nx_tcp_listen_next; + } while (listen_ptr != ip_ptr -> nx_ip_tcp_active_listen_requests); + } + + /* Unsuccessful listen request, release the protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return error code. */ + return(NX_ENTRY_NOT_FOUND); +} + diff --git a/common/src/nx_tcp_socket_bytes_available.c b/common/src/nx_tcp_socket_bytes_available.c new file mode 100644 index 0000000..08417c5 --- /dev/null +++ b/common/src/nx_tcp_socket_bytes_available.c @@ -0,0 +1,176 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifndef NX_SOURCE_CODE +#define NX_SOURCE_CODE +#endif + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_tcp.h" +#include "nx_packet.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcp_socket_bytes_available PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function determines the number of bytes available on a TCP */ +/* socket for reception. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to the TCP socket */ +/* bytes_available Number of bytes returned to */ +/* the caller. */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Obtain protection */ +/* tx_mutex_put Release protection */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_tcp_socket_bytes_available(NX_TCP_SOCKET *socket_ptr, ULONG *bytes_available) +{ + +NX_IP *ip_ptr; +NX_PACKET *packet_ptr; +ULONG data_size; +NX_TCP_HEADER *header_ptr; +ULONG header_length; +INT done = 0; + + + /* Setup IP pointer. */ + ip_ptr = socket_ptr -> nx_tcp_socket_ip_ptr; + + /* Obtain the IP mutex so we can examine the bound port. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Initialize the result of the byte count to zero. */ + *bytes_available = 0; + + /* Make sure the TCP connection has been established. */ + if ((socket_ptr -> nx_tcp_socket_state <= NX_TCP_LISTEN_STATE) || + (socket_ptr -> nx_tcp_socket_state > NX_TCP_ESTABLISHED)) + { + + /* Release protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + return(NX_NOT_CONNECTED); + } + + /* Get a pointer to the start of the packet receive queue. */ + packet_ptr = socket_ptr -> nx_tcp_socket_receive_queue_head; + + /* Is there anything in the queue? */ + if (packet_ptr == NX_NULL) + { + + /* No; receive queue is empty. */ + + /* Release protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* We're done.*/ + return(NX_SUCCESS); + } + + /* Loop through all the packets on the queue and find out the total + number of bytes in the receive queue available to the application. */ + do + { + + data_size = 0; + + /* Make sure the packet is ready to be received. */ + if (packet_ptr -> nx_packet_queue_next == ((NX_PACKET *)NX_PACKET_READY)) + { + + /* Compute the size of TCP payload in this packet */ + header_ptr = (NX_TCP_HEADER *)packet_ptr -> nx_packet_prepend_ptr; + + /* Calculate the header size for this packet. */ + header_length = ((header_ptr -> nx_tcp_header_word_3 >> NX_TCP_HEADER_SHIFT) * sizeof(ULONG)); + + /* Do not include header size as bytes available. */ + data_size = (packet_ptr -> nx_packet_length - header_length); + + *bytes_available += data_size; + + /* Is this the last packet? */ + if (packet_ptr == socket_ptr -> nx_tcp_socket_receive_queue_tail) + { + + /* Yes; Already reached the last packet. */ + done = 1; + } + else + { + + /* Move on to the next packet. */ + packet_ptr = packet_ptr -> nx_packet_tcp_queue_next; + } + } + else + { + + /* If the packet has not been acked yet, then just return the + amount of bytes available so far. */ + done = 1; + } + } while (!done); + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_TCP_SOCKET_BYTES_AVAILABLE, ip_ptr, socket_ptr, *bytes_available, 0, NX_TRACE_UDP_EVENTS, 0, 0); + + /* Release protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + return(NX_SUCCESS); +} + diff --git a/common/src/nx_tcp_socket_connection_reset.c b/common/src/nx_tcp_socket_connection_reset.c new file mode 100644 index 0000000..c9d390c --- /dev/null +++ b/common/src/nx_tcp_socket_connection_reset.c @@ -0,0 +1,180 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_tcp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcp_socket_connection_reset PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes a reset (RST) request received from the */ +/* other side of the connection. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to socket */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_tcp_socket_transmit_queue_flush Release transmitted packets */ +/* _nx_tcp_socket_receive_queue_flush Release received packets */ +/* _nx_tcp_connect_cleanup Resume thread suspended */ +/* waiting for connection */ +/* _nx_tcp_disconnect_cleanup Resume thread suspended */ +/* waiting for disconnection */ +/* _nx_tcp_receive_cleanup Resume threads suspended on */ +/* the receive queue */ +/* _nx_tcp_transmit_cleanup Resume threads suspended on */ +/* the transmit queue */ +/* (application disconnect callback) */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_tcp_fast_periodic_processing Transmit retry timeout */ +/* _nx_tcp_periodic_processing Keepalive processing */ +/* _nx_tcp_socket_packet_process Socket packet processing */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_tcp_socket_connection_reset(NX_TCP_SOCKET *socket_ptr) +{ + +UINT saved_state; + + /* Save the current state of the socket. */ + saved_state = socket_ptr -> nx_tcp_socket_state; + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_TCP_STATE_CHANGE, socket_ptr -> nx_tcp_socket_ip_ptr, socket_ptr, socket_ptr -> nx_tcp_socket_state, NX_TCP_CLOSED, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + /* The reset bit is set, immediately enter a CLOSED state. */ + socket_ptr -> nx_tcp_socket_state = NX_TCP_CLOSED; + + /* Clear the timeout. */ + socket_ptr -> nx_tcp_socket_timeout = 0; + + /* Clear the connected IP information to enable new connections + to come in prior to this socket being unaccepted or unbound. */ + socket_ptr -> nx_tcp_socket_connect_ip = 0; + + /* Check for queued sent packets and if found they need + to be released. */ + if (socket_ptr -> nx_tcp_socket_transmit_sent_count) + { + + /* Release all transmit packets. */ + _nx_tcp_socket_transmit_queue_flush(socket_ptr); + } + + /* Check for queued receive packets and if found they need + to be released. */ + if (socket_ptr -> nx_tcp_socket_receive_queue_count) + { + + /* Release all received packets. */ + _nx_tcp_socket_receive_queue_flush(socket_ptr); + } + + /* Clear all receive thread suspensions on this socket. */ + while (socket_ptr -> nx_tcp_socket_receive_suspension_list) + { + + /* Call the receive thread suspension cleanup routine. */ + _nx_tcp_receive_cleanup(socket_ptr -> nx_tcp_socket_receive_suspension_list NX_CLEANUP_ARGUMENT); + } + + /* Clear all transmit thread suspensions on this socket. */ + while (socket_ptr -> nx_tcp_socket_transmit_suspension_list) + { + + /* Call the receive thread suspension cleanup routine. */ + _nx_tcp_transmit_cleanup(socket_ptr -> nx_tcp_socket_transmit_suspension_list NX_CLEANUP_ARGUMENT); + } + + /* Check for suspended connect thread. */ + if (socket_ptr -> nx_tcp_socket_connect_suspended_thread) + { + + /* Call the connect thread suspension cleanup routine. */ + _nx_tcp_connect_cleanup(socket_ptr -> nx_tcp_socket_connect_suspended_thread NX_CLEANUP_ARGUMENT); + } + + /* Check for suspended disconnect thread. */ + if (socket_ptr -> nx_tcp_socket_disconnect_suspended_thread) + { + + /* Resume the thread suspended on the disconnect. */ + _nx_tcp_disconnect_cleanup(socket_ptr -> nx_tcp_socket_disconnect_suspended_thread NX_CLEANUP_ARGUMENT); + } + + /* Determine if the socket was in an established state. */ + if (saved_state == NX_TCP_ESTABLISHED) + { + + /* If given, call the application's disconnect callback function + for disconnect. */ + if (socket_ptr -> nx_tcp_disconnect_callback) + { + + /* Call the application's disconnect handling function. It is + responsible for calling the socket disconnect function. */ + (socket_ptr -> nx_tcp_disconnect_callback)(socket_ptr); + } + } + +#ifndef NX_DISABLE_EXTENDED_NOTIFY_SUPPORT + + /* Is a disconnect complete callback registered with the TCP socket? */ + if (socket_ptr -> nx_tcp_disconnect_complete_notify) + { + + /* Notify the application through the socket disconnect_complete callback. */ + (socket_ptr -> nx_tcp_disconnect_complete_notify)(socket_ptr); + } +#endif +} + diff --git a/common/src/nx_tcp_socket_create.c b/common/src/nx_tcp_socket_create.c new file mode 100644 index 0000000..aeec362 --- /dev/null +++ b/common/src/nx_tcp_socket_create.c @@ -0,0 +1,232 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_tcp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcp_socket_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates a TCP socket for the specified IP instance. */ +/* Both client and server sockets are created by this service. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP instance pointer */ +/* socket_ptr Pointer to new TCP socket */ +/* name Name of new TCP socket */ +/* type_of_service Type of service for this TCP */ +/* socket */ +/* fragment Flag to enable IP fragmenting */ +/* time_to_live Time to live value for socket */ +/* window_size Size of socket's receive */ +/* window */ +/* tcp_urgent_data_callback Routine to call when urgent */ +/* data is received */ +/* tcp_disconnect_callback Routine to call when a */ +/* disconnect occurs */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Obtain protection */ +/* tx_mutex_put Release protection */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_tcp_socket_create(NX_IP *ip_ptr, NX_TCP_SOCKET *socket_ptr, CHAR *name, + ULONG type_of_service, ULONG fragment, UINT time_to_live, ULONG window_size, + VOID (*tcp_urgent_data_callback)(NX_TCP_SOCKET *socket_ptr), + VOID (*tcp_disconnect_callback)(NX_TCP_SOCKET *socket_ptr)) +{ +TX_INTERRUPT_SAVE_AREA + +NX_TCP_SOCKET *tail_ptr; + + + /* Initialize the TCP control block to zero. */ + memset((void *)socket_ptr, 0, sizeof(NX_TCP_SOCKET)); + + /* Fill in the basic information in the new TCP socket structure. */ + + /* Remember the associated IP structure. */ + socket_ptr -> nx_tcp_socket_ip_ptr = ip_ptr; + + /* By default, indicate the socket is a client socket. */ + socket_ptr -> nx_tcp_socket_client_type = NX_TRUE; + + /* Save the TCP socket's name. */ + socket_ptr -> nx_tcp_socket_name = name; + + /* Initialize the socket MSS to 0. The MSS size is filled in when the underlying interface can be + determined. For client socket, the MSS is determined inside the nx_tcp_client_connect call. For + server sockets, the MSS is determined when the first SYN is received. */ + socket_ptr -> nx_tcp_socket_mss = 0; + socket_ptr -> nx_tcp_socket_connect_mss = 0; + + /* Save the type of service input parameter. */ + socket_ptr -> nx_tcp_socket_type_of_service = type_of_service; + + /* Save the fragment input parameter. */ + socket_ptr -> nx_tcp_socket_fragment_enable = fragment & NX_DONT_FRAGMENT; + + /* Save the time-to-live input parameter. */ + socket_ptr -> nx_tcp_socket_time_to_live = time_to_live; + + /* Clear the socket bind in progress flag. */ + socket_ptr -> nx_tcp_socket_bind_in_progress = NX_FALSE; + + /* Setup the delayed ACK timeout periodic rate. */ + socket_ptr -> nx_tcp_socket_delayed_ack_timeout = _nx_tcp_ack_timer_rate; + + /* Setup the default transmit timeout. */ + socket_ptr -> nx_tcp_socket_timeout_rate = _nx_tcp_transmit_timer_rate; + socket_ptr -> nx_tcp_socket_timeout_max_retries = NX_TCP_MAXIMUM_RETRIES; + socket_ptr -> nx_tcp_socket_timeout_shift = NX_TCP_RETRY_SHIFT; + + /* Setup the default maximum transmit queue depth. */ + socket_ptr -> nx_tcp_socket_transmit_queue_maximum_default = NX_TCP_MAXIMUM_TX_QUEUE; + socket_ptr -> nx_tcp_socket_transmit_queue_maximum = NX_TCP_MAXIMUM_TX_QUEUE; + +#ifdef NX_ENABLE_TCP_WINDOW_SCALING + + /* Window scaling feature is enabled. Record this user-specified window size. */ + socket_ptr -> nx_tcp_socket_rx_window_maximum = window_size; +#else + if (window_size > 65535) + { + window_size = 65535; + } + +#endif /* NX_ENABLE_TCP_WINDOW_SCALING */ + + /* Setup the sliding window information. */ + socket_ptr -> nx_tcp_socket_rx_window_default = window_size; + socket_ptr -> nx_tcp_socket_rx_window_current = window_size; + socket_ptr -> nx_tcp_socket_tx_outstanding_bytes = 0; + socket_ptr -> nx_tcp_socket_tx_window_advertised = 0; + socket_ptr -> nx_tcp_socket_tx_window_congestion = 0; + + + /* Initialize the ack_n_packet counter. */ + socket_ptr -> nx_tcp_socket_ack_n_packet_counter = 1; + + /* Save the application callback routines. */ + socket_ptr -> nx_tcp_urgent_data_callback = tcp_urgent_data_callback; + socket_ptr -> nx_tcp_disconnect_callback = tcp_disconnect_callback; + + /* Clear the receive notify function pointer. */ + socket_ptr -> nx_tcp_receive_callback = NX_NULL; + +#ifdef NX_ENABLE_TCP_KEEPALIVE + /* If the Keep alive feature is enabled in NetX, enable it + on all TCP sockets. */ + socket_ptr -> nx_tcp_socket_keepalive_enabled = NX_TRUE; +#endif + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_TCP_STATE_CHANGE, ip_ptr, socket_ptr, socket_ptr -> nx_tcp_socket_state, NX_TCP_CLOSED, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + /* Setup the initial TCP socket state. */ + socket_ptr -> nx_tcp_socket_state = NX_TCP_CLOSED; + + /* If trace is enabled, register this object. */ + NX_TRACE_OBJECT_REGISTER(NX_TRACE_OBJECT_TYPE_TCP_SOCKET, socket_ptr, name, type_of_service, window_size) + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_TCP_SOCKET_CREATE, ip_ptr, socket_ptr, type_of_service, window_size, NX_TRACE_TCP_EVENTS, 0, 0) + + /* Get protection while we insert the TCP socket into the created list. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Disable interrupts while we link the new TCP socket to the IP structure. */ + TX_DISABLE + + /* Load the TCP ID field in the TCP control block. */ + socket_ptr -> nx_tcp_socket_id = NX_TCP_ID; + + /* Place the new TCP control block on the list of created TCP sockets for this IP. First, + check for an empty list. */ + if (ip_ptr -> nx_ip_tcp_created_sockets_ptr) + { + + /* Pickup tail pointer. */ + tail_ptr = (ip_ptr -> nx_ip_tcp_created_sockets_ptr) -> nx_tcp_socket_created_previous; + + /* Place the new TCP socket control block in the list. */ + (ip_ptr -> nx_ip_tcp_created_sockets_ptr) -> nx_tcp_socket_created_previous = socket_ptr; + tail_ptr -> nx_tcp_socket_created_next = socket_ptr; + + /* Setup this TCP socket's created links. */ + socket_ptr -> nx_tcp_socket_created_previous = tail_ptr; + socket_ptr -> nx_tcp_socket_created_next = ip_ptr -> nx_ip_tcp_created_sockets_ptr; + } + else + { + + /* The created TCP socket list is empty. Add TCP socket control block to empty list. */ + ip_ptr -> nx_ip_tcp_created_sockets_ptr = socket_ptr; + socket_ptr -> nx_tcp_socket_created_previous = socket_ptr; + socket_ptr -> nx_tcp_socket_created_next = socket_ptr; + } + + /* Increment the created TCP socket counter. */ + ip_ptr -> nx_ip_tcp_created_sockets_count++; + + /* Restore previous interrupt posture. */ + TX_RESTORE + + /* Release protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return successful completion. */ + return(NX_SUCCESS); +} + diff --git a/common/src/nx_tcp_socket_delete.c b/common/src/nx_tcp_socket_delete.c new file mode 100644 index 0000000..60e146b --- /dev/null +++ b/common/src/nx_tcp_socket_delete.c @@ -0,0 +1,158 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_tcp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcp_socket_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function deletes a previously created socket and unbound */ +/* socket. If the socket is still bound, an error is returned. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to TCP socket */ +/* */ +/* 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_tcp_socket_delete(NX_TCP_SOCKET *socket_ptr) +{ + +TX_INTERRUPT_SAVE_AREA + +NX_IP *ip_ptr; + + + /* Setup the pointer to the associated IP instance. */ + ip_ptr = socket_ptr -> nx_tcp_socket_ip_ptr; + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_TCP_SOCKET_DELETE, ip_ptr, socket_ptr, socket_ptr -> nx_tcp_socket_state, 0, NX_TRACE_TCP_EVENTS, 0, 0) + + /* Obtain the IP mutex so we can process the socket delete request. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Determine if the socket has been created. */ + if (socket_ptr -> nx_tcp_socket_id != NX_TCP_ID) + { + + /* Release the protection mutex. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return a not created error code. */ + return(NX_NOT_CREATED); + } + + /* Determine if the socket is still bound to port. */ + if (socket_ptr -> nx_tcp_socket_bound_next) + { + + /* Release the protection mutex. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return a still bound error code. */ + return(NX_STILL_BOUND); + } + + /* Disable interrupts. */ + TX_DISABLE + + /* Now, remove the TCP socket from the created socket list. */ + + /* Clear the socket ID to make it invalid. */ + socket_ptr -> nx_tcp_socket_id = 0; + + /* See if the socket is the only one on the list. */ + if (socket_ptr == socket_ptr -> nx_tcp_socket_created_next) + { + + /* Only created socket, just set the created list to NULL. */ + ip_ptr -> nx_ip_tcp_created_sockets_ptr = NX_NULL; + } + else + { + + /* Link-up the neighbors. */ + (socket_ptr -> nx_tcp_socket_created_next) -> nx_tcp_socket_created_previous = + socket_ptr -> nx_tcp_socket_created_previous; + (socket_ptr -> nx_tcp_socket_created_previous) -> nx_tcp_socket_created_next = + socket_ptr -> nx_tcp_socket_created_next; + + /* See if we have to update the created list head pointer. */ + if (ip_ptr -> nx_ip_tcp_created_sockets_ptr == socket_ptr) + { + + /* Yes, move the head pointer to the next link. */ + ip_ptr -> nx_ip_tcp_created_sockets_ptr = socket_ptr -> nx_tcp_socket_created_next; + } + } + + /* Decrease the created sockets count. */ + ip_ptr -> nx_ip_tcp_created_sockets_count--; + + /* Restore interrupts. */ + TX_RESTORE + + /* If trace is enabled, unregister this object. */ + NX_TRACE_OBJECT_UNREGISTER(ip_ptr) + + /* Release the IP protection mutex. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return success. */ + return(NX_SUCCESS); +} + diff --git a/common/src/nx_tcp_socket_disconnect.c b/common/src/nx_tcp_socket_disconnect.c new file mode 100644 index 0000000..8f946c0 --- /dev/null +++ b/common/src/nx_tcp_socket_disconnect.c @@ -0,0 +1,400 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_tcp.h" +#include "tx_thread.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcp_socket_disconnect PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function handles the disconnect request for both active and */ +/* passive calls. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to TCP client socket */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_tcp_connect_cleanup Clear connect suspension */ +/* _nx_tcp_disconnect_cleanup Clear disconnect suspension */ +/* _nx_tcp_packet_send_fin Send FIN message */ +/* _nx_tcp_packet_send_rst Send RST on no timeout */ +/* _nx_tcp_receive_cleanup Clear receive suspension */ +/* _nx_tcp_transmit_cleanup Clear transmit suspension */ +/* _nx_tcp_socket_thread_suspend Suspend calling thread */ +/* _nx_tcp_socket_transmit_queue_flush Release all transmit packets */ +/* 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 */ +/* */ +/**************************************************************************/ +UINT _nx_tcp_socket_disconnect(NX_TCP_SOCKET *socket_ptr, ULONG wait_option) +{ + +#ifndef NX_DISABLE_RESET_DISCONNECT +NX_TCP_HEADER tcp_header; +#endif +UINT status; +NX_IP *ip_ptr; + + + /* Setup IP pointer. */ + ip_ptr = socket_ptr -> nx_tcp_socket_ip_ptr; + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_TCP_SOCKET_DISCONNECT, ip_ptr, socket_ptr, wait_option, socket_ptr -> nx_tcp_socket_state, NX_TRACE_TCP_EVENTS, 0, 0) + + /* Default status to success. */ + status = NX_SUCCESS; + + /* Obtain the IP mutex so we can access socket and IP information. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + +#ifndef NX_DISABLE_TCP_INFO + /* Increment the TCP disconnections count. */ + ip_ptr -> nx_ip_tcp_disconnections++; +#endif + + /* Determine if the socket is in a state not valid for a disconnect. */ + if ((socket_ptr -> nx_tcp_socket_state != NX_TCP_ESTABLISHED) && + (socket_ptr -> nx_tcp_socket_state != NX_TCP_SYN_SENT) && + (socket_ptr -> nx_tcp_socket_state != NX_TCP_SYN_RECEIVED) && + (socket_ptr -> nx_tcp_socket_state != NX_TCP_CLOSE_WAIT)) + { + + /* Release protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return a not connected error code. */ + return(NX_NOT_CONNECTED); + } + +#ifdef NX_ENABLE_TCP_KEEPALIVE + /* Clear the TCP Keepalive timer to disable it for this socket (only needed when + the socket is connected. */ + socket_ptr -> nx_tcp_socket_keepalive_timeout = 0; + socket_ptr -> nx_tcp_socket_keepalive_retries = 0; +#endif + + /* Determine if the connection wasn't fully completed. */ + if ((socket_ptr -> nx_tcp_socket_state == NX_TCP_SYN_SENT) || + (socket_ptr -> nx_tcp_socket_state == NX_TCP_SYN_RECEIVED)) + { + + /* Connection wasn't fully completed, reset to the proper socket state. */ + if (socket_ptr -> nx_tcp_socket_client_type) + { + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_TCP_STATE_CHANGE, ip_ptr, socket_ptr, socket_ptr -> nx_tcp_socket_state, NX_TCP_CLOSED, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + if (socket_ptr -> nx_tcp_socket_state == NX_TCP_SYN_RECEIVED) + { + + /* Setup FIN timeout. */ + socket_ptr -> nx_tcp_socket_timeout = socket_ptr -> nx_tcp_socket_timeout_rate; + socket_ptr -> nx_tcp_socket_timeout_retries = 0; + + /* Increment the sequence number. */ + socket_ptr -> nx_tcp_socket_tx_sequence++; + + /* Send FIN packet. */ + _nx_tcp_packet_send_fin(socket_ptr, (socket_ptr -> nx_tcp_socket_tx_sequence - 1)); + } + + /* Client socket, return to a CLOSED state. */ + socket_ptr -> nx_tcp_socket_state = NX_TCP_CLOSED; + } + else + { + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_TCP_STATE_CHANGE, ip_ptr, socket_ptr, socket_ptr -> nx_tcp_socket_state, NX_TCP_LISTEN_STATE, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + if ((socket_ptr -> nx_tcp_socket_state == NX_TCP_SYN_RECEIVED) && + (socket_ptr -> nx_tcp_socket_connect_interface != NX_NULL)) + { + + /* Setup FIN timeout. */ + socket_ptr -> nx_tcp_socket_timeout = socket_ptr -> nx_tcp_socket_timeout_rate; + socket_ptr -> nx_tcp_socket_timeout_retries = 0; + + /* Increment the sequence number. */ + socket_ptr -> nx_tcp_socket_tx_sequence++; + + /* Send FIN packet. */ + _nx_tcp_packet_send_fin(socket_ptr, (socket_ptr -> nx_tcp_socket_tx_sequence - 1)); + } + + /* Server socket, return to LISTEN state. */ + socket_ptr -> nx_tcp_socket_state = NX_TCP_LISTEN_STATE; + + /* Move back the acknowledgment number just in case there is a retry. */ + socket_ptr -> nx_tcp_socket_rx_sequence--; + } + + /* Socket is no longer active. Clear the timeout. */ + socket_ptr -> nx_tcp_socket_timeout = 0; + } + +#ifndef NX_DISABLE_RESET_DISCONNECT + + /* Determine if there is no timeout associated with the disconnect. If this is the case, + we will send a RST and simply enter a closed state. */ + else if (wait_option == NX_NO_WAIT) + { + + /* No timeout was specified, simply send a RST and enter a closed or listen state. */ + + /* Clear this field so the RST packet handler knows this is a fake header. */ + tcp_header.nx_tcp_header_word_3 = NX_TCP_ACK_BIT; + + /* Send the RST packet. We just want to create a fake header, so assume this packet is incoming packet. */ + tcp_header.nx_tcp_acknowledgment_number = socket_ptr -> nx_tcp_socket_tx_sequence; + tcp_header.nx_tcp_sequence_number = socket_ptr -> nx_tcp_socket_rx_sequence; + _nx_tcp_packet_send_rst(socket_ptr, &tcp_header); + + /* Connection needs to be closed down immediately. */ + if (socket_ptr -> nx_tcp_socket_client_type) + { + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_TCP_STATE_CHANGE, ip_ptr, socket_ptr, socket_ptr -> nx_tcp_socket_state, NX_TCP_CLOSED, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + /* Client socket, return to a CLOSED state. */ + socket_ptr -> nx_tcp_socket_state = NX_TCP_CLOSED; + } + else + { + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_TCP_STATE_CHANGE, ip_ptr, socket_ptr, socket_ptr -> nx_tcp_socket_state, NX_TCP_LISTEN_STATE, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + /* Server socket, return to LISTEN state. */ + socket_ptr -> nx_tcp_socket_state = NX_TCP_LISTEN_STATE; + } + + /* Socket is no longer active. Clear the timeout. */ + socket_ptr -> nx_tcp_socket_timeout = 0; + + /* Ensure the connect information is cleared. */ + socket_ptr -> nx_tcp_socket_connect_ip = 0; + socket_ptr -> nx_tcp_socket_connect_port = 0; + + /* No suspension is requested, just set the return status to in progress. */ + status = NX_IN_PROGRESS; + } +#endif + + /* Determine if this is an active disconnect, i.e. initiated by the application rather + than in response to a disconnect from the connected socket. */ + else if (socket_ptr -> nx_tcp_socket_state != NX_TCP_CLOSE_WAIT) + { + + /* Yes, this disconnect was initiated by the application. Initiate the disconnect + process. */ + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_TCP_STATE_CHANGE, ip_ptr, socket_ptr, socket_ptr -> nx_tcp_socket_state, NX_TCP_FIN_WAIT_1, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + /* Move the TCP state to FIN WAIT 1 state, the first state of an active close. */ + socket_ptr -> nx_tcp_socket_state = NX_TCP_FIN_WAIT_1; + + /* Determine if the transmit queue is empty. Only setup a FIN timeout here when + there are no more transmit packets waiting to be ACKed. If there are transmit + packets still waiting, the FIN timeout will be setup when the transmit queue is completely + acknowledged. */ + if (socket_ptr -> nx_tcp_socket_transmit_sent_head == NX_NULL) + { + + /* No transmit packets queue, setup FIN timeout. */ + socket_ptr -> nx_tcp_socket_timeout = socket_ptr -> nx_tcp_socket_timeout_rate; + socket_ptr -> nx_tcp_socket_timeout_retries = 0; + } + + /* Increment the sequence number. */ + socket_ptr -> nx_tcp_socket_tx_sequence++; + + /* Send FIN packet. */ + _nx_tcp_packet_send_fin(socket_ptr, (socket_ptr -> nx_tcp_socket_tx_sequence - 1)); + } + else + { + + /* This disconnect request is coming after the other side of the TCP connection + initiated a disconnect. */ + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_TCP_STATE_CHANGE, ip_ptr, socket_ptr, socket_ptr -> nx_tcp_socket_state, NX_TCP_LAST_ACK, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + /* Move the TCP state to wait for the last ACK message for the complete disconnect. */ + socket_ptr -> nx_tcp_socket_state = NX_TCP_LAST_ACK; + + /* Send a FIN message back to the side of the connection that initiated the + disconnect. */ + + /* Determine if the transmit queue is empty. Only setup a FIN timeout here when + there are no more transmit packets waiting to be ACKed. If there are transmit + packets still waiting, the FIN timeout will be setup when the transmit queue is completely + acknowledged. */ + if (socket_ptr -> nx_tcp_socket_transmit_sent_head == NX_NULL) + { + + /* No transmit packets queue, setup FIN timeout. */ + socket_ptr -> nx_tcp_socket_timeout = socket_ptr -> nx_tcp_socket_timeout_rate; + socket_ptr -> nx_tcp_socket_timeout_retries = 0; + } + + /* Increment the sequence number. */ + socket_ptr -> nx_tcp_socket_tx_sequence++; + + /* Send FIN packet. */ + _nx_tcp_packet_send_fin(socket_ptr, (socket_ptr -> nx_tcp_socket_tx_sequence - 1)); + } + + /* Optionally suspend the thread. If timeout occurs, return a disconnect timeout status. If + immediate response is selected, return a disconnect in progress status. Only on a real + disconnect should success be returned. */ + if ((socket_ptr -> nx_tcp_socket_state != NX_TCP_CLOSED) && (socket_ptr -> nx_tcp_socket_state != NX_TCP_LISTEN_STATE) && + (wait_option) && (_tx_thread_current_ptr != &(ip_ptr -> nx_ip_thread))) + { + + /* Suspend the thread on socket disconnect. */ + _nx_tcp_socket_thread_suspend(&(socket_ptr -> nx_tcp_socket_disconnect_suspended_thread), _nx_tcp_disconnect_cleanup, socket_ptr, &(ip_ptr -> nx_ip_protection), wait_option); + + /* Reobtain the IP mutex. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Ensure the connect information is cleared. */ + socket_ptr -> nx_tcp_socket_connect_ip = 0; + socket_ptr -> nx_tcp_socket_connect_port = 0; + + /* Return to the proper disconnected socket state. */ + if (socket_ptr -> nx_tcp_socket_client_type) + { + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_TCP_STATE_CHANGE, ip_ptr, socket_ptr, socket_ptr -> nx_tcp_socket_state, NX_TCP_CLOSED, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + /* Client socket, return to a CLOSED state. */ + socket_ptr -> nx_tcp_socket_state = NX_TCP_CLOSED; + } + else + { + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_TCP_STATE_CHANGE, ip_ptr, socket_ptr, socket_ptr -> nx_tcp_socket_state, NX_TCP_LISTEN_STATE, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + /* Server socket, return to LISTEN state. */ + socket_ptr -> nx_tcp_socket_state = NX_TCP_LISTEN_STATE; + } + + /* Socket is no longer active. Clear the timeout. */ + socket_ptr -> nx_tcp_socket_timeout = 0; + + /* Use the thread return the completion code. */ + status = _tx_thread_current_ptr -> tx_thread_suspend_status; + } + + /* We now need to check for any remaining sent packets in the transmit queue. + If found they need to be released. */ + if (socket_ptr -> nx_tcp_socket_transmit_sent_count) + { + + /* Clear the timeout if we have not already done so. */ + socket_ptr -> nx_tcp_socket_timeout = 0; + + /* Release all transmit packets. */ + _nx_tcp_socket_transmit_queue_flush(socket_ptr); + } + + /* Clear any connection suspension on this socket. */ + if (socket_ptr -> nx_tcp_socket_connect_suspended_thread) + { + + /* Call the connect thread suspension cleanup routine. */ + _nx_tcp_connect_cleanup(socket_ptr -> nx_tcp_socket_connect_suspended_thread NX_CLEANUP_ARGUMENT); + } + + /* Check for a thread suspended for disconnect processing to complete. */ + if (socket_ptr -> nx_tcp_socket_disconnect_suspended_thread) + { + + /* Call the disconnect thread suspension cleanup routine. */ + _nx_tcp_disconnect_cleanup(socket_ptr -> nx_tcp_socket_disconnect_suspended_thread NX_CLEANUP_ARGUMENT); + } + + /* Clear all receive thread suspensions on this socket. */ + while (socket_ptr -> nx_tcp_socket_receive_suspension_list) + { + + /* Call the receive thread suspension cleanup routine. */ + _nx_tcp_receive_cleanup(socket_ptr -> nx_tcp_socket_receive_suspension_list NX_CLEANUP_ARGUMENT); + } + + /* Clear all transmit thread suspensions on this socket. */ + while (socket_ptr -> nx_tcp_socket_transmit_suspension_list) + { + + /* Call the receive thread suspension cleanup routine. */ + _nx_tcp_transmit_cleanup(socket_ptr -> nx_tcp_socket_transmit_suspension_list NX_CLEANUP_ARGUMENT); + } + + /* Release the IP protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return in-progress completion status. */ + return(status); +} + diff --git a/common/src/nx_tcp_socket_disconnect_complete_notify.c b/common/src/nx_tcp_socket_disconnect_complete_notify.c new file mode 100644 index 0000000..a7d456c --- /dev/null +++ b/common/src/nx_tcp_socket_disconnect_complete_notify.c @@ -0,0 +1,99 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_tcp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcp_socket_disconnect_complete_notify PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets the disconnect complete notify function pointer */ +/* to the function specified by the application, which is called when */ +/* disconnect with the remote TCP host is complete. If a NULL pointer */ +/* is supplied, the disconnect complete notify function is disabled. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to TCP socket */ +/* tcp_disconnect_complete_notify Routine to call when the */ +/* disconnect is complete */ +/* */ +/* 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_tcp_socket_disconnect_complete_notify(NX_TCP_SOCKET *socket_ptr, VOID (*tcp_disconnect_complete_notify)(NX_TCP_SOCKET *socket_ptr)) +{ + +#ifndef NX_DISABLE_EXTENDED_NOTIFY_SUPPORT +TX_INTERRUPT_SAVE_AREA + + + /* Disable interrupts. */ + TX_DISABLE + + /* Setup the establish notify function pointer. */ + socket_ptr -> nx_tcp_disconnect_complete_notify = tcp_disconnect_complete_notify; + + /* Restore interrupts. */ + TX_RESTORE + + /* Return successful completion. */ + return(NX_SUCCESS); +#else /* NX_DISABLE_EXTENDED_NOTIFY_SUPPORT */ + NX_PARAMETER_NOT_USED(socket_ptr); + NX_PARAMETER_NOT_USED(tcp_disconnect_complete_notify); + + return(NX_NOT_SUPPORTED); +#endif /* NX_DISABLE_EXTENDED_NOTIFY_SUPPORT */ +} + diff --git a/common/src/nx_tcp_socket_establish_notify.c b/common/src/nx_tcp_socket_establish_notify.c new file mode 100644 index 0000000..1bda229 --- /dev/null +++ b/common/src/nx_tcp_socket_establish_notify.c @@ -0,0 +1,100 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_tcp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcp_socket_establish_notify PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets the establish notify function pointer to the */ +/* function specified by the application, which is called when the */ +/* handshake connection with the remote TCP host is complete. If a */ +/* NULL pointer is supplied, the establish notify function is disabled.*/ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to TCP socket */ +/* tcp_establish_notify Routine to call when the */ +/* connection handshake is */ +/* complete socket */ +/* */ +/* 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_tcp_socket_establish_notify(NX_TCP_SOCKET *socket_ptr, VOID (*tcp_establish_notify)(NX_TCP_SOCKET *socket_ptr)) +{ + +#ifndef NX_DISABLE_EXTENDED_NOTIFY_SUPPORT +TX_INTERRUPT_SAVE_AREA + + + /* Disable interrupts. */ + TX_DISABLE + + /* Setup the establish notify function pointer. */ + socket_ptr -> nx_tcp_establish_notify = tcp_establish_notify; + + /* Restore interrupts. */ + TX_RESTORE + + /* Return successful completion. */ + return(NX_SUCCESS); +#else /* NX_DISABLE_EXTENDED_NOTIFY_SUPPORT */ + NX_PARAMETER_NOT_USED(socket_ptr); + NX_PARAMETER_NOT_USED(tcp_establish_notify); + + return(NX_NOT_SUPPORTED); +#endif /* NX_DISABLE_EXTENDED_NOTIFY_SUPPORT */ +} + diff --git a/common/src/nx_tcp_socket_info_get.c b/common/src/nx_tcp_socket_info_get.c new file mode 100644 index 0000000..56d3d0b --- /dev/null +++ b/common/src/nx_tcp_socket_info_get.c @@ -0,0 +1,223 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_tcp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcp_socket_info_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves TCP information for the specified TCP */ +/* socket. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to the TCP socket */ +/* tcp_packets_sent Destination for number of */ +/* packets sent */ +/* tcp_bytes_sent Destination for number of */ +/* bytes sent */ +/* tcp_packets_received Destination for number of */ +/* packets received */ +/* tcp_bytes_received Destination for number of */ +/* bytes received */ +/* tcp_retransmit_packets Destination for number of */ +/* retransmit packets */ +/* tcp_packets_queued Destination for number of */ +/* receive packets queued */ +/* tcp_checksum_errors Destination for number of */ +/* checksum errors */ +/* tcp_socket_state Destination for the current */ +/* socket state */ +/* tcp_transmit_queue_depth Destination for number of */ +/* sockets still in transmit */ +/* queue */ +/* tcp_transmit_window Destination for number of */ +/* bytes in transmit window */ +/* tcp_receive_window Destination for number of */ +/* bytes in receive window */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Obtain protection */ +/* tx_mutex_put Release protection */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_tcp_socket_info_get(NX_TCP_SOCKET *socket_ptr, ULONG *tcp_packets_sent, ULONG *tcp_bytes_sent, + ULONG *tcp_packets_received, ULONG *tcp_bytes_received, + ULONG *tcp_retransmit_packets, ULONG *tcp_packets_queued, + ULONG *tcp_checksum_errors, ULONG *tcp_socket_state, + ULONG *tcp_transmit_queue_depth, ULONG *tcp_transmit_window, + ULONG *tcp_receive_window) +{ + +NX_IP *ip_ptr; + + + /* Setup IP pointer. */ + ip_ptr = socket_ptr -> nx_tcp_socket_ip_ptr; + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_TCP_SOCKET_INFO_GET, ip_ptr, socket_ptr, socket_ptr -> nx_tcp_socket_packets_sent, socket_ptr -> nx_tcp_socket_bytes_received, NX_TRACE_TCP_EVENTS, 0, 0) + + /* Obtain the IP mutex so we can examine the bound port. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Determine if packets sent is wanted. */ + if (tcp_packets_sent) + { + + /* Return the number of packets sent by this socket. */ + *tcp_packets_sent = socket_ptr -> nx_tcp_socket_packets_sent; + } + + /* Determine if bytes sent is wanted. */ + if (tcp_bytes_sent) + { + + /* Return the number of bytes sent by this socket. */ + *tcp_bytes_sent = socket_ptr -> nx_tcp_socket_bytes_sent; + } + + /* Determine if packets received is wanted. */ + if (tcp_packets_received) + { + + /* Return the number of packets received by this socket. */ + *tcp_packets_received = socket_ptr -> nx_tcp_socket_packets_received; + } + + /* Determine if bytes received is wanted. */ + if (tcp_bytes_received) + { + + /* Return the number of bytes received by this socket. */ + *tcp_bytes_received = socket_ptr -> nx_tcp_socket_bytes_received; + } + + /* Determine if retransmit packets is wanted. */ + if (tcp_retransmit_packets) + { + + /* Return the number of retransmit packets by this socket. */ + *tcp_retransmit_packets = socket_ptr -> nx_tcp_socket_retransmit_packets; + } + + /* Determine if packets queued is wanted. */ + if (tcp_packets_queued) + { + + /* Return the number of packets queued by this socket. */ + *tcp_packets_queued = socket_ptr -> nx_tcp_socket_receive_queue_count; + } + + /* Determine if checksum errors is wanted. */ + if (tcp_checksum_errors) + { + + /* Return the number of checksum errors by this socket. */ + *tcp_checksum_errors = socket_ptr -> nx_tcp_socket_checksum_errors; + } + + /* Determine if socket state is wanted. */ + if (tcp_socket_state) + { + + /* Return the state this socket. */ + *tcp_socket_state = socket_ptr -> nx_tcp_socket_state; + } + + /* Determine if transmit queue depth is wanted. */ + if (tcp_transmit_queue_depth) + { + + /* Return the transmit queue depth of this socket. */ + *tcp_transmit_queue_depth = socket_ptr -> nx_tcp_socket_transmit_sent_count; + } + + /* Determine if transmit window size is wanted. */ + if (tcp_transmit_window) + { + + /* Return the transmit window size of this socket. */ + if (socket_ptr -> nx_tcp_socket_tx_window_advertised > socket_ptr -> nx_tcp_socket_tx_window_congestion) + { + *tcp_transmit_window = socket_ptr -> nx_tcp_socket_tx_window_congestion; + } + else + { + *tcp_transmit_window = socket_ptr -> nx_tcp_socket_tx_window_advertised; + } + if (*tcp_transmit_window > socket_ptr -> nx_tcp_socket_tx_outstanding_bytes) + { + *tcp_transmit_window = *tcp_transmit_window - socket_ptr -> nx_tcp_socket_tx_outstanding_bytes; + } + else + { + *tcp_transmit_window = 0; + } + } + + /* Determine if receive window size is wanted. */ + if (tcp_receive_window) + { + + /* Return the receive window size of this socket. */ + *tcp_receive_window = socket_ptr -> nx_tcp_socket_rx_window_current; + } + + /* Release protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return successful completion status. */ + return(NX_SUCCESS); +} + diff --git a/common/src/nx_tcp_socket_mss_get.c b/common/src/nx_tcp_socket_mss_get.c new file mode 100644 index 0000000..1ebb217 --- /dev/null +++ b/common/src/nx_tcp_socket_mss_get.c @@ -0,0 +1,117 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_tcp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcp_socket_mss_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves TCP Maximum Segment Size (MSS) for the */ +/* specified TCP socket. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to the TCP socket */ +/* mss Destination for the MSS */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Obtain protection */ +/* tx_mutex_put Release protection */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_tcp_socket_mss_get(NX_TCP_SOCKET *socket_ptr, ULONG *mss) +{ + +NX_IP *ip_ptr; + + + /* Setup IP pointer. */ + ip_ptr = socket_ptr -> nx_tcp_socket_ip_ptr; + + /* Obtain the IP mutex so we can examine the bound port. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + if (socket_ptr -> nx_tcp_socket_state < NX_TCP_ESTABLISHED) + { + + /* The socket is not connected. */ + if (socket_ptr -> nx_tcp_socket_mss) + { + + /* Return custom MSS. */ + *mss = socket_ptr -> nx_tcp_socket_mss; + } + else + { + + /* Return default MSS. */ + *mss = NX_TCP_MSS_SIZE; + } + } + else + { + + /* Pickup SMSS value. */ + *mss = socket_ptr -> nx_tcp_socket_connect_mss; + } + + /* Release protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_TCP_SOCKET_MSS_GET, ip_ptr, socket_ptr, socket_ptr -> nx_tcp_socket_mss, socket_ptr -> nx_tcp_socket_state, NX_TRACE_TCP_EVENTS, 0, 0) + + /* Return successful completion status. */ + return(NX_SUCCESS); +} + diff --git a/common/src/nx_tcp_socket_mss_peer_get.c b/common/src/nx_tcp_socket_mss_peer_get.c new file mode 100644 index 0000000..747b4c4 --- /dev/null +++ b/common/src/nx_tcp_socket_mss_peer_get.c @@ -0,0 +1,96 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_tcp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcp_socket_mss_peer_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves TCP Maximum Segment Size (MSS) of the */ +/* peer connected to the specified TCP socket. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to the TCP socket */ +/* peer_mss Destination for the MSS */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Obtain protection */ +/* tx_mutex_put Release protection */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_tcp_socket_mss_peer_get(NX_TCP_SOCKET *socket_ptr, ULONG *peer_mss) +{ + +NX_IP *ip_ptr; + + + /* Setup IP pointer. */ + ip_ptr = socket_ptr -> nx_tcp_socket_ip_ptr; + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_TCP_SOCKET_MSS_PEER_GET, ip_ptr, socket_ptr, socket_ptr -> nx_tcp_socket_peer_mss, socket_ptr -> nx_tcp_socket_state, NX_TRACE_TCP_EVENTS, 0, 0) + + /* Obtain the IP mutex so we can examine the bound port. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Pickup socket's peer MSS value. */ + *peer_mss = socket_ptr -> nx_tcp_socket_peer_mss; + + /* Release protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return successful completion status. */ + return(NX_SUCCESS); +} + diff --git a/common/src/nx_tcp_socket_mss_set.c b/common/src/nx_tcp_socket_mss_set.c new file mode 100644 index 0000000..32bae79 --- /dev/null +++ b/common/src/nx_tcp_socket_mss_set.c @@ -0,0 +1,115 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_tcp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcp_socket_mss_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets the TCP Maximum Segment Size (MSS) for the */ +/* specified TCP socket. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to the TCP socket */ +/* mss New value for the MSS */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Obtain protection */ +/* tx_mutex_put Release protection */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_tcp_socket_mss_set(NX_TCP_SOCKET *socket_ptr, ULONG mss) +{ + +NX_IP *ip_ptr; +UINT status; + + /* Setup IP pointer. */ + ip_ptr = socket_ptr -> nx_tcp_socket_ip_ptr; + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_TCP_SOCKET_MSS_SET, ip_ptr, socket_ptr, mss, socket_ptr -> nx_tcp_socket_state, NX_TRACE_TCP_EVENTS, 0, 0) + + if (mss == 0) + { + + /* Invalid MSS, return an error. */ + return(NX_SIZE_ERROR); + } + + /* Obtain the IP mutex so we can examine the bound port. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + if (socket_ptr -> nx_tcp_socket_state < NX_TCP_SYN_SENT) + { + + /* Set the socket's MSS value. */ + socket_ptr -> nx_tcp_socket_mss = mss; + status = NX_SUCCESS; + } + else + { + + /* MSS can not be modified when connection is started. */ + status = NX_NOT_SUCCESSFUL; + } + + /* Release protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return successful completion status. */ + return(status); +} + diff --git a/common/src/nx_tcp_socket_packet_process.c b/common/src/nx_tcp_socket_packet_process.c new file mode 100644 index 0000000..967f9fe --- /dev/null +++ b/common/src/nx_tcp_socket_packet_process.c @@ -0,0 +1,427 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_tcp.h" +#include "nx_packet.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcp_socket_packet_process PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes an incoming TCP packet relative to the */ +/* socket it belongs to, including processing state changes, and */ +/* sending and receiving data. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to owning socket */ +/* packet_ptr Pointer to packet to process */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_packet_release Packet release function */ +/* _nx_tcp_socket_connection_reset Reset connection */ +/* _nx_tcp_socket_state_ack_check Process received ACKs */ +/* _nx_tcp_socket_state_closing Process CLOSING state */ +/* _nx_tcp_socket_state_data_check Process received data */ +/* _nx_tcp_socket_state_established Process ESTABLISHED state */ +/* _nx_tcp_socket_state_fin_wait1 Process FIN WAIT 1 state */ +/* _nx_tcp_socket_state_fin_wait2 Process FIN WAIT 2 state */ +/* _nx_tcp_socket_state_last_ack Process LAST ACK state */ +/* _nx_tcp_socket_state_syn_received Process SYN RECEIVED state */ +/* _nx_tcp_socket_state_syn_sent Process SYN SENT state */ +/* _nx_tcp_socket_state_transmit_check Check for transmit ability */ +/* (nx_tcp_urgent_data_callback) Application urgent callback */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_tcp_packet_process Process raw TCP packet */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_tcp_socket_packet_process(NX_TCP_SOCKET *socket_ptr, NX_PACKET *packet_ptr) +{ + +UINT packet_queued = NX_FALSE; +NX_TCP_HEADER tcp_header_copy; +VOID (*urgent_callback)(NX_TCP_SOCKET *socket_ptr); +ULONG header_length; +ULONG packet_data_length; +ULONG packet_sequence; +ULONG rx_sequence; +ULONG rx_window; +UINT outside_of_window; +ULONG mss = 0; + + /* Copy the TCP header, since the actual packet can be delivered to + a waiting socket/thread during this routine and before we are done + using the header. */ + tcp_header_copy = *((NX_TCP_HEADER *)packet_ptr -> nx_packet_prepend_ptr); + + /* Get the size of the TCP header. */ + header_length = (tcp_header_copy.nx_tcp_header_word_3 >> NX_TCP_HEADER_SHIFT) * sizeof(ULONG); + + /* Detect whether or not the data is outside the window. */ + if ((socket_ptr -> nx_tcp_socket_state >= NX_TCP_SYN_RECEIVED) || + (tcp_header_copy.nx_tcp_header_word_3 & NX_TCP_RST_BIT)) + { + + /* Pickup the sequence of this packet. */ + packet_sequence = tcp_header_copy.nx_tcp_sequence_number; + + /* Calculate the data length in the packet. */ + packet_data_length = packet_ptr -> nx_packet_length - header_length; + + /* Pickup the rx sequence. */ + rx_sequence = socket_ptr -> nx_tcp_socket_rx_sequence; + + /* Pickup the rx window. */ + rx_window = socket_ptr -> nx_tcp_socket_rx_window_current; + + /* There are four cases for the acceptability test for an incoming segment. + Section 3.9 Page 69, RFC 793. */ + outside_of_window = NX_TRUE; + + if (packet_data_length == 0) + { + if (((rx_window == 0) && + (packet_sequence == rx_sequence)) || + ((rx_window > 0) && + ((int)packet_sequence - (int)rx_sequence >= 0) && + ((int)rx_sequence + (int)rx_window - (int)packet_sequence > 0))) + { + outside_of_window = NX_FALSE; + } + } + else + { + if ((rx_window > 0) && + ((((int)packet_sequence - (int)rx_sequence >= 0) && + ((int)rx_sequence + (int)rx_window - (int)packet_sequence > 0)) || + (((int)packet_sequence + (int)packet_data_length - 1 - (int)rx_sequence >= 0) && + ((int)rx_sequence + (int)rx_window - (int)packet_sequence - (int)packet_data_length + 1 > 0)))) + { + outside_of_window = NX_FALSE; + } + } + + + /* Check whether or not a RST (reset) control message is acceptable. */ + if (tcp_header_copy.nx_tcp_header_word_3 & NX_TCP_RST_BIT) + { + + /* The state is SYN-SENT, Check for an ACK bit is set,According to RFC 793, Section 3.9, Page 67. */ + if ((socket_ptr -> nx_tcp_socket_state == NX_TCP_SYN_SENT) && + (!(tcp_header_copy.nx_tcp_header_word_3 & NX_TCP_ACK_BIT))) + { + + /* Release the packet. */ + _nx_packet_release(packet_ptr); + + /* Finished processing, simply return! */ + return; + } + + /*Check whether or not a RST is acceptable, according to RFC 793, Section 3.4, Page 37. */ + if ((outside_of_window && (socket_ptr -> nx_tcp_socket_state != NX_TCP_SYN_SENT)) || + ((tcp_header_copy.nx_tcp_acknowledgment_number != socket_ptr -> nx_tcp_socket_tx_sequence) && + (socket_ptr -> nx_tcp_socket_state == NX_TCP_SYN_SENT))) + { + + /* This RST packet is unacceptable. Ignore the RST and release the packet. */ + _nx_packet_release(packet_ptr); + + /* Finished processing, simply return! */ + return; + } + +#ifndef NX_DISABLE_TCP_INFO + + /* Increment the resets received count. */ + (socket_ptr -> nx_tcp_socket_ip_ptr) -> nx_ip_tcp_resets_received++; +#endif + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_TCP_RESET_RECEIVE, socket_ptr -> nx_tcp_socket_ip_ptr, socket_ptr, packet_ptr, tcp_header_copy.nx_tcp_sequence_number, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + /* Reset connection. */ + _nx_tcp_socket_connection_reset(socket_ptr); + + /* Release the packet. */ + _nx_packet_release(packet_ptr); + + /* Finished processing, simply return! */ + return; + } + else if (outside_of_window) + { + + /* If an incoming segment is not acceptable, an acknowledgment + should be sent in reply. + Section 3.9, Page 69, RFC 793. */ +#ifndef NX_DISABLE_TCP_INFO + + /* Increment the TCP dropped packet count. */ + socket_ptr -> nx_tcp_socket_ip_ptr -> nx_ip_tcp_receive_packets_dropped++; +#endif + + /* Release the packet. */ + _nx_packet_release(packet_ptr); + + /* Send an immediate ACK. */ + _nx_tcp_packet_send_ack(socket_ptr, socket_ptr -> nx_tcp_socket_tx_sequence); + + /* Finished processing, simply return! */ + return; + } + } + + /* Illegal option length check. */ + if (header_length > sizeof(NX_TCP_HEADER)) + { + if (!_nx_tcp_mss_option_get((packet_ptr -> nx_packet_prepend_ptr + sizeof(NX_TCP_HEADER)), + header_length - sizeof(NX_TCP_HEADER), &mss)) + { + + /* Send RST message. + TCP MUST be prepared to handle an illegal option length (e.g., zero) without crashing; + a suggested procedure is to reset the connection and log the reason, outlined in RFC 1122, Section 4.2.2.5, Page85. */ + _nx_tcp_packet_send_rst(socket_ptr, &tcp_header_copy); + + /* Reset connection. */ + _nx_tcp_socket_connection_reset(socket_ptr); + + /* Release the packet. */ + _nx_packet_release(packet_ptr); + +#ifndef NX_DISABLE_TCP_INFO + + /* Increment the TCP dropped packet count. */ + socket_ptr -> nx_tcp_socket_ip_ptr -> nx_ip_tcp_receive_packets_dropped++; +#endif + + return; + } + } + + /* Process relative to the state of the socket. */ + switch (socket_ptr -> nx_tcp_socket_state) + { + + case NX_TCP_SYN_SENT: + { + + /* Call the SYN SENT state handling function to process any state + changes caused by this new packet. */ + _nx_tcp_socket_state_syn_sent(socket_ptr, &tcp_header_copy); + + /* Check whether socket is established. */ + if (socket_ptr -> nx_tcp_socket_state == NX_TCP_ESTABLISHED) + { + + /* Check for data in the current packet. */ + packet_queued = _nx_tcp_socket_state_data_check(socket_ptr, packet_ptr); + } + + /* State processing is complete. */ + break; + } + + case NX_TCP_SYN_RECEIVED: + { + + + /* Call the SYN RECEIVED state handling function to process any state + changes caused by this new packet. */ + _nx_tcp_socket_state_syn_received(socket_ptr, &tcp_header_copy); + + /* Check whether socket is established. */ + if (socket_ptr -> nx_tcp_socket_state == NX_TCP_ESTABLISHED) + { + + /* Check for data in the current packet. */ + packet_queued = _nx_tcp_socket_state_data_check(socket_ptr, packet_ptr); + } + + /* State processing is complete. */ + break; + } + + case NX_TCP_ESTABLISHED: + { + + /* Check and process an ACK specified in the current packet. */ + _nx_tcp_socket_state_ack_check(socket_ptr, &tcp_header_copy); + + /* Check for data in the current packet. */ + packet_queued = _nx_tcp_socket_state_data_check(socket_ptr, packet_ptr); + + /* Call the ESTABLISHED state state handling function to process any state + changes caused by this new packet. */ + _nx_tcp_socket_state_established(socket_ptr, &tcp_header_copy); + + /* Determine if any transmit suspension can be lifted. */ + _nx_tcp_socket_state_transmit_check(socket_ptr); + + /* State processing is complete. */ + break; + } + + case NX_TCP_CLOSE_WAIT: + { + + /* Not much needs to be done in this state since the application is + responsible for moving to the next state, which is LAST ACK. In the + meantime, this side of the connection is still allowed to transmit + so we need to check for ACK and threads suspended for transmit. */ + + /* Check and process an ACK specified in the current packet. */ + _nx_tcp_socket_state_ack_check(socket_ptr, &tcp_header_copy); + + /* Check for data in the current packet. */ + packet_queued = _nx_tcp_socket_state_data_check(socket_ptr, packet_ptr); + + /* Determine if any transmit suspension can be lifted. */ + _nx_tcp_socket_state_transmit_check(socket_ptr); + + /* State processing is complete. */ + break; + } + + case NX_TCP_LAST_ACK: + { + + + /* Check and process an ACK specified in the current packet. */ + _nx_tcp_socket_state_ack_check(socket_ptr, &tcp_header_copy); + + /* Call the LAST ACK state state handling function to process any state + changes caused by this new packet. */ + _nx_tcp_socket_state_last_ack(socket_ptr, &tcp_header_copy); + + /* State processing is complete. */ + break; + } + + case NX_TCP_FIN_WAIT_1: + { + + /* Check and process an ACK specified in the current packet. */ + _nx_tcp_socket_state_ack_check(socket_ptr, &tcp_header_copy); + + /* Check for data in the current packet. */ + packet_queued = _nx_tcp_socket_state_data_check(socket_ptr, packet_ptr); + + /* Call the FIN WAIT 1 state state handling function to process any state + changes caused by this new packet. */ + _nx_tcp_socket_state_fin_wait1(socket_ptr, &tcp_header_copy); + + /* State processing is complete. */ + break; + } + + case NX_TCP_FIN_WAIT_2: + { + + + /* Check and process an ACK specified in the current packet. */ + _nx_tcp_socket_state_ack_check(socket_ptr, &tcp_header_copy); + + /* Check for data in the current packet. */ + packet_queued = _nx_tcp_socket_state_data_check(socket_ptr, packet_ptr); + + /* Call the FIN WAIT 2 state state handling function to process any state + changes caused by this new packet. */ + _nx_tcp_socket_state_fin_wait2(socket_ptr, &tcp_header_copy); + + /* State processing is complete. */ + break; + } + + case NX_TCP_CLOSING: + { + + /* Call the CLOSING state state handling function to process any state + changes caused by this new packet. */ + _nx_tcp_socket_state_closing(socket_ptr, &tcp_header_copy); + + /* State processing is complete. */ + break; + } + + default: + break; + } + + /* Check for an URG (urgent) bit set. */ + if (tcp_header_copy.nx_tcp_header_word_3 & NX_TCP_URG_BIT) + { + + /* Yes, an Urgent bit is set. */ + + /* Pickup the urgent callback function specified when the socket was created. */ + urgent_callback = socket_ptr -> nx_tcp_urgent_data_callback; + + /* Determine if there is an urgent callback function specified. */ + if (urgent_callback) + { + + /* Yes, call the application's urgent callback function to alert the application + of the presence of the urgent bit. */ + (urgent_callback)(socket_ptr); + } + } + + /* Determine if we need to release the packet. */ + if (!packet_queued) + { + + /* Yes, the packet was not queued up above, so it needs to be released. */ + _nx_packet_release(packet_ptr); + } +} + diff --git a/common/src/nx_tcp_socket_peer_info_get.c b/common/src/nx_tcp_socket_peer_info_get.c new file mode 100644 index 0000000..287d1b5 --- /dev/null +++ b/common/src/nx_tcp_socket_peer_info_get.c @@ -0,0 +1,125 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifndef NX_SOURCE_CODE +#define NX_SOURCE_CODE +#endif + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_tcp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcp_socket_peer_info_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves IP address and port number of the peer */ +/* connected to the specified TCP socket. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to the TCP sockete */ +/* peer_ip_address Pointer to the IP address */ +/* of the peer. */ +/* peer_port Pointer to the port number */ +/* of the peer. */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Obtain protection */ +/* tx_mutex_put Release protection */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_tcp_socket_peer_info_get(NX_TCP_SOCKET *socket_ptr, + ULONG *peer_ip_address, + ULONG *peer_port) +{ +NX_IP *ip_ptr; + + /* Setup IP pointer. */ + ip_ptr = socket_ptr -> nx_tcp_socket_ip_ptr; + + /* Obtain the IP mutex so we can examine the bound port. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + + /* Make sure the TCP connection has been established. */ + if ((socket_ptr -> nx_tcp_socket_state <= NX_TCP_LISTEN_STATE) || + (socket_ptr -> nx_tcp_socket_state > NX_TCP_ESTABLISHED)) + { + /* Release protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + return(NX_NOT_CONNECTED); + } + + /* Determine the peer IP address */ + if (peer_ip_address) + { + /* Return the IP address of the peer connected to the TCP socket. */ + *peer_ip_address = socket_ptr -> nx_tcp_socket_connect_ip; + } + + + /* Determine the peer port number */ + if (peer_port) + { + /* Return the port number of the peer connected to the TCP socket. */ + *peer_port = socket_ptr -> nx_tcp_socket_connect_port; + } + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_TCP_SOCKET_PEER_INFO_GET, socket_ptr, *peer_ip_address, *peer_port, 0, NX_TRACE_TCP_EVENTS, 0, 0) + + + /* Release protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return successful completion status. */ + return(NX_SUCCESS); +} + diff --git a/common/src/nx_tcp_socket_receive.c b/common/src/nx_tcp_socket_receive.c new file mode 100644 index 0000000..1cd0c41 --- /dev/null +++ b/common/src/nx_tcp_socket_receive.c @@ -0,0 +1,272 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_packet.h" +#include "nx_tcp.h" +#include "tx_thread.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcp_socket_receive PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function attempts to receive one or more TCP packets from the */ +/* specified socket. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to socket */ +/* packet_ptr Pointer to packet pointer */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_tcp_packet_send_ack Send ACK message */ +/* _nx_tcp_socket_thread_suspend Suspend calling thread */ +/* tx_mutex_get Get protection mutex */ +/* tx_mutex_put Put protection mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_tcp_socket_receive(NX_TCP_SOCKET *socket_ptr, NX_PACKET **packet_ptr, ULONG wait_option) +{ + +NX_IP *ip_ptr; +NX_TCP_HEADER *header_ptr; +NX_PACKET *head_packet_ptr; +ULONG header_length; + +#ifdef TX_ENABLE_EVENT_TRACE +TX_TRACE_BUFFER_ENTRY *trace_event; +ULONG trace_timestamp; +#endif + + + /* Setup the pointer to the associated IP instance. */ + ip_ptr = socket_ptr -> nx_tcp_socket_ip_ptr; + + /* Set the return pointer to NULL initially. */ + *packet_ptr = NX_NULL; + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_TCP_SOCKET_RECEIVE, socket_ptr, 0, 0, 0, NX_TRACE_TCP_EVENTS, &trace_event, &trace_timestamp) + + /* Get protection while we look at this socket. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Determine if the socket is currently bound. */ + if (!socket_ptr -> nx_tcp_socket_bound_next) + { + + /* Release protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Socket is not bound, return an error message. */ + return(NX_NOT_BOUND); + } + + /* Do not return without data if there is data on the queue. */ + if (!socket_ptr -> nx_tcp_socket_receive_queue_head) + { + /* There is no data on the queue. */ + + /* Determine if the socket is still in an active state (will allow a receive + socket operation if there are still more queued receive + packets for this socket. */ + + if ((socket_ptr -> nx_tcp_socket_state <= NX_TCP_SYN_SENT) || + (socket_ptr -> nx_tcp_socket_state == NX_TCP_CLOSE_WAIT) || + (socket_ptr -> nx_tcp_socket_state >= NX_TCP_CLOSING)) + { + + /* No the packet cannot receive more data. */ + + /* Release the IP protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return an error code. */ + return(NX_NOT_CONNECTED); + } + } + + /* Pickup the important information from the socket. */ + + /* Attempt to build a pointer to the first packet in the socket's + receive queue. */ + if (socket_ptr -> nx_tcp_socket_receive_queue_head) + { + + /* Yes, there is a packet on the receive queue. Setup a pointer to it and + its header. */ + head_packet_ptr = socket_ptr -> nx_tcp_socket_receive_queue_head; + header_ptr = (NX_TCP_HEADER *)head_packet_ptr -> nx_packet_prepend_ptr; + } + else + { + + /* Just set the pointers to NULL. */ + head_packet_ptr = NX_NULL; + header_ptr = NX_NULL; + } + + /* Determine if there is a receive packet available. */ + if ((head_packet_ptr) && (head_packet_ptr -> nx_packet_queue_next == ((NX_PACKET *)NX_PACKET_READY))) + { + + + /* Yes, the first packet in the queue is available and has been ACKed. Remove it + from the queue and return it to the caller. */ + if (head_packet_ptr == socket_ptr -> nx_tcp_socket_receive_queue_tail) + { + + /* Only item in the queue. Set the head and tail pointers to NULL. */ + socket_ptr -> nx_tcp_socket_receive_queue_head = NX_NULL; + socket_ptr -> nx_tcp_socket_receive_queue_tail = NX_NULL; + } + else + { + + /* Simply update the head pointer to the packet after the current. The tail pointer does not + need update. */ + socket_ptr -> nx_tcp_socket_receive_queue_head = head_packet_ptr -> nx_packet_tcp_queue_next; + } + + /* Decrease the number of received packets. */ + socket_ptr -> nx_tcp_socket_receive_queue_count--; + + /* Calculate the header size for this packet. */ + header_length = (header_ptr -> nx_tcp_header_word_3 >> NX_TCP_HEADER_SHIFT) * sizeof(ULONG); + + /* Adjust the packet prepend pointer and length to position past the TCP header. */ + head_packet_ptr -> nx_packet_prepend_ptr = head_packet_ptr -> nx_packet_prepend_ptr + header_length; + head_packet_ptr -> nx_packet_length = head_packet_ptr -> nx_packet_length - header_length; + + /* Indicate that this TCP packet is no longer enqueued by marking it again as allocated. This is what + it was prior to being part of the TCP receive queue. */ + head_packet_ptr -> nx_packet_tcp_queue_next = (NX_PACKET *)NX_PACKET_ALLOCATED; + + /* Clear the queue next pointer. */ + head_packet_ptr -> nx_packet_queue_next = NX_NULL; + + /* Place the packet pointer in the return pointer. */ + *packet_ptr = head_packet_ptr; + + /* Increase the receive window size. */ + socket_ptr -> nx_tcp_socket_rx_window_current += (*packet_ptr) -> nx_packet_length; + + /* Determine if the new size is greater than the default window size. */ + if (socket_ptr -> nx_tcp_socket_rx_window_current > socket_ptr -> nx_tcp_socket_rx_window_default) + { + + /* Yes, new receive window size is greater than the socket's default, + adjust to the default window size. */ + socket_ptr -> nx_tcp_socket_rx_window_current = socket_ptr -> nx_tcp_socket_rx_window_default; + } + + /* Determine if an ACK should be forced out for window update, SWS avoidance algorithm. + RFC1122, Section4.2.3.3, Page97-98. */ + if (((socket_ptr -> nx_tcp_socket_rx_window_current - socket_ptr -> nx_tcp_socket_rx_window_last_sent) >= (socket_ptr -> nx_tcp_socket_rx_window_default / 2)) && + ((socket_ptr -> nx_tcp_socket_state == NX_TCP_ESTABLISHED) || (socket_ptr -> nx_tcp_socket_state == NX_TCP_FIN_WAIT_1) || (socket_ptr -> nx_tcp_socket_state == NX_TCP_FIN_WAIT_2))) + { + + /* Send a Window Update. */ + _nx_tcp_packet_send_ack(socket_ptr, socket_ptr -> nx_tcp_socket_tx_sequence); + } + + /* Update the trace event with the status. */ + NX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, NX_TRACE_TCP_SOCKET_RECEIVE, 0, *packet_ptr, (*packet_ptr) -> nx_packet_length, socket_ptr -> nx_tcp_socket_rx_sequence) + + /* Release protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return a successful status. */ + return(NX_SUCCESS); + } + else if ((wait_option) && (_tx_thread_current_ptr != &(ip_ptr -> nx_ip_thread))) + { + + /* Suspend the thread on this socket's receive queue. */ + + /* Save the return packet pointer address as well. */ + _tx_thread_current_ptr -> tx_thread_additional_suspend_info = (void *)packet_ptr; + + /* Increment the suspended thread count. */ + socket_ptr -> nx_tcp_socket_receive_suspended_count++; + + /* Suspend the thread on the receive queue. */ + _nx_tcp_socket_thread_suspend(&(socket_ptr -> nx_tcp_socket_receive_suspension_list), _nx_tcp_receive_cleanup, socket_ptr, &(ip_ptr -> nx_ip_protection), wait_option); + +#ifdef TX_ENABLE_EVENT_TRACE + + /* Update the trace event with the status. */ + if (*packet_ptr) + { + NX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, NX_TRACE_TCP_SOCKET_RECEIVE, 0, *packet_ptr, (*packet_ptr) -> nx_packet_length, socket_ptr -> nx_tcp_socket_rx_sequence) + } + else + { + NX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, NX_TRACE_TCP_SOCKET_RECEIVE, 0, *packet_ptr, 0, socket_ptr -> nx_tcp_socket_rx_sequence) + } + +#endif /* TX_ENABLE_EVENT_TRACE */ + /* If not, just return the error code. */ + return(_tx_thread_current_ptr -> tx_thread_suspend_status); + } + else + { + + /* Release protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return an empty receive queue error message. */ + return(NX_NO_PACKET); + } +} + diff --git a/common/src/nx_tcp_socket_receive_notify.c b/common/src/nx_tcp_socket_receive_notify.c new file mode 100644 index 0000000..422c34a --- /dev/null +++ b/common/src/nx_tcp_socket_receive_notify.c @@ -0,0 +1,96 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_tcp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcp_socket_receive_notify PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets the receive notify function pointer to the */ +/* function specified by the application, which is called whenever */ +/* one or more receive packets is available for the socket. If a */ +/* NULL pointer is supplied, the receive notify function is disabled. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to TCP socket */ +/* tcp_receive_notify Routine to call when one or */ +/* receive packets are */ +/* available for the socket */ +/* */ +/* 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_tcp_socket_receive_notify(NX_TCP_SOCKET *socket_ptr, + VOID (*tcp_receive_notify)(NX_TCP_SOCKET *socket_ptr)) +{ +TX_INTERRUPT_SAVE_AREA + + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_TCP_SOCKET_RECEIVE_NOTIFY, socket_ptr -> nx_tcp_socket_ip_ptr, socket_ptr, tcp_receive_notify, 0, NX_TRACE_TCP_EVENTS, 0, 0) + + /* Disable interrupts. */ + TX_DISABLE + + /* Setup the receive notify function pointer. */ + socket_ptr -> nx_tcp_receive_callback = tcp_receive_notify; + + /* Restore interrupts. */ + TX_RESTORE + + /* Return successful completion. */ + return(NX_SUCCESS); +} + diff --git a/common/src/nx_tcp_socket_receive_queue_flush.c b/common/src/nx_tcp_socket_receive_queue_flush.c new file mode 100644 index 0000000..69dd9d9 --- /dev/null +++ b/common/src/nx_tcp_socket_receive_queue_flush.c @@ -0,0 +1,111 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_packet.h" +#include "nx_tcp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcp_socket_receive_queue_flush PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function releases all packets in the specified socket's */ +/* receive queue. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to socket */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_packet_release Release a packet */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_tcp_client_socket_unbind Client socket unbind */ +/* processing */ +/* _nx_tcp_socket_connection_reset Socket connection reset */ +/* processing */ +/* _nx_tcp_server_socket_unaccept Server socket unaccept */ +/* processing */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_tcp_socket_receive_queue_flush(NX_TCP_SOCKET *socket_ptr) +{ + +NX_PACKET *packet_ptr; +NX_PACKET *next_packet_ptr; + + + /* Setup packet pointer. */ + packet_ptr = socket_ptr -> nx_tcp_socket_receive_queue_head; + + /* Clear the head and the tail pointers. */ + socket_ptr -> nx_tcp_socket_receive_queue_head = NX_NULL; + socket_ptr -> nx_tcp_socket_receive_queue_tail = NX_NULL; + + /* Loop to clear all the packets out. */ + while (socket_ptr -> nx_tcp_socket_receive_queue_count) + { + + /* Pickup the next queued packet. */ + next_packet_ptr = packet_ptr -> nx_packet_tcp_queue_next; + + /* Mark it as allocated so it will be released. */ + packet_ptr -> nx_packet_tcp_queue_next = (NX_PACKET *)NX_PACKET_ALLOCATED; + + /* Release the packet. */ + _nx_packet_release(packet_ptr); + + /* Move to the next packet. */ + packet_ptr = next_packet_ptr; + + /* Decrease the queued packet count. */ + socket_ptr -> nx_tcp_socket_receive_queue_count--; + } +} + diff --git a/common/src/nx_tcp_socket_retransmit.c b/common/src/nx_tcp_socket_retransmit.c new file mode 100644 index 0000000..0c56cb0 --- /dev/null +++ b/common/src/nx_tcp_socket_retransmit.c @@ -0,0 +1,210 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_packet.h" +#include "nx_ip.h" +#include "nx_tcp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcp_socket_retransmit PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retransmit a TCP packet. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP instance pointer */ +/* socket_ptr Pointer to owning socket */ +/* need_fast_retransmit Need fast retransmit or not */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_ip_packet_send Resend the transmit packet */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_tcp_fast_periodic_processing Process TCP packet for socket */ +/* _nx_tcp_socket_state_ack_check Process ACK number */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_tcp_socket_retransmit(NX_IP *ip_ptr, NX_TCP_SOCKET *socket_ptr, UINT need_fast_retransmit) +{ +NX_PACKET *packet_ptr; +NX_PACKET *next_ptr; +ULONG window; +ULONG available; + + /* If the reciever winodw is zero, we enter the zero window probe phase + RFC 793 Sec 3.7, p42: keep send new data. + + In the zero window probe phase, we send the zero window probe, and increase + exponentially the interval between successive probes. + RFC 1122 Sec 4.2.2.17, p92. */ + if (socket_ptr -> nx_tcp_socket_tx_window_advertised == 0) + { + + /* In the zero window probe phase, we send the zero window probe, and increase + * exponentially the interval between successive probes. */ + + /* Increment the retry counter. */ + socket_ptr -> nx_tcp_socket_timeout_retries++; + + /* Setup the next timeout. */ + socket_ptr -> nx_tcp_socket_timeout = socket_ptr -> nx_tcp_socket_timeout_rate << + (socket_ptr -> nx_tcp_socket_timeout_retries * + socket_ptr -> nx_tcp_socket_timeout_shift); + + /* Send the zero window probe. */ + _nx_tcp_packet_send_ack(socket_ptr, socket_ptr -> nx_tcp_socket_tx_sequence); + + return; + } + + /* Increment the retry counter only if the reciever window is open. */ + /* Increment the retry counter. */ + socket_ptr -> nx_tcp_socket_timeout_retries++; + + if ((need_fast_retransmit == NX_TRUE) || (socket_ptr -> nx_tcp_socket_fast_recovery == NX_FALSE)) + { + + /* Timed out on an outgoing packet. Enter slow start mode. */ + /* Compute the flight size / 2 value. */ + window = socket_ptr -> nx_tcp_socket_tx_outstanding_bytes >> 1; + + /* Make sure we have at least 2 * MSS */ + if (window < (socket_ptr -> nx_tcp_socket_connect_mss << 1)) + { + window = socket_ptr -> nx_tcp_socket_connect_mss << 1; + } + + /* Set the slow_start_threshold */ + socket_ptr -> nx_tcp_socket_tx_slow_start_threshold = window; + + /* Set the current window to be MSS size. */ + socket_ptr -> nx_tcp_socket_tx_window_congestion = socket_ptr -> nx_tcp_socket_connect_mss; + + /* Determine if this socket needs fast retransmit. */ + if (need_fast_retransmit == NX_TRUE) + { + + /* Update cwnd to ssthreshold plus 3 * MSS. */ + socket_ptr -> nx_tcp_socket_tx_window_congestion += window + (socket_ptr -> nx_tcp_socket_connect_mss << 2); + + /* Now TCP is in fast recovery procedure. */ + socket_ptr -> nx_tcp_socket_fast_recovery = NX_TRUE; + + /* Update the transmit sequence that enters fast transmit. */ + socket_ptr -> nx_tcp_socket_tx_sequence_recover = socket_ptr -> nx_tcp_socket_tx_sequence - 1; + } + } + + /* Setup the next timeout. */ + socket_ptr -> nx_tcp_socket_timeout = socket_ptr -> nx_tcp_socket_timeout_rate << + (socket_ptr -> nx_tcp_socket_timeout_retries * + socket_ptr -> nx_tcp_socket_timeout_shift); + + /* Get available size of packet that can be sent. */ + available = socket_ptr -> nx_tcp_socket_tx_window_congestion; + + /* Pickup the head of the transmit queue. */ + packet_ptr = socket_ptr -> nx_tcp_socket_transmit_sent_head; + + /* Determine if the packet has been released by the + application I/O driver. */ + while (packet_ptr && (packet_ptr -> nx_packet_queue_next == (NX_PACKET *)NX_DRIVER_TX_DONE)) + { + + if (packet_ptr -> nx_packet_length > (available + sizeof(NX_TCP_HEADER))) + { + /* This packet can not be sent. */ + break; + } + + /* Decrease the available size. */ + available -= (packet_ptr -> nx_packet_length - sizeof(NX_TCP_HEADER)); + + /* Pickup next packet. */ + next_ptr = packet_ptr -> nx_packet_tcp_queue_next; + +#ifndef NX_DISABLE_TCP_INFO + /* Increment the TCP retransmit count. */ + ip_ptr -> nx_ip_tcp_retransmit_packets++; + + /* Increment the TCP retransmit count for the socket. */ + socket_ptr -> nx_tcp_socket_retransmit_packets++; +#endif + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_TCP_RETRY, ip_ptr, socket_ptr, packet_ptr, socket_ptr -> nx_tcp_socket_timeout_retries, NX_TRACE_INTERNAL_EVENTS, 0, 0); + + /* Clear the queue next pointer. */ + packet_ptr -> nx_packet_queue_next = NX_NULL; + + /* Yes, the driver has finished with the packet at the head of the + transmit sent list... so it can be sent again! */ + + /* Yes, the driver has finished with the packet at the head of the + transmit sent list... so it can be sent again! */ + _nx_ip_packet_send(ip_ptr, packet_ptr, socket_ptr -> nx_tcp_socket_connect_ip, + socket_ptr -> nx_tcp_socket_type_of_service, socket_ptr -> nx_tcp_socket_time_to_live, NX_IP_TCP, + socket_ptr -> nx_tcp_socket_fragment_enable); + + /* Move to next packet. */ + /* During fast recovery, only one packet is retransmitted at once. */ + /* After a timeout, the sending data can be at most one SMSS. */ + if ((next_ptr == (NX_PACKET *)NX_PACKET_ENQUEUED) || + (socket_ptr -> nx_tcp_socket_fast_recovery == NX_TRUE)) + { + break; + } + else + { + packet_ptr = next_ptr; + } + } +} + diff --git a/common/src/nx_tcp_socket_send.c b/common/src/nx_tcp_socket_send.c new file mode 100644 index 0000000..532d4cf --- /dev/null +++ b/common/src/nx_tcp_socket_send.c @@ -0,0 +1,631 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_packet.h" +#include "nx_tcp.h" +#include "tx_thread.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcp_socket_send_internal PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sends a TCP packet through the specified socket. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to socket */ +/* packet_ptr Pointer to packet to send */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ip_packet_send Packet send function */ +/* _nx_tcp_checksum Calculate TCP checksum */ +/* _nx_tcp_socket_thread_suspend Suspend calling thread */ +/* tx_mutex_get Get protection mutex */ +/* tx_mutex_put Put protection mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static UINT _nx_tcp_socket_send_internal(NX_TCP_SOCKET *socket_ptr, NX_PACKET *packet_ptr, ULONG wait_option) +{ + +TX_INTERRUPT_SAVE_AREA + +NX_IP *ip_ptr; +NX_TCP_HEADER *header_ptr; +ULONG checksum; +ULONG sequence_number; +ULONG tx_window_current; + + /* Determine if the packet is valid. */ + if (packet_ptr -> nx_packet_tcp_queue_next != (NX_PACKET *)NX_PACKET_ALLOCATED) + { + +#ifndef NX_DISABLE_TCP_INFO + /* Setup the pointer to the associated IP instance. */ + ip_ptr = socket_ptr -> nx_tcp_socket_ip_ptr; + + /* Increment the TCP invalid packet count. */ + ip_ptr -> nx_ip_tcp_invalid_packets++; +#endif + + return(NX_INVALID_PACKET); + } + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_TCP_SOCKET_SEND, socket_ptr, packet_ptr, packet_ptr -> nx_packet_length, socket_ptr -> nx_tcp_socket_tx_sequence, NX_TRACE_TCP_EVENTS, 0, 0) + + /* Lockout interrupts. */ + TX_DISABLE + + /* Determine if the socket is currently bound. */ + if (!socket_ptr -> nx_tcp_socket_bound_next) + { + + /* Restore interrupts. */ + TX_RESTORE + + /* Socket is not bound, return an error message. */ + return(NX_NOT_BOUND); + } + + /* Check for the socket being in an established state. */ + if ((socket_ptr -> nx_tcp_socket_state != NX_TCP_ESTABLISHED) && (socket_ptr -> nx_tcp_socket_state != NX_TCP_CLOSE_WAIT)) + { + + /* Restore interrupts. */ + TX_RESTORE + + /* Socket is not connected, return an error message. */ + return(NX_NOT_CONNECTED); + } + + /* Pickup the important information from the socket. */ + + /* Setup the pointer to the associated IP instance. */ + ip_ptr = socket_ptr -> nx_tcp_socket_ip_ptr; + + /* Restore interrupts. */ + TX_RESTORE + + /* Set the outgoing interface. It should have been set for this socket. */ + packet_ptr -> nx_packet_ip_interface = socket_ptr -> nx_tcp_socket_connect_interface; + packet_ptr -> nx_packet_next_hop_address = socket_ptr -> nx_tcp_socket_next_hop_address; + + /* Prepend the TCP header to the packet. First, make room for the TCP header. */ + packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr - sizeof(NX_TCP_HEADER); + + /* Add the length of the TCP header. */ + packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length + sizeof(NX_TCP_HEADER); + + /* Pickup the pointer to the head of the TCP packet. */ + header_ptr = (NX_TCP_HEADER *)packet_ptr -> nx_packet_prepend_ptr; + + /* Build the output request in the TCP header. */ + header_ptr -> nx_tcp_header_word_0 = (((ULONG)(socket_ptr -> nx_tcp_socket_port)) << NX_SHIFT_BY_16) | (ULONG)socket_ptr -> nx_tcp_socket_connect_port; + header_ptr -> nx_tcp_acknowledgment_number = socket_ptr -> nx_tcp_socket_rx_sequence; +#ifdef NX_ENABLE_TCP_WINDOW_SCALING + header_ptr -> nx_tcp_header_word_3 = NX_TCP_HEADER_SIZE | NX_TCP_ACK_BIT | NX_TCP_PSH_BIT | (socket_ptr -> nx_tcp_socket_rx_window_current >> socket_ptr -> nx_tcp_rcv_win_scale_value); +#else /* !NX_ENABLE_TCP_WINDOW_SCALING */ + header_ptr -> nx_tcp_header_word_3 = NX_TCP_HEADER_SIZE | NX_TCP_ACK_BIT | NX_TCP_PSH_BIT | socket_ptr -> nx_tcp_socket_rx_window_current; +#endif /* !NX_ENABLE_TCP_WINDOW_SCALING */ + header_ptr -> nx_tcp_header_word_4 = 0; + + /* Remember the last ACKed sequence and the last reported window size. */ + socket_ptr -> nx_tcp_socket_rx_sequence_acked = socket_ptr -> nx_tcp_socket_rx_sequence; + socket_ptr -> nx_tcp_socket_rx_window_last_sent = socket_ptr -> nx_tcp_socket_rx_window_current; + + /* Setup a new delayed ACK timeout. */ + socket_ptr -> nx_tcp_socket_delayed_ack_timeout = _nx_tcp_ack_timer_rate; + + /* Endian swapping logic. If NX_LITTLE_ENDIAN is specified, these macros will + swap the endian of the TCP header. */ + NX_CHANGE_ULONG_ENDIAN(header_ptr -> nx_tcp_header_word_0); + NX_CHANGE_ULONG_ENDIAN(header_ptr -> nx_tcp_acknowledgment_number); + NX_CHANGE_ULONG_ENDIAN(header_ptr -> nx_tcp_header_word_3); + NX_CHANGE_ULONG_ENDIAN(header_ptr -> nx_tcp_header_word_4); + + do + { + + /* Pickup the current transmit sequence number. */ + header_ptr -> nx_tcp_sequence_number = socket_ptr -> nx_tcp_socket_tx_sequence; + sequence_number = header_ptr -> nx_tcp_sequence_number; + NX_CHANGE_ULONG_ENDIAN(header_ptr -> nx_tcp_sequence_number); + + /* Calculate the TCP checksum without protection. */ +#ifndef NX_DISABLE_TCP_TX_CHECKSUM + checksum = _nx_tcp_checksum(packet_ptr, packet_ptr -> nx_packet_ip_interface -> nx_interface_ip_address, socket_ptr -> nx_tcp_socket_connect_ip); +#else + checksum = 0; +#endif + /* Place protection while we check the sequence number for the new TCP packet. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Determine if the sequence number is the same. */ + if (sequence_number != socket_ptr -> nx_tcp_socket_tx_sequence) + { + + /* Another transmit on this socket took place and changed the sequence. We need to + recalculate the checksum with a new sequence number. Release protection and + just resume the loop. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + } + else + { + + /* We have a good checksum, proceed with sending the packet. */ + break; + } + } while (NX_FOREVER); + + /* Check for the socket being in an established state. It's possible the connection could have gone + away during the TCP checksum calculation above. */ + if ((socket_ptr -> nx_tcp_socket_state != NX_TCP_ESTABLISHED) && (socket_ptr -> nx_tcp_socket_state != NX_TCP_CLOSE_WAIT)) + { + + /* Release protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Socket is not connected, return an error message. */ + return(NX_NOT_CONNECTED); + } + + /* Disable interrupts. */ + TX_DISABLE + + /* Restore interrupts. */ + TX_RESTORE + + /* Move the checksum into header. */ + NX_CHANGE_ULONG_ENDIAN(header_ptr -> nx_tcp_header_word_4); + header_ptr -> nx_tcp_header_word_4 = (checksum << NX_SHIFT_BY_16); + NX_CHANGE_ULONG_ENDIAN(header_ptr -> nx_tcp_header_word_4); + + /* Pick up the min(cwnd, swnd) */ + if (socket_ptr -> nx_tcp_socket_tx_window_advertised > socket_ptr -> nx_tcp_socket_tx_window_congestion) + { + tx_window_current = socket_ptr -> nx_tcp_socket_tx_window_congestion; + + /* On the first and second duplicate ACKs received, the total FlightSize would + remain less than or equal to cwnd plus 2*SMSS. + Section 3.2, Page 9, RFC5681. */ + + if ((socket_ptr -> nx_tcp_socket_duplicated_ack_received == 1) || + (socket_ptr -> nx_tcp_socket_duplicated_ack_received == 2)) + { + tx_window_current += (socket_ptr -> nx_tcp_socket_connect_mss << 1); + } + } + else + { + tx_window_current = socket_ptr -> nx_tcp_socket_tx_window_advertised; + } + + + /* Substract any data transmitted but unacked (outstanding bytes) */ + if (tx_window_current > socket_ptr -> nx_tcp_socket_tx_outstanding_bytes) + { + tx_window_current -= socket_ptr -> nx_tcp_socket_tx_outstanding_bytes; + } + else /* Set tx_window_current to zero. */ + { + tx_window_current = 0; + } + + /* Now determine if the request is within the advertised window on the other side + of the connection. Also, check for the maximum number of queued transmit packets + being exceeded. */ + if (((packet_ptr -> nx_packet_length - sizeof(NX_TCP_HEADER)) <= tx_window_current) && + (socket_ptr -> nx_tcp_socket_transmit_sent_count < socket_ptr -> nx_tcp_socket_transmit_queue_maximum)) + { + + /* Adjust the transmit sequence number to reflect the output data. */ + socket_ptr -> nx_tcp_socket_tx_sequence = socket_ptr -> nx_tcp_socket_tx_sequence + + (packet_ptr -> nx_packet_length - sizeof(NX_TCP_HEADER)); + + + /* Yes, the packet can be sent. Place the packet on the sent list. */ + if (socket_ptr -> nx_tcp_socket_transmit_sent_head) + { + + /* Yes, other packets are on the list already. Just add this one to the tail. */ + (socket_ptr -> nx_tcp_socket_transmit_sent_tail) -> nx_packet_tcp_queue_next = packet_ptr; + socket_ptr -> nx_tcp_socket_transmit_sent_tail = packet_ptr; + } + else + { + + /* Empty list, just setup the head and tail to the current packet. */ + socket_ptr -> nx_tcp_socket_transmit_sent_head = packet_ptr; + socket_ptr -> nx_tcp_socket_transmit_sent_tail = packet_ptr; + + /* Setup a timeout for the packet at the head of the list. */ + socket_ptr -> nx_tcp_socket_timeout = socket_ptr -> nx_tcp_socket_timeout_rate; + socket_ptr -> nx_tcp_socket_timeout_retries = 0; + socket_ptr -> nx_tcp_socket_tx_outstanding_bytes = 0; + } + + /* Set the next pointer to NX_PACKET_ENQUEUED to indicate the packet is part of a TCP queue. */ + packet_ptr -> nx_packet_tcp_queue_next = (NX_PACKET *)NX_PACKET_ENQUEUED; + + /* Increment the packet sent count. */ + socket_ptr -> nx_tcp_socket_transmit_sent_count++; + + /* Increase the transmit outstanding byte count. */ + socket_ptr -> nx_tcp_socket_tx_outstanding_bytes += + (packet_ptr -> nx_packet_length - sizeof(NX_TCP_HEADER)); +#ifndef NX_DISABLE_TCP_INFO + /* Increment the TCP packet sent count and bytes sent count. */ + ip_ptr -> nx_ip_tcp_packets_sent++; + ip_ptr -> nx_ip_tcp_bytes_sent += packet_ptr -> nx_packet_length - sizeof(NX_TCP_HEADER); + + /* Increment the TCP packet sent count and bytes sent count for the socket. */ + socket_ptr -> nx_tcp_socket_packets_sent++; + socket_ptr -> nx_tcp_socket_bytes_sent += packet_ptr -> nx_packet_length - sizeof(NX_TCP_HEADER); +#endif + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_TCP_DATA_SEND, ip_ptr, socket_ptr, packet_ptr, socket_ptr -> nx_tcp_socket_tx_sequence - (packet_ptr -> nx_packet_length - sizeof(NX_TCP_HEADER)), NX_TRACE_INTERNAL_EVENTS, 0, 0) + + /* Send the TCP packet to the IP component. */ + _nx_ip_packet_send(ip_ptr, packet_ptr, socket_ptr -> nx_tcp_socket_connect_ip, + socket_ptr -> nx_tcp_socket_type_of_service, socket_ptr -> nx_tcp_socket_time_to_live, NX_IP_TCP, socket_ptr -> nx_tcp_socket_fragment_enable); + + /* Release the protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return successful status. */ + return(NX_SUCCESS); + } + else if ((wait_option) && (_tx_thread_current_ptr != &(ip_ptr -> nx_ip_thread))) + { + + /* Determine if there is already a thread suspended on transmit for the + socket. If so, just return an error. */ + if (socket_ptr -> nx_tcp_socket_transmit_suspended_count) + { + + /* Remove the TCP header from the packet. */ + packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - sizeof(NX_TCP_HEADER); + packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr + sizeof(NX_TCP_HEADER); + + /* Release protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return the already suspended error. */ + return(NX_ALREADY_SUSPENDED); + } + + /* Save the return packet pointer address as well. */ + _tx_thread_current_ptr -> tx_thread_additional_suspend_info = (VOID *)packet_ptr; + + /* Increment the suspended thread count. */ + socket_ptr -> nx_tcp_socket_transmit_suspended_count++; + + /* Suspend the thread on the transmit suspension list. */ + _nx_tcp_socket_thread_suspend(&(socket_ptr -> nx_tcp_socket_transmit_suspension_list), _nx_tcp_transmit_cleanup, socket_ptr, &(ip_ptr -> nx_ip_protection), wait_option); + + /* Determine if the send request was successful. */ + if (_tx_thread_current_ptr -> tx_thread_suspend_status) + { + + /* Remove the TCP header from the packet. */ + packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - sizeof(NX_TCP_HEADER); + packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr + sizeof(NX_TCP_HEADER); + } + + /* If not, just return the error code. */ + return(_tx_thread_current_ptr -> tx_thread_suspend_status); + } + else + { + + /* Remove the TCP header from the packet. */ + packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - sizeof(NX_TCP_HEADER); + packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr + sizeof(NX_TCP_HEADER); + + /* Determine which transmit error is present. */ + if (socket_ptr -> nx_tcp_socket_transmit_sent_count < socket_ptr -> nx_tcp_socket_transmit_queue_maximum) + { + + /* Release protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Not a queue depth problem, return a window overflow error. */ + return(NX_WINDOW_OVERFLOW); + } + else + { + + /* Release protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return a transmit queue exceeded error. */ + return(NX_TX_QUEUE_DEPTH); + } + } +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcp_socket_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sends a TCP packet through the specified socket. */ +/* If payload size exceeds MSS, this service fragments the payload */ +/* to fit into MSS. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to socket */ +/* packet_ptr Pointer to packet to send */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* NX_INVALID_PARAMETERS Unknown packet IP version */ +/* NX_INVALID_PACKET Source packet chain missing */ +/* packet data */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_tcp_socket_send_internal Transmit TCP payload */ +/* _nx_packet_allocate Packet allocation for */ +/* fragmentation */ +/* _nx_packet_release Packet release */ +/* _nx_packet_data_append Move data into fragments */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_tcp_socket_send(NX_TCP_SOCKET *socket_ptr, NX_PACKET *packet_ptr, ULONG wait_option) +{ + +ULONG remaining_bytes; +NX_IP *ip_ptr; +NX_PACKET *fragment_packet = NX_NULL; +NX_PACKET *current_packet = NX_NULL; +ULONG ret; +ULONG source_data_size; +ULONG fragment_packet_space_remaining = 0; +ULONG copy_size; +UCHAR *current_ptr; +ULONG fragment_length; + + /* Initialize outcome to successful completion. */ + ret = NX_SUCCESS; + + /* MSS size is IP MTU - IP header - optional header - TCP header. */ + + /* Send the packet directly if it is within MSS size. */ + if (packet_ptr -> nx_packet_length <= socket_ptr -> nx_tcp_socket_connect_mss) + { + + return(_nx_tcp_socket_send_internal(socket_ptr, packet_ptr, wait_option)); + } + + /* The packet size is determined to be larger than MSS size. */ + + /* Obtain the size of the source packet. */ + remaining_bytes = packet_ptr -> nx_packet_length; + + /* Have a handle on the IP instance. */ + ip_ptr = socket_ptr -> nx_tcp_socket_ip_ptr; + + /* Points to the source packet. */ + current_packet = packet_ptr; + /* Mark the beginning of data. */ + current_ptr = packet_ptr -> nx_packet_prepend_ptr; + + /* Loop through the entire source packet. */ + while (remaining_bytes) + { + + /* Obtain a new fragment packet if the previous one has been transmitted. */ + if (fragment_packet == NX_NULL) + { + + ret = _nx_packet_allocate(ip_ptr -> nx_ip_default_packet_pool, &fragment_packet, NX_TCP_PACKET, wait_option); + + if (ret != NX_SUCCESS) + { + return(ret); + } + + /* The fragment remaining bytes cannot exceed the socket MSS. */ + fragment_packet_space_remaining = socket_ptr -> nx_tcp_socket_connect_mss; + + /* Initialize the fragment packet length. */ + fragment_packet -> nx_packet_length = 0; + } + + /* Figure out whether or not the source packet still contains data. */ + source_data_size = (ULONG)(current_packet -> nx_packet_append_ptr - current_ptr); + if (source_data_size == 0) + { + + /* The current buffer is exhausted. Move to the next buffer on the source packet chain. */ + current_packet = current_packet -> nx_packet_next; + + if (current_packet == NX_NULL) + { + + /* No more data in the source packet. However there are still bytes remaining even though + the packet is not done yet. This is an unrecoverable error. */ + _nx_packet_release(fragment_packet); + + return(NX_INVALID_PACKET); + } + + /* Mark the beginning of data in the next packet. */ + current_ptr = current_packet -> nx_packet_prepend_ptr; + + /* Compute the amount of data present in this source buffer. */ + source_data_size = (ULONG)(current_packet -> nx_packet_append_ptr - current_ptr); + } + + + /* copy_size = min(fragment_packet, source) */ + if (fragment_packet_space_remaining > source_data_size) + { + copy_size = source_data_size; + } + else + { + copy_size = fragment_packet_space_remaining; + } + + /* Append data. */ + ret = _nx_packet_data_append(fragment_packet, current_ptr, copy_size, + ip_ptr -> nx_ip_default_packet_pool, wait_option); + + /* Check for errors with data append. */ + if (ret != NX_SUCCESS) + { + + /* Append failed. Release the packets we will not send and return + the error status from the data append call. */ + _nx_packet_release(fragment_packet); + return(ret); + } + + /* Reduce the remaining_bytes counter by the amount being copied over. */ + remaining_bytes -= copy_size; + + /* Advance the prepend ptr on the source buffer, by the amount being copied. */ + current_ptr += copy_size; + + /* Tracking the amount of space left in the fragment packet. */ + fragment_packet_space_remaining -= copy_size; + + /* At this point, either the source buffer is exhausted (so during the next iteration + source buffer will move to the next buffer on the chain), or this fragment has been + filled up and ready to be transmitted. */ + + if (fragment_packet_space_remaining == 0) + { + /* A fragment is ready to be transmitted. */ + fragment_length = fragment_packet -> nx_packet_length; + ret = _nx_tcp_socket_send_internal(socket_ptr, fragment_packet, wait_option); + + if (ret != NX_SUCCESS) + { + + /* Release the packet fragment that failed to get sent. */ + _nx_packet_release(fragment_packet); + + return(ret); + } + + /* Adjust the packet for data already sent. */ + packet_ptr -> nx_packet_length -= fragment_length; + for (fragment_packet = packet_ptr; + fragment_packet != NX_NULL; + fragment_packet = fragment_packet -> nx_packet_next) + { + if (((ULONG)fragment_packet -> nx_packet_append_ptr - + (ULONG)fragment_packet -> nx_packet_prepend_ptr) > fragment_length) + { + + /* This is the last packet to trim. */ + fragment_packet -> nx_packet_prepend_ptr += fragment_length; + break; + } + + /* Trim the whole packet. */ + fragment_length -= ((ULONG)fragment_packet -> nx_packet_append_ptr - + (ULONG)fragment_packet -> nx_packet_prepend_ptr); + fragment_packet -> nx_packet_prepend_ptr = fragment_packet -> nx_packet_append_ptr; + } + fragment_packet = NX_NULL; + } + } + + /* Transmit the last fragment if not transmitted yet. */ + if (fragment_packet) + { + ret = _nx_tcp_socket_send_internal(socket_ptr, fragment_packet, wait_option); + + if (ret != NX_SUCCESS) + { + + /* Release the packet fragment that failed to get sent. */ + _nx_packet_release(fragment_packet); + + return(ret); + } + } + + _nx_packet_release(packet_ptr); + + return(ret); +} + diff --git a/common/src/nx_tcp_socket_state_ack_check.c b/common/src/nx_tcp_socket_state_ack_check.c new file mode 100644 index 0000000..b13d1b6 --- /dev/null +++ b/common/src/nx_tcp_socket_state_ack_check.c @@ -0,0 +1,670 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_packet.h" +#include "nx_tcp.h" + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcp_socket_state_ack_check PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for ACK conditions in various states of the */ +/* TCP socket. ACK messages are examined against the queued transmit */ +/* packets in order to see if one or more transmit packets may be */ +/* removed from the socket's transmit queue. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to owning socket */ +/* tcp_header_ptr Pointer to packet header */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_tcp_packet_send_ack Send ACK message */ +/* _nx_packet_release Packet release function */ +/* _nx_tcp_socket_retransmit Retransmit packet */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_tcp_socket_packet_process Process TCP packet for socket */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_tcp_socket_state_ack_check(NX_TCP_SOCKET *socket_ptr, NX_TCP_HEADER *tcp_header_ptr) +{ + +NX_TCP_HEADER *search_header_ptr; +NX_PACKET *search_ptr; +NX_PACKET *previous_ptr; +ULONG header_length; +ULONG search_sequence; +ULONG temp; +ULONG packet_release_count; +ULONG ending_packet_sequence; +ULONG starting_tx_sequence = 0; +ULONG ending_tx_sequence = 0; +ULONG acked_bytes; +UINT wrapped_flag = NX_FALSE; + + + /* Determine if invalid SYN bit is present. */ + if (tcp_header_ptr -> nx_tcp_header_word_3 & NX_TCP_SYN_BIT) + { + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_TCP_SYN_RECEIVE, socket_ptr -> nx_tcp_socket_ip_ptr, socket_ptr, NX_NULL, tcp_header_ptr -> nx_tcp_sequence_number, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + /* Yes, an invalid SYN bit is present. Respond with an ACK to let the other + side of the connection figure out if everything is still okay. */ + _nx_tcp_packet_send_ack(socket_ptr, socket_ptr -> nx_tcp_socket_tx_sequence); + } + + /* Determine if the header has an ACK bit set. This is an + acknowledgement of a previous transmission. */ + if (tcp_header_ptr -> nx_tcp_header_word_3 & NX_TCP_ACK_BIT) + { + +#ifdef NX_ENABLE_TCP_KEEPALIVE + /* Determine if the socket is in the established state. */ + if (socket_ptr -> nx_tcp_socket_state == NX_TCP_ESTABLISHED) + { + + /* Is the keepalive feature enabled on this socket? */ + if (socket_ptr -> nx_tcp_socket_keepalive_enabled) + { + + /* Yes, reset the TCP Keepalive timer to initial values. */ + socket_ptr -> nx_tcp_socket_keepalive_timeout = NX_TCP_KEEPALIVE_INITIAL; + socket_ptr -> nx_tcp_socket_keepalive_retries = 0; + + /* Determine if we have received a Keepalive ACK request from the other side + of the connection. */ + if (tcp_header_ptr -> nx_tcp_sequence_number == (socket_ptr -> nx_tcp_socket_rx_sequence - 1)) + { + + /* Yes, a Keepalive ACK probe is present. Respond with an ACK to let the other + side of the connection know that we are still alive. */ + _nx_tcp_packet_send_ack(socket_ptr, socket_ptr -> nx_tcp_socket_tx_sequence); + } + } + } +#endif + + + /* First, determine if incoming ACK matches our transmit sequence. */ + if (tcp_header_ptr -> nx_tcp_acknowledgment_number == socket_ptr -> nx_tcp_socket_tx_sequence) + { + + /* In this case, everything on the transmit list is acknowledged. Simply set the packet + release count to the number of packets in the transmit queue. */ + packet_release_count = socket_ptr -> nx_tcp_socket_transmit_sent_count; + + /* Set the previous pointer to the socket transmit tail pointer. */ + previous_ptr = socket_ptr -> nx_tcp_socket_transmit_sent_tail; + + /* In this case, all data is acked, so we just need to set starting_tx_seq and ending_tx_seq to the current + TX sequence number, which is the same as the ACK number. */ + starting_tx_sequence = socket_ptr -> nx_tcp_socket_tx_sequence; + ending_tx_sequence = socket_ptr -> nx_tcp_socket_tx_sequence; + /* Update this socket's transmit window with the advertised window size in the ACK message. */ + socket_ptr -> nx_tcp_socket_tx_window_advertised = (tcp_header_ptr -> nx_tcp_header_word_3) & NX_LOWER_16_MASK; + +#ifdef NX_ENABLE_TCP_WINDOW_SCALING + socket_ptr -> nx_tcp_socket_tx_window_advertised <<= socket_ptr -> nx_tcp_snd_win_scale_value; +#endif /* NX_ENABLE_TCP_WINDOW_SCALING */ + } + else + { + + /* Calculate the start and end of the transmit sequence. */ + + /* Pickup the head of the transmit queue. */ + search_ptr = socket_ptr -> nx_tcp_socket_transmit_sent_head; + + /* Determine if there is a packet on the transmit queue... and determine if the packet has been + transmitted. */ + if ((search_ptr) && (search_ptr -> nx_packet_queue_next == ((NX_PACKET *)NX_DRIVER_TX_DONE))) + { + + /* Setup a pointer to header of this packet in the sent list. */ + search_header_ptr = (NX_TCP_HEADER *)search_ptr -> nx_packet_prepend_ptr; + + /* Pickup the starting sequence number. */ + starting_tx_sequence = search_header_ptr -> nx_tcp_sequence_number; + + NX_CHANGE_ULONG_ENDIAN(starting_tx_sequence); + + /* Determine if the incoming ACK matches the front of our transmit queue. If so, + decrease the retransmit timeout by 50% in order to improve the retry time. */ + if (tcp_header_ptr -> nx_tcp_acknowledgment_number == starting_tx_sequence) + { + + /* Handle duplicated ACK packet. */ + socket_ptr -> nx_tcp_socket_duplicated_ack_received++; + + if (socket_ptr -> nx_tcp_socket_duplicated_ack_received == 3) + { + if ((INT)((tcp_header_ptr -> nx_tcp_acknowledgment_number - 1) - + socket_ptr -> nx_tcp_socket_tx_sequence_recover > 0)) + { + + /* Cumulative acknowledge covers more than recover. */ + /* Section 3.2, Page 5, RFC6582. */ + /* Retransmit packet immediately. */ + _nx_tcp_socket_retransmit(socket_ptr -> nx_tcp_socket_ip_ptr, socket_ptr, NX_TRUE); + } + else if ((socket_ptr -> nx_tcp_socket_tx_window_congestion > socket_ptr -> nx_tcp_socket_connect_mss) && + ((INT)(tcp_header_ptr -> nx_tcp_acknowledgment_number - (socket_ptr -> nx_tcp_socket_previous_highest_ack + + (socket_ptr -> nx_tcp_socket_connect_mss << 2))) < 0)) + { + + /* Congestion window is greater than SMSS bytes and + the difference between highest_ack and prev_highest_ack is at most 4*SMSS bytes.*/ + /* Section 4.1, Page 5, RFC6582. */ + /* Retransmit packet immediately. */ + _nx_tcp_socket_retransmit(socket_ptr -> nx_tcp_socket_ip_ptr, socket_ptr, NX_TRUE); + } + } + else if ((socket_ptr -> nx_tcp_socket_duplicated_ack_received > 3) && + (socket_ptr -> nx_tcp_socket_fast_recovery == NX_TRUE)) + { + + /* CWND += MSS */ + socket_ptr -> nx_tcp_socket_tx_window_congestion += socket_ptr -> nx_tcp_socket_connect_mss; + } + } + + + /* Pickup the ending transmit queue sequence. */ + ending_tx_sequence = socket_ptr -> nx_tcp_socket_tx_sequence; + + /* Determine if the transmit queue has wrapped. */ + if (ending_tx_sequence > starting_tx_sequence) + { + + /* Clear the wrapped flag. */ + wrapped_flag = NX_FALSE; + } + else + { + + /* Set the wrapped flag. */ + wrapped_flag = NX_TRUE; + } + } + else + { + + if (search_ptr == NX_NULL) + { + + /* No outstanding packets so the valid sequence number is the current tx sequence number. */ + starting_tx_sequence = socket_ptr -> nx_tcp_socket_tx_sequence; + ending_tx_sequence = socket_ptr -> nx_tcp_socket_tx_sequence; + } + else + { + + /* ACK Number is not TX Seq, but there are no packet waiting for ACK + (the 1st packet in the tx queue has not been sent yet). + In this case, we do not need to send an ACK back. */ + starting_tx_sequence = socket_ptr -> nx_tcp_socket_tx_sequence - socket_ptr -> nx_tcp_socket_tx_outstanding_bytes; + ending_tx_sequence = starting_tx_sequence; + } + } + + /* Determine if the transmit window size should be updated. */ + if (tcp_header_ptr -> nx_tcp_sequence_number == socket_ptr -> nx_tcp_socket_rx_sequence) + { + + /* Update this socket's transmit window with the advertised window size in the ACK message. */ + socket_ptr -> nx_tcp_socket_tx_window_advertised = (tcp_header_ptr -> nx_tcp_header_word_3) & NX_LOWER_16_MASK; + +#ifdef NX_ENABLE_TCP_WINDOW_SCALING + socket_ptr -> nx_tcp_socket_tx_window_advertised <<= socket_ptr -> nx_tcp_snd_win_scale_value; +#endif + } + + /* Initialize the packet release count. */ + packet_release_count = 0; + + /* See if we can find the sequence number in the sent queue for this socket. */ + previous_ptr = NX_NULL; + + while (search_ptr) + { + + /* Determine if the packet has been transmitted. */ + if (search_ptr -> nx_packet_queue_next != ((NX_PACKET *)NX_DRIVER_TX_DONE)) + { + break; + } + + /* Setup a pointer to header of this packet in the sent list. */ + search_header_ptr = (NX_TCP_HEADER *)search_ptr -> nx_packet_prepend_ptr; + + /* Determine the size of the TCP header. */ + temp = search_header_ptr -> nx_tcp_header_word_3; + NX_CHANGE_ULONG_ENDIAN(temp); + header_length = (temp >> NX_TCP_HEADER_SHIFT) * sizeof(ULONG); + + /* Determine the sequence number in the TCP header. */ + search_sequence = search_header_ptr -> nx_tcp_sequence_number; + NX_CHANGE_ULONG_ENDIAN(search_sequence); + + /* Calculate the ending packet sequence. */ + ending_packet_sequence = (search_sequence + (search_ptr -> nx_packet_length - header_length)); + + /* Determine if the transmit window is wrapped. */ + if (wrapped_flag == NX_FALSE) + { + + /* No, the transmit window is not wrapped. Perform a simple compare to determine if the ACK + covers the current search packet. */ + + /* Is this ACK before the current search packet or after the transmit sequence? */ + if ((tcp_header_ptr -> nx_tcp_acknowledgment_number < ending_packet_sequence) || + (tcp_header_ptr -> nx_tcp_acknowledgment_number > ending_tx_sequence)) + { + + /* The ACK is less than the current packet, just get out of the loop! */ + break; + } + } + else + { + + /* Yes, the transmit window has wrapped. We need to now check for all the wrap conditions to + determine if ACK covers the current search packet. */ + + /* Is the search packet's ending sequence number in the wrapped part of the window. */ + if (ending_packet_sequence < starting_tx_sequence) + { + + /* The search packet ends in the wrapped portion of the window. Determine if the ACK + sequence in the wrapped portion as well. */ + if (tcp_header_ptr -> nx_tcp_acknowledgment_number < starting_tx_sequence) + { + + /* Yes, the ACK sequence is in the wrapped portion as well. Simply compare the ACK + number with the search packet sequence. */ + if (tcp_header_ptr -> nx_tcp_acknowledgment_number < ending_packet_sequence) + { + + /* ACK does not cover the search packet. Break out of the loop. */ + break; + } + } + else + { + + /* The ACK sequence is in the non-wrapped portion of the window and the ending sequence + of the search packet is in the wrapped portion - so the ACK doesn't cover the search + packet. Break out of the loop! */ + break; + } + } + else + { + + /* The search packet is in the non-wrapped portion of the window. Determine if the ACK + sequence is in the non-wrapped portion as well. */ + if (tcp_header_ptr -> nx_tcp_acknowledgment_number >= starting_tx_sequence) + { + + /* Yes, the ACK sequence is in the non-wrapped portion of the window. Simply compare the ACK + sequence with the search packet sequence. */ + if (tcp_header_ptr -> nx_tcp_acknowledgment_number < ending_packet_sequence) + { + + /* ACK does not cover the search packet. Break out of the loop. */ + break; + } + } + } + } + + /* At this point we know that the ACK received covers the search packet. */ + + /* Increase the packet release count. */ + packet_release_count++; + + /* Update this socket's transmit window with the advertised window size in the ACK message. */ + socket_ptr -> nx_tcp_socket_tx_window_advertised = (tcp_header_ptr -> nx_tcp_header_word_3) & NX_LOWER_16_MASK; + +#ifdef NX_ENABLE_TCP_WINDOW_SCALING + socket_ptr -> nx_tcp_socket_tx_window_advertised <<= socket_ptr -> nx_tcp_snd_win_scale_value; +#endif /* NX_ENABLE_TCP_WINDOW_SCALING */ + + /* Move the search and previous pointers forward. */ + previous_ptr = search_ptr; + search_ptr = search_ptr -> nx_packet_tcp_queue_next; + + /* Determine if we are at the end of the TCP queue. */ + if (search_ptr == ((NX_PACKET *)NX_PACKET_ENQUEUED)) + { + + /* Yes, set the search pointer to NULL. */ + search_ptr = NX_NULL; + } + } + } + + /* Determine if anything needs to be released. */ + if (!packet_release_count) + { + + /* No, check and see if the ACK is valid. */ + if ((socket_ptr -> nx_tcp_socket_state == NX_TCP_ESTABLISHED) && + (socket_ptr -> nx_tcp_socket_transmit_sent_head) && + (tcp_header_ptr -> nx_tcp_acknowledgment_number != socket_ptr -> nx_tcp_socket_tx_sequence)) + { + + /* Determine if the transmit sequence is wrapped. */ + if (wrapped_flag == NX_FALSE) + { + + + /* No, not wrapped. Typical compare of sequence number with ACK. */ + if ((tcp_header_ptr -> nx_tcp_acknowledgment_number < starting_tx_sequence) || + (tcp_header_ptr -> nx_tcp_acknowledgment_number > ending_tx_sequence)) + { + + /* The ACK sequence is invalid. Respond with an ACK to let the other + side of the connection figure out if everything is still okay. */ + _nx_tcp_packet_send_ack(socket_ptr, socket_ptr -> nx_tcp_socket_tx_sequence); + } + } + else + { + + /* Yes, the transmit sequence is wrapped. Compare the ACK with the wrapped + sequence numbers. */ + if ((tcp_header_ptr -> nx_tcp_acknowledgment_number > ending_tx_sequence) && + (tcp_header_ptr -> nx_tcp_acknowledgment_number < starting_tx_sequence)) + { + + /* The ACK sequence is invalid. Respond with an ACK to let the other + side of the connection figure out if everything is still okay. */ + _nx_tcp_packet_send_ack(socket_ptr, socket_ptr -> nx_tcp_socket_tx_sequence); + } + } + } + + /* Done, return to caller. */ + return; + } + else + { + + /* Congestion window adjustment during slow start and congestion avoidance is executed + on every incoming ACK that acknowledges new data. RFC5681, Section3.1, Page4-8. */ + /* Check whether the socket is in fast recovery procedure. */ + if (socket_ptr -> nx_tcp_socket_fast_recovery == NX_TRUE) + { + + /* Yes. */ + if ((INT)(tcp_header_ptr -> nx_tcp_acknowledgment_number - + socket_ptr -> nx_tcp_socket_tx_sequence_recover) > 0) + { + + /* All packets sent before entering fast recovery are ACKed. */ + /* Exit fast recovery procedure. */ + socket_ptr -> nx_tcp_socket_fast_recovery = NX_FALSE; + socket_ptr -> nx_tcp_socket_tx_window_congestion = socket_ptr -> nx_tcp_socket_tx_slow_start_threshold; + } + } + + if ((INT)(socket_ptr -> nx_tcp_socket_tx_sequence_recover - + (tcp_header_ptr -> nx_tcp_acknowledgment_number - 2)) < 0) + { + + /* Update the transmit sequence that enters fast transmit. */ + socket_ptr -> nx_tcp_socket_tx_sequence_recover = tcp_header_ptr -> nx_tcp_acknowledgment_number - 2; + } + + /* Reset the duplicated ACK counter. */ + socket_ptr -> nx_tcp_socket_duplicated_ack_received = 0; + + + /* Determine if the packet has been transmitted. */ + /*lint -e{923} suppress cast of ULONG to pointer. */ + if (socket_ptr -> nx_tcp_socket_transmit_sent_head -> nx_packet_queue_next != ((NX_PACKET *)NX_DRIVER_TX_DONE)) + { + + /* Not yet. This could be only when all packets are ACKed. */ + /* Set previous cumulative acknowlesgement. */ + socket_ptr -> nx_tcp_socket_previous_highest_ack = socket_ptr -> nx_tcp_socket_tx_sequence - + socket_ptr -> nx_tcp_socket_tx_outstanding_bytes; + + /* Calculate ACKed length. */ + acked_bytes = socket_ptr -> nx_tcp_socket_tx_outstanding_bytes; + } + else + { + + /* Setup a pointer to header of this packet in the sent list. */ + /*lint -e{927} -e{826} suppress cast of pointer to pointer, since it is necessary */ + search_header_ptr = (NX_TCP_HEADER *)socket_ptr -> nx_tcp_socket_transmit_sent_head -> nx_packet_prepend_ptr; + + /* Pickup the starting sequence number. */ + starting_tx_sequence = search_header_ptr -> nx_tcp_sequence_number; + NX_CHANGE_ULONG_ENDIAN(starting_tx_sequence); + + /* Set previous cumulative acknowlesgement. */ + socket_ptr -> nx_tcp_socket_previous_highest_ack = starting_tx_sequence; + + /* Calculate ACKed length. */ + acked_bytes = tcp_header_ptr -> nx_tcp_acknowledgment_number - starting_tx_sequence; + } + + if (socket_ptr -> nx_tcp_socket_fast_recovery == NX_TRUE) + { + + /* Process cwnd in fast recovery procedure. */ + socket_ptr -> nx_tcp_socket_tx_window_congestion -= acked_bytes; + if (acked_bytes > socket_ptr -> nx_tcp_socket_connect_mss) + { + socket_ptr -> nx_tcp_socket_tx_window_congestion += socket_ptr -> nx_tcp_socket_connect_mss; + } + } + else + { + + /* Adjust the transmit window. In slow start phase, the transmit window is incremented for every ACK. + In Congestion Avoidance phase, the window is incremented for every RTT. */ + if (socket_ptr -> nx_tcp_socket_tx_window_congestion >= socket_ptr -> nx_tcp_socket_tx_slow_start_threshold) + { + + /* In Congestion avoidance phase, for every ACK it receives, increase the window size using the + following approximation: + cwnd = cwnd + MSS * MSS / cwnd; + */ + temp = socket_ptr -> nx_tcp_socket_connect_mss2 / socket_ptr -> nx_tcp_socket_tx_window_congestion; + + /* If the above formula yields 0, the result SHOULD be rounded up to 1 byte. */ + if (temp == 0) + { + temp = 1; + } + + socket_ptr -> nx_tcp_socket_tx_window_congestion = socket_ptr -> nx_tcp_socket_tx_window_congestion + temp; + } + else + { + + /* cwnd += min (N, SMSS). + where N is the number of ACKed bytes. */ + /* Section 3.1, Page 6, RFC5681. */ + if (acked_bytes < socket_ptr -> nx_tcp_socket_connect_mss) + { + + /* In Slow start phase. Increase the cwnd by full MSS for every ack.*/ + socket_ptr -> nx_tcp_socket_tx_window_congestion += (tcp_header_ptr -> nx_tcp_acknowledgment_number - starting_tx_sequence); + } + else + { + + /* In Slow start phase. Increase the cwnd by full MSS for every ack.*/ + socket_ptr -> nx_tcp_socket_tx_window_congestion += socket_ptr -> nx_tcp_socket_connect_mss; + } + } + } + } + + + /* Save the front of the of the transmit queue. */ + search_ptr = socket_ptr -> nx_tcp_socket_transmit_sent_head; + + + /* Okay so now the packet after the previous pointer needs to be the front of the + queue. */ + if (previous_ptr != socket_ptr -> nx_tcp_socket_transmit_sent_tail) + { + + /* Just update the head pointer. */ + socket_ptr -> nx_tcp_socket_transmit_sent_head = + previous_ptr -> nx_packet_tcp_queue_next; + + /* And decrease the transmit queue count accordingly. */ + socket_ptr -> nx_tcp_socket_transmit_sent_count = + socket_ptr -> nx_tcp_socket_transmit_sent_count - packet_release_count; + + /* Setup a new transmit timeout. */ + socket_ptr -> nx_tcp_socket_timeout = socket_ptr -> nx_tcp_socket_timeout_rate; + socket_ptr -> nx_tcp_socket_timeout_retries = 0; + } + else + { + + /* The transmit list is now cleared, just set the head and tail pointers to + NULL. */ + socket_ptr -> nx_tcp_socket_transmit_sent_head = NX_NULL; + socket_ptr -> nx_tcp_socket_transmit_sent_tail = NX_NULL; + + /* Clear the transmit queue count. */ + socket_ptr -> nx_tcp_socket_transmit_sent_count = 0; + + /* Determine if a disconnect FIN has been sent from this side of the connection. */ + if ((socket_ptr -> nx_tcp_socket_state == NX_TCP_FIN_WAIT_1) || + (socket_ptr -> nx_tcp_socket_state == NX_TCP_CLOSING) || + (socket_ptr -> nx_tcp_socket_state == NX_TCP_LAST_ACK)) + { + + /* Yes, setup timeout such that the FIN can be retried if it is lost. */ + socket_ptr -> nx_tcp_socket_timeout = socket_ptr -> nx_tcp_socket_timeout_rate; + socket_ptr -> nx_tcp_socket_timeout_retries = 0; + } + else + { + + /* Otherwise, a FIN has not been sent, simply clear the transmit timeout. */ + socket_ptr -> nx_tcp_socket_timeout = 0; + } + } + + /* Now walk through the packets to release and set them free. */ + while (packet_release_count--) + { + + /* Use the previous pointer as the release pointer. */ + previous_ptr = search_ptr; + + /* Move to the next packet in the queue before we clip the + next pointer. */ + search_ptr = search_ptr -> nx_packet_tcp_queue_next; + + /* Set the packet to allocated to indicate it is no longer part of the TCP queue. */ + previous_ptr -> nx_packet_tcp_queue_next = ((NX_PACKET *)NX_PACKET_ALLOCATED); + + /* Has the packet been transmitted? This is only pertinent if a retransmit of + the packet occurred prior to receiving the ACK. If so, the packet could be + in an ARP queue or in a driver queue waiting for transmission so we can't + release it directly at this point. The driver or the ARP processing will + release it when finished. */ + if (previous_ptr -> nx_packet_queue_next == ((NX_PACKET *)NX_DRIVER_TX_DONE)) + { + + /* Yes, the driver has already released the packet. */ + + /* Open up the transmit window. */ + search_header_ptr = (NX_TCP_HEADER *)previous_ptr -> nx_packet_prepend_ptr; + + temp = search_header_ptr -> nx_tcp_header_word_3; + NX_CHANGE_ULONG_ENDIAN(temp); + header_length = (temp >> NX_TCP_HEADER_SHIFT) * sizeof(ULONG); + if (socket_ptr -> nx_tcp_socket_tx_outstanding_bytes > (previous_ptr -> nx_packet_length - header_length)) + { + socket_ptr -> nx_tcp_socket_tx_outstanding_bytes -= previous_ptr -> nx_packet_length - header_length; + } + else + { + socket_ptr -> nx_tcp_socket_tx_outstanding_bytes = 0; + } + /* Release the packet. */ + _nx_packet_release(previous_ptr); + } + else + { + + /* Not yet. This could be only when all packets are ACKed. */ + /* Simply reset the outstanding bytes. */ + socket_ptr -> nx_tcp_socket_tx_outstanding_bytes = 0; + + /* Let driver release the packet. */ + previous_ptr -> nx_packet_tcp_queue_next = ((NX_PACKET *)NX_PACKET_ALLOCATED); + } + } + + if (socket_ptr -> nx_tcp_socket_fast_recovery == NX_TRUE) + { + + /* Only partial data are ACKed. Retransmit packet immediately. */ + _nx_tcp_socket_retransmit(socket_ptr -> nx_tcp_socket_ip_ptr, socket_ptr, NX_FALSE); + } + } +} + diff --git a/common/src/nx_tcp_socket_state_closing.c b/common/src/nx_tcp_socket_state_closing.c new file mode 100644 index 0000000..3f91774 --- /dev/null +++ b/common/src/nx_tcp_socket_state_closing.c @@ -0,0 +1,121 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_tcp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcp_socket_state_closing PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes packets during the CLOSING state, */ +/* which is the state at the end of an active, simultaneous */ +/* disconnect. If a valid ACK is present, the disconnect is */ +/* complete. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to owning socket */ +/* tcp_header_ptr Pointer to packet header */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_tcp_socket_thread_resume Resume suspended thread */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_tcp_socket_packet_process Process TCP packet for socket */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_tcp_socket_state_closing(NX_TCP_SOCKET *socket_ptr, NX_TCP_HEADER *tcp_header_ptr) +{ + + + /* Determine if the incoming message is an ACK message. If it is and + if it is proper, finish the disconnect. */ + if ((tcp_header_ptr -> nx_tcp_header_word_3 & NX_TCP_ACK_BIT) && + (tcp_header_ptr -> nx_tcp_acknowledgment_number == + socket_ptr -> nx_tcp_socket_tx_sequence)) + { + + /* Ensure the connect information is cleared. */ + socket_ptr -> nx_tcp_socket_connect_ip = 0; + socket_ptr -> nx_tcp_socket_connect_port = 0; + + /* Move the state back to CLOSED or LISTEN depending on the type of + socket we are processing. */ + if (socket_ptr -> nx_tcp_socket_client_type) + { + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_TCP_STATE_CHANGE, socket_ptr -> nx_tcp_socket_ip_ptr, socket_ptr, socket_ptr -> nx_tcp_socket_state, NX_TCP_CLOSED, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + /* Client socket, return to a CLOSED state. */ + socket_ptr -> nx_tcp_socket_state = NX_TCP_CLOSED; + } + else + { + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_TCP_STATE_CHANGE, socket_ptr -> nx_tcp_socket_ip_ptr, socket_ptr, socket_ptr -> nx_tcp_socket_state, NX_TCP_LISTEN_STATE, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + /* Server socket, return to LISTEN state. */ + socket_ptr -> nx_tcp_socket_state = NX_TCP_LISTEN_STATE; + } + + /* Otherwise, simply clear the FIN timeout. */ + socket_ptr -> nx_tcp_socket_timeout = 0; + + /* Determine if we need to wake a thread suspended on the connection. */ + if (socket_ptr -> nx_tcp_socket_disconnect_suspended_thread) + { + + /* Wake up suspended thread. */ + _nx_tcp_socket_thread_resume(&(socket_ptr -> nx_tcp_socket_disconnect_suspended_thread), NX_SUCCESS); + } + } +} + diff --git a/common/src/nx_tcp_socket_state_data_check.c b/common/src/nx_tcp_socket_state_data_check.c new file mode 100644 index 0000000..35dfe2e --- /dev/null +++ b/common/src/nx_tcp_socket_state_data_check.c @@ -0,0 +1,1036 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_packet.h" +#include "nx_ip.h" +#include "nx_tcp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcp_socket_state_data_trim PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function trims extra bytes from the data packet. */ +/* This is an internal utility function, only used by */ +/* _nx_tcp_socket_state_data_check. */ +/* */ +/* INPUT */ +/* */ +/* packet_ptr Pointer to packet to process */ +/* amount Number of bytes to remove */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_packet_release Release packet on overlap */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_tcp_socket_state_data_check Process TCP packet for socket */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static void _nx_tcp_socket_state_data_trim(NX_PACKET *packet_ptr, ULONG amount) +{ +ULONG bytes_to_keep; +NX_PACKET *work_ptr; + + if (amount >= packet_ptr -> nx_packet_length) + { + /* Invalid input. */ + return; + } + + bytes_to_keep = packet_ptr -> nx_packet_length - amount; + + packet_ptr -> nx_packet_length = bytes_to_keep; + + work_ptr = packet_ptr; + + /* Walk down the packet chain for the "bytes_to_keep" amount. */ + while (work_ptr) + { + + NX_PACKET *tmp_ptr; + + if ((int)(work_ptr -> nx_packet_append_ptr - work_ptr -> nx_packet_prepend_ptr) < (int)bytes_to_keep) + { + + bytes_to_keep -= (ULONG)(work_ptr -> nx_packet_append_ptr - work_ptr -> nx_packet_prepend_ptr); + + work_ptr = work_ptr -> nx_packet_next; + + continue; + } + + /* This is the last packet. */ + work_ptr -> nx_packet_append_ptr = work_ptr -> nx_packet_prepend_ptr + bytes_to_keep; + + /* Free the rest of the packet chain. */ + tmp_ptr = work_ptr -> nx_packet_next; + work_ptr -> nx_packet_next = NX_NULL; + work_ptr = tmp_ptr; + + if (work_ptr) + { + + work_ptr -> nx_packet_tcp_queue_next = (NX_PACKET *)NX_PACKET_ALLOCATED; + + _nx_packet_release(work_ptr); + + /* All done. Break out of the while loop and return. */ + break; + } + } +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcp_socket_state_data_trim_front PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function trims extra bytes from the data packet. */ +/* This is an internal utility function, only used by */ +/* _nx_tcp_socket_state_data_check. */ +/* */ +/* INPUT */ +/* */ +/* packet_ptr Pointer to packet to process */ +/* amount Number of bytes to remove */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_packet_release Release packet on overlap */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_tcp_socket_state_data_check Process TCP packet for socket */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static void _nx_tcp_socket_state_data_trim_front(NX_PACKET *packet_ptr, ULONG amount) +{ +NX_PACKET *work_ptr = packet_ptr; +ULONG work_length; + + if (amount >= packet_ptr -> nx_packet_length || amount == 0) + { + /* Invalid input. */ + return; + } + + /* Adjust the packet length. */ + packet_ptr -> nx_packet_length -= amount; + + /* Move prepend_ptr of first packet to TCP data. */ + packet_ptr -> nx_packet_prepend_ptr += sizeof(NX_TCP_HEADER); + + /* Walk down the packet chain for the amount. */ + while (amount) + { + + /* Compute the size of the data portion work_ptr. */ + work_length = (ULONG)(work_ptr -> nx_packet_append_ptr - work_ptr -> nx_packet_prepend_ptr); + + if (amount > work_length) + { + + /* All data in work_ptr need to be trimmed. */ + if (work_ptr == packet_ptr) + { + + /* This packet is the header of packet chain. */ + /* Clear TCP data in this packet. */ + work_ptr -> nx_packet_append_ptr = work_ptr -> nx_packet_prepend_ptr; + } + else + { + + /* This packet is not the first packet. */ + /* Remove work_ptr from packet chain. */ + packet_ptr -> nx_packet_next = work_ptr -> nx_packet_next; + + /* Disconnect work_ptr from the rest of the packet chain. */ + work_ptr -> nx_packet_next = NX_NULL; + + /* Mark the packet as ALLOCATED. */ + work_ptr -> nx_packet_tcp_queue_next = (NX_PACKET *)NX_PACKET_ALLOCATED; + + _nx_packet_release(work_ptr); + } + + /* Reduce the amount being trimmed. */ + amount -= work_length; + + /* Move to the next packet. */ + work_ptr = packet_ptr -> nx_packet_next; + } + else + { + + /* This is the last packet to trim. */ + + if (work_ptr == packet_ptr) + { + + /* For the first packet, move data towards the beginning + of the packet, right after TCP header. */ + memmove(packet_ptr -> nx_packet_prepend_ptr, + packet_ptr -> nx_packet_prepend_ptr + amount, + work_length - amount); + packet_ptr -> nx_packet_append_ptr -= amount; + } + else + { + + /* Advance nx_packet_prepend_ptr to where the usable data starts. */ + work_ptr -> nx_packet_prepend_ptr += amount; + } + + /* Cut down amount*/ + amount = 0; + } + } + + /* Restore prepend_ptr of first packet to TCP data. */ + packet_ptr -> nx_packet_prepend_ptr -= sizeof(NX_TCP_HEADER); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcp_socket_state_data_check PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function looks for incoming data from packets received */ +/* primarily in the ESTABLISHED state, but also in the later states */ +/* of connection and the early disconnection states. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to owning socket */ +/* packet_ptr Pointer to packet to process */ +/* */ +/* OUTPUT */ +/* */ +/* NX_TRUE If the packet had data */ +/* NX_FALSE If the packet had no data */ +/* */ +/* CALLS */ +/* */ +/* _nx_packet_release Release packet on overlap */ +/* _nx_tcp_socket_thread_resume Resume suspended thread */ +/* _nx_tcp_packet_send_ack Send immediate ACK */ +/* (nx_tcp_receive_callback) Packet receive notify function*/ +/* _nx_tcp_socket_state_data_trim Trim off extra bytes */ +/* _nx_tcp_socket_state_data_trim_front Trim off front extra bytes */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_tcp_socket_packet_process Process TCP packet for socket */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_tcp_socket_state_data_check(NX_TCP_SOCKET *socket_ptr, NX_PACKET *packet_ptr) +{ + +NX_TCP_HEADER *tcp_header_ptr; +NX_TCP_HEADER *search_header_ptr; +NX_PACKET *search_ptr; +NX_PACKET *previous_ptr; +ULONG expected_sequence; +ULONG header_length; +ULONG search_header_length; +ULONG packet_begin_sequence; +ULONG packet_end_sequence; +ULONG packet_data_length; +ULONG search_begin_sequence; +ULONG search_end_sequence; +ULONG original_rx_sequence; +ULONG trim_data_length; +TX_THREAD *thread_ptr; +ULONG acked_packets = 0; + +#if ((!defined(NX_DISABLE_TCP_INFO)) || defined(TX_ENABLE_EVENT_TRACE)) +NX_IP *ip_ptr; + /* Setup the IP pointer. */ + ip_ptr = socket_ptr -> nx_tcp_socket_ip_ptr; +#endif + + + /* Pickup the pointer to the head of the TCP packet. */ + tcp_header_ptr = (NX_TCP_HEADER *)packet_ptr -> nx_packet_prepend_ptr; + + /* Determine the size of the TCP header. */ + header_length = (tcp_header_ptr -> nx_tcp_header_word_3 >> NX_TCP_HEADER_SHIFT) * sizeof(ULONG); + + /* Record the original rx_sequence. */ + original_rx_sequence = socket_ptr -> nx_tcp_socket_rx_sequence; + + /* Pickup the begin sequence of this packet. */ + packet_begin_sequence = tcp_header_ptr -> nx_tcp_sequence_number; + + /* Calculate the data length in the packet. */ + packet_data_length = packet_ptr -> nx_packet_length - header_length; + + /* Pickup the end sequence of this packet. The end sequence is one byte to the last byte in this packet. */ + packet_end_sequence = tcp_header_ptr -> nx_tcp_sequence_number + packet_data_length; + + /* Trim the data that out of the receive window, make sure all data are in receive window. */ + if (packet_data_length) + { + + /* Step1. trim the data on the left side of the receive window. */ + if (((INT)socket_ptr -> nx_tcp_socket_rx_sequence - (INT)packet_begin_sequence) > 0) + { + + /* Calculate the data length that out of window. */ + trim_data_length = socket_ptr -> nx_tcp_socket_rx_sequence - packet_begin_sequence; + + /* Trim the data that exceed the receive window. */ + _nx_tcp_socket_state_data_trim_front(packet_ptr, trim_data_length); + + /* Fix the sequence of this packet. */ + tcp_header_ptr -> nx_tcp_sequence_number += trim_data_length; + + /* Update the data length and begin sequence. */ + packet_data_length -= trim_data_length; + packet_begin_sequence += trim_data_length; + } + + /* Step2. trim the data on the right side of the receive window. */ + if (((INT)packet_end_sequence - (INT)socket_ptr -> nx_tcp_socket_rx_sequence - (INT)socket_ptr -> nx_tcp_socket_rx_window_current) > 0) + { + + /* Calculate the data length that out of window. */ + trim_data_length = packet_end_sequence - (socket_ptr -> nx_tcp_socket_rx_sequence + socket_ptr -> nx_tcp_socket_rx_window_current); + + /* Trim the data that exceed the receive window. */ + _nx_tcp_socket_state_data_trim(packet_ptr, trim_data_length); + + /* Update the data length and end sequence. */ + packet_data_length -= trim_data_length; + packet_end_sequence -= trim_data_length; + } + } + + /* Determine if the packet has the FIN bit set to signal a disconnect. */ + if (tcp_header_ptr -> nx_tcp_header_word_3 & NX_TCP_FIN_BIT) + { + + /* Setup the FIN sequence number that we need to look at. */ + socket_ptr -> nx_tcp_socket_fin_sequence = tcp_header_ptr -> nx_tcp_sequence_number + packet_data_length; + + /* Indicate that the FIN sequence is now valid. Once the receive chain is complete + we will process (ACK) the FIN command which is part of a disconnect started by the + other side of the connection. */ + socket_ptr -> nx_tcp_socket_fin_received = NX_TRUE; + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_TCP_FIN_RECEIVE, ip_ptr, socket_ptr, packet_ptr, tcp_header_ptr -> nx_tcp_sequence_number, NX_TRACE_INTERNAL_EVENTS, 0, 0) + } + + /* Compute the amount of payload data in this packet. */ + if (packet_data_length == 0) + { + /* This packet does not contain TCP data payload. */ + + /* Check for invalid sequence number. */ + if ((socket_ptr -> nx_tcp_socket_state == NX_TCP_ESTABLISHED) && + (socket_ptr -> nx_tcp_socket_receive_queue_count == 0) && + (socket_ptr -> nx_tcp_socket_rx_sequence != tcp_header_ptr -> nx_tcp_sequence_number) && + ((socket_ptr -> nx_tcp_socket_rx_sequence - 1) != tcp_header_ptr -> nx_tcp_sequence_number)) + { + + /* Send an immediate ACK. */ + _nx_tcp_packet_send_ack(socket_ptr, socket_ptr -> nx_tcp_socket_tx_sequence); + } + + /* This packet does not have data, so return false. */ + return(NX_FALSE); + } + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_TCP_DATA_RECEIVE, ip_ptr, socket_ptr, packet_ptr, tcp_header_ptr -> nx_tcp_sequence_number, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + /* Ensure the next pointer in the packet is set to NULL, which will indicate to the + receive logic that it is not yet part of a contiguous stream. */ + packet_ptr -> nx_packet_queue_next = (NX_PACKET *)NX_NULL; + + /* Otherwise, the packet is within the receive window so continue processing + the incoming TCP data. */ + + /* Pickup the tail pointer of the receive queue. */ + search_ptr = socket_ptr -> nx_tcp_socket_receive_queue_tail; + + /* Check to see if the tail pointer is part of a contiguous stream. */ + if (search_ptr) + { + + /* Setup a pointer to header of this packet in the sent list. */ + search_header_ptr = (NX_TCP_HEADER *)search_ptr -> nx_packet_prepend_ptr; + + /* Determine the size of the search TCP header. */ + search_header_length = (search_header_ptr -> nx_tcp_header_word_3 >> NX_TCP_HEADER_SHIFT) * sizeof(ULONG); + + /* Now see if the current sequence number accounts for the last packet. */ + search_end_sequence = search_header_ptr -> nx_tcp_sequence_number + search_ptr -> nx_packet_length - search_header_length; + } + else + { + + /* Set the sequence number to the socket's receive sequence if there isn't a receive + packet on the queue. */ + search_end_sequence = socket_ptr -> nx_tcp_socket_rx_sequence; + } + + /* Determine if we have a simple case of TCP data coming in the correct order. This means + the socket's sequence number matches the incoming packet sequence number and the last packet's + data on the socket's receive queue (if any) matches the current sequence number. */ + if ((tcp_header_ptr -> nx_tcp_sequence_number == socket_ptr -> nx_tcp_socket_rx_sequence) && + (search_end_sequence == socket_ptr -> nx_tcp_socket_rx_sequence)) + { + + /* Yes, this is the simple case of adding receive packets in sequence. */ + + /* Mark the packet as ready. This is done to simplify the logic in socket receive. */ + packet_ptr -> nx_packet_queue_next = (NX_PACKET *)NX_PACKET_READY; + + /* Place the packet on the receive queue. Search pointer still points to the tail packet on + the queue. */ + if (search_ptr) + { + + /* Nonempty receive queue, add packet to the end of the receive queue. */ + search_ptr -> nx_packet_tcp_queue_next = packet_ptr; + + /* Update the tail of the receive queue. */ + socket_ptr -> nx_tcp_socket_receive_queue_tail = packet_ptr; + } + else + { + + /* Empty receive queue. Set both the head and the tail pointers this packet. */ + socket_ptr -> nx_tcp_socket_receive_queue_head = packet_ptr; + socket_ptr -> nx_tcp_socket_receive_queue_tail = packet_ptr; + + /* Setup a new delayed ACK timeout. */ + socket_ptr -> nx_tcp_socket_delayed_ack_timeout = _nx_tcp_ack_timer_rate; + } + /* Increment the receive TCP packet count. */ + socket_ptr -> nx_tcp_socket_receive_queue_count++; + + /* Set the next pointer to indicate the packet is part of a TCP queue. */ + packet_ptr -> nx_packet_tcp_queue_next = (NX_PACKET *)NX_PACKET_ENQUEUED; + + /* Update this socket's transmit window with the advertised window size in + the data message. */ + socket_ptr -> nx_tcp_socket_tx_window_advertised = (tcp_header_ptr -> nx_tcp_header_word_3) & NX_LOWER_16_MASK; + +#ifdef NX_ENABLE_TCP_WINDOW_SCALING + socket_ptr -> nx_tcp_socket_tx_window_advertised <<= socket_ptr -> nx_tcp_snd_win_scale_value; +#endif /* NX_ENABLE_TCP_WINDOW_SCALING */ + + /* Calculate the next sequence number. */ + socket_ptr -> nx_tcp_socket_rx_sequence = packet_end_sequence; + + /* Received one packet. */ + acked_packets = 1; + + /* End of the simple case: add new packet towards the end of the recv queue. + All packets in the receive queue are in sequence. */ + } + else if (socket_ptr -> nx_tcp_socket_receive_queue_head == NX_NULL) + { + + /* Packet data begins to the right of the expected sequence (out of sequence data). Force an ACK. */ + _nx_tcp_packet_send_ack(socket_ptr, socket_ptr -> nx_tcp_socket_tx_sequence); + + /* There are no packets chained on the receive queue. Simply add the + new packet to the receive queue. */ + socket_ptr -> nx_tcp_socket_receive_queue_head = packet_ptr; + socket_ptr -> nx_tcp_socket_receive_queue_tail = packet_ptr; + + /* Increase the receive queue count. */ + socket_ptr -> nx_tcp_socket_receive_queue_count = 1; + + /* Setup a new delayed ACK timeout. */ + socket_ptr -> nx_tcp_socket_delayed_ack_timeout = _nx_tcp_ack_timer_rate; + + /* Mark the packet as being part of a TCP queue. */ + packet_ptr -> nx_packet_tcp_queue_next = (NX_PACKET *)NX_PACKET_ENQUEUED; + + /* Update this socket's transmit window with the advertised window size in + the data message. */ + socket_ptr -> nx_tcp_socket_tx_window_advertised = (tcp_header_ptr -> nx_tcp_header_word_3) & NX_LOWER_16_MASK; + +#ifdef NX_ENABLE_TCP_WINDOW_SCALING + socket_ptr -> nx_tcp_socket_tx_window_advertised <<= socket_ptr -> nx_tcp_snd_win_scale_value; +#endif /* NX_ENABLE_TCP_WINDOW_SCALING */ + } + else + { /* Out of order insertion with packets on the queue. */ + + /* Either this packet is not in order or other out-of-order packets have already been + received. In this case searching the receive list must be done to find the proper + place for the new packet. */ + + /* Go through the received packet chain, and locate the first packet that the + packet_begin_sequence is to the right of the end of it. */ + + /* Packet data begins to the right of the expected sequence (out of sequence data). Force an ACK. */ + if (((INT)packet_begin_sequence - (INT)socket_ptr -> nx_tcp_socket_rx_sequence) > 0) + { + _nx_tcp_packet_send_ack(socket_ptr, socket_ptr -> nx_tcp_socket_tx_sequence); + } + + /* At this point, it is guaranteed that the receive queue contains packets. */ + search_ptr = socket_ptr -> nx_tcp_socket_receive_queue_head; + + previous_ptr = NX_NULL; + + while (search_ptr) + { + + if (search_ptr == (NX_PACKET *)NX_PACKET_ENQUEUED) + { + /* We hit the end of the receive queue. */ + search_ptr = NX_NULL; + + /* Terminate the out-of-order search. */ + break; + } + + /* Setup a pointer to header of this packet in the receive list. */ + search_header_ptr = (NX_TCP_HEADER *)search_ptr -> nx_packet_prepend_ptr; + + search_begin_sequence = search_header_ptr -> nx_tcp_sequence_number; + + /* Calculate the header size for this packet. */ + header_length = (search_header_ptr -> nx_tcp_header_word_3 >> NX_TCP_HEADER_SHIFT) * sizeof(ULONG); + + search_end_sequence = search_begin_sequence + search_ptr -> nx_packet_length - header_length; + + /**************************************************************************************** + * (1) PPPPPPPP * + * SSSSSSSS * + * In this configuration, the incoming packet is completely to the right of * + * search_ptr. Move to the next search packet. * + * * + ****************************************************************************************/ + /* packet_ptr is to the right of search_ptr */ + if (((int)(packet_begin_sequence - search_end_sequence)) >= 0) + { + /* Move on to the next packet. */ + previous_ptr = search_ptr; + + search_ptr = search_ptr -> nx_packet_tcp_queue_next; + + /* Continue the search */ + continue; + } + + /**************************************************************************************** + * (2) PPPPPP * + * SSSSSSSSS * + * In this configuration, the incoming packet is completely to the left of * + * search_ptr. Incoming packet needs to be inserted in front of search ptr. * + * * + ****************************************************************************************/ + if(((int)(search_begin_sequence - packet_end_sequence)) >= 0) + { + /* packet_ptr is to the left of search_ptr. We are done. Break out of the while loop.*/ + break; + } + + /* At this point search_ptr and packet_ptr overlapps. */ + /**************************************************************************************** + * There are four cases:(P - packet_ptr, S - search_ptr) * + ****************************************************************************************/ + + + /**************************************************************************************** + * (3) PPPPPPPPPPPPPP * + * SSSSSSSSSSSSSSSSSSSSSSSS * + * In this configuration, the incoming packet is the same as the existing one, * + * or is a subset of the existing one. Remove the incoming packet. No need * + * to search for contigous data, therefore no need to wake up user thread. * + * Howerver may need to send out ACK if new packet is to the right of the seq * + * number. * + * * + ****************************************************************************************/ + if ((((int)(packet_begin_sequence - search_begin_sequence)) >= 0) && + (((int)(search_end_sequence - packet_end_sequence)) >= 0)) + { + + /* If the sequence number is to the right of the expected sequence number, force an ACK. */ + if (((int)(packet_begin_sequence - socket_ptr -> nx_tcp_socket_rx_sequence)) > 0) + { + /* Send an immediate ACK. */ + _nx_tcp_packet_send_ack(socket_ptr, socket_ptr -> nx_tcp_socket_tx_sequence); + } + + /* Since packet is not queued, return NX_FALSE so the caller releases the packet. */ + return(NX_FALSE); + } + + /**************************************************************************************** + * (4) PPPPPPPPPPPPPPPPPP * + * SSSSSSSSSSSSSSSS * + * In this configuration, New packet is a super-set of an existing packet. * + * Release existing packet, and insert new packet, then check for the next * + * packet on the chain. The next search may yield case (5). Need to check * + * for contingous data, may need to send ACK. * + * * + ****************************************************************************************/ + if ((((int)(search_begin_sequence - packet_begin_sequence)) >= 0) && + (((int)(packet_end_sequence - search_end_sequence) >= 0))) + { + NX_PACKET *tmp_ptr; + /* Release the search_ptr, and move to the next packet on the chain. */ + tmp_ptr = search_ptr -> nx_packet_tcp_queue_next; + + /* Mark the packet as no longer being part of the TCP queue. */ + search_ptr -> nx_packet_tcp_queue_next = (NX_PACKET *)NX_PACKET_ALLOCATED; + + /* Decrease the packet queue count */ + socket_ptr -> nx_tcp_socket_receive_queue_count--; + + /* Adjust the receive window. */ + + /* Release the search packet. */ + _nx_packet_release(search_ptr); + +#ifndef NX_DISABLE_TCP_INFO + /* The new packet has been admitted to the receive queue. */ + + /* Increment the TCP packet receive count and bytes received count. */ + ip_ptr -> nx_ip_tcp_packets_received--; + ip_ptr -> nx_ip_tcp_bytes_received -= (search_end_sequence - search_begin_sequence); + + /* Increment the TCP packet receive count and bytes received count for the socket. */ + socket_ptr -> nx_tcp_socket_packets_received--; + socket_ptr -> nx_tcp_socket_bytes_received -= (search_end_sequence - search_begin_sequence); + +#endif /* NX_DISABLE_TCP_INFO */ + + /* Move to the next packet. (note: no need to update previous_ptr. */ + search_ptr = tmp_ptr; + + /* Continue the search. */ + continue; + } + + + /**************************************************************************************** + * (5) PPPPPPPPPPPPPPPPPP * + * SSSSSSSSSSSS * + * In this configuration, remove data from the back of the new packet, insert * + * packet into the chain, and terminate the search. Need to search for * + * contigous data, may need to send out ACK. * + ****************************************************************************************/ + if ((((int)(search_begin_sequence - packet_begin_sequence)) >= 0) && + (((int)(search_end_sequence - packet_end_sequence)) > 0)) + { + + _nx_tcp_socket_state_data_trim(packet_ptr, (packet_end_sequence - search_begin_sequence)); + + /* Update packet_data_length. */ + packet_data_length -= (packet_end_sequence - search_begin_sequence); + + /* Now the packet should be chained before search_ptr. */ + + break; + } + + /**************************************************************************************** + * * + * (6) PPPPPPPPPPPPPP * + * SSSSSSSS * + * In this configuration, remove data from the beginning of the search_ptr, * + * insert the packet after the search packet and continue the search. This may * + * lead to case (2) and (3). * + * * + * * + ***************************************************************************************/ + if ((((int)(packet_begin_sequence - search_begin_sequence)) >= 0) && + (((int)(packet_end_sequence - search_begin_sequence)) > 0)) + { + _nx_tcp_socket_state_data_trim(search_ptr, (ULONG)(search_end_sequence - packet_begin_sequence)); + +#ifndef NX_DISABLE_TCP_INFO + /* The new packet has been admitted to the receive queue. */ + + /* Reduce the TCP bytes received count. */ + ip_ptr -> nx_ip_tcp_bytes_received -= (search_end_sequence - packet_begin_sequence); + + /* Reduce the TCP bytes received count for the socket. */ + socket_ptr -> nx_tcp_socket_bytes_received -= (search_end_sequence - packet_begin_sequence); + +#endif /* NX_DISABLE_TCP_INFO */ + + /* Move to the next packet and continue; */ + previous_ptr = search_ptr; + search_ptr = search_ptr -> nx_packet_tcp_queue_next; + continue; + } + + /* The logic should not get here! */ + } /* End of while (search_ptr) */ + + /* At this point, the logic (within the while loop) finds a location where this packet should be inserted. */ + if (previous_ptr == NX_NULL) + { + /* The packet needs to be inserted at the beginning of the queue. */ + socket_ptr -> nx_tcp_socket_receive_queue_head = packet_ptr; + } + else + { + /* The packet needs to be inserted after previous_ptr. */ + previous_ptr -> nx_packet_tcp_queue_next = packet_ptr; + } + + if (search_ptr == NX_NULL) + { + /* This packet is on the last one on the queue. */ + socket_ptr -> nx_tcp_socket_receive_queue_tail = packet_ptr; + /* Set the next pointer to indicate the packet is part of a TCP queue. */ + packet_ptr -> nx_packet_tcp_queue_next = (NX_PACKET *)NX_PACKET_ENQUEUED; + } + else + { + /* Chain search_ptr onto packet_ptr. */ + packet_ptr -> nx_packet_tcp_queue_next = search_ptr; + } + + /* Increment the receive TCP packet count. */ + socket_ptr -> nx_tcp_socket_receive_queue_count++; + + /* End of the out-of-order search. At this point, the packet has been inserted. */ + + /* Now we need to figure out how much, if any, we can ACK. */ + search_ptr = socket_ptr -> nx_tcp_socket_receive_queue_head; + + /* Setup a pointer to header of this packet in the sent list. */ + search_header_ptr = (NX_TCP_HEADER *)search_ptr -> nx_packet_prepend_ptr; + + /* Get the sequence number expected by the TCP receive socket. */ + expected_sequence = socket_ptr -> nx_tcp_socket_rx_sequence; + + /* Loop to see how much data is contiguous in the queued packets. */ + do + { + + /* Setup a pointer to header of this packet in the sent list. */ + search_header_ptr = (NX_TCP_HEADER *)search_ptr -> nx_packet_prepend_ptr; + + + /* Calculate the header size for this packet. */ + header_length = (search_header_ptr -> nx_tcp_header_word_3 >> NX_TCP_HEADER_SHIFT) * sizeof(ULONG); + + search_begin_sequence = search_header_ptr -> nx_tcp_sequence_number; + + search_end_sequence = search_begin_sequence + search_ptr -> nx_packet_length - header_length; + + if ((int)(expected_sequence - search_begin_sequence) >= 0) + { + + if ((int)(search_end_sequence - expected_sequence) > 0) + { + /* Sequence number is within this packet. Advance sequence number. */ + expected_sequence = search_end_sequence; + + socket_ptr -> nx_tcp_socket_rx_sequence = expected_sequence; + + acked_packets++; + + /* Mark this packet as ready for retrieval. */ + search_ptr -> nx_packet_queue_next = (NX_PACKET *)NX_PACKET_READY; + } + } + else if (search_ptr -> nx_packet_queue_next != (NX_PACKET *)NX_PACKET_READY) + { + + /* Expected number is to the left of search_ptr. Get out of the do-while loop! */ + break; + } + + /* Move the search pointer to the next queued receive packet. */ + search_ptr = search_ptr -> nx_packet_tcp_queue_next; + + /* Determine if we are at the end of the queue. */ + if (search_ptr == ((NX_PACKET *)NX_PACKET_ENQUEUED)) + { + + /* At the end, set the search pointer to NULL. */ + search_ptr = NX_NULL; + } + } while (search_ptr); + + /* If there are no packet crosses the rx_sequence, the TCP stream in the receive queue contains + missing pieces. */ + } /* End of out-of-order insertion. */ + + +#ifndef NX_DISABLE_TCP_INFO + /* The new packet has been admitted to the receive queue. */ + + /* Increment the TCP packet receive count and bytes received count. */ + ip_ptr -> nx_ip_tcp_packets_received++; + ip_ptr -> nx_ip_tcp_bytes_received += packet_data_length; + + /* Increment the TCP packet receive count and bytes received count for the socket. */ + socket_ptr -> nx_tcp_socket_packets_received++; + socket_ptr -> nx_tcp_socket_bytes_received += packet_data_length; +#endif + + /* Check if the rx sequence number has been updated. */ + if (original_rx_sequence != socket_ptr -> nx_tcp_socket_rx_sequence) + { + + /* Decrease the receive window size since rx_sequence is updated. */ + socket_ptr -> nx_tcp_socket_rx_window_current -= (socket_ptr -> nx_tcp_socket_rx_sequence - original_rx_sequence); + + /* Update the rx_window_last_sent for SWS avoidance algorithm. + RFC1122, Section4.2.3.3, Page97-98. */ + socket_ptr -> nx_tcp_socket_rx_window_last_sent -= (socket_ptr -> nx_tcp_socket_rx_sequence - original_rx_sequence); + } + +#ifdef NX_TCP_MAX_OUT_OF_ORDER_PACKETS + + /* Does the count of out of order packets exceed the defined value? */ + if ((socket_ptr -> nx_tcp_socket_receive_queue_count - acked_packets) > NX_TCP_MAX_OUT_OF_ORDER_PACKETS) + { + + /* Yes it is. Remove the last packet in queue. */ + socket_ptr -> nx_tcp_socket_receive_queue_tail -> nx_packet_tcp_queue_next = (NX_PACKET *)NX_PACKET_ALLOCATED; + + if (socket_ptr -> nx_tcp_socket_receive_queue_count > 1) + { + + /* Find the previous packet of tail. */ + search_ptr = socket_ptr -> nx_tcp_socket_receive_queue_head; + + while (search_ptr -> nx_packet_tcp_queue_next != socket_ptr -> nx_tcp_socket_receive_queue_tail) + { + search_ptr = search_ptr -> nx_packet_tcp_queue_next; + } + + /* Release the tail. */ + _nx_packet_release(socket_ptr -> nx_tcp_socket_receive_queue_tail); + + /* Setup the tail packet. */ + socket_ptr -> nx_tcp_socket_receive_queue_tail = search_ptr; + + search_ptr -> nx_packet_tcp_queue_next = (NX_PACKET *)NX_PACKET_ENQUEUED; + } + else + { + + /* Release the tail. */ + _nx_packet_release(socket_ptr -> nx_tcp_socket_receive_queue_tail); + + /* Clear the head and tail packets. */ + socket_ptr -> nx_tcp_socket_receive_queue_head = NX_NULL; + socket_ptr -> nx_tcp_socket_receive_queue_tail = NX_NULL; + } + + /* Decrease receive queue count. */ + socket_ptr -> nx_tcp_socket_receive_queue_count--; + } +#endif /* NX_TCP_MAX_OUT_OF_ORDER_PACKETS */ + + /* At this point, we can use the packet TCP header pointers since the received + packet is already queued. */ + + /* Any packets for receving? */ + while (acked_packets && socket_ptr -> nx_tcp_socket_receive_suspension_list) + { + + /* Setup a pointer to the first queued packet. */ + packet_ptr = socket_ptr -> nx_tcp_socket_receive_queue_head; + /* Remove it from the queue. */ + + /* Does the queue only have one entry?. */ + if (socket_ptr -> nx_tcp_socket_receive_queue_count == 1) + { + + /* Yes, single entry queue. Set both head and tail pointers to NULL. */ + socket_ptr -> nx_tcp_socket_receive_queue_head = NX_NULL; + socket_ptr -> nx_tcp_socket_receive_queue_tail = NX_NULL; + } + else + { + + /* Simply update the head pointer of the queue. The tail pointer does + not need update. */ + socket_ptr -> nx_tcp_socket_receive_queue_head = packet_ptr -> nx_packet_tcp_queue_next; + } + + /* Mark the packet as no longer being part of the TCP queue. */ + packet_ptr -> nx_packet_tcp_queue_next = (NX_PACKET *)NX_PACKET_ALLOCATED; + + /* Clear the queue next pointer. */ + packet_ptr -> nx_packet_queue_next = NX_NULL; + + /* Decrease the number of received packets. */ + socket_ptr -> nx_tcp_socket_receive_queue_count--; + + /* Adjust the packet for delivery to the suspended thread. */ + + /* Setup a pointer to the TCP header of this packet. */ + tcp_header_ptr = (NX_TCP_HEADER *)packet_ptr -> nx_packet_prepend_ptr; + + /* Calculate the header size for this packet. */ + header_length = (tcp_header_ptr -> nx_tcp_header_word_3 >> NX_TCP_HEADER_SHIFT) * sizeof(ULONG); + + /* Adjust the packet prepend pointer and length to position past the TCP header. */ + packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_prepend_ptr + header_length; + packet_ptr -> nx_packet_length = packet_ptr -> nx_packet_length - header_length; + + /* Setup a pointer to the first thread suspended on the receive queue. */ + thread_ptr = socket_ptr -> nx_tcp_socket_receive_suspension_list; + + /* Place the packet pointer in the return pointer. */ + *((NX_PACKET **)thread_ptr -> tx_thread_additional_suspend_info) = packet_ptr; + + /* Increase the receive window size. */ + socket_ptr -> nx_tcp_socket_rx_window_current += packet_ptr -> nx_packet_length; + + /* Determine if the new size is greater than the default window size. */ + if (socket_ptr -> nx_tcp_socket_rx_window_current > socket_ptr -> nx_tcp_socket_rx_window_default) + { + + /* Yes, new receive window size is greater than the socket's default, + adjust to the default window size. */ + socket_ptr -> nx_tcp_socket_rx_window_current = socket_ptr -> nx_tcp_socket_rx_window_default; + } + + /* Remove the suspended thread from the list. */ + + /* Decrement the suspension count. */ + socket_ptr -> nx_tcp_socket_receive_suspended_count--; + + /* Decrement the acked_packets count. */ + acked_packets--; + + /* Resume thread. */ + _nx_tcp_socket_thread_resume(&(socket_ptr -> nx_tcp_socket_receive_suspension_list), NX_SUCCESS); + } + + /* Determine if an ACK should be forced out for window update, SWS avoidance algorithm. + RFC1122, Section4.2.3.3, Page97-98. */ + if ((socket_ptr -> nx_tcp_socket_rx_window_current - socket_ptr -> nx_tcp_socket_rx_window_last_sent) >= (socket_ptr -> nx_tcp_socket_rx_window_default / 2)) + { + + /* Send a Window Update. */ + _nx_tcp_packet_send_ack(socket_ptr, socket_ptr -> nx_tcp_socket_tx_sequence); + } + + /* If the incoming packet caused the sequence number to move forward, + indicating the new piece of data is in order, in sequence, and valid for receiving. */ + if (original_rx_sequence != socket_ptr -> nx_tcp_socket_rx_sequence) + { + /* Determine if there is a socket receive notification function specified. */ + if (socket_ptr -> nx_tcp_receive_callback) + { + + /* Yes, notification is requested. Call the application's receive notification + function for this socket. */ + (socket_ptr -> nx_tcp_receive_callback)(socket_ptr); + } + +#ifdef NX_TCP_ACK_EVERY_N_PACKETS + /* Determine if we need to ACK up to the current sequence number. */ + + /* If we are still in an ESTABLISHED state, a FIN isn't present and we can + allocate a packet for the ACK message, send an ACK message. */ + if ((socket_ptr -> nx_tcp_socket_state == NX_TCP_ESTABLISHED) && + ((tcp_header_ptr -> nx_tcp_header_word_3 & NX_TCP_FIN_BIT) == 0)) + { + if (socket_ptr -> nx_tcp_socket_ack_n_packet_counter >= NX_TCP_ACK_EVERY_N_PACKETS) + { + socket_ptr -> nx_tcp_socket_ack_n_packet_counter = 1; + + /* Send an immediate ACK. */ + _nx_tcp_packet_send_ack(socket_ptr, socket_ptr -> nx_tcp_socket_tx_sequence); + } + else + { + socket_ptr -> nx_tcp_socket_ack_n_packet_counter++; + } + } +#endif + } + + /* Return true since the packet was queued. */ + return(NX_TRUE); +} + diff --git a/common/src/nx_tcp_socket_state_established.c b/common/src/nx_tcp_socket_state_established.c new file mode 100644 index 0000000..0bfa75e --- /dev/null +++ b/common/src/nx_tcp_socket_state_established.c @@ -0,0 +1,147 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_tcp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcp_socket_state_established PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes packets during the ESTABLISHED state, */ +/* the state of the socket during typical TCP data sending and */ +/* receiving. The expected packet that changes state once in the */ +/* established state is the FIN packet. Reception of this will move */ +/* the state for this socket to the CLOSE WAIT state. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to owning socket */ +/* tcp_header_ptr Pointer to packet header */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_tcp_packet_send_ack Send ACK message */ +/* (nx_tcp_disconnect_callback) Application's callback */ +/* function when disconnect */ +/* FIN is received */ +/* _nx_tcp_receive_cleanup Release thread(s) suspended */ +/* socket's receive queue */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_tcp_socket_packet_process Process TCP packet for socket */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_tcp_socket_state_established(NX_TCP_SOCKET *socket_ptr, NX_TCP_HEADER *tcp_header_ptr) +{ + +#if !defined(NX_DISABLE_TCP_INFO) || defined(TX_ENABLE_EVENT_TRACE) +NX_IP *ip_ptr; + + + /* Setup the IP pointer. */ + ip_ptr = socket_ptr -> nx_tcp_socket_ip_ptr; +#endif + + NX_PARAMETER_NOT_USED(tcp_header_ptr); + + /* Determine if a FIN has been previously detected in the _nx_tcp_socket_state_data_check + routine and if the socket's sequence number matches the expected FIN sequence number. */ + if ((socket_ptr -> nx_tcp_socket_fin_received) && + (socket_ptr -> nx_tcp_socket_fin_sequence == socket_ptr -> nx_tcp_socket_rx_sequence)) + { + +#ifndef NX_DISABLE_TCP_INFO + /* Increment the TCP disconnections count. */ + ip_ptr -> nx_ip_tcp_disconnections++; +#endif + +#ifdef NX_ENABLE_TCP_KEEPALIVE + /* Is the keepalive feature enabled on this socket? */ + if (socket_ptr -> nx_tcp_socket_keepalive_enabled) + { + + /* Clear the TCP Keepalive timer to disable it for this socket (only needed when + the socket is connected. */ + socket_ptr -> nx_tcp_socket_keepalive_timeout = 0; + socket_ptr -> nx_tcp_socket_keepalive_retries = 0; + } +#endif + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_TCP_STATE_CHANGE, ip_ptr, socket_ptr, socket_ptr -> nx_tcp_socket_state, NX_TCP_CLOSE_WAIT, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + /* The FIN bit is set, we need to go into the finished state. */ + socket_ptr -> nx_tcp_socket_state = NX_TCP_CLOSE_WAIT; + + /* Increment the received sequence. */ + socket_ptr -> nx_tcp_socket_rx_sequence++; + + /* Loop to release all threads suspended while trying to receive on the socket. */ + while (socket_ptr -> nx_tcp_socket_receive_suspension_list) + { + + /* Release the head of the receive suspension list. */ + _nx_tcp_receive_cleanup(socket_ptr -> nx_tcp_socket_receive_suspension_list NX_CLEANUP_ARGUMENT); + } + + /* Send ACK message. */ + _nx_tcp_packet_send_ack(socket_ptr, socket_ptr -> nx_tcp_socket_tx_sequence); + + /* If given, call the application's disconnect callback function + for disconnect. */ + if (socket_ptr -> nx_tcp_disconnect_callback) + { + + /* Call the application's disconnect handling function. It is + responsible for calling the socket disconnect function. */ + (socket_ptr -> nx_tcp_disconnect_callback)(socket_ptr); + } + } +} + diff --git a/common/src/nx_tcp_socket_state_fin_wait1.c b/common/src/nx_tcp_socket_state_fin_wait1.c new file mode 100644 index 0000000..d6f7e06 --- /dev/null +++ b/common/src/nx_tcp_socket_state_fin_wait1.c @@ -0,0 +1,189 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_tcp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcp_socket_state_fin_wait1 PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes packets during the FIN WAIT 1 state, */ +/* which is the state after the initial FIN was issued in an active */ +/* disconnect issued by the application. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to owning socket */ +/* tcp_header_ptr Pointer to packet header */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_tcp_packet_send_ack Send ACK message */ +/* _nx_tcp_socket_thread_resume Resume suspended thread */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_tcp_socket_packet_process Process TCP packet for socket */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_tcp_socket_state_fin_wait1(NX_TCP_SOCKET *socket_ptr, NX_TCP_HEADER *tcp_header_ptr) +{ + + + /* Determine if the incoming message is an ACK only message. If it is and + if it is proper, move into the FIN WAIT 2 state and do nothing else. */ + if ((tcp_header_ptr -> nx_tcp_header_word_3 & NX_TCP_ACK_BIT) && + (tcp_header_ptr -> nx_tcp_acknowledgment_number == socket_ptr -> nx_tcp_socket_tx_sequence) && + (!(tcp_header_ptr -> nx_tcp_header_word_3 & NX_TCP_FIN_BIT))) + { + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_TCP_STATE_CHANGE, socket_ptr -> nx_tcp_socket_ip_ptr, socket_ptr, socket_ptr -> nx_tcp_socket_state, NX_TCP_FIN_WAIT_2, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + /* We have a legitimate ACK message. Simply move into the WAIT FIN 2 state + for the other side to finish its processing and disconnect. */ + socket_ptr -> nx_tcp_socket_state = NX_TCP_FIN_WAIT_2; + + /* Otherwise, simply clear the FIN timeout. */ + socket_ptr -> nx_tcp_socket_timeout = 0; + } + else if ((tcp_header_ptr -> nx_tcp_header_word_3 & NX_TCP_ACK_BIT) && + (tcp_header_ptr -> nx_tcp_acknowledgment_number == socket_ptr -> nx_tcp_socket_tx_sequence) && + (tcp_header_ptr -> nx_tcp_header_word_3 & NX_TCP_FIN_BIT)) + { + + /* Is this a client socket?. */ + if (socket_ptr -> nx_tcp_socket_client_type) + { + + /* Yes, return the socket to the CLOSED state. */ + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_TCP_STATE_CHANGE, socket_ptr -> nx_tcp_socket_ip_ptr, socket_ptr, socket_ptr -> nx_tcp_socket_state, NX_TCP_CLOSED, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + /* Set the socket state to CLOSED now. */ + socket_ptr -> nx_tcp_socket_state = NX_TCP_CLOSED; + } + else + { + + /* No, this is a server socket. */ + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_TCP_STATE_CHANGE, socket_ptr -> nx_tcp_socket_ip_ptr, socket_ptr, socket_ptr -> nx_tcp_socket_state, NX_TCP_LISTEN_STATE, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + /* Set the socket state to LISTEN directly. */ + socket_ptr -> nx_tcp_socket_state = NX_TCP_LISTEN_STATE; + } + + /* Otherwise, simply clear the FIN timeout. */ + socket_ptr -> nx_tcp_socket_timeout = 0; + + /* Send ACK back to the other side of the connection. */ + + /* Increment the received sequence. */ + socket_ptr -> nx_tcp_socket_rx_sequence++; + + /* Send ACK message. */ + _nx_tcp_packet_send_ack(socket_ptr, socket_ptr -> nx_tcp_socket_tx_sequence); + + /* Determine if we need to wake a thread suspended on the connection. */ + if (socket_ptr -> nx_tcp_socket_disconnect_suspended_thread) + { + + /* Resume the thread suspended for the disconnect. */ + _nx_tcp_socket_thread_resume(&(socket_ptr -> nx_tcp_socket_disconnect_suspended_thread), NX_SUCCESS); + } + } + else if (tcp_header_ptr -> nx_tcp_header_word_3 & NX_TCP_FIN_BIT) + { + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_TCP_STATE_CHANGE, socket_ptr -> nx_tcp_socket_ip_ptr, socket_ptr, socket_ptr -> nx_tcp_socket_state, NX_TCP_CLOSING, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + /* Move to the CLOSING state for simultaneous close situation. */ + socket_ptr -> nx_tcp_socket_state = NX_TCP_CLOSING; + + /* Send ACK back to the other side of the connection. */ + + /* Increment the received sequence number. */ + socket_ptr -> nx_tcp_socket_rx_sequence++; + + /* Send ACK message. */ + _nx_tcp_packet_send_ack(socket_ptr, socket_ptr -> nx_tcp_socket_tx_sequence); + } + +#ifndef NX_DISABLE_EXTENDED_NOTIFY_SUPPORT + + /* If the socket connection is shut down, check if we need to notify the host application the + socket is entering the timed wait state. */ + if ((socket_ptr -> nx_tcp_socket_state == NX_TCP_CLOSED) || (socket_ptr -> nx_tcp_socket_state == NX_TCP_LISTEN_STATE)) + { + + + /* Is a timed wait callback registered for this socket? This puts the socket + in a timed wait state but returns immediately rather than block the IP thread entry. */ + if (socket_ptr -> nx_tcp_timed_wait_callback) + { + + (socket_ptr -> nx_tcp_timed_wait_callback)(socket_ptr); + return; + } + + + /* If registered with the TCP socket, call the application's disconnect complete function. */ + if (socket_ptr -> nx_tcp_disconnect_complete_notify) + { + + /* Call the application's disconnect_complete callback function. */ + (socket_ptr -> nx_tcp_disconnect_complete_notify)(socket_ptr); + } + } +#endif +} + diff --git a/common/src/nx_tcp_socket_state_fin_wait2.c b/common/src/nx_tcp_socket_state_fin_wait2.c new file mode 100644 index 0000000..a3ccb32 --- /dev/null +++ b/common/src/nx_tcp_socket_state_fin_wait2.c @@ -0,0 +1,153 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_tcp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcp_socket_state_fin_wait2 PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes packets during the FIN WAIT 2 state, */ +/* which is the state after the initial FIN was issued and the other */ +/* side of the connection issued an ACK. If a FIN is received in */ +/* this state, an ACK is sent back the disconnection is complete. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to owning socket */ +/* tcp_header_ptr Pointer to packet header */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_tcp_packet_send_ack Send ACK message */ +/* _nx_tcp_socket_thread_resume Resume suspended thread */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_tcp_socket_packet_process Process TCP packet for socket */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_tcp_socket_state_fin_wait2(NX_TCP_SOCKET *socket_ptr, NX_TCP_HEADER *tcp_header_ptr) +{ + + /* Determine if the incoming message is a FIN message signalling that the other + side of the connection is now ready disconnecting as well. */ + if (tcp_header_ptr -> nx_tcp_header_word_3 & NX_TCP_FIN_BIT) + { + + /* Return to the proper socket state. */ + + /* Is this a client socket? */ + if (socket_ptr -> nx_tcp_socket_client_type) + { + + /* Yes, return the socket to the CLOSED state. */ + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_TCP_STATE_CHANGE, socket_ptr -> nx_tcp_socket_ip_ptr, socket_ptr, socket_ptr -> nx_tcp_socket_state, NX_TCP_CLOSED, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + /* Set the socket state to CLOSED now. */ + socket_ptr -> nx_tcp_socket_state = NX_TCP_CLOSED; + } + else + { + + /* No this is a server socket. */ + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_TCP_STATE_CHANGE, socket_ptr -> nx_tcp_socket_ip_ptr, socket_ptr, socket_ptr -> nx_tcp_socket_state, NX_TCP_LISTEN_STATE, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + /* Set the socket state to LISTEN now. */ + socket_ptr -> nx_tcp_socket_state = NX_TCP_LISTEN_STATE; + } + + /* This socket should not have an active timeout. */ + socket_ptr -> nx_tcp_socket_timeout = 0; + + /* Send ACK back to the other side of the connection. */ + + /* Increment the received sequence number. */ + socket_ptr -> nx_tcp_socket_rx_sequence++; + + /* Send ACK message. */ + _nx_tcp_packet_send_ack(socket_ptr, socket_ptr -> nx_tcp_socket_tx_sequence); + + /* Determine if we need to wake a thread suspended on the connection. */ + if (socket_ptr -> nx_tcp_socket_disconnect_suspended_thread) + { + + /* Resume the thread suspended for the disconnect. */ + _nx_tcp_socket_thread_resume(&(socket_ptr -> nx_tcp_socket_disconnect_suspended_thread), NX_SUCCESS); + } + + +#ifndef NX_DISABLE_EXTENDED_NOTIFY_SUPPORT + + /* Is a timed wait callback registered for this socket? */ + if (socket_ptr -> nx_tcp_timed_wait_callback) + { + + /* Call the timed wait callback for this socket to let the host + know the socket can now be put in the timed wait state (if + the RE-USE ADDRESS socket option is not enabled). */ + (socket_ptr -> nx_tcp_timed_wait_callback)(socket_ptr); + + return; + } + + /* Is a disconnect complete callback registered with the TCP socket? */ + if (socket_ptr -> nx_tcp_disconnect_complete_notify) + { + + /* Call the application's disconnect_complete callback function. */ + (socket_ptr -> nx_tcp_disconnect_complete_notify)(socket_ptr); + } +#endif + } +} + diff --git a/common/src/nx_tcp_socket_state_last_ack.c b/common/src/nx_tcp_socket_state_last_ack.c new file mode 100644 index 0000000..c2e29c7 --- /dev/null +++ b/common/src/nx_tcp_socket_state_last_ack.c @@ -0,0 +1,130 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_tcp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcp_socket_state_last_ack PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes packets during the LAST ACK state, */ +/* which is the state at the end of a passive disconnect, i.e. a */ +/* disconnect issued by the other side of the connection. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to owning socket */ +/* tcp_header_ptr Pointer to packet header */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_tcp_socket_thread_resume Resume suspended thread */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_tcp_socket_packet_process Process TCP packet for socket */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_tcp_socket_state_last_ack(NX_TCP_SOCKET *socket_ptr, NX_TCP_HEADER *tcp_header_ptr) +{ + + /* Determine if the incoming message is an ACK message. If it is and + if it is proper, finish the disconnect. */ + if ((tcp_header_ptr -> nx_tcp_header_word_3 & NX_TCP_ACK_BIT) && + (tcp_header_ptr -> nx_tcp_acknowledgment_number == + socket_ptr -> nx_tcp_socket_tx_sequence)) + { + + /* Ensure the connect information is cleared. */ + socket_ptr -> nx_tcp_socket_connect_ip = 0; + socket_ptr -> nx_tcp_socket_connect_port = 0; + + /* Move the state back to CLOSED or LISTEN depending on the type of + socket we are processing. */ + if (socket_ptr -> nx_tcp_socket_client_type) + { + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_TCP_STATE_CHANGE, socket_ptr -> nx_tcp_socket_ip_ptr, socket_ptr, socket_ptr -> nx_tcp_socket_state, NX_TCP_CLOSED, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + /* Client socket, return to a CLOSED state. */ + socket_ptr -> nx_tcp_socket_state = NX_TCP_CLOSED; + } + else + { + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_TCP_STATE_CHANGE, socket_ptr -> nx_tcp_socket_ip_ptr, socket_ptr, socket_ptr -> nx_tcp_socket_state, NX_TCP_LISTEN_STATE, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + /* Server socket, return to LISTEN state. */ + socket_ptr -> nx_tcp_socket_state = NX_TCP_LISTEN_STATE; + } + + /* Otherwise, simply clear the FIN timeout. */ + socket_ptr -> nx_tcp_socket_timeout = 0; + + /* Determine if we need to wake a thread suspended on the disconnection. */ + if (socket_ptr -> nx_tcp_socket_disconnect_suspended_thread) + { + + /* Resume suspended thread. */ + _nx_tcp_socket_thread_resume(&(socket_ptr -> nx_tcp_socket_disconnect_suspended_thread), NX_SUCCESS); + } + +#ifndef NX_DISABLE_EXTENDED_NOTIFY_SUPPORT + + /* Is a disconnect callback registered with the TCP socket? */ + if (socket_ptr -> nx_tcp_disconnect_complete_notify) + { + + /* Call the application's disconnect_complete callback function. */ + (socket_ptr -> nx_tcp_disconnect_complete_notify)(socket_ptr); + } +#endif + } +} + diff --git a/common/src/nx_tcp_socket_state_syn_received.c b/common/src/nx_tcp_socket_state_syn_received.c new file mode 100644 index 0000000..9978a66 --- /dev/null +++ b/common/src/nx_tcp_socket_state_syn_received.c @@ -0,0 +1,266 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_tcp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcp_socket_state_syn_received PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes packets during the SYN RECEIVED state, */ +/* which is the state after the initial SYN message was responded to */ +/* with an SYN/ACK message. The expected value here is an ACK, which */ +/* will move us into an ESTABLISHED state ready for sending and */ +/* receiving of TCP data. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to owning socket */ +/* tcp_header_ptr Pointer to packet header */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_tcp_socket_thread_resume Resume suspended thread */ +/* _nx_tcp_packet_send_rst Send RST packet */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_tcp_socket_packet_process Process TCP packet for socket */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_tcp_socket_state_syn_received(NX_TCP_SOCKET *socket_ptr, NX_TCP_HEADER *tcp_header_ptr) +{ +UINT window_wrap_flag = NX_FALSE; +UINT outside_of_window; + + + /* Determine if the incoming message is an ACK message. If it is and + if it is proper, move into the ESTABLISHED state. */ + if ((tcp_header_ptr -> nx_tcp_header_word_3 & NX_TCP_ACK_BIT) && + (tcp_header_ptr -> nx_tcp_acknowledgment_number == + socket_ptr -> nx_tcp_socket_tx_sequence)) + { + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_TCP_STATE_CHANGE, socket_ptr -> nx_tcp_socket_ip_ptr, socket_ptr, socket_ptr -> nx_tcp_socket_state, NX_TCP_ESTABLISHED, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + /* Save the window size. */ + socket_ptr -> nx_tcp_socket_tx_window_advertised = tcp_header_ptr -> nx_tcp_header_word_3 & NX_LOWER_16_MASK; + +#ifdef NX_ENABLE_TCP_WINDOW_SCALING + + /* The window size advertised in the SYN packet is NEVER scaled. Therefore there is no + need to apply the scale shift. However validate snd_win_scale and rcv_win_scale. */ + if (socket_ptr -> nx_tcp_snd_win_scale_value == 0xFF) + { + /* Peer does not support window scale option. */ + socket_ptr -> nx_tcp_snd_win_scale_value = 0; + socket_ptr -> nx_tcp_rcv_win_scale_value = 0; + + /* Since peer does not offer window scaling feature, make sure + our default window size for this connection does not exceed 65535 bytes. */ + if (socket_ptr -> nx_tcp_socket_rx_window_maximum > 65535) + { + socket_ptr -> nx_tcp_socket_rx_window_default = 65535; + socket_ptr -> nx_tcp_socket_rx_window_current = 65535; + } + } + else if (socket_ptr -> nx_tcp_snd_win_scale_value > 14) + { + /* Otherwise make sure window scale is limited to 14, per RFC 1323 pp.11 */ + socket_ptr -> nx_tcp_snd_win_scale_value = 14; + } + +#endif /* NX_ENABLE_TCP_WINDOW_SCALING */ + + /* Set the initial slow start threshold to be the advertised window size. */ + socket_ptr -> nx_tcp_socket_tx_slow_start_threshold = socket_ptr -> nx_tcp_socket_tx_window_advertised; + + /* Set the initial congestion control window size. */ + /* Section 3.1, Page 5, RFC5681. */ + if (socket_ptr -> nx_tcp_socket_timeout_retries > 0) + { + + /* Set the initial congestion control window size to be the mss. */ + socket_ptr -> nx_tcp_socket_tx_window_congestion = socket_ptr -> nx_tcp_socket_connect_mss; + } + else + { + socket_ptr -> nx_tcp_socket_tx_window_congestion = (socket_ptr -> nx_tcp_socket_connect_mss << 2); + if (socket_ptr -> nx_tcp_socket_connect_mss > 1095) + { + socket_ptr -> nx_tcp_socket_tx_window_congestion -= socket_ptr -> nx_tcp_socket_connect_mss; + } + if (socket_ptr -> nx_tcp_socket_connect_mss > 2190) + { + socket_ptr -> nx_tcp_socket_tx_window_congestion -= socket_ptr -> nx_tcp_socket_connect_mss; + } + } + + /* Move into the ESTABLISHED state. */ + socket_ptr -> nx_tcp_socket_state = NX_TCP_ESTABLISHED; + +#ifndef NX_DISABLE_EXTENDED_NOTIFY_SUPPORT + + /* If registered with the TCP socket, call the application's connection completion callback function. */ + if (socket_ptr -> nx_tcp_establish_notify) + { + + /* Call the application's establish callback function. */ + (socket_ptr -> nx_tcp_establish_notify)(socket_ptr); + } +#endif + +#ifdef NX_ENABLE_TCP_KEEPALIVE + /* Is the keepalive feature enabled on this socket? */ + if (socket_ptr -> nx_tcp_socket_keepalive_enabled) + { + + /* Setup the TCP Keepalive timer to initial values. */ + socket_ptr -> nx_tcp_socket_keepalive_timeout = NX_TCP_KEEPALIVE_INITIAL; + socket_ptr -> nx_tcp_socket_keepalive_retries = 0; + } +#endif + + /* Update the value of nx_tcp_socket_rx_sequence_acked */ + socket_ptr -> nx_tcp_socket_rx_sequence_acked = socket_ptr -> nx_tcp_socket_rx_sequence; + + /* Determine if we need to wake a thread suspended on the connection. */ + if (socket_ptr -> nx_tcp_socket_connect_suspended_thread) + { + + /* Resume the suspended thread. */ + _nx_tcp_socket_thread_resume(&(socket_ptr -> nx_tcp_socket_connect_suspended_thread), NX_SUCCESS); + } + } + /* Check for another SYN received. */ + else if (tcp_header_ptr -> nx_tcp_header_word_3 & NX_TCP_SYN_BIT) + { + /* Determine if the window has wrapped. */ + if ((socket_ptr -> nx_tcp_socket_rx_sequence + socket_ptr -> nx_tcp_socket_rx_window_current) < socket_ptr -> nx_tcp_socket_rx_sequence) + { + + /* Window has wrapped so set the flag. */ + window_wrap_flag = NX_TRUE; + } + + /* Clear the outside of window flag. This will detect a packet outside of the current receive window - + including anything that has already been ACKed. */ + outside_of_window = NX_FALSE; + + /* Determine if this window is in a wrap condition. */ + if (window_wrap_flag == NX_FALSE) + { + + /* Window is not wrapped. Simply compare the sequence numbers. */ + + /* Is the new packet starting sequence number before the current receive sequence number? */ + if (tcp_header_ptr -> nx_tcp_sequence_number < socket_ptr -> nx_tcp_socket_rx_sequence) + { + + /* Yes, the incoming packet is before the receive window. */ + outside_of_window = NX_TRUE; + } + } + else + { + + /* Receive window is in a wrapped condition. */ + + /* Determine if the new packet starting sequence number is outside the receive window. */ + if ((tcp_header_ptr -> nx_tcp_sequence_number < socket_ptr -> nx_tcp_socket_rx_sequence) && + (tcp_header_ptr -> nx_tcp_sequence_number > (socket_ptr -> nx_tcp_socket_rx_sequence + socket_ptr -> nx_tcp_socket_rx_window_current))) + { + + /* Yes, the incoming packet is outside the receive window. */ + outside_of_window = NX_TRUE; + } + } + + /* If the SYN is in the window it is an error, send a reset. Enter the CLOSED state. */ + if (outside_of_window == NX_FALSE) + { + + /* Adjust the SEQ for the SYN bit. */ + /* The reset logic uses the sequence number in tcp_header_ptr as its ACK number. */ + tcp_header_ptr -> nx_tcp_sequence_number++; + + /* Send the RST packet. */ + _nx_tcp_packet_send_rst(socket_ptr, tcp_header_ptr); + + /* Move into the CLOSED state. */ + socket_ptr -> nx_tcp_socket_state = NX_TCP_CLOSED; + + /* This socket should not have an active timeout. */ + socket_ptr -> nx_tcp_socket_timeout = 0; + } + else + { + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_TCP_SYN_RECEIVE, socket_ptr -> nx_tcp_socket_ip_ptr, socket_ptr, NX_NULL, tcp_header_ptr -> nx_tcp_sequence_number, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + /* Resend the SYN/ACK response to the initial SYN message. */ + _nx_tcp_packet_send_syn(socket_ptr, (socket_ptr -> nx_tcp_socket_tx_sequence - 1)); + } + } + /* Check for an invalid ACK message that signals an error on the other side. */ + else if ((tcp_header_ptr -> nx_tcp_header_word_3 & NX_TCP_ACK_BIT) && + (tcp_header_ptr -> nx_tcp_acknowledgment_number != + socket_ptr -> nx_tcp_socket_tx_sequence)) + { + + /* Invalid response was received, it is likely that the other side still + thinks a previous connection is active. Send a reset (RST) message to + the other side to clear any previous connection. */ + + /* Send the RST packet. */ + _nx_tcp_packet_send_rst(socket_ptr, tcp_header_ptr); + } +} + diff --git a/common/src/nx_tcp_socket_state_syn_sent.c b/common/src/nx_tcp_socket_state_syn_sent.c new file mode 100644 index 0000000..8e9fc39 --- /dev/null +++ b/common/src/nx_tcp_socket_state_syn_sent.c @@ -0,0 +1,262 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_tcp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcp_socket_state_syn_sent PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes packets during the SYN SENT state, which is */ +/* the state of the socket immediately after the initial SYN is sent */ +/* in the establishment of a TCP connection. We are expecting a SYN */ +/* and an ACK from the other side of the connection in order to move */ +/* into an established state. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to owning socket */ +/* tcp_header_ptr Pointer to packet header */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_tcp_packet_send_ack Send ACK packet */ +/* _nx_tcp_packet_send_syn Send SYN packet */ +/* _nx_tcp_packet_send_rst Send RST packet */ +/* _nx_tcp_socket_thread_resume Resume suspended thread */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_tcp_socket_packet_process Process TCP packet for socket */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_tcp_socket_state_syn_sent(NX_TCP_SOCKET *socket_ptr, NX_TCP_HEADER *tcp_header_ptr) +{ + + + /* Determine if a valid SYN/ACK is present. */ + if ((tcp_header_ptr -> nx_tcp_header_word_3 & NX_TCP_SYN_BIT) && + (tcp_header_ptr -> nx_tcp_header_word_3 & NX_TCP_ACK_BIT) && + (tcp_header_ptr -> nx_tcp_acknowledgment_number == socket_ptr -> nx_tcp_socket_tx_sequence)) + { + + /* Yes, this is a proper SYN/ACK message. We need to send an ACK + back the other direction before we go into the ESTABLISHED + state. */ + + /* Save the sequence number. */ + socket_ptr -> nx_tcp_socket_rx_sequence = tcp_header_ptr -> nx_tcp_sequence_number + 1; + + /* Save the window size. */ + socket_ptr -> nx_tcp_socket_tx_window_advertised = tcp_header_ptr -> nx_tcp_header_word_3 & NX_LOWER_16_MASK; + +#ifdef NX_ENABLE_TCP_WINDOW_SCALING + + /* The window size advertised in the SYN packet is NEVER scaled. Therefore there is no + need to apply the scale shift. However validate snd_win_scale and rcv_win_scale. */ + if (socket_ptr -> nx_tcp_snd_win_scale_value == 0xFF) + { + /* Peer does not support window scale option. */ + socket_ptr -> nx_tcp_snd_win_scale_value = 0; + socket_ptr -> nx_tcp_rcv_win_scale_value = 0; + + /* Since the peer does not offer window scaling feature, make sure + our default window size for this connection does not exceed 65535 bytes. */ + if (socket_ptr -> nx_tcp_socket_rx_window_maximum > 65535) + { + socket_ptr -> nx_tcp_socket_rx_window_default = 65535; + socket_ptr -> nx_tcp_socket_rx_window_current = 65535; + } + } + else if (socket_ptr -> nx_tcp_snd_win_scale_value > 14) + { + /* Otherwise make sure window scale is limited to 14, per RFC 1323 pp.11 */ + socket_ptr -> nx_tcp_snd_win_scale_value = 14; + } + +#endif /* NX_ENABLE_TCP_WINDOW_SCALING */ + + /* Initialize the slow start threshold to be the advertised window size. */ + socket_ptr -> nx_tcp_socket_tx_slow_start_threshold = socket_ptr -> nx_tcp_socket_tx_window_advertised; + + /* Set the Initial transmit outstanding byte count. */ + socket_ptr -> nx_tcp_socket_tx_outstanding_bytes = 0; + + /* Set the initial congestion control window size. */ + /* Section 3.1, Page 5, RFC5681. */ + if (socket_ptr -> nx_tcp_socket_timeout_retries > 0) + { + + /* Set the initial congestion control window size to be the mss. */ + socket_ptr -> nx_tcp_socket_tx_window_congestion = socket_ptr -> nx_tcp_socket_connect_mss; + } + else + { + socket_ptr -> nx_tcp_socket_tx_window_congestion = (socket_ptr -> nx_tcp_socket_connect_mss << 2); + if (socket_ptr -> nx_tcp_socket_connect_mss > 1095) + { + socket_ptr -> nx_tcp_socket_tx_window_congestion -= socket_ptr -> nx_tcp_socket_connect_mss; + } + if (socket_ptr -> nx_tcp_socket_connect_mss > 2190) + { + socket_ptr -> nx_tcp_socket_tx_window_congestion -= socket_ptr -> nx_tcp_socket_connect_mss; + } + } + + /* Send the ACK. */ + _nx_tcp_packet_send_ack(socket_ptr, socket_ptr -> nx_tcp_socket_tx_sequence); + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_TCP_STATE_CHANGE, socket_ptr -> nx_tcp_socket_ip_ptr, socket_ptr, socket_ptr -> nx_tcp_socket_state, NX_TCP_ESTABLISHED, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + /* Move to the ESTABLISHED state. */ + socket_ptr -> nx_tcp_socket_state = NX_TCP_ESTABLISHED; + + /* Clear the socket timeout. */ + socket_ptr -> nx_tcp_socket_timeout = 0; + +#ifndef NX_DISABLE_EXTENDED_NOTIFY_SUPPORT + + /* Is a connection completion callback registered with the TCP socket? */ + if (socket_ptr -> nx_tcp_establish_notify) + { + + /* Call the application's establish callback function. */ + (socket_ptr -> nx_tcp_establish_notify)(socket_ptr); + } +#endif + +#ifdef NX_ENABLE_TCP_KEEPALIVE + /* Is the keepalive feature enabled on this socket? */ + if (socket_ptr -> nx_tcp_socket_keepalive_enabled) + { + + /* Setup the TCP Keepalive timer to initial values. */ + socket_ptr -> nx_tcp_socket_keepalive_timeout = NX_TCP_KEEPALIVE_INITIAL; + socket_ptr -> nx_tcp_socket_keepalive_retries = 0; + } +#endif + + /* Determine if we need to wake a thread suspended on the connection. */ + if (socket_ptr -> nx_tcp_socket_connect_suspended_thread) + { + + /* Resume the suspended thread. */ + _nx_tcp_socket_thread_resume(&(socket_ptr -> nx_tcp_socket_connect_suspended_thread), NX_SUCCESS); + } + } + else if ((tcp_header_ptr -> nx_tcp_header_word_3 & NX_TCP_SYN_BIT) && + (!(tcp_header_ptr -> nx_tcp_header_word_3 & NX_TCP_ACK_BIT))) + { + + /* A SYN message was received. We need to send both a SYN and ACK and move + to the SYN RECEIVED state. */ + + /* Save the sequence number. */ + socket_ptr -> nx_tcp_socket_rx_sequence = tcp_header_ptr -> nx_tcp_sequence_number + 1; + + /* Save the window size. */ + socket_ptr -> nx_tcp_socket_tx_window_advertised = tcp_header_ptr -> nx_tcp_header_word_3 & NX_LOWER_16_MASK; + +#ifdef NX_ENABLE_TCP_WINDOW_SCALING + socket_ptr -> nx_tcp_socket_tx_window_advertised <<= socket_ptr -> nx_tcp_rcv_win_scale_value; +#endif /* NX_ENABLE_TCP_WINDOW_SCALING */ + + /* Initialize the slow start threshold to be the advertised window size. */ + socket_ptr -> nx_tcp_socket_tx_slow_start_threshold = socket_ptr -> nx_tcp_socket_tx_window_advertised; + + /* Set the initial congestion control window size. */ + /* Section 3.1, Page 5, RFC5681. */ + socket_ptr -> nx_tcp_socket_tx_window_congestion = (socket_ptr -> nx_tcp_socket_connect_mss << 2); + if (socket_ptr -> nx_tcp_socket_connect_mss > 1095) + { + socket_ptr -> nx_tcp_socket_tx_window_congestion -= socket_ptr -> nx_tcp_socket_connect_mss; + } + if (socket_ptr -> nx_tcp_socket_connect_mss > 2190) + { + socket_ptr -> nx_tcp_socket_tx_window_congestion -= socket_ptr -> nx_tcp_socket_connect_mss; + } + + /* Set the Initial transmit outstanding byte count. */ + socket_ptr -> nx_tcp_socket_tx_outstanding_bytes = 0; + + /* Increment the transmit sequence number. */ + socket_ptr -> nx_tcp_socket_tx_sequence++; + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_TCP_STATE_CHANGE, socket_ptr -> nx_tcp_socket_ip_ptr, socket_ptr, socket_ptr -> nx_tcp_socket_state, NX_TCP_SYN_RECEIVED, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + /* Move to the SYN RECEIVED state. */ + socket_ptr -> nx_tcp_socket_state = NX_TCP_SYN_RECEIVED; + + /* Clear the timeout. */ + socket_ptr -> nx_tcp_socket_timeout = 0; + + /* Send the SYN packet. */ + _nx_tcp_packet_send_syn(socket_ptr, (socket_ptr -> nx_tcp_socket_tx_sequence - 1)); + } + /* Check for an invalid response to an attempted connection. */ + else if ((tcp_header_ptr -> nx_tcp_header_word_3 & NX_TCP_ACK_BIT) && + (tcp_header_ptr -> nx_tcp_acknowledgment_number != socket_ptr -> nx_tcp_socket_tx_sequence)) + { + + /* Invalid response was received, it is likely that the other side still + thinks a previous connection is active. Send a reset (RST) message to + the other side to clear any previous connection. */ + + /* Adjust the SEQ for the SYN bit. */ + /* Note that in the RST message, the ACK number is set to the SYN in tcp_header_ptr. */ + if (tcp_header_ptr -> nx_tcp_header_word_3 & NX_TCP_SYN_BIT) + { + tcp_header_ptr -> nx_tcp_sequence_number++; + } + + /* Send the RST packet. */ + _nx_tcp_packet_send_rst(socket_ptr, tcp_header_ptr); + } +} + diff --git a/common/src/nx_tcp_socket_state_transmit_check.c b/common/src/nx_tcp_socket_state_transmit_check.c new file mode 100644 index 0000000..56f621a --- /dev/null +++ b/common/src/nx_tcp_socket_state_transmit_check.c @@ -0,0 +1,208 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_packet.h" +#include "nx_tcp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcp_socket_state_transmit_check PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function determines if the new receive window value is large */ +/* enough to satisfy a thread suspended trying to send data on the TCP */ +/* connection. This is typically called from the ESTABLISHED state. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to owning socket */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_ip_packet_send Send IP packet */ +/* _nx_tcp_socket_thread_resume Resume suspended thread */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_tcp_socket_packet_process Process TCP packet for socket */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_tcp_socket_state_transmit_check(NX_TCP_SOCKET *socket_ptr) +{ + +NX_IP *ip_ptr; +NX_PACKET *packet_ptr; +TX_THREAD *thread_ptr; +ULONG tx_window_current; + + + /* Setup the IP pointer. */ + ip_ptr = socket_ptr -> nx_tcp_socket_ip_ptr; + + /* Now check to see if there is a thread suspended attempting to transmit. */ + if (socket_ptr -> nx_tcp_socket_transmit_suspension_list) + { + + /* Yes, a thread is suspended attempting to transmit when the transmit window + is lower than its request size. Determine if the current transmit window + size can now accommodate the request. */ + + /* Setup a thread pointer. */ + thread_ptr = socket_ptr -> nx_tcp_socket_transmit_suspension_list; + + /* Pickup the packet the thread is trying to send. */ + packet_ptr = (NX_PACKET *)thread_ptr -> tx_thread_additional_suspend_info; + + /* Pick up the min(cwnd, swnd) */ + if (socket_ptr -> nx_tcp_socket_tx_window_advertised > socket_ptr -> nx_tcp_socket_tx_window_congestion) + { + tx_window_current = socket_ptr -> nx_tcp_socket_tx_window_congestion; + + /* On the first and second duplicate ACKs received, the total FlightSize would + remain less than or equal to cwnd plus 2*SMSS. + Section 3.2, Page 9, RFC5681. */ + if ((socket_ptr -> nx_tcp_socket_duplicated_ack_received == 1) || + (socket_ptr -> nx_tcp_socket_duplicated_ack_received == 2)) + { + tx_window_current += (socket_ptr -> nx_tcp_socket_connect_mss << 1); + } + } + else + { + tx_window_current = socket_ptr -> nx_tcp_socket_tx_window_advertised; + } + + /* Substract any data transmitted but unacked (outstanding bytes) */ + if (tx_window_current > socket_ptr -> nx_tcp_socket_tx_outstanding_bytes) + { + tx_window_current -= socket_ptr -> nx_tcp_socket_tx_outstanding_bytes; + } + else /* Set tx_window_current to zero. */ + { + tx_window_current = 0; + } + + + /* Determine if the current transmit window (received from the connected socket) + is large enough to handle the transmit. */ + if ((tx_window_current >= (packet_ptr -> nx_packet_length - sizeof(NX_TCP_HEADER))) && + (socket_ptr -> nx_tcp_socket_transmit_sent_count < socket_ptr -> nx_tcp_socket_transmit_queue_maximum)) + { + + /* Is NetX set up with a window update callback? */ + if (socket_ptr -> nx_tcp_socket_window_update_notify) + { + + /* Yes; Call this function when there is a change in transmit window size. */ + (socket_ptr -> nx_tcp_socket_window_update_notify)(socket_ptr); + } + + /* Send the packet. */ + + /* Yes, the packet can be sent. Place the packet on the sent list. */ + if (socket_ptr -> nx_tcp_socket_transmit_sent_head) + { + + /* Yes, other packets are on the list already. Just add this one to the tail. */ + (socket_ptr -> nx_tcp_socket_transmit_sent_tail) -> nx_packet_tcp_queue_next = packet_ptr; + socket_ptr -> nx_tcp_socket_transmit_sent_tail = packet_ptr; + } + else + { + /* Empty list, just setup the head and tail to the current packet. */ + socket_ptr -> nx_tcp_socket_transmit_sent_head = packet_ptr; + socket_ptr -> nx_tcp_socket_transmit_sent_tail = packet_ptr; + + /* Setup a transmit timeout for this packet. */ + socket_ptr -> nx_tcp_socket_timeout = socket_ptr -> nx_tcp_socket_timeout_rate; + socket_ptr -> nx_tcp_socket_timeout_retries = 0; + } + + /* Set the next pointer to indicate the packet is on a TCP queue. */ + packet_ptr -> nx_packet_tcp_queue_next = (NX_PACKET *)NX_PACKET_ENQUEUED; + + /* Increment the packet sent count. */ + socket_ptr -> nx_tcp_socket_transmit_sent_count++; + + /* Increase the outstanding byte count. */ + socket_ptr -> nx_tcp_socket_tx_outstanding_bytes += + (packet_ptr -> nx_packet_length - sizeof(NX_TCP_HEADER)); + + /* Adjust the transmit sequence number to reflect the output data. */ + socket_ptr -> nx_tcp_socket_tx_sequence = socket_ptr -> nx_tcp_socket_tx_sequence + + (packet_ptr -> nx_packet_length - sizeof(NX_TCP_HEADER)); + + /* The packet is already in the native endian format so just send it out + the IP interface. */ + +#ifndef NX_DISABLE_TCP_INFO + /* Increment the TCP packet sent count and bytes sent count. */ + ip_ptr -> nx_ip_tcp_packets_sent++; + ip_ptr -> nx_ip_tcp_bytes_sent += packet_ptr -> nx_packet_length - sizeof(NX_TCP_HEADER); + + /* Increment the TCP packet sent count and bytes sent count for the socket. */ + socket_ptr -> nx_tcp_socket_packets_sent++; + socket_ptr -> nx_tcp_socket_bytes_sent += packet_ptr -> nx_packet_length - sizeof(NX_TCP_HEADER); +#endif + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_TCP_DATA_SEND, ip_ptr, socket_ptr, packet_ptr, socket_ptr -> nx_tcp_socket_tx_sequence - (packet_ptr -> nx_packet_length - sizeof(NX_TCP_HEADER)), NX_TRACE_INTERNAL_EVENTS, 0, 0) + + + /* Send the TCP packet to the IP component. */ + _nx_ip_packet_send(ip_ptr, packet_ptr, socket_ptr -> nx_tcp_socket_connect_ip, + socket_ptr -> nx_tcp_socket_type_of_service, socket_ptr -> nx_tcp_socket_time_to_live, NX_IP_TCP, socket_ptr -> nx_tcp_socket_fragment_enable); + + /* Decrement the suspension count. */ + socket_ptr -> nx_tcp_socket_transmit_suspended_count--; + + /* Remove the suspended thread from the list. */ + _nx_tcp_socket_thread_resume(&(socket_ptr -> nx_tcp_socket_transmit_suspension_list), NX_SUCCESS); + } + } +} + diff --git a/common/src/nx_tcp_socket_state_wait.c b/common/src/nx_tcp_socket_state_wait.c new file mode 100644 index 0000000..377cef6 --- /dev/null +++ b/common/src/nx_tcp_socket_state_wait.c @@ -0,0 +1,116 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_tcp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcp_socket_state_wait PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function waits for the specified socket to reach the specified */ +/* TCP state. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to socket */ +/* desired_state Desired TCP state */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_thread_sleep Sleep to wait for state change*/ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_tcp_socket_state_wait(NX_TCP_SOCKET *socket_ptr, UINT desired_state, ULONG wait_option) +{ + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_TCP_SOCKET_STATE_WAIT, socket_ptr -> nx_tcp_socket_ip_ptr, socket_ptr, desired_state, socket_ptr -> nx_tcp_socket_state, NX_TRACE_TCP_EVENTS, 0, 0) + + /* Loop to wait for the desired socket state. */ + do + { + + /* Determine if the socket pointer is still valid. */ + if (socket_ptr -> nx_tcp_socket_id != NX_TCP_ID) + { + + /* Not still valid, return an error. */ + return(NX_PTR_ERROR); + } + + /* Determine if the desired state is present. */ + if (socket_ptr -> nx_tcp_socket_state == desired_state) + { + + /* The desired state is present, return success! */ + return(NX_SUCCESS); + } + + /* Check to see if there is more time to wait. */ + if (wait_option) + { + + /* Yes, there is more time... sleep for a tick. */ + tx_thread_sleep(1); + + /* Decrease the wait time. */ + wait_option--; + } + else + { + + /* Timeout, just return an error. */ + return(NX_NOT_SUCCESSFUL); + } + } while (NX_FOREVER); +} + diff --git a/common/src/nx_tcp_socket_thread_resume.c b/common/src/nx_tcp_socket_thread_resume.c new file mode 100644 index 0000000..ae1a52c --- /dev/null +++ b/common/src/nx_tcp_socket_thread_resume.c @@ -0,0 +1,150 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_tcp.h" +#include "tx_thread.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcp_socket_thread_resume PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function resumes a thread suspended on a TCP service within */ +/* NetX. */ +/* */ +/* INPUT */ +/* */ +/* thread_ptr Pointer to thread to resume */ +/* status Return status */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _tx_thread_system_resume Resume suspended thread */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_tcp_client_socket_unbind Client socket unbind */ +/* processing */ +/* _nx_tcp_socket_connection_reset Received reset processing */ +/* _nx_tcp_socket_state_closing Socket state closing */ +/* processing */ +/* _nx_tcp_socket_state_data_check Socket data check processing */ +/* _nx_tcp_socket_state_fin_wait2 Socket FIN wait-2 processing */ +/* _nx_tcp_socket_state_fin_wait1 Socket FIN wait-1 processing */ +/* _nx_tcp_socket_state_last_ack Socket last ack processing */ +/* _nx_tcp_socket_state_syn_received Socket SYN received */ +/* processing */ +/* _nx_tcp_socket_state_syn_sent Socket SYN sent processing */ +/* _nx_tcp_socket_state_transmit_check Socket transmit check */ +/* processing */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_tcp_socket_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 + } +} + diff --git a/common/src/nx_tcp_socket_thread_suspend.c b/common/src/nx_tcp_socket_thread_suspend.c new file mode 100644 index 0000000..cb454ad --- /dev/null +++ b/common/src/nx_tcp_socket_thread_suspend.c @@ -0,0 +1,144 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_tcp.h" +#include "tx_thread.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcp_socket_thread_suspend PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function suspends a thread on a TCP service within */ +/* NetX. */ +/* */ +/* 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 */ +/* */ +/* _nx_tcp_client_socket_bind Client socket bind processing */ +/* _nx_tcp_client_socket_connect Client socket connect */ +/* processing */ +/* _nx_tcp_socket_disconnect Socket disconnect processing */ +/* _nx_tcp_socket_receive Socket receive processing */ +/* _nx_tcp_socket_send Socket send processing */ +/* _nx_tcp_server_socket_accept Server socket accept */ +/* processing */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_tcp_socket_thread_suspend(TX_THREAD **suspension_list_head, VOID (*suspend_cleanup)(TX_THREAD *NX_CLEANUP_PARAMETER), NX_TCP_SOCKET *socket_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 *)socket_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); +} + diff --git a/common/src/nx_tcp_socket_timed_wait_callback.c b/common/src/nx_tcp_socket_timed_wait_callback.c new file mode 100644 index 0000000..a45425c --- /dev/null +++ b/common/src/nx_tcp_socket_timed_wait_callback.c @@ -0,0 +1,97 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_tcp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcp_socket_timed_wait_callback PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets the timed wait callback function pointer */ +/* to the function specified by the application, which is called when */ +/* it is time to start the timed wait state before a socket can be set */ +/* to the closed or listen state. */ +/* */ +/* socket_ptr Pointer to TCP socket */ +/* tcp_timed_wait_callback Routine to call to start */ +/* timed wait before close */ +/* */ +/* 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_tcp_socket_timed_wait_callback(NX_TCP_SOCKET *socket_ptr, VOID (*tcp_timed_wait_callback)(NX_TCP_SOCKET *socket_ptr)) +{ + +#ifndef NX_DISABLE_EXTENDED_NOTIFY_SUPPORT +TX_INTERRUPT_SAVE_AREA + + + /* Disable interrupts. */ + TX_DISABLE + + /* Setup the establish notify function pointer. */ + socket_ptr -> nx_tcp_timed_wait_callback = tcp_timed_wait_callback; + + /* Restore interrupts. */ + TX_RESTORE + + /* Return successful completion. */ + return(NX_SUCCESS); +#else /* NX_DISABLE_EXTENDED_NOTIFY_SUPPORT */ + NX_PARAMETER_NOT_USED(socket_ptr); + NX_PARAMETER_NOT_USED(tcp_timed_wait_callback); + + return(NX_NOT_SUPPORTED); +#endif /* NX_DISABLE_EXTENDED_NOTIFY_SUPPORT */ +} + diff --git a/common/src/nx_tcp_socket_transmit_configure.c b/common/src/nx_tcp_socket_transmit_configure.c new file mode 100644 index 0000000..114ea3b --- /dev/null +++ b/common/src/nx_tcp_socket_transmit_configure.c @@ -0,0 +1,110 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_tcp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcp_socket_transmit_configure PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets up various parameters associated with the */ +/* socket's transmit operation. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to TCP socket */ +/* max_queue_depth Maximum number of transmit */ +/* packets that can be queued */ +/* for the socket */ +/* timeout Number of timer ticks for the */ +/* initial transmit timeout */ +/* max_retries Maximum number of retries */ +/* timeout_shift Factor to be applied to */ +/* subsequent timeouts, a */ +/* value of 0 causes identical */ +/* subsequent timeouts */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Obtain a protection mutex */ +/* tx_mutex_put Release a protection mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_tcp_socket_transmit_configure(NX_TCP_SOCKET *socket_ptr, ULONG max_queue_depth, + ULONG timeout, ULONG max_retries, ULONG timeout_shift) +{ + +NX_IP *ip_ptr; + + + /* Pickup the associated IP structure. */ + ip_ptr = socket_ptr -> nx_tcp_socket_ip_ptr; + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_TCP_SOCKET_TRANSMIT_CONFIGURE, ip_ptr, socket_ptr, max_queue_depth, timeout, NX_TRACE_TCP_EVENTS, 0, 0) + + /* Obtain the IP mutex so we can initiate accept processing for this socket. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Setup the socket with the new transmit parameters. */ + socket_ptr -> nx_tcp_socket_timeout_rate = timeout; + socket_ptr -> nx_tcp_socket_timeout_max_retries = max_retries; + socket_ptr -> nx_tcp_socket_timeout_shift = timeout_shift; + socket_ptr -> nx_tcp_socket_transmit_queue_maximum_default = max_queue_depth; + socket_ptr -> nx_tcp_socket_transmit_queue_maximum = max_queue_depth; + + /* Release the IP protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return completion status. */ + return(NX_SUCCESS); +} + diff --git a/common/src/nx_tcp_socket_transmit_queue_flush.c b/common/src/nx_tcp_socket_transmit_queue_flush.c new file mode 100644 index 0000000..40a5259 --- /dev/null +++ b/common/src/nx_tcp_socket_transmit_queue_flush.c @@ -0,0 +1,129 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_packet.h" +#include "nx_tcp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcp_socket_transmit_queue_flush PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function releases all packets in the specified socket's */ +/* transmit queue. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to socket */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_packet_release Release a packet */ +/* */ +/* CALLED BY */ +/* */ +/* _nx_tcp_socket_connection_reset Socket connection reset */ +/* processing */ +/* _nx_tcp_socket_disconnect Socket disconnect processing */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_tcp_socket_transmit_queue_flush(NX_TCP_SOCKET *socket_ptr) +{ + +TX_INTERRUPT_SAVE_AREA + +NX_PACKET *packet_ptr; +NX_PACKET *next_packet_ptr; + + + /* Setup packet pointer. */ + packet_ptr = socket_ptr -> nx_tcp_socket_transmit_sent_head; + + /* Clear the head and the tail pointers. */ + socket_ptr -> nx_tcp_socket_transmit_sent_head = NX_NULL; + socket_ptr -> nx_tcp_socket_transmit_sent_tail = NX_NULL; + + /* Loop to clear all the packets out. */ + while (socket_ptr -> nx_tcp_socket_transmit_sent_count) + { + + /* Disable interrupts. */ + TX_DISABLE + + /* Pickup the next queued packet. */ + next_packet_ptr = packet_ptr -> nx_packet_tcp_queue_next; + + /* Mark the packet as no longer being in a TCP queue. */ + packet_ptr -> nx_packet_tcp_queue_next = (NX_PACKET *)NX_PACKET_ALLOCATED; + + /* Has the packet been transmitted? */ + if (packet_ptr -> nx_packet_queue_next == ((NX_PACKET *)NX_DRIVER_TX_DONE)) + { + + /* Yes, the driver has already released the packet. */ + + /* Restore interrupts. */ + TX_RESTORE + + /* Release the packet. */ + _nx_packet_release(packet_ptr); + } + else + { + + /* Just restore interrupts. */ + TX_RESTORE + } + + /* Move to the next packet. */ + packet_ptr = next_packet_ptr; + + /* Decrease the queued packet count. */ + socket_ptr -> nx_tcp_socket_transmit_sent_count--; + } +} + diff --git a/common/src/nx_tcp_socket_window_update_notify_set.c b/common/src/nx_tcp_socket_window_update_notify_set.c new file mode 100644 index 0000000..cfaf64d --- /dev/null +++ b/common/src/nx_tcp_socket_window_update_notify_set.c @@ -0,0 +1,98 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_tcp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcp_socket_window_update_notify_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets the window update notify function pointer to the */ +/* function specified by the application, which is called whenever */ +/* the specified socket receives a packet indicating an increase in */ +/* window size of the remote host. */ +/* */ +/* If a NULL pointer is supplied, the window update notify function is */ +/* disabled. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to TCP socket */ +/* tcp_window_udpate_notify Routine to call when NetX */ +/* receives a window update */ +/* */ +/* 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_tcp_socket_window_update_notify_set(NX_TCP_SOCKET *socket_ptr, + VOID (*tcp_socket_window_update_notify)(NX_TCP_SOCKET *socket_ptr)) +{ +TX_INTERRUPT_SAVE_AREA + + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_TCP_SOCKET_WINDOW_UPDATE_NOTIFY_SET, socket_ptr, 0, 0, 0, NX_TRACE_TCP_EVENTS, 0, 0) + + /* Disable interrupts. */ + TX_DISABLE + + /* Setup the receive notify function pointer. */ + socket_ptr -> nx_tcp_socket_window_update_notify = tcp_socket_window_update_notify; + + /* Restore interrupts. */ + TX_RESTORE + + /* Return successful completion. */ + return(NX_SUCCESS); +} + diff --git a/common/src/nx_tcp_transmit_cleanup.c b/common/src/nx_tcp_transmit_cleanup.c new file mode 100644 index 0000000..12eb02e --- /dev/null +++ b/common/src/nx_tcp_transmit_cleanup.c @@ -0,0 +1,229 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "tx_thread.h" +#include "tx_timer.h" +#include "nx_ip.h" +#include "nx_tcp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_tcp_transmit_cleanup PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes TCP transmit timeout and thread terminate */ +/* actions that require the TCP socket 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 */ +/* */ +/* _nx_tcp_deferred_cleanup_check Deferred cleanup processing */ +/* _nx_tcp_socket_disconnect Disconnect processing */ +/* _nx_tcp_socket_connection_reset Reset processing */ +/* _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_tcp_transmit_cleanup(TX_THREAD *thread_ptr NX_CLEANUP_PARAMETER) +{ + +TX_INTERRUPT_SAVE_AREA + +NX_TCP_SOCKET *socket_ptr; /* Working socket pointer */ +NX_IP *ip_ptr; + + NX_CLEANUP_EXTENSION + + /* Disable interrupts. */ + TX_DISABLE + + /* Setup pointer to TCP socket control block. */ + socket_ptr = (NX_TCP_SOCKET *)thread_ptr -> tx_thread_suspend_control_block; + + /* Determine if the socket pointer is valid. */ + if ((!socket_ptr) || (socket_ptr -> nx_tcp_socket_id != NX_TCP_ID)) + { + + /* 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 NetX IP thread. */ + + /* Under interrupt protection, see if the suspension is still in effect. */ + if ((thread_ptr -> tx_thread_suspend_cleanup) && (socket_ptr) && (socket_ptr -> nx_tcp_socket_id == NX_TCP_ID)) + { + + /* Yes, change the suspend cleanup routine to indicate the cleanup is deferred. */ + thread_ptr -> tx_thread_suspend_cleanup = _nx_tcp_cleanup_deferred; + + /* Pickup the IP pointer. */ + ip_ptr = socket_ptr -> nx_tcp_socket_ip_ptr; + + /* Restore interrupts. */ + TX_RESTORE + + /* Set the deferred cleanup flag for the IP thread. */ + tx_event_flags_set(&(ip_ptr -> nx_ip_events), NX_IP_TCP_CLEANUP_DEFERRED, TX_OR); + + /* Return to caller. */ + return; + } + else + { + + /* Restore interrupts. */ + TX_RESTORE + + /* Return to caller. */ + return; + } + } + + /* Determine if the cleanup is still required. */ + if ((thread_ptr -> tx_thread_suspend_cleanup) && (socket_ptr) && (socket_ptr -> nx_tcp_socket_id == NX_TCP_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. */ + socket_ptr -> nx_tcp_socket_transmit_suspension_list = NX_NULL; + } + else + { + + /* At least one more thread is on the same suspension list. */ + + /* Update the list head pointer. */ + socket_ptr -> nx_tcp_socket_transmit_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. */ + socket_ptr -> nx_tcp_socket_transmit_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 TCP socket. Setup return error status and + resume the thread. */ + + /* Determine which transmit error is present. */ + if (socket_ptr -> nx_tcp_socket_state != NX_TCP_ESTABLISHED) + { + + /* This socket is no longer connected. */ + thread_ptr -> tx_thread_suspend_status = NX_NOT_CONNECTED; + } + else if (socket_ptr -> nx_tcp_socket_transmit_sent_count < socket_ptr -> nx_tcp_socket_transmit_queue_maximum) + { + + /* Not a queue depth problem, return a window overflow error. */ + thread_ptr -> tx_thread_suspend_status = NX_WINDOW_OVERFLOW; + } + else + { + + /* Return a transmit queue exceeded error. */ + thread_ptr -> tx_thread_suspend_status = NX_TX_QUEUE_DEPTH; + } + + /* Temporarily disable preemption. */ + _tx_thread_preempt_disable++; + + /* Restore interrupts. */ + TX_RESTORE + + /* Resume the thread! */ + _tx_thread_system_resume(thread_ptr); + + /* Finished, just return. */ + return; + } + } + + /* Restore interrupts. */ + TX_RESTORE +} + diff --git a/common/src/nx_trace_event_insert.c b/common/src/nx_trace_event_insert.c new file mode 100644 index 0000000..72a6b6f --- /dev/null +++ b/common/src/nx_trace_event_insert.c @@ -0,0 +1,139 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Trace */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifndef NX_SOURCE_CODE +#define NX_SOURCE_CODE +#endif + + +/* Include necessary system files. */ + +#include "nx_api.h" + +#ifdef TX_ENABLE_EVENT_TRACE +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_trace_event_insert PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function inserts a NetX event into the current trace buffer. */ +/* */ +/* INPUT */ +/* */ +/* event_id User Event ID */ +/* info_field_1 First information field */ +/* info_field_2 First information field */ +/* info_field_3 First information field */ +/* info_field_4 First information field */ +/* current_event Current event pointer for */ +/* post event update */ +/* current_timestamp Timestamp for post event */ +/* update */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Internal NetX Functions */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_trace_event_insert(ULONG event_id, ULONG info_field_1, ULONG info_field_2, ULONG info_field_3, ULONG info_field_4, ULONG filter, TX_TRACE_BUFFER_ENTRY **current_event, ULONG *current_timestamp) +{ + +TX_INTERRUPT_SAVE_AREA + +TX_TRACE_BUFFER_ENTRY *event; +ULONG timestamp; + + + /* Disable interrupts. */ + TX_DISABLE + + /* Pickup the current event. */ + event = _tx_trace_buffer_current_ptr; + + /* Insert this event into the trace buffer. */ + TX_TRACE_IN_LINE_INSERT(event_id, info_field_1, info_field_2, info_field_3, info_field_4, filter); + + /* Initialize the timestamp to 0. */ + timestamp = 0; + + /* Determine if the event was inserted. */ + if (event) + { + + /* Was the event inserted? */ + if (event -> tx_trace_buffer_entry_event_id == event_id) + { + + /* Yes, the event was inserted in the event trace so pickup the timestamp. */ + timestamp = event -> tx_trace_buffer_entry_time_stamp; + } + else + { + + /* Event was not inserted, simply set the event pointer to NULL. */ + event = NX_NULL; + } + } + + /* Now determine if the caller requested the current event. */ + if (current_event) + { + + /* Yes, return the event pointer of potential subsequent update. */ + *current_event = event; + } + + /* Now determine if the current timestamp was requested. */ + if (current_timestamp) + { + + /* Yes, return the current timestamp. */ + *current_timestamp = timestamp; + } + + /* Restore interrupts. */ + TX_RESTORE +} + + +#endif /* TX_ENABLE_EVENT_TRACE */ + diff --git a/common/src/nx_trace_event_update.c b/common/src/nx_trace_event_update.c new file mode 100644 index 0000000..17687c4 --- /dev/null +++ b/common/src/nx_trace_event_update.c @@ -0,0 +1,128 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Trace */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifndef NX_SOURCE_CODE +#define NX_SOURCE_CODE +#endif + + +/* Include necessary system files. */ + +#include "nx_api.h" + +#ifdef TX_ENABLE_EVENT_TRACE +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_trace_event_update PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function inserts a NetX event into the current trace buffer. */ +/* */ +/* INPUT */ +/* */ +/* event Event pointer */ +/* timestamp Timestamp of the event */ +/* event_id User Event ID */ +/* info_field_1 First information field */ +/* info_field_2 First information field */ +/* info_field_3 First information field */ +/* info_field_4 First information field */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Internal NetX Functions */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_trace_event_update(TX_TRACE_BUFFER_ENTRY *event, ULONG timestamp, ULONG event_id, ULONG info_field_1, ULONG info_field_2, ULONG info_field_3, ULONG info_field_4) +{ + +TX_INTERRUPT_SAVE_AREA + + /* Disable interrupts. */ + TX_DISABLE + + /* Determine if the event exists and is still the event originally inserted into the trace. */ + if ((event) && (event -> tx_trace_buffer_entry_event_id == event_id) && (event -> tx_trace_buffer_entry_time_stamp == timestamp)) + { + + /* Yes, update this trace entry based on the info input parameters. */ + + /* Check for info field 1 update. */ + if (info_field_1) + { + + /* Yes, update info field 1. */ + event -> tx_trace_buffer_entry_information_field_1 = info_field_1; + } + + /* Check for info field 2 update. */ + if (info_field_2) + { + + /* Yes, update info field 2. */ + event -> tx_trace_buffer_entry_information_field_2 = info_field_2; + } + + /* Check for info field 3 update. */ + if (info_field_3) + { + + /* Yes, update info field 3. */ + event -> tx_trace_buffer_entry_information_field_3 = info_field_3; + } + + /* Check for info field 4 update. */ + if (info_field_4) + { + + /* Yes, update info field 4. */ + event -> tx_trace_buffer_entry_information_field_4 = info_field_4; + } + } + /* Restore interrupts. */ + TX_RESTORE +} + + + +#endif /* TX_ENABLE_EVENT_TRACE */ + diff --git a/common/src/nx_trace_object_register.c b/common/src/nx_trace_object_register.c new file mode 100644 index 0000000..f9dd4dc --- /dev/null +++ b/common/src/nx_trace_object_register.c @@ -0,0 +1,90 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Trace */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifndef NX_SOURCE_CODE +#define NX_SOURCE_CODE +#endif + +/* Include necessary system files. */ + +#include "nx_api.h" + +#ifdef TX_ENABLE_EVENT_TRACE +extern VOID _tx_trace_object_register(UCHAR, VOID *, CHAR *, ULONG, ULONG); +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_trace_object_register PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function registers a NetX object in the trace registry. */ +/* */ +/* INPUT */ +/* */ +/* object_type Type of system object */ +/* object_ptr Address of system object */ +/* object_name Name of system object */ +/* parameter_1 Supplemental parameter 1 */ +/* parameter_2 Supplemental parameter 2 */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _tx_trace_object_register Actual register function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Initialization */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_trace_object_register(UCHAR object_type, VOID *object_ptr, CHAR *object_name, ULONG parameter_1, ULONG parameter_2) +{ + +TX_INTERRUPT_SAVE_AREA + + + /* Disable interrupts. */ + TX_DISABLE + + /* Call actual object register function. */ + _tx_trace_object_register(object_type, object_ptr, object_name, parameter_1, parameter_2); + + /* Restore interrupts. */ + TX_RESTORE +} + +#endif /* TX_ENABLE_EVENT_TRACE */ + diff --git a/common/src/nx_trace_object_unregister.c b/common/src/nx_trace_object_unregister.c new file mode 100644 index 0000000..5fc72d6 --- /dev/null +++ b/common/src/nx_trace_object_unregister.c @@ -0,0 +1,86 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Trace */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifndef NX_SOURCE_CODE +#define NX_SOURCE_CODE +#endif + +/* Include necessary system files. */ + +#include "nx_api.h" + +#ifdef TX_ENABLE_EVENT_TRACE +extern VOID _tx_trace_object_unregister(VOID *); +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_trace_object_unregister PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function unregisters a NetX object in the trace registry. */ +/* */ +/* INPUT */ +/* */ +/* object_pointer Address of system object */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _tx_trace_object_unregister Actual unregister function */ +/* */ +/* CALLED BY */ +/* */ +/* NetX delete functions */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_trace_object_unregister(VOID *object_ptr) +{ + +TX_INTERRUPT_SAVE_AREA + + + /* Disable interrupts. */ + TX_DISABLE + + /* Call actual object unregister function. */ + _tx_trace_object_unregister(object_ptr); + + /* Restore interrupts. */ + TX_RESTORE +} + +#endif /* TX_ENABLE_EVENT_TRACE */ + diff --git a/common/src/nx_udp_bind_cleanup.c b/common/src/nx_udp_bind_cleanup.c new file mode 100644 index 0000000..ccd9de1 --- /dev/null +++ b/common/src/nx_udp_bind_cleanup.c @@ -0,0 +1,167 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** User Datagram Protocol (UDP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "tx_thread.h" +#include "nx_udp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_udp_bind_cleanup PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes UDP bind timeout and thread terminate */ +/* actions that require the UDP socket 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 */ +/* */ +/* _nx_udp_socket_unbind Unbind processing */ +/* _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_udp_bind_cleanup(TX_THREAD *thread_ptr NX_CLEANUP_PARAMETER) +{ + +TX_INTERRUPT_SAVE_AREA + +NX_UDP_SOCKET *socket_ptr; /* Working socket pointer */ +NX_UDP_SOCKET *owning_socket_ptr; /* Socket owning the port */ + + NX_CLEANUP_EXTENSION + + /* Setup pointer to UDP socket control block. */ + socket_ptr = (NX_UDP_SOCKET *)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) && (socket_ptr) && + (socket_ptr -> nx_udp_socket_id == NX_UDP_ID)) + { + + /* Yes, we still have thread suspension! */ + + /* Clear the socket bind in progress flag. */ + socket_ptr -> nx_udp_socket_bind_in_progress = NX_NULL; + + /* Clear the suspension cleanup flag. */ + thread_ptr -> tx_thread_suspend_cleanup = TX_NULL; + + /* Pickup the socket owning the port. This pointer was + saved in the bind processing prior to suspension. */ + owning_socket_ptr = socket_ptr -> nx_udp_socket_bound_previous; + + /* 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. */ + owning_socket_ptr -> nx_udp_socket_bind_suspension_list = NX_NULL; + } + else + { + + /* At least one more thread is on the same suspension list. */ + + /* Update the list head pointer. */ + owning_socket_ptr -> nx_udp_socket_bind_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. */ + owning_socket_ptr -> nx_udp_socket_bind_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_PORT_UNAVAILABLE; + + /* 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 +} + diff --git a/common/src/nx_udp_enable.c b/common/src/nx_udp_enable.c new file mode 100644 index 0000000..41fd9b9 --- /dev/null +++ b/common/src/nx_udp_enable.c @@ -0,0 +1,83 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** User Datagram Protocol (UDP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_udp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_udp_enable PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function enables the UDP management component for the */ +/* specified IP instance. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP instance pointer */ +/* */ +/* 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_udp_enable(NX_IP *ip_ptr) +{ + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_UDP_ENABLE, ip_ptr, 0, 0, 0, NX_TRACE_UDP_EVENTS, 0, 0) + + /* Set the UDP packet receive function in the IP structure to indicate + we are ready to receive UDP packets. */ + ip_ptr -> nx_ip_udp_packet_receive = _nx_udp_packet_receive; + + /* Return successful completion. */ + return(NX_SUCCESS); +} + diff --git a/common/src/nx_udp_free_port_find.c b/common/src/nx_udp_free_port_find.c new file mode 100644 index 0000000..a0b29a7 --- /dev/null +++ b/common/src/nx_udp_free_port_find.c @@ -0,0 +1,170 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** User Datagram Protocol (UDP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_udp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_udp_free_port_find PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function finds the first available UDP port, starting from the */ +/* supplied port. If no available ports are found, an error is */ +/* returned. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP instance pointer */ +/* port Starting port */ +/* free_port_ptr Pointer to return free port */ +/* */ +/* 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_udp_free_port_find(NX_IP *ip_ptr, UINT port, UINT *free_port_ptr) +{ + +UINT index; +UINT bound; +UINT starting_port; +NX_UDP_SOCKET *search_ptr; +NX_UDP_SOCKET *end_ptr; + +#ifdef TX_ENABLE_EVENT_TRACE +TX_TRACE_BUFFER_ENTRY *trace_event; +ULONG trace_timestamp; +#endif + + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_UDP_FREE_PORT_FIND, ip_ptr, port, 0, 0, NX_TRACE_UDP_EVENTS, &trace_event, &trace_timestamp) + + /* Save the original port. */ + starting_port = port; + + /* Loop through the UDP ports until a free entry is found. */ + do + { + + /* Calculate the hash index in the UDP port array of the associated IP instance. */ + index = (UINT)((port + (port >> 8)) & NX_UDP_PORT_TABLE_MASK); + + /* Obtain the IP mutex so we can figure out whether or not the port has already + been bound to. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Pickup the head of the UDP ports bound list. */ + search_ptr = ip_ptr -> nx_ip_udp_port_table[index]; + + /* Set the bound flag to false. */ + bound = NX_FALSE; + + /* Determine if we need to perform a list search. */ + if (search_ptr) + { + + /* Walk through the circular list of UDP sockets that are already + bound. */ + end_ptr = search_ptr; + do + { + + /* Determine if this entry is the same as the requested port. */ + if (search_ptr -> nx_udp_socket_port == port) + { + + /* Set the bound flag. */ + bound = NX_TRUE; + + /* Get out of the loop. */ + break; + } + + /* Move to the next entry in the list. */ + search_ptr = search_ptr -> nx_udp_socket_bound_next; + } while (search_ptr != end_ptr); + } + + /* Release protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Determine if the port is available. */ + if (!bound) + { + + /* Setup the return port number. */ + *free_port_ptr = port; + + /* Update the trace event with the status. */ + NX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, NX_TRACE_UDP_FREE_PORT_FIND, 0, 0, port, 0) + + /* Return success. */ + return(NX_SUCCESS); + } + + /* Move to the next port. */ + port++; + + /* Determine if we need to wrap. */ + if (port > NX_MAX_PORT) + { + + /* Yes, we need to wrap around. */ + port = NX_SEARCH_PORT_START; + } + } while (starting_port != port); + + /* A free port was not found, return an error. */ + return(NX_NO_FREE_PORTS); +} + diff --git a/common/src/nx_udp_info_get.c b/common/src/nx_udp_info_get.c new file mode 100644 index 0000000..e2951cd --- /dev/null +++ b/common/src/nx_udp_info_get.c @@ -0,0 +1,161 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** User Datagram Protocol (UDP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_udp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_udp_info_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves UDP information from the specified IP */ +/* instance. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP control block */ +/* udp_packets_sent Destination to the number of */ +/* packets sent */ +/* udp_bytes_sent Destination to the number of */ +/* bytes sent */ +/* udp_packets_received Destination to the number of */ +/* packets received */ +/* udp_bytes_received Destination to the number of */ +/* bytes received */ +/* udp_invalid_packets Destination to the number of */ +/* invalid packets */ +/* udp_receive_packets_dropped Destination to the number of */ +/* receive packets dropped */ +/* udp_checksum_errors Destination to the number of */ +/* checksum errors */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_udp_info_get(NX_IP *ip_ptr, ULONG *udp_packets_sent, ULONG *udp_bytes_sent, + ULONG *udp_packets_received, ULONG *udp_bytes_received, + ULONG *udp_invalid_packets, ULONG *udp_receive_packets_dropped, + ULONG *udp_checksum_errors) +{ + +TX_INTERRUPT_SAVE_AREA + + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_UDP_INFO_GET, ip_ptr, ip_ptr -> nx_ip_udp_bytes_sent, ip_ptr -> nx_ip_udp_bytes_received, ip_ptr -> nx_ip_udp_invalid_packets, NX_TRACE_UDP_EVENTS, 0, 0) + + /* Disable interrupts. */ + TX_DISABLE + + /* Determine if packets sent is wanted. */ + if (udp_packets_sent) + { + + /* Return the number of packets sent by this IP instance. */ + *udp_packets_sent = ip_ptr -> nx_ip_udp_packets_sent; + } + + /* Determine if bytes sent is wanted. */ + if (udp_bytes_sent) + { + + /* Return the number of bytes sent by this IP instance. */ + *udp_bytes_sent = ip_ptr -> nx_ip_udp_bytes_sent; + } + + /* Determine if packets received is wanted. */ + if (udp_packets_received) + { + + /* Return the number of packets received by this IP instance. */ + *udp_packets_received = ip_ptr -> nx_ip_udp_packets_received; + } + + /* Determine if bytes received is wanted. */ + if (udp_bytes_received) + { + + /* Return the number of bytes received by this IP instance. */ + *udp_bytes_received = ip_ptr -> nx_ip_udp_bytes_received; + } + + /* Determine if invalid packets is wanted. */ + if (udp_invalid_packets) + { + + /* Return the number of invalid packets by this IP instance. */ + *udp_invalid_packets = ip_ptr -> nx_ip_udp_invalid_packets; + } + + /* Determine if receive packets dropped is wanted. */ + if (udp_receive_packets_dropped) + { + + /* Return the number of receive packets dropped by this IP instance. */ + *udp_receive_packets_dropped = ip_ptr -> nx_ip_udp_receive_packets_dropped; + } + + /* Determine if checksum errors is wanted. */ + if (udp_checksum_errors) + { + + /* Return the number of checksum errors by this IP instance. */ + *udp_checksum_errors = ip_ptr -> nx_ip_udp_checksum_errors; + } + + /* Restore interrupts. */ + TX_RESTORE + + /* Return successful completion. */ + return(NX_SUCCESS); +} + diff --git a/common/src/nx_udp_packet_info_extract.c b/common/src/nx_udp_packet_info_extract.c new file mode 100644 index 0000000..f59eb4f --- /dev/null +++ b/common/src/nx_udp_packet_info_extract.c @@ -0,0 +1,147 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** User Datagram Protocol (UDP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_udp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_udp_packet_info_extract PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function extracts the source IP, protocol, (the protocol is */ +/* always UDP), port number and the incoming interface from the */ +/* incoming packet. */ +/* */ +/* INPUT */ +/* */ +/* packet_ptr Pointer to UDP packet */ +/* ip_address Pointer to sender IP address */ +/* protocol Pointer to packet protocol. */ +/* Always 17 (UDP) */ +/* port Pointer to sender source port */ +/* interface_index Pointer to interface index */ +/* packet received on */ +/* */ +/* 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_udp_packet_info_extract(NX_PACKET *packet_ptr, ULONG *ip_address, + UINT *protocol, UINT *port, UINT *interface_index) +{ + +ULONG *temp_ptr; +NX_IP *ip_ptr; +NX_INTERFACE *nx_interface; +UINT index; +UINT source_port; +ULONG source_ip; + + + /* Build an address to the current top of the packet. */ + temp_ptr = (ULONG *)packet_ptr -> nx_packet_prepend_ptr; + + /* Pickup the source port. */ + source_port = (UINT)(*(temp_ptr - 2) >> NX_SHIFT_BY_16); + if (port != NX_NULL) + { + *port = source_port; + } + + /* Pickup the source IP address. */ + source_ip = *(temp_ptr - 4); + if (ip_address != NX_NULL) + { + *ip_address = source_ip; + } + + if (protocol != NX_NULL) + { + *protocol = 0x11; + } + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_UDP_SOURCE_EXTRACT, packet_ptr, source_ip, source_port, 0, NX_TRACE_PACKET_EVENTS, 0, 0); + + + 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; + + nx_interface = packet_ptr -> nx_packet_ip_interface; + + if (nx_interface == NX_NULL) + { + /* No interface attached. Done here, and return success. */ + return(NX_SUCCESS); + } + + ip_ptr = nx_interface -> nx_interface_ip_instance; + + /* Find the index number of this interface. */ + for (index = 0; index < NX_MAX_PHYSICAL_INTERFACES; index++) + { + if (nx_interface == &(ip_ptr -> nx_ip_interface[index])) + { + *interface_index = index; + break; + } + } + + return(NX_SUCCESS); +} + diff --git a/common/src/nx_udp_packet_receive.c b/common/src/nx_udp_packet_receive.c new file mode 100644 index 0000000..ea7afa4 --- /dev/null +++ b/common/src/nx_udp_packet_receive.c @@ -0,0 +1,425 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** User Datagram Protocol (UDP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "tx_thread.h" +#include "nx_udp.h" +#include "nx_packet.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_udp_packet_receive PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function receives an UDP packet from the IP receive processing */ +/* and places on the appropriate socket's input queue. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP control block */ +/* packet_ptr Pointer to packet to send */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_packet_release Packet release function */ +/* tx_mutex_get Get protection mutex */ +/* tx_mutex_put Release protection mutex */ +/* _tx_thread_system_resume Resume suspended thread */ +/* (nx_udp_receive_callback) Packet receive notify function*/ +/* */ +/* CALLED BY */ +/* */ +/* _nx_ip_packet_receive Dispatch received IP packets */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +VOID _nx_udp_packet_receive(NX_IP *ip_ptr, NX_PACKET *packet_ptr) +{ + +TX_INTERRUPT_SAVE_AREA +VOID (*receive_callback)(struct NX_UDP_SOCKET_STRUCT *socket_ptr); +UINT index; +UINT port; +TX_THREAD *thread_ptr; +NX_UDP_SOCKET *socket_ptr; +NX_UDP_HEADER *udp_header_ptr; + + +#ifndef NX_DISABLE_UDP_INFO + + /* Increment the total UDP receive packets count. */ + ip_ptr -> nx_ip_udp_packets_received++; +#endif + +#ifndef NX_DISABLE_RX_SIZE_CHECKING + + /* Check for valid packet length. */ + if (packet_ptr -> nx_packet_length < sizeof(NX_UDP_HEADER)) + { + +#ifndef NX_DISABLE_UDP_INFO + + /* Increment the UDP invalid packet error. */ + ip_ptr -> nx_ip_udp_invalid_packets++; +#endif + + /* Invalid packet length, just release it. */ + _nx_packet_release(packet_ptr); + + /* The function is complete, just return! */ + return; + } +#endif + + /* Pickup the pointer to the head of the UDP packet. */ + udp_header_ptr = (NX_UDP_HEADER *)packet_ptr -> nx_packet_prepend_ptr; + + /* 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); + +#ifndef NX_DISABLE_RX_SIZE_CHECKING + + /* Check for valid packet length. */ + if (packet_ptr -> nx_packet_length < (((udp_header_ptr -> nx_udp_header_word_1) >> NX_SHIFT_BY_16) & NX_LOWER_16_MASK)) + { + +#ifndef NX_DISABLE_UDP_INFO + + /* Increment the UDP invalid packet error. */ + ip_ptr -> nx_ip_udp_invalid_packets++; +#endif + + /* Invalid packet length, just release it. */ + _nx_packet_release(packet_ptr); + + /* The function is complete, just return! */ + return; + } +#endif + + /* Pickup the destination UDP port. */ + port = (UINT)(udp_header_ptr -> nx_udp_header_word_0 & NX_LOWER_16_MASK); + + /* Calculate the hash index in the UDP port array of the associated IP instance. */ + index = (UINT)((port + (port >> 8)) & NX_UDP_PORT_TABLE_MASK); + + /* Determine if the caller is a thread. If so, we should use the protection mutex + to avoid having the port list examined while we are traversing it. If this routine + is called from an ISR nothing needs to be done since bind/unbind are not allowed + from ISRs. */ + if ((_tx_thread_current_ptr) && (TX_THREAD_GET_SYSTEM_STATE() == 0)) + { + + /* Get mutex protection. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), NX_WAIT_FOREVER); + } + + /* Search the bound sockets in this index for the particular port. */ + socket_ptr = ip_ptr -> nx_ip_udp_port_table[index]; + + /* Determine if there are any sockets bound on this port index. */ + if (!socket_ptr) + { + +#ifndef NX_DISABLE_UDP_INFO + + /* Increment the no port for delivery count. */ + ip_ptr -> nx_ip_udp_no_port_for_delivery++; + + /* Increment the total UDP receive packets dropped count. */ + ip_ptr -> nx_ip_udp_receive_packets_dropped++; +#endif + + /* Determine if the caller is a thread. If so, release the mutex protection previously setup. */ + if ((_tx_thread_current_ptr) && (TX_THREAD_GET_SYSTEM_STATE() == 0)) + { + + /* Release mutex protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + } + + /* Release the packet. */ + _nx_packet_release(packet_ptr); + + /* Just return. */ + return; + } + + /* Loop to examine the list of bound ports on this index. */ + do + { + + /* Determine if the port has been found. */ + if (socket_ptr -> nx_udp_socket_port == port) + { + + /* Yes, we have a match. */ + +#ifndef NX_DISABLE_UDP_INFO + + /* Increment the total number of packets received for this socket. */ + socket_ptr -> nx_udp_socket_packets_received++; + + /* Increment the total UDP receive bytes. */ + ip_ptr -> nx_ip_udp_bytes_received += packet_ptr -> nx_packet_length - sizeof(NX_UDP_HEADER); + socket_ptr -> nx_udp_socket_bytes_received += packet_ptr -> nx_packet_length - sizeof(NX_UDP_HEADER); +#endif + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_UDP_RECEIVE, ip_ptr, socket_ptr, packet_ptr, udp_header_ptr -> nx_udp_header_word_0, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + /* Get out of the search loop. */ + break; + } + else + { + + /* Move to the next entry in the bound index. */ + socket_ptr = socket_ptr -> nx_udp_socket_bound_next; + } + } while (socket_ptr != ip_ptr -> nx_ip_udp_port_table[index]); + + /* Determine if the caller is a thread. If so, release the mutex protection previously setup. */ + if ((_tx_thread_current_ptr) && (TX_THREAD_GET_SYSTEM_STATE() == 0)) + { + + /* Release mutex protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + } + + /* Determine if a match was found. */ + if (socket_ptr -> nx_udp_socket_port != port) + { + +#ifndef NX_DISABLE_UDP_INFO + + /* Increment the no port for delivery count. */ + ip_ptr -> nx_ip_udp_no_port_for_delivery++; + + /* Increment the total UDP receive packets dropped count. */ + ip_ptr -> nx_ip_udp_receive_packets_dropped++; +#endif + + /* No socket structure bound to this port, just release the packet. */ + _nx_packet_release(packet_ptr); + return; + } + + /* Disable interrupts. */ + TX_DISABLE + + /* Determine if the socket is still valid. */ + if ((socket_ptr -> nx_udp_socket_port != port) || (socket_ptr -> nx_udp_socket_id != NX_UDP_ID)) + { + +#ifndef NX_DISABLE_UDP_INFO + + /* Increment the no port for delivery count. */ + ip_ptr -> nx_ip_udp_no_port_for_delivery++; + + /* Increment the total UDP receive packets dropped count. */ + ip_ptr -> nx_ip_udp_receive_packets_dropped++; + + /* Increment the total UDP receive packets dropped count for this socket. */ + socket_ptr -> nx_udp_socket_packets_dropped++; +#endif + + /* Restore interrupts. */ + TX_RESTORE + + /* Release the packet. */ + _nx_packet_release(packet_ptr); + + /* Return to caller. */ + return; + } + + /* Pickup the receive notify function. */ + receive_callback = socket_ptr -> nx_udp_receive_callback; + + /* Determine if we need to update the UDP port head pointer. This should + only be done if the found socket pointer is not the head pointer and + the mutex for this IP instance is available. */ + if ((socket_ptr != ip_ptr -> nx_ip_udp_port_table[index]) && (!ip_ptr -> nx_ip_protection.tx_mutex_ownership_count)) + { + + /* Move the port head pointer to this socket. */ + ip_ptr -> nx_ip_udp_port_table[index] = socket_ptr; + } + + /* Determine if there is thread waiting for a packet from this port. */ + thread_ptr = socket_ptr -> nx_udp_socket_receive_suspension_list; + 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. */ + socket_ptr -> nx_udp_socket_receive_suspension_list = NX_NULL; + } + else + { + + /* At least one more thread is on the same expiration list. */ + + /* Update the list head pointer. */ + socket_ptr -> nx_udp_socket_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. */ + socket_ptr -> nx_udp_socket_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_PACKET **)thread_ptr -> tx_thread_additional_suspend_info) = packet_ptr; + + /* Restore interrupts. */ + TX_RESTORE + + /* Put return status into the thread control block. */ + thread_ptr -> tx_thread_suspend_status = NX_SUCCESS; + + /* Resume thread. */ + _tx_thread_system_resume(thread_ptr); + } + else + { + + /* No, queue the thread in the socket's receive packet queue. */ + + /* Place the packet at the end of the socket's receive queue. */ + if (socket_ptr -> nx_udp_socket_receive_head) + { + + /* Add the new packet to a nonempty list. */ + (socket_ptr -> nx_udp_socket_receive_tail) -> nx_packet_queue_next = packet_ptr; + socket_ptr -> nx_udp_socket_receive_tail = packet_ptr; + packet_ptr -> nx_packet_queue_next = NX_NULL; + + /* Increment the number of packets queued. */ + socket_ptr -> nx_udp_socket_receive_count++; + + /* Determine if the maximum queue depth has been reached. */ + if (socket_ptr -> nx_udp_socket_receive_count > + socket_ptr -> nx_udp_socket_queue_maximum) + { + + /* We have exceeded the queue depth, so remove the first item + in the queue (which is the oldest). */ + packet_ptr = socket_ptr -> nx_udp_socket_receive_head; + socket_ptr -> nx_udp_socket_receive_head = packet_ptr -> nx_packet_queue_next; + + /* Decrement the number of packets queued. */ + socket_ptr -> nx_udp_socket_receive_count--; + +#ifndef NX_DISABLE_UDP_INFO + + /* Increment the total UDP receive packets dropped count. */ + ip_ptr -> nx_ip_udp_receive_packets_dropped++; + + /* Increment the total UDP receive packets dropped count for this socket. */ + socket_ptr -> nx_udp_socket_packets_dropped++; +#endif + + /* Restore interrupts. */ + TX_RESTORE + + /* Release the packet. */ + _nx_packet_release(packet_ptr); + } + else + { + + /* Restore interrupts. */ + TX_RESTORE + } + } + else + { + + /* Add the new packet to an empty list. */ + socket_ptr -> nx_udp_socket_receive_head = packet_ptr; + socket_ptr -> nx_udp_socket_receive_tail = packet_ptr; + packet_ptr -> nx_packet_queue_next = NX_NULL; + + /* Increment the number of packets queued. */ + socket_ptr -> nx_udp_socket_receive_count++; + + /* Restore interrupts. */ + TX_RESTORE + } + } + + /* Determine if there is a socket receive notification function specified. */ + if (receive_callback) + { + + /* Yes, notification is requested. Call the application's receive notification + function for this socket. */ + (receive_callback)(socket_ptr); + } +} + diff --git a/common/src/nx_udp_receive_cleanup.c b/common/src/nx_udp_receive_cleanup.c new file mode 100644 index 0000000..0ae2a17 --- /dev/null +++ b/common/src/nx_udp_receive_cleanup.c @@ -0,0 +1,158 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** User Datagram Protocol (UDP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "tx_thread.h" +#include "nx_udp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_udp_receive_cleanup PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes UDP receive timeout and thread terminate */ +/* actions that require the UDP socket 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_udp_receive_cleanup(TX_THREAD *thread_ptr NX_CLEANUP_PARAMETER) +{ + +TX_INTERRUPT_SAVE_AREA + +NX_UDP_SOCKET *socket_ptr; /* Working socket pointer */ + + NX_CLEANUP_EXTENSION + + /* Setup pointer to UDP socket control block. */ + socket_ptr = (NX_UDP_SOCKET *)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) && (socket_ptr) && + (socket_ptr -> nx_udp_socket_id == NX_UDP_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. */ + socket_ptr -> nx_udp_socket_receive_suspension_list = NX_NULL; + } + else + { + + /* At least one more thread is on the same suspension list. */ + + /* Update the list head pointer. */ + socket_ptr -> nx_udp_socket_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. */ + socket_ptr -> nx_udp_socket_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_NO_PACKET; + + /* 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 +} + diff --git a/common/src/nx_udp_socket_bind.c b/common/src/nx_udp_socket_bind.c new file mode 100644 index 0000000..1420253 --- /dev/null +++ b/common/src/nx_udp_socket_bind.c @@ -0,0 +1,286 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** User Datagram Protocol (UDP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_udp.h" +#include "tx_thread.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_udp_socket_bind PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function binds the UDP socket structure to a specific UDP */ +/* port. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to UDP socket */ +/* port 16-bit UDP port number */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_udp_free_port_find Find a free UDP port */ +/* tx_mutex_get Obtain protection mutex */ +/* tx_mutex_put Release protection mutex */ +/* _tx_thread_system_suspend Suspend thread */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_udp_socket_bind(NX_UDP_SOCKET *socket_ptr, UINT port, ULONG wait_option) +{ + +TX_INTERRUPT_SAVE_AREA +UINT index; +NX_IP *ip_ptr; +TX_THREAD *thread_ptr; +NX_UDP_SOCKET *search_ptr; +NX_UDP_SOCKET *end_ptr; + + + /* Setup the pointer to the associated IP instance. */ + ip_ptr = socket_ptr -> nx_udp_socket_ip_ptr; + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_UDP_SOCKET_BIND, ip_ptr, socket_ptr, port, wait_option, NX_TRACE_UDP_EVENTS, 0, 0) + + /* Obtain the IP mutex so we can figure out whether or not the port has already + been bound to. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Determine if the socket has already been bound to port or if a socket bind is + already pending from another thread. */ + if ((socket_ptr -> nx_udp_socket_bound_next) || + (socket_ptr -> nx_udp_socket_bind_in_progress)) + { + + /* Release the protection mutex. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return an already bound error code. */ + return(NX_ALREADY_BOUND); + } + + /* Determine if the port needs to be allocated. */ + if (port == NX_ANY_PORT) + { + + /* Call the find routine to allocate a UDP port. */ + port = NX_SEARCH_PORT_START + (UINT)(NX_RAND() % ((NX_MAX_PORT + 1) - NX_SEARCH_PORT_START)); + if (_nx_udp_free_port_find(ip_ptr, port, &port) != NX_SUCCESS) + { + + /* Release the protection mutex. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* There was no free port, return an error code. */ + return(NX_NO_FREE_PORTS); + } + } + + /* Save the port number in the UDP socket structure. */ + socket_ptr -> nx_udp_socket_port = port; + + /* 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. */ + search_ptr = ip_ptr -> nx_ip_udp_port_table[index]; + + /* Determine if we need to perform a list search. */ + if (search_ptr) + { + + /* Walk through the circular list of UDP sockets that are already + bound. */ + end_ptr = search_ptr; + do + { + + /* Determine if this entry is the same as the requested port. */ + if (search_ptr -> nx_udp_socket_port == port) + { + + /* Yes, the port has already been allocated. */ + break; + } + + /* Move to the next entry in the list. */ + search_ptr = search_ptr -> nx_udp_socket_bound_next; + } while (search_ptr != end_ptr); + } + + /* Now determine if the port is available. */ + if ((search_ptr == NX_NULL) || (search_ptr -> nx_udp_socket_port != port)) + { + + /* Place this UDP socket structure on the list of bound ports. */ + + /* Disable interrupts. */ + TX_DISABLE + + /* Determine if the list is NULL. */ + if (search_ptr) + { + + /* There are already sockets on this list... just add this one + to the end. */ + socket_ptr -> nx_udp_socket_bound_next = + ip_ptr -> nx_ip_udp_port_table[index]; + socket_ptr -> nx_udp_socket_bound_previous = + (ip_ptr -> nx_ip_udp_port_table[index]) -> nx_udp_socket_bound_previous; + ((ip_ptr -> nx_ip_udp_port_table[index]) -> nx_udp_socket_bound_previous) -> nx_udp_socket_bound_next = + socket_ptr; + (ip_ptr -> nx_ip_udp_port_table[index]) -> nx_udp_socket_bound_previous = socket_ptr; + } + else + { + + /* Nothing is on the UDP port list. Add this UDP socket to an + empty list. */ + socket_ptr -> nx_udp_socket_bound_next = socket_ptr; + socket_ptr -> nx_udp_socket_bound_previous = socket_ptr; + ip_ptr -> nx_ip_udp_port_table[index] = socket_ptr; + } + + /* Restore interrupts. */ + TX_RESTORE + + /* Release the mutex protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return success to the caller. */ + return(NX_SUCCESS); + } + else if (wait_option) + { + + /* Prepare for suspension of this thread. */ + + /* Disable interrupts. */ + TX_DISABLE + + /* Pickup thread pointer. */ + thread_ptr = _tx_thread_current_ptr; + + /* Setup cleanup routine pointer. */ + thread_ptr -> tx_thread_suspend_cleanup = _nx_udp_bind_cleanup; + + /* Setup cleanup information, i.e. this socket control + block. */ + thread_ptr -> tx_thread_suspend_control_block = (void *)socket_ptr; + + /* Also remember the socket that has bound to the port, since the thread + is going to be suspended on that socket. */ + socket_ptr -> nx_udp_socket_bound_previous = search_ptr; + + /* Set the socket bind in progress flag (thread pointer). */ + socket_ptr -> nx_udp_socket_bind_in_progress = thread_ptr; + + /* Setup suspension list. */ + if (search_ptr -> nx_udp_socket_bind_suspension_list) + { + + /* This list is not NULL, add current thread to the end. */ + thread_ptr -> tx_thread_suspended_next = + search_ptr -> nx_udp_socket_bind_suspension_list; + thread_ptr -> tx_thread_suspended_previous = + (search_ptr -> nx_udp_socket_bind_suspension_list) -> tx_thread_suspended_previous; + ((search_ptr -> nx_udp_socket_bind_suspension_list) -> tx_thread_suspended_previous) -> tx_thread_suspended_next = + thread_ptr; + (search_ptr -> nx_udp_socket_bind_suspension_list) -> tx_thread_suspended_previous = thread_ptr; + } + else + { + + /* No other threads are suspended. Setup the head pointer and + just setup this threads pointers to itself. */ + search_ptr -> nx_udp_socket_bind_suspension_list = thread_ptr; + thread_ptr -> tx_thread_suspended_next = thread_ptr; + thread_ptr -> tx_thread_suspended_previous = thread_ptr; + } + + /* Increment the suspended thread count. */ + search_ptr -> nx_udp_socket_bind_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 + + /* Release the mutex protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Call actual thread suspension routine. */ + _tx_thread_system_suspend(thread_ptr); + + /* Return the completion status. */ + return(thread_ptr -> tx_thread_suspend_status); + } + else + { + + /* Release the IP protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return the port unavailable error. */ + return(NX_PORT_UNAVAILABLE); + } +} + diff --git a/common/src/nx_udp_socket_bytes_available.c b/common/src/nx_udp_socket_bytes_available.c new file mode 100644 index 0000000..53329ed --- /dev/null +++ b/common/src/nx_udp_socket_bytes_available.c @@ -0,0 +1,122 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** User Datagram Protocol (UDP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#ifndef NX_SOURCE_CODE +#define NX_SOURCE_CODE +#endif + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_udp.h" + + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_udp_socket_bytes_available PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function determines the number of bytes available on a UDP */ +/* socket for reception. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to the UDP sockete */ +/* bytes_available Number of bytes returned to */ +/* the caller. */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Obtain protection */ +/* tx_mutex_put Release protection */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_udp_socket_bytes_available(NX_UDP_SOCKET *socket_ptr, ULONG *bytes_available) +{ + +NX_IP *ip_ptr; +NX_PACKET *packet_ptr; +ULONG count; + + + /* Setup IP pointer. */ + ip_ptr = socket_ptr -> nx_udp_socket_ip_ptr; + + /* Obtain the IP mutex so we can examine the bound port. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + *bytes_available = 0; + + /* Determine if the socket is currently bound. */ + if (!socket_ptr -> nx_udp_socket_bound_next) + { + /* Release mutex */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + return(NX_NOT_SUCCESSFUL); + } + + packet_ptr = socket_ptr -> nx_udp_socket_receive_head; + + /* Loop through all the packets on the queue and find out the total + number of bytes in the rx queue that are available to the applciation. */ + for (count = 0; count < socket_ptr -> nx_udp_socket_receive_count; count++) + { + + *bytes_available += (packet_ptr -> nx_packet_length - sizeof(NX_UDP_HEADER)); + + /* Move on to the next packet. */ + packet_ptr = packet_ptr -> nx_packet_queue_next; + } + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_UDP_SOCKET_BYTES_AVAILABLE, ip_ptr, socket_ptr, *bytes_available, 0, NX_TRACE_UDP_EVENTS, 0, 0); + + /* Release protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + return(NX_SUCCESS); +} + diff --git a/common/src/nx_udp_socket_checksum_disable.c b/common/src/nx_udp_socket_checksum_disable.c new file mode 100644 index 0000000..bd0e615 --- /dev/null +++ b/common/src/nx_udp_socket_checksum_disable.c @@ -0,0 +1,101 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** User Datagram Protocol (UDP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_udp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_udp_socket_checksum_disable PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function disables the UDP checksum logic for the specified */ +/* socket. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to UDP socket */ +/* */ +/* 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_udp_socket_checksum_disable(NX_UDP_SOCKET *socket_ptr) +{ +TX_INTERRUPT_SAVE_AREA + + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_UDP_SOCKET_CHECKSUM_DISABLE, socket_ptr -> nx_udp_socket_ip_ptr, socket_ptr, 0, 0, NX_TRACE_UDP_EVENTS, 0, 0) + + /* Lockout interrupts. */ + TX_DISABLE + + /* Determine if the socket is currently bound. */ + if (!socket_ptr -> nx_udp_socket_bound_next) + { + + /* Restore interrupts. */ + TX_RESTORE + + /* Socket is not bound, return an error message. */ + return(NX_NOT_BOUND); + } + + /* Set the checksum disable flag. */ + socket_ptr -> nx_udp_socket_disable_checksum = NX_TRUE; + + /* Restore interrupts. */ + TX_RESTORE + + /* Return a successful status. */ + return(NX_SUCCESS); +} + diff --git a/common/src/nx_udp_socket_checksum_enable.c b/common/src/nx_udp_socket_checksum_enable.c new file mode 100644 index 0000000..dd125f7 --- /dev/null +++ b/common/src/nx_udp_socket_checksum_enable.c @@ -0,0 +1,101 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** User Datagram Protocol (UDP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_udp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_udp_socket_checksum_enable PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function enables the UDP checksum logic for the specified */ +/* socket. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to UDP socket */ +/* */ +/* 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_udp_socket_checksum_enable(NX_UDP_SOCKET *socket_ptr) +{ +TX_INTERRUPT_SAVE_AREA + + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_UDP_SOCKET_CHECKSUM_ENABLE, socket_ptr -> nx_udp_socket_ip_ptr, socket_ptr, 0, 0, NX_TRACE_UDP_EVENTS, 0, 0) + + /* Lockout interrupts. */ + TX_DISABLE + + /* Determine if the socket is currently bound. */ + if (!socket_ptr -> nx_udp_socket_bound_next) + { + + /* Restore interrupts. */ + TX_RESTORE + + /* Socket is not bound, return an error message. */ + return(NX_NOT_BOUND); + } + + /* Clear the checksum disable flag. */ + socket_ptr -> nx_udp_socket_disable_checksum = NX_FALSE; + + /* Restore interrupts. */ + TX_RESTORE + + /* Return a successful status. */ + return(NX_SUCCESS); +} + diff --git a/common/src/nx_udp_socket_create.c b/common/src/nx_udp_socket_create.c new file mode 100644 index 0000000..c992307 --- /dev/null +++ b/common/src/nx_udp_socket_create.c @@ -0,0 +1,182 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** User Datagram Protocol (UDP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_udp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_udp_socket_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function creates a UDP socket for the specified IP instance. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP instance pointer */ +/* socket_ptr Pointer to new UDP socket */ +/* name Name of new UDP socket */ +/* type_of_service Type of service for this UDP */ +/* socket */ +/* fragment Flag to enable IP fragmenting */ +/* time_to_live Time to live value for socket */ +/* queue_maximum Maximum depth of receive queue*/ +/* */ +/* 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_udp_socket_create(NX_IP *ip_ptr, NX_UDP_SOCKET *socket_ptr, CHAR *name, + ULONG type_of_service, ULONG fragment, UINT time_to_live, ULONG queue_maximum) +{ +TX_INTERRUPT_SAVE_AREA + +NX_UDP_SOCKET *tail_ptr; + + + /* Initialize the TCP control block to zero. */ + memset((void *)socket_ptr, 0, sizeof(NX_UDP_SOCKET)); + + /* Fill in the basic information in the new UDP socket structure. */ + + /* Remember the associated IP structure. */ + socket_ptr -> nx_udp_socket_ip_ptr = ip_ptr; + + /* Save the UDP socket's name. */ + socket_ptr -> nx_udp_socket_name = name; + + /* Save the type of service input parameter. */ + socket_ptr -> nx_udp_socket_type_of_service = type_of_service; + + /* Save the fragment input parameter. */ + socket_ptr -> nx_udp_socket_fragment_enable = fragment & NX_DONT_FRAGMENT; + + /* Save the time-to-live input parameter. */ + socket_ptr -> nx_udp_socket_time_to_live = time_to_live; + + /* By default, have UDP checksum logic enabled. To disable checksum logic, the + application must call the nx_udp_checksum disable function for this UDP socket. */ + socket_ptr -> nx_udp_socket_disable_checksum = NX_FALSE; + + /* Clear the socket bind in progress flag. */ + socket_ptr -> nx_udp_socket_bind_in_progress = NX_FALSE; + + /* Set various list pointers to NULL. */ + socket_ptr -> nx_udp_socket_bound_next = NX_NULL; + socket_ptr -> nx_udp_socket_bound_previous = NX_NULL; + socket_ptr -> nx_udp_socket_bind_suspension_list = NX_NULL; + socket_ptr -> nx_udp_socket_bind_suspended_count = 0; + + /* Initialize the receive queue parameters. */ + socket_ptr -> nx_udp_socket_receive_count = 0; + socket_ptr -> nx_udp_socket_queue_maximum = queue_maximum; + socket_ptr -> nx_udp_socket_receive_head = NX_NULL; + socket_ptr -> nx_udp_socket_receive_tail = NX_NULL; + + /* Clear the receive notify function pointer. */ + socket_ptr -> nx_udp_receive_callback = NX_NULL; + + /* If trace is enabled, register this object. */ + NX_TRACE_OBJECT_REGISTER(NX_TRACE_OBJECT_TYPE_UDP_SOCKET, socket_ptr, name, type_of_service, queue_maximum) + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_UDP_SOCKET_CREATE, ip_ptr, socket_ptr, type_of_service, queue_maximum, NX_TRACE_IP_EVENTS, 0, 0) + + /* Obtain the IP mutex so we can add socket to IP structure. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Disable interrupts while we link the new UDP socket to the IP structure. */ + TX_DISABLE + + /* Load the UDP ID field in the UDP control block. */ + socket_ptr -> nx_udp_socket_id = NX_UDP_ID; + + /* Initialize the ougoing interface to "NULL". */ + socket_ptr -> nx_udp_socket_ip_interface = NX_NULL; + + /* Place the new UDP control block on the list of created UDP sockets for this IP. First, + check for an empty list. */ + if (ip_ptr -> nx_ip_udp_created_sockets_ptr) + { + + /* Pickup tail pointer. */ + tail_ptr = (ip_ptr -> nx_ip_udp_created_sockets_ptr) -> nx_udp_socket_created_previous; + + /* Place the new UDP socket control block in the list. */ + (ip_ptr -> nx_ip_udp_created_sockets_ptr) -> nx_udp_socket_created_previous = socket_ptr; + tail_ptr -> nx_udp_socket_created_next = socket_ptr; + + /* Setup this UDP socket's created links. */ + socket_ptr -> nx_udp_socket_created_previous = tail_ptr; + socket_ptr -> nx_udp_socket_created_next = ip_ptr -> nx_ip_udp_created_sockets_ptr; + } + else + { + + /* The created UDP socket list is empty. Add UDP socket control block to empty list. */ + ip_ptr -> nx_ip_udp_created_sockets_ptr = socket_ptr; + socket_ptr -> nx_udp_socket_created_previous = socket_ptr; + socket_ptr -> nx_udp_socket_created_next = socket_ptr; + } + + /* Increment the created UDP socket counter. */ + ip_ptr -> nx_ip_udp_created_sockets_count++; + + /* Restore previous interrupt posture. */ + TX_RESTORE + + /* Release the IP protection mutex. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return successful completion. */ + return(NX_SUCCESS); +} + diff --git a/common/src/nx_udp_socket_delete.c b/common/src/nx_udp_socket_delete.c new file mode 100644 index 0000000..4995a73 --- /dev/null +++ b/common/src/nx_udp_socket_delete.c @@ -0,0 +1,163 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** User Datagram Protocol (UDP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_udp.h" +#include "tx_thread.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_udp_socket_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function deletes a previously created socket and unbound */ +/* socket. If the socket is still bound, an error is returned. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to UDP socket */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* tx_mutex_get Obtain protection mutex */ +/* tx_mutex_put Release protection mutex */ +/* _tx_thread_system_preempt_check Check for preemption */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_udp_socket_delete(NX_UDP_SOCKET *socket_ptr) +{ + +TX_INTERRUPT_SAVE_AREA + +NX_IP *ip_ptr; + + + /* Setup the pointer to the associated IP instance. */ + ip_ptr = socket_ptr -> nx_udp_socket_ip_ptr; + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_UDP_SOCKET_DELETE, ip_ptr, socket_ptr, 0, 0, NX_TRACE_UDP_EVENTS, 0, 0) + + /* Obtain the IP mutex so we can process the socket delete request. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Determine if the socket has been created. */ + if (socket_ptr -> nx_udp_socket_id != NX_UDP_ID) + { + + /* Release the protection mutex. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return a not created error code. */ + return(NX_NOT_CREATED); + } + + /* Determine if the socket is still bound to port. */ + if (socket_ptr -> nx_udp_socket_bound_next) + { + + /* Release the protection mutex. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return a still bound error code. */ + return(NX_STILL_BOUND); + } + + /* Disable interrupts. */ + TX_DISABLE + + /* Now, remove the UDP socket from the created socket list. */ + + /* Clear the socket ID to make it invalid. */ + socket_ptr -> nx_udp_socket_id = 0; + + /* See if the socket is the only one on the list. */ + if (socket_ptr == socket_ptr -> nx_udp_socket_created_next) + { + + /* Only created socket, just set the created list to NULL. */ + ip_ptr -> nx_ip_udp_created_sockets_ptr = NX_NULL; + } + else + { + + /* Link-up the neighbors. */ + (socket_ptr -> nx_udp_socket_created_next) -> nx_udp_socket_created_previous = + socket_ptr -> nx_udp_socket_created_previous; + (socket_ptr -> nx_udp_socket_created_previous) -> nx_udp_socket_created_next = + socket_ptr -> nx_udp_socket_created_next; + + /* See if we have to update the created list head pointer. */ + if (ip_ptr -> nx_ip_udp_created_sockets_ptr == socket_ptr) + { + + /* Yes, move the head pointer to the next link. */ + ip_ptr -> nx_ip_udp_created_sockets_ptr = socket_ptr -> nx_udp_socket_created_next; + } + } + + /* Decrease the created sockets count. */ + ip_ptr -> nx_ip_udp_created_sockets_count--; + + /* Restore interrupts. */ + TX_RESTORE + + /* If trace is enabled, unregister this object. */ + NX_TRACE_OBJECT_UNREGISTER(socket_ptr) + + /* Release the IP protection mutex. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Check for preemption. */ + _tx_thread_system_preempt_check(); + + /* Return success. */ + return(NX_SUCCESS); +} + diff --git a/common/src/nx_udp_socket_info_get.c b/common/src/nx_udp_socket_info_get.c new file mode 100644 index 0000000..c5d0d31 --- /dev/null +++ b/common/src/nx_udp_socket_info_get.c @@ -0,0 +1,159 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** User Datagram Protocol (UDP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_udp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_udp_socket_info_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves UDP information from the specified socket. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP control block */ +/* udp_packets_sent Destination to the number of */ +/* packets sent */ +/* udp_bytes_sent Destination to the number of */ +/* bytes sent */ +/* udp_packets_received Destination to the number of */ +/* packets received */ +/* udp_bytes_received Destination to the number of */ +/* bytes received */ +/* udp_packets_queued Destination to the number of */ +/* receive packets queued */ +/* udp_receive_packets_dropped Destination to the number of */ +/* receive packets dropped */ +/* udp_checksum_errors Destination to the number of */ +/* checksum errors */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_udp_socket_info_get(NX_UDP_SOCKET *socket_ptr, ULONG *udp_packets_sent, ULONG *udp_bytes_sent, + ULONG *udp_packets_received, ULONG *udp_bytes_received, ULONG *udp_packets_queued, + ULONG *udp_receive_packets_dropped, ULONG *udp_checksum_errors) +{ + +TX_INTERRUPT_SAVE_AREA + + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_UDP_SOCKET_INFO_GET, socket_ptr -> nx_udp_socket_ip_ptr, socket_ptr, socket_ptr -> nx_udp_socket_bytes_sent, socket_ptr -> nx_udp_socket_bytes_received, NX_TRACE_UDP_EVENTS, 0, 0) + + /* Disable interrupts. */ + TX_DISABLE + + /* Determine if packets sent is wanted. */ + if (udp_packets_sent) + { + + /* Return the number of packets sent by this socket. */ + *udp_packets_sent = socket_ptr -> nx_udp_socket_packets_sent; + } + + /* Determine if bytes sent is wanted. */ + if (udp_bytes_sent) + { + + /* Return the number of bytes sent by this socket. */ + *udp_bytes_sent = socket_ptr -> nx_udp_socket_bytes_sent; + } + + /* Determine if packets received is wanted. */ + if (udp_packets_received) + { + + /* Return the number of packets received by this socket. */ + *udp_packets_received = socket_ptr -> nx_udp_socket_packets_received; + } + + /* Determine if bytes received is wanted. */ + if (udp_bytes_received) + { + + /* Return the number of bytes received by this socket. */ + *udp_bytes_received = socket_ptr -> nx_udp_socket_bytes_received; + } + + /* Determine if receive packets queued is wanted. */ + if (udp_packets_queued) + { + + /* Return the number of queued receive packets by this socket. */ + *udp_packets_queued = socket_ptr -> nx_udp_socket_receive_count; + } + + /* Determine if receive packets dropped is wanted. */ + if (udp_receive_packets_dropped) + { + + /* Return the number of receive packets dropped by this socket. */ + *udp_receive_packets_dropped = socket_ptr -> nx_udp_socket_packets_dropped; + } + + /* Determine if checksum errors is wanted. */ + if (udp_checksum_errors) + { + + /* Return the number of checksum errors by this socket. */ + *udp_checksum_errors = socket_ptr -> nx_udp_socket_checksum_errors; + } + + /* Restore interrupts. */ + TX_RESTORE + + /* Return successful completion. */ + return(NX_SUCCESS); +} + diff --git a/common/src/nx_udp_socket_interface_send.c b/common/src/nx_udp_socket_interface_send.c new file mode 100644 index 0000000..b286913 --- /dev/null +++ b/common/src/nx_udp_socket_interface_send.c @@ -0,0 +1,101 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** User Datagram Protocol (UDP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_udp.h" +#include "nx_ip.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_udp_socket_interface_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sends the supplied UDP packet through the supplied */ +/* socket to the supplied IP address and port. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to UDP socket */ +/* packet_ptr Pointer to UDP packet */ +/* ip_address IP address */ +/* port 16-bit UDP port number */ +/* interface_index Network interface to use */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ip_packet_send Send the UDP packet over IP */ +/* nx_ip_route_find Find a suitable outgoing */ +/* interface. */ +/* tx_mutex_get Get protection mutex */ +/* tx_mutex_put Put protection mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_udp_socket_interface_send(NX_UDP_SOCKET *socket_ptr, NX_PACKET *packet_ptr, + ULONG ip_address, UINT port, UINT interface_index) +{ +UINT status; +NX_IP *ip_ptr; + + + /* Obtain the IP pointer. */ + ip_ptr = socket_ptr -> nx_udp_socket_ip_ptr; + /* Insert interface information into the packet. */ + + /* Setup the pointer to the associated IP instance. */ + ip_ptr = socket_ptr -> nx_udp_socket_ip_ptr; + + /* Store interface information into the packet structure. */ + packet_ptr -> nx_packet_ip_interface = &(ip_ptr -> nx_ip_interface[interface_index]); + + /* Call udp_socket_send service */ + status = _nx_udp_socket_send(socket_ptr, packet_ptr, ip_address, port); + + return(status); +} + diff --git a/common/src/nx_udp_socket_port_get.c b/common/src/nx_udp_socket_port_get.c new file mode 100644 index 0000000..060e5aa --- /dev/null +++ b/common/src/nx_udp_socket_port_get.c @@ -0,0 +1,104 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** User Datagram Protocol (UDP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_udp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_udp_socket_port_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves the bound port of the specified socket, */ +/* which is especially useful in situations where NX_ANY_PORT was */ +/* used to bind. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to UDP socket */ +/* port_ptr Destination for port bound to */ +/* this socket */ +/* */ +/* 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_udp_socket_port_get(NX_UDP_SOCKET *socket_ptr, UINT *port_ptr) +{ +TX_INTERRUPT_SAVE_AREA + + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_UDP_SOCKET_PORT_GET, socket_ptr -> nx_udp_socket_ip_ptr, socket_ptr, socket_ptr -> nx_udp_socket_port, 0, NX_TRACE_UDP_EVENTS, 0, 0) + + /* Lockout interrupts. */ + TX_DISABLE + + /* Determine if the socket is currently bound. */ + if (!socket_ptr -> nx_udp_socket_bound_next) + { + + /* Restore interrupts. */ + TX_RESTORE + + /* Socket is not bound, return an error message. */ + return(NX_NOT_BOUND); + } + + /* Pickup the bound port for the UDP socket. */ + *port_ptr = socket_ptr -> nx_udp_socket_port; + + /* Restore interrupts. */ + TX_RESTORE + + /* Return a successful status. */ + return(NX_SUCCESS); +} + diff --git a/common/src/nx_udp_socket_receive.c b/common/src/nx_udp_socket_receive.c new file mode 100644 index 0000000..999f04d --- /dev/null +++ b/common/src/nx_udp_socket_receive.c @@ -0,0 +1,432 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** User Datagram Protocol (UDP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "tx_thread.h" +#include "nx_packet.h" +#include "nx_udp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_udp_socket_receive PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves UDP packet received on the socket; if a wait*/ +/* option is specified, it suspends; otherwise it returns immediately. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to UDP socket */ +/* packet_ptr Pointer to UDP packet pointer */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_packet_release Release data packet */ +/* _tx_thread_system_suspend Suspend thread */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_udp_socket_receive(NX_UDP_SOCKET *socket_ptr, NX_PACKET **packet_ptr, ULONG wait_option) +{ +TX_INTERRUPT_SAVE_AREA + +#ifndef NX_DISABLE_UDP_RX_CHECKSUM +ULONG checksum; +ULONG length; +ULONG temp; +ULONG *temp_ptr; +UCHAR *word_ptr; +UCHAR *pad_ptr; +ULONG packet_length; +ULONG adjusted_packet_length; +NX_PACKET *current_packet; +#endif +TX_THREAD *thread_ptr; + +#ifdef TX_ENABLE_EVENT_TRACE +TX_TRACE_BUFFER_ENTRY *trace_event; +ULONG trace_timestamp; +#endif + + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_UDP_SOCKET_RECEIVE, socket_ptr -> nx_udp_socket_ip_ptr, socket_ptr, 0, 0, NX_TRACE_UDP_EVENTS, &trace_event, &trace_timestamp) + + /* Set the return pointer to NULL initially. */ + *packet_ptr = NX_NULL; + + /* Loop to retrieve a packet from the interface. */ + do + { + + /* Lockout interrupts. */ + TX_DISABLE + + /* Determine if the socket is currently bound. */ + if (!socket_ptr -> nx_udp_socket_bound_next) + { + + /* Restore interrupts. */ + TX_RESTORE + + /* Socket is not bound, return an error message. */ + return(NX_NOT_BOUND); + } + + /* Determine if there is a packet already queued up for this socket. */ + if (socket_ptr -> nx_udp_socket_receive_count) + { + + /* Yes, there is a packet waiting. */ + + /* Remove it and place it in the thread's destination. */ + *packet_ptr = socket_ptr -> nx_udp_socket_receive_head; + socket_ptr -> nx_udp_socket_receive_head = (*packet_ptr) -> nx_packet_queue_next; + + /* If this was the last packet, set the tail pointer to NULL. */ + if (socket_ptr -> nx_udp_socket_receive_head == NX_NULL) + { + socket_ptr -> nx_udp_socket_receive_tail = NX_NULL; + } + + /* Decrease the queued packet count. */ + socket_ptr -> nx_udp_socket_receive_count--; + + /* Restore interrupts. */ + TX_RESTORE + } + else + { + + /* Determine if the request specifies suspension. */ + if (wait_option) + { + + /* Prepare for suspension of this thread. */ + + /* Pickup thread pointer. */ + thread_ptr = _tx_thread_current_ptr; + + /* Setup cleanup routine pointer. */ + thread_ptr -> tx_thread_suspend_cleanup = _nx_udp_receive_cleanup; + + /* Setup cleanup information, i.e. this pool control + block. */ + thread_ptr -> tx_thread_suspend_control_block = (void *)socket_ptr; + + /* Save the return packet pointer address as well. */ + thread_ptr -> tx_thread_additional_suspend_info = (void *)packet_ptr; + + /* Setup suspension list. */ + if (socket_ptr -> nx_udp_socket_receive_suspension_list) + { + + /* This list is not NULL, add current thread to the end. */ + thread_ptr -> tx_thread_suspended_next = + socket_ptr -> nx_udp_socket_receive_suspension_list; + thread_ptr -> tx_thread_suspended_previous = + (socket_ptr -> nx_udp_socket_receive_suspension_list) -> tx_thread_suspended_previous; + ((socket_ptr -> nx_udp_socket_receive_suspension_list) -> tx_thread_suspended_previous) -> tx_thread_suspended_next = + thread_ptr; + (socket_ptr -> nx_udp_socket_receive_suspension_list) -> tx_thread_suspended_previous = thread_ptr; + } + else + { + + /* No other threads are suspended. Setup the head pointer and + just setup this threads pointers to itself. */ + socket_ptr -> nx_udp_socket_receive_suspension_list = thread_ptr; + thread_ptr -> tx_thread_suspended_next = thread_ptr; + thread_ptr -> tx_thread_suspended_previous = thread_ptr; + } + + /* Increment the suspended thread count. */ + socket_ptr -> nx_udp_socket_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); + + /* Determine if a packet was received successfully. */ + if (thread_ptr -> tx_thread_suspend_status != NX_SUCCESS) + { + + /* If not, just return the error code. */ + return(thread_ptr -> tx_thread_suspend_status); + } + + /* Otherwise, just fall through to the checksum logic for the UDP + packet. */ + } + else + { + + /* Restore interrupts. */ + TX_RESTORE + + /* Immediate return, return error completion. */ + return(NX_NO_PACKET); + } + } + +#ifndef NX_DISABLE_UDP_RX_CHECKSUM + + /* Determine if we need to compute the UDP checksum. If it is disabled for this socket + or if the UDP packet has a zero in the checksum field (indicating it was not computed + by the sender, skip the checksum processing. */ + temp_ptr = (ULONG *)(*packet_ptr) -> nx_packet_prepend_ptr; + if ((!socket_ptr -> nx_udp_socket_disable_checksum) && (*(temp_ptr + 1) & NX_LOWER_16_MASK)) + { + + /* Yes, we need to compute the UDP checksum. */ + + /* First calculate the checksum of the pseudo UDP header that includes the source IP + address, destination IP address, protocol word, and the UDP length. */ + temp = *(temp_ptr - 2); + checksum = (temp >> NX_SHIFT_BY_16); + checksum += (temp & NX_LOWER_16_MASK); + temp = *(temp_ptr - 1); + checksum += (temp >> NX_SHIFT_BY_16); + checksum += (temp & NX_LOWER_16_MASK); + checksum += (NX_IP_UDP >> NX_SHIFT_BY_16); + checksum += (*packet_ptr) -> nx_packet_length; + + /* Endian swapping logic. If NX_LITTLE_ENDIAN is specified, these macros will + swap the endian of the UDP header. */ + NX_CHANGE_ULONG_ENDIAN(*(temp_ptr)); + NX_CHANGE_ULONG_ENDIAN(*(temp_ptr + 1)); + + /* Setup the length of the packet checksum. */ + length = (*packet_ptr) -> nx_packet_length; + + /* Initialize the current packet to the input packet pointer. */ + current_packet = *packet_ptr; + + /* Loop to calculate the packet's checksum. */ + while (length) + { + /* Calculate the current packet length. */ + packet_length = (ULONG)(current_packet -> nx_packet_append_ptr - current_packet -> nx_packet_prepend_ptr); + + /* Make the adjusted packet length evenly divisible by sizeof(ULONG). */ + adjusted_packet_length = ((packet_length + (sizeof(ULONG) - 1)) / sizeof(ULONG)) * sizeof(ULONG); + + /* Determine if we need to add padding bytes. */ + if (packet_length < adjusted_packet_length) + { + + /* Calculate how many bytes we need to zero at the end of the packet. */ + temp = adjusted_packet_length - packet_length; + + /* Setup temporary pointer to the current packet's append pointer. */ + pad_ptr = current_packet -> nx_packet_append_ptr; + + /* Loop to pad current packet with 0s so we don't have to worry about a partial last word. */ + while (temp) + { + + /* Check for the end of the packet. */ + if (pad_ptr >= current_packet -> nx_packet_data_end) + { + break; + } + + /* Write a 0. */ + *pad_ptr++ = 0; + + /* Decrease the pad count. */ + temp--; + } + } + + /* Setup the pointer to the start of the packet. */ + word_ptr = (UCHAR *)current_packet -> nx_packet_prepend_ptr; + + /* Now loop through the current packet to compute the checksum on this packet. */ + while (adjusted_packet_length) + { + + /* Pickup a whole ULONG. */ + temp = *((ULONG *)word_ptr); + + /* Endian swapping logic. If NX_LITTLE_ENDIAN is specified, these macros will + swap the endian of the long word in the message. */ + NX_CHANGE_ULONG_ENDIAN(temp); + + /* Add upper 16-bits into checksum. */ + checksum = checksum + (temp >> NX_SHIFT_BY_16); + + /* Add lower 16-bits into checksum. */ + checksum = checksum + (temp & NX_LOWER_16_MASK); + + /* Move the word pointer and decrease the length. */ + word_ptr = word_ptr + sizeof(ULONG); + adjusted_packet_length = adjusted_packet_length - sizeof(ULONG); + } + + /* Adjust the checksum length. */ + length = length - packet_length; + + /* Determine if we are at the end of the current packet. */ + if ((length) && (word_ptr >= (UCHAR *)current_packet -> nx_packet_append_ptr) && + (current_packet -> nx_packet_next)) + { + + /* We have crossed the packet boundary. Move to the next packet + structure. */ + current_packet = current_packet -> nx_packet_next; + + /* Setup the new word pointer. */ + word_ptr = (UCHAR *)current_packet -> nx_packet_prepend_ptr; + } + } + + /* Endian swapping logic. If NX_LITTLE_ENDIAN is specified, these macros will + swap the endian of the UDP header. */ + NX_CHANGE_ULONG_ENDIAN(*(temp_ptr)); + NX_CHANGE_ULONG_ENDIAN(*(temp_ptr + 1)); + + /* Add in the carry bits into the checksum. */ + checksum = (checksum >> NX_SHIFT_BY_16) + (checksum & NX_LOWER_16_MASK); + + /* Do it again in case previous operation generates an overflow. */ + checksum = (checksum >> NX_SHIFT_BY_16) + (checksum & NX_LOWER_16_MASK); + + /* Perform the one's complement processing on the checksum. */ + checksum = NX_LOWER_16_MASK & ~checksum; + + /* Determine if it is valid. */ + if (checksum == 0) + { + + /* The checksum is okay, so get out of the loop. */ + break; + } + else + { + +#ifndef NX_DISABLE_UDP_INFO + + /* Disable interrupts. */ + TX_DISABLE + + /* Increment the UDP checksum error count. */ + (socket_ptr -> nx_udp_socket_ip_ptr) -> nx_ip_udp_checksum_errors++; + + /* Increment the UDP invalid packets error count. */ + (socket_ptr -> nx_udp_socket_ip_ptr) -> nx_ip_udp_invalid_packets++; + + /* Increment the UDP checksum error count for this socket. */ + socket_ptr -> nx_udp_socket_checksum_errors++; + + /* Decrement the total UDP receive packets count. */ + (socket_ptr -> nx_udp_socket_ip_ptr) -> nx_ip_udp_packets_received--; + + /* Decrement the total UDP receive bytes. */ + (socket_ptr -> nx_udp_socket_ip_ptr) -> nx_ip_udp_bytes_received -= (*packet_ptr) -> nx_packet_length - sizeof(NX_UDP_HEADER); + + /* Decrement the total UDP receive packets count. */ + socket_ptr -> nx_udp_socket_packets_received--; + + /* Decrement the total UDP receive bytes. */ + socket_ptr -> nx_udp_socket_bytes_received -= (*packet_ptr) -> nx_packet_length - sizeof(NX_UDP_HEADER); + + /* Restore interrupts. */ + TX_RESTORE +#endif + + /* Bad UDP checksum. Release the packet. */ + _nx_packet_release(*packet_ptr); + } + } + else + { + + /* Checksum logic is either disabled for this socket or the received + UDP packet checksum was not calculated - get out of the loop. */ + break; + } +#else + + /* Simply break - checksum logic is conditionally disabled. */ + break; +#endif + } while (NX_FOREVER); + + /* At this point, we have a valid UDP packet for the caller. */ + + /* Remove the UDP header. */ + + /* Decrease the packet length. */ + (*packet_ptr) -> nx_packet_length = (*packet_ptr) -> nx_packet_length - sizeof(NX_UDP_HEADER); + + /* Position past the UDP header pointer. */ + (*packet_ptr) -> nx_packet_prepend_ptr = (*packet_ptr) -> nx_packet_prepend_ptr + sizeof(NX_UDP_HEADER); + + /* Update the trace event with the status. */ + NX_TRACE_EVENT_UPDATE(trace_event, trace_timestamp, NX_TRACE_UDP_SOCKET_RECEIVE, 0, 0, *packet_ptr, (*packet_ptr) -> nx_packet_length) + + /* Return a successful status to the caller. */ + return(NX_SUCCESS); +} + diff --git a/common/src/nx_udp_socket_receive_notify.c b/common/src/nx_udp_socket_receive_notify.c new file mode 100644 index 0000000..af2accb --- /dev/null +++ b/common/src/nx_udp_socket_receive_notify.c @@ -0,0 +1,96 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** User Datagram Protocol (UDP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_udp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_udp_socket_receive_notify PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sets the receive notify function pointer to the */ +/* function specified by the application, which is called whenever */ +/* a packet is received on the socket. If a NULL pointer is supplied, */ +/* the receive notify function is disabled. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to UDP socket */ +/* udp_receive_notify Routine to call when one or */ +/* receive packets are */ +/* available for the socket */ +/* */ +/* 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_udp_socket_receive_notify(NX_UDP_SOCKET *socket_ptr, + VOID (*udp_receive_notify)(NX_UDP_SOCKET *socket_ptr)) +{ +TX_INTERRUPT_SAVE_AREA + + + /* Disable interrupts. */ + TX_DISABLE + + /* Setup the receive notify function pointer. */ + socket_ptr -> nx_udp_receive_callback = udp_receive_notify; + + /* Restore interrupts. */ + TX_RESTORE + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_UDP_SOCKET_RECEIVE_NOTIFY, socket_ptr -> nx_udp_socket_ip_ptr, socket_ptr, udp_receive_notify, 0, NX_TRACE_UDP_EVENTS, 0, 0) + + /* Return successful completion. */ + return(NX_SUCCESS); +} + diff --git a/common/src/nx_udp_socket_send.c b/common/src/nx_udp_socket_send.c new file mode 100644 index 0000000..4d09cb4 --- /dev/null +++ b/common/src/nx_udp_socket_send.c @@ -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 Component */ +/** */ +/** User Datagram Protocol (UDP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_udp.h" +#include "nx_ip.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_udp_socket_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function sends the supplied UDP packet through the supplied */ +/* socket to the supplied IP address and port. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to UDP socket */ +/* packet_ptr Pointer to UDP packet */ +/* ip_address IP address */ +/* port 16-bit UDP port number */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ip_packet_send Send the UDP packet over IP */ +/* nx_ip_route_find Find a suitable outgoing */ +/* interface. */ +/* tx_mutex_get Get protection mutex */ +/* tx_mutex_put Put protection mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_udp_socket_send(NX_UDP_SOCKET *socket_ptr, NX_PACKET *packet_ptr, + ULONG ip_address, UINT port) +{ +TX_INTERRUPT_SAVE_AREA + +#ifndef NX_DISABLE_UDP_TX_CHECKSUM +ULONG checksum; +ULONG length; +ULONG temp; +UCHAR *word_ptr; +ULONG packet_length; +ULONG adjusted_packet_length; +NX_PACKET *current_packet; +UCHAR *pad_ptr; +#endif +NX_IP *ip_ptr; +NX_UDP_HEADER *udp_header_ptr; + + /* Lockout interrupts. */ + TX_DISABLE + + /* Determine if the socket is currently bound. */ + if (!socket_ptr -> nx_udp_socket_bound_next) + { + + /* Restore interrupts. */ + TX_RESTORE + + /* Socket is not bound, return an error message. */ + return(NX_NOT_BOUND); + } + + /* Pickup the important information from the socket. */ + + /* Setup the pointer to the associated IP instance. */ + ip_ptr = socket_ptr -> nx_udp_socket_ip_ptr; + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_UDP_SOCKET_SEND, socket_ptr, packet_ptr, packet_ptr -> nx_packet_length, ip_address, NX_TRACE_UDP_EVENTS, 0, 0) + + /* Restore interrupts. */ + TX_RESTORE + + /* If the packet does not have outgoing interface defined, pick up the outgoing interface from the socket structure. */ + if (packet_ptr -> nx_packet_ip_interface == NX_NULL) + { + packet_ptr -> nx_packet_ip_interface = socket_ptr -> nx_udp_socket_ip_interface; + } + + /* Call IP routing service to find the best interface for transmitting this packet. */ + if (_nx_ip_route_find(ip_ptr, ip_address, &packet_ptr -> nx_packet_ip_interface, &packet_ptr -> nx_packet_next_hop_address) != NX_SUCCESS) + { + return(NX_IP_ADDRESS_ERROR); + } + + /* 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); + +#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 + 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)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); + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_INTERNAL_UDP_SEND, ip_ptr, socket_ptr, packet_ptr, udp_header_ptr -> nx_udp_header_word_0, NX_TRACE_INTERNAL_EVENTS, 0, 0) + + /* 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); + +#ifndef NX_DISABLE_UDP_TX_CHECKSUM + + /* Determine if we need to compute the UDP checksum. */ + if (!socket_ptr -> nx_udp_socket_disable_checksum) + { + + /* Yes, we need to compute the UDP checksum. */ + + /* First calculate the checksum of the pseudo UDP header that includes the source IP + address, destination IP address, protocol word, and the UDP length. */ + temp = packet_ptr -> nx_packet_ip_interface -> nx_interface_ip_address; + checksum = (temp >> NX_SHIFT_BY_16); + checksum += (temp & NX_LOWER_16_MASK); + checksum += (ip_address >> NX_SHIFT_BY_16); + checksum += (ip_address & NX_LOWER_16_MASK); + checksum += (NX_IP_UDP >> NX_SHIFT_BY_16); + checksum += packet_ptr -> nx_packet_length; + + /* Setup the length of the packet checksum. */ + length = packet_ptr -> nx_packet_length; + + /* Initialize the current packet to the input packet pointer. */ + current_packet = packet_ptr; + + /* Loop to calculate the packet's checksum. */ + while (length) + { + /* Calculate the current packet length. */ + packet_length = (ULONG)(current_packet -> nx_packet_append_ptr - current_packet -> nx_packet_prepend_ptr); + + /* Make the adjusted packet length evenly divisible by sizeof(ULONG). */ + adjusted_packet_length = ((packet_length + (sizeof(ULONG) - 1)) / sizeof(ULONG)) * sizeof(ULONG); + + /* Determine if we need to add padding bytes. */ + if (packet_length < adjusted_packet_length) + { + + /* Calculate how many bytes we need to zero at the end of the packet. */ + temp = adjusted_packet_length - packet_length; + + /* Setup temporary pointer to the current packet's append pointer. */ + pad_ptr = current_packet -> nx_packet_append_ptr; + + /* Loop to pad current packet with 0s so we don't have to worry about a partial last word. */ + while (temp) + { + + /* Check for the end of the packet. */ + if (pad_ptr >= current_packet -> nx_packet_data_end) + { + break; + } + + /* Write a 0. */ + *pad_ptr++ = 0; + + /* Decrease the pad count. */ + temp--; + } + } + + + /* Setup the pointer to the start of the packet. */ + word_ptr = (UCHAR *)current_packet -> nx_packet_prepend_ptr; + + /* Now loop through the current packet to compute the checksum on this packet. */ + while (adjusted_packet_length) + { + + /* Pickup a whole ULONG. */ + temp = *((ULONG *)word_ptr); + + /* Endian swapping logic. If NX_LITTLE_ENDIAN is specified, these macros will + swap the endian of the long word in the message. */ + NX_CHANGE_ULONG_ENDIAN(temp); + + /* Add upper 16-bits into checksum. */ + checksum = checksum + (temp >> NX_SHIFT_BY_16); + + /* Add lower 16-bits into checksum. */ + checksum = checksum + (temp & NX_LOWER_16_MASK); + + /* Move the word pointer and decrease the length. */ + word_ptr = word_ptr + sizeof(ULONG); + adjusted_packet_length = adjusted_packet_length - sizeof(ULONG); + } + + /* Adjust the checksum length. */ + length = length - packet_length; + + /* Determine if we are at the end of the current packet. */ + if ((length) && (word_ptr >= (UCHAR *)current_packet -> nx_packet_append_ptr) && + (current_packet -> nx_packet_next)) + { + + /* We have crossed the packet boundary. Move to the next packet + structure. */ + current_packet = current_packet -> nx_packet_next; + + /* Setup the new word pointer. */ + word_ptr = (UCHAR *)current_packet -> nx_packet_prepend_ptr; + } + } + + /* Add in the carry bits into the checksum. */ + checksum = (checksum >> NX_SHIFT_BY_16) + (checksum & NX_LOWER_16_MASK); + + /* Do it again in case previous operation generates an overflow. */ + checksum = (checksum >> NX_SHIFT_BY_16) + (checksum & NX_LOWER_16_MASK); + + /* Place the packet in the second word of the UDP header. */ + 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_LOWER_16_MASK); + NX_CHANGE_ULONG_ENDIAN(udp_header_ptr -> nx_udp_header_word_1); + } +#endif + + /* Get mutex protection. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Send the UDP packet to the IP component. */ + _nx_ip_packet_send(ip_ptr, packet_ptr, ip_address, + socket_ptr -> nx_udp_socket_type_of_service, socket_ptr -> nx_udp_socket_time_to_live, NX_IP_UDP, socket_ptr -> nx_udp_socket_fragment_enable); + + /* Release mutex protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return a successful status. */ + return(NX_SUCCESS); +} + diff --git a/common/src/nx_udp_socket_unbind.c b/common/src/nx_udp_socket_unbind.c new file mode 100644 index 0000000..b34ad9c --- /dev/null +++ b/common/src/nx_udp_socket_unbind.c @@ -0,0 +1,363 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** User Datagram Protocol (UDP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_udp.h" +#include "nx_packet.h" +#include "tx_thread.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_udp_socket_unbind PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function unbinds the UDP socket structure from the previously */ +/* bound UDP port. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to UDP socket */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_packet_release Release data packet */ +/* _nx_udp_bind_cleanup Remove and cleanup bind req */ +/* tx_mutex_get Obtain protection mutex */ +/* tx_mutex_put Release protection mutex */ +/* _tx_thread_system_resume Resume suspended thread */ +/* _tx_thread_system_preempt_check Check for preemption */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_udp_socket_unbind(NX_UDP_SOCKET *socket_ptr) +{ +TX_INTERRUPT_SAVE_AREA + +UINT index; +UINT port; +NX_IP *ip_ptr; +TX_THREAD *thread_ptr; +NX_UDP_SOCKET *new_socket_ptr; +NX_PACKET *packet_ptr; +NX_PACKET *next_packet_ptr; + + + /* Setup the pointer to the associated IP instance. */ + ip_ptr = socket_ptr -> nx_udp_socket_ip_ptr; + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_UDP_SOCKET_UNBIND, ip_ptr, socket_ptr, socket_ptr -> nx_udp_socket_port, 0, NX_TRACE_UDP_EVENTS, 0, 0) + + /* Obtain the IP mutex so we can figure out whether or not the port has already + been bound to. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Determine if the socket is bound to port. */ + if (!socket_ptr -> nx_udp_socket_bound_next) + { + + /* Determine if there is a special condition for the socket not being in + a bound condition... i.e. the socket is in a pending-to-be-bound condition + in a call from a different thread. */ + if (socket_ptr -> nx_udp_socket_bind_in_progress) + { + + /* Execute the bind suspension cleanup routine. */ + _nx_udp_bind_cleanup(socket_ptr -> nx_udp_socket_bind_in_progress NX_CLEANUP_ARGUMENT); + + /* Release the protection mutex. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return success. */ + return(NX_SUCCESS); + } + else + { + + /* Release the protection mutex. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return a not bound error code. */ + return(NX_NOT_BOUND); + } + } + + /* Otherwise, the socket is bound. We need to remove this socket from the + port and check for any other UDP socket bind requests that are queued. */ + + /* Pickup the port number in the UDP socket structure. */ + port = socket_ptr -> nx_udp_socket_port; + + /* Calculate the hash index in the UDP port array of the associated IP instance. */ + index = (UINT)((port + (port >> 8)) & NX_UDP_PORT_TABLE_MASK); + + /* Disable interrupts while we unlink the current socket. */ + TX_DISABLE + + /* Determine if this is the only socket bound on this port list. */ + if (socket_ptr -> nx_udp_socket_bound_next == socket_ptr) + { + + /* Yes, this is the only socket on the port list. */ + + /* Clear the list head pointer and the next pointer in the socket. */ + ip_ptr -> nx_ip_udp_port_table[index] = NX_NULL; + socket_ptr -> nx_udp_socket_bound_next = NX_NULL; + } + else + { + + /* Relink the neighbors of this UDP socket. */ + + /* Update the links of the adjacent sockets. */ + (socket_ptr -> nx_udp_socket_bound_next) -> nx_udp_socket_bound_previous = + socket_ptr -> nx_udp_socket_bound_previous; + (socket_ptr -> nx_udp_socket_bound_previous) -> nx_udp_socket_bound_next = + socket_ptr -> nx_udp_socket_bound_next; + + /* Determine if the head of the port list points to the socket being removed. + If so, we need to move the head pointer. */ + if (ip_ptr -> nx_ip_udp_port_table[index] == socket_ptr) + { + + /* Yes, we need to move the port list head pointer. */ + ip_ptr -> nx_ip_udp_port_table[index] = socket_ptr -> nx_udp_socket_bound_next; + } + + /* Clear the next pointer in the socket to indicate it is no longer bound. */ + socket_ptr -> nx_udp_socket_bound_next = NX_NULL; + } + + /* Restore interrupts. */ + TX_RESTORE + + /* The socket is off the bound list... we need to check for queued packets and possible + receive suspension. We need to clean up either of these conditions. */ + if (socket_ptr -> nx_udp_socket_receive_count) + { + + /* Setup packet pointer. */ + packet_ptr = socket_ptr -> nx_udp_socket_receive_head; + + /* Clear the head and the tail pointers. */ + socket_ptr -> nx_udp_socket_receive_head = NX_NULL; + socket_ptr -> nx_udp_socket_receive_tail = NX_NULL; + + /* Loop to clear all the packets out. */ + while (socket_ptr -> nx_udp_socket_receive_count) + { + + /* Pickup the next queued packet. */ + next_packet_ptr = packet_ptr -> nx_packet_queue_next; + + /* Release the packet. */ + _nx_packet_release(packet_ptr); + + /* Move to the next packet. */ + packet_ptr = next_packet_ptr; + + /* Decrease the queued packet count. */ + socket_ptr -> nx_udp_socket_receive_count--; + } + } + else if (socket_ptr -> nx_udp_socket_receive_suspended_count) + { + + /* Clear out all threads suspended on this socket. */ + + /* Pickup the first suspended thread. */ + thread_ptr = socket_ptr -> nx_udp_socket_receive_suspension_list; + + /* Clear the thread receive suspension list. */ + socket_ptr -> nx_udp_socket_receive_suspension_list = NX_NULL; + + /* Walk through the queue list to resume any and all threads suspended + on this queue. */ + while (socket_ptr -> nx_udp_socket_receive_suspended_count) + { + + /* Lockout interrupts. */ + TX_DISABLE + + /* Clear the cleanup pointer, this prevents the timeout from doing + anything. */ + thread_ptr -> tx_thread_suspend_cleanup = TX_NULL; + + /* Temporarily disable preemption again. */ + _tx_thread_preempt_disable++; + + /* Restore interrupts. */ + TX_RESTORE + + /* Set the return status in the thread to NX_SOCKET_UNBOUND. */ + thread_ptr -> tx_thread_suspend_status = NX_SOCKET_UNBOUND; + + /* Move the thread pointer ahead. */ + thread_ptr = thread_ptr -> tx_thread_suspended_next; + + /* Resume the thread. */ + _tx_thread_system_resume(thread_ptr -> tx_thread_suspended_previous); + + /* Decrease the suspended count. */ + socket_ptr -> nx_udp_socket_receive_suspended_count--; + } + } + + /* Disable interrupts again. */ + TX_DISABLE + + /* Determine if there are any threads suspended on trying to bind to the + same port. */ + thread_ptr = socket_ptr -> nx_udp_socket_bind_suspension_list; + 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. */ + socket_ptr -> nx_udp_socket_bind_suspension_list = NX_NULL; + } + else + { + + /* At least one more thread is on the same expiration list. */ + + /* Update the list head pointer. */ + socket_ptr -> nx_udp_socket_bind_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. */ + socket_ptr -> nx_udp_socket_bind_suspended_count--; + + /* Pickup the new socket structure to link to the port list. */ + new_socket_ptr = (NX_UDP_SOCKET *)thread_ptr -> tx_thread_suspend_control_block; + + /* Clear the new socket's bind in progress flag. */ + new_socket_ptr -> nx_udp_socket_bind_in_progress = NX_NULL; + + /* Inherit the suspension list from the previously bound socket. */ + new_socket_ptr -> nx_udp_socket_bind_suspension_list = + socket_ptr -> nx_udp_socket_bind_suspension_list; + socket_ptr -> nx_udp_socket_bind_suspension_list = NX_NULL; + + /* Link the new socket to the bound list. */ + if (ip_ptr -> nx_ip_udp_port_table[index]) + { + + /* There are already sockets on this list... just add this one + to the end. */ + new_socket_ptr -> nx_udp_socket_bound_next = + ip_ptr -> nx_ip_udp_port_table[index]; + new_socket_ptr -> nx_udp_socket_bound_previous = + (ip_ptr -> nx_ip_udp_port_table[index]) -> nx_udp_socket_bound_previous; + ((ip_ptr -> nx_ip_udp_port_table[index]) -> nx_udp_socket_bound_previous) -> nx_udp_socket_bound_next = + new_socket_ptr; + (ip_ptr -> nx_ip_udp_port_table[index]) -> nx_udp_socket_bound_previous = new_socket_ptr; + } + else + { + + /* Nothing is on the UDP port list. Add this UDP socket to an + empty list. */ + new_socket_ptr -> nx_udp_socket_bound_next = new_socket_ptr; + new_socket_ptr -> nx_udp_socket_bound_previous = new_socket_ptr; + ip_ptr -> nx_ip_udp_port_table[index] = new_socket_ptr; + } + + /* 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++; + + /* Restore interrupts. */ + TX_RESTORE + + /* Put return status into the thread control block. */ + thread_ptr -> tx_thread_suspend_status = NX_SUCCESS; + + /* Release the mutex protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Resume thread. */ + _tx_thread_system_resume(thread_ptr); + } + else + { + + /* Restore interrupts. */ + TX_RESTORE + + /* Release the mutex protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return success to the caller. */ + return(NX_SUCCESS); + } + + /* Check for preemption. */ + _tx_thread_system_preempt_check(); + + /* Return success. */ + return(NX_SUCCESS); +} + diff --git a/common/src/nx_udp_source_extract.c b/common/src/nx_udp_source_extract.c new file mode 100644 index 0000000..ac9eea9 --- /dev/null +++ b/common/src/nx_udp_source_extract.c @@ -0,0 +1,107 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** User Datagram Protocol (UDP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_udp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_udp_socket_extract PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function extracts the source IP and UDP port number from the */ +/* supplied packet. If the supplied packet does not have an IP and */ +/* UDP header, an error will be returned. */ +/* */ +/* INPUT */ +/* */ +/* packet_ptr Pointer to UDP packet pointer */ +/* ip_address Pointer to destination for IP */ +/* address */ +/* port Pointer to destination for */ +/* source UDP port */ +/* */ +/* 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_udp_source_extract(NX_PACKET *packet_ptr, ULONG *ip_address, UINT *port) +{ + +ULONG *temp_ptr; + + + /* Build an address to the current top of the packet. */ + temp_ptr = (ULONG *)packet_ptr -> nx_packet_prepend_ptr; + + /* Pickup the source port. */ + *port = (UINT)(*(temp_ptr - 2) >> NX_SHIFT_BY_16); + + /* Pickup the source IP address. */ + *ip_address = *(temp_ptr - 4); + + /* If trace is enabled, insert this event into the trace buffer. */ + NX_TRACE_IN_LINE_INSERT(NX_TRACE_UDP_SOURCE_EXTRACT, packet_ptr, *ip_address, *port, 0, NX_TRACE_UDP_EVENTS, 0, 0) + + /* Determine if IP address is non-zero. */ + if (*ip_address) + { + + /* Return a successful status to the caller. */ + return(NX_SUCCESS); + } + else + { + + /* Return an invalid packet error. */ + return(NX_INVALID_PACKET); + } +} + diff --git a/common/src/nx_utility.c b/common/src/nx_utility.c new file mode 100644 index 0000000..a120a33 --- /dev/null +++ b/common/src/nx_utility.c @@ -0,0 +1,109 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Utility */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "nx_api.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_utility_string_length_check PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function traverses the string and returns the string length, */ +/* if the string is invalid or the string length is bigger than max */ +/* string length, returns error. */ +/* */ +/* INPUT */ +/* */ +/* input_string Pointer to input string */ +/* string_length Pointer to string length, or */ +/* NX_NULL if caller does not */ +/* need the value. */ +/* max_string_length Max string length */ +/* */ +/* 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_utility_string_length_check(CHAR *input_string, UINT *string_length, UINT max_string_length) +{ + +UINT i; + + + /* Check for invalid input pointers. */ + if (input_string == NX_NULL) + { + return(NX_PTR_ERROR); + } + + /* Traverse the string. */ + for (i = 0; input_string[i]; i++) + { + + /* Check if the string length is bigger than the max string length. */ + if (i >= max_string_length) + { + return(NX_SIZE_ERROR); + } + } + + /* Return the string length if string_length is not NULL. + String_length being NULL indicates the caller needs to check for string + length within the max_string_length. */ + if (string_length) + { + *string_length = i; + } + + /* Return success. */ + return(NX_SUCCESS); +} + diff --git a/common/src/nxe_arp_dynamic_entries_invalidate.c b/common/src/nxe_arp_dynamic_entries_invalidate.c new file mode 100644 index 0000000..efeb9f0 --- /dev/null +++ b/common/src/nxe_arp_dynamic_entries_invalidate.c @@ -0,0 +1,103 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Address Resolution Protocol (ARP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_arp.h" + + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_arp_dynamic_entries_invalidate PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the ARP dynamic entries */ +/* invalidate function call. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP instance pointer */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_arp_dynamic_entries_invalidate Invalidate dynamic ARP entries*/ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_arp_dynamic_entries_invalidate(NX_IP *ip_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID)) + { + return(NX_PTR_ERROR); + } + + /* Check to see if ARP is enabled. */ + if (!ip_ptr -> nx_ip_arp_allocate) + { + return(NX_NOT_ENABLED); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual invalidate ARP dynamic entries function. */ + status = _nx_arp_dynamic_entries_invalidate(ip_ptr); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_arp_dynamic_entry_set.c b/common/src/nxe_arp_dynamic_entry_set.c new file mode 100644 index 0000000..443a637 --- /dev/null +++ b/common/src/nxe_arp_dynamic_entry_set.c @@ -0,0 +1,113 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Address Resolution Protocol (ARP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_arp.h" + + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_arp_dynamic_entry_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the ARP dynamic entry set */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP instance pointer */ +/* ip_address IP Address to bind to */ +/* physical_msw Physical address MSW */ +/* physical_lsw Physical address LSW */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_arp_dynamic_entry_set ARP dynamic entry set */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_arp_dynamic_entry_set(NX_IP *ip_ptr, ULONG ip_address, + ULONG physical_msw, ULONG physical_lsw) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID)) + { + return(NX_PTR_ERROR); + } + + /* Check for invalid IP address. */ + if (!ip_address) + { + return(NX_IP_ADDRESS_ERROR); + } + + /* Check to see if ARP is enabled. */ + if (!ip_ptr -> nx_ip_arp_allocate) + { + return(NX_NOT_ENABLED); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual ARP dynamic entry set function. */ + status = _nx_arp_dynamic_entry_set(ip_ptr, ip_address, physical_msw, physical_lsw); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_arp_enable.c b/common/src/nxe_arp_enable.c new file mode 100644 index 0000000..164b06a --- /dev/null +++ b/common/src/nxe_arp_enable.c @@ -0,0 +1,110 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Address Resolution Protocol (ARP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_arp.h" + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_arp_enable PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the ARP enable function */ +/* call. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP instance pointer */ +/* arp_cache_memory Start of ARP cache memory */ +/* arp_cache_size Size in bytes of cache memory */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_arp_enable Actual ARP enable function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_arp_enable(NX_IP *ip_ptr, VOID *arp_cache_memory, ULONG arp_cache_size) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) || (arp_cache_memory == NX_NULL)) + { + return(NX_PTR_ERROR); + } + + /* Check to see if ARP is already enabled. */ + if (ip_ptr -> nx_ip_arp_allocate) + { + return(NX_ALREADY_ENABLED); + } + + /* Check for invalid ARP cache size. */ + if (arp_cache_size < sizeof(NX_ARP)) + { + return(NX_SIZE_ERROR); + } + + /* Check for appropriate caller. */ + NX_INIT_AND_THREADS_CALLER_CHECKING + + /* Call actual ARP enable function. */ + status = _nx_arp_enable(ip_ptr, arp_cache_memory, arp_cache_size); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_arp_gratuitous_send.c b/common/src/nxe_arp_gratuitous_send.c new file mode 100644 index 0000000..5643362 --- /dev/null +++ b/common/src/nxe_arp_gratuitous_send.c @@ -0,0 +1,105 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Address Resolution Protocol (ARP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_arp.h" + + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_arp_gratuitous_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the Gratuitous ARP send */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP instance pointer */ +/* response_handler Pointer to function to handle */ +/* Gratuitous ARP response */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_arp_gratuitous_send Send Gratuitous ARP */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_arp_gratuitous_send(NX_IP *ip_ptr, VOID (*response_handler)(NX_IP *ip_ptr, NX_PACKET *packet_ptr)) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID)) + { + return(NX_PTR_ERROR); + } + + /* Check to see if ARP is enabled. */ + if (!ip_ptr -> nx_ip_arp_allocate) + { + return(NX_NOT_ENABLED); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual Gratuitous ARP send function. */ + status = _nx_arp_gratuitous_send(ip_ptr, response_handler); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_arp_hardware_address_find.c b/common/src/nxe_arp_hardware_address_find.c new file mode 100644 index 0000000..f33ba77 --- /dev/null +++ b/common/src/nxe_arp_hardware_address_find.c @@ -0,0 +1,113 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Address Resolution Protocol (ARP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_arp.h" + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_arp_hardware_address_find PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the ARP hardware address find */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP instance pointer */ +/* ip_address IP Address to search for */ +/* physical_msw Physical address MSW pointer */ +/* physical_lsw Physical address LSW pointer */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_arp_hardware_address_find Actual hardware address find */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_arp_hardware_address_find(NX_IP *ip_ptr, ULONG ip_address, + ULONG *physical_msw, ULONG *physical_lsw) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) || (physical_msw == NX_NULL) || (physical_lsw == NX_NULL)) + { + return(NX_PTR_ERROR); + } + + /* Check for invalid IP address. */ + if (!ip_address) + { + return(NX_IP_ADDRESS_ERROR); + } + + /* Check to see if ARP is enabled. */ + if (!ip_ptr -> nx_ip_arp_allocate) + { + return(NX_NOT_ENABLED); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual ARP hardware address find function. */ + status = _nx_arp_hardware_address_find(ip_ptr, ip_address, physical_msw, physical_lsw); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_arp_info_get.c b/common/src/nxe_arp_info_get.c new file mode 100644 index 0000000..2068bbd --- /dev/null +++ b/common/src/nxe_arp_info_get.c @@ -0,0 +1,126 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Address Resolution Protocol (ARP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_arp.h" + + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_arp_info_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the ARP information get */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP instance pointer */ +/* arp_requests_sent Destination for number of ARP */ +/* requests sent */ +/* arp_requests_received Destination for number of ARP */ +/* requests received */ +/* arp_responses_sent Destination for number of ARP */ +/* responses sent */ +/* arp_responses_received Destination for number of ARP */ +/* responses received */ +/* arp_dynamic_entries Destination for number of ARP */ +/* dynamic entries */ +/* arp_static_entries Destination for number of ARP */ +/* static entries */ +/* arp_aged_entries Destination for number of ARP */ +/* aged entries */ +/* arp_invalid_messages Destination for number of ARP */ +/* invalid messages */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_arp_info_get Actual ARP information get */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_arp_info_get(NX_IP *ip_ptr, ULONG *arp_requests_sent, ULONG *arp_requests_received, + ULONG *arp_responses_sent, ULONG *arp_responses_received, + ULONG *arp_dynamic_entries, ULONG *arp_static_entries, + ULONG *arp_aged_entries, ULONG *arp_invalid_messages) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID)) + { + return(NX_PTR_ERROR); + } + + /* Check to see if ARP is enabled. */ + if (!ip_ptr -> nx_ip_arp_allocate) + { + return(NX_NOT_ENABLED); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual ARP information get function. */ + status = _nx_arp_info_get(ip_ptr, arp_requests_sent, arp_requests_received, + arp_responses_sent, arp_responses_received, + arp_dynamic_entries, arp_static_entries, + arp_aged_entries, arp_invalid_messages); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_arp_ip_address_find.c b/common/src/nxe_arp_ip_address_find.c new file mode 100644 index 0000000..4929fad --- /dev/null +++ b/common/src/nxe_arp_ip_address_find.c @@ -0,0 +1,107 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Address Resolution Protocol (ARP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_arp.h" + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_arp_ip_address_find PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the ARP IP address find */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP instance pointer */ +/* ip_address IP Address return pointer */ +/* physical_msw Physical address MSW */ +/* physical_lsw Physical address LSW */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_arp_ip_address_find Actual IP address find */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_arp_ip_address_find(NX_IP *ip_ptr, ULONG *ip_address, + ULONG physical_msw, ULONG physical_lsw) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) || (ip_address == NX_NULL)) + { + return(NX_PTR_ERROR); + } + + /* Check to see if ARP is enabled. */ + if (!ip_ptr -> nx_ip_arp_allocate) + { + return(NX_NOT_ENABLED); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual ARP IP address find function. */ + status = _nx_arp_ip_address_find(ip_ptr, ip_address, physical_msw, physical_lsw); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_arp_static_entries_delete.c b/common/src/nxe_arp_static_entries_delete.c new file mode 100644 index 0000000..db2c240 --- /dev/null +++ b/common/src/nxe_arp_static_entries_delete.c @@ -0,0 +1,103 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Address Resolution Protocol (ARP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_arp.h" + + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_arp_static_entries_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the ARP static entries */ +/* delete function call. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP instance pointer */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_arp_static_entries_delete Delete static ARP entries */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_arp_static_entries_delete(NX_IP *ip_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID)) + { + return(NX_PTR_ERROR); + } + + /* Check to see if ARP is enabled. */ + if (!ip_ptr -> nx_ip_arp_allocate) + { + return(NX_NOT_ENABLED); + } + + /* Check for appropriate caller. */ + NX_INIT_AND_THREADS_CALLER_CHECKING + + /* Call actual delete ARP static entries function. */ + status = _nx_arp_static_entries_delete(ip_ptr); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_arp_static_entry_create.c b/common/src/nxe_arp_static_entry_create.c new file mode 100644 index 0000000..870bbe2 --- /dev/null +++ b/common/src/nxe_arp_static_entry_create.c @@ -0,0 +1,113 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Address Resolution Protocol (ARP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_arp.h" + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_arp_static_entry_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the ARP static entry create */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP instance pointer */ +/* ip_address IP Address to bind to */ +/* physical_msw Physical address MSW */ +/* physical_lsw Physical address LSW */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_arp_static_entry_create Actual static entry create */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_arp_static_entry_create(NX_IP *ip_ptr, ULONG ip_address, + ULONG physical_msw, ULONG physical_lsw) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID)) + { + return(NX_PTR_ERROR); + } + + /* Check for invalid IP address. */ + if (!ip_address) + { + return(NX_IP_ADDRESS_ERROR); + } + + /* Check to see if ARP is enabled. */ + if (!ip_ptr -> nx_ip_arp_allocate) + { + return(NX_NOT_ENABLED); + } + + /* Check for appropriate caller. */ + NX_INIT_AND_THREADS_CALLER_CHECKING + + /* Call actual ARP static entry create function. */ + status = _nx_arp_static_entry_create(ip_ptr, ip_address, physical_msw, physical_lsw); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_arp_static_entry_delete.c b/common/src/nxe_arp_static_entry_delete.c new file mode 100644 index 0000000..e9c0177 --- /dev/null +++ b/common/src/nxe_arp_static_entry_delete.c @@ -0,0 +1,113 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Address Resolution Protocol (ARP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_arp.h" + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_arp_static_entry_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the ARP static entry delete */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP instance pointer */ +/* ip_address IP Address binding to delete */ +/* physical_msw Physical address MSW */ +/* physical_lsw Physical address LSW */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_arp_static_entry_delete Actual static entry delete */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_arp_static_entry_delete(NX_IP *ip_ptr, ULONG ip_address, + ULONG physical_msw, ULONG physical_lsw) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID)) + { + return(NX_PTR_ERROR); + } + + /* Check for invalid IP address. */ + if (!ip_address) + { + return(NX_IP_ADDRESS_ERROR); + } + + /* Check to see if ARP is enabled. */ + if (!ip_ptr -> nx_ip_arp_allocate) + { + return(NX_NOT_ENABLED); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual ARP static entry delete function. */ + status = _nx_arp_static_entry_delete(ip_ptr, ip_address, physical_msw, physical_lsw); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_icmp_enable.c b/common/src/nxe_icmp_enable.c new file mode 100644 index 0000000..7401d69 --- /dev/null +++ b/common/src/nxe_icmp_enable.c @@ -0,0 +1,101 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Control Message Protocol (ICMP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_icmp.h" + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_icmp_enable PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the ICMP enable function call. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP instance pointer */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_icmp_enable Actual ICMP enable function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_icmp_enable(NX_IP *ip_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID)) + { + return(NX_PTR_ERROR); + } + + /* Check to see if ICMP is enabled. */ + if (ip_ptr -> nx_ip_icmp_packet_receive) + { + return(NX_ALREADY_ENABLED); + } + + /* Check for appropriate caller. */ + NX_INIT_AND_THREADS_CALLER_CHECKING + + /* Call actual ICMP enable function. */ + status = _nx_icmp_enable(ip_ptr); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_icmp_info_get.c b/common/src/nxe_icmp_info_get.c new file mode 100644 index 0000000..c2bdb82 --- /dev/null +++ b/common/src/nxe_icmp_info_get.c @@ -0,0 +1,118 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Control Message Protocol (ICMP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_icmp.h" + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_icmp_info_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the ICMP information get */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP instance */ +/* pings_sent Destination for number of */ +/* pings sent */ +/* ping_timeouts Destination for number of */ +/* ping timeouts */ +/* ping_threads_suspended Destination for number of */ +/* threads suspended on pings */ +/* ping_responses_received Destination for number of */ +/* ping responses received */ +/* icmp_checksum_errors Destination for number of */ +/* ICMP checksum errors */ +/* icmp_unhandled_messages Destination for number of */ +/* unhandled ICMP messages */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_icmp_info_get Actual ICMP information get */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_icmp_info_get(NX_IP *ip_ptr, ULONG *pings_sent, ULONG *ping_timeouts, + ULONG *ping_threads_suspended, ULONG *ping_responses_received, + ULONG *icmp_checksum_errors, ULONG *icmp_unhandled_messages) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID)) + { + return(NX_PTR_ERROR); + } + + /* Check to see if ICMP is enabled. */ + if (!ip_ptr -> nx_ip_icmp_packet_receive) + { + return(NX_NOT_ENABLED); + } + + /* Check for appropriate caller. */ + NX_INIT_AND_THREADS_CALLER_CHECKING + + /* Call actual ICMP information get function. */ + status = _nx_icmp_info_get(ip_ptr, pings_sent, ping_timeouts, ping_threads_suspended, + ping_responses_received, icmp_checksum_errors, icmp_unhandled_messages); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_icmp_ping.c b/common/src/nxe_icmp_ping.c new file mode 100644 index 0000000..68eb63a --- /dev/null +++ b/common/src/nxe_icmp_ping.c @@ -0,0 +1,116 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Control Message Protocol (ICMP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_icmp.h" + + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_icmp_ping PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the ICMP ping function call. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP instance */ +/* ip_address IP address to ping */ +/* data_ptr User Data pointer */ +/* data_size Size of User Data */ +/* response_ptr Pointer to Response Packet */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _nx_icmp_ping Actual ICMP ping function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_icmp_ping(NX_IP *ip_ptr, ULONG ip_address, + CHAR *data_ptr, ULONG data_size, + NX_PACKET **response_ptr, ULONG wait_option) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) || (response_ptr == NX_NULL)) + { + return(NX_PTR_ERROR); + } + + /* Check for invalid IP address. */ + if (!ip_address) + { + return(NX_IP_ADDRESS_ERROR); + } + + /* Check to see if ICMP is enabled. */ + if (!ip_ptr -> nx_ip_icmp_packet_receive) + { + return(NX_NOT_ENABLED); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual ICMP ping function. */ + status = _nx_icmp_ping(ip_ptr, ip_address, data_ptr, data_size, + response_ptr, wait_option); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_igmp_enable.c b/common/src/nxe_igmp_enable.c new file mode 100644 index 0000000..54110c2 --- /dev/null +++ b/common/src/nxe_igmp_enable.c @@ -0,0 +1,101 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Group Management Protocol (IGMP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_igmp.h" + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_igmp_enable PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the IGMP enable function call. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP instance pointer */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_igmp_enable Actual IGMP enable function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_igmp_enable(NX_IP *ip_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID)) + { + return(NX_PTR_ERROR); + } + + /* Check to see if IGMP is enabled. */ + if (ip_ptr -> nx_ip_igmp_packet_receive) + { + return(NX_ALREADY_ENABLED); + } + + /* Check for appropriate caller. */ + NX_INIT_AND_THREADS_CALLER_CHECKING + + /* Call actual IGMP enable function. */ + status = _nx_igmp_enable(ip_ptr); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_igmp_info_get.c b/common/src/nxe_igmp_info_get.c new file mode 100644 index 0000000..b08ba8b --- /dev/null +++ b/common/src/nxe_igmp_info_get.c @@ -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. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** NetX Component */ +/** */ +/** Internet Group Management Protocol (IGMP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_igmp.h" + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_igmp_info_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the IGMP information get */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP instance pointer */ +/* igmp_reports_sent Destination for the number */ +/* of IGMP reports sent */ +/* igmp_queries_received Destination for the number */ +/* of IGMP queries received */ +/* igmp_checksum_errors Destination for the number */ +/* of IGMP checksum errors */ +/* current_groups_joined Destination for the number */ +/* of IGMP multicast groups */ +/* currently joined */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_igmp_info_get Actual IGMP information get */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_igmp_info_get(NX_IP *ip_ptr, ULONG *igmp_reports_sent, ULONG *igmp_queries_received, + ULONG *igmp_checksum_errors, ULONG *current_groups_joined) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID)) + { + return(NX_PTR_ERROR); + } + + /* Check to see if IGMP is enabled. */ + if (!ip_ptr -> nx_ip_igmp_packet_receive) + { + return(NX_NOT_ENABLED); + } + + /* Check for appropriate caller. */ + NX_INIT_AND_THREADS_CALLER_CHECKING + + /* Call actual IGMP information get function. */ + status = _nx_igmp_info_get(ip_ptr, igmp_reports_sent, igmp_queries_received, + igmp_checksum_errors, current_groups_joined); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_igmp_loopback_disable.c b/common/src/nxe_igmp_loopback_disable.c new file mode 100644 index 0000000..ee7751c --- /dev/null +++ b/common/src/nxe_igmp_loopback_disable.c @@ -0,0 +1,103 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Group Management Protocol (IGMP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_igmp.h" + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_igmp_loopback_disable PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the IGMP loopback disable */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP instance pointer */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_igmp_loopback_disable Actual IGMP loopback disable */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_igmp_loopback_disable(NX_IP *ip_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID)) + { + return(NX_PTR_ERROR); + } + + /* Check to see if IGMP is enabled. */ + if (ip_ptr -> nx_ip_igmp_packet_receive == NX_NULL) + { + return(NX_NOT_ENABLED); + } + + /* Check for appropriate caller. */ + NX_INIT_AND_THREADS_CALLER_CHECKING + + /* Call actual IGMP loopback disable function. */ + status = _nx_igmp_loopback_disable(ip_ptr); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_igmp_loopback_enable.c b/common/src/nxe_igmp_loopback_enable.c new file mode 100644 index 0000000..195f30b --- /dev/null +++ b/common/src/nxe_igmp_loopback_enable.c @@ -0,0 +1,103 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Group Management Protocol (IGMP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_igmp.h" + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_igmp_loopback_enable PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the IGMP loopback enable */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP instance pointer */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_igmp_loopback_enable Actual IGMP loopback enable */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_igmp_loopback_enable(NX_IP *ip_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID)) + { + return(NX_PTR_ERROR); + } + + /* Check to see if IGMP is enabled. */ + if (ip_ptr -> nx_ip_igmp_packet_receive == NX_NULL) + { + return(NX_NOT_ENABLED); + } + + /* Check for appropriate caller. */ + NX_INIT_AND_THREADS_CALLER_CHECKING + + /* Call actual IGMP loopback enable function. */ + status = _nx_igmp_loopback_enable(ip_ptr); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_igmp_multicast_interface_join.c b/common/src/nxe_igmp_multicast_interface_join.c new file mode 100644 index 0000000..e7a3ce4 --- /dev/null +++ b/common/src/nxe_igmp_multicast_interface_join.c @@ -0,0 +1,122 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Group Management Protocol (IGMP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_igmp.h" + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_igmp_multicast_join PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the IGMP multicast join */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP instance pointer */ +/* group_address Multicast group to join */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_igmp_multicast_join Actual IGMP multicast join */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_igmp_multicast_interface_join(NX_IP *ip_ptr, ULONG group_address, UINT nx_interface_index) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID)) + { + return(NX_PTR_ERROR); + } + + /* Check for invalid multicast address. */ + if ((group_address & NX_IP_CLASS_D_MASK) != NX_IP_CLASS_D_TYPE) + { + return(NX_IP_ADDRESS_ERROR); + } + + /* Check to see if IGMP is enabled. */ + if (!ip_ptr -> nx_ip_igmp_packet_receive) + { + return(NX_NOT_ENABLED); + } + + /* Validate the interface. */ + if ((nx_interface_index >= NX_MAX_IP_INTERFACES) || (ip_ptr -> nx_ip_interface[nx_interface_index].nx_interface_valid == 0)) + { + /* Invalid interface. Return .*/ + + /* Release the IP protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + return(NX_INVALID_INTERFACE); + } + + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual IGMP multicast join function. */ + status = _nx_igmp_multicast_interface_join(ip_ptr, group_address, nx_interface_index); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_igmp_multicast_join.c b/common/src/nxe_igmp_multicast_join.c new file mode 100644 index 0000000..ca68b30 --- /dev/null +++ b/common/src/nxe_igmp_multicast_join.c @@ -0,0 +1,124 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Group Management Protocol (IGMP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_igmp.h" + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_igmp_multicast_join PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the IGMP multicast join */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP instance pointer */ +/* group_address Multicast group to join */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_igmp_multicast_join Actual IGMP multicast join */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_igmp_multicast_join(NX_IP *ip_ptr, ULONG group_address) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID)) + { + return(NX_PTR_ERROR); + } + + /* Check for invalid multicast address. */ + if ((group_address & NX_IP_CLASS_D_MASK) != NX_IP_CLASS_D_TYPE) + { + return(NX_IP_ADDRESS_ERROR); + } + + /* Check to see if IGMP is enabled. */ + if (!ip_ptr -> nx_ip_igmp_packet_receive) + { + return(NX_NOT_ENABLED); + } + + /* + Validate the interface. For backward compatibility, this service assumes multicast join + on the primary interface, which is nx_ip_interface[0]. + */ + if (ip_ptr -> nx_ip_interface[0].nx_interface_valid == 0) + { + /* Invalid interface. Return .*/ + + /* Release the IP protection. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + return(NX_INVALID_INTERFACE); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual IGMP multicast join function. */ + status = _nx_igmp_multicast_join(ip_ptr, group_address); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_igmp_multicast_leave.c b/common/src/nxe_igmp_multicast_leave.c new file mode 100644 index 0000000..0e08ea9 --- /dev/null +++ b/common/src/nxe_igmp_multicast_leave.c @@ -0,0 +1,111 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Group Management Protocol (IGMP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_igmp.h" + + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_igmp_multicast_leave PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the IGMP multicast leave */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP instance pointer */ +/* group_address Multicast group to join */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_igmp_multicast_leave Actual IGMP multicast leave */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_igmp_multicast_leave(NX_IP *ip_ptr, ULONG group_address) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID)) + { + return(NX_PTR_ERROR); + } + + /* Check for invalid multicast address. */ + if ((group_address & NX_IP_CLASS_D_MASK) != NX_IP_CLASS_D_TYPE) + { + return(NX_IP_ADDRESS_ERROR); + } + + /* Check to see if IGMP is enabled. */ + if (!ip_ptr -> nx_ip_igmp_packet_receive) + { + return(NX_NOT_ENABLED); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual IGMP multicast leave function. */ + status = _nx_igmp_multicast_leave(ip_ptr, group_address); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_ip_address_change_notify.c b/common/src/nxe_ip_address_change_notify.c new file mode 100644 index 0000000..ec42c6c --- /dev/null +++ b/common/src/nxe_ip_address_change_notify.c @@ -0,0 +1,98 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ip_address_change_notify PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the IP address change notify */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP control block pointer */ +/* ip_address_change_notify Application callback function */ +/* additional_info Optional additional information */ +/* for the callback function */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ip_address_change_notify Actual IP address change notify */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_ip_address_change_notify(NX_IP *ip_ptr, VOID (*ip_address_change_notify)(NX_IP *, VOID *), VOID *additional_info) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID)) + { + return(NX_PTR_ERROR); + } + + NX_INIT_AND_THREADS_CALLER_CHECKING + + /* Call actual IP address change notify function. */ + status = _nx_ip_address_change_notify(ip_ptr, ip_address_change_notify, additional_info); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_ip_address_get.c b/common/src/nxe_ip_address_get.c new file mode 100644 index 0000000..285cccc --- /dev/null +++ b/common/src/nxe_ip_address_get.c @@ -0,0 +1,98 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ip_address_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the IP address get function */ +/* call. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP control block pointer */ +/* ip_address Pointer to IP address destination */ +/* network_mask Pointer to network mask */ +/* destination */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ip_address_get Actual IP address get function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_ip_address_get(NX_IP *ip_ptr, ULONG *ip_address, ULONG *network_mask) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) || (ip_address == NX_NULL) || (network_mask == NX_NULL)) + { + return(NX_PTR_ERROR); + } + + /* Check for appropriate caller. */ + NX_INIT_AND_THREADS_CALLER_CHECKING + + /* Call actual IP address get function. */ + status = _nx_ip_address_get(ip_ptr, ip_address, network_mask); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_ip_address_set.c b/common/src/nxe_ip_address_set.c new file mode 100644 index 0000000..692a7a8 --- /dev/null +++ b/common/src/nxe_ip_address_set.c @@ -0,0 +1,105 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ip_address_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the IP address set */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP control block pointer */ +/* ip_address IP address */ +/* network_mask Network mask */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ip_address_set Actual IP address set function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_ip_address_set(NX_IP *ip_ptr, ULONG ip_address, ULONG network_mask) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID)) + { + return(NX_PTR_ERROR); + } + + /* Check for invalid IP address. */ + if (((ip_address & NX_IP_CLASS_A_MASK) != NX_IP_CLASS_A_TYPE) && + ((ip_address & NX_IP_CLASS_B_MASK) != NX_IP_CLASS_B_TYPE) && + ((ip_address & NX_IP_CLASS_C_MASK) != NX_IP_CLASS_C_TYPE)) + { + return(NX_IP_ADDRESS_ERROR); + } + + /* Check for appropriate caller. */ + NX_INIT_AND_THREADS_CALLER_CHECKING + + /* Call actual IP address set function. */ + status = _nx_ip_address_set(ip_ptr, ip_address, network_mask); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_ip_create.c b/common/src/nxe_ip_create.c new file mode 100644 index 0000000..52b2693 --- /dev/null +++ b/common/src/nxe_ip_create.c @@ -0,0 +1,178 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_packet.h" + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ip_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the IP instance create */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP control block */ +/* name Name of this IP instance */ +/* ip_address Internet address for this IP */ +/* network_mask Network mask for IP address */ +/* default_pool Default packet pool */ +/* ip_link_driver User supplied IP link driver */ +/* memory_ptr Pointer memory area for IP */ +/* memory_size Size of IP memory area */ +/* priority Priority of IP helper thread */ +/* ip_control_block_size Size of NX_IP structure */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ip_create Actual IP instance create */ +/* function */ +/* tx_thread_identify Get current thread pointer */ +/* tx_thread_preemption_change Change preemption for thread */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_ip_create(NX_IP *ip_ptr, CHAR *name, ULONG ip_address, ULONG network_mask, + NX_PACKET_POOL *default_pool, VOID (*ip_link_driver)(struct NX_IP_DRIVER_STRUCT *), + VOID *memory_ptr, ULONG memory_size, UINT priority, UINT ip_control_block_size) +{ + +UINT status; +UINT old_threshold; +NX_IP *created_ip; +ULONG created_count; +UCHAR *end_stack; +TX_THREAD *current_thread; + + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (default_pool == NX_NULL) || + (default_pool -> nx_packet_pool_id != NX_PACKET_POOL_ID) || (ip_link_driver == NX_NULL) || + (memory_ptr == NX_NULL) || (ip_control_block_size != sizeof(NX_IP))) + { + return(NX_PTR_ERROR); + } + + /* Check for a memory size error. */ + if (memory_size < TX_MINIMUM_STACK) + { + return(NX_SIZE_ERROR); + } + + /* Calculate the end of the stack area. */ + end_stack = ((UCHAR *)memory_ptr) + (memory_size - 1); + + /* Pickup current thread pointer. */ + current_thread = tx_thread_identify(); + + /* Disable preemption temporarily. */ + if (current_thread) + { + tx_thread_preemption_change(current_thread, 0, &old_threshold); + } + + /* Loop to check for the IP instance already created. */ + created_ip = _nx_ip_created_ptr; + created_count = _nx_ip_created_count; + while (created_count--) + { + + /* Is the new ip already created? */ + if ((ip_ptr == created_ip) || + ((memory_ptr >= created_ip -> nx_ip_thread.tx_thread_stack_start) && (memory_ptr < created_ip -> nx_ip_thread.tx_thread_stack_end)) || + ((((VOID *)end_stack) >= created_ip -> nx_ip_thread.tx_thread_stack_start) && (((VOID *)end_stack) < created_ip -> nx_ip_thread.tx_thread_stack_end))) + { + + /* Restore preemption. */ + if (current_thread) + { + tx_thread_preemption_change(current_thread, old_threshold, &old_threshold); + } + + /* Duplicate ip created, return an error! */ + return(NX_PTR_ERROR); + } + + /* Move to next entry. */ + created_ip = created_ip -> nx_ip_created_next; + } + + /* Restore preemption. */ + if (current_thread) + { + tx_thread_preemption_change(current_thread, old_threshold, &old_threshold); + } + + /* Check for invalid IP address. Note that Interface with DHCP enabled + would start with 0.0.0.0. Therefore the 0 IP address is allowed. */ + if ((ip_address != 0) && + ((ip_address & NX_IP_CLASS_A_MASK) != NX_IP_CLASS_A_TYPE) && + ((ip_address & NX_IP_CLASS_B_MASK) != NX_IP_CLASS_B_TYPE) && + ((ip_address & NX_IP_CLASS_C_MASK) != NX_IP_CLASS_C_TYPE)) + { + return(NX_IP_ADDRESS_ERROR); + } + + /* Check for appropriate caller. */ + NX_INIT_AND_THREADS_CALLER_CHECKING + + /* Call actual IP instance create function. */ + status = _nx_ip_create(ip_ptr, name, ip_address, network_mask, default_pool, ip_link_driver, + memory_ptr, memory_size, priority); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_ip_delete.c b/common/src/nxe_ip_delete.c new file mode 100644 index 0000000..ef73fe9 --- /dev/null +++ b/common/src/nxe_ip_delete.c @@ -0,0 +1,97 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" + + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ip_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the IP instance delete */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP control block */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ip_delete Actual IP instance delete */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_ip_delete(NX_IP *ip_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID)) + { + return(NX_PTR_ERROR); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual IP instance delete function. */ + status = _nx_ip_delete(ip_ptr); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_ip_driver_direct_command.c b/common/src/nxe_ip_driver_direct_command.c new file mode 100644 index 0000000..afaa026 --- /dev/null +++ b/common/src/nxe_ip_driver_direct_command.c @@ -0,0 +1,98 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ip_driver_direct_command PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the IP direct driver command */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP instance */ +/* command Driver command (NX_LINK_*) */ +/* return_value_ptr Pointer to place return values*/ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ip_driver_direct_command Actual direct driver command */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_ip_driver_direct_command(NX_IP *ip_ptr, UINT command, ULONG *return_value_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) || (return_value_ptr == NX_NULL)) + { + return(NX_PTR_ERROR); + } + + /* Check for appropriate caller. */ + NX_INIT_AND_THREADS_CALLER_CHECKING + + /* Call actual IP direct driver command function. */ + status = _nx_ip_driver_direct_command(ip_ptr, command, return_value_ptr); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_ip_driver_interface_direct_command.c b/common/src/nxe_ip_driver_interface_direct_command.c new file mode 100644 index 0000000..eb9067a --- /dev/null +++ b/common/src/nxe_ip_driver_interface_direct_command.c @@ -0,0 +1,102 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ip_driver_interface_direct_command PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the IP direct driver command */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP instance */ +/* command Driver command (NX_LINK_*) */ +/* interface_index Index to the interface */ +/* return_value_ptr Pointer to place return values*/ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ip_driver_interface_direct_command Actual direct driver command */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_ip_driver_interface_direct_command(NX_IP *ip_ptr, UINT command, UINT interface_index, ULONG *return_value_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) || (return_value_ptr == NX_NULL)) + { + return(NX_PTR_ERROR); + } + + if (interface_index >= NX_MAX_PHYSICAL_INTERFACES) + { + return(NX_INVALID_INTERFACE); + } + + /* Check for appropriate caller. */ + NX_INIT_AND_THREADS_CALLER_CHECKING + + /* Call actual IP direct driver command function. */ + status = _nx_ip_driver_interface_direct_command(ip_ptr, command, interface_index, return_value_ptr); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_ip_forwarding_disable.c b/common/src/nxe_ip_forwarding_disable.c new file mode 100644 index 0000000..e6f72e6 --- /dev/null +++ b/common/src/nxe_ip_forwarding_disable.c @@ -0,0 +1,96 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ip_forwarding_disable PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the IP forwarding disable */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP instance */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ip_forwarding_disable Actual IP forwarding disable */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_ip_forwarding_disable(NX_IP *ip_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID)) + { + return(NX_PTR_ERROR); + } + + /* Check for appropriate caller. */ + NX_NOT_ISR_CALLER_CHECKING + + /* Call actual IP forwarding disable function. */ + status = _nx_ip_forwarding_disable(ip_ptr); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_ip_forwarding_enable.c b/common/src/nxe_ip_forwarding_enable.c new file mode 100644 index 0000000..ea80f7e --- /dev/null +++ b/common/src/nxe_ip_forwarding_enable.c @@ -0,0 +1,96 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ip_forwarding_enable PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the IP forwarding enable */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP instance */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ip_forwarding_enable Actual IP forwarding enable */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_ip_forwarding_enable(NX_IP *ip_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID)) + { + return(NX_PTR_ERROR); + } + + /* Check for appropriate caller. */ + NX_NOT_ISR_CALLER_CHECKING + + /* Call actual IP forwarding enable function. */ + status = _nx_ip_forwarding_enable(ip_ptr); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_ip_fragment_disable.c b/common/src/nxe_ip_fragment_disable.c new file mode 100644 index 0000000..1be2434 --- /dev/null +++ b/common/src/nxe_ip_fragment_disable.c @@ -0,0 +1,97 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" + + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ip_fragment_disable PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the IP fragment disable */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP instance */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ip_fragment_disable Actual IP fragment disable */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_ip_fragment_disable(NX_IP *ip_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID)) + { + return(NX_PTR_ERROR); + } + + /* Check for appropriate caller. */ + NX_INIT_AND_THREADS_CALLER_CHECKING + + /* Call actual IP fragment disable function. */ + status = _nx_ip_fragment_disable(ip_ptr); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_ip_fragment_enable.c b/common/src/nxe_ip_fragment_enable.c new file mode 100644 index 0000000..c18b86b --- /dev/null +++ b/common/src/nxe_ip_fragment_enable.c @@ -0,0 +1,96 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ip_fragment_enable PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the IP fragment enable */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP instance */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ip_fragment_enable Actual IP fragment enable */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_ip_fragment_enable(NX_IP *ip_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID)) + { + return(NX_PTR_ERROR); + } + + /* Check for appropriate caller. */ + NX_INIT_AND_THREADS_CALLER_CHECKING + + /* Call actual IP fragment enable function. */ + status = _nx_ip_fragment_enable(ip_ptr); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_ip_gateway_address_set.c b/common/src/nxe_ip_gateway_address_set.c new file mode 100644 index 0000000..7076aa3 --- /dev/null +++ b/common/src/nxe_ip_gateway_address_set.c @@ -0,0 +1,97 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_arp.h" +#include "nx_ip.h" + + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ip_gateway_address_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the IP gateway address set */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP control block pointer */ +/* ip_address Gateway IP address */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ip_gateway_address_set Actual IP gateway address */ +/* set function call */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_ip_gateway_address_set(NX_IP *ip_ptr, ULONG ip_address) +{ + +UINT status; + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID)) + { + return(NX_PTR_ERROR); + } + + /* Check for appropriate caller. */ + NX_INIT_AND_THREADS_CALLER_CHECKING + + /* Call actual IP gateway address set function. */ + status = _nx_ip_gateway_address_set(ip_ptr, ip_address); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_ip_info_get.c b/common/src/nxe_ip_info_get.c new file mode 100644 index 0000000..1b6e82e --- /dev/null +++ b/common/src/nxe_ip_info_get.c @@ -0,0 +1,123 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ip_info_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the IP information get */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP instance */ +/* ip_total_packets_sent Destination for number of */ +/* packets sent */ +/* ip_total_bytes_sent Destination for number of */ +/* bytes sent */ +/* ip_total_packets_received Destination for number of */ +/* packets received */ +/* ip_total_bytes_received Destination for number of */ +/* bytes received */ +/* ip_invalid_packets Destination for number of */ +/* invalid packets */ +/* ip_receive_packets_dropped Destination for number of */ +/* packets dropped */ +/* ip_receive_checksum_errors Destination for number of */ +/* checksum errors */ +/* ip_send_packets_dropped Destination for number of */ +/* send packets dropped */ +/* ip_total_fragments_sent Destination for number of */ +/* fragments sent */ +/* ip_total_fragments_received Destination for number of */ +/* fragments received */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ip_info_get Actual IP information get */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_ip_info_get(NX_IP *ip_ptr, ULONG *ip_total_packets_sent, ULONG *ip_total_bytes_sent, + ULONG *ip_total_packets_received, ULONG *ip_total_bytes_received, + ULONG *ip_invalid_packets, ULONG *ip_receive_packets_dropped, + ULONG *ip_receive_checksum_errors, ULONG *ip_send_packets_dropped, + ULONG *ip_total_fragments_sent, ULONG *ip_total_fragments_received) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID)) + { + return(NX_PTR_ERROR); + } + + /* Check for appropriate caller. */ + NX_INIT_AND_THREADS_CALLER_CHECKING + + /* Call actual IP information get function. */ + status = _nx_ip_info_get(ip_ptr, ip_total_packets_sent, ip_total_bytes_sent, ip_total_packets_received, + ip_total_bytes_received, ip_invalid_packets, ip_receive_packets_dropped, + ip_receive_checksum_errors, ip_send_packets_dropped, + ip_total_fragments_sent, ip_total_fragments_received); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_ip_interface_address_get.c b/common/src/nxe_ip_interface_address_get.c new file mode 100644 index 0000000..8b0617a --- /dev/null +++ b/common/src/nxe_ip_interface_address_get.c @@ -0,0 +1,99 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ip_interface_address_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the IP address get function */ +/* call. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP control block pointer */ +/* interface_index IP Interface Index */ +/* ip_address Pointer to IP address destination */ +/* network_mask Pointer to network mask */ +/* destination */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ip_interface_address_get Actual IP address get function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_ip_interface_address_get(NX_IP *ip_ptr, ULONG interface_index, ULONG *ip_address, ULONG *network_mask) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) || (ip_address == NX_NULL) || (network_mask == NX_NULL)) + { + return(NX_PTR_ERROR); + } + + /* Check for appropriate caller. */ + NX_INIT_AND_THREADS_CALLER_CHECKING + + /* Call actual IP address get function. */ + status = _nx_ip_interface_address_get(ip_ptr, interface_index, ip_address, network_mask); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_ip_interface_address_set.c b/common/src/nxe_ip_interface_address_set.c new file mode 100644 index 0000000..2726c6f --- /dev/null +++ b/common/src/nxe_ip_interface_address_set.c @@ -0,0 +1,106 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ip_interface_address_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the IP address set */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP control block pointer */ +/* interface_index IP Interface Index */ +/* ip_address IP address */ +/* network_mask Network mask */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ip_interface_address_set Actual IP address set function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_ip_interface_address_set(NX_IP *ip_ptr, ULONG interface_index, ULONG ip_address, ULONG network_mask) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID)) + { + return(NX_PTR_ERROR); + } + + /* Check for invalid IP address. */ + if (((ip_address & NX_IP_CLASS_A_MASK) != NX_IP_CLASS_A_TYPE) && + ((ip_address & NX_IP_CLASS_B_MASK) != NX_IP_CLASS_B_TYPE) && + ((ip_address & NX_IP_CLASS_C_MASK) != NX_IP_CLASS_C_TYPE)) + { + return(NX_IP_ADDRESS_ERROR); + } + + /* Check for appropriate caller. */ + NX_INIT_AND_THREADS_CALLER_CHECKING + + /* Call actual IP address set function. */ + status = _nx_ip_interface_address_set(ip_ptr, interface_index, ip_address, network_mask); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_ip_interface_attach.c b/common/src/nxe_ip_interface_attach.c new file mode 100644 index 0000000..aa67edb --- /dev/null +++ b/common/src/nxe_ip_interface_attach.c @@ -0,0 +1,110 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ip_interface_attach PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the IP interface attach */ +/* function call. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr_value Pointer to IP control block */ +/* interface_name Name of this interface */ +/* ip_address IP Address, in host byte order*/ +/* network_mask Network Mask, in host byte */ +/* order */ +/* ip_link_driver User supplied link driver */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ip_interface_attach Attaches the interface */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_ip_interface_attach(NX_IP *ip_ptr, CHAR *interface_name, ULONG ip_address, ULONG network_mask, VOID (*ip_link_driver)(struct NX_IP_DRIVER_STRUCT *)) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) || (ip_link_driver == NX_NULL) || (interface_name == NX_NULL)) + { + return(NX_PTR_ERROR); + } + + /* Check for invalid IP address. Note that Interface with DHCP enabled + would start with 0.0.0.0. Therefore the 0 IP address is allowed. */ + if ((ip_address != 0) && + ((ip_address & NX_IP_CLASS_A_MASK) != NX_IP_CLASS_A_TYPE) && + ((ip_address & NX_IP_CLASS_B_MASK) != NX_IP_CLASS_B_TYPE) && + ((ip_address & NX_IP_CLASS_C_MASK) != NX_IP_CLASS_C_TYPE)) + { + return(NX_IP_ADDRESS_ERROR); + } + + /* Check for appropriate caller. */ + NX_INIT_AND_THREADS_CALLER_CHECKING + + /* Call actual invalidate ARP dynamic entries function. */ + status = _nx_ip_interface_attach(ip_ptr, interface_name, ip_address, network_mask, ip_link_driver); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_ip_interface_info_get.c b/common/src/nxe_ip_interface_info_get.c new file mode 100644 index 0000000..71c6baf --- /dev/null +++ b/common/src/nxe_ip_interface_info_get.c @@ -0,0 +1,112 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" + +/* Bring in externs for caller checking code */ +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ip_interface_info_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking for nx_ip_interface_info_get */ +/* service call. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP control block pointer */ +/* interface_index Interface ID to query. */ +/* interface_name Name of the interface */ +/* ip_address Pointer to IP address destination */ +/* in host byte order */ +/* network_mask Pointer to network mask */ +/* destination, in host byte order */ +/* mtu_size Pointer to storage space for MTU */ +/* physical_address_msw Pointer to storage space for */ +/* device phsyical address, MSW */ +/* physical_address_lsw Pointer to storage space for */ +/* device phsyical address, LSW */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ip_interface_info_get Actual IP interface info get */ +/* service call. */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +UINT _nxe_ip_interface_info_get(NX_IP *ip_ptr, UINT interface_index, CHAR **interface_name, ULONG *ip_address, ULONG *network_mask, ULONG *mtu_size, ULONG *physical_address_msw, ULONG *physical_address_lsw) +{ +UINT status; + + if (ip_ptr == NX_NULL) + { + return(NX_PTR_ERROR); + } + + if (ip_ptr -> nx_ip_id != NX_IP_ID) + { + return(NX_PTR_ERROR); + } + + if (interface_index >= NX_MAX_PHYSICAL_INTERFACES) + { + return(NX_INVALID_INTERFACE); + } + + NX_INIT_AND_THREADS_CALLER_CHECKING + + status = _nx_ip_interface_info_get(ip_ptr, interface_index, interface_name, ip_address, network_mask, + mtu_size, physical_address_msw, physical_address_lsw); + + return(status); +} + diff --git a/common/src/nxe_ip_interface_status_check.c b/common/src/nxe_ip_interface_status_check.c new file mode 100644 index 0000000..c7caea9 --- /dev/null +++ b/common/src/nxe_ip_interface_status_check.c @@ -0,0 +1,116 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ip_interface_status_check PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the IP interface status check */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP instance */ +/* interface_index Interface to check status on */ +/* needed_status Status needed request */ +/* actual_status Pointer to return status area */ +/* wait_option Maximum suspension time */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ip_interface_status_check Actual IP interface status */ +/* check function */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_ip_interface_status_check(NX_IP *ip_ptr, UINT interface_index, ULONG needed_status, + ULONG *actual_status, ULONG wait_option) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) || (actual_status == NX_NULL)) + { + return(NX_PTR_ERROR); + } + + /* Check for invalid interface index. */ + if (interface_index >= NX_MAX_PHYSICAL_INTERFACES) + { + return NX_INVALID_INTERFACE; + } + + /* Check for valid options. */ + if (needed_status & + (ULONG)(~(NX_IP_INITIALIZE_DONE | NX_IP_ADDRESS_RESOLVED | NX_IP_LINK_ENABLED | NX_IP_ARP_ENABLED | + NX_IP_UDP_ENABLED | NX_IP_TCP_ENABLED | NX_IP_IGMP_ENABLED | + NX_IP_RARP_COMPLETE | NX_IP_INTERFACE_LINK_ENABLED))) + { + return(NX_OPTION_ERROR); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual IP interface status check function. */ + status = _nx_ip_interface_status_check(ip_ptr, interface_index, needed_status, actual_status, wait_option); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_ip_link_status_change_notify_set.c b/common/src/nxe_ip_link_status_change_notify_set.c new file mode 100644 index 0000000..4d0aeab --- /dev/null +++ b/common/src/nxe_ip_link_status_change_notify_set.c @@ -0,0 +1,92 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ip_link_status_change_notify_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is the error handling service for the link status */ +/* change callback setting function. */ +/* */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP instance */ +/* link_status_change_notify Routine to call when link */ +/* staus is change */ +/* */ +/* OUTPUT */ +/* */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ip_link_status_change_notify_set Actual callback set function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_ip_link_status_change_notify_set(NX_IP *ip_ptr, VOID (*link_status_change_notify)(NX_IP *ip_ptr, UINT interface_index, UINT link_up)) +{ +UINT status; + + if ((ip_ptr == NX_NULL) || (link_status_change_notify == NX_NULL)) + { + return(NX_PTR_ERROR); + } + + /* Check for appropriate caller. */ + NX_INIT_AND_THREADS_CALLER_CHECKING + + status = _nx_ip_link_status_change_notify_set(ip_ptr, link_status_change_notify); + + return(status); +} + diff --git a/common/src/nxe_ip_raw_packet_disable.c b/common/src/nxe_ip_raw_packet_disable.c new file mode 100644 index 0000000..9465b61 --- /dev/null +++ b/common/src/nxe_ip_raw_packet_disable.c @@ -0,0 +1,97 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" + + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ip_raw_packet_disable PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the IP raw packet disable */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP control block */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ip_raw_packet_disable Actual IP raw packet disable */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_ip_raw_packet_disable(NX_IP *ip_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID)) + { + return(NX_PTR_ERROR); + } + + /* Check for appropriate caller. */ + NX_INIT_AND_THREADS_CALLER_CHECKING + + /* Call actual IP raw packet disable function. */ + status = _nx_ip_raw_packet_disable(ip_ptr); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_ip_raw_packet_enable.c b/common/src/nxe_ip_raw_packet_enable.c new file mode 100644 index 0000000..d7cfdb4 --- /dev/null +++ b/common/src/nxe_ip_raw_packet_enable.c @@ -0,0 +1,96 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ip_raw_packet_enable PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the IP raw packet enable */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP control block */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ip_raw_packet_enable Actual IP raw packet enable */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_ip_raw_packet_enable(NX_IP *ip_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID)) + { + return(NX_PTR_ERROR); + } + + /* Check for appropriate caller. */ + NX_INIT_AND_THREADS_CALLER_CHECKING + + /* Call actual IP raw packet enable function. */ + status = _nx_ip_raw_packet_enable(ip_ptr); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_ip_raw_packet_interface_send.c b/common/src/nxe_ip_raw_packet_interface_send.c new file mode 100644 index 0000000..d3fb23d --- /dev/null +++ b/common/src/nxe_ip_raw_packet_interface_send.c @@ -0,0 +1,161 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_packet.h" + + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ip_raw_packet_interface_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the IP raw packet send */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP control block */ +/* packet_ptr Pointer to packet to send */ +/* destination_ip Destination IP address */ +/* interface_index Network interface to use */ +/* type_of_service Type of service for packet */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ip_raw_packet_interface_send Actual IP raw packet send */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_ip_raw_packet_interface_send(NX_IP *ip_ptr, NX_PACKET **packet_ptr_ptr, + ULONG destination_ip, UINT interface_index, ULONG type_of_service) +{ + + +UINT status; +NX_PACKET *packet_ptr; + + + /* Setup packet pointer. */ + packet_ptr = *packet_ptr_ptr; + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) || (packet_ptr == NX_NULL) || (packet_ptr -> nx_packet_tcp_queue_next != ((NX_PACKET *)NX_PACKET_ALLOCATED))) + { + return(NX_PTR_ERROR); + } + + /* Check to see if IP raw packet processing is enabled. */ + if (!ip_ptr -> nx_ip_raw_ip_processing) + { + return(NX_NOT_ENABLED); + } + + /* Check for invalid IP address. */ + if (!destination_ip) + { + return(NX_IP_ADDRESS_ERROR); + } + + /* Check for valid type of service. */ + if (type_of_service & ~(NX_IP_TOS_MASK)) + { + return(NX_OPTION_ERROR); + } + + /* Check for an invalid packet prepend pointer. */ + if ((packet_ptr -> nx_packet_prepend_ptr - sizeof(NX_IP_HEADER)) < packet_ptr -> nx_packet_data_start) + { + return(NX_UNDERFLOW); + } + + /* Check for an invalid packet append pointer. */ + if (packet_ptr -> nx_packet_append_ptr > packet_ptr -> nx_packet_data_end) + { + return(NX_OVERFLOW); + } + + + /* Validate the interface */ + if (interface_index >= NX_MAX_PHYSICAL_INTERFACES) + { + return(NX_INVALID_INTERFACE); + } + + if (!(ip_ptr -> nx_ip_interface[interface_index].nx_interface_valid)) + { + return(NX_INVALID_INTERFACE); + } + + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual IP raw packet send function. */ + status = _nx_ip_raw_packet_interface_send(ip_ptr, packet_ptr, destination_ip, interface_index, type_of_service); + + /* Determine if the raw packet send was successful. */ + if (status == NX_SUCCESS) + { + + /* Yes, now clear the application's packet pointer so it can't be accidentally + used again by the application. This is only done when error checking is + enabled. */ + *packet_ptr_ptr = NX_NULL; + } + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_ip_raw_packet_receive.c b/common/src/nxe_ip_raw_packet_receive.c new file mode 100644 index 0000000..765b1f9 --- /dev/null +++ b/common/src/nxe_ip_raw_packet_receive.c @@ -0,0 +1,132 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_packet.h" +#include "nx_ip.h" + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ip_raw_packet_receive PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the IP raw packet receive */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP control block pointer */ +/* packet_ptr Pointer to place allocated packet */ +/* in */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_packet_release Release invalid packet */ +/* _nx_ip_raw_packet_receive Actual IP raw packet receive */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_ip_raw_packet_receive(NX_IP *ip_ptr, NX_PACKET **packet_ptr, + ULONG wait_option) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) || (packet_ptr == NX_NULL)) + { + return(NX_PTR_ERROR); + } + + /* Check to see if IP raw packet processing is enabled. */ + if (!ip_ptr -> nx_ip_raw_ip_processing) + { + return(NX_NOT_ENABLED); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + do + { + + /* Call actual IP raw packet receive function. */ + status = _nx_ip_raw_packet_receive(ip_ptr, packet_ptr, wait_option); + + /* Check for good status. */ + if (status == NX_SUCCESS) + { + + /* Check for an invalid packet prepend pointer. */ + if ((((*packet_ptr) -> nx_packet_prepend_ptr - (sizeof(NX_IP_HEADER))) < (*packet_ptr) -> nx_packet_data_start) || + ((*packet_ptr) -> nx_packet_append_ptr > (*packet_ptr) -> nx_packet_data_end)) + { + + /* Release the packet. */ + _nx_packet_release(*packet_ptr); + + /* Clear packet pointer. */ + *packet_ptr = NX_NULL; + + /* Set the status to an error. */ + status = NX_PTR_ERROR; + } + } + } while ((status != NX_SUCCESS) && (status != NX_NO_PACKET)); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_ip_raw_packet_send.c b/common/src/nxe_ip_raw_packet_send.c new file mode 100644 index 0000000..7c46456 --- /dev/null +++ b/common/src/nxe_ip_raw_packet_send.c @@ -0,0 +1,147 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_packet.h" + + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ip_raw_packet_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the IP raw packet send */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP control block */ +/* packet_ptr Pointer to packet to send */ +/* destination_ip Destination IP address */ +/* type_of_service Type of service for packet */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ip_raw_packet_send Actual IP raw packet send */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_ip_raw_packet_send(NX_IP *ip_ptr, NX_PACKET **packet_ptr_ptr, + ULONG destination_ip, ULONG type_of_service) +{ + + +UINT status; +NX_PACKET *packet_ptr; + + + /* Setup packet pointer. */ + packet_ptr = *packet_ptr_ptr; + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) || (packet_ptr == NX_NULL) || (packet_ptr -> nx_packet_tcp_queue_next != ((NX_PACKET *)NX_PACKET_ALLOCATED))) + { + return(NX_PTR_ERROR); + } + + /* Check to see if IP raw packet processing is enabled. */ + if (!ip_ptr -> nx_ip_raw_ip_processing) + { + return(NX_NOT_ENABLED); + } + + /* Check for invalid IP address. */ + if (!destination_ip) + { + return(NX_IP_ADDRESS_ERROR); + } + + /* Check for valid type of service. */ + if (type_of_service & ~(NX_IP_TOS_MASK)) + { + return(NX_OPTION_ERROR); + } + + /* Check for an invalid packet prepend pointer. */ + if ((packet_ptr -> nx_packet_prepend_ptr - sizeof(NX_IP_HEADER)) < packet_ptr -> nx_packet_data_start) + { + return(NX_UNDERFLOW); + } + + /* Check for an invalid packet append pointer. */ + if (packet_ptr -> nx_packet_append_ptr > packet_ptr -> nx_packet_data_end) + { + return(NX_OVERFLOW); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual IP raw packet send function. */ + status = _nx_ip_raw_packet_send(ip_ptr, packet_ptr, destination_ip, type_of_service); + + /* Determine if the raw packet send was successful. */ + if (status == NX_SUCCESS) + { + + /* Yes, now clear the application's packet pointer so it can't be accidentally + used again by the application. This is only done when error checking is + enabled. */ + *packet_ptr_ptr = NX_NULL; + } + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_ip_static_route_add.c b/common/src/nxe_ip_static_route_add.c new file mode 100644 index 0000000..71d5cb0 --- /dev/null +++ b/common/src/nxe_ip_static_route_add.c @@ -0,0 +1,115 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ip_static_route_add PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking for the IP static route add */ +/* service. If static routing is not enabled, this service returns an */ +/* error status. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP instance */ +/* network_address network address, in network */ +/* byte order. */ +/* net_mask Network Mask, in network */ +/* byte order. */ +/* next_hop Next Hop address, in network */ +/* byte order. */ +/* */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ip_staic_route_add Actual IP static route */ +/* add function. */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* NOTE: */ +/* */ +/* None */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_ip_static_route_add(NX_IP *ip_ptr, ULONG network_address, + ULONG net_mask, ULONG next_hop) +{ +#ifdef NX_ENABLE_IP_STATIC_ROUTING +UINT status; + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID)) + { + return(NX_PTR_ERROR); + } + + /* Check for appropriate caller. */ + NX_INIT_AND_THREADS_CALLER_CHECKING + + /* Call actual IP forwarding disable function. */ + status = _nx_ip_static_route_add(ip_ptr, network_address, net_mask, next_hop); + + /* Return completion status. */ + return(status); +#else /* !NX_ENABLE_IP_STATIC_ROUTING */ + NX_PARAMETER_NOT_USED(ip_ptr); + NX_PARAMETER_NOT_USED(network_address); + NX_PARAMETER_NOT_USED(net_mask); + NX_PARAMETER_NOT_USED(next_hop); + + return(NX_NOT_SUPPORTED); +#endif /* NX_ENABLE_IP_STATIC_ROUTING*/ +} + diff --git a/common/src/nxe_ip_static_route_delete.c b/common/src/nxe_ip_static_route_delete.c new file mode 100644 index 0000000..16c7555 --- /dev/null +++ b/common/src/nxe_ip_static_route_delete.c @@ -0,0 +1,112 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" + + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ip_static_route_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking for the static routing entry */ +/* delete service. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP instance */ +/* network_address Address to delete, in host */ +/* byte order. */ +/* net_mask Network Mask, in host byte */ +/* order. */ +/* */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ip_staic_route_delete Acutal IP static routing */ +/* table delete function. */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* NOTE: */ +/* */ +/* None */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_ip_static_route_delete(NX_IP *ip_ptr, ULONG network_address, ULONG net_mask) +{ +#ifdef NX_ENABLE_IP_STATIC_ROUTING +UINT status; + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID)) + { + return(NX_PTR_ERROR); + } + + /* Check for appropriate caller. */ + NX_INIT_AND_THREADS_CALLER_CHECKING + + /* Call actual IP forwarding disable function. */ + status = _nx_ip_static_route_delete(ip_ptr, network_address, net_mask); + + /* Return completion status. */ + return(status); + +#else /* !NX_ENABLE_IP_STATIC_ROUTING */ + NX_PARAMETER_NOT_USED(ip_ptr); + NX_PARAMETER_NOT_USED(network_address); + NX_PARAMETER_NOT_USED(net_mask); + + return(NX_NOT_SUPPORTED); +#endif /* NX_ENABLE_IP_STATIC_ROUTING */ +} + diff --git a/common/src/nxe_ip_status_check.c b/common/src/nxe_ip_status_check.c new file mode 100644 index 0000000..4f6f9a7 --- /dev/null +++ b/common/src/nxe_ip_status_check.c @@ -0,0 +1,108 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_ip_status_check PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the IP status check */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP instance */ +/* needed_status Status needed request */ +/* actual_status Pointer to return status area */ +/* wait_option Maximum suspension time */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_ip_status_check Actual IP status check */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_ip_status_check(NX_IP *ip_ptr, ULONG needed_status, ULONG *actual_status, + ULONG wait_option) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) || (actual_status == NX_NULL)) + { + return(NX_PTR_ERROR); + } + + /* Check for valid options. */ + if (needed_status & + (ULONG)(~(NX_IP_INITIALIZE_DONE | NX_IP_ADDRESS_RESOLVED | NX_IP_LINK_ENABLED | NX_IP_ARP_ENABLED | + NX_IP_UDP_ENABLED | NX_IP_TCP_ENABLED | NX_IP_IGMP_ENABLED | NX_IP_RARP_COMPLETE | NX_IP_INTERFACE_LINK_ENABLED))) + { + return(NX_OPTION_ERROR); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual IP status check function. */ + status = _nx_ip_status_check(ip_ptr, needed_status, actual_status, wait_option); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_packet_allocate.c b/common/src/nxe_packet_allocate.c new file mode 100644 index 0000000..8cfd53a --- /dev/null +++ b/common/src/nxe_packet_allocate.c @@ -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. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** NetX Component */ +/** */ +/** Packet Pool Management (Packet) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_packet.h" + + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_packet_allocate PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the packet allocate function */ +/* call. */ +/* */ +/* INPUT */ +/* */ +/* pool_ptr Pool to allocate the packet */ +/* packet_ptr Pointer to place allocated */ +/* packet pointer */ +/* packet_type Type of packet to allocate */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_packet_allocate Actual packet allocate service*/ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_packet_allocate(NX_PACKET_POOL *pool_ptr, NX_PACKET **packet_ptr, + ULONG packet_type, ULONG wait_option) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((pool_ptr == NX_NULL) || (pool_ptr -> nx_packet_pool_id != NX_PACKET_POOL_ID) || (packet_ptr == NX_NULL)) + { + return(NX_PTR_ERROR); + } + + /* Check for an invalid packet type - for alignment purposes, it must be evenly divisible by the size + of a ULONG. */ + if (packet_type % sizeof(ULONG)) + { + return(NX_OPTION_ERROR); + } + + /* Make sure the packet_type does not go beyond nx_packet_data_end. */ + if (pool_ptr -> nx_packet_pool_payload_size < packet_type) + { + return(NX_INVALID_PARAMETERS); + } + + /* Check for a thread caller if the wait option specifies suspension. */ + NX_THREAD_WAIT_CALLER_CHECKING + + /* Call actual packet allocate function. */ + status = _nx_packet_allocate(pool_ptr, packet_ptr, packet_type, wait_option); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_packet_copy.c b/common/src/nxe_packet_copy.c new file mode 100644 index 0000000..df950e3 --- /dev/null +++ b/common/src/nxe_packet_copy.c @@ -0,0 +1,113 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Packet Pool Management (Packet) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_packet.h" + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_packet_copy PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the packet copy */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* packet_ptr Pointer to source packet */ +/* new_packet_ptr Pointer to return packet */ +/* pool_ptr Pointer to packet pool to use */ +/* for new packet(s) */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_packet_copy Actual packet copy function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_packet_copy(NX_PACKET *packet_ptr, NX_PACKET **new_packet_ptr, + NX_PACKET_POOL *pool_ptr, ULONG wait_option) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((pool_ptr == NX_NULL) || (pool_ptr -> nx_packet_pool_id != NX_PACKET_POOL_ID) || + (packet_ptr == NX_NULL) || (new_packet_ptr == NX_NULL)) + { + return(NX_PTR_ERROR); + } + + /* Check for an invalid packet prepend pointer. */ + if (packet_ptr -> nx_packet_prepend_ptr < packet_ptr -> nx_packet_data_start) + { + return(NX_UNDERFLOW); + } + + /* Check for an invalid packet append pointer. */ + if (packet_ptr -> nx_packet_append_ptr > packet_ptr -> nx_packet_data_end) + { + return(NX_OVERFLOW); + } + + /* Check for appropriate caller. */ + NX_THREAD_WAIT_CALLER_CHECKING + + /* Call actual packet copy function. */ + status = _nx_packet_copy(packet_ptr, new_packet_ptr, pool_ptr, wait_option); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_packet_data_append.c b/common/src/nxe_packet_data_append.c new file mode 100644 index 0000000..5502f96 --- /dev/null +++ b/common/src/nxe_packet_data_append.c @@ -0,0 +1,120 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Packet Pool Management (Packet) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_packet.h" + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_packet_data_append PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the packet data append */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* packet_ptr Pointer to packet to append */ +/* data_start Pointer to start of the data */ +/* data_size Number of bytes to append */ +/* pool_ptr Pool to allocate the packet */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_packet_data_append Actual packet data append */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_packet_data_append(NX_PACKET *packet_ptr, VOID *data_start, ULONG data_size, + NX_PACKET_POOL *pool_ptr, ULONG wait_option) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((pool_ptr == NX_NULL) || (pool_ptr -> nx_packet_pool_id != NX_PACKET_POOL_ID) || + (packet_ptr == NX_NULL) || (data_start == NX_NULL)) + { + return(NX_PTR_ERROR); + } + + /* Check for an invalid size of data to append. */ + if (!data_size) + { + return(NX_SIZE_ERROR); + } + + /* Check for an invalid packet prepend pointer. */ + if (packet_ptr -> nx_packet_prepend_ptr < packet_ptr -> nx_packet_data_start) + { + return(NX_UNDERFLOW); + } + + /* Check for an invalid packet append pointer. */ + if (packet_ptr -> nx_packet_append_ptr > packet_ptr -> nx_packet_data_end) + { + return(NX_OVERFLOW); + } + + /* Check for appropriate caller. */ + NX_THREAD_WAIT_CALLER_CHECKING + + /* Call actual packet data append function. */ + status = _nx_packet_data_append(packet_ptr, data_start, data_size, pool_ptr, wait_option); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_packet_data_extract_offset.c b/common/src/nxe_packet_data_extract_offset.c new file mode 100644 index 0000000..14dc93d --- /dev/null +++ b/common/src/nxe_packet_data_extract_offset.c @@ -0,0 +1,96 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Internet Protocol (IP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_packet.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_packet_data_extract_offset PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the packet data extract */ +/* function call. */ +/* */ +/* 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 */ +/* */ +/* _nx_packet_data_extract_offset Acutal packet data extract offset */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_packet_data_extract_offset(NX_PACKET *packet_ptr, ULONG offset, VOID *buffer_start, ULONG buffer_length, ULONG *bytes_copied) +{ + + if (packet_ptr == NX_NULL) + { + return(NX_PTR_ERROR); + } + + if (buffer_start == NX_NULL) + { + return(NX_PTR_ERROR); + } + + if (bytes_copied == NX_NULL) + { + return(NX_PTR_ERROR); + } + + + return(_nx_packet_data_extract_offset(packet_ptr, offset, buffer_start, buffer_length, bytes_copied)); +} + diff --git a/common/src/nxe_packet_data_retrieve.c b/common/src/nxe_packet_data_retrieve.c new file mode 100644 index 0000000..17c3786 --- /dev/null +++ b/common/src/nxe_packet_data_retrieve.c @@ -0,0 +1,91 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Packet Pool Management (Packet) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_packet.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_packet_data_retrieve PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the packet data retrieve */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* packet_ptr Packet to retrieve from */ +/* buffer_start Pointer to start of the buffer*/ +/* bytes_copied Number of bytes copied */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_packet_data_retrieve Actual packet data retrieve */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_packet_data_retrieve(NX_PACKET *packet_ptr, VOID *buffer_start, ULONG *bytes_copied) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((packet_ptr == NX_NULL) || (buffer_start == NX_NULL) || (bytes_copied == NX_NULL)) + { + return(NX_PTR_ERROR); + } + + /* Call actual packet data retrieve function. */ + status = _nx_packet_data_retrieve(packet_ptr, buffer_start, bytes_copied); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_packet_length_get.c b/common/src/nxe_packet_length_get.c new file mode 100644 index 0000000..be9ef63 --- /dev/null +++ b/common/src/nxe_packet_length_get.c @@ -0,0 +1,93 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Packet Pool Management (Packet) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_packet.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_packet_length_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the packet length get */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* packet_ptr Pointer of packet */ +/* length Destination for the length */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_packet_length_get Actual packet length get */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_packet_length_get(NX_PACKET *packet_ptr, ULONG *length) +{ + +UINT status; + + + /* Simple integrity check on the packet. */ + if ((packet_ptr == NX_NULL) || (packet_ptr -> nx_packet_pool_owner == NX_NULL) || + ((packet_ptr -> nx_packet_pool_owner) -> nx_packet_pool_id != NX_PACKET_POOL_ID) || + (length == NX_NULL)) + { + + /* Return an error! */ + return(NX_PTR_ERROR); + } + + /* Call actual packet length get function. */ + status = _nx_packet_length_get(packet_ptr, length); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_packet_pool_create.c b/common/src/nxe_packet_pool_create.c new file mode 100644 index 0000000..ff5d8fa --- /dev/null +++ b/common/src/nxe_packet_pool_create.c @@ -0,0 +1,173 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Packet Pool Management (Packet) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_packet.h" + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_packet_pool_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the packet pool create */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* pool_ptr Packet Pool control block */ +/* name_ptr Packet Pool string pointer */ +/* payload_size Size of packet payload */ +/* pool_start Starting address of pool */ +/* pool_size Number of bytes in pool */ +/* pool_control_block_size Size of packet pool control */ +/* block */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_packet_pool_create Actual packet pool create */ +/* function */ +/* tx_thread_identify Get current thread pointer */ +/* tx_thread_preemption_change Change preemption for thread */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_packet_pool_create(NX_PACKET_POOL *pool_ptr, CHAR *name_ptr, ULONG payload_size, + VOID *pool_start, ULONG pool_size, UINT pool_control_block_size) +{ + +UINT status; +UINT rounded_payload_size; +UINT old_threshold; +NX_PACKET_POOL *created_pool; +ULONG created_count; +CHAR *end_memory; +CHAR *created_end; +TX_THREAD *current_thread; + + + /* Check for invalid input pointers. */ + if ((pool_ptr == NX_NULL) || (pool_start == NX_NULL) || (pool_control_block_size != sizeof(NX_PACKET_POOL))) + { + return(NX_PTR_ERROR); + } + + /* Round the packet size up to something that is evenly divisible by + an ULONG. This helps guarantee proper alignment. */ + rounded_payload_size = ((payload_size + sizeof(ULONG) - 1) / sizeof(ULONG)) * sizeof(ULONG); + + /* Round the pool size down to something that is evenly divisible by + an ULONG. */ + pool_size = (pool_size / sizeof(ULONG)) * sizeof(ULONG); + + /* Check for an invalid pool and payload size. */ + if ((!payload_size) || (!pool_size) || (rounded_payload_size > (pool_size - sizeof(NX_PACKET)))) + { + return(NX_SIZE_ERROR); + } + + /* Calculate the end of the pool memory area. */ + end_memory = ((CHAR *)pool_start) + (pool_size - 1); + + /* Pickup current thread pointer. */ + current_thread = tx_thread_identify(); + + /* Disable preemption temporarily. */ + if (current_thread) + { + tx_thread_preemption_change(current_thread, 0, &old_threshold); + } + + /* Loop to check for the pool instance already created. */ + created_pool = _nx_packet_pool_created_ptr; + created_count = _nx_packet_pool_created_count; + while (created_count--) + { + + /* Calculate the created pool's end of memory. */ + created_end = created_pool -> nx_packet_pool_start + (created_pool -> nx_packet_pool_size - 1); + + /* Is the new pool already created? */ + if ((pool_ptr == created_pool) || + ((pool_start >= (VOID *)created_pool -> nx_packet_pool_start) && (pool_start < (VOID *)created_end)) || + ((end_memory >= created_pool -> nx_packet_pool_start) && (end_memory < created_end))) + { + + /* Restore preemption. */ + if (current_thread) + { + tx_thread_preemption_change(current_thread, old_threshold, &old_threshold); + } + + /* Duplicate packet pool created, return an error! */ + return(NX_PTR_ERROR); + } + + /* Move to next entry. */ + created_pool = created_pool -> nx_packet_pool_created_next; + } + + /* Restore preemption. */ + if (current_thread) + { + tx_thread_preemption_change(current_thread, old_threshold, &old_threshold); + } + + /* Check for appropriate caller. */ + NX_INIT_AND_THREADS_CALLER_CHECKING + + /* Call actual packet pool create function. */ + status = _nx_packet_pool_create(pool_ptr, name_ptr, payload_size, pool_start, pool_size); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_packet_pool_delete.c b/common/src/nxe_packet_pool_delete.c new file mode 100644 index 0000000..8d2a8f8 --- /dev/null +++ b/common/src/nxe_packet_pool_delete.c @@ -0,0 +1,96 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Packet Pool Management (Packet) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_packet.h" + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_packet_pool_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the packet pool delete */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* pool_ptr Packet Pool control block */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_packet_pool_delete Actual packet pool delete */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_packet_pool_delete(NX_PACKET_POOL *pool_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((pool_ptr == NX_NULL) || (pool_ptr -> nx_packet_pool_id != NX_PACKET_POOL_ID)) + { + return(NX_PTR_ERROR); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual packet pool delete function. */ + status = _nx_packet_pool_delete(pool_ptr); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_packet_pool_info_get.c b/common/src/nxe_packet_pool_info_get.c new file mode 100644 index 0000000..08c73ed --- /dev/null +++ b/common/src/nxe_packet_pool_info_get.c @@ -0,0 +1,106 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Packet Pool Management (Packet) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_packet.h" + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_packet_pool_info_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the packet pool information get */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* pool_ptr Pool to get information from */ +/* total_packets Destination for total packets */ +/* free_packets Destination for free packets */ +/* empty_pool_requests Destination for empty requests*/ +/* empty_pool_suspensions Destination for empty */ +/* suspensions */ +/* invalid_packet_releases Destination for invalid packet*/ +/* release requests */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_packet_pool_info_get Actual packet pool info get */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_packet_pool_info_get(NX_PACKET_POOL *pool_ptr, ULONG *total_packets, ULONG *free_packets, + ULONG *empty_pool_requests, ULONG *empty_pool_suspensions, + ULONG *invalid_packet_releases) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((pool_ptr == NX_NULL) || (pool_ptr -> nx_packet_pool_id != NX_PACKET_POOL_ID)) + { + return(NX_PTR_ERROR); + } + + /* Check for appropriate caller. */ + NX_NOT_ISR_CALLER_CHECKING + + /* Call actual packet pool information get function. */ + status = _nx_packet_pool_info_get(pool_ptr, total_packets, free_packets, empty_pool_requests, + empty_pool_suspensions, invalid_packet_releases); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_packet_release.c b/common/src/nxe_packet_release.c new file mode 100644 index 0000000..c7ddff9 --- /dev/null +++ b/common/src/nxe_packet_release.c @@ -0,0 +1,117 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Packet Pool Management (Packet) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_packet.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_packet_release PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the packet release */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* packet_ptr Pointer of packet to release */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_packet_release Actual packet release */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_packet_release(NX_PACKET **packet_ptr_ptr) +{ + +UINT status; +NX_PACKET *packet_ptr; + + + /* Setup packet pointer. */ + packet_ptr = *packet_ptr_ptr; + + /* Simple integrity check on the packet. */ + if ((packet_ptr == NX_NULL) || (packet_ptr -> nx_packet_pool_owner == NX_NULL) || + ((packet_ptr -> nx_packet_pool_owner) -> nx_packet_pool_id != NX_PACKET_POOL_ID)) + { + + return(NX_PTR_ERROR); + } + + /* Check for an invalid packet prepend pointer. */ + if (packet_ptr -> nx_packet_prepend_ptr < packet_ptr -> nx_packet_data_start) + { + return(NX_UNDERFLOW); + } + + /* Check for an invalid packet append pointer. */ + if (packet_ptr -> nx_packet_append_ptr > packet_ptr -> nx_packet_data_end) + { + return(NX_OVERFLOW); + } + + /* Call actual packet release function. */ + status = _nx_packet_release(packet_ptr); + + /* Determine if the packet release was successful. */ + if (status == NX_SUCCESS) + { + + /* Yes, now clear the application's packet pointer so it can't be accidentally + used again by the application. This is only done when error checking is + enabled. */ + *packet_ptr_ptr = NX_NULL; + } + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_packet_transmit_release.c b/common/src/nxe_packet_transmit_release.c new file mode 100644 index 0000000..c48d6cb --- /dev/null +++ b/common/src/nxe_packet_transmit_release.c @@ -0,0 +1,117 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Packet Pool Management (Packet) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_packet.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_packet_transmit_release PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the packet transmit release */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* packet_ptr Pointer of packet to release */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_packet_transmit_release Actual packet transmit release*/ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_packet_transmit_release(NX_PACKET **packet_ptr_ptr) +{ + +UINT status; +NX_PACKET *packet_ptr; + + + /* Setup packet pointer. */ + packet_ptr = *packet_ptr_ptr; + + /* Simple integrity check on the packet. */ + if ((packet_ptr == NX_NULL) || (packet_ptr -> nx_packet_pool_owner == NX_NULL) || + ((packet_ptr -> nx_packet_pool_owner) -> nx_packet_pool_id != NX_PACKET_POOL_ID)) + { + + return(NX_PTR_ERROR); + } + + /* Check for an invalid packet prepend pointer. */ + if (packet_ptr -> nx_packet_prepend_ptr < packet_ptr -> nx_packet_data_start) + { + return(NX_UNDERFLOW); + } + + /* Check for an invalid packet append pointer. */ + if (packet_ptr -> nx_packet_append_ptr > packet_ptr -> nx_packet_data_end) + { + return(NX_OVERFLOW); + } + + /* Call actual packet transmit release function. */ + status = _nx_packet_transmit_release(packet_ptr); + + /* Determine if the packet release was successful. */ + if (status == NX_SUCCESS) + { + + /* Yes, now clear the application's packet pointer so it can't be accidentally + used again by the application. This is only done when error checking is + enabled. */ + *packet_ptr_ptr = NX_NULL; + } + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_rarp_disable.c b/common/src/nxe_rarp_disable.c new file mode 100644 index 0000000..7b558b1 --- /dev/null +++ b/common/src/nxe_rarp_disable.c @@ -0,0 +1,95 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Reverse Address Resolution Protocol (RARP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_rarp.h" + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_rarp_disable PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the RARP disable function call. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP instance pointer */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_rarp_disable Actual RARP disable function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_rarp_disable(NX_IP *ip_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID)) + { + return(NX_PTR_ERROR); + } + + /* Check for appropriate caller. */ + NX_INIT_AND_THREADS_CALLER_CHECKING + + /* Call actual RARP disable function. */ + status = _nx_rarp_disable(ip_ptr); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_rarp_enable.c b/common/src/nxe_rarp_enable.c new file mode 100644 index 0000000..db55173 --- /dev/null +++ b/common/src/nxe_rarp_enable.c @@ -0,0 +1,95 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Reverse Address Resolution Protocol (RARP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_rarp.h" + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_rarp_enable PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the RARP enable function call. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP instance pointer */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_rarp_enable Actual RARP enable function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_rarp_enable(NX_IP *ip_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID)) + { + return(NX_PTR_ERROR); + } + + /* Check for appropriate caller. */ + NX_INIT_AND_THREADS_CALLER_CHECKING + + /* Call actual RARP enable function. */ + status = _nx_rarp_enable(ip_ptr); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_rarp_info_get.c b/common/src/nxe_rarp_info_get.c new file mode 100644 index 0000000..5009d54 --- /dev/null +++ b/common/src/nxe_rarp_info_get.c @@ -0,0 +1,111 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Reverse Address Resolution Protocol (RARP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_rarp.h" + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_rarp_info_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the RARP information get */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP instance pointer */ +/* rarp_requests_sent Destination for the number of */ +/* RARP requests sent */ +/* rarp_responses_received Destination for the number of */ +/* RARP responses received */ +/* rarp_invalid_messages Destination for the number of */ +/* RARP invalid messages (or */ +/* unhandled) */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_rarp_info_get Actual RARP information get */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_rarp_info_get(NX_IP *ip_ptr, ULONG *rarp_requests_sent, ULONG *rarp_responses_received, + ULONG *rarp_invalid_messages) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID)) + { + return(NX_PTR_ERROR); + } + + /* Check to see if RARP is enabled. */ + if ((!ip_ptr -> nx_ip_rarp_queue_process) && (ip_ptr -> nx_ip_rarp_responses_received == 0)) + { + return(NX_NOT_ENABLED); + } + + /* Check for appropriate caller. */ + NX_INIT_AND_THREADS_CALLER_CHECKING + + /* Call actual RARP information get function. */ + status = _nx_rarp_info_get(ip_ptr, rarp_requests_sent, rarp_responses_received, rarp_invalid_messages); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_tcp_client_socket_bind.c b/common/src/nxe_tcp_client_socket_bind.c new file mode 100644 index 0000000..eb825e7 --- /dev/null +++ b/common/src/nxe_tcp_client_socket_bind.c @@ -0,0 +1,110 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_tcp.h" + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_tcp_client_socket_bind PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the TCP socket bind */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to TCP socket */ +/* port 16-bit TCP port number */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_tcp_client_socket_bind Actual TCP client socket bind */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_tcp_client_socket_bind(NX_TCP_SOCKET *socket_ptr, UINT port, ULONG wait_option) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((socket_ptr == NX_NULL) || (socket_ptr -> nx_tcp_socket_id != NX_TCP_ID)) + { + return(NX_PTR_ERROR); + } + + /* Check to see if TCP is enabled. */ + if (!(socket_ptr -> nx_tcp_socket_ip_ptr) -> nx_ip_tcp_packet_receive) + { + return(NX_NOT_ENABLED); + } + + /* Check for an invalid port. */ + if (((ULONG)port) > (ULONG)NX_MAX_PORT) + { + return(NX_INVALID_PORT); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual TCP client socket bind function. */ + status = _nx_tcp_client_socket_bind(socket_ptr, port, wait_option); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_tcp_client_socket_connect.c b/common/src/nxe_tcp_client_socket_connect.c new file mode 100644 index 0000000..968829e --- /dev/null +++ b/common/src/nxe_tcp_client_socket_connect.c @@ -0,0 +1,120 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_tcp.h" + + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_tcp_client_socket_connect PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the TCP client socket connect */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to TCP client socket */ +/* server_ip IP address of server */ +/* server_port Port number of server */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_tcp_client_socket_connect Actual client socket connect */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_tcp_client_socket_connect(NX_TCP_SOCKET *socket_ptr, ULONG server_ip, UINT server_port, ULONG wait_option) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((socket_ptr == NX_NULL) || (socket_ptr -> nx_tcp_socket_id != NX_TCP_ID)) + { + return(NX_PTR_ERROR); + } + + /* Check to see if TCP is enabled. */ + if (!(socket_ptr -> nx_tcp_socket_ip_ptr) -> nx_ip_tcp_packet_receive) + { + return(NX_NOT_ENABLED); + } + + /* Check for invalid IP address. */ + if (((server_ip & NX_IP_CLASS_A_MASK) != NX_IP_CLASS_A_TYPE) && + ((server_ip & NX_IP_CLASS_B_MASK) != NX_IP_CLASS_B_TYPE) && + ((server_ip & NX_IP_CLASS_C_MASK) != NX_IP_CLASS_C_TYPE)) + { + return(NX_IP_ADDRESS_ERROR); + } + + /* Check for an invalid port. */ + if (((ULONG)server_port) > (ULONG)NX_MAX_PORT) + { + return(NX_INVALID_PORT); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual TCP client socket connect function. */ + status = _nx_tcp_client_socket_connect(socket_ptr, server_ip, server_port, wait_option); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_tcp_client_socket_port_get.c b/common/src/nxe_tcp_client_socket_port_get.c new file mode 100644 index 0000000..5c0415e --- /dev/null +++ b/common/src/nxe_tcp_client_socket_port_get.c @@ -0,0 +1,105 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_tcp.h" + + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_tcp_client_socket_port_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the client socket port get */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to TCP client socket */ +/* port_ptr Destination for port bound to */ +/* this socket */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_tcp_client_socket_port_get Actual client socket port get */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_tcp_client_socket_port_get(NX_TCP_SOCKET *socket_ptr, UINT *port_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((socket_ptr == NX_NULL) || (socket_ptr -> nx_tcp_socket_id != NX_TCP_ID) || (port_ptr == NX_NULL)) + { + return(NX_PTR_ERROR); + } + + /* Check to see if TCP is enabled. */ + if (!(socket_ptr -> nx_tcp_socket_ip_ptr) -> nx_ip_tcp_packet_receive) + { + return(NX_NOT_ENABLED); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual TCP client socket port get function. */ + status = _nx_tcp_client_socket_port_get(socket_ptr, port_ptr); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_tcp_client_socket_unbind.c b/common/src/nxe_tcp_client_socket_unbind.c new file mode 100644 index 0000000..feda86d --- /dev/null +++ b/common/src/nxe_tcp_client_socket_unbind.c @@ -0,0 +1,103 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_tcp.h" + + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_tcp_client_socket_unbind PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the client socket unbind */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to TCP client socket */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_tcp_client_socket_unbind Actual client socket unbind */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_tcp_client_socket_unbind(NX_TCP_SOCKET *socket_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((socket_ptr == NX_NULL) || (socket_ptr -> nx_tcp_socket_id != NX_TCP_ID)) + { + return(NX_PTR_ERROR); + } + + /* Check to see if TCP is enabled. */ + if (!(socket_ptr -> nx_tcp_socket_ip_ptr) -> nx_ip_tcp_packet_receive) + { + return(NX_NOT_ENABLED); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual TCP client socket unbind function. */ + status = _nx_tcp_client_socket_unbind(socket_ptr); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_tcp_enable.c b/common/src/nxe_tcp_enable.c new file mode 100644 index 0000000..f62558b --- /dev/null +++ b/common/src/nxe_tcp_enable.c @@ -0,0 +1,102 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_tcp.h" + + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_tcp_enable PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the TCP enable function call. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP instance pointer */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_tcp_enable Actual TCP enable function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_tcp_enable(NX_IP *ip_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID)) + { + return(NX_PTR_ERROR); + } + + /* Check to see if TCP is already enabled. */ + if (ip_ptr -> nx_ip_tcp_packet_receive) + { + return(NX_ALREADY_ENABLED); + } + + /* Check for appropriate caller. */ + NX_NOT_ISR_CALLER_CHECKING + + /* Call actual TCP enable function. */ + status = _nx_tcp_enable(ip_ptr); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_tcp_free_port_find.c b/common/src/nxe_tcp_free_port_find.c new file mode 100644 index 0000000..6dc8299 --- /dev/null +++ b/common/src/nxe_tcp_free_port_find.c @@ -0,0 +1,112 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_tcp.h" + + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_tcp_free_port_find PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the TCP free port find */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP instance pointer */ +/* port Starting port */ +/* free_port_ptr Pointer to return free port */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_tcp_free_port_find Actual TCP free port find */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_tcp_free_port_find(NX_IP *ip_ptr, UINT port, UINT *free_port_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) || (free_port_ptr == NX_NULL)) + { + return(NX_PTR_ERROR); + } + + /* Check to see if TCP is enabled. */ + if (!ip_ptr -> nx_ip_tcp_packet_receive) + { + return(NX_NOT_ENABLED); + } + + /* Check for an invalid port. */ + if (((ULONG)port) > (ULONG)NX_MAX_PORT) + { + return(NX_INVALID_PORT); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual TCP free port find function. */ + status = _nx_tcp_free_port_find(ip_ptr, port, free_port_ptr); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_tcp_info_get.c b/common/src/nxe_tcp_info_get.c new file mode 100644 index 0000000..e5ecd61 --- /dev/null +++ b/common/src/nxe_tcp_info_get.c @@ -0,0 +1,134 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_tcp.h" + + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_tcp_info_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the TCP information get */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to the IP instance */ +/* tcp_packets_sent Destination for number of */ +/* packets sent */ +/* tcp_bytes_sent Destination for number of */ +/* bytes sent */ +/* tcp_packets_received Destination for number of */ +/* packets received */ +/* tcp_bytes_received Destination for number of */ +/* bytes received */ +/* tcp_invalid_packets Destination for number of */ +/* invalid packets */ +/* tcp_receive_packets_dropped Destination for number of */ +/* receive packets dropped */ +/* tcp_checksum_errors Destination for number of */ +/* checksum errors */ +/* tcp_connections Destination for number of */ +/* connections */ +/* tcp_disconnections Destination for number of */ +/* disconnections */ +/* tcp_connections_dropped Destination for number of */ +/* connections dropped */ +/* tcp_retransmit_packets Destination for number of */ +/* retransmit packets */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_tcp_info_get Actual TCP information get */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_tcp_info_get(NX_IP *ip_ptr, ULONG *tcp_packets_sent, ULONG *tcp_bytes_sent, + ULONG *tcp_packets_received, ULONG *tcp_bytes_received, + ULONG *tcp_invalid_packets, ULONG *tcp_receive_packets_dropped, + ULONG *tcp_checksum_errors, ULONG *tcp_connections, + ULONG *tcp_disconnections, ULONG *tcp_connections_dropped, + ULONG *tcp_retransmit_packets) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID)) + { + return(NX_PTR_ERROR); + } + + /* Check to see if TCP is enabled. */ + if (!ip_ptr -> nx_ip_tcp_packet_receive) + { + return(NX_NOT_ENABLED); + } + + /* Check for appropriate caller. */ + NX_INIT_AND_THREADS_CALLER_CHECKING + + /* Call actual TCP information get function. */ + status = _nx_tcp_info_get(ip_ptr, tcp_packets_sent, tcp_bytes_sent, tcp_packets_received, + tcp_bytes_received, tcp_invalid_packets, tcp_receive_packets_dropped, + tcp_checksum_errors, tcp_connections, tcp_disconnections, + tcp_connections_dropped, tcp_retransmit_packets); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_tcp_server_socket_accept.c b/common/src/nxe_tcp_server_socket_accept.c new file mode 100644 index 0000000..1618747 --- /dev/null +++ b/common/src/nxe_tcp_server_socket_accept.c @@ -0,0 +1,104 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_tcp.h" + + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_tcp_server_socket_accept PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the server socket accept */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to new TCP socket */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_tcp_server_socket_accept Actual server socket accept */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_tcp_server_socket_accept(NX_TCP_SOCKET *socket_ptr, ULONG wait_option) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((socket_ptr == NX_NULL) || (socket_ptr -> nx_tcp_socket_id != NX_TCP_ID)) + { + return(NX_PTR_ERROR); + } + + /* Check to see if TCP is enabled. */ + if (!(socket_ptr -> nx_tcp_socket_ip_ptr) -> nx_ip_tcp_packet_receive) + { + return(NX_NOT_ENABLED); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual TCP server socket accept function. */ + status = _nx_tcp_server_socket_accept(socket_ptr, wait_option); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_tcp_server_socket_listen.c b/common/src/nxe_tcp_server_socket_listen.c new file mode 100644 index 0000000..6616f48 --- /dev/null +++ b/common/src/nxe_tcp_server_socket_listen.c @@ -0,0 +1,118 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_tcp.h" + + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_tcp_server_socket_listen PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the server socket listen */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP instance */ +/* port TCP port number */ +/* socket_ptr Server socket pointer */ +/* listen_queue_size Maximum number of connections */ +/* that can be queued */ +/* tcp_listen_callback Callback routine when a */ +/* connect request arrives */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_tcp_server_socket_listen Actual server socket listen */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_tcp_server_socket_listen(NX_IP *ip_ptr, UINT port, NX_TCP_SOCKET *socket_ptr, UINT listen_queue_size, + VOID (*tcp_listen_callback)(NX_TCP_SOCKET *socket_ptr, UINT port)) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) || + (socket_ptr == NX_NULL) || (socket_ptr -> nx_tcp_socket_id != NX_TCP_ID)) + { + return(NX_PTR_ERROR); + } + + /* Check to see if TCP is enabled. */ + if (!ip_ptr -> nx_ip_tcp_packet_receive) + { + return(NX_NOT_ENABLED); + } + + /* Check for an invalid port. */ + if ((!port) || (((ULONG)port) > (ULONG)NX_MAX_PORT)) + { + return(NX_INVALID_PORT); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual TCP server socket listen function. */ + status = _nx_tcp_server_socket_listen(ip_ptr, port, socket_ptr, listen_queue_size, tcp_listen_callback); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_tcp_server_socket_relisten.c b/common/src/nxe_tcp_server_socket_relisten.c new file mode 100644 index 0000000..62024f7 --- /dev/null +++ b/common/src/nxe_tcp_server_socket_relisten.c @@ -0,0 +1,113 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_tcp.h" + + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_tcp_server_socket_relisten PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the server socket relisten */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP instance */ +/* port TCP port number */ +/* socket_ptr Server socket pointer */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_tcp_server_socket_relisten Actual server socket relisten */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_tcp_server_socket_relisten(NX_IP *ip_ptr, UINT port, NX_TCP_SOCKET *socket_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) || + (socket_ptr == NX_NULL) || (socket_ptr -> nx_tcp_socket_id != NX_TCP_ID)) + { + return(NX_PTR_ERROR); + } + + /* Check to see if TCP is enabled. */ + if (!ip_ptr -> nx_ip_tcp_packet_receive) + { + return(NX_NOT_ENABLED); + } + + /* Check for an invalid port. */ + if ((!port) || (((ULONG)port) > (ULONG)NX_MAX_PORT)) + { + return(NX_INVALID_PORT); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual TCP server socket relisten function. */ + status = _nx_tcp_server_socket_relisten(ip_ptr, port, socket_ptr); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_tcp_server_socket_unaccept.c b/common/src/nxe_tcp_server_socket_unaccept.c new file mode 100644 index 0000000..c9775fc --- /dev/null +++ b/common/src/nxe_tcp_server_socket_unaccept.c @@ -0,0 +1,103 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_tcp.h" + + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_tcp_server_socket_unaccept PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the server socket unaccept */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to new TCP socket */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_tcp_server_socket_unaccept Actual server socket unaccept */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_tcp_server_socket_unaccept(NX_TCP_SOCKET *socket_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((socket_ptr == NX_NULL) || (socket_ptr -> nx_tcp_socket_id != NX_TCP_ID)) + { + return(NX_PTR_ERROR); + } + + /* Check to see if TCP is enabled. */ + if (!(socket_ptr -> nx_tcp_socket_ip_ptr) -> nx_ip_tcp_packet_receive) + { + return(NX_NOT_ENABLED); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual TCP server socket unaccept function. */ + status = _nx_tcp_server_socket_unaccept(socket_ptr); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_tcp_server_socket_unlisten.c b/common/src/nxe_tcp_server_socket_unlisten.c new file mode 100644 index 0000000..f33e31a --- /dev/null +++ b/common/src/nxe_tcp_server_socket_unlisten.c @@ -0,0 +1,110 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_tcp.h" + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_tcp_server_socket_unlisten PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the server socket unlisten */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP instance */ +/* port TCP port number */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_tcp_server_socket_unlisten Actual server socket unlisten */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_tcp_server_socket_unlisten(NX_IP *ip_ptr, UINT port) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID)) + { + return(NX_PTR_ERROR); + } + + /* Check to see if TCP is enabled. */ + if (!ip_ptr -> nx_ip_tcp_packet_receive) + { + return(NX_NOT_ENABLED); + } + + /* Check for an invalid port. */ + if ((!port) || (((ULONG)port) > (ULONG)NX_MAX_PORT)) + { + return(NX_INVALID_PORT); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual TCP server socket unlisten function. */ + status = _nx_tcp_server_socket_unlisten(ip_ptr, port); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_tcp_socket_bytes_available.c b/common/src/nxe_tcp_socket_bytes_available.c new file mode 100644 index 0000000..a8cb1eb --- /dev/null +++ b/common/src/nxe_tcp_socket_bytes_available.c @@ -0,0 +1,108 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_packet.h" +#include "nx_tcp.h" + + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_tcp_socket_bytes_available PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the TCP socket bytes */ +/* available function call. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to socket */ +/* bytes_available Pointer to bytes available */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_tcp_socket_bytes_available Actual TCP socket bytes */ +/* available function */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_tcp_socket_bytes_available(NX_TCP_SOCKET *socket_ptr, ULONG *bytes_available) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((socket_ptr == NX_NULL) || + (socket_ptr -> nx_tcp_socket_id != NX_TCP_ID) || + (bytes_available == NX_NULL)) + { + return(NX_PTR_ERROR); + } + + /* Check to see if TCP is enabled. */ + if (!(socket_ptr -> nx_tcp_socket_ip_ptr) -> nx_ip_tcp_packet_receive) + { + return(NX_NOT_ENABLED); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual TCP socket receive function. */ + status = _nx_tcp_socket_bytes_available(socket_ptr, bytes_available); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_tcp_socket_create.c b/common/src/nxe_tcp_socket_create.c new file mode 100644 index 0000000..5c2e260 --- /dev/null +++ b/common/src/nxe_tcp_socket_create.c @@ -0,0 +1,190 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_tcp.h" + + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_tcp_socket_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the TCP socket create */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP instance pointer */ +/* socket_ptr Pointer to new TCP socket */ +/* name Name of new TCP socket */ +/* type_of_service Type of service for this TCP */ +/* socket */ +/* fragment Flag to enable IP fragmenting */ +/* time_to_live Time to live value for socket */ +/* window_size Size of socket's receive */ +/* window */ +/* tcp_urgent_data_callback Routine to call when urgent */ +/* data is received */ +/* tcp_disconnect_callback Routine to call when a */ +/* disconnect occurs */ +/* tcp_socket_size Size of TCP socket */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_tcp_socket_create Actual TCP socket create */ +/* function */ +/* tx_mutex_get Get protection mutex */ +/* tx_mutex_put Put protection mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_tcp_socket_create(NX_IP *ip_ptr, NX_TCP_SOCKET *socket_ptr, CHAR *name, + ULONG type_of_service, ULONG fragment, UINT time_to_live, ULONG window_size, + VOID (*tcp_urgent_data_callback)(NX_TCP_SOCKET *socket_ptr), + VOID (*tcp_disconnect_callback)(NX_TCP_SOCKET *socket_ptr), + UINT tcp_socket_size) +{ + +UINT status; +NX_TCP_SOCKET *created_socket; +ULONG created_count; + + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) || (socket_ptr == NX_NULL) || + (tcp_socket_size != sizeof(NX_TCP_SOCKET))) + { + return(NX_PTR_ERROR); + } + + /* Check for appropriate caller. */ + NX_INIT_AND_THREADS_CALLER_CHECKING + + /* Get protection mutex. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Pickup created count and created socket pointer. */ + created_count = ip_ptr -> nx_ip_tcp_created_sockets_count; + created_socket = ip_ptr -> nx_ip_tcp_created_sockets_ptr; + + /* Loop to look for socket already created. */ + while (created_count--) + { + + /* Compare the new socket with the already created socket. */ + if (socket_ptr == created_socket) + { + + /* Error, socket already created! */ + + /* Release protection mutex. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return error. */ + return(NX_PTR_ERROR); + } + + /* Move to next created socket. */ + created_socket = created_socket -> nx_tcp_socket_created_next; + } + + /* Release protection mutex. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Check to see if TCP is enabled. */ + if (!ip_ptr -> nx_ip_tcp_packet_receive) + { + return(NX_NOT_ENABLED); + } + + /* Check for valid type of service. */ + if (type_of_service & ~(NX_IP_TOS_MASK)) + { + return(NX_OPTION_ERROR); + } + + /* Check for valid fragment option. */ + if ((fragment != NX_FRAGMENT_OKAY) && + (fragment != NX_DONT_FRAGMENT)) + { + return(NX_OPTION_ERROR); + } + + /* Check for valid time to live option. */ + if (((ULONG)time_to_live) > NX_IP_TIME_TO_LIVE_MASK) + { + return(NX_OPTION_ERROR); + } + + /* Check for valid window size. */ + if (!window_size) + { + return(NX_OPTION_ERROR); + } + +#ifndef NX_ENABLE_TCP_WINDOW_SCALING + if (window_size > NX_LOWER_16_MASK) + { + return(NX_OPTION_ERROR); + } +#endif /* NX_ENABLE_TCP_WINDOW_SCALING */ + + /* Call actual TCP socket create function. */ + status = _nx_tcp_socket_create(ip_ptr, socket_ptr, name, type_of_service, fragment, time_to_live, + window_size, tcp_urgent_data_callback, tcp_disconnect_callback); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_tcp_socket_delete.c b/common/src/nxe_tcp_socket_delete.c new file mode 100644 index 0000000..5f2eb2d --- /dev/null +++ b/common/src/nxe_tcp_socket_delete.c @@ -0,0 +1,103 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_tcp.h" + + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_tcp_socket_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the TCP socket delete */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to TCP socket */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_tcp_socket_delete Actual TCP socket delete */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_tcp_socket_delete(NX_TCP_SOCKET *socket_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((socket_ptr == NX_NULL) || (socket_ptr -> nx_tcp_socket_id != NX_TCP_ID)) + { + return(NX_PTR_ERROR); + } + + /* Check to see if TCP is enabled. */ + if (!(socket_ptr -> nx_tcp_socket_ip_ptr) -> nx_ip_tcp_packet_receive) + { + return(NX_NOT_ENABLED); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual TCP socket delete function. */ + status = _nx_tcp_socket_delete(socket_ptr); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_tcp_socket_disconnect.c b/common/src/nxe_tcp_socket_disconnect.c new file mode 100644 index 0000000..8e89565 --- /dev/null +++ b/common/src/nxe_tcp_socket_disconnect.c @@ -0,0 +1,104 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_tcp.h" + + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_tcp_socket_disconnect PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the socket disconnect */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to TCP client socket */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_tcp_socket_disconnect Actual TCP socket disconnect */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_tcp_socket_disconnect(NX_TCP_SOCKET *socket_ptr, ULONG wait_option) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((socket_ptr == NX_NULL) || (socket_ptr -> nx_tcp_socket_id != NX_TCP_ID)) + { + return(NX_PTR_ERROR); + } + + /* Check to see if TCP is enabled. */ + if (!(socket_ptr -> nx_tcp_socket_ip_ptr) -> nx_ip_tcp_packet_receive) + { + return(NX_NOT_ENABLED); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual TCP socket disconnect function. */ + status = _nx_tcp_socket_disconnect(socket_ptr, wait_option); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_tcp_socket_disconnect_complete_notify.c b/common/src/nxe_tcp_socket_disconnect_complete_notify.c new file mode 100644 index 0000000..785e67c --- /dev/null +++ b/common/src/nxe_tcp_socket_disconnect_complete_notify.c @@ -0,0 +1,104 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_tcp.h" + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_tcp_socket_disconnect_complete_notify PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the TCP socket disconnect */ +/* complete notify function call. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to TCP socket */ +/* tcp_disconnect_complete_notify Routine to call when the */ +/* disconnect is completed */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_tcp_socket_disconnect_complete_notify */ +/* Actual socket disconnect */ +/* complete notify function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_tcp_socket_disconnect_complete_notify(NX_TCP_SOCKET *socket_ptr, VOID (*tcp_disconnect_complete_notify)(NX_TCP_SOCKET *socket_ptr)) +{ + +#ifndef NX_DISABLE_EXTENDED_NOTIFY_SUPPORT +UINT status; + + /* Check for invalid input pointers. */ + if ((socket_ptr == NX_NULL) || (socket_ptr -> nx_tcp_socket_id != NX_TCP_ID) || (tcp_disconnect_complete_notify == NX_NULL)) + { + return(NX_PTR_ERROR); + } + + /* Check for appropriate caller. */ + NX_INIT_AND_THREADS_CALLER_CHECKING + + /* Call actual socket disconnect complete notify function. */ + status = _nx_tcp_socket_disconnect_complete_notify(socket_ptr, tcp_disconnect_complete_notify); + + /* Return to caller. */ + return(status); +#else /* NX_DISABLE_EXTENDED_NOTIFY_SUPPORT */ + NX_PARAMETER_NOT_USED(socket_ptr); + NX_PARAMETER_NOT_USED(tcp_disconnect_complete_notify); + + return(NX_NOT_SUPPORTED); +#endif /* NX_DISABLE_EXTENDED_NOTIFY_SUPPORT */ +} + diff --git a/common/src/nxe_tcp_socket_establish_notify.c b/common/src/nxe_tcp_socket_establish_notify.c new file mode 100644 index 0000000..d5fcd99 --- /dev/null +++ b/common/src/nxe_tcp_socket_establish_notify.c @@ -0,0 +1,106 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_tcp.h" + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_tcp_socket_establishe_notify PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the TCP socket establish notify */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to TCP socket */ +/* tcp_establish_notify Routine to call when the */ +/* connection handshake is */ +/* completed */ +/* */ +/* OUTPUT */ +/* */ +/* NX_PTR_ERROR Invalid pointer input */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_tcp_socket_establish_notify Actual socket establish notify*/ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_tcp_socket_establish_notify(NX_TCP_SOCKET *socket_ptr, VOID (*tcp_establish_notify)(NX_TCP_SOCKET *socket_ptr)) +{ + +#ifndef NX_DISABLE_EXTENDED_NOTIFY_SUPPORT +UINT status; + + /* Check for invalid input pointers. */ + if ((socket_ptr == NX_NULL) || (socket_ptr -> nx_tcp_socket_id != NX_TCP_ID) || (tcp_establish_notify == NX_NULL)) + { + return(NX_PTR_ERROR); + } + + /* Check for appropriate caller. */ + NX_INIT_AND_THREADS_CALLER_CHECKING + + /* Call actual socket establish notify function. */ + status = _nx_tcp_socket_establish_notify(socket_ptr, tcp_establish_notify); + + /* Return to caller. */ + return(status); +#else /* NX_DISABLE_EXTENDED_NOTIFY_SUPPORT */ + NX_PARAMETER_NOT_USED(socket_ptr); + NX_PARAMETER_NOT_USED(tcp_establish_notify); + + return(NX_NOT_SUPPORTED); +#endif /* NX_DISABLE_EXTENDED_NOTIFY_SUPPORT */ +} + diff --git a/common/src/nxe_tcp_socket_info_get.c b/common/src/nxe_tcp_socket_info_get.c new file mode 100644 index 0000000..7f91cfa --- /dev/null +++ b/common/src/nxe_tcp_socket_info_get.c @@ -0,0 +1,134 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_tcp.h" + + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_tcp_socket_info_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the socket information get */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to the TCP socket */ +/* tcp_packets_sent Destination for number of */ +/* packets sent */ +/* tcp_bytes_sent Destination for number of */ +/* bytes sent */ +/* tcp_packets_received Destination for number of */ +/* packets received */ +/* tcp_bytes_received Destination for number of */ +/* bytes received */ +/* tcp_retransmit_packets Destination for number of */ +/* retransmit packets */ +/* tcp_packets_queued Destination for number of */ +/* receive packets queued */ +/* tcp_checksum_errors Destination for number of */ +/* checksum errors */ +/* tcp_socket_state Destination for the current */ +/* socket state */ +/* tcp_transmit_queue_depth Destination for number of */ +/* sockets still in transmit */ +/* queue */ +/* tcp_transmit_window Destination for number of */ +/* bytes in transmit window */ +/* tcp_receive_window Destination for number of */ +/* bytes in receive window */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_tcp_socket_info_get Actual socket information get */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_tcp_socket_info_get(NX_TCP_SOCKET *socket_ptr, ULONG *tcp_packets_sent, ULONG *tcp_bytes_sent, + ULONG *tcp_packets_received, ULONG *tcp_bytes_received, + ULONG *tcp_retransmit_packets, ULONG *tcp_packets_queued, + ULONG *tcp_checksum_errors, ULONG *tcp_socket_state, + ULONG *tcp_transmit_queue_depth, ULONG *tcp_transmit_window, + ULONG *tcp_receive_window) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((socket_ptr == NX_NULL) || (socket_ptr -> nx_tcp_socket_id != NX_TCP_ID)) + { + return(NX_PTR_ERROR); + } + + /* Check to see if TCP is enabled. */ + if (!(socket_ptr -> nx_tcp_socket_ip_ptr) -> nx_ip_tcp_packet_receive) + { + return(NX_NOT_ENABLED); + } + + /* Check for appropriate caller. */ + NX_INIT_AND_THREADS_CALLER_CHECKING + + /* Call actual TCP socket information get function. */ + status = _nx_tcp_socket_info_get(socket_ptr, tcp_packets_sent, tcp_bytes_sent, tcp_packets_received, + tcp_bytes_received, tcp_retransmit_packets, tcp_packets_queued, + tcp_checksum_errors, tcp_socket_state, tcp_transmit_queue_depth, + tcp_transmit_window, tcp_receive_window); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_tcp_socket_mss_get.c b/common/src/nxe_tcp_socket_mss_get.c new file mode 100644 index 0000000..ff4744c --- /dev/null +++ b/common/src/nxe_tcp_socket_mss_get.c @@ -0,0 +1,104 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_tcp.h" + + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_tcp_socket_mss_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the socket MSS get */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to the TCP socket */ +/* mss Destination for the MSS */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_tcp_socket_mss_get Actual socket MSS get */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_tcp_socket_mss_get(NX_TCP_SOCKET *socket_ptr, ULONG *mss) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((socket_ptr == NX_NULL) || (socket_ptr -> nx_tcp_socket_id != NX_TCP_ID) || (mss == NX_NULL)) + { + return(NX_PTR_ERROR); + } + + /* Check to see if TCP is enabled. */ + if (!(socket_ptr -> nx_tcp_socket_ip_ptr) -> nx_ip_tcp_packet_receive) + { + return(NX_NOT_ENABLED); + } + + /* Check for appropriate caller. */ + NX_INIT_AND_THREADS_CALLER_CHECKING + + /* Call actual TCP socket MSS get function. */ + status = _nx_tcp_socket_mss_get(socket_ptr, mss); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_tcp_socket_mss_peer_get.c b/common/src/nxe_tcp_socket_mss_peer_get.c new file mode 100644 index 0000000..640a45f --- /dev/null +++ b/common/src/nxe_tcp_socket_mss_peer_get.c @@ -0,0 +1,104 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_tcp.h" + + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_tcp_socket_mss_peer_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the socket MSS peer get */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to the TCP socket */ +/* peer_mss Destination for the MSS */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_tcp_socket_mss_peer_get Actual socket MSS get */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_tcp_socket_mss_peer_get(NX_TCP_SOCKET *socket_ptr, ULONG *peer_mss) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((socket_ptr == NX_NULL) || (socket_ptr -> nx_tcp_socket_id != NX_TCP_ID) || (peer_mss == NX_NULL)) + { + return(NX_PTR_ERROR); + } + + /* Check to see if TCP is enabled. */ + if (!(socket_ptr -> nx_tcp_socket_ip_ptr) -> nx_ip_tcp_packet_receive) + { + return(NX_NOT_ENABLED); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual TCP socket MSS peer get function. */ + status = _nx_tcp_socket_mss_peer_get(socket_ptr, peer_mss); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_tcp_socket_mss_set.c b/common/src/nxe_tcp_socket_mss_set.c new file mode 100644 index 0000000..764cb63 --- /dev/null +++ b/common/src/nxe_tcp_socket_mss_set.c @@ -0,0 +1,104 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_tcp.h" + + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_tcp_socket_mss_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the socket MSS set */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to the TCP socket */ +/* mss New value for the MSS */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_tcp_socket_mss_set Actual socket MSS set */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_tcp_socket_mss_set(NX_TCP_SOCKET *socket_ptr, ULONG mss) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((socket_ptr == NX_NULL) || (socket_ptr -> nx_tcp_socket_id != NX_TCP_ID)) + { + return(NX_PTR_ERROR); + } + + /* Check to see if TCP is enabled. */ + if (!(socket_ptr -> nx_tcp_socket_ip_ptr) -> nx_ip_tcp_packet_receive) + { + return(NX_NOT_ENABLED); + } + + /* Check for appropriate caller. */ + NX_INIT_AND_THREADS_CALLER_CHECKING + + /* Call actual TCP socket MSS set function. */ + status = _nx_tcp_socket_mss_set(socket_ptr, mss); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_tcp_socket_peer_info_get.c b/common/src/nxe_tcp_socket_peer_info_get.c new file mode 100644 index 0000000..327209b --- /dev/null +++ b/common/src/nxe_tcp_socket_peer_info_get.c @@ -0,0 +1,106 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_tcp.h" + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_tcp_socket_peer_info_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function retrieves IP address and port number of the peer */ +/* connected to the specified TCP socket. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to the TCP sockete */ +/* peer_ip_address Pointer to the IP address */ +/* of the peer. */ +/* peer_port Pointer to the port number */ +/* of the peer. */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_tcp_socket_peer_info_get Actual TCP socket peer info */ +/* get function */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_tcp_socket_peer_info_get(NX_TCP_SOCKET *socket_ptr, + ULONG *peer_ip_address, + ULONG *peer_port) +{ +UINT status; + + + /* Check for invalid input pointers. */ + if ((socket_ptr == NX_NULL) || (socket_ptr -> nx_tcp_socket_id != NX_TCP_ID)) + { + return(NX_PTR_ERROR); + } + + /* Check to see if TCP is enabled. */ + if (!(socket_ptr -> nx_tcp_socket_ip_ptr) -> nx_ip_tcp_packet_receive) + { + return(NX_NOT_ENABLED); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual TCP socket MSS get function. */ + status = _nx_tcp_socket_peer_info_get(socket_ptr, peer_ip_address, peer_port); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_tcp_socket_receive.c b/common/src/nxe_tcp_socket_receive.c new file mode 100644 index 0000000..85e3cc0 --- /dev/null +++ b/common/src/nxe_tcp_socket_receive.c @@ -0,0 +1,107 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_packet.h" +#include "nx_tcp.h" + + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_tcp_socket_receive PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the TCP socket receive */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to socket */ +/* packet_ptr Pointer to packet pointer */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_tcp_socket_receive Actual TCP socket receive */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_tcp_socket_receive(NX_TCP_SOCKET *socket_ptr, NX_PACKET **packet_ptr, ULONG wait_option) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((socket_ptr == NX_NULL) || (socket_ptr -> nx_tcp_socket_id != NX_TCP_ID) || (packet_ptr == NX_NULL)) + { + return(NX_PTR_ERROR); + } + + /* Check to see if TCP is enabled. */ + if (!(socket_ptr -> nx_tcp_socket_ip_ptr) -> nx_ip_tcp_packet_receive) + { + return(NX_NOT_ENABLED); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual TCP socket receive function. */ + status = _nx_tcp_socket_receive(socket_ptr, packet_ptr, wait_option); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_tcp_socket_receive_notify.c b/common/src/nxe_tcp_socket_receive_notify.c new file mode 100644 index 0000000..5474f7d --- /dev/null +++ b/common/src/nxe_tcp_socket_receive_notify.c @@ -0,0 +1,99 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_tcp.h" + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_tcp_socket_receive_notify PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the TCP socket receive notify */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to TCP socket */ +/* tcp_receive_notify Routine to call when one or */ +/* receive packets are */ +/* available for the socket */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_tcp_socket_receive_notify Actual socket receive notify */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_tcp_socket_receive_notify(NX_TCP_SOCKET *socket_ptr, + VOID (*tcp_receive_notify)(NX_TCP_SOCKET *socket_ptr)) +{ + +UINT status; + + /* Check for invalid input pointers. */ + if ((socket_ptr == NX_NULL) || (socket_ptr -> nx_tcp_socket_id != NX_TCP_ID)) + { + return(NX_PTR_ERROR); + } + + /* Check for appropriate caller. */ + NX_INIT_AND_THREADS_CALLER_CHECKING + + /* Call actual socket receive notify function. */ + status = _nx_tcp_socket_receive_notify(socket_ptr, tcp_receive_notify); + + /* Return to caller. */ + return(status); +} + diff --git a/common/src/nxe_tcp_socket_send.c b/common/src/nxe_tcp_socket_send.c new file mode 100644 index 0000000..7914ec2 --- /dev/null +++ b/common/src/nxe_tcp_socket_send.c @@ -0,0 +1,155 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_tcp.h" +#include "nx_packet.h" + + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_tcp_socket_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the TCP socket send */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to socket */ +/* packet_ptr Pointer to packet to send */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_tcp_socket_send Actual TCP socket send */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_tcp_socket_send(NX_TCP_SOCKET *socket_ptr, NX_PACKET **packet_ptr_ptr, ULONG wait_option) +{ + +NX_PACKET *packet_ptr; +UINT status; + + + /* Setup packet pointer. */ + packet_ptr = *packet_ptr_ptr; + + /* Check for invalid input pointers. */ + if ((socket_ptr == NX_NULL) || (socket_ptr -> nx_tcp_socket_id != NX_TCP_ID)) + { + return(NX_PTR_ERROR); + } + + /* Check for an invalid packet pointer. */ + if ((packet_ptr == NX_NULL) || (packet_ptr -> nx_packet_tcp_queue_next != ((NX_PACKET *)NX_PACKET_ALLOCATED))) + { + return(NX_INVALID_PACKET); + } + + /* Check to see if TCP is enabled. */ + if (!(socket_ptr -> nx_tcp_socket_ip_ptr) -> nx_ip_tcp_packet_receive) + { + return(NX_NOT_ENABLED); + } + + /* Check for an invalid packet prepend pointer. */ + if ((packet_ptr -> nx_packet_prepend_ptr - (sizeof(NX_IP_HEADER) + sizeof(NX_TCP_HEADER))) < packet_ptr -> nx_packet_data_start) + { + +#ifndef NX_DISABLE_TCP_INFO + + /* Increment the TCP invalid packet count. */ + (socket_ptr -> nx_tcp_socket_ip_ptr) -> nx_ip_tcp_invalid_packets++; +#endif + + /* Return error code. */ + return(NX_UNDERFLOW); + } + + /* Check for an invalid packet append pointer. */ + if (packet_ptr -> nx_packet_append_ptr > packet_ptr -> nx_packet_data_end) + { + +#ifndef NX_DISABLE_TCP_INFO + + /* Increment the TCP invalid packet count. */ + (socket_ptr -> nx_tcp_socket_ip_ptr) -> nx_ip_tcp_invalid_packets++; +#endif + + /* Return error code. */ + return(NX_OVERFLOW); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual TCP socket send function. */ + status = _nx_tcp_socket_send(socket_ptr, packet_ptr, wait_option); + + /* Determine if the packet send was successful. */ + if (status == NX_SUCCESS) + { + + /* Yes, now clear the application's packet pointer so it can't be accidentally + used again by the application. This is only done when error checking is + enabled. */ + *packet_ptr_ptr = NX_NULL; + } + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_tcp_socket_state_wait.c b/common/src/nxe_tcp_socket_state_wait.c new file mode 100644 index 0000000..f65f8a1 --- /dev/null +++ b/common/src/nxe_tcp_socket_state_wait.c @@ -0,0 +1,111 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_tcp.h" + + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_tcp_socket_state_wait PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the socket state wait */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to socket */ +/* desired_state Desired TCP state */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_tcp_socket_state_wait Actual socket state wait */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_tcp_socket_state_wait(NX_TCP_SOCKET *socket_ptr, UINT desired_state, ULONG wait_option) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((socket_ptr == NX_NULL) || (socket_ptr -> nx_tcp_socket_id != NX_TCP_ID)) + { + return(NX_PTR_ERROR); + } + + /* Check to see if TCP is enabled. */ + if (!(socket_ptr -> nx_tcp_socket_ip_ptr) -> nx_ip_tcp_packet_receive) + { + return(NX_NOT_ENABLED); + } + + /* Check for an invalid state request. */ + if ((desired_state < NX_TCP_CLOSED) || (desired_state > NX_TCP_LAST_ACK)) + { + return(NX_OPTION_ERROR); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual TCP socket state wait function. */ + status = _nx_tcp_socket_state_wait(socket_ptr, desired_state, wait_option); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_tcp_socket_timed_wait_callback.c b/common/src/nxe_tcp_socket_timed_wait_callback.c new file mode 100644 index 0000000..5b3096c --- /dev/null +++ b/common/src/nxe_tcp_socket_timed_wait_callback.c @@ -0,0 +1,107 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_tcp.h" + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_tcp_socket_timed_wait_callback PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking for the timed wait callback */ +/* service. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to TCP socket */ +/* tcp_timed_wait_callback Routine to call to start */ +/* timed wait before close */ +/* */ +/* OUTPUT */ +/* */ +/* NX_PTR_ERROR Invalid pointer input */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_tcp_socket_timed_wait_callback Actual timed wait callback */ +/* service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_tcp_socket_timed_wait_callback(NX_TCP_SOCKET *socket_ptr, VOID (*tcp_timed_wait_callback)(NX_TCP_SOCKET *socket_ptr)) +{ + +#ifndef NX_DISABLE_EXTENDED_NOTIFY_SUPPORT +UINT status; + + + /* Check for invalid input. Note that a NULL pointer is ok for the callback. This is + how the application cancels the callback during the life of the socket. */ + if (socket_ptr == NX_NULL) + { + + return NX_PTR_ERROR; + } + + /* Check for appropriate caller. */ + NX_INIT_AND_THREADS_CALLER_CHECKING + + /* Call the actual service. */ + status = _nx_tcp_socket_timed_wait_callback(socket_ptr, tcp_timed_wait_callback); + + /* Return completion status. */ + return(status); +#else /* NX_DISABLE_EXTENDED_NOTIFY_SUPPORT */ + NX_PARAMETER_NOT_USED(socket_ptr); + NX_PARAMETER_NOT_USED(tcp_timed_wait_callback); + + return(NX_NOT_SUPPORTED); +#endif /* NX_DISABLE_EXTENDED_NOTIFY_SUPPORT */ +} + diff --git a/common/src/nxe_tcp_socket_transmit_configure.c b/common/src/nxe_tcp_socket_transmit_configure.c new file mode 100644 index 0000000..2afcdf4 --- /dev/null +++ b/common/src/nxe_tcp_socket_transmit_configure.c @@ -0,0 +1,113 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_tcp.h" + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_tcp_socket_transmit_configure PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the TCP socket transmit */ +/* configure function call. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to TCP socket */ +/* max_queue_depth Maximum number of transmit */ +/* packets that can be queued */ +/* for the socket */ +/* timeout Number of timer ticks for the */ +/* initial transmit timeout */ +/* max_retries Maximum number of retries */ +/* timeout_shift Factor to be applied to */ +/* subsequent timeouts, a */ +/* value of 0 causes identical */ +/* subsequent timeouts */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_tcp_socket_transmit_configure Actual transmit configure */ +/* service */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_tcp_socket_transmit_configure(NX_TCP_SOCKET *socket_ptr, ULONG max_queue_depth, + ULONG timeout, ULONG max_retries, ULONG timeout_shift) +{ + +UINT status; + + + /* Check for invalid input pointer. */ + if ((socket_ptr == NX_NULL) || (socket_ptr -> nx_tcp_socket_id != NX_TCP_ID)) + { + return(NX_PTR_ERROR); + } + + /* Check for valid options. */ + if (!max_queue_depth) + { + return(NX_OPTION_ERROR); + } + + /* Check for appropriate caller. */ + NX_INIT_AND_THREADS_CALLER_CHECKING + + /* Call actual socket transmit configure service. */ + status = _nx_tcp_socket_transmit_configure(socket_ptr, max_queue_depth, + timeout, max_retries, timeout_shift); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_tcp_socket_window_update_notify_set.c b/common/src/nxe_tcp_socket_window_update_notify_set.c new file mode 100644 index 0000000..8ef071a --- /dev/null +++ b/common/src/nxe_tcp_socket_window_update_notify_set.c @@ -0,0 +1,97 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Transmission Control Protocol (TCP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_tcp.h" + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_tcp_socket_window_update_notify_set PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the TCP socket window update */ +/* notify set call. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to TCP socket */ +/* tcp_window_udpate_notify Routine to call when NetX */ +/* receives a window update */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_tcp_socket_window_update_notify_set Acutal notify set routine.*/ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_tcp_socket_window_update_notify_set(NX_TCP_SOCKET *socket_ptr, + VOID (*tcp_socket_window_update_notify)(NX_TCP_SOCKET *socket_ptr)) +{ + + /* Check for invalid input pointers. */ + if ((socket_ptr == NX_NULL) || (socket_ptr -> nx_tcp_socket_id != NX_TCP_ID)) + { + return(NX_PTR_ERROR); + } + + /* Check to see if TCP is enabled. */ + if (!(socket_ptr -> nx_tcp_socket_ip_ptr) -> nx_ip_tcp_packet_receive) + { + return(NX_NOT_ENABLED); + } + + /* Check for appropriate caller. */ + NX_INIT_AND_THREADS_CALLER_CHECKING + + return(_nx_tcp_socket_window_update_notify_set(socket_ptr, tcp_socket_window_update_notify)); +} + diff --git a/common/src/nxe_udp_enable.c b/common/src/nxe_udp_enable.c new file mode 100644 index 0000000..7ddc2db --- /dev/null +++ b/common/src/nxe_udp_enable.c @@ -0,0 +1,102 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** User Datagram Protocol (UDP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_udp.h" + + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_udp_enable PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the UDP enable function call. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP instance pointer */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_udp_enable Actual UDP enable function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_udp_enable(NX_IP *ip_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID)) + { + return(NX_PTR_ERROR); + } + + /* Check to see if UDP is enabled. */ + if (ip_ptr -> nx_ip_udp_packet_receive) + { + return(NX_ALREADY_ENABLED); + } + + /* Check for appropriate caller. */ + NX_NOT_ISR_CALLER_CHECKING + + /* Call actual UDP enable function. */ + status = _nx_udp_enable(ip_ptr); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_udp_free_port_find.c b/common/src/nxe_udp_free_port_find.c new file mode 100644 index 0000000..0d34b1a --- /dev/null +++ b/common/src/nxe_udp_free_port_find.c @@ -0,0 +1,112 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** User Datagram Protocol (UDP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_udp.h" + + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_udp_free_port_find PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the UDP free port find */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP instance pointer */ +/* port Starting port */ +/* free_port_ptr Pointer to return free port */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_udp_free_port_find Actual UDP free port find */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_udp_free_port_find(NX_IP *ip_ptr, UINT port, UINT *free_port_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) || (free_port_ptr == NX_NULL)) + { + return(NX_PTR_ERROR); + } + + /* Check to see if UDP is enabled. */ + if (!ip_ptr -> nx_ip_udp_packet_receive) + { + return(NX_NOT_ENABLED); + } + + /* Check for an invalid port. */ + if ((!port) || (((ULONG)port) > (ULONG)NX_MAX_PORT)) + { + return(NX_INVALID_PORT); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual UDP free port find function. */ + status = _nx_udp_free_port_find(ip_ptr, port, free_port_ptr); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_udp_info_get.c b/common/src/nxe_udp_info_get.c new file mode 100644 index 0000000..799eda2 --- /dev/null +++ b/common/src/nxe_udp_info_get.c @@ -0,0 +1,123 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** User Datagram Protocol (UDP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_udp.h" + + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_udp_info_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the UDP information get */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP control block */ +/* udp_packets_sent Destination to the number of */ +/* packets sent */ +/* udp_bytes_sent Destination to the number of */ +/* bytes sent */ +/* udp_packets_received Destination to the number of */ +/* packets received */ +/* udp_bytes_received Destination to the number of */ +/* bytes received */ +/* udp_invalid_packets Destination to the number of */ +/* invalid packets */ +/* udp_receive_packets_dropped Destination to the number of */ +/* receive packets dropped */ +/* udp_checksum_errors Destination to the number of */ +/* checksum errors */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_udp_info_get Actual UDP information get */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_udp_info_get(NX_IP *ip_ptr, ULONG *udp_packets_sent, ULONG *udp_bytes_sent, + ULONG *udp_packets_received, ULONG *udp_bytes_received, + ULONG *udp_invalid_packets, ULONG *udp_receive_packets_dropped, + ULONG *udp_checksum_errors) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID)) + { + return(NX_PTR_ERROR); + } + + /* Check to see if UDP is enabled. */ + if (!ip_ptr -> nx_ip_udp_packet_receive) + { + return(NX_NOT_ENABLED); + } + + /* Check for appropriate caller. */ + NX_NOT_ISR_CALLER_CHECKING + + /* Call actual UDP information get function. */ + status = _nx_udp_info_get(ip_ptr, udp_packets_sent, udp_bytes_sent, udp_packets_received, + udp_bytes_received, udp_invalid_packets, udp_receive_packets_dropped, + udp_checksum_errors); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_udp_packet_info_extract.c b/common/src/nxe_udp_packet_info_extract.c new file mode 100644 index 0000000..14fbe04 --- /dev/null +++ b/common/src/nxe_udp_packet_info_extract.c @@ -0,0 +1,121 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** User Datagram Protocol (UDP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_udp.h" +#include "nx_ip.h" + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_udp_pacekt_info_extract PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function performs error checking for UDP packet info extract */ +/* service. */ +/* */ +/* INPUT */ +/* */ +/* packet_ptr Pointer to UDP packet pointer */ +/* ip_address Pointer to destination for IP */ +/* address, or NULL */ +/* protocol Pointer to destination for */ +/* protocol information, or */ +/* NULL */ +/* port Pointer to destination for */ +/* source port. This service */ +/* always returns 17 (UDP), or */ +/* NULL */ +/* interface_index Pointer to destination for */ +/* incoming interface ID, or */ +/* NULL */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_udp_packet_info_extract The actual service routine. */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_udp_packet_info_extract(NX_PACKET *packet_ptr, ULONG *ip_address, + UINT *protocol, UINT *port, UINT *interface_index) +{ +UINT status; +NX_IP *ip_ptr; + + if (packet_ptr == NX_NULL) + { + return(NX_PTR_ERROR); + } + + /* If interface field is present in the packet structure, + validate that the interface is attached to an IP instance. */ + if (packet_ptr -> nx_packet_ip_interface) + { + ip_ptr = packet_ptr -> nx_packet_ip_interface -> nx_interface_ip_instance; + + if (ip_ptr == NX_NULL) + { + return(NX_PTR_ERROR); + } + + if (ip_ptr -> nx_ip_id != NX_IP_ID) + { + return(NX_PTR_ERROR); + } + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + status = _nx_udp_packet_info_extract(packet_ptr, ip_address, protocol, port, interface_index); + + + return(status); +} + diff --git a/common/src/nxe_udp_socket_bind.c b/common/src/nxe_udp_socket_bind.c new file mode 100644 index 0000000..25b1bd1 --- /dev/null +++ b/common/src/nxe_udp_socket_bind.c @@ -0,0 +1,111 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** User Datagram Protocol (UDP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_udp.h" + + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_udp_socket_bind PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the UDP socket bind */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to UDP socket */ +/* port 16-bit UDP port number */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_udp_socket_bind Actual UDP socket bind */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_udp_socket_bind(NX_UDP_SOCKET *socket_ptr, UINT port, ULONG wait_option) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((socket_ptr == NX_NULL) || (socket_ptr -> nx_udp_socket_id != NX_UDP_ID)) + { + return(NX_PTR_ERROR); + } + + /* Check to see if UDP is enabled. */ + if (!(socket_ptr -> nx_udp_socket_ip_ptr) -> nx_ip_udp_packet_receive) + { + return(NX_NOT_ENABLED); + } + + /* Check for an invalid port. */ + if (((ULONG)port) > (ULONG)NX_MAX_PORT) + { + return(NX_INVALID_PORT); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual UDP socket bind function. */ + status = _nx_udp_socket_bind(socket_ptr, port, wait_option); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_udp_socket_bytes_available.c b/common/src/nxe_udp_socket_bytes_available.c new file mode 100644 index 0000000..c7c2607 --- /dev/null +++ b/common/src/nxe_udp_socket_bytes_available.c @@ -0,0 +1,106 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** User Datagram Protocol (UDP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_packet.h" +#include "nx_udp.h" + + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_udp_socket_bytes_available PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the UDP socket bytes */ +/* available function call. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to socket */ +/* bytes_available Pointer to bytes available */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_udp_socket_bytes_available Actual UDP socket bytes */ +/* available function */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_udp_socket_bytes_available(NX_UDP_SOCKET *socket_ptr, ULONG *bytes_available) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((socket_ptr == NX_NULL) || (socket_ptr -> nx_udp_socket_id != NX_UDP_ID) || (bytes_available == NX_NULL)) + { + return(NX_PTR_ERROR); + } + + /* Check to see if UDP is enabled. */ + if (!(socket_ptr -> nx_udp_socket_ip_ptr) -> nx_ip_udp_packet_receive) + { + return(NX_NOT_ENABLED); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual UDP socket receive function. */ + status = _nx_udp_socket_bytes_available(socket_ptr, bytes_available); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_udp_socket_checksum_disable.c b/common/src/nxe_udp_socket_checksum_disable.c new file mode 100644 index 0000000..6b4661e --- /dev/null +++ b/common/src/nxe_udp_socket_checksum_disable.c @@ -0,0 +1,104 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** User Datagram Protocol (UDP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_udp.h" + + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_udp_socket_checksum_disable PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the socket checksum disable */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to UDP socket */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_udp_socket_checksum_disable Actual socket checksum */ +/* disable function */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_udp_socket_checksum_disable(NX_UDP_SOCKET *socket_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((socket_ptr == NX_NULL) || (socket_ptr -> nx_udp_socket_id != NX_UDP_ID)) + { + return(NX_PTR_ERROR); + } + + /* Check to see if UDP is enabled. */ + if (!(socket_ptr -> nx_udp_socket_ip_ptr) -> nx_ip_udp_packet_receive) + { + return(NX_NOT_ENABLED); + } + + /* Check for appropriate caller. */ + NX_NOT_ISR_CALLER_CHECKING + + /* Call actual UDP socket checksum disable function. */ + status = _nx_udp_socket_checksum_disable(socket_ptr); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_udp_socket_checksum_enable.c b/common/src/nxe_udp_socket_checksum_enable.c new file mode 100644 index 0000000..2db2a58 --- /dev/null +++ b/common/src/nxe_udp_socket_checksum_enable.c @@ -0,0 +1,103 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** User Datagram Protocol (UDP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_udp.h" + + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_udp_socket_checksum_enable PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the socket checksum enable */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to UDP socket */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_udp_socket_checksum_enable Actual socket checksum enable */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_udp_socket_checksum_enable(NX_UDP_SOCKET *socket_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((socket_ptr == NX_NULL) || (socket_ptr -> nx_udp_socket_id != NX_UDP_ID)) + { + return(NX_PTR_ERROR); + } + + /* Check to see if UDP is enabled. */ + if (!(socket_ptr -> nx_udp_socket_ip_ptr) -> nx_ip_udp_packet_receive) + { + return(NX_NOT_ENABLED); + } + + /* Check for appropriate caller. */ + NX_NOT_ISR_CALLER_CHECKING + + /* Call actual UDP socket checksum enable function. */ + status = _nx_udp_socket_checksum_enable(socket_ptr); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_udp_socket_create.c b/common/src/nxe_udp_socket_create.c new file mode 100644 index 0000000..55f22d5 --- /dev/null +++ b/common/src/nxe_udp_socket_create.c @@ -0,0 +1,170 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** User Datagram Protocol (UDP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_udp.h" + + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_udp_socket_create PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the UDP socket create */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr IP instance pointer */ +/* socket_ptr Pointer to new UDP socket */ +/* name Name of new UDP socket */ +/* type_of_service Type of service for this UDP */ +/* socket */ +/* fragment Flag to enable IP fragmenting */ +/* time_to_live Time to live value for socket */ +/* queue_maximum Maximum depth of receive queue*/ +/* udp_socket_size Size of UDP socket */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_udp_socket_create Actual UDP socket create */ +/* function */ +/* tx_mutex_get Get protection mutex */ +/* tx_mutex_put Put protection mutex */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_udp_socket_create(NX_IP *ip_ptr, NX_UDP_SOCKET *socket_ptr, CHAR *name, + ULONG type_of_service, ULONG fragment, UINT time_to_live, + ULONG queue_maximum, UINT udp_socket_size) +{ + +UINT status; +NX_UDP_SOCKET *created_socket; +ULONG created_count; + + + /* Check for invalid input pointers. */ + if ((ip_ptr == NX_NULL) || (ip_ptr -> nx_ip_id != NX_IP_ID) || + (socket_ptr == NX_NULL) || (udp_socket_size != sizeof(NX_UDP_SOCKET))) + { + return(NX_PTR_ERROR); + } + + /* Check for appropriate caller. */ + NX_INIT_AND_THREADS_CALLER_CHECKING + + /* Get protection mutex. */ + tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER); + + /* Pickup created count and created socket pointer. */ + created_count = ip_ptr -> nx_ip_udp_created_sockets_count; + created_socket = ip_ptr -> nx_ip_udp_created_sockets_ptr; + + /* Loop to look for socket already created. */ + while (created_count--) + { + + /* Compare the new socket with the already created socket. */ + if (socket_ptr == created_socket) + { + + /* Error, socket already created! */ + + /* Release protection mutex. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Return error. */ + return(NX_PTR_ERROR); + } + + /* Move to next created socket. */ + created_socket = created_socket -> nx_udp_socket_created_next; + } + + /* Release protection mutex. */ + tx_mutex_put(&(ip_ptr -> nx_ip_protection)); + + /* Check to see if UDP is enabled. */ + if (!ip_ptr -> nx_ip_udp_packet_receive) + { + return(NX_NOT_ENABLED); + } + + /* Check for valid type of service. */ + if (type_of_service & ~(NX_IP_TOS_MASK)) + { + return(NX_OPTION_ERROR); + } + + /* Check for valid fragment option. */ + if ((fragment != NX_FRAGMENT_OKAY) && + (fragment != NX_DONT_FRAGMENT)) + { + return(NX_OPTION_ERROR); + } + + /* Check for valid time to live option. */ + if (((ULONG)time_to_live) > NX_IP_TIME_TO_LIVE_MASK) + { + return(NX_OPTION_ERROR); + } + + /* Call actual UDP socket create function. */ + status = _nx_udp_socket_create(ip_ptr, socket_ptr, name, type_of_service, + fragment, time_to_live, queue_maximum); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_udp_socket_delete.c b/common/src/nxe_udp_socket_delete.c new file mode 100644 index 0000000..f82b911 --- /dev/null +++ b/common/src/nxe_udp_socket_delete.c @@ -0,0 +1,103 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** User Datagram Protocol (UDP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_udp.h" + + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_udp_socket_delete PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the UDP socket delete */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to UDP socket */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_udp_socket_delete Actual UDP socket delete */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_udp_socket_delete(NX_UDP_SOCKET *socket_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((socket_ptr == NX_NULL) || (socket_ptr -> nx_udp_socket_id != NX_UDP_ID)) + { + return(NX_PTR_ERROR); + } + + /* Check to see if UDP is enabled. */ + if (!(socket_ptr -> nx_udp_socket_ip_ptr) -> nx_ip_udp_packet_receive) + { + return(NX_NOT_ENABLED); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual UDP socket delete function. */ + status = _nx_udp_socket_delete(socket_ptr); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_udp_socket_info_get.c b/common/src/nxe_udp_socket_info_get.c new file mode 100644 index 0000000..9532c78 --- /dev/null +++ b/common/src/nxe_udp_socket_info_get.c @@ -0,0 +1,121 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** User Datagram Protocol (UDP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_udp.h" + + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_udp_socket_info_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the UDP socket information get */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* ip_ptr Pointer to IP control block */ +/* udp_packets_sent Destination to the number of */ +/* packets sent */ +/* udp_bytes_sent Destination to the number of */ +/* bytes sent */ +/* udp_packets_received Destination to the number of */ +/* packets received */ +/* udp_bytes_received Destination to the number of */ +/* bytes received */ +/* udp_packets_queued Destination to the number of */ +/* receive packets queued */ +/* udp_receive_packets_dropped Destination to the number of */ +/* receive packets dropped */ +/* udp_checksum_errors Destination to the number of */ +/* checksum errors */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_udp_socket_info_get Actual UDP socket information */ +/* get function */ +/* */ +/* CALLED BY */ +/* */ +/* Application */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_udp_socket_info_get(NX_UDP_SOCKET *socket_ptr, ULONG *udp_packets_sent, ULONG *udp_bytes_sent, + ULONG *udp_packets_received, ULONG *udp_bytes_received, ULONG *udp_packets_queued, + ULONG *udp_receive_packets_dropped, ULONG *udp_checksum_errors) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((socket_ptr == NX_NULL) || (socket_ptr -> nx_udp_socket_id != NX_UDP_ID)) + { + return(NX_PTR_ERROR); + } + + /* Check to see if UDP is enabled. */ + if (!(socket_ptr -> nx_udp_socket_ip_ptr) -> nx_ip_udp_packet_receive) + { + return(NX_NOT_ENABLED); + } + + /* Check for appropriate caller. */ + NX_NOT_ISR_CALLER_CHECKING + + /* Call actual UDP socket information get function. */ + status = _nx_udp_socket_info_get(socket_ptr, udp_packets_sent, udp_bytes_sent, udp_packets_received, + udp_bytes_received, udp_packets_queued, udp_receive_packets_dropped, + udp_checksum_errors); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_udp_socket_interface_send.c b/common/src/nxe_udp_socket_interface_send.c new file mode 100644 index 0000000..2752bc1 --- /dev/null +++ b/common/src/nxe_udp_socket_interface_send.c @@ -0,0 +1,198 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** User Datagram Protocol (UDP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_udp.h" +#include "nx_packet.h" + + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_udp_socket_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the UDP socket send */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to UDP socket */ +/* packet_ptr Pointer to UDP packet */ +/* ip_address IP address */ +/* port 16-bit UDP port number */ +/* interface_index Network interface to use */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_udp_socket_send Actual UDP socket send */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_udp_socket_interface_send(NX_UDP_SOCKET *socket_ptr, NX_PACKET **packet_ptr_ptr, + ULONG ip_address, UINT port, UINT interface_index) +{ + +NX_PACKET *packet_ptr; +UINT status; +NX_IP *ip_ptr; + + /* Setup packet pointer. */ + packet_ptr = *packet_ptr_ptr; + + /* Check for invalid input pointers. */ + if ((socket_ptr == NX_NULL) || (packet_ptr == NX_NULL)) + { + return(NX_PTR_ERROR); + } + + if ((socket_ptr -> nx_udp_socket_id != NX_UDP_ID) || + (packet_ptr -> nx_packet_tcp_queue_next != ((NX_PACKET *)NX_PACKET_ALLOCATED))) + { + return(NX_PTR_ERROR); + } + + /* Check to see if UDP is enabled. */ + if (!(socket_ptr -> nx_udp_socket_ip_ptr) -> nx_ip_udp_packet_receive) + { + return(NX_NOT_ENABLED); + } + + /* Check for invalid IP address. */ + if (!ip_address) + { + return(NX_IP_ADDRESS_ERROR); + } + + /* Check for an invalid port. */ + if (((ULONG)port) > (ULONG)NX_MAX_PORT) + { + return(NX_INVALID_PORT); + } + + /* Validate the IP instance. */ + ip_ptr = socket_ptr -> nx_udp_socket_ip_ptr; + + if (ip_ptr == NX_NULL) + { + return(NX_PTR_ERROR); + } + + if (ip_ptr -> nx_ip_id != NX_IP_ID) + { + return(NX_PTR_ERROR); + } + + /* Validate the interface */ + if (interface_index >= NX_MAX_PHYSICAL_INTERFACES) + { + return(NX_INVALID_INTERFACE); + } + + if (!(ip_ptr -> nx_ip_interface[interface_index].nx_interface_valid)) + { + return(NX_INVALID_INTERFACE); + } + + /* Check for an invalid packet prepend pointer. */ + if ((packet_ptr -> nx_packet_prepend_ptr - (sizeof(NX_IP_HEADER) + sizeof(NX_UDP_HEADER))) < packet_ptr -> nx_packet_data_start) + { + +#ifndef NX_DISABLE_UDP_INFO + /* Increment the total UDP invalid packet count. */ + (socket_ptr -> nx_udp_socket_ip_ptr) -> nx_ip_udp_invalid_packets++; + + /* Increment the total UDP invalid packet count for this socket. */ + socket_ptr -> nx_udp_socket_invalid_packets++; +#endif + + /* Return error code. */ + return(NX_UNDERFLOW); + } + + /* Check for an invalid packet append pointer. */ + if (packet_ptr -> nx_packet_append_ptr > packet_ptr -> nx_packet_data_end) + { + +#ifndef NX_DISABLE_UDP_INFO + /* Increment the total UDP invalid packet count. */ + (socket_ptr -> nx_udp_socket_ip_ptr) -> nx_ip_udp_invalid_packets++; + + /* Increment the total UDP invalid packet count for this socket. */ + socket_ptr -> nx_udp_socket_invalid_packets++; +#endif + + /* Return error code. */ + return(NX_OVERFLOW); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual UDP socket send function. */ + status = _nx_udp_socket_interface_send(socket_ptr, packet_ptr, ip_address, port, interface_index); + + /* Determine if the packet send was successful. */ + if (status == NX_SUCCESS) + { + + /* Yes, now clear the application's packet pointer so it can't be accidentally + used again by the application. This is only done when error checking is + enabled. */ + *packet_ptr_ptr = NX_NULL; + } + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_udp_socket_port_get.c b/common/src/nxe_udp_socket_port_get.c new file mode 100644 index 0000000..580611e --- /dev/null +++ b/common/src/nxe_udp_socket_port_get.c @@ -0,0 +1,105 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** User Datagram Protocol (UDP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_udp.h" + + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_udp_socket_port_get PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the UDP socket port get */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to UDP socket */ +/* port_ptr Destination for port bound to */ +/* this socket */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_udp_socket_port_get Actual UDP socket port get */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_udp_socket_port_get(NX_UDP_SOCKET *socket_ptr, UINT *port_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((socket_ptr == NX_NULL) || (socket_ptr -> nx_udp_socket_id != NX_UDP_ID) || (port_ptr == NX_NULL)) + { + return(NX_PTR_ERROR); + } + + /* Check to see if UDP is enabled. */ + if (!(socket_ptr -> nx_udp_socket_ip_ptr) -> nx_ip_udp_packet_receive) + { + return(NX_NOT_ENABLED); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual UDP socket port get function. */ + status = _nx_udp_socket_port_get(socket_ptr, port_ptr); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_udp_socket_receive.c b/common/src/nxe_udp_socket_receive.c new file mode 100644 index 0000000..f457094 --- /dev/null +++ b/common/src/nxe_udp_socket_receive.c @@ -0,0 +1,107 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** User Datagram Protocol (UDP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_packet.h" +#include "nx_udp.h" + + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_udp_socket_receive PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the UDP socket receive */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to UDP socket */ +/* packet_ptr Pointer to UDP packet pointer */ +/* wait_option Suspension option */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_udp_socket_receive Actual UDP socket receive */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_udp_socket_receive(NX_UDP_SOCKET *socket_ptr, NX_PACKET **packet_ptr, ULONG wait_option) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((socket_ptr == NX_NULL) || (socket_ptr -> nx_udp_socket_id != NX_UDP_ID) || (packet_ptr == NX_NULL)) + { + return(NX_PTR_ERROR); + } + + /* Check to see if UDP is enabled. */ + if (!(socket_ptr -> nx_udp_socket_ip_ptr) -> nx_ip_udp_packet_receive) + { + return(NX_NOT_ENABLED); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual UDP socket receive function. */ + status = _nx_udp_socket_receive(socket_ptr, packet_ptr, wait_option); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_udp_socket_receive_notify.c b/common/src/nxe_udp_socket_receive_notify.c new file mode 100644 index 0000000..7697dca --- /dev/null +++ b/common/src/nxe_udp_socket_receive_notify.c @@ -0,0 +1,92 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** User Datagram Protocol (UDP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_udp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_udp_socket_receive_notify PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the UDP socket receive notify */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to UDP socket */ +/* udp_receive_notify Routine to call when one or */ +/* receive packets are */ +/* available for the socket */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_udp_socket_receive_notify Actual socket receive notify */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_udp_socket_receive_notify(NX_UDP_SOCKET *socket_ptr, + VOID (*udp_receive_notify)(NX_UDP_SOCKET *socket_ptr)) +{ + +UINT status; + + /* Check for invalid input pointers. */ + if ((socket_ptr == NX_NULL) || (socket_ptr -> nx_udp_socket_id != NX_UDP_ID)) + { + return(NX_PTR_ERROR); + } + + /* Call actual socket receive notify function. */ + status = _nx_udp_socket_receive_notify(socket_ptr, udp_receive_notify); + + /* Return to caller. */ + return(status); +} + diff --git a/common/src/nxe_udp_socket_send.c b/common/src/nxe_udp_socket_send.c new file mode 100644 index 0000000..570b2f2 --- /dev/null +++ b/common/src/nxe_udp_socket_send.c @@ -0,0 +1,167 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** User Datagram Protocol (UDP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_udp.h" +#include "nx_packet.h" + + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_udp_socket_send PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the UDP socket send */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to UDP socket */ +/* packet_ptr Pointer to UDP packet */ +/* ip_address IP address */ +/* port 16-bit UDP port number */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_udp_socket_send Actual UDP socket send */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_udp_socket_send(NX_UDP_SOCKET *socket_ptr, NX_PACKET **packet_ptr_ptr, + ULONG ip_address, UINT port) +{ + +NX_PACKET *packet_ptr; +UINT status; + + + /* Setup packet pointer. */ + packet_ptr = *packet_ptr_ptr; + + /* Check for invalid input pointers. */ + if ((socket_ptr == NX_NULL) || (socket_ptr -> nx_udp_socket_id != NX_UDP_ID) || (packet_ptr == NX_NULL) || (packet_ptr -> nx_packet_tcp_queue_next != ((NX_PACKET *)NX_PACKET_ALLOCATED))) + { + return(NX_PTR_ERROR); + } + + /* Check to see if UDP is enabled. */ + if (!(socket_ptr -> nx_udp_socket_ip_ptr) -> nx_ip_udp_packet_receive) + { + return(NX_NOT_ENABLED); + } + + /* Check for invalid IP address. */ + if (!ip_address) + { + return(NX_IP_ADDRESS_ERROR); + } + + /* Check for an invalid port. */ + if (((ULONG)port) > (ULONG)NX_MAX_PORT) + { + return(NX_INVALID_PORT); + } + + /* Check for an invalid packet prepend pointer. */ + if ((packet_ptr -> nx_packet_prepend_ptr - (sizeof(NX_IP_HEADER) + sizeof(NX_UDP_HEADER))) < packet_ptr -> nx_packet_data_start) + { + +#ifndef NX_DISABLE_UDP_INFO + /* Increment the total UDP invalid packet count. */ + (socket_ptr -> nx_udp_socket_ip_ptr) -> nx_ip_udp_invalid_packets++; + + /* Increment the total UDP invalid packet count for this socket. */ + socket_ptr -> nx_udp_socket_invalid_packets++; +#endif + + /* Return error code. */ + return(NX_UNDERFLOW); + } + + /* Check for an invalid packet append pointer. */ + if (packet_ptr -> nx_packet_append_ptr > packet_ptr -> nx_packet_data_end) + { + +#ifndef NX_DISABLE_UDP_INFO + /* Increment the total UDP invalid packet count. */ + (socket_ptr -> nx_udp_socket_ip_ptr) -> nx_ip_udp_invalid_packets++; + + /* Increment the total UDP invalid packet count for this socket. */ + socket_ptr -> nx_udp_socket_invalid_packets++; +#endif + + /* Return error code. */ + return(NX_OVERFLOW); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual UDP socket send function. */ + status = _nx_udp_socket_send(socket_ptr, packet_ptr, ip_address, port); + + /* Determine if the packet send was successful. */ + if (status == NX_SUCCESS) + { + + /* Yes, now clear the application's packet pointer so it can't be accidentally + used again by the application. This is only done when error checking is + enabled. */ + *packet_ptr_ptr = NX_NULL; + } + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_udp_socket_unbind.c b/common/src/nxe_udp_socket_unbind.c new file mode 100644 index 0000000..b05e5a1 --- /dev/null +++ b/common/src/nxe_udp_socket_unbind.c @@ -0,0 +1,103 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** User Datagram Protocol (UDP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_udp.h" + + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_udp_socket_unbind PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the UDP socket unbind */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* socket_ptr Pointer to UDP socket */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_udp_socket_unbind Actual UDP socket unbind */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_udp_socket_unbind(NX_UDP_SOCKET *socket_ptr) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((socket_ptr == NX_NULL) || (socket_ptr -> nx_udp_socket_id != NX_UDP_ID)) + { + return(NX_PTR_ERROR); + } + + /* Check to see if UDP is enabled. */ + if (!(socket_ptr -> nx_udp_socket_ip_ptr) -> nx_ip_udp_packet_receive) + { + return(NX_NOT_ENABLED); + } + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual UDP socket unbind function. */ + status = _nx_udp_socket_unbind(socket_ptr); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/nxe_udp_source_extract.c b/common/src/nxe_udp_source_extract.c new file mode 100644 index 0000000..4f1d5b7 --- /dev/null +++ b/common/src/nxe_udp_source_extract.c @@ -0,0 +1,101 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** User Datagram Protocol (UDP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define NX_SOURCE_CODE + + +/* Include necessary system files. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_udp.h" + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_udp_socket_extract PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function checks for errors in the UDP source extract */ +/* function call. */ +/* */ +/* INPUT */ +/* */ +/* packet_ptr Pointer to UDP packet pointer */ +/* ip_address Pointer to destination for IP */ +/* address */ +/* port Pointer to destination for */ +/* source UDP port */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* */ +/* CALLS */ +/* */ +/* _nx_udp_source_extract Actual UDP source extract */ +/* function */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nxe_udp_source_extract(NX_PACKET *packet_ptr, ULONG *ip_address, UINT *port) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((packet_ptr == NX_NULL) || (ip_address == NX_NULL) || (port == NX_NULL)) + { + return(NX_PTR_ERROR); + } + + /* Check to see if the packet has enough room in front for backing up. */ + if ((UINT)(packet_ptr -> nx_packet_prepend_ptr - packet_ptr -> nx_packet_data_start) < + (sizeof(NX_UDP_HEADER) + sizeof(NX_IP_HEADER))) + { + return(NX_INVALID_PACKET); + } + + /* Call actual UDP source extract function. */ + status = _nx_udp_source_extract(packet_ptr, ip_address, port); + + /* Return completion status. */ + return(status); +} + diff --git a/common/src/readme_netx_generic.txt b/common/src/readme_netx_generic.txt new file mode 100755 index 0000000..d600565 --- /dev/null +++ b/common/src/readme_netx_generic.txt @@ -0,0 +1,12 @@ + Microsoft Azure RTOS NetX + +1. Revision History + + +05/19/2020 Initial Azure RTOS NetX generic code version 6.0. + + +Copyright(c) Microsoft Corporation. All rights reserved + + +https://azure.microsoft.com/en-us/services/rtos/ diff --git a/docs/NetX_Express_Startup.pdf b/docs/NetX_Express_Startup.pdf new file mode 100755 index 0000000..ad0c882 Binary files /dev/null and b/docs/NetX_Express_Startup.pdf differ diff --git a/ports/cortex_m0/gnu/CMakeLists.txt b/ports/cortex_m0/gnu/CMakeLists.txt new file mode 100644 index 0000000..62111b3 --- /dev/null +++ b/ports/cortex_m0/gnu/CMakeLists.txt @@ -0,0 +1,9 @@ +target_sources(${PROJECT_NAME} PRIVATE + # {{BEGIN_TARGET_SOURCES}} + + # {{END_TARGET_SOURCES}} +) + +target_include_directories(${PROJECT_NAME} PUBLIC + ${CMAKE_CURRENT_LIST_DIR}/inc +) \ No newline at end of file diff --git a/ports/cortex_m0/gnu/inc/nx_port.h b/ports/cortex_m0/gnu/inc/nx_port.h new file mode 100644 index 0000000..2619204 --- /dev/null +++ b/ports/cortex_m0/gnu/inc/nx_port.h @@ -0,0 +1,199 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Port Specific */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* PORT SPECIFIC C INFORMATION RELEASE */ +/* */ +/* nx_port.h Cortex-M0/GNU */ +/* 6.0 */ +/* */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file contains data type definitions that make the NetX */ +/* real-time TCP/IP function identically on a variety of different */ +/* processor architectures. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +#ifndef NX_PORT_H +#define NX_PORT_H + +/* Determine if the optional NetX user define file should be used. */ + +#ifdef NX_INCLUDE_USER_DEFINE_FILE + + +/* Yes, include the user defines in nx_user.h. The defines in this file may + alternately be defined on the command line. */ + +#include "nx_user.h" +#endif + + +/* Default to little endian, since this is what most ARM targets are. */ + +#define NX_LITTLE_ENDIAN 1 + + +/* By default IPv6 is enabled. */ + +#ifndef FEATURE_NX_IPV6 +#define FEATURE_NX_IPV6 +#endif /* FEATURE_NX_IPV6 */ + +#ifdef NX_DISABLE_IPV6 +#undef FEATURE_NX_IPV6 +#endif /* !NX_DISABLE_IPV6 */ + +#include +#include +#include + + +/* Define various constants for the port. */ + +#ifndef NX_IP_PERIODIC_RATE +#define NX_IP_PERIODIC_RATE 100 /* Default IP periodic rate of 1 second for + ports with 10ms timer interrupts. This + value may be defined instead at the + command line and this value will not be + used. */ +#endif + + +/* Define macros that swap the endian for little endian ports. */ +#ifdef NX_LITTLE_ENDIAN +#define NX_CHANGE_ULONG_ENDIAN(arg) (arg) = __builtin_bswap32(arg) +#define NX_CHANGE_USHORT_ENDIAN(arg) (arg) = __builtin_bswap16(arg) + + +#ifndef htonl +#define htonl(val) __builtin_bswap32(val) +#endif /* htonl */ +#ifndef ntohl +#define ntohl(val) __builtin_bswap32(val) +#endif /* htonl */ + +#ifndef htons +#define htons(val) __builtin_bswap16(val) +#endif /*htons */ + +#ifndef ntohs +#define ntohs(val) __builtin_bswap16(val) +#endif /*htons */ + + +#else +#define NX_CHANGE_ULONG_ENDIAN(a) +#define NX_CHANGE_USHORT_ENDIAN(a) + +#ifndef htons +#define htons(val) (val) +#endif /* htons */ + +#ifndef ntohs +#define ntohs(val) (val) +#endif /* ntohs */ + +#ifndef ntohl +#define ntohl(val) (val) +#endif + +#ifndef htonl +#define htonl(val) (val) +#endif /* htonl */ +#endif + + +/* Define several macros for the error checking shell in NetX. */ + +#ifndef TX_TIMER_PROCESS_IN_ISR + +#define NX_CALLER_CHECKING_EXTERNS extern TX_THREAD *_tx_thread_current_ptr; \ + extern TX_THREAD _tx_timer_thread; \ + extern volatile ULONG _tx_thread_system_state; + +#define NX_THREADS_ONLY_CALLER_CHECKING if ((_tx_thread_system_state) || \ + (_tx_thread_current_ptr == TX_NULL) || \ + (_tx_thread_current_ptr == &_tx_timer_thread)) \ + return(NX_CALLER_ERROR); + +#define NX_INIT_AND_THREADS_CALLER_CHECKING if (((_tx_thread_system_state) && (_tx_thread_system_state < ((ULONG) 0xF0F0F0F0))) || \ + (_tx_thread_current_ptr == &_tx_timer_thread)) \ + return(NX_CALLER_ERROR); + + +#define NX_NOT_ISR_CALLER_CHECKING if ((_tx_thread_system_state) && (_tx_thread_system_state < ((ULONG) 0xF0F0F0F0))) \ + return(NX_CALLER_ERROR); + +#define NX_THREAD_WAIT_CALLER_CHECKING if ((wait_option) && \ + ((_tx_thread_current_ptr == NX_NULL) || (_tx_thread_system_state) || (_tx_thread_current_ptr == &_tx_timer_thread))) \ + return(NX_CALLER_ERROR); + + +#else + + + +#define NX_CALLER_CHECKING_EXTERNS extern TX_THREAD *_tx_thread_current_ptr; \ + extern volatile ULONG _tx_thread_system_state; + +#define NX_THREADS_ONLY_CALLER_CHECKING if ((_tx_thread_system_state) || \ + (_tx_thread_current_ptr == TX_NULL)) \ + return(NX_CALLER_ERROR); + +#define NX_INIT_AND_THREADS_CALLER_CHECKING if (((_tx_thread_system_state) && (_tx_thread_system_state < ((ULONG) 0xF0F0F0F0)))) \ + return(NX_CALLER_ERROR); + +#define NX_NOT_ISR_CALLER_CHECKING if ((_tx_thread_system_state) && (_tx_thread_system_state < ((ULONG) 0xF0F0F0F0))) \ + return(NX_CALLER_ERROR); + +#define NX_THREAD_WAIT_CALLER_CHECKING if ((wait_option) && \ + ((_tx_thread_current_ptr == NX_NULL) || (_tx_thread_system_state))) \ + return(NX_CALLER_ERROR); + +#endif + + +/* Define the version ID of NetX. This may be utilized by the application. */ + +#ifdef NX_SYSTEM_INIT +CHAR _nx_version_id[] = + "Copyright (c) Microsoft Corporation. All rights reserved. * NetX Cortex-M0/GNU Version 6.0 *"; +#else +extern CHAR _nx_version_id[]; +#endif + +#endif + diff --git a/ports/cortex_m3/gnu/CMakeLists.txt b/ports/cortex_m3/gnu/CMakeLists.txt new file mode 100644 index 0000000..62111b3 --- /dev/null +++ b/ports/cortex_m3/gnu/CMakeLists.txt @@ -0,0 +1,9 @@ +target_sources(${PROJECT_NAME} PRIVATE + # {{BEGIN_TARGET_SOURCES}} + + # {{END_TARGET_SOURCES}} +) + +target_include_directories(${PROJECT_NAME} PUBLIC + ${CMAKE_CURRENT_LIST_DIR}/inc +) \ No newline at end of file diff --git a/ports/cortex_m3/gnu/inc/nx_port.h b/ports/cortex_m3/gnu/inc/nx_port.h new file mode 100644 index 0000000..0e6b524 --- /dev/null +++ b/ports/cortex_m3/gnu/inc/nx_port.h @@ -0,0 +1,199 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Port Specific */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* PORT SPECIFIC C INFORMATION RELEASE */ +/* */ +/* nx_port.h Cortex-M3/GNU */ +/* 6.0 */ +/* */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file contains data type definitions that make the NetX */ +/* real-time TCP/IP function identically on a variety of different */ +/* processor architectures. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +#ifndef NX_PORT_H +#define NX_PORT_H + +/* Determine if the optional NetX user define file should be used. */ + +#ifdef NX_INCLUDE_USER_DEFINE_FILE + + +/* Yes, include the user defines in nx_user.h. The defines in this file may + alternately be defined on the command line. */ + +#include "nx_user.h" +#endif + + +/* Default to little endian, since this is what most ARM targets are. */ + +#define NX_LITTLE_ENDIAN 1 + + +/* By default IPv6 is enabled. */ + +#ifndef FEATURE_NX_IPV6 +#define FEATURE_NX_IPV6 +#endif /* FEATURE_NX_IPV6 */ + +#ifdef NX_DISABLE_IPV6 +#undef FEATURE_NX_IPV6 +#endif /* !NX_DISABLE_IPV6 */ + +#include +#include +#include + + +/* Define various constants for the port. */ + +#ifndef NX_IP_PERIODIC_RATE +#define NX_IP_PERIODIC_RATE 100 /* Default IP periodic rate of 1 second for + ports with 10ms timer interrupts. This + value may be defined instead at the + command line and this value will not be + used. */ +#endif + + +/* Define macros that swap the endian for little endian ports. */ +#ifdef NX_LITTLE_ENDIAN +#define NX_CHANGE_ULONG_ENDIAN(arg) (arg) = __builtin_bswap32(arg) +#define NX_CHANGE_USHORT_ENDIAN(arg) (arg) = __builtin_bswap16(arg) + + +#ifndef htonl +#define htonl(val) __builtin_bswap32(val) +#endif /* htonl */ +#ifndef ntohl +#define ntohl(val) __builtin_bswap32(val) +#endif /* htonl */ + +#ifndef htons +#define htons(val) __builtin_bswap16(val) +#endif /*htons */ + +#ifndef ntohs +#define ntohs(val) __builtin_bswap16(val) +#endif /*htons */ + + +#else +#define NX_CHANGE_ULONG_ENDIAN(a) +#define NX_CHANGE_USHORT_ENDIAN(a) + +#ifndef htons +#define htons(val) (val) +#endif /* htons */ + +#ifndef ntohs +#define ntohs(val) (val) +#endif /* ntohs */ + +#ifndef ntohl +#define ntohl(val) (val) +#endif + +#ifndef htonl +#define htonl(val) (val) +#endif /* htonl */ +#endif + + +/* Define several macros for the error checking shell in NetX. */ + +#ifndef TX_TIMER_PROCESS_IN_ISR + +#define NX_CALLER_CHECKING_EXTERNS extern TX_THREAD *_tx_thread_current_ptr; \ + extern TX_THREAD _tx_timer_thread; \ + extern volatile ULONG _tx_thread_system_state; + +#define NX_THREADS_ONLY_CALLER_CHECKING if ((_tx_thread_system_state) || \ + (_tx_thread_current_ptr == TX_NULL) || \ + (_tx_thread_current_ptr == &_tx_timer_thread)) \ + return(NX_CALLER_ERROR); + +#define NX_INIT_AND_THREADS_CALLER_CHECKING if (((_tx_thread_system_state) && (_tx_thread_system_state < ((ULONG) 0xF0F0F0F0))) || \ + (_tx_thread_current_ptr == &_tx_timer_thread)) \ + return(NX_CALLER_ERROR); + + +#define NX_NOT_ISR_CALLER_CHECKING if ((_tx_thread_system_state) && (_tx_thread_system_state < ((ULONG) 0xF0F0F0F0))) \ + return(NX_CALLER_ERROR); + +#define NX_THREAD_WAIT_CALLER_CHECKING if ((wait_option) && \ + ((_tx_thread_current_ptr == NX_NULL) || (_tx_thread_system_state) || (_tx_thread_current_ptr == &_tx_timer_thread))) \ + return(NX_CALLER_ERROR); + + +#else + + + +#define NX_CALLER_CHECKING_EXTERNS extern TX_THREAD *_tx_thread_current_ptr; \ + extern volatile ULONG _tx_thread_system_state; + +#define NX_THREADS_ONLY_CALLER_CHECKING if ((_tx_thread_system_state) || \ + (_tx_thread_current_ptr == TX_NULL)) \ + return(NX_CALLER_ERROR); + +#define NX_INIT_AND_THREADS_CALLER_CHECKING if (((_tx_thread_system_state) && (_tx_thread_system_state < ((ULONG) 0xF0F0F0F0)))) \ + return(NX_CALLER_ERROR); + +#define NX_NOT_ISR_CALLER_CHECKING if ((_tx_thread_system_state) && (_tx_thread_system_state < ((ULONG) 0xF0F0F0F0))) \ + return(NX_CALLER_ERROR); + +#define NX_THREAD_WAIT_CALLER_CHECKING if ((wait_option) && \ + ((_tx_thread_current_ptr == NX_NULL) || (_tx_thread_system_state))) \ + return(NX_CALLER_ERROR); + +#endif + + +/* Define the version ID of NetX. This may be utilized by the application. */ + +#ifdef NX_SYSTEM_INIT +CHAR _nx_version_id[] = + "Copyright (c) Microsoft Corporation. All rights reserved. * NetX Cortex-M3/GNU Version 6.0 *"; +#else +extern CHAR _nx_version_id[]; +#endif + +#endif + diff --git a/ports/cortex_m4/gnu/CMakeLists.txt b/ports/cortex_m4/gnu/CMakeLists.txt new file mode 100644 index 0000000..62111b3 --- /dev/null +++ b/ports/cortex_m4/gnu/CMakeLists.txt @@ -0,0 +1,9 @@ +target_sources(${PROJECT_NAME} PRIVATE + # {{BEGIN_TARGET_SOURCES}} + + # {{END_TARGET_SOURCES}} +) + +target_include_directories(${PROJECT_NAME} PUBLIC + ${CMAKE_CURRENT_LIST_DIR}/inc +) \ No newline at end of file diff --git a/ports/cortex_m4/gnu/inc/nx_port.h b/ports/cortex_m4/gnu/inc/nx_port.h new file mode 100644 index 0000000..0a6493b --- /dev/null +++ b/ports/cortex_m4/gnu/inc/nx_port.h @@ -0,0 +1,199 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Port Specific */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* PORT SPECIFIC C INFORMATION RELEASE */ +/* */ +/* nx_port.h Cortex-M4/GNU */ +/* 6.0 */ +/* */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file contains data type definitions that make the NetX */ +/* real-time TCP/IP function identically on a variety of different */ +/* processor architectures. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +#ifndef NX_PORT_H +#define NX_PORT_H + +/* Determine if the optional NetX user define file should be used. */ + +#ifdef NX_INCLUDE_USER_DEFINE_FILE + + +/* Yes, include the user defines in nx_user.h. The defines in this file may + alternately be defined on the command line. */ + +#include "nx_user.h" +#endif + + +/* Default to little endian, since this is what most ARM targets are. */ + +#define NX_LITTLE_ENDIAN 1 + + +/* By default IPv6 is enabled. */ + +#ifndef FEATURE_NX_IPV6 +#define FEATURE_NX_IPV6 +#endif /* FEATURE_NX_IPV6 */ + +#ifdef NX_DISABLE_IPV6 +#undef FEATURE_NX_IPV6 +#endif /* !NX_DISABLE_IPV6 */ + +#include +#include +#include + + +/* Define various constants for the port. */ + +#ifndef NX_IP_PERIODIC_RATE +#define NX_IP_PERIODIC_RATE 100 /* Default IP periodic rate of 1 second for + ports with 10ms timer interrupts. This + value may be defined instead at the + command line and this value will not be + used. */ +#endif + + +/* Define macros that swap the endian for little endian ports. */ +#ifdef NX_LITTLE_ENDIAN +#define NX_CHANGE_ULONG_ENDIAN(arg) (arg) = __builtin_bswap32(arg) +#define NX_CHANGE_USHORT_ENDIAN(arg) (arg) = __builtin_bswap16(arg) + + +#ifndef htonl +#define htonl(val) __builtin_bswap32(val) +#endif /* htonl */ +#ifndef ntohl +#define ntohl(val) __builtin_bswap32(val) +#endif /* htonl */ + +#ifndef htons +#define htons(val) __builtin_bswap16(val) +#endif /*htons */ + +#ifndef ntohs +#define ntohs(val) __builtin_bswap16(val) +#endif /*htons */ + + +#else +#define NX_CHANGE_ULONG_ENDIAN(a) +#define NX_CHANGE_USHORT_ENDIAN(a) + +#ifndef htons +#define htons(val) (val) +#endif /* htons */ + +#ifndef ntohs +#define ntohs(val) (val) +#endif /* ntohs */ + +#ifndef ntohl +#define ntohl(val) (val) +#endif + +#ifndef htonl +#define htonl(val) (val) +#endif /* htonl */ +#endif + + +/* Define several macros for the error checking shell in NetX. */ + +#ifndef TX_TIMER_PROCESS_IN_ISR + +#define NX_CALLER_CHECKING_EXTERNS extern TX_THREAD *_tx_thread_current_ptr; \ + extern TX_THREAD _tx_timer_thread; \ + extern volatile ULONG _tx_thread_system_state; + +#define NX_THREADS_ONLY_CALLER_CHECKING if ((_tx_thread_system_state) || \ + (_tx_thread_current_ptr == TX_NULL) || \ + (_tx_thread_current_ptr == &_tx_timer_thread)) \ + return(NX_CALLER_ERROR); + +#define NX_INIT_AND_THREADS_CALLER_CHECKING if (((_tx_thread_system_state) && (_tx_thread_system_state < ((ULONG) 0xF0F0F0F0))) || \ + (_tx_thread_current_ptr == &_tx_timer_thread)) \ + return(NX_CALLER_ERROR); + + +#define NX_NOT_ISR_CALLER_CHECKING if ((_tx_thread_system_state) && (_tx_thread_system_state < ((ULONG) 0xF0F0F0F0))) \ + return(NX_CALLER_ERROR); + +#define NX_THREAD_WAIT_CALLER_CHECKING if ((wait_option) && \ + ((_tx_thread_current_ptr == NX_NULL) || (_tx_thread_system_state) || (_tx_thread_current_ptr == &_tx_timer_thread))) \ + return(NX_CALLER_ERROR); + + +#else + + + +#define NX_CALLER_CHECKING_EXTERNS extern TX_THREAD *_tx_thread_current_ptr; \ + extern volatile ULONG _tx_thread_system_state; + +#define NX_THREADS_ONLY_CALLER_CHECKING if ((_tx_thread_system_state) || \ + (_tx_thread_current_ptr == TX_NULL)) \ + return(NX_CALLER_ERROR); + +#define NX_INIT_AND_THREADS_CALLER_CHECKING if (((_tx_thread_system_state) && (_tx_thread_system_state < ((ULONG) 0xF0F0F0F0)))) \ + return(NX_CALLER_ERROR); + +#define NX_NOT_ISR_CALLER_CHECKING if ((_tx_thread_system_state) && (_tx_thread_system_state < ((ULONG) 0xF0F0F0F0))) \ + return(NX_CALLER_ERROR); + +#define NX_THREAD_WAIT_CALLER_CHECKING if ((wait_option) && \ + ((_tx_thread_current_ptr == NX_NULL) || (_tx_thread_system_state))) \ + return(NX_CALLER_ERROR); + +#endif + + +/* Define the version ID of NetX. This may be utilized by the application. */ + +#ifdef NX_SYSTEM_INIT +CHAR _nx_version_id[] = + "Copyright (c) Microsoft Corporation. All rights reserved. * NetX Cortex-M4/GNU Version 6.0 *"; +#else +extern CHAR _nx_version_id[]; +#endif + +#endif + diff --git a/ports/cortex_m7/gnu/CMakeLists.txt b/ports/cortex_m7/gnu/CMakeLists.txt new file mode 100644 index 0000000..62111b3 --- /dev/null +++ b/ports/cortex_m7/gnu/CMakeLists.txt @@ -0,0 +1,9 @@ +target_sources(${PROJECT_NAME} PRIVATE + # {{BEGIN_TARGET_SOURCES}} + + # {{END_TARGET_SOURCES}} +) + +target_include_directories(${PROJECT_NAME} PUBLIC + ${CMAKE_CURRENT_LIST_DIR}/inc +) \ No newline at end of file diff --git a/ports/cortex_m7/gnu/inc/nx_port.h b/ports/cortex_m7/gnu/inc/nx_port.h new file mode 100644 index 0000000..965a777 --- /dev/null +++ b/ports/cortex_m7/gnu/inc/nx_port.h @@ -0,0 +1,199 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Port Specific */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* PORT SPECIFIC C INFORMATION RELEASE */ +/* */ +/* nx_port.h Cortex-M7/GNU */ +/* 6.0 */ +/* */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file contains data type definitions that make the NetX */ +/* real-time TCP/IP function identically on a variety of different */ +/* processor architectures. */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +#ifndef NX_PORT_H +#define NX_PORT_H + +/* Determine if the optional NetX user define file should be used. */ + +#ifdef NX_INCLUDE_USER_DEFINE_FILE + + +/* Yes, include the user defines in nx_user.h. The defines in this file may + alternately be defined on the command line. */ + +#include "nx_user.h" +#endif + + +/* Default to little endian, since this is what most ARM targets are. */ + +#define NX_LITTLE_ENDIAN 1 + + +/* By default IPv6 is enabled. */ + +#ifndef FEATURE_NX_IPV6 +#define FEATURE_NX_IPV6 +#endif /* FEATURE_NX_IPV6 */ + +#ifdef NX_DISABLE_IPV6 +#undef FEATURE_NX_IPV6 +#endif /* !NX_DISABLE_IPV6 */ + +#include +#include +#include + + +/* Define various constants for the port. */ + +#ifndef NX_IP_PERIODIC_RATE +#define NX_IP_PERIODIC_RATE 100 /* Default IP periodic rate of 1 second for + ports with 10ms timer interrupts. This + value may be defined instead at the + command line and this value will not be + used. */ +#endif + + +/* Define macros that swap the endian for little endian ports. */ +#ifdef NX_LITTLE_ENDIAN +#define NX_CHANGE_ULONG_ENDIAN(arg) (arg) = __builtin_bswap32(arg) +#define NX_CHANGE_USHORT_ENDIAN(arg) (arg) = __builtin_bswap16(arg) + + +#ifndef htonl +#define htonl(val) __builtin_bswap32(val) +#endif /* htonl */ +#ifndef ntohl +#define ntohl(val) __builtin_bswap32(val) +#endif /* htonl */ + +#ifndef htons +#define htons(val) __builtin_bswap16(val) +#endif /*htons */ + +#ifndef ntohs +#define ntohs(val) __builtin_bswap16(val) +#endif /*htons */ + + +#else +#define NX_CHANGE_ULONG_ENDIAN(a) +#define NX_CHANGE_USHORT_ENDIAN(a) + +#ifndef htons +#define htons(val) (val) +#endif /* htons */ + +#ifndef ntohs +#define ntohs(val) (val) +#endif /* ntohs */ + +#ifndef ntohl +#define ntohl(val) (val) +#endif + +#ifndef htonl +#define htonl(val) (val) +#endif /* htonl */ +#endif + + +/* Define several macros for the error checking shell in NetX. */ + +#ifndef TX_TIMER_PROCESS_IN_ISR + +#define NX_CALLER_CHECKING_EXTERNS extern TX_THREAD *_tx_thread_current_ptr; \ + extern TX_THREAD _tx_timer_thread; \ + extern volatile ULONG _tx_thread_system_state; + +#define NX_THREADS_ONLY_CALLER_CHECKING if ((_tx_thread_system_state) || \ + (_tx_thread_current_ptr == TX_NULL) || \ + (_tx_thread_current_ptr == &_tx_timer_thread)) \ + return(NX_CALLER_ERROR); + +#define NX_INIT_AND_THREADS_CALLER_CHECKING if (((_tx_thread_system_state) && (_tx_thread_system_state < ((ULONG) 0xF0F0F0F0))) || \ + (_tx_thread_current_ptr == &_tx_timer_thread)) \ + return(NX_CALLER_ERROR); + + +#define NX_NOT_ISR_CALLER_CHECKING if ((_tx_thread_system_state) && (_tx_thread_system_state < ((ULONG) 0xF0F0F0F0))) \ + return(NX_CALLER_ERROR); + +#define NX_THREAD_WAIT_CALLER_CHECKING if ((wait_option) && \ + ((_tx_thread_current_ptr == NX_NULL) || (_tx_thread_system_state) || (_tx_thread_current_ptr == &_tx_timer_thread))) \ + return(NX_CALLER_ERROR); + + +#else + + + +#define NX_CALLER_CHECKING_EXTERNS extern TX_THREAD *_tx_thread_current_ptr; \ + extern volatile ULONG _tx_thread_system_state; + +#define NX_THREADS_ONLY_CALLER_CHECKING if ((_tx_thread_system_state) || \ + (_tx_thread_current_ptr == TX_NULL)) \ + return(NX_CALLER_ERROR); + +#define NX_INIT_AND_THREADS_CALLER_CHECKING if (((_tx_thread_system_state) && (_tx_thread_system_state < ((ULONG) 0xF0F0F0F0)))) \ + return(NX_CALLER_ERROR); + +#define NX_NOT_ISR_CALLER_CHECKING if ((_tx_thread_system_state) && (_tx_thread_system_state < ((ULONG) 0xF0F0F0F0))) \ + return(NX_CALLER_ERROR); + +#define NX_THREAD_WAIT_CALLER_CHECKING if ((wait_option) && \ + ((_tx_thread_current_ptr == NX_NULL) || (_tx_thread_system_state))) \ + return(NX_CALLER_ERROR); + +#endif + + +/* Define the version ID of NetX. This may be utilized by the application. */ + +#ifdef NX_SYSTEM_INIT +CHAR _nx_version_id[] = + "Copyright (c) Microsoft Corporation. All rights reserved. * NetX Cortex-M7/GNU Version 6.0 *"; +#else +extern CHAR _nx_version_id[]; +#endif + +#endif + diff --git a/protocol_handlers/AUTO_IP/nx_auto_ip.c b/protocol_handlers/AUTO_IP/nx_auto_ip.c new file mode 100644 index 0000000..db2d04b --- /dev/null +++ b/protocol_handlers/AUTO_IP/nx_auto_ip.c @@ -0,0 +1,1221 @@ +/**************************************************************************/ +/* */ +/* 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" +#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); +} diff --git a/protocol_handlers/AUTO_IP/nx_auto_ip.h b/protocol_handlers/AUTO_IP/nx_auto_ip.h new file mode 100644 index 0000000..e5de5ea --- /dev/null +++ b/protocol_handlers/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/protocol_handlers/BSD/bsd_demo_tcp.c b/protocol_handlers/BSD/bsd_demo_tcp.c new file mode 100644 index 0000000..710b3c7 --- /dev/null +++ b/protocol_handlers/BSD/bsd_demo_tcp.c @@ -0,0 +1,440 @@ +/* This is a small demo of BSD Wrapper for the high-performance NetX TCP/IP stack. + This demo used standard BSD services for TCP connection, disconnection, sending, and + receiving using a simulated Ethernet driver. */ + + +#include "tx_api.h" +#include "nx_api.h" +#include "nx_bsd.h" +#include +#include + +#define DEMO_STACK_SIZE (16*1024) +#define SERVER_PORT 87 +#define CLIENT_PORT 77 +#define SERVER_RCV_BUFFER_SIZE 100 + + +/* Define the ThreadX and NetX object control blocks... */ + +TX_THREAD thread_server; +TX_THREAD thread_client; +NX_PACKET_POOL bsd_pool; +NX_IP bsd_ip; + +/* Define some global data. */ +INT maxfd; + +/* Define the counters used in the demo application... */ + +ULONG error_counter; + +/* Define fd_sets for the BSD server socket. */ +fd_set master_list, read_ready; + + + +/* Define thread prototypes. */ + +VOID thread_server_entry(ULONG thread_input); +VOID thread_client_entry(ULONG thread_input); +void _nx_ram_network_driver(struct NX_IP_DRIVER_STRUCT *driver_req); + + +/* Define main entry point. */ + +int main() +{ + + /* Enter the ThreadX kernel. */ + tx_kernel_enter(); +} + +/* Define what the initial system looks like. */ + +void tx_application_define(void *first_unused_memory) +{ +CHAR *pointer; +UINT status; + + + /* Setup the working pointer. */ + pointer = (CHAR *) first_unused_memory; + + /* Create a server thread. */ + tx_thread_create(&thread_server, "Server", thread_server_entry, 0, + pointer, DEMO_STACK_SIZE, 8, 8, TX_NO_TIME_SLICE, TX_AUTO_START); + + pointer = pointer + DEMO_STACK_SIZE; + + /* Create a Client thread. */ + tx_thread_create(&thread_client, "Client", thread_client_entry, 0, + pointer, DEMO_STACK_SIZE, 16, 16, TX_NO_TIME_SLICE, TX_AUTO_START); + + pointer = pointer + DEMO_STACK_SIZE; + + + /* Initialize the NetX system. */ + nx_system_initialize(); + + /* Create a BSD packet pool. */ + status = nx_packet_pool_create(&bsd_pool, "NetX BSD Packet Pool", 128, pointer, 16384); + pointer = pointer + 16384; + if (status) + { + error_counter++; + printf("Error in creating BSD packet pool\n!"); + } + + /* Create an IP instance for BSD. */ + status = nx_ip_create(&bsd_ip, "BSD IP Instance", IP_ADDRESS(1,2,3,4), 0xFFFFFF00UL, &bsd_pool, _nx_ram_network_driver, + pointer, 2048, 1); + pointer = pointer + 2048; + + if (status) + { + error_counter++; + printf("Error creating BSD IP instance\n!"); + } + + /* Enable ARP and supply ARP cache memory for BSD IP Instance */ + status = nx_arp_enable(&bsd_ip, (void *) pointer, 1024); + pointer = pointer + 1024; + + /* Check ARP enable status. */ + if (status) + { + error_counter++; + printf("Error in Enable ARP and supply ARP cache memory to BSD IP instance\n"); + } + + /* Enable TCP processing for BSD IP instances. */ + + status = nx_tcp_enable(&bsd_ip); + + /* Check TCP enable status. */ + if (status) + { + error_counter++; + printf("Error in Enable TCP \n"); + } + + /* Now initialize BSD Scoket Wrapper */ + status = (UINT)bsd_initialize (&bsd_ip, &bsd_pool,pointer, 2048, 2); +} + + +/* Define the Server thread. */ +CHAR Server_Rcv_Buffer[SERVER_RCV_BUFFER_SIZE]; + +VOID thread_server_entry(ULONG thread_input) +{ + + +INT status, sock, sock_tcp_server; +ULONG actual_status; +INT Clientlen; +INT i; +INT is_set = 0; +struct sockaddr_in serverAddr; +struct sockaddr_in ClientAddr; + + NX_PARAMETER_NOT_USED(thread_input); + + status = (INT)nx_ip_status_check(&bsd_ip, NX_IP_INITIALIZE_DONE, &actual_status, NX_IP_PERIODIC_RATE); + + /* Check status... */ + if (status != NX_SUCCESS) + { + return; + } + + + /* Create BSD TCP Socket */ + sock_tcp_server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + + if (sock_tcp_server == -1) + { + printf("\nError: BSD TCP Server socket create \n"); + return; + } + + printf("\nBSD TCP Server socket created %lu \n", (ULONG)sock_tcp_server); + + /* Set the server port and IP address */ + memset(&serverAddr, 0, sizeof(serverAddr)); + serverAddr.sin_family = AF_INET; + serverAddr.sin_addr.s_addr = htonl(IP_ADDRESS(1,2,3,4)); + serverAddr.sin_port = htons(SERVER_PORT); + + /* Bind this server socket */ + status = bind (sock_tcp_server, (struct sockaddr *) &serverAddr, sizeof(serverAddr)); + + if (status < 0) + { + printf("Error: Server Socket Bind \n"); + return; + } + + FD_ZERO(&master_list); + FD_ZERO(&read_ready); + FD_SET(sock_tcp_server,&master_list); + maxfd = sock_tcp_server; + + /* Now listen for any client connections for this server socket */ + status = listen (sock_tcp_server, 5); + if (status < 0) + { + printf("Error: Server Socket Listen\n"); + return; + } + else + printf("Server Listen complete\n"); + + /* All set to accept client connections */ + printf("Now accepting client connections\n"); + + /* Loop to create and establish server connections. */ + while(1) + { + + printf("\n"); + + read_ready = master_list; + + tx_thread_sleep(20); /* Allow some time to other threads too */ + + /* Let the underlying TCP stack determine the timeout. */ + status = select(maxfd + 1, &read_ready, 0, 0, 0); + + if ( (status == ERROR) || (status == 0) ) + { + + printf("Error with select? Status 0x%x. Try again\n", status); + + continue; + } + + /* Detected a connection request. */ + is_set = FD_ISSET(sock_tcp_server,&read_ready); + + if(is_set) + { + + Clientlen = sizeof(ClientAddr); + + sock = accept(sock_tcp_server,(struct sockaddr*)&ClientAddr, &Clientlen); + + /* Add this new connection to our master list */ + FD_SET(sock, &master_list); + + if ( sock > maxfd) + { + printf("New connection %d\n", sock); + + maxfd = sock; + } + + continue; + } + + /* Check the set of 'ready' sockets, e.g connected to remote host and waiting for + notice of packets received. */ + for (i = 0; i < (maxfd+1); i++) + { + + if (((i+ NX_BSD_SOCKFD_START) != sock_tcp_server) && + (FD_ISSET(i + NX_BSD_SOCKFD_START, &master_list)) && + (FD_ISSET(i + NX_BSD_SOCKFD_START, &read_ready))) + { + + while(1) + { + + status = recv(i + NX_BSD_SOCKFD_START, (VOID *)Server_Rcv_Buffer, SERVER_RCV_BUFFER_SIZE, 0); + + if (status == ERROR) + { + /* This is a blocking socket. If no data is received, but the connection is still good, + the EAGAIN error is set. If it was a non blocking socket, the EWOULDBLOCK socket + error is set. */ + if (errno == EAGAIN) + { + printf("No error received. Try again later\n"); + continue; + } + else if (errno == ENOTCONN) + { + /* If the socket connection is terminated, the socket error will be ENOTCONN. */ + printf("Connection is broken. Close the socket.\n"); + break; + } + else + { + /* Another error has occurred...probably an internal error of some kind + so best to terminate the connection. */ + printf("Error on Client Socket %d receiving data: 0x%x \n", i, errno); + break; + } + } + /* recv returns with message. Make sure Server_Rcv_Buffer is NULL-terminated. */ + if(status == SERVER_RCV_BUFFER_SIZE) + status--; + Server_Rcv_Buffer[status] = 0; + + printf("Server socket received from Client on socket %d %lu bytes: %s\n ", + i+ NX_BSD_SOCKFD_START, (ULONG)status, Server_Rcv_Buffer); + + + status = send(i + NX_BSD_SOCKFD_START, "Hello\n", sizeof("Hello\n"), 0); + + if (status == ERROR) + { + printf("Error on Server sending to Client on socket %d\n", i+ NX_BSD_SOCKFD_START); + } + else + { + printf("Server socket message sent to Client on socket %d: Hello\n", i+ NX_BSD_SOCKFD_START); + } + } + + /* Close this socket */ + status = soc_close(i+ NX_BSD_SOCKFD_START); + + if (status != ERROR) + { + printf("Socket closing socket connected to Client on %d \n", i+ NX_BSD_SOCKFD_START); + } + else + { + + printf("Error on Server closing socket %d connected to Client \n", i+ NX_BSD_SOCKFD_START); + } + } + } + + /* Loop back to check any next client connection */ + } +} + +CHAR Client_Rcv_Buffer[100]; + +VOID thread_client_entry(ULONG thread_input) +{ + + +INT status; +ULONG actual_status; +INT sock_tcp_client, length; +struct sockaddr_in echoServAddr; /* Echo server address */ +struct sockaddr_in localAddr; /* Local address */ +struct sockaddr_in remoteAddr; /* Remote address */ + + NX_PARAMETER_NOT_USED(thread_input); + + status = (INT)nx_ip_status_check(&bsd_ip, NX_IP_INITIALIZE_DONE, &actual_status, NX_IP_PERIODIC_RATE); + + /* Check status... */ + if (status != NX_SUCCESS) + { + return; + } + + memset(&localAddr, 0, sizeof(localAddr)); + localAddr.sin_family = AF_INET; + localAddr.sin_addr.s_addr = htonl(IP_ADDRESS(1,2,3,4)); + localAddr.sin_port = htons(CLIENT_PORT); + + memset(&echoServAddr, 0, sizeof(echoServAddr)); + echoServAddr.sin_family = AF_INET; + echoServAddr.sin_addr.s_addr = htonl(IP_ADDRESS(1,2,3,4)); + echoServAddr.sin_port = htons(SERVER_PORT); + + /* Now make client connections with the server. */ + while (1) + { + + printf("\n"); + /* Create BSD TCP Socket */ + sock_tcp_client = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP); + + if (sock_tcp_client == -1) + { + printf("Error: BSD TCP Client socket create \n"); + return; + } + + printf("Client socket created %lu \n", (ULONG)sock_tcp_client); + + /* Now connect this client to the server */ + status = connect(sock_tcp_client, (struct sockaddr *)&echoServAddr, sizeof(echoServAddr)); + + /* Check for error. */ + if (status != OK) + { + printf("\nError: BSD TCP Client socket Connect\n"); + status = soc_close(sock_tcp_client); + return; + + } + /* Get and print source and destination information */ + printf("Client socket %d connected \n", sock_tcp_client); + + length = sizeof(struct sockaddr_in); + status = getsockname(sock_tcp_client, (struct sockaddr *)&localAddr, &length); + printf("Client port = %lu , Client = 0x%x,", (ULONG)localAddr.sin_port, (UINT)localAddr.sin_addr.s_addr); + length = sizeof(struct sockaddr_in); + status = getpeername( sock_tcp_client, (struct sockaddr *) &remoteAddr, &length); + printf("Remote port = %lu, Remote IP = 0x%x \n", (ULONG)remoteAddr.sin_port, (UINT)remoteAddr.sin_addr.s_addr); + + /* Now receive the echoed packet from the server */ + while(1) + { + + printf("Client sock %d sending packet to server\n", sock_tcp_client); + + status = send(sock_tcp_client, "Hello", (sizeof("Hello")), 0); + + if (status == ERROR) + { + printf("Error: Client Socket (%d) send \n", sock_tcp_client); + } + else + { + printf("Client socket %d sent message Hello\n", sock_tcp_client); + } + + status = recv(sock_tcp_client, (VOID *)Client_Rcv_Buffer, 100, 0); + + if (status < 0) + { + + printf("Connection terminated or error on receiving data on socket %d \n", sock_tcp_client); + + break; + } + else + { + printf("Client socket %d received %d bytes and this message: %s\n", sock_tcp_client, status, Client_Rcv_Buffer); + } + + } + + /* close this client socket */ + status = soc_close(sock_tcp_client); + + if (status != ERROR) + { + printf("Client Socket %d closed\n", sock_tcp_client); + } + else + { + printf("Error: Client Socket %d on close \n", sock_tcp_client); + } + + /* Make another Client connection...*/ + + } +} + + diff --git a/protocol_handlers/BSD/bsd_demo_udp.c b/protocol_handlers/BSD/bsd_demo_udp.c new file mode 100644 index 0000000..c8827af --- /dev/null +++ b/protocol_handlers/BSD/bsd_demo_udp.c @@ -0,0 +1,293 @@ +/* This is a small demo of the high-performance NetX TCP/IP stack. This demo concentrates + on UDP packet sending and receiving - with ARP - using a simulated Ethernet driver. */ +/* This demo works for IPv4 only */ + +#include "tx_api.h" +#include "nx_api.h" +#include "nx_bsd.h" +#include +#include + +#define DEMO_STACK_SIZE 2048 +#define SERVER_PORT 721 + +/* Message sent to the server */ +#define CLIENT_MESSAGE "Client BSD UDP Socket testing\n" + + +/* Define the ThreadX and NetX object control blocks... */ + +TX_THREAD thread_server; +TX_THREAD thread_client; +NX_PACKET_POOL bsd_pool; +NX_IP bsd_ip; + + +/* Define the counters used in the demo application... */ + +ULONG thread_0_counter; +ULONG thread_2_counter; +ULONG error_counter; + +/* Define thread prototypes. */ + +VOID thread_server_entry(ULONG thread_input); +VOID thread_client_entry(ULONG thread_input); +VOID _nx_ram_network_driver(struct NX_IP_DRIVER_STRUCT *driver_req); + + +/* Define main entry point. */ + +int main() +{ + + /* Enter the ThreadX kernel. */ + tx_kernel_enter(); +} + +/* Define what the initial system looks like. */ + +void tx_application_define(void *first_unused_memory) +{ + +CHAR *pointer; +UINT status; + + + /* Setup the working pointer. */ + pointer = (CHAR *) first_unused_memory; + + /* Create a thread for the Server */ + tx_thread_create(&thread_server, "Server", thread_server_entry, 0, + pointer, DEMO_STACK_SIZE, + 8, 8, TX_NO_TIME_SLICE, TX_AUTO_START); + + pointer = pointer + DEMO_STACK_SIZE; + + /* Create a thread for client. */ + tx_thread_create(&thread_client, "Client", thread_client_entry, 0, + pointer, DEMO_STACK_SIZE, + 16, 16, TX_NO_TIME_SLICE, TX_AUTO_START); + + pointer = pointer + DEMO_STACK_SIZE; + + /* Initialize the NetX system. */ + nx_system_initialize(); + + /* Create a BSD packet pool. */ + status = nx_packet_pool_create(&bsd_pool, "NetX BSD Packet Pool", 128, pointer, 16384); + + pointer = pointer + 16384; + if (status) + { + error_counter++; + printf("Error in creating BSD packet pool\n!"); + } + + /* Create an IP instance for BSD. */ + status += nx_ip_create(&bsd_ip, "NetX IP Instance 2", IP_ADDRESS(1, 2, 3, 4), 0xFFFFFF00UL, + &bsd_pool, _nx_ram_network_driver, + pointer, DEMO_STACK_SIZE, 1); + + pointer = pointer + DEMO_STACK_SIZE; + + /* Check for any errors */ + if (status) + error_counter++; + + if (status) + printf("Error creating BSD IP instance\n!"); + + /* Enable ARP and supply ARP cache memory for BSD IP Instance */ + status += nx_arp_enable(&bsd_ip, (void *) pointer, 1024); + + pointer = pointer + 1024; + + /* Check ARP enable status. */ + if (status) + error_counter++; + + if (status) + printf("Error in Enable ARP and supply ARP cache memory to BSD IP instance\n"); + + /* Enable UDP traffic. */ + status = nx_udp_enable(&bsd_ip); + + /* Check for UDP enable errors. */ + if (status) + error_counter++; + + /* Now initialize BSD Socket Wrapper */ + status = (UINT)bsd_initialize (&bsd_ip, &bsd_pool, pointer, 2048, 2); + + if (status) + error_counter++; + +} + + +void thread_server_entry(ULONG thread_input) +{ + + /* Start the Server */ +INT status,addrlen1; +INT sock_udp_2; +struct sockaddr_in echoServAddr; /* Echo server address */ +struct sockaddr_in fromAddr; /* Cleint address */ +CHAR buffer[64]; + + NX_PARAMETER_NOT_USED(thread_input); + + /* Create a BSD UDP Server Socket */ + sock_udp_2 = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); + + /* Check for any errors */ + if (sock_udp_2 == -1) + { + printf("Error: BSD UDP Servert socket create\n"); + return; + } + + /* Fill ths socket with Server side information */ + memset(&echoServAddr, 0, sizeof(echoServAddr)); + echoServAddr.sin_family = PF_INET; + echoServAddr.sin_addr.s_addr = htonl(IP_ADDRESS(1,2,3,4)); + echoServAddr.sin_port = htons(SERVER_PORT); + + /* Bind the UDP socket to the IP port. */ + status = bind (sock_udp_2, (struct sockaddr *) &echoServAddr, sizeof(echoServAddr)); + if (status < 0) + { + printf("Error: BSD UDP Server Socket Bind\n"); + return; + } + + while(1) + { + + addrlen1 = sizeof(struct sockaddr_in); + + /* Receive a UDP packet from a client. */ + status = recvfrom(sock_udp_2,(VOID *)buffer, 64, 0,(struct sockaddr *) &fromAddr, &addrlen1); + + /* Check for any errors */ + if (status == ERROR) + printf("Error: BSD Server Socket receive\n"); + else + { + + /* Print client information */ + printf("Server received data from Client at IP address 0x%x at port %lu\n", + (UINT)fromAddr.sin_addr.s_addr, (ULONG)fromAddr.sin_port); + + /* Print the packet received from the client */ + printf("Server received from Client: %s\n", buffer); + + /* Now echo the recieved data string to the same client */ + status = sendto(sock_udp_2, buffer, (INT)(status + 1), 0, (struct sockaddr *) &fromAddr, sizeof(fromAddr)); + + /* Check for any errors */ + if (status == ERROR) + printf("Error:BSD Server Socket echo\n"); + } + + tx_thread_sleep(NX_IP_PERIODIC_RATE); + + /* All done , loop back to recieve next packet */ + } +} + +/* Define the Client thread. */ +void thread_client_entry(ULONG thread_input) +{ + +INT status,sock_udp_1; +INT addrlen; +struct sockaddr_in destAddr; /* Destination address */ +struct sockaddr_in ClientAddr; /* Client address */ +struct sockaddr_in fromAddr; /* Cleint address */ +CHAR echomsg[64]; /* Message echoed by the server */ + + NX_PARAMETER_NOT_USED(thread_input); + + /* Allow Server side to set up */ + tx_thread_sleep(10); + thread_2_counter =0; + + while(1) + { + + /* Create a BSD UDP Client Socket */ + sock_udp_1 = socket( PF_INET, SOCK_DGRAM, IPPROTO_UDP); + + /* Check for any errors */ + if (sock_udp_1 == ERROR) + { + printf("Error: BSD UDP Client socket create\n"); + return; + } + + /* Set up client side */ + memset(&ClientAddr, 0, sizeof(ClientAddr)); + ClientAddr.sin_family = PF_INET; + ClientAddr.sin_addr.s_addr = htonl(IP_ADDRESS(1,2,3,4)); + + /* Assign a known Server port */ + memset(&destAddr, 0, sizeof(destAddr)); + destAddr.sin_addr.s_addr = htonl(IP_ADDRESS(1,2,3,4)); + destAddr.sin_port = htons(SERVER_PORT); + destAddr.sin_family = PF_INET; + + /* Client socket is ready now start sending packets */ + printf("BSD Client Socket (%lu) sending test message: %s\n", (ULONG)sock_udp_1, CLIENT_MESSAGE); + + status = sendto(sock_udp_1, CLIENT_MESSAGE, (INT)(sizeof(CLIENT_MESSAGE)), 0, + (struct sockaddr *) &destAddr, sizeof(destAddr)); + + /* Check for any errors */ + if (status == ERROR) + { + + printf("Error: BSD Client Socket send\n"); + } + else + { + + addrlen = sizeof(struct sockaddr_in); + + /* Try to receive an echo from the server. */ + status = recvfrom(sock_udp_1,(VOID *)echomsg,64, 0, (struct sockaddr *) &fromAddr, &addrlen); + + /* * Check for any errors */ + if (status == ERROR) + { + + printf("Error: BSD Client Socket echo receive\n"); + } + else + { + + /* Print Server detials */ + printf("Client contacted Server at IP address 0x%x and port %lu\n", + (UINT)fromAddr.sin_addr.s_addr, (ULONG)fromAddr.sin_port); + + /* Print the received echo string from the server */ + printf("Client (%lu) received echo string: %s\n", (ULONG)sock_udp_1, echomsg); + } + } + + /* Done with this client socket */ + status = soc_close(sock_udp_1); + + /* Check for any errors */ + if (status == ERROR) + { + printf("Error: BSD Client Socket close\n"); + } + + /* Increment client transaction counter. */ + thread_2_counter++; + + tx_thread_sleep(NX_IP_PERIODIC_RATE); + } +} diff --git a/protocol_handlers/BSD/nx_bsd.c b/protocol_handlers/BSD/nx_bsd.c new file mode 100644 index 0000000..6d7cd39 --- /dev/null +++ b/protocol_handlers/BSD/nx_bsd.c @@ -0,0 +1,10807 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/* Include necessary files. */ +#include "nx_api.h" +#include "nx_packet.h" +#include "nx_tcp.h" +#include "nx_ip.h" + +#include "nx_bsd.h" + +#ifdef NX_BSD_ENABLE_DNS +#include "nx_dns.h" +#endif + + +#include "nx_udp.h" +#include "nx_igmp.h" +#include "nx_system.h" +#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]; + + +/* 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 and SOCK_DGRAM, + * 3 blocks for addrinfo) + 1 block for IP adddress = 4 blocks */ + +static UCHAR nx_bsd_addrinfo_pool_memory[NX_BSD_IPV4_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_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]; + +/* 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. */ + +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); +#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_send_internal(INT sockID, const CHAR *msg, INT msgLength, INT flags, + ULONG dst_address, USHORT dst_port, UINT local_interface_index); + + +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_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_TCP_FAST_TIMER_RATE - 1)) / NX_TCP_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; + + + NX_PARAMETER_NOT_USED(protocol); + + /* Check for a supported protocol family. */ + if (protocolFamily == AF_INET) + { + } + else +#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_tcp_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. */ + if (nx_bsd_default_ip -> nx_ip_tcp_fast_periodic_timer.tx_timer_id != TX_TIMER_ID) + { + _nx_tcp_enable(nx_bsd_default_ip); + } + + /* Replace timer expiration function entry. */ + nx_bsd_ip_fast_periodic_timer_entry = nx_bsd_default_ip -> nx_ip_tcp_fast_periodic_timer.tx_timer_internal.tx_timer_internal_timeout_function; + nx_bsd_default_ip -> nx_ip_tcp_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 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) + { + + + if(protocolFamily == AF_PACKET) + { +#if 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; + + /* 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 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 */ +/* 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 , a NULL remoteAddress dis-associate + a remote address bound to the socket. */ + if (bsd_socket_ptr -> nx_bsd_socket_protocol != NX_PROTOCOL_TCP) + { + bsd_socket_ptr -> nx_bsd_socket_peer_ip = 0; + 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)))) + { + + /* 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); + } + + /* 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 + 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 = 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 + + { + + /* 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. */ + + /* 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 = nx_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); + bsd_socket_ptr -> nx_bsd_socket_source_ip_address = 0; + 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)))) + { + 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; + + 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; + } + } + } + } +#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; + + /* 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 + { + +#ifdef NX_BSD_RAW_SUPPORT + if ((localAddress -> sa_family == AF_PACKET) && (addressLength == sizeof(struct sockaddr_ll))) + { + + /* Bind to link layer address is supported. */ + status = NX_SUCCESS; + } + else +#endif /* NX_BSD_RAW_SUPPORT */ + { + + /* Unsupported socket type. */ + /* Set the socket error. */ + set_errno(EINVAL); + + /* Return an error, unsuccessful socket bind call. */ + NX_BSD_ERROR(NX_SOC_ERROR, __LINE__); + + /* Release the protection mutex. */ + tx_mutex_put(nx_bsd_protection_ptr); + + return(NX_SOC_ERROR); + } + } + + + /* 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. */ + 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; +struct sockaddr_in peer4_address; + + + /* 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 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 = nx_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)); + + bsd_secondary_socket -> nx_bsd_socket_peer_ip = bsd_secondary_socket -> nx_bsd_socket_source_ip_address; + + bsd_secondary_socket -> nx_bsd_socket_peer_port = (USHORT)(bsd_secondary_socket -> nx_bsd_socket_source_port); + + /* Record the peer information. */ + if(bsd_socket_ptr -> nx_bsd_socket_family == AF_INET) + { + + bsd_secondary_socket -> nx_bsd_socket_source_ip_address = + bsd_secondary_socket -> nx_bsd_socket_tcp_socket -> nx_tcp_socket_connect_ip; + } + + /* Attempt to obtain peer address if ClientAddress is not NULL. */ + if(ClientAddress && addressLength != 0) + { + + /* 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); + 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 + + { + + /* 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 */ +/* 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, + ULONG 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]; + + /* 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_UDP_PACKET; + } + else if(bsd_socket_ptr -> nx_bsd_socket_protocol == NX_PROTOCOL_TCP) + { + + /* Allocate an IPv4 TCP packet. */ + packet_type = NX_TCP_PACKET; + } + else if(bsd_socket_ptr -> nx_bsd_socket_status_flags & NX_BSD_SOCKET_TX_HDR_INCLUDE) + { + + packet_type = NX_PHYSICAL_HEADER; + } + else + { + + /* Unsupported socket type. */ + packet_type = 0; + } + } + + /* 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 = nx_udp_socket_send(udp_socket_ptr, packet_ptr, dst_address, dst_port); + else + status = nx_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); + } + } + + /* 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) */ +/* */ +/* 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) + { + + /* 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; +ULONG peer_ip_address = 0; +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 socket. */ + + /* Check whther or not the socket is AF_PACKET family. */ + if(bsd_socket_ptr -> nx_bsd_socket_family == AF_PACKET) + { + +#if 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); + + } + + /* 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; + } + + } + + + + { + /* Get the destination IP and port for this UDP socket. */ + if (bsd_socket_ptr -> nx_bsd_socket_family == AF_INET) + { + + /* This is for an IPv4 packet. */ + peer_ip_address = 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. */ + + } + } + + /* 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 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. */ + nx_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_bsd_default_ip -> nx_ip_interface) / sizeof(NX_INTERFACE); + + } +#endif /* defined(NX_BSD_RAW_SUPPORT) || defined(NX_BSD_RAW_PPPOE_SUPPORT) */ + + + + /* Pickup the current offset. */ + offset = bsd_socket_ptr -> nx_bsd_socket_received_packet_offset; + + + + /* 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) + ) + { + + /* For UDP 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; +struct sockaddr_in peer4_address; + + /* 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)) + { + + /* 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); + 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); + + 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 + +#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; + + /* 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); + } + +#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 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; +INT i; +struct ip_mreq *mreq; +UINT mcast_interface; +UINT status; + + + /* 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 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 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_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; + + + 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 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) +{ + +struct sockaddr_in soc_struct; +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); + } + + 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 + { + + /* 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; +struct sockaddr_in *soc_struct_ptr = NX_NULL; + + + /* 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]; + + 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 + { + + /* 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) + { + + /* 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); + } + else + { + + /* 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) + { + + /* 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 + { + + /* 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); + } + } + } + + } + } + /* 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; + + /* 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; + } + /* 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; + } +} + + + + + + + +/**************************************************************************/ +/* */ +/* 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 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; +ULONG packet_fragment_length; +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; + 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; + } + + /* 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; + } + + /* Loop to copy bytes from packet(s). */ + while (working_packet_ptr && remaining_bytes) + { + + /* 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; + + /* 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; + } + } + + /* 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 support TCP keep alive? */ + /* Is NetX 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 _nx_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_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 API return code */ +/* */ +/* INPUT */ +/* */ +/* bsd_socket_ptr Pointer to the BSD socket */ +/* status_code NetX 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 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]; + + addr_family = AF_INET; + interface_ptr = packet_ptr -> nx_packet_ip_interface; + + /* 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)) + { + + 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) + { + + nx_udp_source_extract(packet_ptr, + &bsd_ptr -> nx_bsd_socket_source_ip_address, + (UINT *)&bsd_ptr -> nx_bsd_socket_source_port); + + 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 == + bsd_ptr -> nx_bsd_socket_peer_ip) && + (bsd_ptr -> nx_bsd_socket_source_port == + bsd_ptr -> nx_bsd_socket_peer_port)) + { + exact_match = bsd_ptr; + } + } + + 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 */ +/* */ +/* 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; + + addr_family = AF_INET; + + /* Start the search at the position of the input socket. */ + search_index = (INT)bsd_socket_index; + + /* Get the packet interface. */ + interface_ptr = packet_ptr -> nx_packet_ip_interface; + + 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)) + { + + 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 */ +/* */ +/* 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 */ +/* */ +/* 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); + } +} + + + + +#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); + } + + + /* 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) +{ + +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 + { + /* 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) +{ + + + + 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 + { + 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 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). */ +/* 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 */ +/* */ +/* 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 +#endif +UINT pton_flag; +UINT port; +UINT i, j; +INT addr_family; +UINT ipv4_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_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))) + 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 = 2; + match_service_socktype[0] = SOCK_STREAM; + match_service_protocol[0] = IPPROTO_TCP; + match_service_socktype[1] = SOCK_DGRAM; + match_service_protocol[1] = IPPROTO_UDP; + } + 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 + { + + /* 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; + + + /* 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; + } + } + + 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 + { + + /* Address family is not specified. Query for IPv4 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); + + if(status != 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; + + } + else + { + + /* Localhost address. */ + nx_bsd_ipv4_addr_buffer[0] = 0x7F000001; + + } + + { + ipv4_addr_count = 1; + } + } + + + for(i = 0; i < ipv4_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); + } + + 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); + } + + 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 */ +/* */ +/* 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; +#endif +const CHAR *rt_ptr; + + if(!sa) + { + + /* sa is NULL. */ + return EAI_FAMILY; + } + else + { + if(sa -> sa_family != AF_INET) + { + + /* sa isn't NULL, but family type is invalid. */ + return EAI_FAMILY; + } + else if(sa -> sa_family == AF_INET && salen != sizeof(struct sockaddr_in)) + { + + /* 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) + { + + /* 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; + } + + + 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. */ + rt_ptr = inet_ntop(AF_INET, &((struct sockaddr_in*)sa) -> sin_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 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/nx_bsd.h b/protocol_handlers/BSD/nx_bsd.h new file mode 100644 index 0000000..f683e56 --- /dev/null +++ b/protocol_handlers/BSD/nx_bsd.h @@ -0,0 +1,817 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +/**************************************************************************/ +/* */ +/* BSD DEFINITIONS RELEASE */ +/* */ +/* nx_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. */ +/* */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ + +#ifndef NX_BSD_H +#define NX_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 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 +*/ + + +/* 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 */ +#if defined(__PRODUCT_NETXDUO__) || defined(NX_BSD_RAW_SUPPORT) || defined(NX_ENABLE_IP_RAW_PACKET_FILTER) || defined(NX_BSD_RAW_PPPOE_SUPPORT) +#define SOCK_RAW 3 /* Raw socket */ +#endif +#define IPPROTO_TCP 6 /* TCP Socket */ +#define IPPROTO_UDP 17 /* TCP 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_PACKET 4 /* Raw Packet type (Link Layer packets) */ + +/* Protocol families, same as address families. */ +#define PF_INET AF_INET +#if defined(__PRODUCT_NETXDUO__) || defined(NX_BSD_RAW_SUPPORT) +#define PF_PACKET AF_PACKET +#endif +#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 socket. */ +#ifndef NX_BSD_SOCKET_QUEUE_MAX +#define NX_BSD_SOCKET_QUEUE_MAX 5 +#endif + + +/* 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 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_OPTION_MAX IP_DROP_MEMBERSHIP + + + +/* + * 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 protocol types. */ +#define NX_PROTOCOL_TCP 6 +#define NX_PROTOCOL_UDP 17 + +/* 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. */ +}; + + +/* 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 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 */ + + +/* 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_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. */ + 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; + ULONG nx_bsd_socket_source_ip_address; + ULONG nx_bsd_socket_peer_ip; + + /* For TCP/UDP, the local port is the port number this socket receives on. */ + 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; +#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); +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 _nx_get_errno(VOID); +#define errno (_nx_get_errno()) + + +#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 /* NX_BSD_H */ + diff --git a/protocol_handlers/DHCP/nx_dhcp.c b/protocol_handlers/DHCP/nx_dhcp.c new file mode 100644 index 0000000..90bf274 --- /dev/null +++ b/protocol_handlers/DHCP/nx_dhcp.c @@ -0,0 +1,10273 @@ +/**************************************************************************/ +/* */ +/* 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" +#include "nx_system.h" +#include "nx_ip.h" +#include "nx_arp.h" +#include "nx_dhcp.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); + +static USHORT _nx_dhcp_client_checksum_compute(NX_PACKET *packet_ptr, ULONG protocol, + UINT data_length, ULONG* src_ip_addr, + ULONG* dest_ip_addr); + +#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); + + + /* 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); + + + /* 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_set 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. */ + gateway_address = dhcp_ptr -> nx_dhcp_ip_ptr->nx_ip_gateway_address; + + /* Check the gateway address. */ + if ((gateway_address != 0) && (gateway_address == interface_record -> nx_dhcp_gateway_address)) + { + + /* Clear the Gateway/Router IP address. */ + nx_ip_gateway_address_set(dhcp_ptr -> nx_dhcp_ip_ptr, 0); + } + } + + /* 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. */ + 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. */ + 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_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_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_IP_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); + + +#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 */ + + + if (compute_checksum) + { + + /* Yes, we need to compute the UDP checksum. */ + checksum = _nx_dhcp_client_checksum_compute(packet_ptr, + 17, + (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); + } + + /* 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_IP_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 */ + + + if (compute_checksum) + { + checksum = _nx_dhcp_client_checksum_compute(packet_ptr, 4, 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_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_client_checksum_compute PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function computes the checksum from the supplied packet */ +/* pointer and IP address fields required for the pseudo header. */ +/* */ +/* INPUT */ +/* */ +/* packet_ptr Pointer to packet */ +/* protocol Protocol type */ +/* data_length Size of the protocol payload */ +/* src_ip_addr IPv4 source address */ +/* dest_ip_addr IPv4 destination address */ +/* */ +/* OUTPUT */ +/* */ +/* computed checksum */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* NetX Duo internal routines */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +static USHORT _nx_dhcp_client_checksum_compute(NX_PACKET *packet_ptr, ULONG protocol, + UINT data_length, ULONG* src_ip_addr, + ULONG* dest_ip_addr) +{ + +ULONG checksum = 0; +USHORT tmp; +USHORT *short_ptr; +ULONG *long_ptr; +ULONG packet_size; +NX_PACKET *current_packet; +ULONG *end_ptr; + + /* For computing UDP(17), we need to include the pseudo header. */ + if (protocol == 17) + { + + USHORT *src_ip_short, *dest_ip_short; + + checksum = protocol; + + src_ip_short = (USHORT*)src_ip_addr; + dest_ip_short = (USHORT*)dest_ip_addr; + + checksum += src_ip_short[0]; + checksum += src_ip_short[1]; + checksum += dest_ip_short[0]; + checksum += dest_ip_short[1]; + + /* Take care of data length */ + checksum += data_length; + + /* Fold a 4-byte value into a two byte value */ + checksum = (checksum >> 16) + (checksum & 0xFFFF); + + /* Do it again in case previous operation generates an overflow */ + checksum = (checksum >> 16) + (checksum & 0xFFFF); + + /* Convert to network byte order. */ + tmp = (USHORT)checksum; + NX_CHANGE_USHORT_ENDIAN(tmp); + checksum = tmp; + } + + /* Now we need to go through the payloads */ + + /* Setup the pointer to the start of the packet. */ + long_ptr = (ULONG *) packet_ptr -> nx_packet_prepend_ptr; + + /* Initialize the current packet to the input packet pointer. */ + current_packet = packet_ptr; + + /* Loop the packet. */ + while (current_packet) + { + + /* Calculate current packet size. */ + packet_size = (ULONG)(current_packet -> nx_packet_append_ptr - current_packet -> nx_packet_prepend_ptr); + + /* Calculate the end address in this packet. */ + if (data_length > (UINT)packet_size) + { + end_ptr = (ULONG *)(((ULONG)current_packet -> nx_packet_append_ptr) & (ULONG)(~3)); + } + else + { + end_ptr = (ULONG *)(current_packet -> nx_packet_prepend_ptr + data_length - 3); + } + + /* Set the start address in this packet. */ + long_ptr = (ULONG *)current_packet -> nx_packet_prepend_ptr; + + if (long_ptr < end_ptr) + { + + /* Calculate the data_length. */ + data_length -= (((ULONG)end_ptr + 3) & (ULONG)(~3)) - (ULONG)long_ptr; + + /* Loop to calculate the packet's checksum. */ + while (long_ptr < end_ptr) + { + checksum += (*long_ptr & NX_LOWER_16_MASK); + checksum += (*long_ptr >> NX_SHIFT_BY_16); + long_ptr++; + } + } + + /* Determine if we are at the end of the current packet. */ + if ((data_length > 0) && (current_packet -> nx_packet_next)) + { + + /* Is append_ptr two bytes aligned but not four bytes aligned? */ + if ((((ULONG)current_packet -> nx_packet_append_ptr) & 3) == 2) + { + + /* Yes it is. Process the last two bytes in chaining packets. */ + short_ptr = (USHORT *)long_ptr; + checksum += *short_ptr; + data_length -= 2; + } + + /* We have crossed the packet boundary. Move to the next packet + structure. */ + current_packet = current_packet -> nx_packet_next; + } + else + { + break; + } + } + + /* Determine if there is only one byte left. */ + if (data_length) + { + + /* Set the short_ptr. */ + short_ptr = (USHORT *)(long_ptr); + + /* Check the data length. */ + if (data_length == 1) + { + *((UCHAR *)short_ptr + 1) = 0; + } + else if (data_length == 3) + { + checksum += *short_ptr; + short_ptr++; + + *((UCHAR *)short_ptr + 1) = 0; + } + + checksum += *short_ptr; + } + + /* Fold a 4-byte value into a two byte value */ + checksum = (checksum >> 16) + (checksum & 0xFFFF); + + /* Do it again in case previous operation generates an overflow */ + checksum = (checksum >> 16) + (checksum & 0xFFFF); + + /* Convert to host byte order. */ + tmp = (USHORT)checksum; + NX_CHANGE_USHORT_ENDIAN(tmp); + + /* Return the computed checksum. */ + return(tmp); +} + + +/**************************************************************************/ +/* */ +/* 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 */ diff --git a/protocol_handlers/DHCP/nx_dhcp.h b/protocol_handlers/DHCP/nx_dhcp.h new file mode 100644 index 0000000..6d3ed31 --- /dev/null +++ b/protocol_handlers/DHCP/nx_dhcp.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 */ +/* */ +/* nx_dhcp.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 NX_DHCP_H +#define NX_DHCP_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 clear_flag, UINT iface_index); +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 clear_flag, UINT iface_index); +UINT _nx_dhcp_interface_clear_broadcast_flag(NX_DHCP *dhcp_ptr, UINT clear_flag, UINT iface_index); +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 /* NX_DHCP_H */ diff --git a/protocol_handlers/DHCP/nx_dhcp_server.c b/protocol_handlers/DHCP/nx_dhcp_server.c new file mode 100644 index 0000000..3b18700 --- /dev/null +++ b/protocol_handlers/DHCP/nx_dhcp_server.c @@ -0,0 +1,5526 @@ +/**************************************************************************/ +/* */ +/* 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" +#include "nx_ip.h" +#include "nx_udp.h" +#include "nx_dhcp_server.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); + + + /* 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); + + + /* 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); + + + /* 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. */ + 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. */ + 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. */ + 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_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_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_IP_HEADER)); + length = ((packet_ptr -> nx_packet_length + sizeof(ULONG) - 1)/sizeof(ULONG)) + sizeof(NX_UDP_HEADER) + sizeof(NX_IP_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_IP_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_IP_HEADER *)(packet_ptr -> nx_packet_prepend_ptr - sizeof(NX_UDP_HEADER) - sizeof(NX_IP_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; + } +} + diff --git a/protocol_handlers/DHCP/nx_dhcp_server.h b/protocol_handlers/DHCP/nx_dhcp_server.h new file mode 100644 index 0000000..96af3e4 --- /dev/null +++ b/protocol_handlers/DHCP/nx_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 */ +/* */ +/* nx_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 NX_DHCP_SERVER_H +#define NX_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_IP_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 /* NX_DHCP_SERVER_H */ diff --git a/protocol_handlers/DNS/nx_dns.c b/protocol_handlers/DNS/nx_dns.c new file mode 100644 index 0000000..c153442 --- /dev/null +++ b/protocol_handlers/DNS/nx_dns.c @@ -0,0 +1,8638 @@ +/**************************************************************************/ +/* */ +/* 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 "nx_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); +static UINT _nx_dns_number_to_ascii_convert(UINT number, CHAR *buffstring); +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 */ + +static UINT _nx_dns_server_add_internal(NX_DNS *dns_ptr, ULONG server_address); +static UINT _nx_dns_server_remove_internal(NX_DNS *dns_ptr, ULONG server_address); +static UINT _nx_dns_server_get_internal(NX_DNS *dns_ptr, UINT index, ULONG *server_address); +static UINT _nx_dns_host_by_address_get_internal(NX_DNS *dns_ptr, ULONG host_address, UCHAR *host_name_ptr, + UINT host_name_buffer_size, ULONG wait_option); +static UINT _nx_dns_send_query_by_address(NX_DNS *dns_ptr, ULONG 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, ULONG 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(ULONG)); + + /* 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] = 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) +{ + +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); +} + + +/**************************************************************************/ +/* */ +/* 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) +{ + + return(_nx_dns_server_add_internal(dns_ptr, 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, ULONG 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) + { + + if(dns_ptr -> nx_dns_server_ip_array[i] != 0) + { + /* Is there a match? */ + if(dns_ptr -> nx_dns_server_ip_array[i] == server_address) + { + /* Error, release the mutex and return. */ + tx_mutex_put(&(dns_ptr -> nx_dns_mutex)); + + /* Yes, no need to add ato the table, just return the 'error' status. */ + return NX_DNS_DUPLICATE_ENTRY; + } + } + 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. */ + dns_ptr -> nx_dns_server_ip_array[i] = server_address; + + /* 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) +{ + +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); +} + + +/**************************************************************************/ +/* */ +/* 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) +{ + + 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, ULONG server_address) +{ + +ULONG *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 + { + + /* Check for a null address. */ + if (DNSserver_array[i] != IP_ADDRESS(0, 0, 0, 0)) + { + /* Determine if this entry matches the specified DNS server. */ + if (DNSserver_array[i] == server_address) + { + found_match = NX_TRUE; + break; + } + } + else + { + + /* Error, release the mutex and return. */ + tx_mutex_put(&(dns_ptr -> nx_dns_mutex)); + return NX_DNS_BAD_ADDRESS_ERROR; + } + + + /* 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. */ + + DNSserver_array[i] = DNSserver_array[i+1]; + + i++; + } + + /* Terminate the last slot. */ + memset(&dns_ptr -> nx_dns_server_ip_array[NX_DNS_MAX_SERVERS - 1], 0, sizeof(ULONG)); + + /* 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(ULONG)); + + /* 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] == 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) +{ + +UINT status; +ULONG 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; + } + + *dns_server_address = server_address; + + return NX_SUCCESS; +} + + + + +/**************************************************************************/ +/* */ +/* 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, ULONG *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] == 0) + { + + /* No, release the mutex and return. */ + tx_mutex_put(&(dns_ptr -> nx_dns_mutex)); + + return NX_DNS_SERVER_NOT_FOUND; + } + + /* 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; +} + + + + +#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; +} + + + + +#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] == 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] != 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 */ +/* nx_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, ULONG 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). */ + id = (USHORT)(dns_server ^ 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, 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 = nx_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) + { + + if (receive_packet_ptr -> nx_packet_next) + { + + /* Chained packet is not supported. */ + nx_packet_release(receive_packet_ptr); + return(NX_INVALID_PACKET); + } + + /* 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 */ +/* nx_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, ULONG 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 = nx_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) + { + + if (receive_packet_ptr -> nx_packet_next) + { + + /* Chained packet is not supported. */ + nx_packet_release(receive_packet_ptr); + return(NX_INVALID_PACKET); + } + + /* 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) +{ + + + + /* Check for null address input. */ + if (dns_address == 0) + { + return NX_DNS_BAD_ADDRESS_ERROR; + } + + return(_nx_dns_host_by_address_get_internal(dns_ptr, dns_address, host_name, 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 */ +/* */ +/* _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, ULONG host_address, 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; +UCHAR dot = '.'; +UINT value; +UINT length, index; + + + if(host_address == 0) + { + return NX_DNS_BAD_ADDRESS_ERROR; + } + + /* 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] == 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? */ + memset(ip_question, 0, NX_DNS_IP_LOOKUP_SIZE); + value = host_address & 0xff; + length = _nx_dns_number_to_ascii_convert(value, (CHAR *)&ip_question[0]); + ip_question[length++] = dot; + index = length; + + value = (host_address >> 8) & 0xff; + length += _nx_dns_number_to_ascii_convert(value, (CHAR *)&ip_question[index]); + ip_question[length++] = dot; + index = length; + + value = (host_address >> 16) & 0xff; + length += _nx_dns_number_to_ascii_convert(value, (CHAR *)&ip_question[index]) ; + ip_question[length++] = dot; + index = length; + + value = (host_address >> 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); + +#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] != 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); +} + + + + +/**************************************************************************/ +/* */ +/* 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); +} + + +/**************************************************************************/ +/* */ +/* 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; +} + + +#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/nx_dns.h b/protocol_handlers/DNS/nx_dns.h new file mode 100644 index 0000000..6c4ae93 --- /dev/null +++ b/protocol_handlers/DNS/nx_dns.h @@ -0,0 +1,982 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/* */ +/* nx_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 NX_DNS_H +#define NX_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_ip.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 */ + ULONG 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 + + +#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 + + +#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 + + +#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); + +#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 /* NX_DNS_H */ + diff --git a/protocol_handlers/FTP/nx_ftp.h b/protocol_handlers/FTP/nx_ftp.h new file mode 100644 index 0000000..bfd64b8 --- /dev/null +++ b/protocol_handlers/FTP/nx_ftp.h @@ -0,0 +1,55 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** File Transfer Protocol (FTP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* APPLICATION INTERFACE DEFINITION RELEASE */ +/* */ +/* nx_ftp.h PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file defines the NetX File Transfer Protocol (FTP) */ +/* 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_FTP_H +#define NX_FTP_H + +#include "nx_ftp_client.h" +#include "nx_ftp_server.h" + +#endif /* NX_FTP_H */ diff --git a/protocol_handlers/FTP/nx_ftp_client.c b/protocol_handlers/FTP/nx_ftp_client.c new file mode 100644 index 0000000..81aaea4 --- /dev/null +++ b/protocol_handlers/FTP/nx_ftp_client.c @@ -0,0 +1,5387 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** 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" +#include "nx_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) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((ftp_client_ptr == NX_NULL) || (ftp_client_ptr -> nx_ftp_client_id != NX_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); +} + + +/**************************************************************************/ +/* */ +/* 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) +{ + + return (_nx_ftp_client_connect_internal(ftp_client_ptr, server_ip, 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 */ +/* nx_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, ULONG 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 = nx_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); + } + + 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); + } + + /* 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); + } + + 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); + } + + /* 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 == NX_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 = NX_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 != NX_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 != NX_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 != NX_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 != NX_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 != NX_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 != NX_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 != NX_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 != NX_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 != NX_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 != NX_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); + } + + if (packet_ptr -> nx_packet_next) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return. */ + return(NX_INVALID_PACKET); + } + + /* 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 != NX_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 != NX_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); + } + + if (packet_ptr -> nx_packet_next) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return. */ + return(NX_INVALID_PACKET); + } + + /* 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 != NX_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 != NX_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; + + + /* 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); +} + + + + +/**************************************************************************/ +/* */ +/* 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 */ +/* */ +/* 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; + + + packet_type = NX_TCP_PACKET; + + + /* 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; +ULONG ip_address; +UCHAR *buffer_ptr; +NX_PACKET *packet_ptr; + + + /* 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. */ + { + /* IPv4 FTP connection */ + + /* 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; + } + + /* 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*/ +/* nx_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; +UINT commas = 0; +ULONG ip_address = 0; +ULONG temp = 0; + + + /* 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; + + { + + /* Now build "PASV" message . */ + buffer_ptr[0] = 'P'; + buffer_ptr[1] = 'A'; + buffer_ptr[2] = 'S'; + buffer_ptr[3] = 'V'; + } + + /* 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; + + { + + /* 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 = ip_address; + ftp_client_ptr -> nx_ftp_client_data_socket.nx_tcp_socket_connect_port = data_port; + + } + + /* 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 = nx_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; +NX_PACKET *before_last_packet; +NX_PACKET *last_packet; + + + /* 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. */ + + /* 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); + } + } + } + + /* 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/nx_ftp_client.h b/protocol_handlers/FTP/nx_ftp_client.h new file mode 100644 index 0000000..ab8d646 --- /dev/null +++ b/protocol_handlers/FTP/nx_ftp_client.h @@ -0,0 +1,363 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** File Transfer Protocol (FTP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* APPLICATION INTERFACE DEFINITION RELEASE */ +/* */ +/* nx_ftp_client.h PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file defines the NetX File Transfer Protocol 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_FTP_CLIENT_H +#define NX_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 NX_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 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 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 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 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 _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, ULONG server_ip, CHAR *username, CHAR *password, ULONG wait_option); + + +/* Determine if a C++ compiler is being used. If so, complete the standard + C conditional started above. */ +#ifdef __cplusplus + } +#endif + +#endif /* NX_FTP_CLIENT_H */ diff --git a/protocol_handlers/FTP/nx_ftp_server.c b/protocol_handlers/FTP/nx_ftp_server.c new file mode 100644 index 0000000..4acf31a --- /dev/null +++ b/protocol_handlers/FTP/nx_ftp_server.c @@ -0,0 +1,5651 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** 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 "nx_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)) +{ + +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); +} + + +/**************************************************************************/ +/* */ +/* 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)) +{ + +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; +} + + + + +/**************************************************************************/ +/* */ +/* 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, ULONG client_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info), + UINT (*ftp_logout)(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, ULONG 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; + + NX_PARAMETER_NOT_USED(ftp_login); + NX_PARAMETER_NOT_USED(ftp_logout); + + /* Set the server ID to indicate the FTP server thread is ready. */ + ftp_server_ptr -> nx_ftp_server_id = NX_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 != NX_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 != NX_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 != NX_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 */ +/* 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) +{ + + +ULONG connect_ip4_address = 0; +UINT commas; +ULONG ip_address; +UINT temp; +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]); + + connect_ip4_address = client_req_ptr -> nx_ftp_client_request_control_socket.nx_tcp_socket_connect_ip; + + /* 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; + } + + if (packet_ptr -> nx_packet_next) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* And continue looking at other client requests. */ + continue; + } + + /* 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_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), + 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); + } + + /* 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. */ + + /* 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, + 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 = nx_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 = nx_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 = nx_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 = nx_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; + } + + case NX_FTP_PORT: + { + + + /* 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; + } + + + 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. */ + + /* 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); + + /* Pickup next packet pointer. */ + next_packet_ptr = next_packet_ptr -> nx_packet_next; + + } 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. */ + + /* 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, + 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. */ + + status = nx_packet_allocate(pool_ptr, packet_ptr, NX_TCP_PACKET, wait_option); + + NX_PARAMETER_NOT_USED(client_request_ptr); + + NX_PARAMETER_NOT_USED(packet_type); + + /* Return completion status. */ + return status; +} + + + + +/**************************************************************************/ +/* */ +/* 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; +NX_PACKET *before_last_packet; +NX_PACKET *last_packet; + + + /* 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. */ + + /* 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); + } + } + } + + /* 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/nx_ftp_server.h b/protocol_handlers/FTP/nx_ftp_server.h new file mode 100644 index 0000000..3ea8a5c --- /dev/null +++ b/protocol_handlers/FTP/nx_ftp_server.h @@ -0,0 +1,415 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** File Transfer Protocol (FTP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* APPLICATION INTERFACE DEFINITION RELEASE */ +/* */ +/* nx_ftp_server.h PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file defines the NetX File Transfer Protocol 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_FTP_SERVER_H +#define NX_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 NX_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 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_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_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); + + 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 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 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 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 _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, ULONG client_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info), + UINT (*ftp_logout)(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, ULONG 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. */ + +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 /* NX_FTP_SERVER_H */ diff --git a/protocol_handlers/HTTP/nx_http.h b/protocol_handlers/HTTP/nx_http.h new file mode 100644 index 0000000..79eb14e --- /dev/null +++ b/protocol_handlers/HTTP/nx_http.h @@ -0,0 +1,55 @@ +/**************************************************************************/ +/* */ +/* 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_http.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 NX_HTTP_H +#define NX_HTTP_H + +#include "nx_http_server.h" +#include "nx_http_client.h" + +#endif /* NX_HTTP_H */ diff --git a/protocol_handlers/HTTP/nx_http_client.c b/protocol_handlers/HTTP/nx_http_client.c new file mode 100644 index 0000000..1dcd47f --- /dev/null +++ b/protocol_handlers/HTTP/nx_http_client.c @@ -0,0 +1,2716 @@ +/**************************************************************************/ +/* */ +/* 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 "nx_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 == NX_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 = NX_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 != NX_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 != NX_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) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((client_ptr == NX_NULL) || (client_ptr -> nx_http_client_id != NX_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); +} + +/**************************************************************************/ +/* */ +/* 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) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((client_ptr == NX_NULL) || (client_ptr -> nx_http_client_id != NX_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); +} + + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_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 */ +/* */ +/* _nx_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_http_client_get_start(NX_HTTP_CLIENT *client_ptr, ULONG 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 = _nx_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 */ +/* */ +/* _nx_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 */ +/* nx_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 _nx_http_client_get_start_extended(NX_HTTP_CLIENT *client_ptr, ULONG 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 = nx_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. */ + status = nx_packet_allocate(client_ptr -> nx_http_client_packet_pool_ptr, &packet_ptr, + NX_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 != NX_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) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((client_ptr == NX_NULL) || (client_ptr -> nx_http_client_id != NX_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); +} + + +/**************************************************************************/ +/* */ +/* 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) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((client_ptr == NX_NULL) || (client_ptr -> nx_http_client_id != NX_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); +} + + + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_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 */ +/* */ +/* _nx_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_http_client_put_start(NX_HTTP_CLIENT *client_ptr, ULONG 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 = _nx_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 */ +/* */ +/* _nx_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 */ +/* nx_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 _nx_http_client_put_start_extended(NX_HTTP_CLIENT *client_ptr, ULONG 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 NetX (IPv4 only) connection call. */ + status = nx_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. */ + status = nx_packet_allocate(client_ptr -> nx_http_client_packet_pool_ptr, &packet_ptr, + NX_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 != NX_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/nx_http_client.h b/protocol_handlers/HTTP/nx_http_client.h new file mode 100644 index 0000000..f7c63d3 --- /dev/null +++ b/protocol_handlers/HTTP/nx_http_client.h @@ -0,0 +1,278 @@ +/**************************************************************************/ +/* */ +/* 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_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 NX_HTTP_CLIENT_H +#define NX_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 NX_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 + +#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 + +#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); + +#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 _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_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); + +/* 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 /* NX_HTTP_CLIENT_H */ diff --git a/protocol_handlers/HTTP/nx_http_server.c b/protocol_handlers/HTTP/nx_http_server.c new file mode 100644 index 0000000..2179ff7 --- /dev/null +++ b/protocol_handlers/HTTP/nx_http_server.c @@ -0,0 +1,9211 @@ +/**************************************************************************/ +/* */ +/* 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_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 != NX_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; +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. */ + 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) + { + + /* 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; + } + + /* 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); + + /* Move to next packet in the chain. */ + new_packet_ptr = new_packet_ptr -> nx_packet_next; + + } 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 != NX_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 != NX_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 != NX_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) + { + + /* 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; + } + + /* 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); + + /* Move to next packet in the chain. */ + new_packet_ptr = new_packet_ptr -> nx_packet_next; + + } 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 == NX_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 = NX_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 != NX_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 != NX_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 != NX_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 != NX_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 != NX_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 != NX_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. */ + + + 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 + + { + /* 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; + while (tmp_ptr) + { + + /* 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); + } + + tmp_ptr = tmp_ptr -> nx_packet_next; + } + + /* 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) + { + + ULONG client_address; + ULONG client_port; + + /* Get the IP address of the client: */ + status = nx_tcp_socket_peer_info_get(&(server_ptr->nx_http_server_socket), &client_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_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) + { + + ULONG client_address; + ULONG client_port; + + /* Get the IP address of the client: */ + status = nx_tcp_socket_peer_info_get(&(server_ptr->nx_http_server_socket), &client_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_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); + } + + + /* 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; + } + + /* 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); + + /* Move to the next pointer. */ + next_packet_ptr = next_packet_ptr -> nx_packet_next; + + } 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) + { + + ULONG client_address; + ULONG client_port; + + /* Get the IP address of the client: */ + status = nx_tcp_socket_peer_info_get(&(server_ptr->nx_http_server_socket), &client_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_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, ULONG client_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, ULONG client_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 != NX_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 != NX_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 != NX_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; + } + 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; + } + } + + /* 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. */ + if(available_packet -> nx_packet_next) + { + + /* Copy data from next packet. */ + available_packet = available_packet -> nx_packet_next; + } + else + { + + /* 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 != NX_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 + { + 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; + } + } + + /* 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. */ + 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 + 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 != NX_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 != NX_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 != NX_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 != NX_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 != NX_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 != NX_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/nx_http_server.h b/protocol_handlers/HTTP/nx_http_server.h new file mode 100644 index 0000000..f08e2bb --- /dev/null +++ b/protocol_handlers/HTTP/nx_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 */ +/* */ +/* nx_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 NX_HTTP_SERVER_H +#define NX_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 NX_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, ULONG client_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, ULONG client_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, ULONG client_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, ULONG client_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 /* NX_HTTP_SERVER_H */ diff --git a/protocol_handlers/POP3/nx_pop3.h b/protocol_handlers/POP3/nx_pop3.h new file mode 100644 index 0000000..e986dfb --- /dev/null +++ b/protocol_handlers/POP3/nx_pop3.h @@ -0,0 +1,52 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/* */ +/* nx_pop3.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_H +#define NX_POP3_H + +#include "nx_pop3_client.h" + +#endif /* NX_POP3_H */ diff --git a/protocol_handlers/POP3/nx_pop3_client.c b/protocol_handlers/POP3/nx_pop3_client.c new file mode 100644 index 0000000..72dfa0b --- /dev/null +++ b/protocol_handlers/POP3/nx_pop3_client.c @@ -0,0 +1,3002 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/* */ +/* nx_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 "nx_pop3_client.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) +{ + +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); +} + + + + +/**************************************************************************/ +/* */ +/* 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 */ +/* */ +/* nx_tcp_socket_create NetX TCP socket create service */ +/* _nx_pop3_client_connect Connect POP3 Client to Server */ +/* */ +/* 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) + +{ + +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 = _nx_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; + + packet_type = NX_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); + } + + if (recv_packet_ptr -> nx_packet_next) + { + + /* Chained packet is not supported. */ + nx_packet_release(recv_packet_ptr); + return(NX_INVALID_PACKET); + } + + /* 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; + } + + packet_type = NX_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); + } + + if (recv_packet_ptr -> nx_packet_next) + { + + /* Chained packet is not supported. */ + nx_packet_release(recv_packet_ptr); + return(NX_INVALID_PACKET); + } + + /* 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. */ + packet_type = NX_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); + } + + if (recv_packet_ptr -> nx_packet_next) + { + + /* Chained packet is not supported. */ + nx_packet_release(recv_packet_ptr); + return(NX_INVALID_PACKET); + } + + /* 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. */ + packet_type = NX_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); + } + + if (recv_packet_ptr -> nx_packet_next) + { + + /* Chained packet is not supported. */ + nx_packet_release(recv_packet_ptr); + return(NX_INVALID_PACKET); + } + + /* 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; + + + packet_type = NX_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); + } + + if (recv_packet_ptr -> nx_packet_next) + { + + /* Chained packet is not supported. */ + nx_packet_release(recv_packet_ptr); + return(NX_INVALID_PACKET); + } + + /* 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 */ +/* */ +/* _nx_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 */ +/* */ +/* _nx_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. */ +/* */ +/* */ +/* 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 */ +/* */ +/* _nx_pop3_client_create Create POP3 Client and socket */ +/* */ +/* CALLS */ +/* */ +/* nx_tcp_client_socket_bind NetX TCP socket bind service */ +/* nx_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 _nx_pop3_client_connect(NX_POP3_CLIENT *client_ptr, ULONG 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 = nx_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); + } + + if (recv_packet_ptr -> nx_packet_next) + { + + /* Chained packet is not supported. */ + nx_packet_release(recv_packet_ptr); + return(NX_INVALID_PACKET); + } + + /* 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 */ +/* */ +/* nx_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; + + + packet_type = NX_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); + } + + if (recv_packet_ptr -> nx_packet_next) + { + + /* Chained packet is not supported. */ + nx_packet_release(recv_packet_ptr); + return(NX_INVALID_PACKET); + } + + /* 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 */ +/* */ +/* nx_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; + + + packet_type = NX_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); + } + + if (recv_packet_ptr -> nx_packet_next) + { + + /* Chained packet is not supported. */ + nx_packet_release(recv_packet_ptr); + return(NX_INVALID_PACKET); + } + + /* 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); + + packet_type = NX_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); + } + + if (next_recv_packet_ptr -> nx_packet_next) + { + + /* Chained packet is not supported. */ + nx_packet_release(next_recv_packet_ptr); + return(NX_INVALID_PACKET); + } + + /* 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/nx_pop3_client.h b/protocol_handlers/POP3/nx_pop3_client.h new file mode 100644 index 0000000..562dac7 --- /dev/null +++ b/protocol_handlers/POP3/nx_pop3_client.h @@ -0,0 +1,272 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/* */ +/* nx_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 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 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 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 _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 _nx_pop3_client_connect(NX_POP3_CLIENT *client_ptr, ULONG 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 new file mode 100644 index 0000000..9e566e2 --- /dev/null +++ b/protocol_handlers/PPP/nx_ppp.c @@ -0,0 +1,12021 @@ +/**************************************************************************/ +/* */ +/* 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" +#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; +NX_PACKET *next_packet_ptr; +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; + + /* 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; + } + } + + /* 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++; + } + + + /* 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++; + } + 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) + { + + + /* Discard the chained packets. */ + if (packet_ptr -> nx_packet_next) + { + + /* Release the packet. */ + nx_packet_release(packet_ptr); + + /* Return. */ + return; + } + + /* 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) + { + + + /* 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; + + } + + /* 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) + { + + + /* 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; + + } + + /* 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) + { + + + /* 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; + + } + + /* 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 */ diff --git a/protocol_handlers/PPP/nx_ppp.h b/protocol_handlers/PPP/nx_ppp.h new file mode 100644 index 0000000..d757c9d --- /dev/null +++ b/protocol_handlers/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/protocol_handlers/PPPoE/nx_pppoe_client.c b/protocol_handlers/PPPoE/nx_pppoe_client.c new file mode 100644 index 0000000..bca12f0 --- /dev/null +++ b/protocol_handlers/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/protocol_handlers/PPPoE/nx_pppoe_client.h b/protocol_handlers/PPPoE/nx_pppoe_client.h new file mode 100644 index 0000000..170e69a --- /dev/null +++ b/protocol_handlers/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/protocol_handlers/PPPoE/nx_pppoe_server.c b/protocol_handlers/PPPoE/nx_pppoe_server.c new file mode 100644 index 0000000..918f198 --- /dev/null +++ b/protocol_handlers/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/protocol_handlers/PPPoE/nx_pppoe_server.h b/protocol_handlers/PPPoE/nx_pppoe_server.h new file mode 100644 index 0000000..acc8db9 --- /dev/null +++ b/protocol_handlers/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/protocol_handlers/SMTP/nx_smtp_client.c b/protocol_handlers/SMTP/nx_smtp_client.c new file mode 100644 index 0000000..6956dd4 --- /dev/null +++ b/protocol_handlers/SMTP/nx_smtp_client.c @@ -0,0 +1,4706 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/* */ +/* nx_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_ip.h" +#include "nx_smtp_client.h" +#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 */ +/* */ +/* _nxe_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 */ +/* */ +/* _nx_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 _nxe_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, + ULONG 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; + } + + + /* Call the actual client create service. */ + status = _nx_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 */ +/* */ +/* _nx_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 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 _nx_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, + ULONG 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. */ + client_ptr -> nx_smtp_server_address = server_address; + 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 */ +/* connection. */ +/* */ +/* 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 = nx_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 */ +/* 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. */ + packet_payload = pool_ptr -> nx_packet_pool_payload_size - sizeof(NX_TCP_HEADER) - sizeof(NX_IP_HEADER); + + + /* 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; + } + + 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; + } + + /* 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; + + + packet_type = NX_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; + + packet_type = NX_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/nx_smtp_client.h b/protocol_handlers/SMTP/nx_smtp_client.h new file mode 100644 index 0000000..ed44847 --- /dev/null +++ b/protocol_handlers/SMTP/nx_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 */ +/* */ +/* nx_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 NX_SMTP_CLIENT_H +#define NX_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. */ + ULONG nx_smtp_server_address; /* Server IP address. */ + 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 nx_smtp_client_create _nx_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 nx_smtp_client_create _nxe_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 nx_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, + ULONG 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 _nx_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, + ULONG server_address, UINT port); +UINT _nxe_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, + ULONG 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 /* NX_SMTP_CLIENT_H */ diff --git a/protocol_handlers/SNMP/nx_des.c b/protocol_handlers/SNMP/nx_des.c new file mode 100644 index 0000000..2054bd6 --- /dev/null +++ b/protocol_handlers/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/protocol_handlers/SNMP/nx_des.h b/protocol_handlers/SNMP/nx_des.h new file mode 100644 index 0000000..eab9a3f --- /dev/null +++ b/protocol_handlers/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/protocol_handlers/SNMP/nx_sha1.c b/protocol_handlers/SNMP/nx_sha1.c new file mode 100644 index 0000000..0537907 --- /dev/null +++ b/protocol_handlers/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/protocol_handlers/SNMP/nx_sha1.h b/protocol_handlers/SNMP/nx_sha1.h new file mode 100644 index 0000000..f265ed5 --- /dev/null +++ b/protocol_handlers/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/protocol_handlers/SNMP/nx_snmp.c b/protocol_handlers/SNMP/nx_snmp.c new file mode 100644 index 0000000..07330d7 --- /dev/null +++ b/protocol_handlers/SNMP/nx_snmp.c @@ -0,0 +1,22506 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** 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 "nx_snmp.h" + + + +/* 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; +NX_PACKET *new_packet_ptr; + + + /* 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! */ + nx_udp_source_extract(packet_ptr, &agent_ptr -> nx_snmp_agent_current_manager_ip, + &(agent_ptr -> nx_snmp_agent_current_manager_port)); + + /* 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; + } + + + 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. */ +/* */ +/* 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) +{ + +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); +} + + + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_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. */ +/* */ +/* 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 _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 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. */ + + packet_type = NX_UDP_PACKET; + + 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; + + + 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; + + 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 = nx_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. */ +/* */ +/* 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) +{ + +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); +} + + + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_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. */ +/* */ +/* 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 _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 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; + } + + packet_type = NX_UDP_PACKET; + + /* 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 = nx_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) +{ + +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); +} + + + +/**************************************************************************/ +/* */ +/* 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. */ +/* */ +/* 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 _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 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; + + + + /* 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 = nx_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); +} + + +#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) +{ + +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); +} + + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_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. */ +/* */ +/* 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 _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 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; + } + + packet_type = NX_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) + { + + /* 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 = nx_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) +{ + +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); +} + + + +/**************************************************************************/ +/* */ +/* 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. */ +/* */ +/* 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 _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 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; + + + + /* 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 = nx_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); +} + + +#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); +} + + +/**************************************************************************/ +/* */ +/* 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 = nx_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; + } + + /* 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; + } + + 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. */ + + packet_type = NX_UDP_PACKET; + + /* 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) && + (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 = nx_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; + } + + + /* 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; + } + + + + /* 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. */ + + + packet_type = NX_UDP_PACKET; + + /* 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) && + (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 = nx_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. */ + + packet_type = NX_UDP_PACKET; + + /* 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; + } + + + /* 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; + } + + + /* 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) && + (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 = nx_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. */ + + packet_type = NX_UDP_PACKET; + + /* 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) && + (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 = nx_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/nx_snmp.h b/protocol_handlers/SNMP/nx_snmp.h new file mode 100644 index 0000000..9f35dc6 --- /dev/null +++ b/protocol_handlers/SNMP/nx_snmp.h @@ -0,0 +1,846 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/** */ +/** Simple Network Management Protocol (SNMP) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* APPLICATION INTERFACE DEFINITION RELEASE */ +/* */ +/* nx_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 NX_SNMP_H +#define NX_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 */ +/* 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 */ + ULONG nx_snmp_agent_current_manager_ip; /* Current SNMP Manager 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 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 +#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 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 +#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 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); +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 _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); +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 /* NX_SNMP_H */ + diff --git a/protocol_handlers/SNTP/nx_sntp.h b/protocol_handlers/SNTP/nx_sntp.h new file mode 100644 index 0000000..c2e73ad --- /dev/null +++ b/protocol_handlers/SNTP/nx_sntp.h @@ -0,0 +1,52 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/* */ +/* nx_sntp.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 NX_SNTP_H +#define NX_SNTP_H + +#include "nx_sntp_client.h" + +#endif /* NX_SNTP_H */ diff --git a/protocol_handlers/SNTP/nx_sntp_client.c b/protocol_handlers/SNTP/nx_sntp_client.c new file mode 100644 index 0000000..c2c27ce --- /dev/null +++ b/protocol_handlers/SNTP/nx_sntp_client.c @@ -0,0 +1,5873 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/* */ +/* nx_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_ip.h" +#include "nx_sntp_client.h" + + +#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 = NX_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. */ + if (packet_pool_ptr -> nx_packet_pool_payload_size < + (sizeof(NX_IP_HEADER) + sizeof(NX_UDP_HEADER) + NX_SNTP_CLIENT_PACKET_DATA_SIZE)) + { + + return NX_SNTP_INSUFFICIENT_PACKET_PAYLOAD; + } + + + 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 != NX_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 */ +/* */ +/* _nx_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 SNTP server as the primary (current) server. */ +/* */ +/* For adding IPv4 SNTP servers to the unicast server list, use the */ +/* nx_sntp_client_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 _nx_sntp_client_initialize_unicast(NX_SNTP_CLIENT *client_ptr, ULONG 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. */ + client_ptr -> nx_sntp_server_ip_address = 0; + + /* Set as the Client's unicast server. */ + client_ptr -> nx_sntp_unicast_time_server = unicast_time_server; + + /* Set as the Client's current SNTP server. */ + client_ptr -> nx_sntp_server_ip_address = client_ptr -> nx_sntp_unicast_time_server; + + /* 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) +{ + +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; +} + + + + +/**************************************************************************/ +/* */ +/* 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 */ +/* */ +/* _nx_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. */ +/* */ +/* 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 _nx_sntp_client_initialize_broadcast(NX_SNTP_CLIENT *client_ptr, ULONG multicast_server_address, ULONG broadcast_server_address) +{ + + + /* Clear Client's current server IP. */ + client_ptr -> nx_sntp_server_ip_address = 0; + + /* Was a multicast IP was supplied. */ + if(multicast_server_address != 0) + { + /* Set the Client multicast server. */ + client_ptr -> nx_sntp_multicast_server_address = multicast_server_address; + + /* Set this as the Client's current SNTP server. */ + client_ptr -> nx_sntp_server_ip_address = multicast_server_address; + } + /* No multicast address supplied, so was a broadcast address specified? */ + else if(broadcast_server_address != 0) + { + + /* Set the Client broadcast server. */ + client_ptr -> nx_sntp_broadcast_time_server = broadcast_server_address; + + /* Set this as the Client's current SNTP server. */ + client_ptr -> nx_sntp_server_ip_address = broadcast_server_address; + } + + + /* 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) +{ + +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; +} + + + + +/**************************************************************************/ +/* */ +/* 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. */ + + if (client_ptr -> nx_sntp_client_packet_pool_ptr -> nx_packet_pool_payload_size < + (sizeof(NX_IP_HEADER) + sizeof(NX_UDP_HEADER) + NX_SNTP_CLIENT_PACKET_DATA_SIZE)) + { + + /* Release the mutex. */ + tx_mutex_put(&client_ptr -> nx_sntp_client_mutex); + + nx_packet_release(packet_ptr); + + return NX_SNTP_INSUFFICIENT_PACKET_PAYLOAD; + } + + + + /* 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 = nx_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; +ULONG source_ip_address, destination_ip_address; +NX_IP_HEADER *ip_header_ptr; + + /* 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; + } + + ip_header_ptr = (NX_IP_HEADER *) (receive_packet -> nx_packet_prepend_ptr - sizeof(NX_UDP_HEADER) - sizeof(NX_IP_HEADER)); + + /* Copy into a local variable. */ + source_ip_address = ip_header_ptr -> nx_ip_header_source_ip; + + /* Copy into a local variable. */ + destination_ip_address = ip_header_ptr -> nx_ip_header_destination_ip; + + 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 != client_ptr -> nx_sntp_server_ip_address) + { + /* 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 != client_ptr -> nx_sntp_server_ip_address) + { + + /* 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 & ~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; + } + } + + + /* 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/nx_sntp_client.h b/protocol_handlers/SNTP/nx_sntp_client.h new file mode 100644 index 0000000..83ecd14 --- /dev/null +++ b/protocol_handlers/SNTP/nx_sntp_client.h @@ -0,0 +1,773 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/* */ +/* nx_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 NX_SNTP_CLIENT_H +#define NX_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 NX_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 */ + ULONG 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. */ + ULONG nx_sntp_broadcast_time_server; /* Client's broadcast SNTP server */ + ULONG 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. */ + ULONG 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 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 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 nx_sntp_client_initialize_broadcast(NX_SNTP_CLIENT *client_ptr, ULONG multicast_server_address, ULONG broadcast_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 _nx_sntp_client_initialize_broadcast(NX_SNTP_CLIENT *client_ptr, ULONG multicast_server_address, ULONG 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 _nx_sntp_client_initialize_unicast(NX_SNTP_CLIENT *client_ptr, ULONG 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 /* NX_SNTP_CLIENT_H */ diff --git a/protocol_handlers/TELNET/nx_telnet.h b/protocol_handlers/TELNET/nx_telnet.h new file mode 100644 index 0000000..8b70b5a --- /dev/null +++ b/protocol_handlers/TELNET/nx_telnet.h @@ -0,0 +1,55 @@ +/**************************************************************************/ +/* */ +/* 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 Protocol */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* APPLICATION INTERFACE DEFINITION RELEASE */ +/* */ +/* nx_telnet.h PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file defines the NetX 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 NX_TELNET_H +#define NX_TELNET_H + +#include "nx_telnet_client.h" +#include "nx_telnet_server.h" + +#endif /* NX_TELNET_H */ diff --git a/protocol_handlers/TELNET/nx_telnet_client.c b/protocol_handlers/TELNET/nx_telnet_client.c new file mode 100644 index 0000000..23e7916 --- /dev/null +++ b/protocol_handlers/TELNET/nx_telnet_client.c @@ -0,0 +1,814 @@ +/**************************************************************************/ +/* */ +/* 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 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 "nx_telnet_client.h" + + + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_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 */ +/* */ +/* nx_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 _nx_telnet_client_connect(NX_TELNET_CLIENT *client_ptr, ULONG 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. */ + status = nx_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) +{ + +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); +} + + + + +/**************************************************************************/ +/* */ +/* 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/nx_telnet_client.h b/protocol_handlers/TELNET/nx_telnet_client.h new file mode 100644 index 0000000..a6c5870 --- /dev/null +++ b/protocol_handlers/TELNET/nx_telnet_client.h @@ -0,0 +1,179 @@ +/**************************************************************************/ +/* */ +/* 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 Client Protocol */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* APPLICATION INTERFACE DEFINITION RELEASE */ +/* */ +/* nx_telnet_client.h PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file defines the NetX 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 NX_TELNET_CLIENT_H +#define NX_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 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 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 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 _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 /* NX_TELNET_CLIENT_H */ diff --git a/protocol_handlers/TELNET/nx_telnet_server.c b/protocol_handlers/TELNET/nx_telnet_server.c new file mode 100644 index 0000000..3f21148 --- /dev/null +++ b/protocol_handlers/TELNET/nx_telnet_server.c @@ -0,0 +1,2563 @@ +/**************************************************************************/ +/* */ +/* 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 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 "nx_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) + { + + if (packet_ptr -> nx_packet_next) + { + + /* Chained packet is not supported. */ + nx_packet_release(packet_ptr); + break; + } + + /* 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/nx_telnet_server.h b/protocol_handlers/TELNET/nx_telnet_server.h new file mode 100644 index 0000000..0837a16 --- /dev/null +++ b/protocol_handlers/TELNET/nx_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 */ +/* */ +/* nx_telnet_server.h PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file defines the NetX 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 NX_TELNET_SERVER_H +#define NX_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 /* NX_TELNET_SERVER_H */ diff --git a/protocol_handlers/TFTP/nx_tftp.h b/protocol_handlers/TFTP/nx_tftp.h new file mode 100644 index 0000000..d3d99ff --- /dev/null +++ b/protocol_handlers/TFTP/nx_tftp.h @@ -0,0 +1,55 @@ +/**************************************************************************/ +/* */ +/* 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) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* APPLICATION INTERFACE DEFINITION RELEASE */ +/* */ +/* nx_tftp.h PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file defines the NetX Trivial File Transfer Protocol (TFTP) */ +/* 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_TFTP_H +#define NX_TFTP_H + +#include "nx_tftp_client.h" +#include "nx_tftp_server.h" + +#endif /* NX_TFTP_H */ diff --git a/protocol_handlers/TFTP/nx_tftp_client.c b/protocol_handlers/TFTP/nx_tftp_client.c new file mode 100644 index 0000000..23a8255 --- /dev/null +++ b/protocol_handlers/TFTP/nx_tftp_client.c @@ -0,0 +1,2081 @@ +/**************************************************************************/ +/* */ +/* 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_tftp_client.h" + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_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 */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* NX_INVALID_PARAMETERS Invalid non pointer input */ +/* */ +/* CALLS */ +/* */ +/* _nx_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 _nxe_tftp_client_create(NX_TFTP_CLIENT *tftp_client_ptr, CHAR *tftp_client_name, NX_IP *ip_ptr, 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) || + (tftp_client_ptr == NX_NULL) || (tftp_client_ptr -> nx_tftp_client_id == NX_TFTP_CLIENT_ID) || + (pool_ptr == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for valid IP version*/ + + status = _nx_tftp_client_create(tftp_client_ptr, tftp_client_name, ip_ptr, pool_ptr); + + /* Return completion status. */ + return(status); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_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 */ +/* */ +/* 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 _nx_tftp_client_create(NX_TFTP_CLIENT *tftp_client_ptr, CHAR *tftp_client_name, NX_IP *ip_ptr, NX_PACKET_POOL *pool_ptr) +{ + +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 = NX_TFTP_CLIENT_ID; + + /* Return success to the caller. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_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 */ +/* */ +/* _nx_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 _nxe_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 != NX_TFTP_CLIENT_ID)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual client delete function. */ + status = _nx_tftp_client_delete(tftp_client_ptr); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_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 _nx_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 */ +/* */ +/* _nxe_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 */ +/* */ +/* _nx_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 _nxe_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 = _nx_tftp_client_set_interface(tftp_client_ptr, if_index); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_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 _nx_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 */ +/* */ +/* _nxe_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 */ +/* */ +/* _nx_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 _nxe_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 != NX_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 = _nx_tftp_client_error_info_get(tftp_client_ptr, error_code, error_string); + + /* Return completion status. */ + return(status); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_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 _nx_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 */ +/* */ +/* _nxe_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 */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* NX_INVALID_PARAMETERS Invalid non pointer input */ +/* */ +/* CALLS */ +/* */ +/* _nx_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 _nxe_tftp_client_file_close(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 != NX_TFTP_CLIENT_ID)) + return(NX_PTR_ERROR); + + /* Check for valid IP version*/ + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual client file close function. */ + status = _nx_tftp_client_file_close(tftp_client_ptr); + + /* Return completion status. */ + return(status); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_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 */ +/* */ +/* OUTPUT */ +/* */ +/* NX_SUCCESS Successful completion status */ +/* status Actual completion status */ +/* */ +/* CALLS */ +/* */ +/* nx_packet_allocate Allocate packet for 0-length */ +/* data packet */ +/* nx_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 _nx_tftp_client_file_close(NX_TFTP_CLIENT *tftp_client_ptr) +{ + +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. */ + status = nx_packet_allocate(tftp_client_ptr -> nx_tftp_client_packet_pool_ptr, &packet_ptr, NX_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 = nx_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) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((tftp_client_ptr == NX_NULL) || (tftp_client_ptr -> nx_tftp_client_id != NX_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); +} + +/**************************************************************************/ +/* */ +/* 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) +{ +UINT status; + + + status = _nx_tftp_client_file_open_internal(tftp_client_ptr, file_name, server_ip_address, open_type, wait_option); + + + /* 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 */ +/* */ +/* 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 */ +/* nx_udp_socket_send Send UDP data packet */ +/* nx_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, ULONG server_ip_address, UINT open_type, ULONG wait_option) + +{ + +UINT status; +UINT i; +ULONG 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. */ + tftp_client_ptr -> nx_tftp_client_server_ip = server_ip_address; + + /* 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. */ + + status = nx_packet_allocate((tftp_client_ptr -> nx_tftp_client_ip_ptr) -> nx_ip_default_packet_pool, + &packet_ptr, NX_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 = nx_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 = nx_udp_source_extract(packet_ptr, &ip_address, &port); + + + /* Check for an invalid server IP address. */ + if(ip_address == tftp_client_ptr -> nx_tftp_client_server_ip) + { + matching = NX_TRUE; + } + else + { + /* 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 */ +/* */ +/* _nxe_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 */ +/* */ +/* _nx_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 _nxe_tftp_client_file_read(NX_TFTP_CLIENT *tftp_client_ptr, NX_PACKET **packet_ptr, ULONG wait_option) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((tftp_client_ptr == NX_NULL) || (tftp_client_ptr -> nx_tftp_client_id != NX_TFTP_CLIENT_ID) || + (packet_ptr == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for valid IP version*/ + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual client file read function. */ + status = _nx_tftp_client_file_read(tftp_client_ptr, packet_ptr, wait_option); + + /* Return completion status. */ + return(status); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_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 */ +/* */ +/* 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 */ +/* nx_udp_socket_send Send TFTP ACK packet */ +/* nx_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_read(NX_TFTP_CLIENT *tftp_client_ptr, NX_PACKET **packet_ptr, ULONG wait_option) +{ + +UCHAR *buffer_ptr; +UINT status; +ULONG 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. */ + nx_udp_source_extract(*packet_ptr, &ip_address, &port); + + /* Check for an invalid server IP address. */ + if(ip_address == tftp_client_ptr -> nx_tftp_client_server_ip) + { + matching = NX_TRUE; + } + else + { + + /* 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. */ + + status = nx_packet_allocate(tftp_client_ptr -> nx_tftp_client_packet_pool_ptr, &ack_packet, NX_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 = nx_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 */ +/* */ +/* _nxe_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 */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* NX_INVALID_PARAMETERS Invalid non pointer input */ +/* */ +/* CALLS */ +/* */ +/* _nx_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 _nxe_tftp_client_file_write(NX_TFTP_CLIENT *tftp_client_ptr, NX_PACKET *packet_ptr, ULONG wait_option) +{ + +UINT status; + + + /* Check for invalid input pointers. */ + if ((tftp_client_ptr == NX_NULL) || (tftp_client_ptr -> nx_tftp_client_id != NX_TFTP_CLIENT_ID) || + (packet_ptr == NX_NULL)) + return(NX_PTR_ERROR); + + /* Check for valid IP version*/ + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual client file write function. */ + status = _nx_tftp_client_file_write(tftp_client_ptr, packet_ptr, wait_option); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_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 */ +/* */ +/* 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 */ +/* nx_udp_socket_send Send TFTP ACK packet */ +/* nx_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 _nx_tftp_client_file_write(NX_TFTP_CLIENT *tftp_client_ptr, NX_PACKET *packet_ptr, ULONG wait_option) +{ + +UCHAR *buffer_ptr; +UINT status; +ULONG length; +ULONG 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 = nx_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. */ + nx_udp_source_extract(packet_ptr, &ip_address, &port); + + /* Check for an invalid server IP address. */ + + if(ip_address == tftp_client_ptr -> nx_tftp_client_server_ip) + { + matching = NX_TRUE; + } + else + { + /* 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 */ +/* */ +/* _nxe_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 */ +/* */ +/* OUTPUT */ +/* */ +/* status Completion status */ +/* NX_PTR_ERROR Invalid pointer input */ +/* NX_INVALID_PARAMETERS Invalid non pointer input */ +/* */ +/* CALLS */ +/* */ +/* _nx_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 _nxe_tftp_client_packet_allocate(NX_PACKET_POOL *pool_ptr, NX_PACKET **packet_ptr, ULONG wait_option) +{ + +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*/ + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual client packet allocate function. */ + status = _nx_tftp_client_packet_allocate(pool_ptr, packet_ptr, wait_option); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_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 */ +/* */ +/* 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 _nx_tftp_client_packet_allocate(NX_PACKET_POOL *pool_ptr, NX_PACKET **packet_ptr, ULONG wait_option) +{ + +UINT status; + + + /* Allocate a new packet. */ + status = nx_packet_allocate(pool_ptr, packet_ptr, NX_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/nx_tftp_client.h b/protocol_handlers/TFTP/nx_tftp_client.h new file mode 100644 index 0000000..5e8ccc9 --- /dev/null +++ b/protocol_handlers/TFTP/nx_tftp_client.h @@ -0,0 +1,287 @@ +/**************************************************************************/ +/* */ +/* 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 */ +/* */ +/* nx_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 NX_TFTP_CLIENT_H +#define NX_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 NX_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 */ + ULONG 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 TFTP service. */ +#define nx_tftp_client_create _nx_tftp_client_create +#define nx_tftp_client_packet_allocate _nx_tftp_client_packet_allocate +#define nx_tftp_client_delete _nx_tftp_client_delete +#define nx_tftp_client_error_info_get _nx_tftp_client_error_info_get +#define nx_tftp_client_file_close _nx_tftp_client_file_close +#define nx_tftp_client_file_read _nx_tftp_client_file_read +#define nx_tftp_client_file_write _nx_tftp_client_file_write +#define nx_tftp_client_set_interface _nx_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 service. */ +#define nx_tftp_client_create _nxe_tftp_client_create +#define nx_tftp_client_packet_allocate _nxe_tftp_client_packet_allocate +#define nx_tftp_client_delete _nxe_tftp_client_delete +#define nx_tftp_client_error_info_get _nxe_tftp_client_error_info_get +#define nx_tftp_client_file_close _nxe_tftp_client_file_close +#define nx_tftp_client_file_read _nxe_tftp_client_file_read +#define nx_tftp_client_file_write _nxe_tftp_client_file_write +#define nx_tftp_client_set_interface _nxe_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 nx_tftp_client_create(NX_TFTP_CLIENT *tftp_client_ptr, CHAR *tftp_client_name, NX_IP *ip_ptr, NX_PACKET_POOL *pool_ptr); +UINT nx_tftp_client_delete(NX_TFTP_CLIENT *tftp_client_ptr); +UINT nx_tftp_client_error_info_get(NX_TFTP_CLIENT *tftp_client_ptr, UINT *error_code, CHAR **error_string); +UINT nx_tftp_client_file_close(NX_TFTP_CLIENT *tftp_client_ptr); +UINT nx_tftp_client_file_read(NX_TFTP_CLIENT *tftp_client_ptr, NX_PACKET **packet_ptr, ULONG wait_option); +UINT nx_tftp_client_file_write(NX_TFTP_CLIENT *tftp_client_ptr, NX_PACKET *packet_ptr, ULONG wait_option); +UINT nx_tftp_client_packet_allocate(NX_PACKET_POOL *pool_ptr, NX_PACKET **packet_ptr, ULONG wait_option); +UINT nx_tftp_client_set_interface(NX_TFTP_CLIENT *tftp_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 _nxe_tftp_client_create(NX_TFTP_CLIENT *tftp_client_ptr, CHAR *tftp_client_name, NX_IP *ip_ptr, NX_PACKET_POOL *pool_ptr); +UINT _nx_tftp_client_create(NX_TFTP_CLIENT *tftp_client_ptr, CHAR *tftp_client_name, NX_IP *ip_ptr, NX_PACKET_POOL *pool_ptr); +UINT _nxe_tftp_client_delete(NX_TFTP_CLIENT *tftp_client_ptr); +UINT _nx_tftp_client_delete(NX_TFTP_CLIENT *tftp_client_ptr); +UINT _nxe_tftp_client_error_info_get(NX_TFTP_CLIENT *tftp_client_ptr, UINT *error_code, CHAR **error_string); +UINT _nx_tftp_client_error_info_get(NX_TFTP_CLIENT *tftp_client_ptr, UINT *error_code, CHAR **error_string); +UINT _nxe_tftp_client_file_close(NX_TFTP_CLIENT *tftp_client_ptr); +UINT _nx_tftp_client_file_close(NX_TFTP_CLIENT *tftp_client_ptr); +UINT _nxe_tftp_client_file_read(NX_TFTP_CLIENT *tftp_client_ptr, NX_PACKET **packet_ptr, ULONG wait_option); +UINT _nx_tftp_client_file_read(NX_TFTP_CLIENT *tftp_client_ptr, NX_PACKET **packet_ptr, ULONG wait_option); +UINT _nxe_tftp_client_file_write(NX_TFTP_CLIENT *tftp_client_ptr, NX_PACKET *packet_ptr, ULONG wait_option); +UINT _nx_tftp_client_file_write(NX_TFTP_CLIENT *tftp_client_ptr, NX_PACKET *packet_ptr, ULONG wait_option); +UINT _nxe_tftp_client_packet_allocate(NX_PACKET_POOL *pool_ptr, NX_PACKET **packet_ptr, ULONG wait_option); +UINT _nx_tftp_client_packet_allocate(NX_PACKET_POOL *pool_ptr, NX_PACKET **packet_ptr, ULONG wait_option); +UINT _nxe_tftp_client_set_interface(NX_TFTP_CLIENT *tftp_client_ptr, UINT if_index); +UINT _nx_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, ULONG server_ip_address, UINT open_type, ULONG wait_option); + + +/* Determine if a C++ compiler is being used. If so, complete the standard + C conditional started above. */ +#ifdef __cplusplus + } +#endif + +#endif /* NX_TFTP_CLIENT_H */ diff --git a/protocol_handlers/TFTP/nx_tftp_server.c b/protocol_handlers/TFTP/nx_tftp_server.c new file mode 100644 index 0000000..a42847c --- /dev/null +++ b/protocol_handlers/TFTP/nx_tftp_server.c @@ -0,0 +1,2718 @@ +/**************************************************************************/ +/* */ +/* 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) 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 "nx_tftp_server.h" + +/* Bring in externs for caller checking code. */ + +NX_CALLER_CHECKING_EXTERNS + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_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 */ +/* */ +/* _nx_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 _nxe_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 == NX_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 = _nx_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 */ +/* */ +/* _nx_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 _nx_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 = NX_TFTP_SERVER_ID; + + /* Return successful completion. */ + return(NX_SUCCESS); +} + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_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 */ +/* */ +/* _nx_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 _nxe_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 != NX_TFTP_SERVER_ID)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual server delete function. */ + status = _nx_tftp_server_delete(tftp_server_ptr); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_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 _nx_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_port != 0) && + (client_request_ptr -> nx_tftp_client_request_ip_address != 0)) + { + /* No, need to close the file on this client! */ + fx_file_close(&(client_request_ptr -> nx_tftp_client_request_file)); + } + + /* Increment the pointer into the client request list. */ + client_request_ptr++; + i++; + } + + /* Return successful completion. */ + return(NX_SUCCESS); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nxe_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 */ +/* */ +/* _nx_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 _nxe_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 != NX_TFTP_SERVER_ID)) + return(NX_PTR_ERROR); + + /* Call actual server start function. */ + status = _nx_tftp_server_start(tftp_server_ptr); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_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 _nx_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 */ +/* */ +/* _nxe_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 */ +/* */ +/* _nx_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 _nxe_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 != NX_TFTP_SERVER_ID)) + return(NX_PTR_ERROR); + + /* Check for appropriate caller. */ + NX_THREADS_ONLY_CALLER_CHECKING + + /* Call actual server delete function. */ + status = _nx_tftp_server_stop(tftp_server_ptr); + + /* Return completion status. */ + return(status); +} + + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_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 _nx_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) +{ +ULONG 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. */ + nx_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. */ + client_request_ptr -> nx_tftp_client_request_ip_address = ip_address; + + + 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. */ + status = nx_packet_allocate(server_ptr -> nx_tftp_server_packet_pool_ptr, &new_packet, NX_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. */ + 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 = nx_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) +{ +ULONG 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. */ + nx_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. */ + status = nx_packet_allocate(server_ptr -> nx_tftp_server_packet_pool_ptr, &new_packet, NX_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. */ + client_request_ptr -> nx_tftp_client_request_ip_address = ip_address; + + + 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 = nx_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) +{ + +ULONG 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. */ + nx_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. */ + + /* 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; + } + + /* 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) +{ + +ULONG ip_address; +UINT port; +USHORT block_number; +UCHAR *buffer_ptr; +NX_TFTP_CLIENT_REQUEST *client_request_ptr; + + + /* Extract the source IP and port numbers. */ + nx_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. */ + status = nx_packet_allocate(server_ptr -> nx_tftp_server_packet_pool_ptr, &new_packet, NX_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 = nx_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. */ + status = nx_packet_allocate(server_ptr -> nx_tftp_server_packet_pool_ptr, &new_packet, NX_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 = nx_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; +ULONG 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. */ + + nx_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, ULONG 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 + { + if((client_request_ptr -> nx_tftp_client_request_port == port) && + (client_request_ptr -> nx_tftp_client_request_ip_address == ip_address )) + { + /* Yes, they match. */ + break; + } + } + } + + /* 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, ULONG 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. */ + status = nx_packet_allocate(server_ptr -> nx_tftp_server_packet_pool_ptr, &new_packet, NX_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 = nx_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/nx_tftp_server.h b/protocol_handlers/TFTP/nx_tftp_server.h new file mode 100644 index 0000000..a67a69a --- /dev/null +++ b/protocol_handlers/TFTP/nx_tftp_server.h @@ -0,0 +1,372 @@ +/**************************************************************************/ +/* */ +/* 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) Server */ +/** */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + +/**************************************************************************/ +/* */ +/* APPLICATION INTERFACE DEFINITION RELEASE */ +/* */ +/* nx_tftp_server.h PORTABLE C */ +/* 6.0 */ +/* AUTHOR */ +/* */ +/* Yuxin Zhou, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This file defines the NetX Trivial File Transfer Protocol (TFTP) */ +/* 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_TFTP_SERVER_H +#define NX_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 NX_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 */ + ULONG 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 */ +#define nx_tftp_server_create _nx_tftp_server_create +#define nx_tftp_server_delete _nx_tftp_server_delete +#define nx_tftp_server_start _nx_tftp_server_start +#define nx_tftp_server_stop _nx_tftp_server_stop + +#else + +/* Services with error checking. */ + +/* NetX TFTP services with error checking */ +#define nx_tftp_server_create _nxe_tftp_server_create +#define nx_tftp_server_delete _nxe_tftp_server_delete +#define nx_tftp_server_start _nxe_tftp_server_start +#define nx_tftp_server_stop _nxe_tftp_server_stop + +#endif /* NX_DISABLE_ERROR_CHECKING */ + +/* Define the prototypes accessible to the application software. */ + +UINT nx_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 nx_tftp_server_delete(NX_TFTP_SERVER *tftp_server_ptr); +UINT nx_tftp_server_start(NX_TFTP_SERVER *tftp_server_ptr); +UINT nx_tftp_server_stop(NX_TFTP_SERVER *tftp_server_ptr); + +#else + +/* TFTP source code is being compiled, do not perform any API mapping. */ + +UINT _nxe_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 _nx_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 _nxe_tftp_server_delete(NX_TFTP_SERVER *tftp_server_ptr); +UINT _nx_tftp_server_delete(NX_TFTP_SERVER *tftp_server_ptr); +UINT _nxe_tftp_server_start(NX_TFTP_SERVER *tftp_server_ptr); +UINT _nx_tftp_server_start(NX_TFTP_SERVER *tftp_server_ptr); +UINT _nxe_tftp_server_stop(NX_TFTP_SERVER *tftp_server_ptr); +UINT _nx_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, ULONG ip_address); +VOID _nx_tftp_server_send_error(NX_TFTP_SERVER *server_ptr, ULONG 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 /* NX_TFTP_SERVER_H */ diff --git a/rebuild.sh b/rebuild.sh new file mode 100755 index 0000000..126135d --- /dev/null +++ b/rebuild.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +# Use paths relative to this script's location +SCRIPT=$(readlink -f "$0") +BASEDIR=$(dirname "$SCRIPT") + +# If you want to build into a different directory, change this variable +BUILDDIR="$BASEDIR/build" + +# Create our build folder if required and clear it +mkdir -p $BUILDDIR +rm -rf $BUILDDIR/* + +# Generate the build system +cmake -B"$BUILDDIR" -DCMAKE_TOOLCHAIN_FILE=$BASEDIR/cmake/arm-gcc-toolchain.cmake $BASEDIR + +# And then do the build +cmake --build $BUILDDIR diff --git a/samples/demo_netx_auto_ip.c b/samples/demo_netx_auto_ip.c new file mode 100644 index 0000000..ac68c3c --- /dev/null +++ b/samples/demo_netx_auto_ip.c @@ -0,0 +1,333 @@ +/* This is a small demo of the NetX TCP/IP stack using the AUTO IP module. */ + +#include "tx_api.h" +#include "nx_api.h" +#include "nx_auto_ip.h" + + +#define DEMO_STACK_SIZE 4096 +#define DEMO_DATA "ABCDEFGHIJKLMNOPQRSTUVWXYZ " + + +/* Define the ThreadX and NetX object control blocks... */ + +TX_THREAD thread_0; +TX_THREAD thread_1; +NX_PACKET_POOL pool_0; +NX_IP ip_0; +NX_IP ip_1; +NX_UDP_SOCKET socket_0; +NX_UDP_SOCKET socket_1; + + +/* Define the AUTO IP structures for each IP instance. */ + +NX_AUTO_IP auto_ip_0; +NX_AUTO_IP auto_ip_1; + + +/* Define the counters used in the demo application... */ + +ULONG thread_0_counter; +ULONG thread_1_counter; +ULONG address_changes; +ULONG error_counter; + + +/* Define thread prototypes. */ + +void thread_0_entry(ULONG thread_input); +void thread_1_entry(ULONG thread_input); +void ip_address_changed(NX_IP *ip_ptr, VOID *auto_ip_address); + +void _nx_ram_network_driver(struct NX_IP_DRIVER_STRUCT *driver_req); + + +/* Define main entry point. */ + +int main() +{ + + /* Enter the ThreadX kernel. */ + tx_kernel_enter(); +} + + +/* Define what the initial system looks like. */ + +void tx_application_define(void *first_unused_memory) +{ + +CHAR *pointer; +UINT status; + + + /* Setup the working pointer. */ + pointer = (CHAR *) first_unused_memory; + + /* Create the main thread. */ + tx_thread_create(&thread_0, "thread 0", thread_0_entry, 0, + pointer, DEMO_STACK_SIZE, + 16, 16, 1, TX_AUTO_START); + + pointer = pointer + DEMO_STACK_SIZE; + + /* Create the main thread. */ + tx_thread_create(&thread_1, "thread 1", thread_1_entry, 0, + pointer, DEMO_STACK_SIZE, + 16, 16, 1, TX_AUTO_START); + pointer = pointer + DEMO_STACK_SIZE; + + /* Initialize the NetX system. */ + nx_system_initialize(); + + /* Create a packet pool. */ + status = nx_packet_pool_create(&pool_0, "NetX Main Packet Pool", 256, pointer, 4096); + pointer = pointer + 4096; + + if (status) + error_counter++; + + /* Create an IP instance. */ + status = nx_ip_create(&ip_0, "NetX IP Instance 0", IP_ADDRESS(0, 0, 0, 0), 0xFFFFFF00UL, &pool_0, _nx_ram_network_driver, + pointer, 4096, 1); + pointer = pointer + 4096; + + /* Create another IP instance. */ + status += nx_ip_create(&ip_1, "NetX IP Instance 1", IP_ADDRESS(0, 0, 0, 0), 0xFFFFFF00UL, &pool_0, _nx_ram_network_driver, + pointer, 4096, 1); + pointer = pointer + 4096; + + if (status) + error_counter++; + + /* Enable ARP and supply ARP cache memory for IP Instance 0. */ + status = nx_arp_enable(&ip_0, (void *) pointer, 1024); + pointer = pointer + 1024; + + /* Enable ARP and supply ARP cache memory for IP Instance 1. */ + status += nx_arp_enable(&ip_1, (void *) pointer, 1024); + pointer = pointer + 1024; + + /* Check ARP enable status. */ + if (status) + error_counter++; + + /* Enable UDP processing for both IP instances. */ + status = nx_udp_enable(&ip_0); + status += nx_udp_enable(&ip_1); + + /* Check UDP enable status. */ + if (status) + error_counter++; + + /* Create the AutoIP instance for each IP instance. */ + status = nx_auto_ip_create(&auto_ip_0, "AutoIP 0", &ip_0, pointer, 4096, 1); + pointer = pointer + 4096; + status += nx_auto_ip_create(&auto_ip_1, "AutoIP 1", &ip_1, pointer, 4096, 1); + pointer = pointer + 4096; + + /* Check AutoIP create status. */ + if (status) + error_counter++; + + /* Start both AutoIP instances. */ + status = nx_auto_ip_start(&auto_ip_0, 0 /*IP_ADDRESS(169,254,254,255)*/); + status += nx_auto_ip_start(&auto_ip_1, 0 /*IP_ADDRESS(169,254,254,255)*/); + + /* Check AutoIP start status. */ + if (status) + error_counter++; + + /* Register an IP address change function for each IP instance. */ + status = nx_ip_address_change_notify(&ip_0, ip_address_changed, (void *) &auto_ip_0); + status += nx_ip_address_change_notify(&ip_1, ip_address_changed, (void *) &auto_ip_1); + + /* Check IP address change notify status. */ + if (status) + error_counter++; +} + + + +/* Define the test threads. */ + +void thread_0_entry(ULONG thread_input) +{ + +UINT status; +ULONG actual_status; +NX_PACKET *my_packet; + + NX_PARAMETER_NOT_USED(thread_input); + + /* Wait for IP address to be resolved. */ + do + { + + /* Call IP status check routine. */ + status = nx_ip_status_check(&ip_0, NX_IP_ADDRESS_RESOLVED, &actual_status, 10 * NX_IP_PERIODIC_RATE); + + } while (status != NX_SUCCESS); + + /* Create a UDP socket. */ + status = nx_udp_socket_create(&ip_0, &socket_0, "Socket 0", NX_IP_NORMAL, NX_FRAGMENT_OKAY, 0x80, 5); + + /* Check status. */ + if (status) + { + error_counter++; + return; + } + + /* Bind the UDP socket to the IP port. */ + status = nx_udp_socket_bind(&socket_0, 0x88, TX_WAIT_FOREVER); + + /* Check status. */ + if (status) + { + error_counter++; + return; + } + + /* Disable checksum logic for this socket. */ + nx_udp_socket_checksum_disable(&socket_0); + + /* Let other threads run again. */ + tx_thread_relinquish(); + + while(1) + { + + + /* Allocate a packet. */ + status = nx_packet_allocate(&pool_0, &my_packet, NX_UDP_PACKET, TX_WAIT_FOREVER); + + /* Check status. */ + if (status != NX_SUCCESS) + break; + + /* Write ABCs into the packet payload! */ + memcpy(my_packet -> nx_packet_prepend_ptr, DEMO_DATA, sizeof(DEMO_DATA)); + + /* Adjust the write pointer. */ + my_packet -> nx_packet_length = sizeof(DEMO_DATA); + my_packet -> nx_packet_append_ptr = my_packet -> nx_packet_prepend_ptr + sizeof(DEMO_DATA); + + /* Send the UDP packet. */ + status = nx_udp_socket_send(&socket_0, my_packet, ip_1.nx_ip_address, 0x89); + + /* Check status. */ + if (status != NX_SUCCESS) + { + error_counter++; + break; + } + + /* Increment thread 0's counter. */ + thread_0_counter++; + + /* Relinquish to thread 1. */ + tx_thread_relinquish(); + } +} + + +void thread_1_entry(ULONG thread_input) +{ + +UINT status; +ULONG actual_status; +NX_PACKET *my_packet; + + NX_PARAMETER_NOT_USED(thread_input); + + /* Wait for IP address to be resolved. */ + do + { + + /* Call IP status check routine. */ + status = nx_ip_status_check(&ip_1, NX_IP_ADDRESS_RESOLVED, &actual_status, 10 * NX_IP_PERIODIC_RATE); + + } while (status != NX_SUCCESS); + + /* Create a UDP socket. */ + status = nx_udp_socket_create(&ip_1, &socket_1, "Socket 1", NX_IP_NORMAL, NX_FRAGMENT_OKAY, 0x80, 5); + + /* Check status. */ + if (status) + { + error_counter++; + return; + } + + /* Bind the UDP socket to the IP port. */ + status = nx_udp_socket_bind(&socket_1, 0x89, TX_WAIT_FOREVER); + + /* Check status. */ + if (status) + { + error_counter++; + return; + } + + while(1) + { + + + /* Receive a UDP packet. */ + status = nx_udp_socket_receive(&socket_1, &my_packet, TX_WAIT_FOREVER); + + /* Check status. */ + if (status != NX_SUCCESS) + break; + + /* Release the packet. */ + status = nx_packet_release(my_packet); + + /* Check status. */ + if (status != NX_SUCCESS) + break; + + /* Increment thread 1's counter. */ + thread_1_counter++; + } +} + +void ip_address_changed(NX_IP *ip_ptr, VOID *auto_ip_address) +{ + +ULONG ip_address; +ULONG network_mask; +NX_AUTO_IP *auto_ip_ptr; + + + /* Setup pointer to auto IP instance. */ + auto_ip_ptr = (NX_AUTO_IP *) auto_ip_address; + + /* Pickup the current IP address. */ + nx_ip_address_get(ip_ptr, &ip_address, &network_mask); + + /* Determine if the IP address has changed back to zero. If so, make sure the + AutoIP instance is started. */ + if (ip_address == 0) + { + + /* Get the last AutoIP address for this node. */ + nx_auto_ip_get_address(auto_ip_ptr, &ip_address); + + /* Start this AutoIP instance. */ + nx_auto_ip_start(auto_ip_ptr, ip_address); + } + + /* Determine if the IP address has transitioned to a non local IP address. */ + else if ((ip_address & 0xFFFF0000UL) != IP_ADDRESS(169, 254, 0, 0)) + { + + /* Stop the AutoIP processing. */ + nx_auto_ip_stop(auto_ip_ptr); + } + + /* Increment a counter. */ + address_changes++; +} diff --git a/samples/demo_netx_dhcp.c b/samples/demo_netx_dhcp.c new file mode 100644 index 0000000..ca058fe --- /dev/null +++ b/samples/demo_netx_dhcp.c @@ -0,0 +1,331 @@ +/* This is a small demo of DHCP Client for the high-performance NetX IP stack. */ + +#include "tx_api.h" +#include "nx_api.h" +#include "nx_dhcp.h" +#include "nx_dhcp_server.h" + +#define DEMO_STACK_SIZE 4096 +#define NX_PACKET_SIZE 1536 +#define NX_PACKET_POOL_SIZE NX_PACKET_SIZE * 8 + +#define NX_DHCP_SERVER_IP_ADDRESS_0 IP_ADDRESS(10,0,0,1) +#define START_IP_ADDRESS_LIST_0 IP_ADDRESS(10,0,0,10) +#define END_IP_ADDRESS_LIST_0 IP_ADDRESS(10,0,0,19) + +#define NX_DHCP_SUBNET_MASK_0 IP_ADDRESS(255,255,255,0) +#define NX_DHCP_DEFAULT_GATEWAY_0 IP_ADDRESS(10,0,0,1) +#define NX_DHCP_DNS_SERVER_0 IP_ADDRESS(10,0,0,1) + +/* Define the interface index. */ +#define NX_DHCP_INTERFACE_INDEX 0 + +/* If defined, the host requests a (previous) client IP address. */ +/* +#define REQUEST_CLIENT_IP +*/ + +#ifdef REQUEST_CLIENT_IP +/* Request a specific IP address using the DHCP client address option. */ +#define NX_DHCP_CLIENT_IP_ADDRESS IP_ADDRESS(10,0,0,18) + +/* If defined NX_TRUE, the client requests to jump to the boot state and skip the DISCOVER message. */ +#define SKIP_DISCOVER_MESSAGE NX_TRUE +#endif + + + +/* Define the ThreadX and NetX object control blocks... */ +TX_THREAD client_thread; +NX_PACKET_POOL client_pool; +NX_IP client_ip; +NX_DHCP dhcp_client; + +TX_THREAD server_thread; +NX_PACKET_POOL server_pool; +NX_IP server_ip; +NX_DHCP_SERVER dhcp_server; + +/* Define the counters used in the demo application... */ + +ULONG client_thread_counter; +ULONG state_changes; +ULONG error_counter; +CHAR *pointer; + +UCHAR message[50] = "My Ping Request!" ; + + +/* Define thread prototypes. */ + +void server_thread_entry(ULONG thread_input); +void client_thread_entry(ULONG thread_input); +void dhcp_state_change(NX_DHCP *dhcp_ptr, UCHAR new_state); + +/******** Optionally substitute your Ethernet driver here. ***********/ +void _nx_ram_network_driver(struct NX_IP_DRIVER_STRUCT *driver_req); + +/* Define main entry point. */ + +int main() +{ + + /* Enter the ThreadX kernel. */ + tx_kernel_enter(); + return 0; +} + + +/* Define what the initial system looks like. */ + +void tx_application_define(void *first_unused_memory) +{ + +UINT status; + + + /* Setup the working pointer. */ + pointer = (CHAR *) first_unused_memory; + + /* Create the client thread. */ + tx_thread_create(&client_thread, "thread client", client_thread_entry, 0, + pointer, DEMO_STACK_SIZE, + 4, 4, TX_NO_TIME_SLICE, TX_AUTO_START); + pointer = pointer + DEMO_STACK_SIZE; + + /* Create the server thread. */ + tx_thread_create(&server_thread, "thread server", server_thread_entry, 0, + pointer, DEMO_STACK_SIZE, + 3, 3, TX_NO_TIME_SLICE, TX_AUTO_START); + pointer = pointer + DEMO_STACK_SIZE; + + /* Initialize the NetX system. */ + nx_system_initialize(); + + /* Create the client packet pool. */ + status = nx_packet_pool_create(&client_pool, "NetX Main Packet Pool", 1024, pointer, NX_PACKET_POOL_SIZE); + pointer = pointer + NX_PACKET_POOL_SIZE; + + /* Check for pool creation error. */ + if (status) + return; + + /* Create the server packet pool. */ + status = nx_packet_pool_create(&server_pool, "NetX Main Packet Pool", 1024, pointer, NX_PACKET_POOL_SIZE); + pointer = pointer + NX_PACKET_POOL_SIZE; + + /* Check for pool creation error. */ + if (status) + return; + + /* Create an IP instance for the DHCP Client. */ + status = nx_ip_create(&client_ip, "DHCP Client", IP_ADDRESS(0, 0, 0, 0), 0xFFFFFF00UL, &client_pool, _nx_ram_network_driver, pointer, 2048, 1); + pointer = pointer + 2048; + + /* Check for IP create errors. */ + if (status) + return; + + /* Create an IP instance for the DHCP Server. */ + status = nx_ip_create(&server_ip, "DHCP Server", NX_DHCP_SERVER_IP_ADDRESS_0, 0xFFFFFF00UL, &server_pool, _nx_ram_network_driver, pointer, 2048, 1); + pointer = pointer + 2048; + + /* Check for IP create errors. */ + if (status) + return; + + /* Enable ARP and supply ARP cache memory for DHCP Client IP. */ + status = nx_arp_enable(&client_ip, (void *) pointer, 1024); + pointer = pointer + 1024; + + /* Enable ARP and supply ARP cache memory for DHCP Server IP. */ + status += nx_arp_enable(&server_ip, (void *) pointer, 1024); + pointer = pointer + 1024; + + /* Check for ARP enable errors. */ + if (status) + return; + + /* Enable UDP traffic. */ + status = nx_udp_enable(&client_ip); + status += nx_udp_enable(&server_ip); + + /* Check for UDP enable errors. */ + if (status) + return; + + /* Enable ICMP. */ + status = nx_icmp_enable(&client_ip); + status += nx_icmp_enable(&server_ip); + + /* Check for errors. */ + if (status) + return; +} + +/* Define the server thread. */ + +void server_thread_entry(ULONG thread_input) +{ + +UINT status; +UINT addresses_added; + + NX_PARAMETER_NOT_USED(thread_input); + + /* Modified the mtu size to avoid fragmenting the DHCP packet since the default mtu size is 128 in _nx_ram_network_driver. */ + server_ip.nx_ip_interface[NX_DHCP_INTERFACE_INDEX].nx_interface_ip_mtu_size = 1500; + + /* Create the DHCP Server. */ + status = nx_dhcp_server_create(&dhcp_server, &server_ip, pointer, DEMO_STACK_SIZE, + "DHCP Server", &server_pool); + pointer = pointer + DEMO_STACK_SIZE; + + /* Check for errors creating the DHCP Server. */ + if (status) + return; + + /* Load the assignable DHCP IP addresses for the first interface. */ + status = nx_dhcp_create_server_ip_address_list(&dhcp_server, NX_DHCP_INTERFACE_INDEX, START_IP_ADDRESS_LIST_0, + END_IP_ADDRESS_LIST_0, &addresses_added); + + /* Check for errors creating the list. */ + if (status) + return; + + /* Verify all the addresses were added to the list. */ + if (addresses_added != 10) + return; + + /* Set the interface network parameters. */ + status = nx_dhcp_set_interface_network_parameters(&dhcp_server, NX_DHCP_INTERFACE_INDEX, NX_DHCP_SUBNET_MASK_0, + NX_DHCP_DEFAULT_GATEWAY_0, NX_DHCP_DNS_SERVER_0); + + /* Check for errors setting network parameters. */ + if (status) + return; + + /* Start DHCP Server task. */ + status = nx_dhcp_server_start(&dhcp_server); + + /* Check for errors starting up the DHCP server. */ + if (status) + return; +} + + +/* Define the client thread. */ + +void client_thread_entry(ULONG thread_input) +{ + +UINT status; +UINT actual_status; +UINT length; +UINT ping = NX_TRUE; +UINT run_dhcp_client = NX_TRUE; +NX_PACKET *my_packet; + + NX_PARAMETER_NOT_USED(thread_input); + + /* Modified the mtu size to avoid fragmenting the DHCP packet since the default mtu size is 128 in _nx_ram_network_driver. */ + client_ip.nx_ip_interface[NX_DHCP_INTERFACE_INDEX].nx_interface_ip_mtu_size = 1500; + + /* Create the DHCP instance. */ + status = nx_dhcp_create(&dhcp_client, &client_ip, "DHCP-CLIENT"); + if (status) + return; + +#ifdef REQUEST_CLIENT_IP + /* Request a specific IP address using the DHCP client address option. */ + status = nx_dhcp_request_client_ip(&dhcp_client, NX_DHCP_CLIENT_IP_ADDRESS, SKIP_DISCOVER_MESSAGE); + if (status) + error_counter++; +#endif + + /* Register state change variable. */ + status = nx_dhcp_state_change_notify(&dhcp_client, dhcp_state_change); + if (status) + error_counter++; + + /* Start the DHCP Client. */ + nx_dhcp_start(&dhcp_client); + while(run_dhcp_client) + { + + /* Wait for DHCP to assign the IP address. */ + do + { + + /* Check for address resolution. */ + status = nx_ip_status_check(&client_ip, NX_IP_ADDRESS_RESOLVED, (ULONG *) &actual_status, NX_IP_PERIODIC_RATE); + + /* Check status. */ + if (status) + { + /* wait a bit. */ + tx_thread_sleep(NX_IP_PERIODIC_RATE); + } + + } while (status != NX_SUCCESS); + + length = sizeof(message); + + while(ping) + { + + /* Send pings to another host on the network... */ + status = nx_icmp_ping(&client_ip, NX_DHCP_SERVER_IP_ADDRESS_0, (CHAR *)message, length, &my_packet, NX_IP_PERIODIC_RATE); + if (status) + error_counter++; + else + nx_packet_release(my_packet); + + /* Increment counter. */ + client_thread_counter++; + + /* Sleep for a few ticks... */ + tx_thread_sleep(NX_IP_PERIODIC_RATE); + } + + /* Use this API to send a message to the server, e.g. a DECLINE if the IP address is owned by another host. + nx_dhcp_send_request(&dhcp_client, NX_DHCP_TYPE_DHCPDECLINE); + */ + + /* Use this API to release an IP address if the host is switching networks or running the host through DHCP cycles. + nx_dhcp_release(&dhcp_client); + */ + + /* Stopping the DHCP client. */ + nx_dhcp_stop(&dhcp_client); + + tx_thread_sleep(NX_IP_PERIODIC_RATE); + + /* Use this API to clear the network parameters and restart the client in the INIT state. */ + nx_dhcp_reinitialize(&dhcp_client); + + /* Resume the DHCP client thread. */ + nx_dhcp_start(&dhcp_client); + + /* Ok to resume ping attempts. */ + ping = NX_TRUE; + } + + /* All done. Return resources to NetX and ThreadX. */ + nx_dhcp_delete(&dhcp_client); + + return; +} + + +void dhcp_state_change(NX_DHCP *dhcp_ptr, UCHAR new_state) +{ + + NX_PARAMETER_NOT_USED(dhcp_ptr); + NX_PARAMETER_NOT_USED(new_state); + + /* Increment state changes counter. */ + state_changes++; + + return; +} diff --git a/samples/demo_netx_dns.c b/samples/demo_netx_dns.c new file mode 100644 index 0000000..86cdc2e --- /dev/null +++ b/samples/demo_netx_dns.c @@ -0,0 +1,601 @@ +/* This is a small demo of DNS Client for the high-performance NetX TCP/IP stack. */ + +#include "tx_api.h" +#include "nx_api.h" +#include "nx_udp.h" +#include "nx_dns.h" + + +#define DEMO_STACK_SIZE 4096 + +#define NX_PACKET_PAYLOAD 1536 +#define NX_PACKET_POOL_SIZE 30 * NX_PACKET_PAYLOAD +#define LOCAL_CACHE_SIZE 2048 + +/* Define the ThreadX and NetX object control blocks... */ + +NX_DNS client_dns; +TX_THREAD client_thread; +NX_IP client_ip; +NX_PACKET_POOL main_pool; +#ifdef NX_DNS_CLIENT_USER_CREATE_PACKET_POOL +NX_PACKET_POOL client_pool; +#endif +UCHAR local_cache[LOCAL_CACHE_SIZE]; + +UINT error_counter = 0; + + +#define CLIENT_ADDRESS IP_ADDRESS(192,168,0,11) +#define DNS_SERVER_ADDRESS IP_ADDRESS(192,168,0,1) + +/* Define thread prototypes. */ + +void thread_client_entry(ULONG thread_input); + +/***** Substitute your ethernet driver entry function here *********/ +extern VOID _nx_ram_network_driver(NX_IP_DRIVER *driver_req_ptr); + + +/* Define main entry point. */ + +int main() +{ + + /* Enter the ThreadX kernel. */ + tx_kernel_enter(); +} + + +/* Define what the initial system looks like. */ + +void tx_application_define(void *first_unused_memory) +{ + +CHAR *pointer; +UINT status; + + + /* Setup the working pointer. */ + pointer = (CHAR *) first_unused_memory; + + /* Create the main thread. */ + tx_thread_create(&client_thread, "Client thread", thread_client_entry, 0, + pointer, DEMO_STACK_SIZE, 4, 4, TX_NO_TIME_SLICE, TX_AUTO_START); + + pointer = pointer + DEMO_STACK_SIZE; + + /* Initialize the NetX system. */ + nx_system_initialize(); + +#ifdef NX_DNS_CLIENT_USER_CREATE_PACKET_POOL + + /* Create the packet pool for the DNS Client to send packets. + + If the DNS Client is configured for letting the host application create + the DNS packet pool, (see NX_DNS_CLIENT_USER_CREATE_PACKET_POOL option), see + nx_dns_create() for guidelines on packet payload size and pool size. + packet traffic for NetX processes. + */ + status = nx_packet_pool_create(&client_pool, "DNS Client Packet Pool", NX_DNS_PACKET_PAYLOAD, pointer, NX_DNS_PACKET_POOL_SIZE); + + pointer = pointer + NX_DNS_PACKET_POOL_SIZE; + + /* Check for pool creation error. */ + if (status) + { + + error_counter++; + return; + } +#endif + + /* Create the packet pool which the IP task will use to send packets. Also available to the host + application to send packet. */ + status = nx_packet_pool_create(&main_pool, "Main Packet Pool", NX_PACKET_PAYLOAD, pointer, NX_PACKET_POOL_SIZE); + + pointer = pointer + NX_PACKET_POOL_SIZE; + + /* Check for pool creation error. */ + if (status) + { + + error_counter++; + return; + } + + /* Create an IP instance for the DNS Client. */ + status = nx_ip_create(&client_ip, "DNS Client IP Instance", CLIENT_ADDRESS, 0xFFFFFF00UL, + &main_pool, _nx_ram_network_driver, pointer, 2048, 1); + + pointer = pointer + 2048; + + /* Check for IP create errors. */ + if (status) + { + + error_counter++; + return; + } + + /* Enable ARP and supply ARP cache memory for the DNS Client IP. */ + status = nx_arp_enable(&client_ip, (void *) pointer, 1024); + pointer = pointer + 1024; + + /* Check for ARP enable errors. */ + if (status) + { + + error_counter++; + return; + } + + /* Enable UDP traffic because DNS is a UDP based protocol. */ + status = nx_udp_enable(&client_ip); + + /* Check for UDP enable errors. */ + if (status) + { + + error_counter++; + return; + } +} + +#define BUFFER_SIZE 200 +#define RECORD_COUNT 10 + +/* Define the Client thread. */ + +void thread_client_entry(ULONG thread_input) +{ + +UCHAR record_buffer[200]; +UINT record_count; +UINT status; +ULONG host_ip_address; +UINT i; +ULONG *ipv4_address_ptr[RECORD_COUNT]; +#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES +NX_DNS_NS_ENTRY + *nx_dns_ns_entry_ptr[RECORD_COUNT]; +NX_DNS_MX_ENTRY + *nx_dns_mx_entry_ptr[RECORD_COUNT]; +NX_DNS_SRV_ENTRY + *nx_dns_srv_entry_ptr[RECORD_COUNT]; +NX_DNS_SOA_ENTRY + *nx_dns_soa_entry_ptr; +ULONG host_address; +USHORT host_port; +#endif + + NX_PARAMETER_NOT_USED(thread_input); + + /* Give NetX IP task a chance to get initialized . */ + tx_thread_sleep(NX_IP_PERIODIC_RATE); + + + /* Create a DNS instance for the Client. Note this function will create + the DNS Client packet pool for creating DNS message packets intended + for querying its DNS server. */ + status = nx_dns_create(&client_dns, &client_ip, (UCHAR *)"DNS Client"); + + /* Check for DNS create error. */ + if (status) + { + + error_counter++; + return; + } + +#ifdef NX_DNS_CACHE_ENABLE + /* Initialize the cache. */ + status = nx_dns_cache_initialize(&client_dns, local_cache, LOCAL_CACHE_SIZE); + + /* Check for DNS cache error. */ + if (status) + { + + error_counter++; + return; + } +#endif + + /* Is the DNS client configured for the host application to create the pecket pool? */ +#ifdef NX_DNS_CLIENT_USER_CREATE_PACKET_POOL + + /* Yes, use the packet pool created above which has appropriate payload size + for DNS messages. */ + status = nx_dns_packet_pool_set(&client_dns, &client_pool); + + /* Check for set DNS packet pool error. */ + if (status) + { + + error_counter++; + return; + } + +#endif /* NX_DNS_CLIENT_USER_CREATE_PACKET_POOL */ + + + /* Add an IPv4 server address to the Client list. */ + status = nx_dns_server_add(&client_dns, DNS_SERVER_ADDRESS); + + /* Check for DNS add server error. */ + if (status) + { + + error_counter++; + return; + } + + + + +/********************************************************************************/ +/* Type A */ +/* Send A type DNS Query to its DNS server and get the IPv4 address. */ +/********************************************************************************/ + + /* Look up an IPv4 address over IPv4. */ + status = nx_dns_host_by_name_get(&client_dns, (UCHAR *)"www.my_example.com", &host_ip_address, NX_IP_PERIODIC_RATE); + + /* Check for DNS query error. */ + if (status != NX_SUCCESS) + { + error_counter++; + } + + else + { + + printf("------------------------------------------------------\n"); + printf("Test A: \n"); + printf("IP address: %lu.%lu.%lu.%lu\n", + host_ip_address >> 24, + host_ip_address >> 16 & 0xFF, + host_ip_address >> 8 & 0xFF, + host_ip_address & 0xFF); + } + + + /* Look up IPv4 addresses to record multiple IPv4 addresses in record_buffer and return the IPv4 address count. */ + status = nx_dns_ipv4_address_by_name_get(&client_dns, (UCHAR *)"www.my_example.com", &record_buffer[0], BUFFER_SIZE, &record_count, NX_IP_PERIODIC_RATE); + + /* Check for DNS query error. */ + if (status != NX_SUCCESS) + { + error_counter++; + } + + else + { + + printf("------------------------------------------------------\n"); + printf("Test A: "); + printf("record_count = %d \n", record_count); + } + + /* Get the IPv4 addresses of host. */ + for(i =0; i< record_count; i++) + { + ipv4_address_ptr[i] = (ULONG *)(record_buffer + i * sizeof(ULONG)); + printf("record %d: IP address: %lu.%lu.%lu.%lu\n", i, + *ipv4_address_ptr[i] >> 24, + *ipv4_address_ptr[i] >> 16 & 0xFF, + *ipv4_address_ptr[i] >> 8 & 0xFF, + *ipv4_address_ptr[i] & 0xFF); + } + + +/********************************************************************************/ +/* Type A + CNAME response */ +/* Send A type DNS Query to its DNS server and get the IPv4 address. */ +/********************************************************************************/ + /* Look up an IPv4 address over IPv4. */ + status = nx_dns_host_by_name_get(&client_dns, (UCHAR *)"www.my_example.com", &host_ip_address, NX_IP_PERIODIC_RATE); + + /* Check for DNS query error. */ + if (status != NX_SUCCESS) + { + error_counter++; + } + + else + { + + printf("------------------------------------------------------\n"); + printf("Test A + CNAME response: \n"); + printf("IP address: %lu.%lu.%lu.%lu\n", + host_ip_address >> 24, + host_ip_address >> 16 & 0xFF, + host_ip_address >> 8 & 0xFF, + host_ip_address & 0xFF); + } + + + /* Look up IPv4 addresses to record multiple IPv4 addresses in record_buffer and return the IPv4 address count. */ + status = nx_dns_ipv4_address_by_name_get(&client_dns, (UCHAR *)"www.my_example.com", &record_buffer[0], BUFFER_SIZE, &record_count, NX_IP_PERIODIC_RATE); + + /* Check for DNS query error. */ + if (status != NX_SUCCESS) + { + error_counter++; + } + + else + { + + printf("------------------------------------------------------\n"); + printf("Test Test A + CNAME response: "); + printf("record_count = %d \n", record_count); + } + + /* Get the IPv4 addresses of host. */ + for(i =0; i< record_count; i++) + { + ipv4_address_ptr[i] = (ULONG *)(record_buffer + i * sizeof(ULONG)); + printf("record %d: IP address: %lu.%lu.%lu.%lu\n", i, + *ipv4_address_ptr[i] >> 24, + *ipv4_address_ptr[i] >> 16 & 0xFF, + *ipv4_address_ptr[i] >> 8 & 0xFF, + *ipv4_address_ptr[i] & 0xFF); + } + + +/********************************************************************************/ +/* Type PTR */ +/* Send PTR type DNS Query to its DNS server and get the host name. */ +/********************************************************************************/ + + + + /* Look up host name over IPv4. */ + host_ip_address = IP_ADDRESS(74, 125, 71, 106); + status = nx_dns_host_by_address_get(&client_dns, host_ip_address, &record_buffer[0], BUFFER_SIZE, NX_IP_PERIODIC_RATE); + + /* Check for DNS query error. */ + if (status != NX_SUCCESS) + { + error_counter++; + } + + else + { + printf("------------------------------------------------------\n"); + printf("Test PTR: %s\n", record_buffer); + } + +#ifdef NX_DNS_ENABLE_EXTENDED_RR_TYPES +/********************************************************************************/ +/* Type CNAME */ +/* Send CNAME type DNS Query to its DNS server and get the canonical name . */ +/********************************************************************************/ + + /* Send CNAME type to record the canonical name of host in record_buffer. */ + status = nx_dns_cname_get(&client_dns, (UCHAR *)"www.my_example.com", &record_buffer[0], BUFFER_SIZE, NX_IP_PERIODIC_RATE); + + /* Check for DNS query error. */ + if (status != NX_SUCCESS) + { + error_counter++; + } + + else + { + + printf("------------------------------------------------------\n"); + printf("Test CNAME: %s\n", record_buffer); + } + + +/********************************************************************************/ +/* Type TXT */ +/* Send TXT type DNS Query to its DNS server and get descriptive text. */ +/********************************************************************************/ + + /* Send TXT type to record the descriptive test of host in record_buffer. */ + status = nx_dns_host_text_get(&client_dns, (UCHAR *)"www.my_example.com", &record_buffer[0], BUFFER_SIZE, NX_IP_PERIODIC_RATE); + + /* Check for DNS query error. */ + if (status != NX_SUCCESS) + { + error_counter++; + } + + else + { + + printf("------------------------------------------------------\n"); + printf("Test TXT: %s\n", record_buffer); + } + + +/********************************************************************************/ +/* Type NS */ +/* Send NS type DNS Query to its DNS server and get the domain name server. */ +/********************************************************************************/ + + /* Send NS type to record multiple name servers in record_buffer and return the name server count. + If the DNS response includes the IPv4 addresses of name server, record it similarly in record_buffer. */ + status = nx_dns_domain_name_server_get(&client_dns, (UCHAR *)"www.my_example.com", &record_buffer[0], BUFFER_SIZE, &record_count, NX_IP_PERIODIC_RATE); + + /* Check for DNS query error. */ + if (status != NX_SUCCESS) + { + error_counter++; + } + + else + { + + printf("------------------------------------------------------\n"); + printf("Test NS: "); + printf("record_count = %d \n", record_count); + } + + /* Get the name server. */ + for(i =0; i< record_count; i++) + { + nx_dns_ns_entry_ptr[i] = (NX_DNS_NS_ENTRY *)(record_buffer + i * sizeof(NX_DNS_NS_ENTRY)); + + printf("record %d: IP address: %lu.%lu.%lu.%lu\n", i, + nx_dns_ns_entry_ptr[i] -> nx_dns_ns_ipv4_address >> 24, + nx_dns_ns_entry_ptr[i] -> nx_dns_ns_ipv4_address >> 16 & 0xFF, + nx_dns_ns_entry_ptr[i] -> nx_dns_ns_ipv4_address >> 8 & 0xFF, + nx_dns_ns_entry_ptr[i] -> nx_dns_ns_ipv4_address & 0xFF); + if(nx_dns_ns_entry_ptr[i] -> nx_dns_ns_hostname_ptr) + printf("hostname = %s\n", nx_dns_ns_entry_ptr[i] -> nx_dns_ns_hostname_ptr); + else + printf("hostname is not set\n"); + } + +/********************************************************************************/ +/* Type MX */ +/* Send MX type DNS Query to its DNS server and get the domain mail exchange. */ +/********************************************************************************/ + + /* Send MX DNS query type to record multiple mail exchanges in record_buffer and return the mail exchange count. + If the DNS response includes the IPv4 addresses of mail exchange, record it similarly in record_buffer. */ + status = nx_dns_domain_mail_exchange_get(&client_dns, (UCHAR *)"www.my_example.com", &record_buffer[0], BUFFER_SIZE, &record_count, NX_IP_PERIODIC_RATE); + + /* Check for DNS query error. */ + if (status != NX_SUCCESS) + { + error_counter++; + } + + else + { + + printf("------------------------------------------------------\n"); + printf("Test MX: "); + printf("record_count = %d \n", record_count); + } + + /* Get the mail exchange. */ + for(i =0; i< record_count; i++) + { + nx_dns_mx_entry_ptr[i] = (NX_DNS_MX_ENTRY *)(record_buffer + i * sizeof(NX_DNS_MX_ENTRY)); + + printf("record %d: IP address: %lu.%lu.%lu.%lu\n", i, + nx_dns_mx_entry_ptr[i] -> nx_dns_mx_ipv4_address >> 24, + nx_dns_mx_entry_ptr[i] -> nx_dns_mx_ipv4_address >> 16 & 0xFF, + nx_dns_mx_entry_ptr[i] -> nx_dns_mx_ipv4_address >> 8 & 0xFF, + nx_dns_mx_entry_ptr[i] -> nx_dns_mx_ipv4_address & 0xFF); + printf("preference = %d \n ", nx_dns_mx_entry_ptr[i] -> nx_dns_mx_preference); + if(nx_dns_mx_entry_ptr[i] -> nx_dns_mx_hostname_ptr) + printf("hostname = %s\n", nx_dns_mx_entry_ptr[i] -> nx_dns_mx_hostname_ptr); + else + printf("hostname is not set\n"); + } + +/********************************************************************************/ +/* Type SRV */ +/* Send SRV type DNS Query to its DNS server and get the location of services. */ +/********************************************************************************/ + + /* Send SRV DNS query type to record the location of services in record_buffer and return count. + If the DNS response includes the IPv4 addresses of service name, record it similarly in record_buffer. */ + status = nx_dns_domain_service_get(&client_dns, (UCHAR *)"www.my_example.com", &record_buffer[0], BUFFER_SIZE, &record_count, NX_IP_PERIODIC_RATE); + + /* Check for DNS query error. */ + if (status != NX_SUCCESS) + { + error_counter++; + } + + else + { + + printf("------------------------------------------------------\n"); + printf("Test SRV: "); + printf("record_count = %d \n", record_count); + } + + /* Get the location of services. */ + for(i =0; i< record_count; i++) + { + nx_dns_srv_entry_ptr[i] = (NX_DNS_SRV_ENTRY *)(record_buffer + i * sizeof(NX_DNS_SRV_ENTRY)); + + printf("record %d: IP address: %lu.%lu.%lu.%lu\n", i, + nx_dns_srv_entry_ptr[i] -> nx_dns_srv_ipv4_address >> 24, + nx_dns_srv_entry_ptr[i] -> nx_dns_srv_ipv4_address >> 16 & 0xFF, + nx_dns_srv_entry_ptr[i] -> nx_dns_srv_ipv4_address >> 8 & 0xFF, + nx_dns_srv_entry_ptr[i] -> nx_dns_srv_ipv4_address & 0xFF); + printf("port number = %d\n", nx_dns_srv_entry_ptr[i] -> nx_dns_srv_port_number ); + printf("priority = %d\n", nx_dns_srv_entry_ptr[i] -> nx_dns_srv_priority ); + printf("weight = %d\n", nx_dns_srv_entry_ptr[i] -> nx_dns_srv_weight ); + if(nx_dns_srv_entry_ptr[i] -> nx_dns_srv_hostname_ptr) + printf("hostname = %s\n", nx_dns_srv_entry_ptr[i] -> nx_dns_srv_hostname_ptr); + else + printf("hostname is not set\n"); + } + + /* Get the service info, NetX old API.*/ + status = nx_dns_info_by_name_get(&client_dns, (UCHAR *)"www.my_example.com", &host_address, &host_port, NX_IP_PERIODIC_RATE); + + /* Check for DNS add server error. */ + if (status != NX_SUCCESS) + { + error_counter++; + } + + else + { + + printf("------------------------------------------------------\n"); + printf("Test SRV: "); + printf("IP address: %lu.%lu.%lu.%lu\n", + host_address >> 24, + host_address >> 16 & 0xFF, + host_address >> 8 & 0xFF, + host_address & 0xFF); + printf("port number = %d\n", host_port); + } + +/********************************************************************************/ +/* Type SOA */ +/* Send SOA type DNS Query to its DNS server and get zone of start of authority.*/ +/********************************************************************************/ + + /* Send SOA DNS query type to record the zone of start of authority in record_buffer. */ + status = nx_dns_authority_zone_start_get(&client_dns, (UCHAR *)"www.my_example.com", &record_buffer[0], BUFFER_SIZE, NX_IP_PERIODIC_RATE); + + /* Check for DNS query error. */ + if (status != NX_SUCCESS) + { + error_counter++; + } + + /* Get the loc*/ + nx_dns_soa_entry_ptr = (NX_DNS_SOA_ENTRY *) record_buffer; + printf("------------------------------------------------------\n"); + printf("Test SOA: \n"); + printf("serial = %lu\n", nx_dns_soa_entry_ptr -> nx_dns_soa_serial ); + printf("refresh = %lu\n", nx_dns_soa_entry_ptr -> nx_dns_soa_refresh ); + printf("retry = %lu\n", nx_dns_soa_entry_ptr -> nx_dns_soa_retry ); + printf("expire = %lu\n", nx_dns_soa_entry_ptr -> nx_dns_soa_expire ); + printf("minmum = %lu\n", nx_dns_soa_entry_ptr -> nx_dns_soa_minmum ); + if(nx_dns_soa_entry_ptr -> nx_dns_soa_host_mname_ptr) + printf("host mname = %s\n", nx_dns_soa_entry_ptr -> nx_dns_soa_host_mname_ptr); + else + printf("host mame is not set\n"); + if(nx_dns_soa_entry_ptr -> nx_dns_soa_host_rname_ptr) + printf("host rname = %s\n", nx_dns_soa_entry_ptr -> nx_dns_soa_host_rname_ptr); + else + printf("host rname is not set\n"); + + +#endif + + /* Shutting down...*/ + + /* Terminate the DNS Client thread. */ + status = nx_dns_delete(&client_dns); + + return; +} + + diff --git a/samples/demo_netx_ftp.c b/samples/demo_netx_ftp.c new file mode 100644 index 0000000..7514c5b --- /dev/null +++ b/samples/demo_netx_ftp.c @@ -0,0 +1,521 @@ +/* This is a small demo of NetX FTP on the high-performance NetX TCP/IP stack. This demo + relies on ThreadX, NetX, and FileX to show a simple file transfer from the client + and then back to the server. */ + + + +#include "tx_api.h" +#include "fx_api.h" +#include "nx_api.h" +#include "nx_ftp_client.h" +#include "nx_ftp_server.h" + +#define DEMO_STACK_SIZE 4096 +#define DEMO_DATA "ABCDEFGHIJKLMNOPQRSTUVWXYZ " + + +/* Uncomment the following line to enable passive transfer mode. */ +/* +#define PASSIVE_MODE +*/ + +/* Uncomment the following line to enable block mode. */ +/* +#define BLOCK_MODE +*/ + + +/* Define the ThreadX, NetX, and FileX object control blocks... */ + +TX_THREAD server_thread; +TX_THREAD client_thread; +NX_PACKET_POOL server_pool; +NX_IP server_ip; +NX_PACKET_POOL client_pool; +NX_IP client_ip; +FX_MEDIA ram_disk; + + +/* Define the NetX FTP object control blocks. */ + +NX_FTP_CLIENT ftp_client; +NX_FTP_SERVER ftp_server; + + +/* Define the counters used in the demo application... */ + +ULONG error_counter = 0; + + +/* Define the memory area for the FileX RAM disk. */ + +UCHAR ram_disk_memory[32000]; +UCHAR ram_disk_sector_cache[512]; + + +#define FTP_SERVER_ADDRESS IP_ADDRESS(1,2,3,4) +#define FTP_CLIENT_ADDRESS IP_ADDRESS(1,2,3,5) + +extern UINT _fx_media_format(FX_MEDIA *media_ptr, VOID (*driver)(FX_MEDIA *media), VOID *driver_info_ptr, UCHAR *memory_ptr, UINT memory_size, + CHAR *volume_name, UINT number_of_fats, UINT directory_entries, UINT hidden_sectors, + ULONG total_sectors, UINT bytes_per_sector, UINT sectors_per_cluster, + UINT heads, UINT sectors_per_track); + +/* Define the FileX and NetX driver entry functions. */ +VOID _fx_ram_driver(FX_MEDIA *media_ptr); + +/* Replace the 'ram' driver with your own Ethernet driver. */ +VOID _nx_ram_network_driver(NX_IP_DRIVER *driver_req_ptr); + + +void client_thread_entry(ULONG thread_input); +void thread_server_entry(ULONG thread_input); + + + + +/* Define server login/logout functions. These are stubs for functions that would + validate a client login request. */ + +UINT server_login(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, ULONG client_ip_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info); +UINT server_logout(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, ULONG client_ip_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info); + + +/* Define main entry point. */ + +int main() +{ + + /* Enter the ThreadX kernel. */ + tx_kernel_enter(); + return(0); +} + + +/* Define what the initial system looks like. */ + +void tx_application_define(void *first_unused_memory) +{ + +UINT status; +UCHAR *pointer; + + /* Initialize NetX. */ + nx_system_initialize(); + + /* Initialize FileX. */ + fx_system_initialize(); + + /* Setup the working pointer. */ + pointer = (UCHAR *) first_unused_memory; + + /* Create a helper thread for the server. */ + tx_thread_create(&server_thread, "FTP Server thread", thread_server_entry, 0, + pointer, DEMO_STACK_SIZE, + 4, 4, TX_NO_TIME_SLICE, TX_AUTO_START); + + pointer = pointer + DEMO_STACK_SIZE; + + /* Create the packet pool for the FTP Server. */ + status = nx_packet_pool_create(&server_pool, "NetX Server Packet Pool", 512, pointer, 8192); + pointer = pointer + 8192; + + /* Check for errors. */ + if (status) + error_counter++; + + /* Create the IP instance for the FTP Server. */ + status = nx_ip_create(&server_ip, "NetX Server IP Instance", FTP_SERVER_ADDRESS, 0xFFFFFF00UL, + &server_pool, _nx_ram_network_driver, pointer, 2048, 1); + pointer = pointer + 2048; + + /* Check status. */ + if (status != NX_SUCCESS) + { + error_counter++; + return; + } + + /* Enable ARP and supply ARP cache memory for server IP instance. */ + nx_arp_enable(&server_ip, (void *) pointer, 1024); + pointer = pointer + 1024; + + /* Enable TCP. */ + nx_tcp_enable(&server_ip); + + /* Create the FTP server. */ + status = nx_ftp_server_create(&ftp_server, "FTP Server Instance", &server_ip, &ram_disk, pointer, DEMO_STACK_SIZE, &server_pool, + server_login, server_logout); + pointer = pointer + DEMO_STACK_SIZE; + + /* Check status. */ + if (status != NX_SUCCESS) + { + error_counter++; + return; + } + + /* Now set up the FTP Client. */ + + /* Create the main FTP client thread. */ + status = tx_thread_create(&client_thread, "FTP Client thread ", client_thread_entry, 0, + pointer, DEMO_STACK_SIZE, + 6, 6, TX_NO_TIME_SLICE, TX_AUTO_START); + pointer = pointer + DEMO_STACK_SIZE ; + + /* Check status. */ + if (status != NX_SUCCESS) + { + error_counter++; + return; + } + + /* Create a packet pool for the FTP client. */ + status = nx_packet_pool_create(&client_pool, "NetX Client Packet Pool", 512, pointer, 8192); + pointer = pointer + 8192; + + /* Create an IP instance for the FTP client. */ + status = nx_ip_create(&client_ip, "NetX Client IP Instance", FTP_CLIENT_ADDRESS, 0xFFFFFF00UL, + &client_pool, _nx_ram_network_driver, pointer, 2048, 1); + pointer = pointer + 2048; + + /* Enable ARP and supply ARP cache memory for the FTP Client IP. */ + nx_arp_enable(&client_ip, (void *) pointer, 1024); + pointer = pointer + 1024; + + /* Enable TCP for client IP instance. */ + nx_tcp_enable(&client_ip); + + return; + +} + +/* Define the FTP client thread. */ + +void client_thread_entry(ULONG thread_input) +{ + +NX_PACKET *my_packet; +NX_PACKET *recv_packet_ptr; +UINT status; +ULONG file_size; + + + NX_PARAMETER_NOT_USED(thread_input); + + /* Format the RAM disk - the memory for the RAM disk was defined above. */ + status = _fx_media_format(&ram_disk, + _fx_ram_driver, /* Driver entry */ + ram_disk_memory, /* RAM disk memory pointer */ + ram_disk_sector_cache, /* Media buffer pointer */ + sizeof(ram_disk_sector_cache), /* Media buffer size */ + "MY_RAM_DISK", /* Volume Name */ + 1, /* Number of FATs */ + 32, /* Directory Entries */ + 0, /* Hidden sectors */ + 256, /* Total sectors */ + 128, /* Sector size */ + 1, /* Sectors per cluster */ + 1, /* Heads */ + 1); /* Sectors per track */ + + /* Check status. */ + if (status != NX_SUCCESS) + { + error_counter++; + return; + } + + /* Open the RAM disk. */ + status = fx_media_open(&ram_disk, "RAM DISK", _fx_ram_driver, ram_disk_memory, ram_disk_sector_cache, sizeof(ram_disk_sector_cache)); + + /* Check status. */ + if (status != NX_SUCCESS) + { + error_counter++; + return; + } + + /* Let the IP threads and driver initialize the system. */ + tx_thread_sleep(NX_IP_PERIODIC_RATE); + + + /* Create an FTP client. */ + status = nx_ftp_client_create(&ftp_client, "FTP Client", &client_ip, 2000, &client_pool); + + /* Check status. */ + if (status != NX_SUCCESS) + { + + error_counter++; + return; + } + + printf("Created the FTP Client\n"); + + + /* Now connect with the NetX FTP (IPv4) server. */ + status = nx_ftp_client_connect(&ftp_client, FTP_SERVER_ADDRESS, "name", "password", NX_IP_PERIODIC_RATE); + + /* Check status. */ + if (status != NX_SUCCESS) + { + error_counter++; + return; + } + + printf("Connected to the FTP Server\n"); + +#ifdef PASSIVE_MODE + /* Enable passive mode. */ + status = nx_ftp_client_passive_mode_set(&ftp_client, NX_TRUE); + if (status != NX_SUCCESS) + { + error_counter++; + return; + } + + printf("Enabled FTP Client Passive Mode\n"); +#endif /* PASSIVE_MODE */ + +#ifdef BLOCK_MODE + /* Set block mode. */ + status = nx_ftp_client_transfer_mode_set(&ftp_client, NX_FTP_TRANSFER_MODE_BLOCK); + if (status != NX_SUCCESS) + { + + error_counter++; + return; + } + + printf("Enabled FTP Client Block Mode\n"); +#endif /* BLOCK_MODE */ + + /* Open a FTP file for writing. */ + status = nx_ftp_client_file_open(&ftp_client, "test.txt", NX_FTP_OPEN_FOR_WRITE, NX_IP_PERIODIC_RATE); + + /* Check status. */ + if (status != NX_SUCCESS) + { + error_counter++; + return; + } + + printf("Opened the FTP client test.txt file\n"); + +#ifdef BLOCK_MODE + /* Set the file size in block mode. */ + status = nx_ftp_client_file_size_set(&ftp_client, 28); + + /* Check status. */ + if (status != NX_SUCCESS) + { + error_counter++; + } + else + printf("Set the File Size in Block Mode\n"); +#endif /* BLOCK_MODE */ + + /* Allocate a FTP packet. */ + status = nx_packet_allocate(&client_pool, &my_packet, NX_TCP_PACKET, NX_IP_PERIODIC_RATE); + + /* Check status. */ + if (status != NX_SUCCESS) + { + error_counter++; + return; + } + + /* Write ABCs into the packet payload! */ + memcpy(my_packet -> nx_packet_prepend_ptr, DEMO_DATA, sizeof(DEMO_DATA)); + + /* Adjust the write pointer. */ + my_packet -> nx_packet_length = sizeof(DEMO_DATA); + my_packet -> nx_packet_append_ptr = my_packet -> nx_packet_prepend_ptr + sizeof(DEMO_DATA); + + /* Write the packet to the file test.txt. */ + status = nx_ftp_client_file_write(&ftp_client, my_packet, NX_IP_PERIODIC_RATE); + + /* Check status. */ + if (status != NX_SUCCESS) + { + error_counter++; + nx_packet_release(my_packet); + return; + } + else + printf("Wrote to the FTP client test.txt file\n"); + + + /* Close the file. */ + status = nx_ftp_client_file_close(&ftp_client, NX_IP_PERIODIC_RATE); + + /* Check status. */ + if (status != NX_SUCCESS) + { + error_counter++; + return; + } + else + printf("Closed the FTP client test.txt file\n"); + + + /* Now open the same file for reading. */ + status = nx_ftp_client_file_open(&ftp_client, "test.txt", NX_FTP_OPEN_FOR_READ, NX_IP_PERIODIC_RATE); + + /* Check status. */ + if (status != NX_SUCCESS) + { + error_counter++; + return; + } + else + printf("Reopened the FTP client test.txt file\n"); + + /* Loop to read the data. */ + file_size = 0; + do + { + + /* Read the file. */ + status = nx_ftp_client_file_read(&ftp_client, &my_packet, 100); + + /* Check status. */ + if (status == NX_SUCCESS) + { + file_size += my_packet -> nx_packet_length; + nx_packet_release(my_packet); + } + } while(status == NX_SUCCESS); + + /* Check file size. */ + if (file_size != 28) + { + error_counter++; + return; + } + else + { + printf("Reread the FTP client test.txt file\n"); + } + + /* Close this file. */ + status = nx_ftp_client_file_close(&ftp_client, NX_IP_PERIODIC_RATE); + + /* Check status. */ + if (status != NX_SUCCESS) + { + error_counter++; + return; + } + else + printf("Reclosed the FTP client test.txt file\n"); + + /* Get directory listing (NLST). */ + status = nx_ftp_client_directory_listing_get(&ftp_client, "", &my_packet, 200); + if (status != NX_SUCCESS) + { + error_counter++; + return; + } + else + { + nx_packet_release(my_packet); + } + + do + { + /* Receive the next data packet. */ + status = nx_ftp_client_directory_listing_continue(&ftp_client, &recv_packet_ptr, 200); + if (status == NX_SUCCESS) + { + nx_packet_release(recv_packet_ptr); + } + + /* Check if this is the end of the download. */ + if (status == NX_FTP_END_OF_LISTING) + break; + + } while (status == NX_SUCCESS); + + printf("Got the directory list test.txt\n"); + + /* Disconnect from the server. */ + status = nx_ftp_client_disconnect(&ftp_client, NX_IP_PERIODIC_RATE); + + /* Check status. */ + if (status != NX_SUCCESS) + { + error_counter++; + return; + } + + /* Delete the FTP client. */ + status = nx_ftp_client_delete(&ftp_client); + + /* Check status. */ + if (status != NX_SUCCESS) + { + error_counter++; + return; + } +} + + +/* Define the helper FTP server thread. */ +void thread_server_entry(ULONG thread_input) +{ + +UINT status; + + NX_PARAMETER_NOT_USED(thread_input); + + /* Wait till the IP thread and driver have initialized the system. */ + tx_thread_sleep(NX_IP_PERIODIC_RATE); + + + /* OK to start the FTP Server. */ + status = nx_ftp_server_start(&ftp_server); + + if (status != NX_SUCCESS) + error_counter++; + + printf("Server started!\n"); + + /* FTP server ready to take requests! */ + + /* Let the IP threads execute. */ + tx_thread_relinquish(); + + return; +} + + +UINT server_login(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, ULONG client_ip_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info) +{ + NX_PARAMETER_NOT_USED(ftp_server_ptr); + NX_PARAMETER_NOT_USED(client_ip_address); + NX_PARAMETER_NOT_USED(client_port); + NX_PARAMETER_NOT_USED(name); + NX_PARAMETER_NOT_USED(password); + NX_PARAMETER_NOT_USED(extra_info); + + printf("Logged in!\n"); + /* Always return success. */ + return(NX_SUCCESS); +} + +UINT server_logout(struct NX_FTP_SERVER_STRUCT *ftp_server_ptr, ULONG client_ip_address, UINT client_port, CHAR *name, CHAR *password, CHAR *extra_info) +{ + NX_PARAMETER_NOT_USED(ftp_server_ptr); + NX_PARAMETER_NOT_USED(client_ip_address); + NX_PARAMETER_NOT_USED(client_port); + NX_PARAMETER_NOT_USED(name); + NX_PARAMETER_NOT_USED(password); + NX_PARAMETER_NOT_USED(extra_info); + + printf("Logged out!\n"); + + /* Always return success. */ + return(NX_SUCCESS); +} diff --git a/samples/demo_netx_http.c b/samples/demo_netx_http.c new file mode 100644 index 0000000..6b55a7c --- /dev/null +++ b/samples/demo_netx_http.c @@ -0,0 +1,378 @@ +/* This is a small demo of the NetX HTTP Client Server API running on a + high-performance NetX TCP/IP stack. */ + +#include "tx_api.h" +#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 +#include "nx_http_client.h" +#include "nx_http_server.h" + + +#define DEMO_STACK_SIZE 4096 + + +/* Set up FileX and file memory resources. */ +UCHAR ram_disk_memory[32000]; +FX_MEDIA ram_disk; +unsigned char media_memory[512]; + + +/* Define device drivers. */ +extern void _fx_ram_driver(FX_MEDIA *media_ptr); + +/* Replace the 'ram' driver with your Ethernet driver. */ +VOID _nx_ram_network_driver(NX_IP_DRIVER *driver_req_ptr); + +UINT authentication_check(NX_HTTP_SERVER *server_ptr, UINT request_type, + CHAR *resource, CHAR **name, CHAR **password, CHAR **realm); + +/* Set up the HTTP client global variables. */ + +TX_THREAD client_thread; +NX_PACKET_POOL client_pool; +NX_HTTP_CLIENT my_client; +NX_IP client_ip; +#define CLIENT_PACKET_SIZE (NX_HTTP_SERVER_MIN_PACKET_SIZE * 2) + + +/* Set up the HTTP server global variables */ + +NX_HTTP_SERVER my_server; +NX_PACKET_POOL server_pool; +TX_THREAD server_thread; +NX_IP server_ip; +ULONG server_ip_address; +#define SERVER_PACKET_SIZE (NX_HTTP_SERVER_MIN_PACKET_SIZE * 2) + +void thread_client_entry(ULONG thread_input); +void thread_server_entry(ULONG thread_input); + +#define HTTP_SERVER_ADDRESS IP_ADDRESS(1,2,3,4) +#define HTTP_CLIENT_ADDRESS IP_ADDRESS(1,2,3,5) + + +/* Define the application's authentication check. This is called by + the HTTP server whenever a new request is received. */ +UINT authentication_check(NX_HTTP_SERVER *server_ptr, UINT request_type, + CHAR *resource, CHAR **name, CHAR **password, CHAR **realm) +{ + NX_PARAMETER_NOT_USED(server_ptr); + NX_PARAMETER_NOT_USED(request_type); + NX_PARAMETER_NOT_USED(resource); + + /* Just use a simple name, password, and realm for all + requests and resources. */ + *name = "name"; + *password = "password"; + *realm = "NetX HTTP demo"; + + /* Request basic authentication. */ + return(NX_HTTP_BASIC_AUTHENTICATE); +} + +/* Define main entry point. */ + +int main() +{ + + /* Enter the ThreadX kernel. */ + tx_kernel_enter(); +} + + +/* Define what the initial system looks like. */ +void tx_application_define(void *first_unused_memory) +{ + +CHAR *pointer; +UINT status; + + + /* Setup the working pointer. */ + pointer = (CHAR *) first_unused_memory; + + /* Create a helper thread for the server. */ + tx_thread_create(&server_thread, "HTTP Server thread", thread_server_entry, 0, + pointer, DEMO_STACK_SIZE, + 4, 4, TX_NO_TIME_SLICE, TX_AUTO_START); + + pointer = pointer + DEMO_STACK_SIZE; + + /* Initialize the NetX system. */ + nx_system_initialize(); + + /* Create the server packet pool. */ + status = nx_packet_pool_create(&server_pool, "HTTP Server Packet Pool", SERVER_PACKET_SIZE, + pointer, SERVER_PACKET_SIZE*4); + + pointer = pointer + SERVER_PACKET_SIZE * 4; + + /* Check for pool creation error. */ + if (status) + { + + return; + } + + /* Create an IP instance. */ + status = nx_ip_create(&server_ip, "HTTP Server IP", HTTP_SERVER_ADDRESS, + 0xFFFFFF00UL, &server_pool, _nx_ram_network_driver, + pointer, 4096, 1); + + pointer = pointer + 4096; + + /* Check for IP create errors. */ + if (status) + { + return; + } + + /* Enable ARP and supply ARP cache memory for the server IP instance. */ + status = nx_arp_enable(&server_ip, (void *) pointer, 1024); + pointer = pointer + 1024; + + /* Check for ARP enable errors. */ + if (status) + { + return; + } + + /* Enable TCP traffic. */ + status = nx_tcp_enable(&server_ip); + + if (status) + { + return; + } + server_ip_address = HTTP_SERVER_ADDRESS; + + /* Create the HTTP Server. */ + status = nx_http_server_create(&my_server, "My HTTP Server", &server_ip, &ram_disk, + pointer, 2048, &server_pool, authentication_check, NX_NULL); + if (status) + { + return; + } + + pointer = pointer + 2048; + + /* Create the HTTP Client thread. */ + status = tx_thread_create(&client_thread, "HTTP Client", thread_client_entry, 0, + pointer, DEMO_STACK_SIZE, + 6, 6, TX_NO_TIME_SLICE, TX_AUTO_START); + + pointer = pointer + DEMO_STACK_SIZE; + + /* Check for thread create error. */ + if (status) + { + + return; + } + + /* Create the Client packet pool. */ + status = nx_packet_pool_create(&client_pool, "HTTP Client Packet Pool", SERVER_PACKET_SIZE, + pointer, SERVER_PACKET_SIZE*4); + + pointer = pointer + SERVER_PACKET_SIZE * 4; + + /* Check for pool creation error. */ + if (status) + { + + return; + } + + + /* Create an IP instance. */ + status = nx_ip_create(&client_ip, "HTTP Client IP", HTTP_CLIENT_ADDRESS, + 0xFFFFFF00UL, &client_pool, _nx_ram_network_driver, + pointer, 2048, 1); + + pointer = pointer + 2048; + + /* Check for IP create errors. */ + if (status) + { + return; + } + + /* Enable ARP and supply ARP cache memory for the client IP instance. */ + status = nx_arp_enable(&client_ip, (void *) pointer, 1024); + pointer = pointer + 2048; + + /* Check for ARP enable errors. */ + if (status) + { + return; + } + + /* Enable TCP traffic. */ + status = nx_tcp_enable(&client_ip); + + return; +} + + +VOID thread_client_entry(ULONG thread_input) +{ + +UINT status; +NX_PACKET *my_packet; + + NX_PARAMETER_NOT_USED(thread_input); + + /* Format the RAM disk - the memory for the RAM disk was setup in + tx_application_define above. This must be set up before the client(s) start + sending requests. */ + status = fx_media_format(&ram_disk, + _fx_ram_driver, /* Driver entry */ + ram_disk_memory, /* RAM disk memory pointer */ + media_memory, /* Media buffer pointer */ + sizeof(media_memory), /* Media buffer size */ + "MY_RAM_DISK", /* Volume Name */ + 1, /* Number of FATs */ + 32, /* Directory Entries */ + 0, /* Hidden sectors */ + 256, /* Total sectors */ + 128, /* Sector size */ + 1, /* Sectors per cluster */ + 1, /* Heads */ + 1); /* Sectors per track */ + + /* Check the media format status. */ + if (status != FX_SUCCESS) + { + + /* Error, bail out. */ + return ; + } + + /* Open the RAM disk. */ + status = fx_media_open(&ram_disk, "RAM DISK", _fx_ram_driver, ram_disk_memory, media_memory, sizeof(media_memory)); + + /* Check the media open status. */ + if (status != FX_SUCCESS) + { + + /* Error, bail out. */ + return ; + } + + /* Give IP task and driver a chance to initialize the system. */ + tx_thread_sleep(NX_IP_PERIODIC_RATE); + + /* Create an HTTP client instance. */ + status = nx_http_client_create(&my_client, "HTTP Client", &client_ip, &client_pool, 600); + + /* Check status. */ + if (status != NX_SUCCESS) + { + return; + } + + + + + /* Now upload an HTML file to the HTTP IP server using the 'NetX' service (supports only IPv4). */ + status = nx_http_client_put_start(&my_client, HTTP_SERVER_ADDRESS, "/client_test.htm", + "name", "password", 112, 5 * NX_IP_PERIODIC_RATE); + + /* Check status. */ + if (status != NX_SUCCESS) + { + tx_thread_sleep(NX_IP_PERIODIC_RATE); + } + + + /* Allocate a packet. */ + status = nx_packet_allocate(&client_pool, &my_packet, NX_TCP_PACKET, NX_WAIT_FOREVER); + + /* Check status. */ + if (status != NX_SUCCESS) + { + return; + } + + /* Build a simple 103-byte HTML page. */ + nx_packet_data_append(my_packet, "\r\n", 8, + &client_pool, NX_WAIT_FOREVER); + nx_packet_data_append(my_packet, + "NetX HTTP Test\r\n", 44, + &client_pool, NX_WAIT_FOREVER); + nx_packet_data_append(my_packet, "\r\n", 8, + &client_pool, NX_WAIT_FOREVER); + nx_packet_data_append(my_packet, "

Another NetX Test Page!

\r\n", 34, + &client_pool, NX_WAIT_FOREVER); + nx_packet_data_append(my_packet, "\r\n", 9, + &client_pool, NX_WAIT_FOREVER); + nx_packet_data_append(my_packet, "\r\n", 9, + &client_pool, NX_WAIT_FOREVER); + + /* Complete the PUT by writing the total length. */ + status = nx_http_client_put_packet(&my_client, my_packet, 50); + + /* Check status. */ + if (status != NX_SUCCESS) + { + return; + } + + /* Now GET the test file */ + + + /* Use the 'NetX' service to send a GET request to the server (can only use IPv4 addresses). */ + status = nx_http_client_get_start(&my_client, HTTP_SERVER_ADDRESS, "/client_test.htm", + NX_NULL, 0, "name", "password", 50); + + /* Check status. */ + if (status != NX_SUCCESS) + { + return; + } + + status = nx_http_client_delete(&my_client); + + return; + +} + + +/* Define the helper HTTP server thread. */ +void thread_server_entry(ULONG thread_input) +{ + +UINT status; + + NX_PARAMETER_NOT_USED(thread_input); + + /* Give NetX a chance to initialize the system. */ + tx_thread_sleep(NX_IP_PERIODIC_RATE); + + + /* OK to start the HTTP Server. */ + status = nx_http_server_start(&my_server); + + if (status != NX_SUCCESS) + { + return; + } + + /* HTTP server ready to take requests! */ + + /* Let the IP thread execute. */ + tx_thread_sleep(NX_IP_PERIODIC_RATE); + + return; +} + + + diff --git a/samples/demo_netx_multihome_dhcp_client.c b/samples/demo_netx_multihome_dhcp_client.c new file mode 100644 index 0000000..5737b19 --- /dev/null +++ b/samples/demo_netx_multihome_dhcp_client.c @@ -0,0 +1,314 @@ +/* This is a small demo of DHCP Client for multiple interfaces for the high-performance NetX IP stack. + + It is suggested that applications call interface specific API to do specific action on the specified + interface if DHCP is enabled on multiple interfaces at the same time. + Example of a device possibly with a secondary interfaces attached, and DHCP Client having only the secondary + interface enabled for DHCP: + +#if (NX_MAX_PHYSICAL_INTERFACES >= 2) && (NX_DHCP_CLIENT_MAX_RECORDS >= 2) + + Client configured for DHCP enabled on more than one interface. Use the interface specific service to + request Client IP on the secondary interface. + + status = nx_dhcp_interface_request_client_ip(&dhcp_client, 1, NX_DHCP_CLIENT_IP_ADDRESS_1, SKIP_DISCOVER_MESSAGE); +#else + Client is configured for one interface to be enabled for DHCP. Use the non-interface specific service + to perform the request Client IP action on the interface index that the Client has set for DHCP. + + Note: the application must first call nx_dhcp_set_interface_index() to set the secondary interface as the interface + to run DHCP on. Otherwise DHCP runs on the primary interface, by default. + + status = nx_dhcp_request_client_ip(&dhcp_client, NX_DHCP_CLIENT_IP_ADDRESS_1, SKIP_DISCOVER_MESSAGE); +#endif + + if (status) + error_counter++; + +*/ + +#include "tx_api.h" +#include "nx_api.h" +#include "nx_dhcp.h" + +#define DEMO_STACK_SIZE 4096 +#define NX_PACKET_SIZE 1536 +#define NX_PACKET_POOL_SIZE NX_PACKET_SIZE * 8 + + +/* If defined, the host requests a (previous) client IP address. */ +/* +#define REQUEST_CLIENT_IP +*/ + +#ifdef REQUEST_CLIENT_IP +/* Request a specific IP address using the DHCP client address option. */ +#define NX_DHCP_CLIENT_IP_ADDRESS_0 IP_ADDRESS(192, 168, 0, 18) +#define NX_DHCP_CLIENT_IP_ADDRESS_1 IP_ADDRESS(10, 0, 0, 18) + +/* If defined NX_TRUE, the client requests to jump to the boot state and skip the DISCOVER message. */ +#define SKIP_DISCOVER_MESSAGE NX_TRUE +#endif /* REQUEST_CLIENT_IP */ + +/* Define the ThreadX and NetX object control blocks... */ +TX_THREAD client_thread; +NX_PACKET_POOL client_pool; +NX_IP client_ip; +NX_DHCP dhcp_client; + + +/* Define the counters used in the demo application... */ +ULONG client_thread_counter; +ULONG state_changes; +ULONG error_counter; +CHAR *pointer; + + +/* Define thread prototypes. */ +void client_thread_entry(ULONG thread_input); +void dhcp_interface_state_change(NX_DHCP *dhcp_ptr, UINT iface_index, UCHAR new_state); + +/******** Optionally substitute your Ethernet driver here. ***********/ +void _nx_ram_network_driver(struct NX_IP_DRIVER_STRUCT *driver_req); + +/* Define main entry point. */ + +int main() +{ + + /* Enter the ThreadX kernel. */ + tx_kernel_enter(); + return 0; +} + + +/* Define what the initial system looks like. */ +void tx_application_define(void *first_unused_memory) +{ + +UINT status; + + + /* Setup the working pointer. */ + pointer = (CHAR *) first_unused_memory; + + /* Create the client thread. */ + tx_thread_create(&client_thread, "thread client", client_thread_entry, 0, + pointer, DEMO_STACK_SIZE, + 4, 4, TX_NO_TIME_SLICE, TX_AUTO_START); + pointer = pointer + DEMO_STACK_SIZE; + + /* Initialize the NetX system. */ + nx_system_initialize(); + + /* Create the client packet pool. */ + status = nx_packet_pool_create(&client_pool, "NetX Main Packet Pool", 1024, pointer, NX_PACKET_POOL_SIZE); + pointer = pointer + NX_PACKET_POOL_SIZE; + + /* Check for pool creation error. */ + if (status) + return; + + /* Create an IP instance for the DHCP Client. */ + status = nx_ip_create(&client_ip, "DHCP Client", IP_ADDRESS(0, 0, 0, 0), 0xFFFFFF00UL, &client_pool, _nx_ram_network_driver, pointer, 2048, 1); + pointer = pointer + 2048; + + /* Check for IP create errors. */ + if (status) + return; + + /* Enable ARP and supply ARP cache memory for DHCP Client IP. */ + status = nx_arp_enable(&client_ip, (void *) pointer, 1024); + pointer = pointer + 1024; + + /* Check for ARP enable errors. */ + if (status) + return; + + /* Enable UDP traffic. */ + status = nx_udp_enable(&client_ip); + + /* Check for UDP enable errors. */ + if (status) + return; + + /* Enable TCP traffic. */ + status = nx_tcp_enable(&client_ip); + + /* Check for TCP enable errors. */ + if (status) + return; + + /* Enable ICMP. */ + status = nx_icmp_enable(&client_ip); + + /* Check for errors. */ + if (status) + return; +} + + +/* Define the client thread. */ +void client_thread_entry(ULONG thread_input) +{ + +UINT status; +UINT actual_status; +ULONG server_address; + + NX_PARAMETER_NOT_USED(thread_input); + + /* Check if there are multiple network interfaces */ + +#if (NX_MAX_PHYSICAL_INTERFACES >= 2) && (NX_DHCP_CLIENT_MAX_RECORDS >= 2) + /* There are. Attach the second interface. */ + status = nx_ip_interface_attach(&client_ip, "Second interface", IP_ADDRESS(0, 0, 0, 0), 0xFFFFFF00UL,_nx_ram_network_driver); + + /* Check status. */ + if (status) + return; +#endif + + /* Create the DHCP instance; this automatically enables DHCP on the primary interface. */ + status = nx_dhcp_create(&dhcp_client, &client_ip, "dhcp_client"); + if (status) + return; + + /* Check if there are multiple network interfaces and if DHCP CLient is set up to run DHCP on multiple interfaces. */ +#if (NX_MAX_PHYSICAL_INTERFACES >= 2) && (NX_DHCP_CLIENT_MAX_RECORDS >= 2) + /* Enable DHCP for specified interface(1:second interface). */ + status = nx_dhcp_interface_enable(&dhcp_client, 1); + if (status) + return; +#else + /* for NX_MAX_PHYSICAL_INTERFACES >= 2, NX_DHCP_CLIENT_MAX_RECORDS == 1*/ + status = nx_dhcp_set_interface_index(&dhcp_client, 1); +#endif + +#ifdef REQUEST_CLIENT_IP + + /* nx_dhcp_request_client_ip() requests a specific IP address for DHCP client address option on the first DHCP enabled (valid) interface it finds. */ + /* Suggest using nx_dhcp_interface_request_client_ip() on a single interface if DHCP is enabled on multiple interfaces + status = nx_dhcp_interface_request_client_ip(&dhcp_client, 1, NX_DHCP_CLIENT_IP_ADDRESS_0, SKIP_DISCOVER_MESSAGE) + requests the IP address on the specified address (1:second interface) + */ + status = nx_dhcp_request_client_ip(&dhcp_client, NX_DHCP_CLIENT_IP_ADDRESS_0, SKIP_DISCOVER_MESSAGE); + if (status) + error_counter++; + +#endif /* REQUEST_CLIENT_IP */ + + /* Clear the broadcast flag. */ + /* nx_dhcp_clear_broadcast_flag(&dhcp_client) clears the broadcast flag on all DHCP enabled interfaces. + Suggest using nx_dhcp_interface_clear_broadcast_flag() to clear the flag on one interface if DHCP is enabled on multiple interfaces + status = nx_dhcp_interface_clear_broadcast_flag(&dhcp_client, 1) clears the broadcast flag on the specified interface(1:second interface) + */ + status = nx_dhcp_clear_broadcast_flag(&dhcp_client, NX_TRUE); + if (status) + error_counter++; + + + /* Register the interface state change callback. */ + status = nx_dhcp_interface_state_change_notify(&dhcp_client, dhcp_interface_state_change); + if (status) + error_counter++; + + /* Start the DHCP Client. */ + /* nx_dhcp_start(&dhcp_client) start DHCP for all DHCP enabled interfaces. + Suggest using nx_dhcp_interface_start() to start DHCP on one interface if DHCP is enabled on multiple interfaces + status = nx_dhcp_interface_start(&dhcp_client, 1) starts DHCP on the specified interface (1:second interface) + */ + status = nx_dhcp_start(&dhcp_client); + + /* Loop to test DHCP. */ + while (1) + { + + /* Check the address resolution for primary interface. */ + nx_ip_interface_status_check(&client_ip, 0, NX_IP_ADDRESS_RESOLVED, (ULONG *)&actual_status, NX_WAIT_FOREVER); + + /* Check the address resolution for second interface. */ + nx_ip_interface_status_check(&client_ip, 1, NX_IP_ADDRESS_RESOLVED, (ULONG *)&actual_status, NX_WAIT_FOREVER); + + /* Use this API to get the Server address. */ + /* nx_dhcp_server_address_get(&dhcp_client, &server_address) get the server address for the first DHCP enabled ("valid") interface. + Suggest using nx_dhcp_interface_server_address_get() to get the server address on a specific interface if DHCP is enabled on multiple interfaces + status = nx_dhcp_interface_server_address_get(&dhcp_client, 1, &server_address) returns the server address on specified interface(1:second interface) + */ + status = nx_dhcp_server_address_get(&dhcp_client, &server_address); + if (status) + error_counter++; + + + /* Release the IP address the Client is bound to. + + Use the nx_dhcp_release() API to release an IP address if the host is switching networks or running the host through DHCP cycles. + Note that it is not necessary to call nx_dhcp_reinitialize() or nx_dhcp_interface_reinitialize() after calling this + function. DHCP on this interface (or interfaces) is ready to be restarted. */ + + /* nx_dhcp_release(&dhcp_client) releases the DHCP generated IP address for all DHCP enabled interfaces. + Suggest using nx_dhcp_interface_release() to release the IP address on a specific interface if DHCP is enabled on multiple interfaces + status = nx_dhcp_interface_release(&dhcp_client, 1) releases the IP address for the specified interface(1:second interface) + */ + status = nx_dhcp_release(&dhcp_client); + if (status) + error_counter++; + + /* Stopping the DHCP client. + + Use this API if the Client has not reached the BOUND state. This simply stops the DHCP + Client. It does not clear any network parameters or reset the Client state to NOT STARTED. To do clear network parameters, + and reset the state (e.g. before calling nx_dhcp_start() on the stopped interface(s), call nx_dhcp_reinitialize() or + nx_dhcp_interface_reinitialize() depending which interface(s) need to be reinitialized. + */ + + /* nx_dhcp_stop(&dhcp_client) stops DHCP on all DHCP enabled interfaces. + Suggest using nx_dhcp_interface_stop() to stop DHCP on a specific interface if DHCP is enabled on multiple interfaces + status = nx_dhcp_interface_stop(&dhcp_client, 1) stop DHCP on the specified interface(1:second interface) + */ + status = nx_dhcp_stop(&dhcp_client); + if (status) + error_counter++; + + /* Sleep one second. */ + tx_thread_sleep(NX_IP_PERIODIC_RATE); + + /* Reinitialize the Client for restarting DHCP. + + Use this API to clear the network parameters and restart the client in the not started state. */ + + /* nx_dhcp_reinitialize(&dhcp_client) clears the network parameters on all DHCP enabled interfaces. + Suggest using nx_dhcp_interface_reinitialize() to reinitialize DHCP on a specific interface if DHCP is enabled on multiple interfaces + status = nx_dhcp_interface_reinitialize(&dhcp_client, 1) reinitializes DHCP on the specified interface(1:second interface) + */ + status = nx_dhcp_reinitialize(&dhcp_client); + if (status) + error_counter++; + + /* Resume the DHCP client thread. */ + /* nx_dhcp_start(&dhcp_client) start DHCP for all DHCP enabled interfaces. + or nx_dhcp_interface_start(&dhcp_client, 1) to start DHCP for specified interface(1:second interface) */ + status = nx_dhcp_start(&dhcp_client); + if (status) + error_counter++; + } + + /* All done. Return resources to NetX and ThreadX. */ + nx_dhcp_delete(&dhcp_client); + + return; +} + + +void dhcp_interface_state_change(NX_DHCP *dhcp_ptr, UINT iface_index, UCHAR new_state) +{ + + NX_PARAMETER_NOT_USED(dhcp_ptr); + NX_PARAMETER_NOT_USED(iface_index); + NX_PARAMETER_NOT_USED(new_state); + + /* Increment state changes counter. */ + state_changes++; + + return; +} + diff --git a/samples/demo_netx_multihome_tcp.c b/samples/demo_netx_multihome_tcp.c new file mode 100644 index 0000000..6942a5b --- /dev/null +++ b/samples/demo_netx_multihome_tcp.c @@ -0,0 +1,435 @@ +/* This is a small demo of the high-performance NetX TCP/IP stack. This demo concentrates + on TCP connection, disconnection, sending, and receiving using ARP and a simulated + Ethernet driver in a multihome environment. */ + + +/* + IP_0 has two simulated phyiscal interfaces. + The primary interface is 1.2.3.4/255.255.255.0 + the secondary interface is 2.2.3.4/255.255.255.0 + + IP_1 has two simulated physical interface. + The primary interface is 1.2.3.5/255.255.255.0 + the secondary interface is 2.2.3.5/255.255.255.0 + + These four simulated interfaces are connected to the same channel. + + + + --------- Primary --------- + | | Interface | | + | IP_0 |---------------------- |----------------| IP_1 | + | |1.2.3.4 | | 1.2.3.5 | | + | | | | | | + | | Secondary | | | | + | | Interface | | | | + | |------------------- | | --------------| | + | |2.2.3.4 | | | | 2.2.3.5 | | + --------- | | | | --------- + | | | | + | | | | + ------------------ + | | + | Switch Box | + | | + ------------------ + + + */ + +#include "tx_api.h" +#include "nx_api.h" + +#if (NX_MAX_PHYSICAL_INTERFACES > 1) + +#define DEMO_STACK_SIZE 2048 +#define DEMO_DATA "ABCDEFGHIJKLMNOPQRSTUVWXYZ " +#define PACKET_SIZE 1536 +#define POOL_SIZE ((sizeof(NX_PACKET) + PACKET_SIZE) * 16) + +/* Define the ThreadX and NetX object control blocks... */ + +TX_THREAD thread_0; +TX_THREAD thread_1; + +NX_PACKET_POOL pool_0; +NX_IP ip_0; +NX_IP ip_1; +NX_TCP_SOCKET client_socket; +NX_TCP_SOCKET server_socket; +UCHAR pool_buffer[POOL_SIZE]; + + + +/* Define the counters used in the demo application... */ + +ULONG thread_0_counter; +ULONG thread_1_counter; +ULONG error_counter; + + +/* Define thread prototypes. */ + +void thread_0_entry(ULONG thread_input); +void thread_1_entry(ULONG thread_input); +void thread_1_connect_received(NX_TCP_SOCKET *server_socket, UINT port); +void thread_1_disconnect_received(NX_TCP_SOCKET *server_socket); + +void _nx_ram_network_driver(struct NX_IP_DRIVER_STRUCT *driver_req); + + +/* Define main entry point. */ + +int main() +{ + + /* Enter the ThreadX kernel. */ + tx_kernel_enter(); +} + + +/* Define what the initial system looks like. */ + +void tx_application_define(void *first_unused_memory) +{ + +CHAR *pointer; +UINT status; + + + /* Setup the working pointer. */ + pointer = (CHAR *)first_unused_memory; + + /* Create the main thread. */ + tx_thread_create(&thread_0, "thread 0", thread_0_entry, 0, + pointer, DEMO_STACK_SIZE, + 4, 4, TX_NO_TIME_SLICE, TX_AUTO_START); + + pointer = pointer + DEMO_STACK_SIZE; + + /* Create the main thread. */ + tx_thread_create(&thread_1, "thread 1", thread_1_entry, 0, + pointer, DEMO_STACK_SIZE, + 3, 3, TX_NO_TIME_SLICE, TX_AUTO_START); + + pointer = pointer + DEMO_STACK_SIZE; + + + /* Initialize the NetX system. */ + nx_system_initialize(); + + /* Create a packet pool. */ + status = nx_packet_pool_create(&pool_0, "NetX Main Packet Pool", PACKET_SIZE, pool_buffer, POOL_SIZE); + + if (status) + { + error_counter++; + } + + /* Create an IP instance. */ + status = nx_ip_create(&ip_0, "NetX IP Instance 0", IP_ADDRESS(1, 2, 3, 4), 0xFFFFFF00UL, &pool_0, _nx_ram_network_driver, + pointer, 2048, 1); + pointer = pointer + 2048; + + /* Create another IP instance. */ + status += nx_ip_create(&ip_1, "NetX IP Instance 1", IP_ADDRESS(1, 2, 3, 5), 0xFFFFFF00UL, &pool_0, _nx_ram_network_driver, + pointer, 2048, 1); + pointer = pointer + 2048; + + + if (status) + { + error_counter++; + } + + + /* Attach the second interface to IP_0. Note that this interface is attached during initialization time. + Alternatively the second interface may also be attached in thread context, as illustrated below + in thead_1_entry function. */ + status = nx_ip_interface_attach(&ip_0, "IP_0 Secondary Interface", IP_ADDRESS(2, 2, 3, 4), 0xFFFFFF00, _nx_ram_network_driver); + + if (status) + { + error_counter++; + } + + /* Enable ARP and supply ARP cache memory for IP Instance 0. */ + status = nx_arp_enable(&ip_0, (void *)pointer, 1024); + pointer = pointer + 1024; + + /* Enable ARP and supply ARP cache memory for IP Instance 1. */ + status += nx_arp_enable(&ip_1, (void *)pointer, 1024); + pointer = pointer + 1024; + + /* Check ARP enable status. */ + if (status) + { + error_counter++; + } + + /* Enable TCP processing for both IP instances. */ + status = nx_tcp_enable(&ip_0); + status += nx_tcp_enable(&ip_1); + + /* Check TCP enable status. */ + if (status) + { + error_counter++; + } +} + + + +/* Define the test threads. */ + +void thread_0_entry(ULONG thread_input) +{ + +UINT status; +NX_PACKET *my_packet; +ULONG length; + + NX_PARAMETER_NOT_USED(thread_input); + + /* Loop to repeat things over and over again! */ + while (1) + { + + /* Increment thread 0's counter. */ + thread_0_counter++; + + /* Create a socket. */ + status = nx_tcp_socket_create(&ip_0, &client_socket, "Client Socket", + NX_IP_NORMAL, NX_FRAGMENT_OKAY, NX_IP_TIME_TO_LIVE, 200, + NX_NULL, NX_NULL); + + /* Check for error. */ + if (status) + { + error_counter++; + } + + /* Bind the socket. */ + status = nx_tcp_client_socket_bind(&client_socket, 12, NX_WAIT_FOREVER); + + /* Check for error. */ + if (status) + { + error_counter++; + } + + /* Attempt to connect the socket. */ + if (thread_0_counter & 1) + { + status = nx_tcp_client_socket_connect(&client_socket, IP_ADDRESS(2, 2, 3, 5), 12, NX_IP_PERIODIC_RATE); + } + else + { + status = nx_tcp_client_socket_connect(&client_socket, IP_ADDRESS(1, 2, 3, 5), 12, NX_IP_PERIODIC_RATE); + } + + /* Check for error. */ + if (status) + { + error_counter++; + } + + /* Allocate a packet. */ + status = nx_packet_allocate(&pool_0, &my_packet, NX_TCP_PACKET, NX_WAIT_FOREVER); + + /* Check status. */ + if (status != NX_SUCCESS) + { + break; + } + + /* Write ABCs into the packet payload! */ + memcpy(my_packet -> nx_packet_prepend_ptr, DEMO_DATA, sizeof(DEMO_DATA)); + + /* Adjust the write pointer. */ + my_packet -> nx_packet_length = sizeof(DEMO_DATA); + my_packet -> nx_packet_append_ptr = my_packet -> nx_packet_prepend_ptr + sizeof(DEMO_DATA); + + status = nx_packet_length_get(my_packet, &length); + if ((status) || (length != sizeof(DEMO_DATA))) + { + error_counter++; + } + + /* Send the packet out! */ + status = nx_tcp_socket_send(&client_socket, my_packet, NX_IP_PERIODIC_RATE); + + /* Determine if the status is valid. */ + if (status) + { + error_counter++; + nx_packet_release(my_packet); + } + + /* Disconnect this socket. */ + status = nx_tcp_socket_disconnect(&client_socket, NX_IP_PERIODIC_RATE); + + /* Determine if the status is valid. */ + if (status) + { + error_counter++; + } + + /* Unbind the socket. */ + status = nx_tcp_client_socket_unbind(&client_socket); + + /* Check for error. */ + if (status) + { + error_counter++; + } + + /* Delete the socket. */ + status = nx_tcp_socket_delete(&client_socket); + + /* Check for error. */ + if (status) + { + error_counter++; + } + } +} + + +void thread_1_entry(ULONG thread_input) +{ + +UINT status; +NX_PACKET *packet_ptr; +ULONG actual_status; + + NX_PARAMETER_NOT_USED(thread_input); + + /* Ensure the IP instance has been initialized. */ + status = nx_ip_status_check(&ip_1, NX_IP_INITIALIZE_DONE, &actual_status, NX_IP_PERIODIC_RATE); + + /* Check status... */ + if (status != NX_SUCCESS) + { + + error_counter++; + return; + } + + /* + Attch the second interface to IP_1. Note that this interface is attached in thread context. + Alternatively the second interface may also be attached during system initilization, as illustrated + above in tx_application_define. + */ + + /* Attach the 2nd interface to IP_1 */ + status = nx_ip_interface_attach(&ip_1, "IP_1 Secondary Interface", IP_ADDRESS(2, 2, 3, 5), 0xFFFFFF00, _nx_ram_network_driver); + + /* Check for error. */ + if (status) + { + error_counter++; + } + + /* Create a socket. */ + status = nx_tcp_socket_create(&ip_1, &server_socket, "Server Socket", + NX_IP_NORMAL, NX_FRAGMENT_OKAY, NX_IP_TIME_TO_LIVE, 100, + NX_NULL, thread_1_disconnect_received); + + /* Check for error. */ + if (status) + { + error_counter++; + } + + /* Setup this thread to listen. */ + status = nx_tcp_server_socket_listen(&ip_1, 12, &server_socket, 5, thread_1_connect_received); + + /* Check for error. */ + if (status) + { + error_counter++; + } + + /* Loop to create and establish server connections. */ + while (1) + { + + /* Increment thread 1's counter. */ + thread_1_counter++; + + /* Accept a client socket connection. */ + status = nx_tcp_server_socket_accept(&server_socket, NX_IP_PERIODIC_RATE); + + /* Check for error. */ + if (status) + { + error_counter++; + } + + /* Receive a TCP message from the socket. */ + status = nx_tcp_socket_receive(&server_socket, &packet_ptr, NX_IP_PERIODIC_RATE); + + /* Check for error. */ + if (status) + { + error_counter++; + } + else + { + /* Release the packet. */ + nx_packet_release(packet_ptr); + } + + /* Disconnect the server socket. */ + status = nx_tcp_socket_disconnect(&server_socket, NX_IP_PERIODIC_RATE); + + /* Check for error. */ + if (status) + { + error_counter++; + } + + /* Unaccept the server socket. */ + status = nx_tcp_server_socket_unaccept(&server_socket); + + /* Check for error. */ + if (status) + { + error_counter++; + } + + /* Setup server socket for listening again. */ + status = nx_tcp_server_socket_relisten(&ip_1, 12, &server_socket); + + /* Check for error. */ + if (status) + { + error_counter++; + } + } +} + + +void thread_1_connect_received(NX_TCP_SOCKET *socket_ptr, UINT port) +{ + + /* Check for the proper socket and port. */ + if ((socket_ptr != &server_socket) || (port != 12)) + { + error_counter++; + } +} + + +void thread_1_disconnect_received(NX_TCP_SOCKET *socket) +{ + + /* Check for proper disconnected socket. */ + if (socket != &server_socket) + { + error_counter++; + } +} +#endif + diff --git a/samples/demo_netx_multihome_udp.c b/samples/demo_netx_multihome_udp.c new file mode 100644 index 0000000..84ec1fa --- /dev/null +++ b/samples/demo_netx_multihome_udp.c @@ -0,0 +1,340 @@ +/* This is a small demo of the high-performance NetX TCP/IP stack. This demo concentrates + on UDP packet sending and receiving - with ARP - using a simulated Ethernet driver in + a multihome environment. */ + + + +/* + IP_0 has two simulated phyiscal interfaces. + The primary interface is 1.2.3.4/255.255.255.0 + the secondary interface is 2.2.3.4/255.255.255.0 + + IP_1 has two simulated physical interface. + The primary interface is 1.2.3.5/255.255.255.0 + the secondary interface is 2.2.3.5/255.255.255.0 + + These four simulated interfaces are connected to the same channel. + + + + --------- Primary --------- + | | Interface | | + | IP_0 |---------------------- |----------------| IP_1 | + | |1.2.3.4 | | 1.2.3.5 | | + | | | | | | + | | Secondary | | | | + | | Interface | | | | + | |------------------- | | --------------| | + | |2.2.3.4 | | | | 2.2.3.5 | | + --------- | | | | --------- + | | | | + | | | | + ------------------ + | | + | Switch Box | + | | + ------------------ + + + */ + +#include "tx_api.h" +#include "nx_api.h" + +#if (NX_MAX_PHYSICAL_INTERFACES > 1) + +#define DEMO_STACK_SIZE 2048 +#define DEMO_DATA "ABCDEFGHIJKLMNOPQRSTUVWXYZ " +#define PACKET_SIZE 1536 +#define POOL_SIZE ((sizeof(NX_PACKET) + PACKET_SIZE) * 16) + +/* Define the ThreadX and NetX object control blocks. */ + +TX_THREAD thread_0; +TX_THREAD thread_1; + +NX_PACKET_POOL pool_0; +NX_IP ip_0; +NX_IP ip_1; + + +NX_UDP_SOCKET socket_0; +NX_UDP_SOCKET socket_1; + + +/* Define the counters used in the demo application... */ + +ULONG thread_0_counter; +ULONG thread_1_counter; +ULONG error_counter; +UCHAR pool_buffer[POOL_SIZE]; + +/* Define thread prototypes. */ + +void thread_0_entry(ULONG thread_input); +void thread_1_entry(ULONG thread_input); +void _nx_ram_network_driver(struct NX_IP_DRIVER_STRUCT *driver_req); + + +/* Define main entry point. */ + +int main() +{ + + /* Enter the ThreadX kernel. */ + tx_kernel_enter(); +} + + +/* Define what the initial system looks like. */ + +void tx_application_define(void *first_unused_memory) +{ + +CHAR *pointer; +UINT status; + + + /* Setup the working pointer. */ + pointer = (CHAR *)first_unused_memory; + + /* Create the main thread. */ + tx_thread_create(&thread_0, "thread 0", thread_0_entry, 0, + pointer, DEMO_STACK_SIZE, + 4, 4, TX_NO_TIME_SLICE, TX_AUTO_START); + pointer = pointer + DEMO_STACK_SIZE; + + /* . */ + tx_thread_create(&thread_1, "thread 1", thread_1_entry, 0, + pointer, DEMO_STACK_SIZE, + 3, 3, TX_NO_TIME_SLICE, TX_AUTO_START); + pointer = pointer + DEMO_STACK_SIZE; + + /* Initialize the NetX system. */ + nx_system_initialize(); + + /* Create a packet pool. */ + status = nx_packet_pool_create(&pool_0, "NetX Main Packet Pool", PACKET_SIZE, pool_buffer, POOL_SIZE); + + /* Check for pool creation error. */ + if (status) + { + error_counter++; + } + + /* Create an IP instance. */ + status = nx_ip_create(&ip_0, "NetX IP Instance 0", IP_ADDRESS(1, 2, 3, 4), 0xFFFFF000UL, &pool_0, _nx_ram_network_driver, + pointer, 2048, 1); + pointer = pointer + 2048; + + /* Create another IP instance. */ + status += nx_ip_create(&ip_1, "NetX IP Instance 1", IP_ADDRESS(1, 2, 3, 5), 0xFFFFF000UL, &pool_0, _nx_ram_network_driver, + pointer, 2048, 1); + pointer = pointer + 2048; + + /* Check for IP create errors. */ + if (status) + { + error_counter++; + } + + /* Attach the second interface to IP_0. Note that this interface is attached during initialization time. + Alternatively the second interface may also be attached in thread context, as illustrated below + in thead_1_entry function. */ + status = nx_ip_interface_attach(&ip_0, "IP_0 Secondary Interface", IP_ADDRESS(2, 2, 3, 4), 0xFFFFFF00, _nx_ram_network_driver); + + if (status) + { + error_counter++; + } + + /* Enable ARP and supply ARP cache memory for IP Instance 0. */ + status = nx_arp_enable(&ip_0, (void *)pointer, 1024); + pointer = pointer + 1024; + + /* Enable ARP and supply ARP cache memory for IP Instance 1. */ + status += nx_arp_enable(&ip_1, (void *)pointer, 1024); + pointer = pointer + 1024; + + /* Check for ARP enable errors. */ + if (status) + { + error_counter++; + } + + /* Enable UDP traffic. */ + status = nx_udp_enable(&ip_0); + status += nx_udp_enable(&ip_1); + + /* Check for UDP enable errors. */ + if (status) + { + error_counter++; + } +} + + + +/* Define the test threads. */ + +void thread_0_entry(ULONG thread_input) +{ + +UINT status; +NX_PACKET *my_packet; + + + NX_PARAMETER_NOT_USED(thread_input); + + /* Let the IP threads and thread 1 execute. */ + tx_thread_relinquish(); + + /* Create a UDP socket. */ + status = nx_udp_socket_create(&ip_0, &socket_0, "Socket 0", NX_IP_NORMAL, NX_FRAGMENT_OKAY, 0x80, 5); + + /* Check status. */ + if (status) + { + error_counter++; + return; + } + + /* Bind the UDP socket to the IP port. */ + status = nx_udp_socket_bind(&socket_0, 0x88, TX_WAIT_FOREVER); + + /* Check status. */ + if (status) + { + error_counter++; + return; + } + + /* Disable checksum logic for this socket. */ + nx_udp_socket_checksum_disable(&socket_0); + + /* Setup the ARP entry for the UDP send. */ + nx_arp_dynamic_entry_set(&ip_0, IP_ADDRESS(1, 2, 3, 5), 0, 0); + + /* Let other threads run again. */ + tx_thread_relinquish(); + + while (1) + { + + + /* Allocate a packet. */ + status = nx_packet_allocate(&pool_0, &my_packet, NX_UDP_PACKET, TX_WAIT_FOREVER); + + /* Check status. */ + if (status != NX_SUCCESS) + { + break; + } + + /* Write ABCs into the packet payload! */ + memcpy(my_packet -> nx_packet_prepend_ptr, DEMO_DATA, sizeof(DEMO_DATA)); + + /* Adjust the write pointer. */ + my_packet -> nx_packet_length = sizeof(DEMO_DATA); + my_packet -> nx_packet_append_ptr = my_packet -> nx_packet_prepend_ptr + sizeof(DEMO_DATA); + + /* Send the UDP packet. */ + if (thread_0_counter & 1) + { + status = nx_udp_socket_send(&socket_0, my_packet, IP_ADDRESS(1, 2, 3, 5), 0x89); + } + else + { + status = nx_udp_socket_send(&socket_0, my_packet, IP_ADDRESS(2, 2, 3, 5), 0x89); + } + + /* Check status. */ + if (status != NX_SUCCESS) + { + error_counter++; + break; + } + + /* Increment thread 0's counter. */ + thread_0_counter++; + + /* Relinquish to thread 1. */ + tx_thread_relinquish(); + } +} + + +void thread_1_entry(ULONG thread_input) +{ + +UINT status; +NX_PACKET *my_packet; + + NX_PARAMETER_NOT_USED(thread_input); + + /* + Attch the second interface to IP_1. Note that this interface is attached in thread context. + Alternatively the second interface may also be attached during system initilization, as illustrated + above in tx_application_define. + */ + + /* Attach the 2nd interface to IP_1 */ + status = nx_ip_interface_attach(&ip_1, "IP_1 Secondary Interface", IP_ADDRESS(2, 2, 3, 5), 0xFFFFFF00, _nx_ram_network_driver); + + /* Check for error. */ + if (status) + { + error_counter++; + } + + + /* Create a UDP socket. */ + status = nx_udp_socket_create(&ip_1, &socket_1, "Socket 1", NX_IP_NORMAL, NX_FRAGMENT_OKAY, 0x80, 5); + + /* Check status. */ + if (status) + { + error_counter++; + return; + } + + /* Bind the UDP socket to the IP port. */ + status = nx_udp_socket_bind(&socket_1, 0x89, TX_WAIT_FOREVER); + + /* Check status. */ + if (status) + { + error_counter++; + return; + } + + while (1) + { + + + /* Receive a UDP packet. */ + status = nx_udp_socket_receive(&socket_1, &my_packet, TX_WAIT_FOREVER); + + /* Check status. */ + if (status != NX_SUCCESS) + { + break; + } + + /* Release the packet. */ + status = nx_packet_release(my_packet); + + /* Check status. */ + if (status != NX_SUCCESS) + { + break; + } + + /* Increment thread 1's counter. */ + thread_1_counter++; + } +} + + +#endif + diff --git a/samples/demo_netx_pop3_client.c b/samples/demo_netx_pop3_client.c new file mode 100644 index 0000000..e1bd565 --- /dev/null +++ b/samples/demo_netx_pop3_client.c @@ -0,0 +1,226 @@ +/* + This is a small demo of POP3 Client on the high-performance NetX TCP/IP stack. + This demo relies on Thread, NetX and POP3 Client API to conduct + a POP3 mail session. + */ +/* Note: This demo works for IPv4 only. */ + +#include "tx_api.h" +#include "nx_api.h" +#include "nx_pop3_client.h" + +#define DEMO_STACK_SIZE 4096 +#define CLIENT_ADDRESS IP_ADDRESS(192,2,2,61) +#define SERVER_ADDRESS IP_ADDRESS(192,2,2,89) +#define SERVER_PORT 110 + + +/* Replace the 'ram' driver with your own Ethernet driver. */ +void _nx_ram_network_driver(struct NX_IP_DRIVER_STRUCT *driver_req); + +/* Set up the POP3 Client. */ + +TX_THREAD demo_client_thread; +NX_POP3_CLIENT demo_client; +NX_PACKET_POOL client_packet_pool; +NX_IP client_ip; + +/* Use the maximum size payload to insure no packets are dropped. */ +#define PAYLOAD_SIZE 1460 + +/* Set up Client thread entry point. */ +void demo_thread_entry(ULONG info); + + + /* Shared secret is the same as password. */ + +#define LOCALHOST "recipient@domain.com" +#define LOCALHOST_PASSWORD "testpwd" + + +/* Define main entry point. */ +int main() +{ + /* Enter the ThreadX kernel. */ + tx_kernel_enter(); +} + + +/* Define what the initial system looks like. */ +void tx_application_define(void *first_unused_memory) +{ + +UINT status; +UCHAR *free_memory_pointer; + + + /* Setup the working pointer. */ + free_memory_pointer = first_unused_memory; + + /* Create a client thread. */ + tx_thread_create(&demo_client_thread, "Client", demo_thread_entry, 0, + free_memory_pointer, DEMO_STACK_SIZE, 1, 1, + TX_NO_TIME_SLICE, TX_AUTO_START); + + free_memory_pointer = free_memory_pointer + DEMO_STACK_SIZE; + + /* Initialize the NetX system. */ + nx_system_initialize(); + + /* The demo client username and password is the authentication + data used when the server attempts to authentication the client. */ + + /* Create Client packet pool. */ + status = nx_packet_pool_create(&client_packet_pool, "POP3 Client Packet Pool", + PAYLOAD_SIZE, free_memory_pointer, (PAYLOAD_SIZE * 10)); + if (status != NX_SUCCESS) + { + return; + } + + /* Update pointer to unallocated (free) memory. */ + free_memory_pointer = free_memory_pointer + (PAYLOAD_SIZE * 10); + + + /* Create IP instance for demo Client */ + status = nx_ip_create(&client_ip, "POP3 Client IP Instance", CLIENT_ADDRESS, 0xFFFFFF00UL, + &client_packet_pool, _nx_ram_network_driver, free_memory_pointer, + 2048, 1); + + if (status != NX_SUCCESS) + { + return; + } + + /* Update pointer to unallocated (free) memory. */ + free_memory_pointer = free_memory_pointer + 2048; + + /* Enable ARP and supply ARP cache memory. */ + nx_arp_enable(&client_ip, (void *) free_memory_pointer, 1024); + + /* Update pointer to unallocated (free) memory. */ + free_memory_pointer = free_memory_pointer + 1024; + + /* Enable TCP and ICMP for Client IP. */ + nx_tcp_enable(&client_ip); + nx_icmp_enable(&client_ip); + + return; +} + + + +/* Define the application thread entry function. */ + +void demo_thread_entry(ULONG info) +{ + +UINT status; +UINT mail_item, number_mail_items; +UINT bytes_downloaded = 0; +UINT final_packet = NX_FALSE; +ULONG total_size, mail_item_size, bytes_retrieved; +NX_PACKET *packet_ptr; + + NX_PARAMETER_NOT_USED(info); + + /* Let the IP instance get initialized with driver parameters. */ + tx_thread_sleep(NX_IP_PERIODIC_RATE); + + + /* Create a NetX POP3 Client instance with no byte or block memory pools. + Note that it uses its password for its APOP shared secret. */ + status = nx_pop3_client_create(&demo_client, + NX_TRUE /* if true, enables Client to send APOP command to authenticate */, + &client_ip, &client_packet_pool, SERVER_ADDRESS, SERVER_PORT, + LOCALHOST, LOCALHOST_PASSWORD); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + status = nx_pop3_client_delete(&demo_client); + + /* Abort. */ + return; + } + + /* Find out how many items are in our mailbox. */ + status = nx_pop3_client_mail_items_get(&demo_client, &number_mail_items, &total_size); + + printf("Got %d mail items, total size%ld \n", number_mail_items, total_size); + + /* If nothing in the mailbox, disconnect. */ + if (number_mail_items == 0) + { + + nx_pop3_client_delete(&demo_client); + + return; + } + + /* Download all mail items. */ + mail_item = 1; + + while (mail_item <= number_mail_items) + { + + /* This submits a RETR request and gets the mail message size. */ + status = nx_pop3_client_mail_item_get(&demo_client, mail_item, &mail_item_size); + + /* Loop to get the next mail message packet until the mail item is completely + downloaded. */ + do + { + + status = nx_pop3_client_mail_item_message_get(&demo_client, &packet_ptr, + &bytes_retrieved, + &final_packet); + + if (status != NX_SUCCESS) + { + + break; + } + + if (bytes_retrieved != 0) + { + + printf("Received %ld bytes of data for item %d: %s\n", packet_ptr -> nx_packet_length, mail_item, packet_ptr -> nx_packet_prepend_ptr); + } + + nx_packet_release(packet_ptr); + + /* Determine if this is the last data packet. */ + if (final_packet) + { + /* It is. Let the server know it can delete this mail item. */ + status = nx_pop3_client_mail_item_delete(&demo_client, mail_item); + + if (status != NX_SUCCESS) + { + + break; + } + } + + /* Keep track of how much mail message data is left. */ + bytes_downloaded += bytes_retrieved; + + } while (final_packet == NX_FALSE); + + /* Get the next mail item. */ + mail_item++; + + tx_thread_sleep(NX_IP_PERIODIC_RATE); + + } + + /* Disconnect from the POP3 server. */ + status = nx_pop3_client_quit(&demo_client); + + /* Delete the POP3 Client. This will not delete the packet pool used by the POP3 Client to + transmit messages. */ + status = nx_pop3_client_delete(&demo_client); + +} diff --git a/samples/demo_netx_ppp.c b/samples/demo_netx_ppp.c new file mode 100644 index 0000000..27befb0 --- /dev/null +++ b/samples/demo_netx_ppp.c @@ -0,0 +1,426 @@ +/* This is a small demo of the high-performance NetX TCP/IP stack using PPP. + This demo concentrates on UDP packet sending and receiving using PPP on a + simulated serial link. */ + +#include "tx_api.h" +#include "nx_api.h" + +#include "nx_ppp.h" + + +/* Define demo stack size. */ + +#define DEMO_STACK_SIZE 2048 +#define DEMO_DATA "ABCDEFGHIJKLMNOPQRSTUVWXYZ " + + +/* Define the ThreadX and NetX object control blocks... */ + +TX_THREAD thread_0; +TX_THREAD thread_1; + +NX_PACKET_POOL pool_0; + +NX_IP ip_0; +NX_IP ip_1; + +NX_PPP ppp_0; +NX_PPP ppp_1; + +NX_UDP_SOCKET socket_0; +NX_UDP_SOCKET socket_1; + + +/* Define the counters used in the demo application... */ + +ULONG thread_0_counter; +ULONG thread_1_counter; +ULONG ppp_0_link_up_counter; +ULONG ppp_0_link_down_counter; +ULONG ppp_1_link_up_counter; +ULONG ppp_1_link_down_counter; +ULONG error_counter; + + +/* Define thread prototypes. */ + +void thread_0_entry(ULONG thread_input); +void thread_1_entry(ULONG thread_input); +void ppp_0_serial_byte_output(UCHAR byte); +void ppp_1_serial_byte_output(UCHAR byte); +void invalid_packet_handler(NX_PACKET *packet_ptr); +void link_up_callback(NX_PPP *ppp_ptr); +void link_down_callback(NX_PPP *ppp_ptr); +UINT generate_login(CHAR *name, CHAR *password); +UINT verify_login(CHAR *name, CHAR *password); + + +/* Define main entry point. */ + +int main() +{ + + /* Enter the ThreadX kernel. */ + tx_kernel_enter(); +} + + +/* Define what the initial system looks like. */ + +void tx_application_define(void *first_unused_memory) +{ + +CHAR *pointer; +UINT status; + + + /* Setup the working pointer. */ + pointer = (CHAR *) first_unused_memory; + + /* Create the main thread. */ + tx_thread_create(&thread_0, "thread 0", thread_0_entry, 0, + pointer, DEMO_STACK_SIZE, + 5, 5, TX_NO_TIME_SLICE, TX_AUTO_START); + pointer = pointer + DEMO_STACK_SIZE; + + /* . */ + tx_thread_create(&thread_1, "thread 1", thread_1_entry, 0, + pointer, DEMO_STACK_SIZE, + 5, 5, TX_NO_TIME_SLICE, TX_AUTO_START); + pointer = pointer + DEMO_STACK_SIZE; + + /* Initialize the NetX system. */ + nx_system_initialize(); + + /* Create a packet pool. */ + status = nx_packet_pool_create(&pool_0, "NetX Main Packet Pool", 128, pointer, 2048); + pointer = pointer + 2048; + + /* Check for pool creation error. */ + if (status) + error_counter++; + + /* Create the first PPP instance. */ + status = nx_ppp_create(&ppp_0, "NetX PPP Instance 0", &ip_0, pointer, 2048, 1, &pool_0, invalid_packet_handler, ppp_0_serial_byte_output); + pointer = pointer + 2048; + + /* Check for PPP create error. */ + if (status) + error_counter++; + + /* Define IP address. This PPP instance is effectively the server since it has both IP addresses. */ + status = nx_ppp_ip_address_assign(&ppp_0, IP_ADDRESS(1, 2, 3, 4), IP_ADDRESS(1, 2, 3, 5)); + + /* Check for PPP IP address assign error. */ + if (status) + error_counter++; + + /* Register the link up/down callbacks. */ + status = nx_ppp_link_up_notify(&ppp_0, link_up_callback); + status += nx_ppp_link_down_notify(&ppp_0, link_down_callback); + + /* Check for PPP link up/down callback registration error(s). */ + if (status) + error_counter++; + + /* Setup PAP, this PPP instance is effectively the server since it will verify the name and password. */ + status = nx_ppp_pap_enable(&ppp_0, NX_NULL, verify_login); + + /* Check for PPP PAP enable error. */ + if (status) + error_counter++; + + /* Create an IP instance. */ + status = nx_ip_create(&ip_0, "NetX IP Instance 0", IP_ADDRESS(0, 0, 0, 0), 0xFFFFF000UL, &pool_0, nx_ppp_driver, + pointer, 2048, 1); + pointer = pointer + 2048; + + /* Create the next PPP instance. */ + status = nx_ppp_create(&ppp_1, "NetX PPP Instance 1", &ip_1, pointer, 2048, 1, &pool_0, invalid_packet_handler, ppp_1_serial_byte_output); + pointer = pointer + 2048; + + /* Check for PPP create error. */ + if (status) + error_counter++; + + /* Define IP address. This PPP instance is effectively the client since it doesn't have any IP addresses. */ + status = nx_ppp_ip_address_assign(&ppp_1, IP_ADDRESS(0, 0, 0, 0), IP_ADDRESS(0, 0, 0, 0)); + + /* Check for PPP IP address assign error. */ + if (status) + error_counter++; + + /* Register the link up/down callbacks. */ + status = nx_ppp_link_up_notify(&ppp_1, link_up_callback); + status += nx_ppp_link_down_notify(&ppp_1, link_down_callback); + + /* Check for PPP link up/down callback registration error(s). */ + if (status) + error_counter++; + + /* Setup PAP, this PPP instance is effectively the since it generates the name and password for the peer. */ + status = nx_ppp_pap_enable(&ppp_1, generate_login, NX_NULL); + + /* Check for PPP PAP enable error. */ + if (status) + error_counter++; + + /* Create another IP instance. */ + status += nx_ip_create(&ip_1, "NetX IP Instance 1", IP_ADDRESS(0, 0, 0, 0), 0xFFFFF000UL, &pool_0, nx_ppp_driver, + pointer, 2048, 1); + pointer = pointer + 2048; + + /* Enable UDP traffic. */ + status = nx_udp_enable(&ip_0); + status += nx_udp_enable(&ip_1); + + /* Check for UDP enable errors. */ + if (status) + error_counter++; +} + + + +/* Define the test threads. */ + +void thread_0_entry(ULONG thread_input) +{ + +UINT status; +ULONG ip_status; +NX_PACKET *my_packet; + + NX_PARAMETER_NOT_USED(thread_input); + + do + { + + /* Wait for the link to come up. */ + status = nx_ip_status_check(&ip_0, NX_IP_LINK_ENABLED, &ip_status, 3 * NX_IP_PERIODIC_RATE); + } while (status); + + /* Create a UDP socket. */ + status = nx_udp_socket_create(&ip_0, &socket_0, "Socket 0", NX_IP_NORMAL, NX_FRAGMENT_OKAY, 0x80, 5); + + /* Check status. */ + if (status) + { + error_counter++; + return; + } + + /* Bind the UDP socket to the IP port. */ + status = nx_udp_socket_bind(&socket_0, 0x88, TX_WAIT_FOREVER); + + /* Check status. */ + if (status) + { + error_counter++; + return; + } + + /* Disable checksum logic for this socket. */ + nx_udp_socket_checksum_disable(&socket_0); + + /* Let receiver thread run. */ + tx_thread_relinquish(); + + while(1) + { + + /* Allocate a packet. */ + status = nx_packet_allocate(&pool_0, &my_packet, NX_UDP_PACKET, TX_WAIT_FOREVER); + + /* Check status. */ + if (status != NX_SUCCESS) + break; + + /* Write ABCs into the packet payload! */ + nx_packet_data_append(my_packet, DEMO_DATA, sizeof(DEMO_DATA), &pool_0, TX_WAIT_FOREVER); + + /* Send the UDP packet. */ + status = nx_udp_socket_send(&socket_0, my_packet, IP_ADDRESS(1, 2, 3, 5), 0x89); + + /* Check status. */ + if (status != NX_SUCCESS) + { + error_counter++; + break; + } + + /* Increment thread 0's counter. */ + thread_0_counter++; + + /* Relinquish to thread 1. */ + tx_thread_relinquish(); + } +} + + +void thread_1_entry(ULONG thread_input) +{ + +UINT status; +ULONG ip_status; +NX_PACKET *my_packet; + + NX_PARAMETER_NOT_USED(thread_input); + + do + { + + /* Wait for the link to come up. */ + status = nx_ip_status_check(&ip_1, NX_IP_LINK_ENABLED, &ip_status, 3 * NX_IP_PERIODIC_RATE); + } while (status); + + /* Create a UDP socket. */ + status = nx_udp_socket_create(&ip_1, &socket_1, "Socket 1", NX_IP_NORMAL, NX_FRAGMENT_OKAY, 0x80, 5); + + /* Check status. */ + if (status) + { + error_counter++; + return; + } + + /* Bind the UDP socket to the IP port. */ + status = nx_udp_socket_bind(&socket_1, 0x89, TX_WAIT_FOREVER); + + /* Check status. */ + if (status) + { + error_counter++; + return; + } + + while(1) + { + + + /* Receive a UDP packet. */ + status = nx_udp_socket_receive(&socket_1, &my_packet, TX_WAIT_FOREVER); + + /* Check status. */ + if (status != NX_SUCCESS) + break; + + /* Release the packet. */ + status = nx_packet_release(my_packet); + + /* Check status. */ + if (status != NX_SUCCESS) + break; + + /* Increment thread 1's counter. */ + thread_1_counter++; + } +} + +/* Define serial output routines. Normally these routines would + map to physical UART routines and the nx_ppp_byte_receive call + would be made from a UART receive interrupt. */ + +void ppp_0_serial_byte_output(UCHAR byte) +{ + + /* Just feed the PPP 1 input routine. */ + nx_ppp_byte_receive(&ppp_1, byte); +} + +void ppp_1_serial_byte_output(UCHAR byte) +{ + + /* Just feed the PPP 0 input routine. */ + nx_ppp_byte_receive(&ppp_0, byte); +} + + +void invalid_packet_handler(NX_PACKET *packet_ptr) +{ + /* Print out the non-PPP byte. In Windows, the string "CLIENT" will + be sent before Windows PPP starts. Once CLIENT is received, we need + to send "CLIENTSERVER" to establish communication. It's also possible + to receive modem commands here that might need some response to + continue. */ + nx_packet_release(packet_ptr); +} + + +void link_up_callback(NX_PPP *ppp_ptr) +{ + + /* Just increment the link up counter. */ + if (ppp_ptr == &ppp_0) + ppp_0_link_up_counter++; + else + ppp_1_link_up_counter++; +} + + +void link_down_callback(NX_PPP *ppp_ptr) +{ + + /* Just increment the link down counter. */ + if (ppp_ptr == &ppp_0) + ppp_0_link_down_counter++; + else + ppp_1_link_down_counter++; + + /* Restart the PPP instance. */ + nx_ppp_restart(ppp_ptr); +} + + +UINT generate_login(CHAR *name, CHAR *password) +{ + + /* Make a name and password, called "myname" and "mypassword". */ + name[0] = 'm'; + name[1] = 'y'; + name[2] = 'n'; + name[3] = 'a'; + name[4] = 'm'; + name[5] = 'e'; + name[6] = (CHAR) 0; + + password[0] = 'm'; + password[1] = 'y'; + password[2] = 'p'; + password[3] = 'a'; + password[4] = 's'; + password[5] = 's'; + password[6] = 'w'; + password[7] = 'o'; + password[8] = 'r'; + password[9] = 'd'; + password[10] = (CHAR) 0; + + return(NX_SUCCESS); +} + + +UINT verify_login(CHAR *name, CHAR *password) +{ + +if ((name[0] == 'm') && + (name[1] == 'y') && + (name[2] == 'n') && + (name[3] == 'a') && + (name[4] == 'm') && + (name[5] == 'e') && + (name[6] == (CHAR) 0) && + (password[0] == 'm') && + (password[1] == 'y') && + (password[2] == 'p') && + (password[3] == 'a') && + (password[4] == 's') && + (password[5] == 's') && + (password[6] == 'w') && + (password[7] == 'o') && + (password[8] == 'r') && + (password[9] == 'd') && + (password[10] == (CHAR) 0)) + return(NX_SUCCESS); + else + return(NX_PPP_ERROR); +} diff --git a/samples/demo_netx_pppoe_client.c b/samples/demo_netx_pppoe_client.c new file mode 100644 index 0000000..d022c4c --- /dev/null +++ b/samples/demo_netx_pppoe_client.c @@ -0,0 +1,291 @@ +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** NetX PPPoE Client stack Component */ +/** */ +/** This is a small demo of the high-performance NetX PPPoE Client */ +/** stack. This demo includes IP instance, PPPoE Client and PPP Client */ +/** stack. Create one IP instance includes two interfaces to support */ +/** for normal IP stack and PPPoE Client, PPPoE Client can use the */ +/** mutex of IP instance to send PPPoE message when share one Ethernet */ +/** driver. PPPoE Client work with normal IP instance at the same time. */ +/** */ +/** Note1: Substitute your Ethernet driver instead of */ +/** _nx_ram_network_driver before run this demo */ +/** */ +/** Note2: 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) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + + /*****************************************************************/ + /* NetX Stack */ + /*****************************************************************/ + + /***************************/ + /* PPP Client */ + /***************************/ + + /***************************/ + /* PPPoE Client */ + /***************************/ + /***************************/ /***************************/ + /* Normal Ethernet Type */ /* PPPoE Ethernet Type */ + /***************************/ /***************************/ + /***************************/ /***************************/ + /* Interface 0 */ /* Interface 1 */ + /***************************/ /***************************/ + + /*****************************************************************/ + /* Ethernet Dirver */ + /*****************************************************************/ + +#include "tx_api.h" +#include "nx_api.h" +#include "nx_ppp.h" +#include "nx_pppoe_client.h" + +#ifndef NX_DISABLE_IPV4 + +/* Defined NX_PPP_PPPOE_ENABLE if use Express Logic's PPP, since PPP module has been modified to match PPPoE moduler under this definition. */ +#ifdef NX_PPP_PPPOE_ENABLE + +/* If the driver is not initialized in other module, define NX_PPPOE_CLIENT_INITIALIZE_DRIVER_ENABLE to initialize the driver in PPPoE module . + In this demo, the driver has been initialized in IP module. */ +#ifndef NX_PPPOE_CLIENT_INITIALIZE_DRIVER_ENABLE + +/* Define the block size. */ +#define NX_PACKET_POOL_SIZE ((1536 + sizeof(NX_PACKET)) * 30) +#define DEMO_STACK_SIZE 2048 +#define PPPOE_THREAD_SIZE 2048 + +/* Define the ThreadX and NetX object control blocks... */ +TX_THREAD thread_0; + +/* Define the packet pool and IP instance for normal IP instnace. */ +NX_PACKET_POOL pool_0; +NX_IP ip_0; + +/* Define the PPP Client instance. */ +NX_PPP ppp_client; + +/* Define the PPPoE Client instance. */ +NX_PPPOE_CLIENT pppoe_client; + +/* Define the counters. */ +CHAR *pointer; +ULONG error_counter; + +/* Define thread prototypes. */ +void thread_0_entry(ULONG thread_input); + +/***** Substitute your PPP driver entry function here *********/ +extern void _nx_ppp_driver(NX_IP_DRIVER *driver_req_ptr); + +/***** Substitute your Ethernet driver entry function here *********/ +extern void _nx_ram_network_driver(NX_IP_DRIVER *driver_req_ptr); + +/* Define the porting layer function for Express Logic's PPP to simulate TTP's PPP. + Functions to be provided by PPP for calling by the PPPoE Stack. */ +void ppp_client_packet_send(NX_PACKET *packet_ptr); +void pppoe_client_packet_receive(NX_PACKET *packet_ptr); + +/* Define main entry point. */ + +int main() +{ + + /* Enter the ThreadX kernel. */ + tx_kernel_enter(); +} + +UINT generate_login(CHAR *name, CHAR *password) +{ + + /* Make a name and password, called "myname" and "mypassword". */ + name[0] = 'm'; + name[1] = 'y'; + name[2] = 'n'; + name[3] = 'a'; + name[4] = 'm'; + name[5] = 'e'; + name[6] = (CHAR) 0; + + password[0] = 'm'; + password[1] = 'y'; + password[2] = 'p'; + password[3] = 'a'; + password[4] = 's'; + password[5] = 's'; + password[6] = 'w'; + password[7] = 'o'; + password[8] = 'r'; + password[9] = 'd'; + password[10] = (CHAR) 0; + + return(NX_SUCCESS); +} + +/* Define what the initial system looks like. */ + +void tx_application_define(void *first_unused_memory) +{ + +UINT status; + + /* Setup the working pointer. */ + pointer = (CHAR *) first_unused_memory; + + /* Initialize the NetX system. */ + nx_system_initialize(); + + /* Create a packet pool for normal IP instance. */ + status = nx_packet_pool_create(&pool_0, "NetX Main Packet Pool", + (1536 + sizeof(NX_PACKET)), + pointer, NX_PACKET_POOL_SIZE); + pointer = pointer + NX_PACKET_POOL_SIZE; + + /* Check for error. */ + if (status) + error_counter++; + + /* Create an normal IP instance. */ + status = nx_ip_create(&ip_0, "NetX IP Instance", IP_ADDRESS(192, 168, 100, 44), 0xFFFFFF00UL, &pool_0, _nx_ram_network_driver, + pointer, 2048, 1); + pointer = pointer + 2048; + + /* Check for error. */ + if (status) + error_counter++; + + /* Create the PPP instance. */ + status = nx_ppp_create(&ppp_client, "PPP Instance", &ip_0, pointer, 2048, 1, &pool_0, NX_NULL, NX_NULL); + pointer = pointer + 2048; + + /* Check for PPP create error. */ + if (status) + error_counter++; + + /* Set the PPP packet send function. */ + status = nx_ppp_packet_send_set(&ppp_client, ppp_client_packet_send); + + /* Check for PPP packet send function set error. */ + if (status) + error_counter++; + + /* Define IP address. This PPP instance is effectively the client since it doesn't have any IP addresses. */ + status = nx_ppp_ip_address_assign(&ppp_client, IP_ADDRESS(0, 0, 0, 0), IP_ADDRESS(0, 0, 0, 0)); + + /* Check for PPP IP address assign error. */ + if (status) + error_counter++; + + /* Setup PAP, this PPP instance is effectively the since it generates the name and password for the peer.. */ + status = nx_ppp_pap_enable(&ppp_client, generate_login, NX_NULL); + + /* Check for PPP PAP enable error. */ + if (status) + error_counter++; + + /* Attach an interface for PPP. */ + status = nx_ip_interface_attach(&ip_0, "Second Interface For PPP", IP_ADDRESS(0, 0, 0, 0), 0, nx_ppp_driver); + + /* Check for error. */ + if (status) + error_counter++; + + /* Enable ARP and supply ARP cache memory for Normal IP Instance. */ + status = nx_arp_enable(&ip_0, (void *) pointer, 1024); + pointer = pointer + 1024; + + /* Check for ARP enable errors. */ + if (status) + error_counter++; + + /* Enable ICMP */ + status = nx_icmp_enable(&ip_0); + if(status) + error_counter++; + + /* Enable UDP traffic. */ + status = nx_udp_enable(&ip_0); + if (status) + error_counter++; + + /* Enable TCP traffic. */ + status = nx_tcp_enable(&ip_0); + if (status) + error_counter++; + + /* Create the main thread. */ + tx_thread_create(&thread_0, "thread 0", thread_0_entry, 0, + pointer, DEMO_STACK_SIZE, + 4, 4, TX_NO_TIME_SLICE, TX_AUTO_START); + pointer = pointer + DEMO_STACK_SIZE; + +} + +/* Define the test threads. */ + +void thread_0_entry(ULONG thread_input) +{ +UINT status; +ULONG ip_status; + + /* Create the PPPoE instance. */ + status = nx_pppoe_client_create(&pppoe_client, (UCHAR *)"PPPoE Client", &ip_0, 0, &pool_0, pointer, PPPOE_THREAD_SIZE, 4, _nx_ram_network_driver, pppoe_client_packet_receive); + pointer = pointer + PPPOE_THREAD_SIZE; + if (status) + { + error_counter++; + return; + } + + /* Establish PPPoE Client sessione. */ + status = nx_pppoe_client_session_connect(&pppoe_client, NX_WAIT_FOREVER); + if (status) + { + error_counter++; + return; + } + + /* Wait for the link to come up. */ + status = nx_ip_interface_status_check(&ip_0, 1, NX_IP_ADDRESS_RESOLVED, &ip_status, NX_WAIT_FOREVER); + if (status) + { + error_counter++; + return; + } + + /* Get the PPPoE Server physical address and Session ID after establish PPPoE Session. */ + /* + status = nx_pppoe_client_session_get(&pppoe_client, &server_mac_msw, &server_mac_lsw, &session_id); + if (status) + error_counter++; + */ +} + +/* PPPoE Client receive function. */ +void pppoe_client_packet_receive(NX_PACKET *packet_ptr) +{ + + /* Call PPP Client to receive the PPP data fame. */ + nx_ppp_packet_receive(&ppp_client, packet_ptr); +} + +/* PPP Client send function. */ +void ppp_client_packet_send(NX_PACKET *packet_ptr) +{ + + /* Directly Call PPPoE send function to send out the data through PPPoE module. */ + nx_pppoe_client_session_packet_send(&pppoe_client, packet_ptr); +} +#endif /* NX_PPPOE_CLIENT_INITIALIZE_DRIVER_ENABLE */ + +#endif /* NX_PPP_PPPOE_ENABLE */ + +#endif /* NX_DISABLE_IPV4 */ diff --git a/samples/demo_netx_pppoe_server.c b/samples/demo_netx_pppoe_server.c new file mode 100644 index 0000000..0cf5cf7 --- /dev/null +++ b/samples/demo_netx_pppoe_server.c @@ -0,0 +1,394 @@ +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** NetX PPPoE Server stack Component */ +/** */ +/** This is a small demo of the high-performance NetX PPPoE Server */ +/** stack. This demo includes IP instance, PPPoE Server and PPP Server */ +/** stack. Create one IP instance includes two interfaces to support */ +/** for normal IP stack and PPPoE Server, PPPoE Server can use the */ +/** mutex of IP instance to send PPPoE message when share one Ethernet */ +/** driver. PPPoE Server work with normal IP instance at the same time. */ +/** */ +/** Note1: Substitute your Ethernet driver instead of */ +/** _nx_ram_network_driver before run this demo */ +/** */ +/** Note2: 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) */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + + /*****************************************************************/ + /* NetX Stack */ + /*****************************************************************/ + + /***************************/ + /* PPP Server */ + /***************************/ + + /***************************/ + /* PPPoE Server */ + /***************************/ + /***************************/ /***************************/ + /* Normal Ethernet Type */ /* PPPoE Ethernet Type */ + /***************************/ /***************************/ + /***************************/ /***************************/ + /* Interface 0 */ /* Interface 1 */ + /***************************/ /***************************/ + + /*****************************************************************/ + /* Ethernet Dirver */ + /*****************************************************************/ + +#include "tx_api.h" +#include "nx_api.h" +#include "nx_ppp.h" +#include "nx_pppoe_server.h" + +#ifndef NX_DISABLE_IPV4 + +/* Defined NX_PPP_PPPOE_ENABLE if use Express Logic's PPP, since PPP module has been modified to match PPPoE moduler under this definition. */ +#ifdef NX_PPP_PPPOE_ENABLE + +/* If the driver is not initialized in other module, define NX_PPPOE_SERVER_INITIALIZE_DRIVER_ENABLE to initialize the driver in PPPoE module . + In this demo, the driver has been initialized in IP module. */ +#ifndef NX_PPPOE_SERVER_INITIALIZE_DRIVER_ENABLE + +/* NX_PPPOE_SERVER_SESSION_CONTROL_ENABLE: + If defined, enables the feature that controls the PPPoE session. + PPPoE server does not automatically response to the request until application call specific API. */ + +/* Define the block size. */ +#define NX_PACKET_POOL_SIZE ((1536 + sizeof(NX_PACKET)) * 30) +#define DEMO_STACK_SIZE 2048 +#define PPPOE_THREAD_SIZE 2048 + +/* Define the ThreadX and NetX object control blocks... */ +TX_THREAD thread_0; + +/* Define the packet pool and IP instance for normal IP instnace. */ +NX_PACKET_POOL pool_0; +NX_IP ip_0; + +/* Define the PPP Server instance. */ +NX_PPP ppp_server; + +/* Define the PPPoE Server instance. */ +NX_PPPOE_SERVER pppoe_server; + +/* Define the counters. */ +CHAR *pointer; +ULONG error_counter; + +/* Define thread prototypes. */ +void thread_0_entry(ULONG thread_input); + +/***** Substitute your PPP driver entry function here *********/ +extern void _nx_ppp_driver(NX_IP_DRIVER *driver_req_ptr); + +/***** Substitute your Ethernet driver entry function here *********/ +extern void _nx_ram_network_driver(NX_IP_DRIVER *driver_req_ptr); + +/* Define the callback functions. */ +void PppDiscoverReq(UINT interfaceHandle); +void PppOpenReq(UINT interfaceHandle, ULONG length, UCHAR *data); +void PppCloseRsp(UINT interfaceHandle); +void PppCloseReq(UINT interfaceHandle); +void PppTransmitDataReq(UINT interfaceHandle, ULONG length, UCHAR *data, UINT packet_id); +void PppReceiveDataRsp(UINT interfaceHandle, UCHAR *data); + +/* Define the porting layer function for Express Logic's PPP to simulate TTP's PPP. + Functions to be provided by PPP for calling by the PPPoE Stack. */ +void ppp_server_packet_send(NX_PACKET *packet_ptr); + +/* Define main entry point. */ + +int main() +{ + + /* Enter the ThreadX kernel. */ + tx_kernel_enter(); +} + +UINT verify_login(CHAR *name, CHAR *password) +{ + +if ((name[0] == 'm') && + (name[1] == 'y') && + (name[2] == 'n') && + (name[3] == 'a') && + (name[4] == 'm') && + (name[5] == 'e') && + (name[6] == (CHAR) 0) && + (password[0] == 'm') && + (password[1] == 'y') && + (password[2] == 'p') && + (password[3] == 'a') && + (password[4] == 's') && + (password[5] == 's') && + (password[6] == 'w') && + (password[7] == 'o') && + (password[8] == 'r') && + (password[9] == 'd') && + (password[10] == (CHAR) 0)) + return(NX_SUCCESS); + else + return(NX_PPP_ERROR); +} + +/* Define what the initial system looks like. */ + +void tx_application_define(void *first_unused_memory) +{ + +UINT status; + + /* Setup the working pointer. */ + pointer = (CHAR *) first_unused_memory; + + /* Initialize the NetX system. */ + nx_system_initialize(); + + /* Create a packet pool for normal IP instance. */ + status = nx_packet_pool_create(&pool_0, "NetX Main Packet Pool", + (1536 + sizeof(NX_PACKET)), + pointer, NX_PACKET_POOL_SIZE); + pointer = pointer + NX_PACKET_POOL_SIZE; + + /* Check for error. */ + if (status) + error_counter++; + + /* Create an normal IP instance. */ + status = nx_ip_create(&ip_0, "NetX IP Instance", IP_ADDRESS(192, 168, 100, 43), 0xFFFFFF00UL, &pool_0, _nx_ram_network_driver, + pointer, 2048, 1); + pointer = pointer + 2048; + + /* Check for error. */ + if (status) + error_counter++; + + /* Create the PPP instance. */ + status = nx_ppp_create(&ppp_server, "PPP Instance", &ip_0, pointer, 2048, 1, &pool_0, NX_NULL, NX_NULL); + pointer = pointer + 2048; + + /* Check for PPP create error. */ + if (status) + error_counter++; + + /* Set the PPP packet send function. */ + status = nx_ppp_packet_send_set(&ppp_server, ppp_server_packet_send); + + /* Check for PPP packet send function set error. */ + if (status) + error_counter++; + + /* Define IP address. This PPP instance is effectively the server since it has both IP addresses. */ + status = nx_ppp_ip_address_assign(&ppp_server, IP_ADDRESS(192, 168, 10, 43), IP_ADDRESS(192, 168, 10, 44)); + + /* Check for PPP IP address assign error. */ + if (status) + error_counter++; + + /* Setup PAP, this PPP instance is effectively the server since it will verify the name and password. */ + status = nx_ppp_pap_enable(&ppp_server, NX_NULL, verify_login); + + /* Check for PPP PAP enable error. */ + if (status) + error_counter++; + + /* Attach an interface for PPP. */ + status = nx_ip_interface_attach(&ip_0, "Second Interface For PPP", IP_ADDRESS(0, 0, 0, 0), 0, nx_ppp_driver); + + /* Check for error. */ + if (status) + error_counter++; + + /* Enable ARP and supply ARP cache memory for Normal IP Instance. */ + status = nx_arp_enable(&ip_0, (void *) pointer, 1024); + pointer = pointer + 1024; + + /* Check for ARP enable errors. */ + if (status) + error_counter++; + + /* Enable ICMP */ + status = nx_icmp_enable(&ip_0); + if(status) + error_counter++; + + /* Enable UDP traffic. */ + status = nx_udp_enable(&ip_0); + if (status) + error_counter++; + + /* Enable TCP traffic. */ + status = nx_tcp_enable(&ip_0); + if (status) + error_counter++; + + /* Create the main thread. */ + tx_thread_create(&thread_0, "thread 0", thread_0_entry, 0, + pointer, DEMO_STACK_SIZE, + 4, 4, TX_NO_TIME_SLICE, TX_AUTO_START); + pointer = pointer + DEMO_STACK_SIZE; + +} + +/* Define the test threads. */ + +void thread_0_entry(ULONG thread_input) +{ +UINT status; +ULONG ip_status; + + /* Create the PPPoE instance. */ + status = nx_pppoe_server_create(&pppoe_server, (UCHAR *)"PPPoE Server", &ip_0, 0, _nx_ram_network_driver, &pool_0, pointer, PPPOE_THREAD_SIZE, 4); + pointer = pointer + PPPOE_THREAD_SIZE; + if (status) + { + error_counter++; + return; + } + + /* Set the callback notify function. */ + status = nx_pppoe_server_callback_notify_set(&pppoe_server, PppDiscoverReq, PppOpenReq, PppCloseRsp, PppCloseReq, PppTransmitDataReq, PppReceiveDataRsp); + if (status) + { + error_counter++; + return; + } + +#ifdef NX_PPPOE_SERVER_SESSION_CONTROL_ENABLE + /* Call function function to set the default service Name. */ + /* + PppInitInd(length, aData); + */ +#endif /* NX_PPPOE_SERVER_SESSION_CONTROL_ENABLE */ + + /* Enable PPPoE Server. */ + status = nx_pppoe_server_enable(&pppoe_server); + if (status) + { + error_counter++; + return; + } + + /* Get the PPPoE Client physical address and Session ID after establish PPPoE Session. */ + /* + status = nx_pppoe_server_session_get(&pppoe_server, interfaceHandle, &client_mac_msw, &client_mac_lsw, &session_id); + if (status) + error_counter++; + */ + + /* Wait for the link to come up. */ + status = nx_ip_interface_status_check(&ip_0, 1, NX_IP_ADDRESS_RESOLVED, &ip_status, NX_WAIT_FOREVER); + if (status) + { + error_counter++; + return; + } + +#ifdef NX_PPPOE_SERVER_SESSION_CONTROL_ENABLE + /* Call PPPoE function to terminate the PPPoE Session. */ + /* + PppCloseInd(interfaceHandle, causeCode); + */ +#endif /* NX_PPPOE_SERVER_SESSION_CONTROL_ENABLE */ +} + +void PppDiscoverReq(UINT interfaceHandle) +{ + + /* Receive the PPPoE Discovery Initiation Message. */ + +#ifdef NX_PPPOE_SERVER_SESSION_CONTROL_ENABLE + /* Call PPPoE function to allow TTP's software to define the Service Name field of the PADO packet. */ + PppDiscoverCnf(0, NX_NULL, interfaceHandle); +#endif /* NX_PPPOE_SERVER_SESSION_CONTROL_ENABLE */ +} + +void PppOpenReq(UINT interfaceHandle, ULONG length, UCHAR *data) +{ + + /* Get the notify that receive the PPPoE Discovery Request Message. */ + +#ifdef NX_PPPOE_SERVER_SESSION_CONTROL_ENABLE + /* Call PPPoE function to allow TTP's software to accept the PPPoE session. */ + PppOpenCnf(NX_TRUE, interfaceHandle); +#endif /* NX_PPPOE_SERVER_SESSION_CONTROL_ENABLE */ +} + +void PppCloseRsp(UINT interfaceHandle) +{ + + /* Get the notify that receive the PPPoE Discovery Terminate Message. */ + +#ifdef NX_PPPOE_SERVER_SESSION_CONTROL_ENABLE + /* Call PPPoE function to allow TTP's software to confirm that the handle has been freed. */ + PppCloseCnf(interfaceHandle); +#endif /* NX_PPPOE_SERVER_SESSION_CONTROL_ENABLE */ +} + +void PppCloseReq(UINT interfaceHandle) +{ + + /* Get the notify that PPPoE Discovery Terminate Message has been sent. */ + +} + +void PppTransmitDataReq(UINT interfaceHandle, ULONG length, UCHAR *data, UINT packet_id) +{ + +NX_PACKET *packet_ptr; + + /* Get the notify that receive the PPPoE Session data. */ + + /* Call PPP Server to receive the PPP data fame. */ + packet_ptr = (NX_PACKET *)(packet_id); + nx_ppp_packet_receive(&ppp_server, packet_ptr); + +#ifdef NX_PPPOE_SERVER_SESSION_CONTROL_ENABLE + /* Call PPPoE function to confirm that the data has been processed. */ + PppTransmitDataCnf(interfaceHandle, data, packet_id); +#endif /* NX_PPPOE_SERVER_SESSION_CONTROL_ENABLE */ +} + +void PppReceiveDataRsp(UINT interfaceHandle, UCHAR *data) +{ + + /* Get the notify that the PPPoE Session data has been sent. */ + +} + +/* PPP Server send function. */ +void ppp_server_packet_send(NX_PACKET *packet_ptr) +{ + +/* For Express Logic's PPP test, the session should be the first session, so set interfaceHandle as 0. */ +UINT interfaceHandle = 0; + +#ifdef NX_PPPOE_SERVER_SESSION_CONTROL_ENABLE + while(packet_ptr) + { + + /* Call functions to be provided by PPPoE for TTP. */ + PppReceiveDataInd(interfaceHandle, (packet_ptr -> nx_packet_append_ptr - packet_ptr -> nx_packet_prepend_ptr), packet_ptr -> nx_packet_prepend_ptr); + + /* Move to the next packet structure. */ + packet_ptr = packet_ptr -> nx_packet_next; + } +#else + /* Directly Call PPPoE send function to send out the data through PPPoE module. */ + nx_pppoe_server_session_packet_send(&pppoe_server, interfaceHandle, packet_ptr); +#endif /* NX_PPPOE_SERVER_SESSION_CONTROL_ENABLE */ +} +#endif /* NX_PPPOE_SERVER_INITIALIZE_DRIVER_ENABLE */ + +#endif /* NX_PPP_PPPOE_ENABLE */ + +#endif /* NX_DISABLE_IPV4 */ diff --git a/samples/demo_netx_smtp_client.c b/samples/demo_netx_smtp_client.c new file mode 100644 index 0000000..3615807 --- /dev/null +++ b/samples/demo_netx_smtp_client.c @@ -0,0 +1,208 @@ +/* + This is a small demo of the NetX SMTP Client on the high-performance NetX TCP/IP stack. + This demo relies on Thread, NetX and SMTP Client API to perform simple SMTP mail + transfers in an SMTP client application to an SMTP mail server. + */ +/* Note: This demo works for IPv4 only. */ + +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_smtp_client.h" + + +/* Define the host user name and mail box parameters */ +#define USERNAME "myusername" +#define PASSWORD "mypassword" +#define FROM_ADDRESS "my@mycompany.com" +#define RECIPIENT_ADDRESS "your@yourcompany.com" +#define LOCAL_DOMAIN "mycompany.com" + +#define SUBJECT_LINE "NetX SMTP Client Demo" +#define MAIL_BODY "NetX SMTP client is a simple SMTP client implementation \r\n" \ + "that allow embedded devices to send email to an SMTP server. \r\n" \ + "This feature is intended to allow a device to send simple status\r\n " \ + "reports using the most universal Internet application, email.\r\n" + + +/* See the NetX SMTP Client User Guide for how to set the authentication type. + The most common authentication type is PLAIN. */ +#define CLIENT_AUTHENTICATION_TYPE NX_SMTP_CLIENT_AUTH_PLAIN + + +#define CLIENT_IP_ADDRESS IP_ADDRESS(1,2,3,5) +#define SERVER_IP_ADDRESS IP_ADDRESS(1,2,3,4) +#define SERVER_PORT 25 + + +/* Define the NetX and ThreadX structures for the SMTP client appliciation. */ +NX_PACKET_POOL ip_packet_pool; +NX_PACKET_POOL client_packet_pool; +NX_IP client_ip; +TX_THREAD demo_client_thread; +static NX_SMTP_CLIENT demo_client; + + +void _nx_ram_network_driver(struct NX_IP_DRIVER_STRUCT *driver_req); +void demo_client_thread_entry(ULONG info); + +/* Define main entry point. */ +int main() +{ + /* Enter the ThreadX kernel. */ + tx_kernel_enter(); +} + +/* Define what the initial system looks like. */ +void tx_application_define(void *first_unused_memory) +{ + +UINT status; +CHAR *free_memory_pointer; + + + /* Setup the pointer to unallocated memory. */ + free_memory_pointer = (CHAR *) first_unused_memory; + + /* Create IP default packet pool. This packets do not need a very large payload. */ + status = nx_packet_pool_create(&ip_packet_pool, "Default IP Packet Pool", + 512, free_memory_pointer, 2048); + + /* Update pointer to unallocated (free) memory. */ + free_memory_pointer = free_memory_pointer + 2048; + + /* Create SMTP Client packet pool. This is only for transmitting packets to the server. + It need not be a separate packet pool than the IP default packet pool but for more efficient + resource use, we use two different packet pools because the CLient SMTP messages + generally require more payload than IP control packets. + + Packet payload depends on the SMTP Client application requirements. Size of packet payload + must include IP and TCP headers. IP and TCP header data is 40 bytes (not including TCP options). + */ + + status |= nx_packet_pool_create(&client_packet_pool, "SMTP Client Packet Pool", + 800, free_memory_pointer, (10*800)); + + if (status != NX_SUCCESS) + { + return; + } + + /* Update pointer to unallocated (free) memory. */ + free_memory_pointer = free_memory_pointer + (10*800); + + /* Initialize the NetX system. */ + nx_system_initialize(); + + /* Create the client thread */ + status = tx_thread_create(&demo_client_thread, "client_thread", + demo_client_thread_entry, 0, free_memory_pointer, + 2048, 16, 16, + TX_NO_TIME_SLICE, TX_DONT_START); + + if (status != NX_SUCCESS) + { + + printf("Error creating Client thread. Status 0x%x\r\n", status); + return; + } + + /* Update pointer to unallocated (free) memory. */ + free_memory_pointer = free_memory_pointer + 4096; + + + /* Create Client IP instance. Remember to replace the generic driver + with a real ethernet driver to actually run this demo! */ + status = nx_ip_create(&client_ip, "SMTP Client IP Instance", CLIENT_IP_ADDRESS, 0xFFFFFF00UL, + &ip_packet_pool, _nx_ram_network_driver, free_memory_pointer, + 2048, 1); + + free_memory_pointer = free_memory_pointer + 2048; + + /* Enable ARP and supply ARP cache memory. */ + status = nx_arp_enable(&client_ip, (void **) free_memory_pointer, 1040); + + /* Update pointer to unallocated (free) memory. */ + free_memory_pointer = free_memory_pointer + 1040; + + /* Enable TCP for client. */ + status = nx_tcp_enable(&client_ip); + + if (status != NX_SUCCESS) + { + return; + } + + /* Enable ICMP for client. */ + status = nx_icmp_enable(&client_ip); + + if (status != NX_SUCCESS) + { + return; + } + + /* Start the client thread. */ + tx_thread_resume(&demo_client_thread); + + return; +} + + +/* Define the smtp application thread task. */ +void demo_client_thread_entry(ULONG info) +{ + +UINT status; +UINT error_counter = 0; +ULONG server_ip_address; + + NX_PARAMETER_NOT_USED(info); + + tx_thread_sleep(NX_IP_PERIODIC_RATE); + + /* Set up the server IP address. */ + server_ip_address = SERVER_IP_ADDRESS; + + /* The demo client username and password is the authentication + data used when the server attempts to authentication the client. */ + + status = nx_smtp_client_create(&demo_client, &client_ip, &client_packet_pool, + USERNAME, + PASSWORD, + FROM_ADDRESS, + LOCAL_DOMAIN, CLIENT_AUTHENTICATION_TYPE, + server_ip_address, SERVER_PORT); + + if (status != NX_SUCCESS) + { + printf("Error creating the client. Status: 0x%x.\n\r", status); + return; + } + + /* Create a mail instance with the above text message and recipient info. */ + status = nx_smtp_mail_send(&demo_client, RECIPIENT_ADDRESS, NX_SMTP_MAIL_PRIORITY_NORMAL, + SUBJECT_LINE, MAIL_BODY, sizeof(MAIL_BODY) - 1); + + /* Check for errors. */ + if (status != NX_SUCCESS) + { + + /* Mail item was not sent. Note that we need not delete the client. The error status may be a failed + authentication check or a broken connection. We can simply call nx_smtp_mail_send + again. */ + + error_counter++; + } + + /* Release resources used by client. Note that the transmit packet + pool must be deleted by the application if it no longer has use for it.*/ + status = nx_smtp_client_delete(&demo_client); + + /* Check for errors. */ + if (status != NX_SUCCESS) + { + error_counter++; + } + + return; +} + diff --git a/samples/demo_netx_snmp.c b/samples/demo_netx_snmp.c new file mode 100644 index 0000000..e4a905d --- /dev/null +++ b/samples/demo_netx_snmp.c @@ -0,0 +1,423 @@ +/* This is a small demo of the NetX SNMP Agent on the high-performance NetX TCP/IP stack. + This demo relies on ThreadX and NetX to show simple SNMP GET/GETNEXT/SET requests on + the SNMP MIB-2 objects. */ + +#include "tx_api.h" +#include "nx_api.h" +#include "nx_snmp.h" +#include "demo_snmp_helper.h" + +#define DEMO_STACK_SIZE 4096 +#define AGENT_PRIMARY_ADDRESS IP_ADDRESS(1,2,3,4) + +/* Define the ThreadX and NetX object control blocks... */ + +TX_THREAD thread_0; +NX_PACKET_POOL pool_0; +NX_IP ip_0; +NX_SNMP_AGENT my_agent; + + + +/* To use SNMPv3 features such as authentication and encryption, define NX_SNMP_DISABLE_V3. */ + +/* Define authentication and privacy keys. */ + +#ifdef AUTHENTICATION_REQUIRED +NX_SNMP_SECURITY_KEY my_authentication_key; +#endif + +#ifdef PRIVACY_REQUIRED +NX_SNMP_SECURITY_KEY my_privacy_key; +#endif + +/* Define an error counter variable. */ +UINT error_counter = 0; + +/* This binds a secondary interfaces to the primary IP network interface + if SNMP is required for required for that interface. */ +/* #define MULTI_HOMED_DEVICE */ + +/* Define function prototypes. A generic ram driver is used in this demo. However to properly + run an SNMP agent demo, a real driver should be substituted. */ + +VOID thread_agent_entry(ULONG thread_input); +VOID _nx_ram_network_driver(NX_IP_DRIVER *driver_req_ptr); +UINT mib2_get_processing(NX_SNMP_AGENT *agent_ptr, UCHAR *object_requested, NX_SNMP_OBJECT_DATA *object_data); +UINT mib2_getnext_processing(NX_SNMP_AGENT *agent_ptr, UCHAR *object_requested, NX_SNMP_OBJECT_DATA *object_data); +UINT mib2_set_processing(NX_SNMP_AGENT *agent_ptr, UCHAR *object_requested, NX_SNMP_OBJECT_DATA *object_data); +UINT mib2_username_processing(NX_SNMP_AGENT *agent_ptr, UCHAR *username); +VOID mib2_variable_update(NX_IP *ip_ptr, NX_SNMP_AGENT *agent_ptr); + + +UCHAR context_engine_id[] = {0x80, 0x00, 0x0d, 0xfe, 0x03, 0x00, 0x11, 0x23, 0x23, 0x44, 0x55}; +UINT context_engine_size = 11; +UCHAR context_name[] = {0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c}; +UINT context_name_size = 7; + +/* Define main entry point. */ + +int main() +{ + + /* Enter the ThreadX kernel. */ + tx_kernel_enter(); +} + + +/* Define what the initial system looks like. */ +void tx_application_define(void *first_unused_memory) +{ + +UCHAR *pointer; +UINT status; + + + /* Setup the working pointer. */ + pointer = (UCHAR *) first_unused_memory; + + status = tx_thread_create(&thread_0, "agent thread", thread_agent_entry, 0, + pointer, DEMO_STACK_SIZE, + 4, 4, TX_NO_TIME_SLICE, TX_AUTO_START); + if (status != NX_SUCCESS) + { + return; + } + + pointer = pointer + DEMO_STACK_SIZE; + + + /* Initialize the NetX system. */ + nx_system_initialize(); + + /* Create packet pool. */ + status = nx_packet_pool_create(&pool_0, "NetX Packet Pool 0", 2048, pointer, 20000); + + if (status != NX_SUCCESS) + { + return; + } + + pointer = pointer + 20000; + + /* Create an IP instance. */ + status = nx_ip_create(&ip_0, "SNMP Agent IP Instance", AGENT_PRIMARY_ADDRESS, + 0xFFFFFF00UL, &pool_0, _nx_ram_network_driver, + pointer, 4096, 1); + + if (status != NX_SUCCESS) + { + return; + } + + pointer = pointer + 4096; + + /* Enable ARP and supply ARP cache memory for IP Instance 0. */ + nx_arp_enable(&ip_0, (void *) pointer, 1024); + pointer = pointer + 1024; + + /* Enable ICMP for ping. */ + nx_icmp_enable(&ip_0); + + /* Enable UPD processing for IP instance. */ + nx_udp_enable(&ip_0); + + /* Create an SNMP agent instance. */ + status = nx_snmp_agent_create(&my_agent, "SNMP Agent", &ip_0, pointer, 4096, &pool_0, + mib2_username_processing, mib2_get_processing, mib2_getnext_processing, + mib2_set_processing); + + if (status != NX_SUCCESS) + { + return; + } + + pointer = pointer + 4096; + +#ifdef NX_SNMP_DISABLE_V3 + status = nx_snmp_agent_context_engine_set(&my_agent, context_engine_id, context_engine_size); + + if (status != NX_SUCCESS) + { + error_counter++; + } +#endif /* NX_SNMP_DISABLE_V3 */ + + return; +} + +VOID thread_agent_entry(ULONG thread_input) +{ + +UINT status; + + NX_PARAMETER_NOT_USED(thread_input); + + /* Allow NetX time to get initialized. */ + tx_thread_sleep(NX_IP_PERIODIC_RATE); + + +#ifdef AUTHENTICATION_REQUIRED + + /* Create an authentication key. */ + status = nx_snmp_agent_md5_key_create(&my_agent, (UCHAR *)"authpassword", &my_authentication_key); + if (status) + error_counter++; + + /* Use the authentication key. */ + status = nx_snmp_agent_authenticate_key_use(&my_agent, &my_authentication_key); + if (status) + error_counter++; + +#endif + +#ifdef PRIVACY_REQUIRED + + /* Create a privacy key. */ + status = nx_snmp_agent_md5_key_create(&my_agent, (UCHAR *)"privpassword", &my_privacy_key); + if (status) + error_counter++; + + /* Use the privacy key. */ + status = nx_snmp_agent_privacy_key_use(&my_agent, &my_privacy_key); + if (status) + error_counter++; +#endif + + /* Start the SNMP instance. */ + status = nx_snmp_agent_start(&my_agent); + if (status) + error_counter++; + +} + +/* Define the application's GET processing routine. */ + +UINT mib2_get_processing(NX_SNMP_AGENT *agent_ptr, UCHAR *object_requested, NX_SNMP_OBJECT_DATA *object_data) +{ + +UINT i; +UINT status; + + NX_PARAMETER_NOT_USED(agent_ptr); + + + /* Loop through the sample MIB to see if we have information for the supplied variable. */ + i = 0; + status = NX_SNMP_ERROR; + while (mib2_mib[i].object_name) + { + + /* See if we have found the matching entry. */ + status = nx_snmp_object_compare(object_requested, mib2_mib[i].object_name); + + /* Was it found? */ + if (status == NX_SUCCESS) + { + + /* Yes it was found. */ + break; + } + + /* Move to the next index. */ + i++; + } + + /* Determine if a not found condition is present. */ + if (status != NX_SUCCESS) + { + + + /* The object was not found - return an error. */ + return(NX_SNMP_ERROR_NOSUCHNAME); + } + + /* Determine if the entry has a get function. */ + if (mib2_mib[i].object_get_callback) + { + + /* Yes, call the get function. */ + status = (mib2_mib[i].object_get_callback)(mib2_mib[i].object_value_ptr, object_data); + } + else + { + + + /* No get function, return no access. */ + status = NX_SNMP_ERROR_NOACCESS; + } + + + + /* Return the status. */ + return(status); +} + + +/* Define the application's GETNEXT processing routine. */ + +UINT mib2_getnext_processing(NX_SNMP_AGENT *agent_ptr, UCHAR *object_requested, NX_SNMP_OBJECT_DATA *object_data) +{ + +UINT i; +UINT status; + + NX_PARAMETER_NOT_USED(agent_ptr); + + + + /* Loop through the sample MIB to see if we have information for the supplied variable. */ + i = 0; + status = NX_SNMP_ERROR; + while (mib2_mib[i].object_name) + { + + /* See if we have found the next entry. */ + status = nx_snmp_object_compare(object_requested, mib2_mib[i].object_name); + + /* Is the next entry the mib greater? */ + if (status == NX_SNMP_NEXT_ENTRY) + { + + /* Yes it was found. */ + break; + } + + /* Move to the next index. */ + i++; + } + + /* Determine if a not found condition is present. */ + if (status != NX_SNMP_NEXT_ENTRY) + { + + + /* The object was not found - return an error. */ + return(NX_SNMP_ERROR_NOSUCHNAME); + } + + + /* Copy the new name into the object. */ + nx_snmp_object_copy(mib2_mib[i].object_name, object_requested); + + + /* Determine if the entry has a get function. */ + if (mib2_mib[i].object_get_callback) + { + + /* Yes, call the get function. */ + status = (mib2_mib[i].object_get_callback)(mib2_mib[i].object_value_ptr, object_data); + + /* Determine if the object data indicates an end-of-mib condition. */ + if (object_data -> nx_snmp_object_data_type == NX_SNMP_END_OF_MIB_VIEW) + { + + /* Copy the name supplied in the mib table. */ + nx_snmp_object_copy(mib2_mib[i].object_value_ptr, object_requested); + } + } + else + { + + + /* No get function, return no access. */ + status = NX_SNMP_ERROR_NOACCESS; + } + + + + /* Return the status. */ + return(status); +} + + +/* Define the application's SET processing routine. */ + +UINT mib2_set_processing(NX_SNMP_AGENT *agent_ptr, UCHAR *object_requested, NX_SNMP_OBJECT_DATA *object_data) +{ + +UINT i; +UINT status; + + NX_PARAMETER_NOT_USED(agent_ptr); + + + /* Loop through the sample MIB to see if we have information for the supplied variable. */ + i = 0; + status = NX_SNMP_ERROR; + while (mib2_mib[i].object_name) + { + + /* See if we have found the matching entry. */ + status = nx_snmp_object_compare(object_requested, mib2_mib[i].object_name); + + /* Was it found? */ + if (status == NX_SUCCESS) + { + + /* Yes it was found. */ + break; + } + + /* Move to the next index. */ + i++; + } + + /* Determine if a not found condition is present. */ + if (status != NX_SUCCESS) + { + + + /* The object was not found - return an error. */ + return(NX_SNMP_ERROR_NOSUCHNAME); + } + + + /* Determine if the entry has a set function. */ + if (mib2_mib[i].object_set_callback) + { + + /* Yes, call the set function. */ + status = (mib2_mib[i].object_set_callback)(mib2_mib[i].object_value_ptr, object_data); + } + else + { + + + /* No get function, return no access. */ + status = NX_SNMP_ERROR_NOACCESS; + } + + + /* Return the status. */ + return(status); +} + + +/* Define the application's authentication routine. */ + +UINT mib2_username_processing(NX_SNMP_AGENT *agent_ptr, UCHAR *username) +{ + + NX_PARAMETER_NOT_USED(agent_ptr); + NX_PARAMETER_NOT_USED(username); + + /* Update MIB-2 objects. In this example, it is only the SNMP objects. */ + mib2_variable_update(&ip_0, &my_agent); + + /* No authentication is done, just return success! */ + return(NX_SUCCESS); +} + + +/* Define the application's update routine. */ + +VOID mib2_variable_update(NX_IP *ip_ptr, NX_SNMP_AGENT *agent_ptr) +{ + + NX_PARAMETER_NOT_USED(ip_ptr); + NX_PARAMETER_NOT_USED(agent_ptr); + + /* This section is for updating the snmp parameters defined in the MIB table definition files. */ +} + diff --git a/samples/demo_netx_sntp_client.c b/samples/demo_netx_sntp_client.c new file mode 100644 index 0000000..50836df --- /dev/null +++ b/samples/demo_netx_sntp_client.c @@ -0,0 +1,458 @@ +/* + This is a small demo of the NetX SNTP Client on the high-performance NetX TCP/IP stack. + This demo relies on Thread, NetX and NetX SNTP Client API to execute the Simple Network Time + Protocol in unicast and broadcast modes. + + */ + + +#include +#include "nx_api.h" +#include "nx_ip.h" +#include "nx_sntp_client.h" + +/* Define SNTP packet size. */ +#define NX_SNTP_CLIENT_PACKET_SIZE (NX_UDP_PACKET + 100) + +/* Define SNTP packet pool size. */ +#define NX_SNTP_CLIENT_PACKET_POOL_SIZE (4 * (NX_SNTP_CLIENT_PACKET_SIZE + sizeof(NX_PACKET))) + +/* Define how often the demo checks for SNTP updates. */ +#define DEMO_PERIODIC_CHECK_INTERVAL (1 * NX_IP_PERIODIC_RATE) + +/* Define how often we check on SNTP server status. We expect updates from the SNTP + server about every hour using the SNTP Client defaults. For testing make this (much) shorter. */ +#define CHECK_SNTP_UPDATES_TIMEOUT (180 * NX_IP_PERIODIC_RATE) + +/* Set up generic network driver for demo program. */ +void _nx_ram_network_driver(struct NX_IP_DRIVER_STRUCT *driver_req); + +/* Application defined services of the NetX SNTP Client. */ + +UINT leap_second_handler(NX_SNTP_CLIENT *client_ptr, UINT leap_indicator); +UINT kiss_of_death_handler(NX_SNTP_CLIENT *client_ptr, UINT KOD_code); +VOID time_update_callback(NX_SNTP_TIME_MESSAGE *time_update_ptr, NX_SNTP_TIME *local_time); + + +/* Set up client thread and network resources. */ + +NX_PACKET_POOL client_packet_pool; +NX_IP client_ip; +TX_THREAD demo_client_thread; +NX_SNTP_CLIENT demo_sntp_client; +TX_EVENT_FLAGS_GROUP sntp_flags; + +#define DEMO_SNTP_UPDATE_EVENT 1 + + + +/* Configure the SNTP Client to use unicast SNTP. */ +#define USE_UNICAST + + +#define CLIENT_IP_ADDRESS IP_ADDRESS(192,2,2,66) +#define SERVER_IP_ADDRESS IP_ADDRESS(192,2,2,92) +#define SERVER_IP_ADDRESS_2 SERVER_IP_ADDRESS + +/* Set up the SNTP network and address index; */ +UINT iface_index =0; +UINT prefix = 64; +UINT address_index; + +/* Set up client thread entry point. */ +void demo_client_thread_entry(ULONG info); + +/* Define main entry point. */ +int main() +{ + /* Enter the ThreadX kernel. */ + tx_kernel_enter(); + return 0; +} + +/* Define what the initial system looks like. */ +void tx_application_define(void *first_unused_memory) +{ + +UINT status; +UCHAR *free_memory_pointer; + + + free_memory_pointer = (UCHAR *)first_unused_memory; + + /* Create client packet pool. */ + status = nx_packet_pool_create(&client_packet_pool, "SNTP Client Packet Pool", + NX_SNTP_CLIENT_PACKET_SIZE, free_memory_pointer, + NX_SNTP_CLIENT_PACKET_POOL_SIZE); + + /* Check for errors. */ + if (status != NX_SUCCESS) + { + + return; + } + + /* Initialize the NetX system. */ + nx_system_initialize(); + + /* Update pointer to unallocated (free) memory. */ + free_memory_pointer = free_memory_pointer + NX_SNTP_CLIENT_PACKET_POOL_SIZE; + + /* Create Client IP instances */ + status = nx_ip_create(&client_ip, "SNTP IP Instance", CLIENT_IP_ADDRESS, + 0xFFFFFF00UL, &client_packet_pool, _nx_ram_network_driver, + free_memory_pointer, 2048, 1); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + return; + } + + free_memory_pointer = free_memory_pointer + 2048; + + /* Enable ARP and supply ARP cache memory. */ + status = nx_arp_enable(&client_ip, (void **) free_memory_pointer, 2048); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + return; + } + + /* Update pointer to unallocated (free) memory. */ + free_memory_pointer = free_memory_pointer + 2048; + + /* Enable UDP for client. */ + status = nx_udp_enable(&client_ip); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + return; + } + + status = nx_icmp_enable(&client_ip); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + return; + } + + /* Create the client thread */ + status = tx_thread_create(&demo_client_thread, "SNTP Client Thread", demo_client_thread_entry, + (ULONG)(&demo_sntp_client), free_memory_pointer, 2048, + 4, 4, TX_NO_TIME_SLICE, TX_DONT_START); + + /* Check for errors */ + if (status != TX_SUCCESS) + { + + return; + } + + /* Create the event flags. */ + status = tx_event_flags_create(&sntp_flags, "SNTP event flags"); + + /* Check for errors */ + if (status != TX_SUCCESS) + { + + return; + } + + /* Update pointer to unallocated (free) memory. */ + free_memory_pointer = free_memory_pointer + 2048; + + /* set the SNTP network interface to the primary interface. */ + iface_index = 0; + + /* Create the SNTP Client to run in broadcast mode.. */ + status = nx_sntp_client_create(&demo_sntp_client, &client_ip, iface_index, &client_packet_pool, + leap_second_handler, + kiss_of_death_handler, + NULL /* no random_number_generator callback */); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + + /* Bail out!*/ + return; + } + + tx_thread_resume(&demo_client_thread); + + return; +} + +/* Define size of buffer to display client's local time. */ +#define BUFSIZE 50 + +/* Define the client thread. */ +void demo_client_thread_entry(ULONG info) +{ + +UINT status; +UINT spin; +UINT server_status; +ULONG base_seconds; +ULONG base_fraction; +ULONG seconds, milliseconds, microseconds, fraction; +UINT wait = 0; +UINT error_counter = 0; +ULONG events = 0; + + NX_PARAMETER_NOT_USED(info); + + /* Give other threads (IP instance) initialize first. */ + tx_thread_sleep(NX_IP_PERIODIC_RATE); + + + /* Setup time update callback function. */ + nx_sntp_client_set_time_update_notify(&demo_sntp_client, time_update_callback); + + /* Set up client time updates depending on mode. */ +#ifdef USE_UNICAST + + /* Initialize the Client for unicast mode to poll the SNTP server once an hour. */ + /* Use the IPv4 service to set up the Client and set the IPv4 SNTP server. */ + status = nx_sntp_client_initialize_unicast(&demo_sntp_client, SERVER_IP_ADDRESS); + + +#else /* Broadcast mode */ + + /* Initialize the Client for broadcast mode, no roundtrip calculation required and a broadcast SNTP service. */ + + /* Use the IPv4 service to initialize the Client and set IPv4 SNTP broadcast address. */ + status = nx_sntp_client_initialize_broadcast(&demo_sntp_client, NX_NULL, SERVER_IP_ADDRESS); +#endif /* USE_UNICAST */ + + /* Check for error. */ + if (status != NX_SUCCESS) + { + return; + } + + /* Set the base time which is approximately the number of seconds since the turn of the last century. + If this is not available in SNTP format, the nx_sntp_client_utility_add_msecs_to_ntp_time service + can convert milliseconds to fraction. For how to compute NTP seconds from real time, read the + NetX SNTP User Guide. + + Otherwise set the base time to zero and set NX_SNTP_CLIENT_IGNORE_MAX_ADJUST_STARTUP to NX_TRUE for + the SNTP CLient to accept the first time update without applying a minimum or maximum adjustment + parameters (NX_SNTP_CLIENT_MIN_TIME_ADJUSTMENT and NX_SNTP_CLIENT_MAX_TIME_ADJUSTMENT). */ + + base_seconds = 0xd2c96b90; /* Jan 24, 2012 UTC */ + base_fraction = 0xa132db1e; + + /* Apply to the SNTP Client local time. */ + status = nx_sntp_client_set_local_time(&demo_sntp_client, base_seconds, base_fraction); + + /* Check for error. */ + if (status != NX_SUCCESS) + { + return; + } + + /* Run whichever service the client is configured for. */ +#ifdef USE_UNICAST + status = nx_sntp_client_run_unicast(&demo_sntp_client); +#else + status = nx_sntp_client_run_broadcast(&demo_sntp_client); +#endif /* USE_UNICAST */ + + if (status != NX_SUCCESS) + { + return; + } + + spin = NX_TRUE; + + /* Now check periodically for time changes. */ + while(spin) + { + /* Wait for a server update event. */ + tx_event_flags_get(&sntp_flags, DEMO_SNTP_UPDATE_EVENT, TX_OR_CLEAR, &events, DEMO_PERIODIC_CHECK_INTERVAL); + + if (events == DEMO_SNTP_UPDATE_EVENT) + { + + /* Check for valid SNTP server status. */ + status = nx_sntp_client_receiving_updates(&demo_sntp_client, &server_status); + + if ((status != NX_SUCCESS) || (server_status == NX_FALSE)) + { + + /* We do not have a valid update. Skip processing any time data. */ + + /* If this happens repeatedly, consider stopping the SNTP Client thread, picking another + SNTP server and resuming the SNTP Client thread task (more details about that in the + comments at the end of this function). + + If SNTP Client configurable parameters are too restrictive, such as Max Adjustment, that may also cause + valid server updates to be rejected. Configurable parameters, however, cannot be changed at run time.*/ + + continue; + } + + /* We have a valid update. Get the SNTP Client time. */ + status = nx_sntp_client_get_local_time_extended(&demo_sntp_client, &seconds, &fraction, NX_NULL, 0); + + /* Convert fraction to microseconds. */ + nx_sntp_client_utility_fraction_to_usecs(fraction, µseconds); + + milliseconds = ((microseconds + 500) / 1000); + + if (status != NX_SUCCESS) + { + printf("Internal error with getting local time 0x%x\n", status); + error_counter++; + } + else + { + printf("\nSNTP updated\n"); + printf("Time: %lu.%03lu sec.\r\n", seconds, milliseconds); + } + + /* Clear all events in our event flag. */ + events = 0; + } + else + { + + /* No SNTP update event. + + In the meantime, if we have an RTC we might want to check its notion of time. + In this demo, we simulate the passage of time on our 'RTC' really just the CPU counter, + assuming that seconds and milliseconds have previously been set to a base (starting) time + (as was the SNTP Client before running it) */ + + seconds += 1; /* This is the sleep time (1 second) so is pretty close to an RTC */ + milliseconds += 1; /* We don't know this value but for demonstration purposes we change it */ + + /* Update our timer. */ + wait += DEMO_PERIODIC_CHECK_INTERVAL; + + /* Check if it is time to display the local 'RTC' time. */ + if (wait >= CHECK_SNTP_UPDATES_TIMEOUT) + { + /* It is. Reset the timeout and print local time. */ + wait = 0; + + printf("Time: %lu.%03lu sec.\r\n", seconds, milliseconds); + } + } + } + + /* We can stop the SNTP service if for example we think the SNTP server has stopped sending updates. + + To restart the SNTP Client, simply call the nx_sntp_client_initialize_unicast or nx_sntp_client_initialize_broadcast + using another SNTP server IP address as input, and resume the SNTP Client by calling nx_sntp_client_run_unicast or + nx_sntp_client_run_braodcast. */ + status = nx_sntp_client_stop(&demo_sntp_client); + + if (status != NX_SUCCESS) + { + error_counter++; + } + + /* When done with the SNTP Client, we delete it */ + status = nx_sntp_client_delete(&demo_sntp_client); + + return; +} + + +/* This application defined handler for handling an impending leap second is not + required by the SNTP Client. The default handler below only logs the event for + every time stamp received with the leap indicator set. */ + +UINT leap_second_handler(NX_SNTP_CLIENT *client_ptr, UINT leap_indicator) +{ + NX_PARAMETER_NOT_USED(client_ptr); + NX_PARAMETER_NOT_USED(leap_indicator); + + /* Handle the leap second handler... */ + + return NX_SUCCESS; +} + +/* This application defined handler for handling a Kiss of Death packet is not + required by the SNTP Client. A KOD handler should determine + if the Client task should continue vs. abort sending/receiving time data + from its current time server, and if aborting if it should remove + the server from its active server list. + + Note that the KOD list of codes is subject to change. The list + below is current at the time of this software release. */ + +UINT kiss_of_death_handler(NX_SNTP_CLIENT *client_ptr, UINT KOD_code) +{ + +UINT remove_server_from_list = NX_FALSE; +UINT status = NX_SUCCESS; + + NX_PARAMETER_NOT_USED(client_ptr); + + /* Handle kiss of death by code group. */ + switch (KOD_code) + { + + case NX_SNTP_KOD_RATE: + case NX_SNTP_KOD_NOT_INIT: + case NX_SNTP_KOD_STEP: + + /* Find another server while this one is temporarily out of service. */ + status = NX_SNTP_KOD_SERVER_NOT_AVAILABLE; + + break; + + case NX_SNTP_KOD_AUTH_FAIL: + case NX_SNTP_KOD_NO_KEY: + case NX_SNTP_KOD_CRYP_FAIL: + + /* These indicate the server will not service client with time updates + without successful authentication. */ + + + remove_server_from_list = NX_TRUE; + + break; + + + default: + + /* All other codes. Remove server before resuming time updates. */ + + remove_server_from_list = NX_TRUE; + break; + } + + /* Removing the server from the active server list? */ + if (remove_server_from_list) + { + + /* Let the caller know it has to bail on this server before resuming service. */ + status = NX_SNTP_KOD_REMOVE_SERVER; + } + + return status; +} + + +/* This application defined handler for notifying SNTP time update event. */ + +VOID time_update_callback(NX_SNTP_TIME_MESSAGE *time_update_ptr, NX_SNTP_TIME *local_time) +{ + NX_PARAMETER_NOT_USED(time_update_ptr); + NX_PARAMETER_NOT_USED(local_time); + + tx_event_flags_set(&sntp_flags, DEMO_SNTP_UPDATE_EVENT, TX_OR); +} + diff --git a/samples/demo_netx_tcp.c b/samples/demo_netx_tcp.c new file mode 100644 index 0000000..2a499db --- /dev/null +++ b/samples/demo_netx_tcp.c @@ -0,0 +1,364 @@ +/* This is a small demo of the high-performance NetX TCP/IP stack. This demo concentrates + on TCP connection, disconnection, sending, and receiving using ARP and a simulated + Ethernet driver. */ + +#include "tx_api.h" +#include "nx_api.h" + +#define DEMO_STACK_SIZE 2048 +#define DEMO_DATA "ABCDEFGHIJKLMNOPQRSTUVWXYZ " +#define PACKET_SIZE 1536 +#define POOL_SIZE ((sizeof(NX_PACKET) + PACKET_SIZE) * 16) + + +/* Define the ThreadX and NetX object control blocks... */ + +TX_THREAD thread_0; +TX_THREAD thread_1; + +NX_PACKET_POOL pool_0; +NX_IP ip_0; +NX_IP ip_1; +NX_TCP_SOCKET client_socket; +NX_TCP_SOCKET server_socket; +UCHAR pool_buffer[POOL_SIZE]; + + + +/* Define the counters used in the demo application... */ + +ULONG thread_0_counter; +ULONG thread_1_counter; +ULONG error_counter; + + +/* Define thread prototypes. */ + +void thread_0_entry(ULONG thread_input); +void thread_1_entry(ULONG thread_input); +void thread_1_connect_received(NX_TCP_SOCKET *server_socket, UINT port); +void thread_1_disconnect_received(NX_TCP_SOCKET *server_socket); + +void _nx_ram_network_driver(struct NX_IP_DRIVER_STRUCT *driver_req); + + +/* Define main entry point. */ + +int main() +{ + + /* Enter the ThreadX kernel. */ + tx_kernel_enter(); +} + + +/* Define what the initial system looks like. */ + +void tx_application_define(void *first_unused_memory) +{ + +CHAR *pointer; +UINT status; + + + /* Setup the working pointer. */ + pointer = (CHAR *)first_unused_memory; + + /* Create the main thread. */ + tx_thread_create(&thread_0, "thread 0", thread_0_entry, 0, + pointer, DEMO_STACK_SIZE, + 4, 4, TX_NO_TIME_SLICE, TX_AUTO_START); + + pointer = pointer + DEMO_STACK_SIZE; + + /* Create the main thread. */ + tx_thread_create(&thread_1, "thread 1", thread_1_entry, 0, + pointer, DEMO_STACK_SIZE, + 3, 3, TX_NO_TIME_SLICE, TX_AUTO_START); + + pointer = pointer + DEMO_STACK_SIZE; + + + /* Initialize the NetX system. */ + nx_system_initialize(); + + /* Create a packet pool. */ + status = nx_packet_pool_create(&pool_0, "NetX Main Packet Pool", PACKET_SIZE, pool_buffer, POOL_SIZE); + + if (status) + { + error_counter++; + } + + /* Create an IP instance. */ + status = nx_ip_create(&ip_0, "NetX IP Instance 0", IP_ADDRESS(1, 2, 3, 4), 0xFFFFFF00UL, &pool_0, _nx_ram_network_driver, + pointer, 2048, 1); + pointer = pointer + 2048; + + /* Create another IP instance. */ + status += nx_ip_create(&ip_1, "NetX IP Instance 1", IP_ADDRESS(1, 2, 3, 5), 0xFFFFFF00UL, &pool_0, _nx_ram_network_driver, + pointer, 2048, 1); + pointer = pointer + 2048; + + if (status) + { + error_counter++; + } + + /* Enable ARP and supply ARP cache memory for IP Instance 0. */ + status = nx_arp_enable(&ip_0, (void *)pointer, 1024); + pointer = pointer + 1024; + + /* Enable ARP and supply ARP cache memory for IP Instance 1. */ + status += nx_arp_enable(&ip_1, (void *)pointer, 1024); + pointer = pointer + 1024; + + /* Check ARP enable status. */ + if (status) + { + error_counter++; + } + + /* Enable TCP processing for both IP instances. */ + status = nx_tcp_enable(&ip_0); + status += nx_tcp_enable(&ip_1); + + /* Check TCP enable status. */ + if (status) + { + error_counter++; + } +} + + + +/* Define the test threads. */ + +void thread_0_entry(ULONG thread_input) +{ + +UINT status; +NX_PACKET *my_packet; +ULONG length; + + NX_PARAMETER_NOT_USED(thread_input); + + /* Loop to repeat things over and over again! */ + while (1) + { + + /* Increment thread 0's counter. */ + thread_0_counter++; + + /* Create a socket. */ + status = nx_tcp_socket_create(&ip_0, &client_socket, "Client Socket", + NX_IP_NORMAL, NX_FRAGMENT_OKAY, NX_IP_TIME_TO_LIVE, 200, + NX_NULL, NX_NULL); + + /* Check for error. */ + if (status) + { + error_counter++; + } + + /* Bind the socket. */ + status = nx_tcp_client_socket_bind(&client_socket, 12, NX_WAIT_FOREVER); + + /* Check for error. */ + if (status) + { + error_counter++; + } + + /* Attempt to connect the socket. */ + status = nx_tcp_client_socket_connect(&client_socket, IP_ADDRESS(1, 2, 3, 5), 12, NX_IP_PERIODIC_RATE); + + /* Check for error. */ + if (status) + { + error_counter++; + } + + /* Allocate a packet. */ + status = nx_packet_allocate(&pool_0, &my_packet, NX_TCP_PACKET, NX_WAIT_FOREVER); + + /* Check status. */ + if (status != NX_SUCCESS) + { + break; + } + + /* Write ABCs into the packet payload! */ + memcpy(my_packet -> nx_packet_prepend_ptr, DEMO_DATA, sizeof(DEMO_DATA)); + + /* Adjust the write pointer. */ + my_packet -> nx_packet_length = sizeof(DEMO_DATA); + my_packet -> nx_packet_append_ptr = my_packet -> nx_packet_prepend_ptr + sizeof(DEMO_DATA); + + status = nx_packet_length_get(my_packet, &length); + if ((status) || (length != sizeof(DEMO_DATA))) + { + error_counter++; + } + + /* Send the packet out! */ + status = nx_tcp_socket_send(&client_socket, my_packet, NX_IP_PERIODIC_RATE); + + /* Determine if the status is valid. */ + if (status) + { + error_counter++; + nx_packet_release(my_packet); + } + + /* Disconnect this socket. */ + status = nx_tcp_socket_disconnect(&client_socket, NX_IP_PERIODIC_RATE); + + /* Determine if the status is valid. */ + if (status) + { + error_counter++; + } + + /* Unbind the socket. */ + status = nx_tcp_client_socket_unbind(&client_socket); + + /* Check for error. */ + if (status) + { + error_counter++; + } + + /* Delete the socket. */ + status = nx_tcp_socket_delete(&client_socket); + + /* Check for error. */ + if (status) + { + error_counter++; + } + } +} + + +void thread_1_entry(ULONG thread_input) +{ + +UINT status; +NX_PACKET *packet_ptr; +ULONG actual_status; + + NX_PARAMETER_NOT_USED(thread_input); + + /* Ensure the IP instance has been initialized. */ + status = nx_ip_status_check(&ip_1, NX_IP_INITIALIZE_DONE, &actual_status, NX_IP_PERIODIC_RATE); + + /* Check status... */ + if (status != NX_SUCCESS) + { + + error_counter++; + return; + } + + /* Create a socket. */ + status = nx_tcp_socket_create(&ip_1, &server_socket, "Server Socket", + NX_IP_NORMAL, NX_FRAGMENT_OKAY, NX_IP_TIME_TO_LIVE, 100, + NX_NULL, thread_1_disconnect_received); + + /* Check for error. */ + if (status) + { + error_counter++; + } + + /* Setup this thread to listen. */ + status = nx_tcp_server_socket_listen(&ip_1, 12, &server_socket, 5, thread_1_connect_received); + + /* Check for error. */ + if (status) + { + error_counter++; + } + + /* Loop to create and establish server connections. */ + while (1) + { + + /* Increment thread 1's counter. */ + thread_1_counter++; + + /* Accept a client socket connection. */ + status = nx_tcp_server_socket_accept(&server_socket, NX_IP_PERIODIC_RATE); + + /* Check for error. */ + if (status) + { + error_counter++; + } + + /* Receive a TCP message from the socket. */ + status = nx_tcp_socket_receive(&server_socket, &packet_ptr, NX_IP_PERIODIC_RATE); + + /* Check for error. */ + if (status) + { + error_counter++; + } + else + { + /* Release the packet. */ + nx_packet_release(packet_ptr); + } + + /* Disconnect the server socket. */ + status = nx_tcp_socket_disconnect(&server_socket, NX_IP_PERIODIC_RATE); + + /* Check for error. */ + if (status) + { + error_counter++; + } + + /* Unaccept the server socket. */ + status = nx_tcp_server_socket_unaccept(&server_socket); + + /* Check for error. */ + if (status) + { + error_counter++; + } + + /* Setup server socket for listening again. */ + status = nx_tcp_server_socket_relisten(&ip_1, 12, &server_socket); + + /* Check for error. */ + if (status) + { + error_counter++; + } + } +} + + +void thread_1_connect_received(NX_TCP_SOCKET *socket_ptr, UINT port) +{ + + /* Check for the proper socket and port. */ + if ((socket_ptr != &server_socket) || (port != 12)) + { + error_counter++; + } +} + + +void thread_1_disconnect_received(NX_TCP_SOCKET *socket) +{ + + /* Check for proper disconnected socket. */ + if (socket != &server_socket) + { + error_counter++; + } +} + diff --git a/samples/demo_netx_telnet.c b/samples/demo_netx_telnet.c new file mode 100644 index 0000000..f7b9d10 --- /dev/null +++ b/samples/demo_netx_telnet.c @@ -0,0 +1,389 @@ +/* This is a small demo of TELNET on the high-performance NetX TCP/IP stack. + This demo relies on ThreadX and NetX to show a simple TELNET connection, + send, server echo, and then disconnection from the TELNET server. */ + +#include "tx_api.h" +#include "nx_api.h" +#include "nx_telnet_client.h" +#include "nx_telnet_server.h" + +#define DEMO_STACK_SIZE 4096 + + +/* Define the ThreadX and NetX object control blocks... */ + +TX_THREAD server_thread; +TX_THREAD client_thread; +NX_PACKET_POOL pool_server; +NX_PACKET_POOL pool_client; +NX_IP ip_server; +NX_IP ip_client; + + + +/* Define TELNET objects. */ + +NX_TELNET_SERVER my_server; +NX_TELNET_CLIENT my_client; + + +#define SERVER_ADDRESS IP_ADDRESS(1,2,3,4) +#define CLIENT_ADDRESS IP_ADDRESS(1,2,3,5) + + +/* Define the counters used in the demo application... */ + +ULONG error_counter; + + +/* Define timeout in ticks for connecting and sending/receiving data. */ + +#define TELNET_TIMEOUT (2 * NX_IP_PERIODIC_RATE) + +/* Define function prototypes. */ + +void thread_server_entry(ULONG thread_input); +void thread_client_entry(ULONG thread_input); + +/* Replace the 'ram' driver with your actual Ethernet driver. */ +void _nx_ram_network_driver(struct NX_IP_DRIVER_STRUCT *driver_req); + + +/* Define the application's TELNET Server callback routines. */ + +void telnet_new_connection(NX_TELNET_SERVER *server_ptr, UINT logical_connection); +void telnet_receive_data(NX_TELNET_SERVER *server_ptr, UINT logical_connection, NX_PACKET *packet_ptr); +void telnet_connection_end(NX_TELNET_SERVER *server_ptr, UINT logical_connection); + + +/* Define main entry point. */ + +int main() +{ + + /* Enter the ThreadX kernel. */ + tx_kernel_enter(); +} + + +/* Define what the initial system looks like. */ +void tx_application_define(void *first_unused_memory) +{ + +UINT status; +CHAR *pointer; + + + /* Setup the working pointer. */ + pointer = (CHAR *) first_unused_memory; + + /* Create the server thread. */ + tx_thread_create(&server_thread, "server thread", thread_server_entry, 0, + pointer, DEMO_STACK_SIZE, + 4, 4, TX_NO_TIME_SLICE, TX_AUTO_START); + + pointer = pointer + DEMO_STACK_SIZE; + + /* Create the client thread. */ + tx_thread_create(&client_thread, "client thread", thread_client_entry, 0, + pointer, DEMO_STACK_SIZE, + 6, 6, TX_NO_TIME_SLICE, TX_AUTO_START); + + pointer = pointer + DEMO_STACK_SIZE; + + /* Initialize the NetX system. */ + nx_system_initialize(); + + /* Create packet pool. */ + nx_packet_pool_create(&pool_server, "Server NetX Packet Pool", 600, pointer, 8192); + pointer = pointer + 8192; + + /* Create an IP instance. */ + nx_ip_create(&ip_server, "Server NetX IP Instance", SERVER_ADDRESS, + 0xFFFFFF00UL, &pool_server, _nx_ram_network_driver, + pointer, 4096, 1); + + pointer = pointer + 4096; + + /* Create another packet pool. */ + nx_packet_pool_create(&pool_client, "Client NetX Packet Pool", 600, pointer, 8192); + pointer = pointer + 8192; + + /* Create another IP instance. */ + nx_ip_create(&ip_client, "Client NetX IP Instance", CLIENT_ADDRESS, + 0xFFFFFF00UL, &pool_client, _nx_ram_network_driver, + pointer, 4096, 1); + + pointer = pointer + 4096; + + /* Enable ARP and supply ARP cache memory for IP Instance 0. */ + nx_arp_enable(&ip_server, (void *) pointer, 1024); + pointer = pointer + 1024; + + /* Enable ARP and supply ARP cache memory for IP Instance 1. */ + nx_arp_enable(&ip_client, (void *) pointer, 1024); + pointer = pointer + 1024; + + /* Enable TCP processing for both IP instances. */ + nx_tcp_enable(&ip_server); + nx_tcp_enable(&ip_client); + + + /* Create the NetX TELNET Server. */ + status = nx_telnet_server_create(&my_server, "Telnet Server", &ip_server, + pointer, 2048, telnet_new_connection, telnet_receive_data, + telnet_connection_end); + + /* Check for errors. */ + if (status) + error_counter++; + + return; +} + +/* Define the Server thread. */ +void thread_server_entry(ULONG thread_input) +{ + +UINT status; + + NX_PARAMETER_NOT_USED(thread_input); + + /* Allow IP thread task to initialize the system. */ + tx_thread_sleep(NX_IP_PERIODIC_RATE); + + + + /* Start the TELNET Server. */ + status = nx_telnet_server_start(&my_server); + + /* Check for errors. */ + if (status != NX_SUCCESS) + { + + return; + } + + +} + +/* Define the client thread. */ +void thread_client_entry(ULONG thread_input) +{ + +NX_PACKET *my_packet; +UINT status; + + NX_PARAMETER_NOT_USED(thread_input); + + /* Allow IP thread task to initialize the system. */ + tx_thread_sleep(NX_IP_PERIODIC_RATE); + + + /* Create a TELENT client instance. */ + status = nx_telnet_client_create(&my_client, "My TELNET Client", &ip_client, 600); + + /* Check status. */ + if (status != NX_SUCCESS) + { + return; + } + + do + { + /* Connect the TELNET client to the TELNET Server at port 23 over IPv4. */ + status = nx_telnet_client_connect(&my_client, SERVER_ADDRESS, NX_TELNET_SERVER_PORT, TELNET_TIMEOUT); + } while (status != NX_SUCCESS); + + /* Check status. */ + if (status != NX_SUCCESS) + { + return; + } + + /* Allocate a packet. */ + status = nx_packet_allocate(&pool_client, &my_packet, NX_TCP_PACKET, NX_WAIT_FOREVER); + + /* Check status. */ + if (status != NX_SUCCESS) + { + return; + } + + /* Build a simple 1-byte message. */ + nx_packet_data_append(my_packet, "a", 1, &pool_client, NX_WAIT_FOREVER); + + /* Send the packet to the TELNET Server. */ + status = nx_telnet_client_packet_send(&my_client, my_packet, TELNET_TIMEOUT); + + /* Check status. */ + if (status != NX_SUCCESS) + { + return; + } + + /* Pickup the Server header. */ + status = nx_telnet_client_packet_receive(&my_client, &my_packet, TELNET_TIMEOUT); + + /* Check status. */ + if (status != NX_SUCCESS) + { + return; + } + + /* At this point the packet should contain the Server's banner + message sent by the Server callback function below. Just + release it for this demo. */ + nx_packet_release(my_packet); + + /* Pickup the Server echo of the character. */ + status = nx_telnet_client_packet_receive(&my_client, &my_packet, TELNET_TIMEOUT); + + /* Check status. */ + if (status != NX_SUCCESS) + { + return; + } + + /* At this point the packet should contain the character 'a' that + we sent earlier. Just release the packet for now. */ + nx_packet_release(my_packet); + + /* Now disconnect form the TELNET Server. */ + status = nx_telnet_client_disconnect(&my_client, TELNET_TIMEOUT); + + + /* Check status. */ + if (status != NX_SUCCESS) + { + return; + } + + /* Delete the TELNET Client. */ + status = nx_telnet_client_delete(&my_client); + + /* Check status. */ + if (status != NX_SUCCESS) + { + return; + } +} + + +/* This routine is called by the NetX Telnet Server whenever a new Telnet client + connection is established. */ +void telnet_new_connection(NX_TELNET_SERVER *server_ptr, UINT logical_connection) +{ + +UINT status; +NX_PACKET *packet_ptr; + + + + /* Allocate a packet for client greeting. */ + status = nx_packet_allocate(&pool_server, &packet_ptr, NX_TCP_PACKET, NX_NO_WAIT); + + if (status != NX_SUCCESS) + { + error_counter++; + return; + } + + /* Build a banner message and a prompt. */ + nx_packet_data_append(packet_ptr, "**** Welcome to NetX TELNET Server ****\r\n\r\n\r\n", 45, + &pool_server, NX_NO_WAIT); + + nx_packet_data_append(packet_ptr, "NETX> ", 6, &pool_server, NX_NO_WAIT); + + /* Send the packet to the client. */ + status = nx_telnet_server_packet_send(server_ptr, logical_connection, packet_ptr, TELNET_TIMEOUT); + + if (status != NX_SUCCESS) + { + error_counter++; + nx_packet_release(packet_ptr); + } + + return; +} + + +/* This routine is called by the NetX Telnet Server whenever data is present on a Telnet client + connection. */ +void telnet_receive_data(NX_TELNET_SERVER *server_ptr, UINT logical_connection, NX_PACKET *packet_ptr) +{ + +UINT status; +UCHAR alpha; + + + /* This demo just echoes the character back and on sends a new prompt back to the + client. A real system would most likely buffer the character(s) received in a buffer + associated with the supplied logical connection and process according to it. */ + + + /* Just throw away carriage returns. */ + if ((packet_ptr -> nx_packet_prepend_ptr[0] == '\r') && (packet_ptr -> nx_packet_length == 1)) + { + + nx_packet_release(packet_ptr); + return; + } + + /* Setup new line on line feed. */ + if ((packet_ptr -> nx_packet_prepend_ptr[0] == '\n') || + ((packet_ptr -> nx_packet_prepend_ptr[0] == '\r') && (packet_ptr -> nx_packet_prepend_ptr[1] == '\n'))) + { + + /* Clean up the packet. */ + packet_ptr -> nx_packet_length = 0; + packet_ptr -> nx_packet_prepend_ptr = packet_ptr -> nx_packet_data_start + NX_TCP_PACKET; + packet_ptr -> nx_packet_append_ptr = packet_ptr -> nx_packet_data_start + NX_TCP_PACKET; + + /* Build the next prompt. */ + nx_packet_data_append(packet_ptr, "\r\nNETX> ", 8, &pool_server, NX_NO_WAIT); + + /* Send the packet to the client. */ + status = nx_telnet_server_packet_send(server_ptr, logical_connection, packet_ptr, TELNET_TIMEOUT); + + if (status != NX_SUCCESS) + { + error_counter++; + nx_packet_release(packet_ptr); + } + + return; + } + + /* Pickup first character (usually only one from client). */ + alpha = packet_ptr -> nx_packet_prepend_ptr[0]; + + /* Echo character. */ + status = nx_telnet_server_packet_send(server_ptr, logical_connection, packet_ptr, TELNET_TIMEOUT); + + if (status != NX_SUCCESS) + { + error_counter++; + nx_packet_release(packet_ptr); + } + + /* Check for a disconnection. */ + if (alpha == 'q') + { + + /* Initiate server disconnection. */ + nx_telnet_server_disconnect(server_ptr, logical_connection); + } +} + + +/* This routine is called by the NetX Telnet Server whenever the client disconnects. */ +void telnet_connection_end(NX_TELNET_SERVER *server_ptr, UINT logical_connection) +{ + NX_PARAMETER_NOT_USED(server_ptr); + NX_PARAMETER_NOT_USED(logical_connection); + + /* Cleanup any application specific connection or buffer information. */ + return; +} + diff --git a/samples/demo_netx_tftp.c b/samples/demo_netx_tftp.c new file mode 100644 index 0000000..bcfcfcc --- /dev/null +++ b/samples/demo_netx_tftp.c @@ -0,0 +1,381 @@ +/* This is a small demo of TFTP on the high-performance NetX TCP/IP stack. This demo + relies on ThreadX and NetX , to show a simple file transfer from the client + and then back to the server. */ + +/* Indicate if using a NetX TFTP services. To port a NetX TFTP application to NetX TFTP + undefine this term. */ + + +#include "tx_api.h" +#include "nx_api.h" +#include "nx_tftp_client.h" +#include "nx_tftp_server.h" +#ifndef NX_TFTP_NO_FILEX +#include "fx_api.h" +#endif + + +#define DEMO_STACK_SIZE 4096 +#define DEMO_DATA "ABCDEFGHIJKLMNOPQRSTUVWXYZ " + +/* To use another file storage utility define this symbol: +#define NX_TFTP_NO_FILEX +*/ + +/* Define the ThreadX, NetX, and FileX object control blocks... */ + +TX_THREAD server_thread; +TX_THREAD client_thread; +NX_PACKET_POOL server_pool; +NX_IP server_ip; +NX_PACKET_POOL client_pool; +NX_IP client_ip; +FX_MEDIA ram_disk; + +/* Define the NetX TFTP object control blocks. */ + +NX_TFTP_CLIENT client; +NX_TFTP_SERVER server; + +/* Define the application global variables */ + +#define CLIENT_ADDRESS IP_ADDRESS(1, 2, 3, 5) +#define SERVER_ADDRESS IP_ADDRESS(1, 2, 3, 4) + + +UINT error_counter = 0; + +/* Define buffer used in the demo application. */ +UCHAR buffer[255]; +ULONG data_length; + + +/* Define the memory area for the FileX RAM disk. */ +#ifndef NX_TFTP_NO_FILEX +UCHAR ram_disk_memory[32000]; +UCHAR ram_disk_sector_cache[512]; +#endif + + +/* Define function prototypes. */ + +VOID _fx_ram_driver(FX_MEDIA *media_ptr); +VOID _nx_ram_network_driver(NX_IP_DRIVER *driver_req_ptr); +void client_thread_entry(ULONG thread_input); +void server_thread_entry(ULONG thread_input); + + +/* Define main entry point. */ + +int main() +{ + + /* Enter the ThreadX kernel. */ + tx_kernel_enter(); +} + + +/* Define what the initial system looks like. */ + +void tx_application_define(void *first_unused_memory) +{ + +UINT status; +UCHAR *pointer; + + + /* Setup the working pointer. */ + pointer = (UCHAR *) first_unused_memory; + + + /* Create the main TFTP server thread. */ + status = tx_thread_create(&server_thread, "TFTP Server Thread", server_thread_entry, 0, + pointer, DEMO_STACK_SIZE, + 4,4, TX_NO_TIME_SLICE, TX_AUTO_START); + + pointer += DEMO_STACK_SIZE ; + + /* Check for errors. */ + if (status) + error_counter++; + + + /* Create the main TFTP client thread at a slightly lower priority. */ + status = tx_thread_create(&client_thread, "TFTP Client Thread", client_thread_entry, 0, + pointer, DEMO_STACK_SIZE, + 5, 5, TX_NO_TIME_SLICE, TX_DONT_START); + + pointer += DEMO_STACK_SIZE ; + + /* Check for errors. */ + if (status) + error_counter++; + + /* Initialize the NetX system. */ + nx_system_initialize(); + + /* Note: The data portion of a packet is exactly 512 bytes, but the packet payload size must + be at least 580 bytes. The remaining bytes are used for the UDP, IP, and Ethernet + headers and byte alignment requirements. */ + + status = nx_packet_pool_create(&server_pool, "TFTP Server Packet Pool", NX_TFTP_PACKET_SIZE, pointer, 8192); + pointer = pointer + 8192; + + /* Check for errors. */ + if (status) + error_counter++; + + /* Create the IP instance for the TFTP Server. */ + status = nx_ip_create(&server_ip, "NetX Server IP Instance", SERVER_ADDRESS, 0xFFFFFF00UL, + &server_pool, _nx_ram_network_driver, pointer, 2048, 1); + pointer = pointer + 2048; + + /* Check for errors. */ + if (status) + error_counter++; + + /* Enable ARP and supply ARP cache memory for IP Instance 0. */ + status = nx_arp_enable(&server_ip, (void *) pointer, 1024); + pointer = pointer + 1024; + + /* Check for errors. */ + if (status) + error_counter++; + + /* Enable UDP. */ + status = nx_udp_enable(&server_ip); + + /* Check for errors. */ + if (status) + error_counter++; + + + /* Create the TFTP server. */ + status = nx_tftp_server_create(&server, "TFTP Server Instance", &server_ip, &ram_disk, + pointer, DEMO_STACK_SIZE, &server_pool); + + pointer = pointer + DEMO_STACK_SIZE; + + /* Check for errors for the server. */ + if (status) + error_counter++; + + /* Create a packet pool for the TFTP client. */ + + /* Note: The data portion of a packet is exactly 512 bytes, but the packet payload size must + be at least 580 bytes. The remaining bytes are used for the UDP, IP, and Ethernet + headers and byte alignment requirements. */ + + status = nx_packet_pool_create(&client_pool, "TFTP Client Packet Pool", NX_TFTP_PACKET_SIZE, pointer, 8192); + pointer = pointer + 8192; + + /* Create an IP instance for the TFTP client. */ + status = nx_ip_create(&client_ip, "TFTP Client IP Instance", CLIENT_ADDRESS, 0xFFFFFF00UL, + &client_pool, _nx_ram_network_driver, pointer, 2048, 1); + pointer = pointer + 2048; + + /* Enable ARP and supply ARP cache memory for IP Instance 1. */ + status = nx_arp_enable(&client_ip, (void *) pointer, 1024); + pointer = pointer + 1024; + + /* Enable UDP for client IP instance. */ + status = nx_udp_enable(&client_ip); + + /* Check for errors. */ + if (status) + error_counter++; + + tx_thread_resume(&client_thread); +} + +void server_thread_entry(ULONG thread_input) +{ + +UINT status, running; + + NX_PARAMETER_NOT_USED(thread_input); + + /* Allow time for the network driver and NetX to get initialized. */ + tx_thread_sleep(NX_IP_PERIODIC_RATE); + +#ifndef NX_TFTP_NO_FILEX + + /* Format the RAM disk - the memory for the RAM disk was defined above. */ + status = fx_media_format(&ram_disk, + _fx_ram_driver, /* Driver entry */ + ram_disk_memory, /* RAM disk memory pointer */ + ram_disk_sector_cache, /* Media buffer pointer */ + sizeof(ram_disk_sector_cache), /* Media buffer size */ + "MY_RAM_DISK", /* Volume Name */ + 1, /* Number of FATs */ + 32, /* Directory Entries */ + 0, /* Hidden sectors */ + 256, /* Total sectors */ + 128, /* Sector size */ + 1, /* Sectors per cluster */ + 1, /* Heads */ + 1); /* Sectors per track */ + + /* Check for errors. */ + if (status != FX_SUCCESS) + { + return; + } + + /* Open the RAM disk. */ + status = fx_media_open(&ram_disk, "RAM DISK", _fx_ram_driver, ram_disk_memory, ram_disk_sector_cache, sizeof(ram_disk_sector_cache)); + + /* Check for errors. */ + if (status != FX_SUCCESS) + { + return; + } + +#endif /* NX_TFTP_NO_FILEX */ + + + /* Start the NetX TFTP server. */ + status = nx_tftp_server_start(&server); + + /* Check for errors. */ + if (status) + { + error_counter++; + return; + } + + /* Run for a while */ + running = NX_TRUE; + while(running) + tx_thread_sleep(NX_IP_PERIODIC_RATE); + + nx_tftp_server_delete(&server); + + /* Flush the media of changed file data, close all open files and ensure + directory information is also written out to the media.*/ + status = fx_media_close(&ram_disk); + if (status) + error_counter++; + + return; +} + +/* Define the TFTP client thread. */ + +void client_thread_entry(ULONG thread_input) +{ + +NX_PACKET *my_packet; +UINT status; +UINT all_done = NX_FALSE; + + NX_PARAMETER_NOT_USED(thread_input); + + /* Allow time for the network driver and NetX to get initialized. */ + tx_thread_sleep(NX_IP_PERIODIC_RATE); + + + + /* The TFTP services used below include the NetX equivalent service which will work with + NetX TFTP. + */ + + /* Create a TFTP client. */ + status = nx_tftp_client_create(&client, "TFTP Client", &client_ip, &client_pool); + + /* Check status. */ + if (status) + return; + + /* Open a TFTP file for writing. */ + status = nx_tftp_client_file_open(&client, "test.txt", SERVER_ADDRESS, NX_TFTP_OPEN_FOR_WRITE, NX_IP_PERIODIC_RATE); + + /* Check status. */ + if (status) + return; + + /* Allocate a TFTP packet. */ + status = nx_tftp_client_packet_allocate(&client_pool, &my_packet, NX_IP_PERIODIC_RATE); + /* Check status. */ + if (status) + error_counter++; + + /* Write ABCs into the packet payload! */ + memcpy(my_packet -> nx_packet_prepend_ptr, DEMO_DATA, sizeof(DEMO_DATA)); + + /* Adjust the write pointer. */ + my_packet -> nx_packet_length = sizeof(DEMO_DATA); + my_packet -> nx_packet_append_ptr = my_packet -> nx_packet_prepend_ptr + sizeof(DEMO_DATA); + + /* Write this packet to the file via TFTP. */ + status = nx_tftp_client_file_write(&client, my_packet, NX_IP_PERIODIC_RATE); + + /* Check status. */ + if (status) + error_counter++; + + /* Close this file. */ + status = nx_tftp_client_file_close(&client); + + /* Check status. */ + if (status) + error_counter++; + + /* Open the same file for reading. */ + status = nx_tftp_client_file_open(&client, "test.txt", SERVER_ADDRESS, NX_TFTP_OPEN_FOR_READ, NX_IP_PERIODIC_RATE); + + /* Check status. */ + if (status) + error_counter++; + do + { + + /* Read the file back. */ + status = nx_tftp_client_file_read(&client, &my_packet, NX_IP_PERIODIC_RATE); + /* Check for retranmission/dropped packet error. Benign. Try again... */ + if (status == NX_TFTP_INVALID_BLOCK_NUMBER) + { + + continue; + } + else if (status == NX_TFTP_END_OF_FILE) + { + + /* All done. */ + all_done = NX_TRUE; + } + else if (status != NX_SUCCESS) + { + + /* Internal error, invalid packet or error on read. */ + break; + } + + + /* Do something with the packet data and release when done. */ + nx_packet_data_retrieve(my_packet, buffer, &data_length); + buffer[data_length] = 0; + printf("Receive data: %s\n", buffer); + + printf("release packet in demo.\n"); + + nx_packet_release(my_packet); + + } while (all_done == NX_FALSE); + + /* Close the file again. */ + status = nx_tftp_client_file_close(&client); + + /* Check status. */ + if (status) + error_counter++; + + /* Delete the client. */ + status = nx_tftp_client_delete(&client); + + /* Check status. */ + if (status) + error_counter++; + + return; +} diff --git a/samples/demo_netx_udp.c b/samples/demo_netx_udp.c new file mode 100644 index 0000000..3ef8eb5 --- /dev/null +++ b/samples/demo_netx_udp.c @@ -0,0 +1,265 @@ +/* This is a small demo of the high-performance NetX TCP/IP stack. This demo concentrates + on UDP packet sending and receiving - with ARP - using a simulated Ethernet driver. */ + +#include "tx_api.h" +#include "nx_api.h" + +#define DEMO_STACK_SIZE 2048 +#define DEMO_DATA "ABCDEFGHIJKLMNOPQRSTUVWXYZ " +#define PACKET_SIZE 1536 +#define POOL_SIZE ((sizeof(NX_PACKET) + PACKET_SIZE) * 16) + + +/* Define the ThreadX and NetX object control blocks. */ + +TX_THREAD thread_0; +TX_THREAD thread_1; + +NX_PACKET_POOL pool_0; +NX_IP ip_0; +NX_IP ip_1; + + +NX_UDP_SOCKET socket_0; +NX_UDP_SOCKET socket_1; +UCHAR pool_buffer[POOL_SIZE]; + + +/* Define the counters used in the demo application... */ + +ULONG thread_0_counter; +ULONG thread_1_counter; +ULONG error_counter; + +/* Define thread prototypes. */ + +void thread_0_entry(ULONG thread_input); +void thread_1_entry(ULONG thread_input); +void _nx_ram_network_driver(struct NX_IP_DRIVER_STRUCT *driver_req); + + +/* Define main entry point. */ + +int main() +{ + + /* Enter the ThreadX kernel. */ + tx_kernel_enter(); +} + + +/* Define what the initial system looks like. */ + +void tx_application_define(void *first_unused_memory) +{ + +CHAR *pointer; +UINT status; + + + /* Setup the working pointer. */ + pointer = (CHAR *)first_unused_memory; + + /* Create the main thread. */ + tx_thread_create(&thread_0, "thread 0", thread_0_entry, 0, + pointer, DEMO_STACK_SIZE, + 4, 4, TX_NO_TIME_SLICE, TX_AUTO_START); + pointer = pointer + DEMO_STACK_SIZE; + + /* Create the main thread. */ + tx_thread_create(&thread_1, "thread 1", thread_1_entry, 0, + pointer, DEMO_STACK_SIZE, + 3, 3, TX_NO_TIME_SLICE, TX_AUTO_START); + pointer = pointer + DEMO_STACK_SIZE; + + /* Initialize the NetX system. */ + nx_system_initialize(); + + /* Create a packet pool. */ + status = nx_packet_pool_create(&pool_0, "NetX Main Packet Pool", PACKET_SIZE, pool_buffer, POOL_SIZE); + + /* Check for pool creation error. */ + if (status) + { + error_counter++; + } + + /* Create an IP instance. */ + status = nx_ip_create(&ip_0, "NetX IP Instance 0", IP_ADDRESS(1, 2, 3, 4), 0xFFFFF000UL, &pool_0, _nx_ram_network_driver, + pointer, 2048, 1); + pointer = pointer + 2048; + + /* Create another IP instance. */ + status += nx_ip_create(&ip_1, "NetX IP Instance 1", IP_ADDRESS(1, 2, 3, 5), 0xFFFFF000UL, &pool_0, _nx_ram_network_driver, + pointer, 2048, 1); + pointer = pointer + 2048; + + /* Check for IP create errors. */ + if (status) + { + error_counter++; + } + + /* Enable ARP and supply ARP cache memory for IP Instance 0. */ + status = nx_arp_enable(&ip_0, (void *)pointer, 1024); + pointer = pointer + 1024; + + /* Enable ARP and supply ARP cache memory for IP Instance 1. */ + status += nx_arp_enable(&ip_1, (void *)pointer, 1024); + pointer = pointer + 1024; + + /* Check for ARP enable errors. */ + if (status) + { + error_counter++; + } + + /* Enable UDP traffic. */ + status = nx_udp_enable(&ip_0); + status += nx_udp_enable(&ip_1); + + /* Check for UDP enable errors. */ + if (status) + { + error_counter++; + } +} + + + +/* Define the test threads. */ + +void thread_0_entry(ULONG thread_input) +{ + +UINT status; +NX_PACKET *my_packet; + + NX_PARAMETER_NOT_USED(thread_input); + + /* Let the IP threads and thread 1 execute. */ + tx_thread_relinquish(); + + /* Create a UDP socket. */ + status = nx_udp_socket_create(&ip_0, &socket_0, "Socket 0", NX_IP_NORMAL, NX_FRAGMENT_OKAY, 0x80, 5); + + /* Check status. */ + if (status) + { + error_counter++; + return; + } + + /* Bind the UDP socket to the IP port. */ + status = nx_udp_socket_bind(&socket_0, 0x88, TX_WAIT_FOREVER); + + /* Check status. */ + if (status) + { + error_counter++; + return; + } + + /* Disable checksum logic for this socket. */ + nx_udp_socket_checksum_disable(&socket_0); + + /* Setup the ARP entry for the UDP send. */ + nx_arp_dynamic_entry_set(&ip_0, IP_ADDRESS(1, 2, 3, 5), 0, 0); + + /* Let other threads run again. */ + tx_thread_relinquish(); + + while (1) + { + + + /* Allocate a packet. */ + status = nx_packet_allocate(&pool_0, &my_packet, NX_UDP_PACKET, TX_WAIT_FOREVER); + + /* Check status. */ + if (status != NX_SUCCESS) + { + break; + } + + /* Write ABCs into the packet payload! */ + memcpy(my_packet -> nx_packet_prepend_ptr, DEMO_DATA, sizeof(DEMO_DATA)); + + /* Adjust the write pointer. */ + my_packet -> nx_packet_length = sizeof(DEMO_DATA); + my_packet -> nx_packet_append_ptr = my_packet -> nx_packet_prepend_ptr + sizeof(DEMO_DATA); + + /* Send the UDP packet. */ + status = nx_udp_socket_send(&socket_0, my_packet, IP_ADDRESS(1, 2, 3, 5), 0x89); + + /* Check status. */ + if (status != NX_SUCCESS) + { + error_counter++; + break; + } + + /* Increment thread 0's counter. */ + thread_0_counter++; + + /* Relinquish to thread 1. */ + tx_thread_relinquish(); + } +} + + +void thread_1_entry(ULONG thread_input) +{ + +UINT status; +NX_PACKET *my_packet; + + NX_PARAMETER_NOT_USED(thread_input); + + /* Create a UDP socket. */ + status = nx_udp_socket_create(&ip_1, &socket_1, "Socket 1", NX_IP_NORMAL, NX_FRAGMENT_OKAY, 0x80, 5); + + /* Check status. */ + if (status) + { + error_counter++; + return; + } + + /* Bind the UDP socket to the IP port. */ + status = nx_udp_socket_bind(&socket_1, 0x89, TX_WAIT_FOREVER); + + /* Check status. */ + if (status) + { + error_counter++; + return; + } + + while (1) + { + + + /* Receive a UDP packet. */ + status = nx_udp_socket_receive(&socket_1, &my_packet, TX_WAIT_FOREVER); + + /* Check status. */ + if (status != NX_SUCCESS) + { + break; + } + + /* Release the packet. */ + status = nx_packet_release(my_packet); + + /* Check status. */ + if (status != NX_SUCCESS) + { + break; + } + + /* Increment thread 1's counter. */ + thread_1_counter++; + } +} + diff --git a/samples/demo_snmp_helper.h b/samples/demo_snmp_helper.h new file mode 100644 index 0000000..89452f3 --- /dev/null +++ b/samples/demo_snmp_helper.h @@ -0,0 +1,90 @@ +/* This is an include file for the NetX SNMP demo programs for setting up the MIB for + user callback functions. It is not part of the official release of NetX SNMP Agent. */ + +#ifndef SNMP_HELPER_H +#define SNMP_HELPER_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 "tx_api.h" +#include "nx_api.h" +#include "nx_snmp.h" + +/* Define application MIB data structure. Actual application structures would certainly vary. */ + +typedef struct MIB_ENTRY_STRUCT +{ + + UCHAR *object_name; + void *object_value_ptr; + UINT (*object_get_callback)(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data); + UINT (*object_get_octet_callback)(VOID *source_ptr, NX_SNMP_OBJECT_DATA *object_data, UINT length); + UINT (*object_set_callback)(VOID *destination_ptr, NX_SNMP_OBJECT_DATA *object_data); + UINT length; +} MIB_ENTRY; + +/* Define the MIB-2 "system" group. */ + +UCHAR sysDescr[] = "NetX SNMP Agent"; /* sysDescr:OctetString RO */ +UCHAR sysObjectID[] = "1.3.6.1.2.1.1"; /* sysObjectID:ObjectID RO */ +ULONG sysUpTime = 0; /* sysUpTime:TimeTicks RO */ +UCHAR sysContact[128] = "NetX sysContact Name"; /* sysContact:OctetString RW */ +UCHAR sysName[128] = "NetX sysName"; /* sysName:OctetString RW */ +UCHAR sysLocation[128] = "NetX sysLocation"; /* sysLocation:OctetString RW */ +ULONG sysServices = 1; /* sysServices:Integer RW */ +ULONG ipForwarding = 0; /* ipForwarding:Integer RW */ +ULONG ipDefaultTTL = NX_IP_TIME_TO_LIVE; /* ipDefaultTTL:Integer RW */ + +/* Define the MIB-2 "interfaces" group, assuming one interface. Update of these variables could be added to the + underlying application driver, but for now simple defaults are used. */ +ULONG ifLastChange = 2048; /* ifLastChange:TimeTicks RO */ +ULONG ifInOctets = 155; /* ifInOctets:Counter RO */ +ULONG ifInUcastPkts = 0; /* ifInUcastPkts:Counter RO */ +UCHAR ifDescr[] = "NetX Physical Interface"; /* ifDescr:OctetString RO */ + +/* Define the MIB-2 "address translation" group, assuming one address translation. */ + +UCHAR atPhysAddress[] = {0x00,0x04,0xac,0xe3,0x1d,0xc5};/* atPhysAddress:OctetString RW */ +ULONG atNetworkAddress = 0; /* atNetworkAddress:NetworkAddr RW */ +UCHAR atIPv6NetworkAddress[16]; /* atNetworkAddress:NetworkAddr IPv6 RW */ + + +/* Define the actual MIB-2. */ + +MIB_ENTRY mib2_mib[] = { + + /* OBJECT ID OBJECT VARIABLE GET ROUTINE/ GET_OCTET_ROUTINE SET ROUTINE LENGTH */ + + {(UCHAR *) "1.3.6.1.2.1.1.1.0", sysDescr, nx_snmp_object_string_get, NX_NULL, nx_snmp_object_string_set, 0}, + {(UCHAR *) "1.3.6.1.2.1.1.2.0", sysObjectID, nx_snmp_object_id_get, NX_NULL, NX_NULL, 0}, + {(UCHAR *) "1.3.6.1.2.1.1.3.0", &sysUpTime, nx_snmp_object_timetics_get, NX_NULL, NX_NULL, 0}, + {(UCHAR *) "1.3.6.1.2.1.1.4.0", sysContact, nx_snmp_object_string_get, NX_NULL, nx_snmp_object_string_set, 0}, + {(UCHAR *) "1.3.6.1.2.1.1.5.0", sysName, nx_snmp_object_string_get, NX_NULL, nx_snmp_object_string_set, 0}, + {(UCHAR *) "1.3.6.1.2.1.1.6.0", sysLocation, nx_snmp_object_string_get, NX_NULL, nx_snmp_object_string_set, 0}, + {(UCHAR *) "1.3.6.1.2.1.1.7.0", &sysServices, nx_snmp_object_integer_get, NX_NULL, NX_NULL, 0}, + + {(UCHAR *) "1.3.6.1.2.1.3.1.1.3.0", &atNetworkAddress, nx_snmp_object_ip_address_get, NX_NULL, nx_snmp_object_ip_address_set, 0}, + + {(UCHAR *) "1.3.6.1.2.1.2.2.1.2.0", ifDescr, nx_snmp_object_string_get, NX_NULL, NX_NULL, 0}, + {(UCHAR *) "1.3.6.1.2.1.3.1.1.2.0", &atPhysAddress, NX_NULL, nx_snmp_object_octet_string_get, nx_snmp_object_octet_string_set, 0}, + {(UCHAR *) "1.3.6.1.2.1.2.2.1.9.0", &ifLastChange, nx_snmp_object_timetics_get, NX_NULL, nx_snmp_object_timetics_set, 0}, + {(UCHAR *) "1.3.6.1.2.1.2.2.1.10.0", &ifInOctets, nx_snmp_object_counter_get, NX_NULL, nx_snmp_object_counter_set, 0}, + {(UCHAR *) "1.3.6.1.2.1.2.2.1.11.0", &ifInUcastPkts, nx_snmp_object_counter64_get, NX_NULL, nx_snmp_object_counter64_set, 0}, + + {(UCHAR *) "1.3.6.1.2.1.4.1.0", &ipForwarding, nx_snmp_object_integer_get, NX_NULL, nx_snmp_object_integer_set, 0}, + {(UCHAR *) "1.3.6.1.2.1.4.2.0", &ipDefaultTTL, nx_snmp_object_integer_get, NX_NULL, NX_NULL, 0}, + + {(UCHAR *) "1.3.6.1.7", (UCHAR *) "1.3.6.1.7", nx_snmp_object_end_of_mib, NX_NULL, NX_NULL, 0}, + {NX_NULL, NX_NULL, NX_NULL, NX_NULL, NX_NULL, 0} + +}; + + +#endif /* SNMP_HELPER_H */