diff options
| author | PProvost <[email protected]> | 2020-05-11 08:54:23 -0600 |
|---|---|---|
| committer | PProvost <[email protected]> | 2020-05-11 08:54:23 -0600 |
| commit | 0c4f784459a7564933ed91bf39f00d12608cf91c (patch) | |
| tree | cfa743731d1cfb11d83119bf1c8d0d942e8c3c73 /common/src/nx_icmp_interface_ping.c | |
Initial commit
Diffstat (limited to 'common/src/nx_icmp_interface_ping.c')
| -rw-r--r-- | common/src/nx_icmp_interface_ping.c | 405 |
1 files changed, 405 insertions, 0 deletions
diff --git a/common/src/nx_icmp_interface_ping.c b/common/src/nx_icmp_interface_ping.c new file mode 100644 index 00000000..7226bae4 --- /dev/null +++ b/common/src/nx_icmp_interface_ping.c @@ -0,0 +1,405 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the 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" + +#ifdef NX_IPSEC_ENABLE +#include "nx_ipsec.h" +#endif /* NX_IPSEC_ENABLE */ + +#ifndef NX_DISABLE_IPV4 +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _nx_icmp_interface_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 */ +/* interface_ptr Pointer to interface */ +/* next_hop_address Next hop address */ +/* 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_ip_checksum_compute Computer checksum */ +/* _nx_ip_packet_send IP packet send function */ +/* _nx_packet_allocate Allocate a packet for the */ +/* ICMP ping request */ +/* _nx_packet_release Release packet to packet pool */ +/* 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 */ +/* */ +/* _nx_icmp_ping */ +/* _nxd_icmp_source_ping */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 05-19-2020 Yuxin Zhou Initial Version 6.0 */ +/* */ +/**************************************************************************/ +UINT _nx_icmp_interface_ping(NX_IP *ip_ptr, ULONG ip_address, + NX_INTERFACE *interface_ptr, ULONG next_hop_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 checksum; +#if defined(NX_DISABLE_ICMPV4_TX_CHECKSUM) || defined(NX_ENABLE_INTERFACE_CAPABILITY) || defined(NX_IPSEC_ENABLE) +ULONG compute_checksum = 1; +#endif /* defined(NX_DISABLE_ICMPV4_TX_CHECKSUM) || defined(NX_ENABLE_INTERFACE_CAPABILITY) || defined(NX_IPSEC_ENABLE) */ +ULONG sequence; +TX_THREAD *thread_ptr; +ULONG data_offset; + +#ifdef NX_IPSEC_ENABLE +VOID *sa = NX_NULL; +NXD_ADDRESS src_addr; +NXD_ADDRESS dest_addr; +UINT ret = 0; +#endif /* NX_IPSEC_ENABLE */ + + + /* 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; + data_offset = 0; + +#ifdef NX_IPSEC_ENABLE + /* Create address data for finding an IPSec SA match. */ + src_addr.nxd_ip_version = NX_IP_VERSION_V4; + src_addr.nxd_ip_address.v4 = interface_ptr -> nx_interface_ip_address; + dest_addr.nxd_ip_version = NX_IP_VERSION_V4; + dest_addr.nxd_ip_address.v4 = ip_address; + + /* Check if IPsec is enabled. */ + if (ip_ptr -> nx_ip_packet_egress_sa_lookup != NX_NULL) + { + /* It is. Check for possible SA match. */ + ret = ip_ptr -> nx_ip_packet_egress_sa_lookup(ip_ptr, /* IP ptr */ + &src_addr, /* src_addr */ + &dest_addr, /* dest_addr */ + NX_PROTOCOL_ICMP, /* protocol */ + 0, /* src_port */ + 0, /* dest_port */ + &data_offset, &sa, (NX_ICMP_ECHO_REQUEST_TYPE << 8)); + + /* Does our IPSec SA allow this ping packet to pass through? */ + if (ret == NX_IPSEC_TRAFFIC_BYPASS) + { + + /* Yes, ok to pass through without encryption or authentication. */ + sa = NX_NULL; + data_offset = 0; + } + /* Does our IPSec SA indicate this packet may not be sent? */ + else if (ret == NX_IPSEC_TRAFFIC_DROP || ret == NX_IPSEC_TRAFFIC_PENDING_IKEV2) + { + + /* Return the error status. */ + return(NX_IPSEC_REJECTED); + } + } + +#endif /* NX_IPSEC_ENABLE */ + + /* Allocate a packet to place the ICMP echo request message in. */ + /*lint -e{845} suppress argument to operator '+' is certain to be 0, since "data_offset" can be non-zero when NX_IPSEC_ENABLE is defined. */ + status = _nx_packet_allocate(ip_ptr -> nx_ip_default_packet_pool, &request_ptr, + (ULONG)(NX_IPv4_ICMP_PACKET + data_offset + NX_ICMP_HEADER_SIZE), wait_option); + if (status) + { + + /* Error getting packet, so just get out! */ + return(status); + } + + /* Add debug information. */ + NX_PACKET_DEBUG(__FILE__, __LINE__, request_ptr); + + /* Copy the data into the packet payload area. */ + /*lint -e{644} suppress variable might not be initialized, since "request_ptr" was initialized in _nx_packet_allocate. */ + status = _nx_packet_data_append(request_ptr, (VOID *)data_ptr, data_size, ip_ptr -> nx_ip_default_packet_pool, wait_option); + + /* Check return status. */ + if (status) + { + + /* Release the packet. */ + _nx_packet_release(request_ptr); + + /* Error, the data area is too big for the default packet payload. */ + return(status); + } + + /* Store outgoing interface. */ + request_ptr -> nx_packet_address.nx_packet_interface_ptr = interface_ptr; + +#ifdef NX_IPSEC_ENABLE + /* Store SA. */ + request_ptr -> nx_packet_ipsec_sa_ptr = sa; +#endif /* NX_IPSEC_ENABLE */ + +#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 += (ULONG)NX_ICMP_HEADER_SIZE; + + /* Adjust the nx_packet_prepend_ptr for ICMP header. */ + request_ptr -> nx_packet_prepend_ptr -= NX_ICMP_HEADER_SIZE; + + /* Build the ICMP request 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_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_address.nx_packet_interface_ptr -> nx_interface_ip_address << 16) | sequence; + + /* 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); + +#ifdef NX_DISABLE_ICMPV4_TX_CHECKSUM + compute_checksum = 0; +#endif /* NX_DISABLE_ICMPV4_TX_CHECKSUM */ + +#ifdef NX_ENABLE_INTERFACE_CAPABILITY + if (request_ptr -> nx_packet_address.nx_packet_interface_ptr -> nx_interface_capability_flag & NX_INTERFACE_CAPABILITY_ICMPV4_TX_CHECKSUM) + { + compute_checksum = 0; + } +#endif /* NX_ENABLE_INTERFACE_CAPABILITY */ +#ifdef NX_IPSEC_ENABLE + if ((sa != NX_NULL) && (((NX_IPSEC_SA *)sa) -> nx_ipsec_sa_encryption_method != NX_CRYPTO_NONE)) + { + compute_checksum = 1; + } +#endif + +#if defined(NX_DISABLE_ICMPV4_TX_CHECKSUM) || defined(NX_ENABLE_INTERFACE_CAPABILITY) || defined(NX_IPSEC_ENABLE) + if (compute_checksum) +#endif /* defined(NX_DISABLE_ICMPV4_TX_CHECKSUM) || defined(NX_ENABLE_INTERFACE_CAPABILITY) || defined(NX_IPSEC_ENABLE) */ + { + + /* Compute the checksum of the ICMP packet. */ + checksum = _nx_ip_checksum_compute(request_ptr, NX_IP_ICMP, + (UINT)request_ptr -> nx_packet_length, + /* ICMPV4 checksum does not include + src/dest addresses */ + NX_NULL, NX_NULL); + + /* 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); + } +#ifdef NX_ENABLE_INTERFACE_CAPABILITY + else + { + request_ptr -> nx_packet_interface_capability_flag |= NX_INTERFACE_CAPABILITY_ICMPV4_TX_CHECKSUM; + } +#endif /* NX_ENABLE_INTERFACE_CAPABILITY */ + + /* 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. */ + /*lint -e{644} suppress variable might not be initialized, since "next_hop_address" was initialized in _nx_ip_route_find. */ + _nx_ip_packet_send(ip_ptr, request_ptr, ip_address, + NX_IP_NORMAL, NX_IP_TIME_TO_LIVE, NX_IP_ICMP, NX_FRAGMENT_OKAY, next_hop_address); + + /* 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); + + if (thread_ptr -> tx_thread_suspend_status == NX_SUCCESS) + { + + /* Add debug information. */ + NX_PACKET_DEBUG(__FILE__, __LINE__, *response_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); + } +} +#endif /* !NX_DISABLE_IPV4 */ + |
