Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers 6lowpan_iphc.c Source File

6lowpan_iphc.c

00001 /*
00002  * Copyright (c) 2013-2018, 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 
00018 #include "nsconfig.h"
00019 #define HAVE_CIPV6
00020 
00021 #ifdef HAVE_CIPV6
00022 #include "ns_types.h"
00023 #include "string.h"
00024 #include "ns_trace.h"
00025 #include "Common_Protocols/ipv6.h"
00026 #include "Common_Protocols/ipv6_resolution.h"
00027 #include "6LoWPAN/IPHC_Decode/cipv6.h"
00028 #include "NWK_INTERFACE/Include/protocol.h"
00029 #include "ipv6_stack/protocol_ipv6.h"
00030 #include "6LoWPAN/IPHC_Decode/iphc_compress.h"
00031 #include "6LoWPAN/IPHC_Decode/iphc_decompress.h"
00032 #include "6LoWPAN/Mesh/mesh.h"
00033 #include "6LoWPAN/Thread/thread_common.h"
00034 #include "6LoWPAN/MAC/mac_helper.h"
00035 #include "MLE/mle.h"
00036 
00037 #include "6LoWPAN/Bootstraps/protocol_6lowpan.h"
00038 #include "nwk_stats_api.h"
00039 #include "NWK_INTERFACE/Include/protocol_stats.h"
00040 #include "common_functions.h"
00041 
00042 #define TRACE_GROUP  "iphc"
00043 
00044 /* Input: Final IP packet for transmission on link.
00045  *        Buffer destination = final destination
00046  *        Buffer source undefined.
00047  *        Route next hop address set.
00048  * Output: Buffer destination+source = link-layer addresses
00049  *         Sent to mesh, LowPAN fragmentation or MAC layers
00050  */
00051 buffer_t *lowpan_down(buffer_t *buf)
00052 {
00053     protocol_interface_info_entry_t *cur = buf->interface ;
00054 
00055     buf->options .type  = 0;
00056 
00057     if (!buf->route) {
00058         tr_debug("lowpan_down route");
00059         return buffer_free(buf);
00060     }
00061 
00062     const uint8_t *ip_src = buffer_data_pointer(buf) + 8;
00063     const uint8_t *next_hop = buf->route->route_info.next_hop_addr;
00064     bool link_local = addr_is_ipv6_link_local(next_hop);
00065     bool stable_only = false;
00066 
00067     /* We have IP next hop - figure out the MAC address */
00068     if (addr_is_ipv6_multicast(next_hop)) {
00069         buf->dst_sa .addr_type  = ADDR_BROADCAST ;
00070         common_write_16_bit(cur->mac_parameters->pan_id, buf->dst_sa .address );
00071         buf->dst_sa .address [2] = 0x80 | (next_hop[14] & 0x1f);
00072         buf->dst_sa .address [3] = next_hop[15];
00073         stable_only = true;
00074     } else { /* unicast */
00075         ipv6_neighbour_t *n = ipv6_interface_resolve_new(cur, buf);
00076         if (!n) {
00077             return NULL;
00078         }
00079         if (thread_info(cur)) {
00080             stable_only = thread_stable_context_check(cur, buf);
00081         }
00082     }
00083 
00084     if (!buf->link_specific.ieee802_15_4.useDefaultPanId) {
00085         /* Override dest PAN ID (from multicast map above, or neighbour cache) */
00086         common_write_16_bit(buf->link_specific.ieee802_15_4.dstPanId, buf->dst_sa .address );
00087     }
00088 
00089     /* Figure out which source MAC address to use. Usually try to match the
00090      * source, for best compression, and to ensure if the layer above uses LL64
00091      * (like MLE), it forces us to use our MAC64.
00092      */
00093     if (thread_info(cur) && !(link_local && thread_insist_that_mesh_isnt_a_link(cur)) && buf->dst_sa .addr_type  == ADDR_802_15_4_SHORT ) {
00094         /* For Thread, we want to always use short source address for unicast
00095          * to non-link-local 16-bit addresses, which is the case where we want
00096          * to use mesh headers.
00097          */
00098         buf->src_sa .addr_type  = ADDR_802_15_4_SHORT ;
00099     } else if (addr_iid_matches_eui64(ip_src + 8, cur->mac)) {
00100         buf->src_sa .addr_type  = ADDR_802_15_4_LONG ;
00101     } else if (cur->mac_parameters->mac_short_address < 0xfffe && addr_iid_matches_lowpan_short(ip_src + 8, cur->mac_parameters->mac_short_address)) {
00102         buf->src_sa .addr_type  = ADDR_802_15_4_SHORT ;
00103     } else {
00104         /* This lets mac_mlme_write_our_addr choose based on address mode */
00105         buf->src_sa .addr_type  = ADDR_NONE ;
00106     }
00107 
00108     if (!mac_helper_write_our_addr(cur, &buf->src_sa )) {
00109         return buffer_free(buf);
00110     }
00111 
00112     /* Clear Link Layer Re Transmission Counter */
00113     //buf->fhss_channel_retries_left = 1+ cur->mac_parameters->number_of_fhss_channel_retries;
00114 
00115 
00116     if (buf->dst_sa .addr_type  != ADDR_802_15_4_LONG  && buf->dst_sa .addr_type  != ADDR_802_15_4_SHORT  && buf->dst_sa .addr_type  != ADDR_BROADCAST ) {
00117         tr_debug("IP:Dest Pro. addr_type: %02x", buf->dst_sa .addr_type );
00118         return buffer_free(buf);
00119     }
00120 
00121     uint_fast8_t mesh_size;
00122     if (link_local && thread_insist_that_mesh_isnt_a_link(cur)) {
00123         mesh_size = 0;
00124     } else {
00125         /* Allow the link-layer destination addresses passed from upper layers
00126          * to be remapped - used to implement Thread anycast.
00127          *
00128          * Mapping function can change address and type - if it returns false,
00129          * packet is dropped.
00130          *
00131          * Note that this mapping has to be done before IPHC compression, which
00132          * is why it moved from mesh.c.
00133          */
00134         if (!mesh_address_map(cur, &buf->dst_sa .addr_type , buf->dst_sa .address )) {
00135             tr_debug("mesh_address_map fail");
00136             return buffer_free(buf);
00137         }
00138 
00139         /* After mapping, compute final mesh header size (which depends on
00140          * the final address).
00141          */
00142         mesh_size = mesh_header_size(buf);
00143     }
00144 
00145     if (mesh_size == 0) {
00146         if (buf->dst_sa .addr_type  == ADDR_BROADCAST ) {
00147             /* Thread says multicasts other than MLE are sent to our parent, if we're an end device */
00148             if (cur->ip_multicast_as_mac_unicast_to_parent && !buf->options .ll_broadcast_tx ) {
00149                 if (protocol_6lowpan_interface_get_mac_coordinator_address(cur, &buf->dst_sa ) < 0) {
00150                     tr_warn("IP: No parent for multicast as unicast");
00151                     return buffer_free(buf);
00152                 }
00153             } else {
00154                 /*
00155                  * Not using a mesh header, so have to "purify" RFC 4944 multicast - we
00156                  * set a 100xxxxxxxxxxxxx RFC 4944 multicast address above, but
00157                  * IEEE 802.15.4 only supports broadcast in the real MAC header.
00158                  */
00159                 common_write_16_bit(0xFFFF, buf->dst_sa .address  + 2);
00160             }
00161         }
00162     }
00163 
00164     /* RFC 6282+4944 require that we limit compression to the first fragment.
00165      * This check is slightly conservative - always allow 4 for first-fragment header
00166      */
00167     uint_fast16_t overhead = mac_helper_frame_overhead(cur, buf);
00168     uint_fast16_t max_iphc_size = mac_helper_max_payload_size(cur, overhead) - mesh_size - 4;
00169 
00170     buf = iphc_compress(&cur->lowpan_contexts, buf, max_iphc_size, stable_only);
00171     if (!buf) {
00172         return NULL;
00173     }
00174 
00175     if (mesh_size != 0) {
00176         buf->info  = (buffer_info_t)(B_FROM_IPV6_TXRX | B_TO_MESH_ROUTING | B_DIR_DOWN);
00177         return buf;
00178     }
00179 
00180     buf->info  = (buffer_info_t)(B_FROM_IPV6_TXRX | B_TO_MAC | B_DIR_DOWN);
00181 
00182     return buf;
00183 }
00184 
00185 buffer_t *lowpan_up(buffer_t *buf)
00186 {
00187     protocol_interface_info_entry_t *cur = buf->interface ;
00188 
00189     /* Reject:
00190      *    Packets without address
00191      *    Source broadcast PAN ID
00192      *    Short source addresses 0xfffe (illegal) and 0xffff (broadcast)
00193      */
00194     if (buf->dst_sa .addr_type  == ADDR_NONE  || buf->src_sa .addr_type  == ADDR_NONE  ||
00195             common_read_16_bit(buf->src_sa .address ) == 0xffff ||
00196             (buf->dst_sa .addr_type  == ADDR_802_15_4_SHORT  && common_read_16_bit(buf->src_sa .address  + 2) > 0xfffd)) {
00197         goto drop;
00198     }
00199 
00200     /* If our PAN ID is set to 0xffff (eg during beacon scan), the MAC will be
00201      * receiving all packets to all PANs. "Mute" 6LoWPAN reception in this state.
00202      */
00203     if (cur->mac_parameters->pan_id == 0xffff) {
00204         goto drop;
00205     }
00206 
00207     const uint8_t *ip_hc = buffer_data_pointer(buf);
00208 
00209     //tr_debug("IP-UP";
00210 
00211     if (buffer_data_length(buf) < 4 || addr_check_broadcast(buf->src_sa .address , buf->src_sa .addr_type ) == 0) {
00212         tr_debug("cipv6_up() Too short or broadcast src");
00213         goto drop;
00214     } else if ((ip_hc[0] & LOWPAN_FRAG_MASK) == LOWPAN_FRAG) {
00215         /* 11 x00xxx: FRAG1/FRAGN (RFC 4944) */
00216         buf->info  = (buffer_info_t)(B_DIR_UP | B_FROM_IPV6_TXRX | B_TO_FRAGMENTATION);
00217         return buf;
00218     } else if ((ip_hc[0] & LOWPAN_MESH_MASK) == LOWPAN_MESH) {
00219         /* 10 xxxxxx: MESH (RFC 4944) */
00220         buf->info  = (buffer_info_t)(B_DIR_UP | B_FROM_IPV6_TXRX | B_TO_MESH_ROUTING);
00221         return buf;
00222     } else if (ip_hc[0] == LOWPAN_DISPATCH_IPV6) {
00223         /* Send this to new handler */
00224         buffer_data_strip_header(buf, 1);
00225         buf->ip_routed_up = true;
00226         buf->info  = (buffer_info_t)(B_DIR_UP | B_FROM_IPV6_TXRX | B_TO_IPV6_FWD);
00227         return buf;
00228     } else if ((ip_hc[0] & LOWPAN_DISPATCH_IPHC_MASK) != LOWPAN_DISPATCH_IPHC) {
00229         /* Not handled: LOWPAN_HC1/LOWPAN_BC0/IPv6 (RFC 4944), or extension */
00230         tr_debug("LOWPAN: %02x %02x", ip_hc[0], ip_hc[1]);
00231         goto drop;
00232     }
00233 
00234     /* Divert to new routing system - in final system, MAC/Mesh/Frag should send to IPV6_TXRX layer */
00235     buf->ip_routed_up = true;
00236     buf = iphc_decompress(&cur->lowpan_contexts, buf);
00237     if (buf) {
00238         buf->info  = (buffer_info_t)(B_DIR_UP | B_FROM_IPV6_TXRX | B_TO_IPV6_FWD);
00239     }
00240     return buf;
00241 
00242 drop:
00243     protocol_stats_update(STATS_IP_RX_DROP, 1);
00244     return buffer_free(buf);
00245 }
00246 
00247 #endif /* HAVE_CIPV6 */
00248