Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers 6lowpan_iphc.c Source File

6lowpan_iphc.c

00001 /*
00002  * Copyright (c) 2013-2017, 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             mle_neigh_table_entry_t *mle_entry;
00081             mle_entry = mle_class_get_by_link_address(cur->id, buf->dst_sa .address  + 2, buf->dst_sa .addr_type );
00082             if (mle_entry && thread_addr_is_child(mac_helper_mac16_address_get(cur), mle_entry->short_adr)) {
00083                 /* Check if the child can handle only stable network data (e.g. sleepy device) */
00084                 stable_only = !(mle_entry->mode & MLE_THREAD_REQ_FULL_DATA_SET);
00085             }
00086         }
00087     }
00088 
00089     if (!buf->link_specific.ieee802_15_4.useDefaultPanId) {
00090         /* Override dest PAN ID (from multicast map above, or neighbour cache) */
00091         common_write_16_bit(buf->link_specific.ieee802_15_4.dstPanId, buf->dst_sa .address );
00092     }
00093 
00094     /* Figure out which source MAC address to use. Usually try to match the
00095      * source, for best compression, and to ensure if the layer above uses LL64
00096      * (like MLE), it forces us to use our MAC64.
00097      */
00098     if (thread_info(cur) && !(link_local && thread_insist_that_mesh_isnt_a_link(cur)) && buf->dst_sa .addr_type  == ADDR_802_15_4_SHORT ) {
00099         /* For Thread, we want to always use short source address for unicast
00100          * to non-link-local 16-bit addresses, which is the case where we want
00101          * to use mesh headers.
00102          */
00103         buf->src_sa .addr_type  = ADDR_802_15_4_SHORT ;
00104     } else if (addr_iid_matches_eui64(ip_src + 8, cur->mac)) {
00105         buf->src_sa .addr_type  = ADDR_802_15_4_LONG ;
00106     } else if (cur->mac_parameters->mac_short_address < 0xfffe && addr_iid_matches_lowpan_short(ip_src + 8, cur->mac_parameters->mac_short_address)) {
00107         buf->src_sa .addr_type  = ADDR_802_15_4_SHORT ;
00108     } else {
00109         /* This lets mac_mlme_write_our_addr choose based on address mode */
00110         buf->src_sa .addr_type  = ADDR_NONE ;
00111     }
00112 
00113     if (!mac_helper_write_our_addr(cur, &buf->src_sa )) {
00114         return buffer_free(buf);
00115     }
00116 
00117     /* Clear Link Layer Re Transmission Counter */
00118     //buf->fhss_channel_retries_left = 1+ cur->mac_parameters->number_of_fhss_channel_retries;
00119 
00120 
00121     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 ) {
00122         tr_debug("IP:Dest Pro. addr_type: %02x", buf->dst_sa .addr_type );
00123         return buffer_free(buf);
00124     }
00125 
00126     uint_fast8_t mesh_size;
00127     if (link_local && thread_insist_that_mesh_isnt_a_link(cur)) {
00128         mesh_size = 0;
00129     } else {
00130         /* Allow the link-layer destination addresses passed from upper layers
00131          * to be remapped - used to implement Thread anycast.
00132          *
00133          * Mapping function can change address and type - if it returns false,
00134          * packet is dropped.
00135          *
00136          * Note that this mapping has to be done before IPHC compression, which
00137          * is why it moved from mesh.c.
00138          */
00139         if (!mesh_address_map(cur, &buf->dst_sa .addr_type , buf->dst_sa .address )) {
00140             tr_debug("mesh_address_map fail");
00141             return buffer_free(buf);
00142         }
00143 
00144         /* After mapping, compute final mesh header size (which depends on
00145          * the final address).
00146          */
00147         mesh_size = mesh_header_size(buf);
00148     }
00149 
00150     if (mesh_size == 0) {
00151         if (buf->dst_sa .addr_type  == ADDR_BROADCAST ) {
00152             /* Thread says multicasts other than MLE are sent to our parent, if we're an end device */
00153             if (cur->ip_multicast_as_mac_unicast_to_parent && !buf->options .ll_broadcast_tx ) {
00154                 if (protocol_6lowpan_interface_get_mac_coordinator_address(cur, &buf->dst_sa ) < 0) {
00155                     tr_warn("IP: No parent for multicast as unicast");
00156                     return buffer_free(buf);
00157                 }
00158             } else {
00159                 /*
00160                  * Not using a mesh header, so have to "purify" RFC 4944 multicast - we
00161                  * set a 100xxxxxxxxxxxxx RFC 4944 multicast address above, but
00162                  * IEEE 802.15.4 only supports broadcast in the real MAC header.
00163                  */
00164                 common_write_16_bit(0xFFFF, buf->dst_sa .address  + 2);
00165             }
00166         }
00167     }
00168 
00169     /* RFC 6282+4944 require that we limit compression to the first fragment.
00170      * This check is slightly conservative - always allow 4 for first-fragment header
00171      */
00172     uint_fast8_t overhead = mac_helper_frame_overhead(cur, buf);
00173     uint_fast16_t max_iphc_size = mac_helper_max_payload_size(cur, overhead) - mesh_size - 4;
00174 
00175     buf = iphc_compress(&cur->lowpan_contexts, buf, max_iphc_size, stable_only);
00176     if (!buf) {
00177         return NULL;
00178     }
00179 
00180     if (mesh_size != 0) {
00181         buf->info  = (buffer_info_t)(B_FROM_IPV6_TXRX | B_TO_MESH_ROUTING | B_DIR_DOWN);
00182         return buf;
00183     }
00184 
00185     buf->info  = (buffer_info_t)(B_FROM_IPV6_TXRX | B_TO_MAC | B_DIR_DOWN);
00186 
00187     return buf;
00188 }
00189 
00190 buffer_t *lowpan_up(buffer_t *buf)
00191 {
00192     protocol_interface_info_entry_t *cur = buf->interface ;
00193 
00194     /* Reject:
00195      *    Packets without address
00196      *    Source broadcast PAN ID
00197      *    Short source addresses 0xfffe (illegal) and 0xffff (broadcast)
00198      */
00199     if (buf->dst_sa .addr_type  == ADDR_NONE  || buf->src_sa .addr_type  == ADDR_NONE  ||
00200             common_read_16_bit(buf->src_sa .address ) == 0xffff ||
00201             (buf->dst_sa .addr_type  == ADDR_802_15_4_SHORT  && common_read_16_bit(buf->src_sa .address  + 2) > 0xfffd)) {
00202         goto drop;
00203     }
00204 
00205     /* If our PAN ID is set to 0xffff (eg during beacon scan), the MAC will be
00206      * receiving all packets to all PANs. "Mute" 6LoWPAN reception in this state.
00207      */
00208     if (cur->mac_parameters->pan_id == 0xffff) {
00209         goto drop;
00210     }
00211 
00212     const uint8_t *ip_hc = buffer_data_pointer(buf);
00213 
00214     //tr_debug("IP-UP";
00215 
00216     if (buffer_data_length(buf) < 4 || addr_check_broadcast(buf->src_sa .address , buf->src_sa .addr_type ) == 0) {
00217         tr_debug("cipv6_up() Too short or broadcast src");
00218         goto drop;
00219     } else if ((ip_hc[0] & LOWPAN_FRAG_MASK) == LOWPAN_FRAG) {
00220         /* 11 x00xxx: FRAG1/FRAGN (RFC 4944) */
00221         buf->info  = (buffer_info_t)(B_DIR_UP | B_FROM_IPV6_TXRX | B_TO_FRAGMENTATION);
00222         return buf;
00223     } else if ((ip_hc[0] & LOWPAN_MESH_MASK) == LOWPAN_MESH) {
00224         /* 10 xxxxxx: MESH (RFC 4944) */
00225         buf->info  = (buffer_info_t)(B_DIR_UP | B_FROM_IPV6_TXRX | B_TO_MESH_ROUTING);
00226         return buf;
00227     } else if (ip_hc[0] == LOWPAN_DISPATCH_IPV6) {
00228         /* Send this to new handler */
00229         buffer_data_strip_header(buf, 1);
00230         buf->ip_routed_up = true;
00231         buf->info  = (buffer_info_t)(B_DIR_UP | B_FROM_IPV6_TXRX | B_TO_IPV6_FWD);
00232         return buf;
00233     } else if ((ip_hc[0] & LOWPAN_DISPATCH_IPHC_MASK) != LOWPAN_DISPATCH_IPHC) {
00234         /* Not handled: LOWPAN_HC1/LOWPAN_BC0/IPv6 (RFC 4944), or extension */
00235         tr_debug("LOWPAN: %02x %02x", ip_hc[0], ip_hc[1]);
00236         goto drop;
00237     }
00238 
00239     /* Divert to new routing system - in final system, MAC/Mesh/Frag should send to IPV6_TXRX layer */
00240     buf->ip_routed_up = true;
00241     buf = iphc_decompress(&cur->lowpan_contexts, buf);
00242     if (buf) {
00243         buf->info  = (buffer_info_t)(B_DIR_UP | B_FROM_IPV6_TXRX | B_TO_IPV6_FWD);
00244     }
00245     return buf;
00246 
00247 drop:
00248     protocol_stats_update(STATS_IP_RX_DROP, 1);
00249     return buffer_free(buf);
00250 }
00251 
00252 #endif /* HAVE_CIPV6 */
00253