Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers udp.c Source File

udp.c

00001 /*
00002  * Copyright (c) 2013-2017, 2019, Arm Limited and affiliates.
00003  * SPDX-License-Identifier: Apache-2.0
00004  *
00005  * Licensed under the Apache License, Version 2.0 (the "License");
00006  * you may not use this file except in compliance with the License.
00007  * You may obtain a copy of the License at
00008  *
00009  *     http://www.apache.org/licenses/LICENSE-2.0
00010  *
00011  * Unless required by applicable law or agreed to in writing, software
00012  * distributed under the License is distributed on an "AS IS" BASIS,
00013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014  * See the License for the specific language governing permissions and
00015  * limitations under the License.
00016  */
00017 #include "nsconfig.h"
00018 #include "ns_types.h"
00019 #include "string.h"
00020 #include "ns_trace.h"
00021 #include "ip_fsc.h"
00022 #include "NWK_INTERFACE/Include/protocol.h"
00023 #include "NWK_INTERFACE/Include/protocol_stats.h"
00024 #include "6LoWPAN/Bootstraps/network_lib.h" // for nwk_udp_rx_security_check
00025 #include "Common_Protocols/ipv6_constants.h"
00026 #include "Common_Protocols/icmpv6.h"
00027 #include "Common_Protocols/udp.h"
00028 #include "Core/include/ns_socket.h"
00029 #include "common_functions.h"
00030 
00031 #define TRACE_GROUP "udp"
00032 
00033 static buffer_t *udp_checksum_check(buffer_t *buf)
00034 {
00035     uint8_t *ptr = buffer_data_pointer(buf) + 6;
00036     uint16_t check = common_read_16_bit(ptr);
00037 
00038     // We refuse checksum field 0000, as per IPv6 (RFC 2460). Would have
00039     // to accept this if handling IPv4.
00040     if (check == 0 || buffer_ipv6_fcf(buf, IPV6_NH_UDP)) {
00041         tr_err("CKSUM ERROR - src=%s", trace_ipv6(buf->src_sa .address ));
00042         protocol_stats_update(STATS_IP_CKSUM_ERROR, 1);
00043         buf = buffer_free(buf);
00044     }
00045     return buf;
00046 }
00047 
00048 void udp_checksum_write(buffer_t *buf)
00049 {
00050     uint8_t *ptr = buffer_data_pointer(buf) + 6;
00051     uint16_t check;
00052 
00053     common_write_16_bit(0, ptr);
00054     check = buffer_ipv6_fcf(buf, IPV6_NH_UDP);
00055     if (check == 0) {
00056         check = 0xffff;
00057     }
00058     common_write_16_bit(check, ptr);
00059 }
00060 
00061 
00062 buffer_t *udp_down(buffer_t *buf)
00063 {
00064     if (buf->src_sa .addr_type  != ADDR_IPV6 ) {
00065         //tr_debug("Create Address");
00066 //      if(protocol_stack_interface_get_address_by_prefix(buf->if_index, buf->src_sa.address,buf->dst_sa.address, 0) != 0)
00067 //      {
00068         tr_debug("InterFace Address Get Fail--> free Buffer");
00069         return buffer_free(buf);
00070 //      }
00071 //      else
00072 //      {
00073 //          buf->src_sa.addr_type = ADDR_IPV6;
00074 //      }
00075     }
00076 
00077     buf = buffer_headroom(buf, 8);
00078     if (buf) {
00079         uint8_t *ptr;
00080         buf->buf_ptr  -= 8;
00081 
00082         ptr = buffer_data_pointer(buf);
00083         ptr = common_write_16_bit(buf->src_sa .port , ptr);
00084         ptr = common_write_16_bit(buf->dst_sa .port , ptr);
00085         ptr = common_write_16_bit(buffer_data_length(buf), ptr);
00086         udp_checksum_write(buf);
00087         buf->IPHC_NH = 0;
00088         buf->info  = (buffer_info_t)(B_FROM_UDP | B_TO_IPV6 | B_DIR_DOWN);
00089         buf->options .type  = IPV6_NH_UDP;
00090         buf->options .code  = 0;
00091     }
00092     return (buf);
00093 }
00094 
00095 buffer_t *udp_up(buffer_t *buf)
00096 {
00097     //tr_debug("UDP UP");
00098     const uint8_t *ip_hdr;
00099     if ((buf->info  & B_FROM_MASK) == B_FROM_IPV6_FWD) {
00100         // New paths leave IP header on for us to permit ICMP response;
00101         // note the pointer and strip now.
00102         ip_hdr = buffer_data_pointer(buf);
00103         buffer_data_strip_header(buf, buf->offset );
00104         buf->offset  = 0;
00105     } else {
00106         // We came from cipv6_up (or...?) - we have no real IP headers
00107         ip_hdr = NULL;
00108     }
00109 
00110     uint16_t ip_len = buffer_data_length(buf);
00111     if (ip_len < 8) {
00112         return buffer_free(buf);
00113     }
00114 
00115     const uint8_t *udp_hdr = buffer_data_pointer(buf);
00116 
00117     buf->src_sa .port  = common_read_16_bit(udp_hdr + 0);
00118     buf->dst_sa .port  = common_read_16_bit(udp_hdr + 2);
00119     uint16_t udp_len = common_read_16_bit(udp_hdr + 4);
00120 
00121     buf = nwk_udp_rx_security_check(buf);
00122     if (!buf) {
00123         return NULL;
00124     }
00125 
00126     if (udp_len < 8 || udp_len > ip_len) {
00127         return buffer_free(buf);
00128     }
00129 
00130     // Set UDP length - may trim the buffer
00131     buffer_data_length_set(buf, udp_len);
00132 
00133     buf = udp_checksum_check(buf);
00134     if (!buf) {
00135         return buf;
00136     }
00137 
00138     // Remove UDP header
00139     buffer_data_pointer_set(buf, udp_hdr + 8);
00140 
00141     if (buf->dst_sa .port  == 0) {
00142         tr_err("UDP port 0");
00143         protocol_stats_update(STATS_IP_RX_DROP, 1);
00144         return buffer_free(buf);
00145     }
00146 
00147     if (buf->dst_sa .port  == UDP_PORT_ECHO && buf->src_sa .port  != UDP_PORT_ECHO) {
00148         protocol_interface_info_entry_t *cur;
00149         tr_debug("UDP echo msg from %s", trace_ipv6(buf->src_sa .address ));
00150 
00151         cur = buf->interface ;
00152 
00153         if (addr_is_ipv6_multicast(buf->dst_sa .address )) {
00154             const uint8_t *ipv6_ptr;
00155             ipv6_ptr = addr_select_source(cur, buf->dst_sa .address , 0);
00156             if (!ipv6_ptr) {
00157                 tr_debug("UDP Echo:No address");
00158                 return buffer_free(buf);
00159             }
00160             memcpy(buf->dst_sa .address , buf->src_sa .address , 16);
00161             memcpy(buf->src_sa .address , ipv6_ptr, 16);
00162         } else {
00163             memswap(buf->dst_sa .address , buf->src_sa .address , 16);
00164         }
00165         buf->dst_sa .port  = buf->src_sa .port ;
00166         buf->src_sa .port  = UDP_PORT_ECHO;
00167 
00168         buf->info  = (buffer_info_t)(B_FROM_UDP | B_TO_UDP | B_DIR_DOWN);
00169         buf->options .hop_limit  = UNICAST_HOP_LIMIT_DEFAULT;
00170         buf->options .traffic_class  = 0;
00171         buf->IPHC_NH = 0;
00172         return buffer_turnaround(buf);
00173     }
00174 
00175     if (ip_hdr) {
00176         /* New path generates port unreachable here, using the real IP headers
00177          * that we know the position of thanks to buf->offset.
00178          *
00179          * Old path has socket_up make port unreachable itself, creating a
00180          * fake IP header.
00181          */
00182         if (!buf->socket ) {
00183             buffer_socket_set(buf, socket_lookup_ipv6(IPV6_NH_UDP, &buf->dst_sa , &buf->src_sa , true));
00184         }
00185         if (!buf->socket ) {
00186             // Reconstruct original IP packet
00187             buffer_data_pointer_set(buf, udp_hdr);
00188             buffer_data_length_set(buf, ip_len);
00189             buffer_data_pointer_set(buf, ip_hdr);
00190             return icmpv6_error(buf, NULL, ICMPV6_TYPE_ERROR_DESTINATION_UNREACH, ICMPV6_CODE_DST_UNREACH_PORT_UNREACH, 0);
00191         }
00192     }
00193 
00194     buf->options .type  = (uint8_t) SOCKET_FAMILY_IPV6;
00195     buf->options .code  = IPV6_NH_UDP;
00196     buf->info  = (buffer_info_t)(B_FROM_UDP | B_TO_APP | B_DIR_UP);
00197     return buf;
00198 }