EL4121 Embedded System / mbed-os

Dependents:   cobaLCDJoyMotor_Thread odometry_omni_3roda_v3 odometry_omni_3roda_v1 odometry_omni_3roda_v2 ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers mesh.c Source File

mesh.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2014-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  * \file mesh.c
00019  * \brief 6LoWPAN Mesh header handling (RFC 4944: S5.2, S11)
00020  *
00021  */
00022 
00023 #include "nsconfig.h"
00024 #include <string.h>
00025 #include <ns_types.h>
00026 #include <ns_list.h>
00027 #include "ns_trace.h"
00028 #include "common_functions.h"
00029 #include "NWK_INTERFACE/Include/protocol.h"
00030 #include "NWK_INTERFACE/Include/protocol_stats.h"
00031 #include "6LoWPAN/IPHC_Decode/cipv6.h"
00032 #include "Core/include/socket.h"
00033 #include "6LoWPAN/Mesh/mesh.h"
00034 #include "6LoWPAN/MAC/mac_helper.h"
00035 
00036 #define TRACE_GROUP "mesh"
00037 
00038 #ifdef HAVE_MESH
00039 
00040 /* Nit - this should really be per-interface */
00041 static uint8_t mesh_bc0_sequence;
00042 
00043 /* Thread wants to treat RFC 4944 S.9 multicast addresses as unicast, so
00044  * have to allow a hook to disable multicast functionality. (Also, should
00045  * really be per-interface)
00046  */
00047 static bool support_mesh_multicast = true;
00048 
00049 bool mesh_supports_multicast(void)
00050 {
00051     return support_mesh_multicast;
00052 }
00053 
00054 void mesh_all_addresses_unicast(bool flag)
00055 {
00056     support_mesh_multicast = !flag;
00057 }
00058 
00059 bool mesh_short_address_is_multicast(uint16_t addr)
00060 {
00061     return ((addr & 0xE000) == 0x8000) && support_mesh_multicast;
00062 }
00063 
00064 bool mesh_short_address_is_broadcast_or_multicast(uint16_t addr)
00065 {
00066     return addr == 0xffff || mesh_short_address_is_multicast(addr);
00067 }
00068 
00069 buffer_t *mesh_up(buffer_t *buf)
00070 {
00071     uint8_t *ptr = buffer_data_pointer(buf);
00072     uint_fast16_t len = buffer_data_length(buf);
00073     uint_fast8_t orig_addrlen, final_addrlen, last_hop_addrlen;
00074     uint_fast8_t hops;
00075     const uint8_t *orig_addr, *final_addr, *last_hop_addr;
00076     bool for_us = false;
00077     protocol_interface_info_entry_t *cur = buf->interface ;
00078     if (!cur) {
00079         goto drop;
00080     }
00081 
00082     /* Sanity check - must have 5 bytes (header + 2x16-bit addresses) */
00083     if (len < 5) {
00084         goto drop;
00085     }
00086 
00087     orig_addrlen  = ptr[0] & 0x20 ? 2 : 8;
00088     final_addrlen = ptr[0] & 0x10 ? 2 : 8;
00089     hops          = ptr[0] & 0x0F;
00090     ptr++, len--;
00091 
00092     /* Hops up to 14 can be stored in first byte; can use extra byte for more */
00093     if (hops == 0x0F) {
00094         hops = *ptr++;
00095         len--;
00096     }
00097 
00098     if (hops == 0) {
00099         goto drop;
00100     }
00101 
00102     if (len < orig_addrlen + final_addrlen) {
00103         goto drop;
00104     }
00105 
00106     orig_addr = ptr;
00107     ptr += orig_addrlen;
00108 
00109     final_addr = ptr;
00110     ptr += final_addrlen;
00111 
00112     /* Also consume any BC0 header (we don't need its contents) */
00113     if (len >= 2 && ptr[0] == LOWPAN_DISPATCH_BC0) {
00114         ptr += 2;
00115     }
00116 
00117     /* Routing functions may need to see last hop to avoid loops */
00118     last_hop_addrlen = buf->src_sa .addr_type  == ADDR_802_15_4_LONG  ? 8 : 2;
00119     last_hop_addr = buf->src_sa .address  + 2;
00120 
00121     if (!for_us && final_addrlen == 2) {
00122         uint16_t addr = common_read_16_bit(final_addr);
00123         /* At this layer, we accept all broadcasts, and all multicasts.
00124          * No point in software filtering multicasts here - let the higher
00125          * layers do it. Simplifies code below too.
00126          */
00127         if (mesh_short_address_is_broadcast_or_multicast(addr)) {
00128             if (addr == 0xFFFF) {
00129                 buf->options .ll_broadcast_rx  = true;
00130             } else {
00131                 buf->options .ll_broadcast_rx  = false;
00132                 buf->options .ll_multicast_rx  = true;
00133             }
00134             for_us = true;
00135             /* Potentially let a multicast forwarder deal with it too - if they
00136              * want to retransmit, they'll have to take a copy.
00137              */
00138             if (cur->mesh_callbacks && cur->mesh_callbacks->multicast) {
00139                 cur->mesh_callbacks->multicast(cur, addr, buf);
00140             }
00141         } else if (addr == 0xFFFE) { /* definitely reserved */
00142             goto drop;
00143         } else if ((addr & 0x8000) && mesh_supports_multicast()) {
00144             /* Reserved, but allow use as unicast if mesh_supports_multicast() is false */
00145             goto drop;
00146         }
00147     }
00148 
00149     /* Mirror IP's behaviour with respect to link-layer addresses - it doesn't
00150      * like receiving IP unicasts that aren't link-layer unicasts. Similarly,
00151      * we don't like receiving mesh unicasts that aren't IEEE 802.15.4 unicasts.
00152      */
00153     if (!for_us && buf->options .ll_broadcast_rx ) {
00154         goto drop;
00155     }
00156 
00157     if (!for_us) {
00158         for_us = nwk_interface_compare_mac_address(cur, final_addrlen, final_addr);
00159     }
00160 
00161     if (for_us) {
00162 intercept:
00163         /* Set the source MAC address from the Mesh header */
00164         /* XXX any more sanity checks needed here? */
00165         buf->src_sa .addr_type  = orig_addrlen == 2 ? ADDR_802_15_4_SHORT  : ADDR_802_15_4_LONG ;
00166         /* src_sa is in 802.15.4 header form - ie 2-byte PAN ID, followed by
00167          * 2 or 8 byte address. Leave PAN ID in place and overwrite address */
00168         memcpy(buf->src_sa .address  + 2, orig_addr, orig_addrlen);
00169 
00170         /* Set the buffer dest MAC address from the Mesh header */
00171         buf->dst_sa .addr_type  = final_addrlen == 2 ? ADDR_802_15_4_SHORT  : ADDR_802_15_4_LONG ;
00172         memcpy(buf->dst_sa .address  + 2, final_addr, final_addrlen);
00173 
00174         buf->options .lowpan_mesh_rx  = true;
00175 
00176         /* Remove the Mesh header */
00177         buffer_data_pointer_set(buf, ptr);
00178         /* XXX check - any side-effects of not being B_FROM_MAC? */
00179         buf->info  = (buffer_info_t)(B_DIR_UP | B_FROM_MESH_ROUTING | B_TO_IPV6_TXRX);
00180         return buf;
00181     }
00182 
00183     /* Now we know it's not addressed to us, we can check security - had
00184      * to allow bypass so far for MLE packets to us.
00185      */
00186     if (buf->options .ll_security_bypass_rx ) {
00187         goto drop;
00188     }
00189 
00190     /* We are not the final destination; if we've been given no routing
00191      * routing function pointer, then we just drop the packet. */
00192     if (!cur->mesh_callbacks || !cur->mesh_callbacks->route) {
00193         goto drop;
00194     }
00195 
00196     /*
00197      * Note that all multicast/broadcast are treated as "for us", so only
00198      * unicasts reach here.
00199      */
00200 
00201     /* Do not forward unicast packets that were sent to a broadcast address  */
00202     if (addr_check_broadcast(buf->dst_sa .address , buf->dst_sa .addr_type ) == 0) {
00203         goto drop;
00204     }
00205 
00206     /* Decrement and check the hops count */
00207     if (--hops == 0) {
00208         goto drop;
00209     }
00210 
00211     /* Ask the routing function where to send this */
00212     mesh_routing_route_response_t route;
00213     route.intercept = false;
00214 
00215     if (cur->mesh_callbacks->route(cur, last_hop_addrlen, last_hop_addr, final_addrlen, final_addr, &route)) {
00216         goto drop;
00217     }
00218 
00219     /* If the function says to intercept the packet, do so */
00220     if (route.intercept) {
00221         buf->options .ll_not_ours_rx  = true;
00222         goto intercept;
00223     }
00224 
00225     /* Rewind to rewrite the Mesh Hops Left field */
00226     ptr = buffer_data_pointer(buf);
00227     if ((ptr[0] & 0x0F) != 0x0F) {
00228         /* Modify 4-bit hops field */
00229         ptr[0] = (ptr[0] & 0xF0) | hops;
00230     } else {
00231         /* Modify 8-bit hops field */
00232         if (hops < 0x0F) {
00233             /* 8 bits no longer needed - convert to 4-bit header, save a byte */
00234             ptr[1] = (ptr[0] & 0xF0) | hops;
00235             buffer_data_strip_header(buf, 1);
00236         } else {
00237             ptr[1] = hops;
00238         }
00239     }
00240 
00241     /* Set dest MAC address from routing response */
00242     buf->dst_sa .addr_type  = route.addr_len == 2 ? ADDR_802_15_4_SHORT  : ADDR_802_15_4_LONG ;
00243     memcpy(buf->dst_sa .address  + 2, route.address, route.addr_len);
00244 
00245     /* Set src MAC address from our interface */
00246     if (!mac_helper_write_our_addr(cur, &buf->src_sa )) {
00247         goto drop;
00248     }
00249 
00250     /* Send back down to MAC */
00251     buf->ip_routed_up = true;
00252     buf->info  = (buffer_info_t)(B_FROM_MESH_ROUTING | B_TO_MAC);
00253 
00254     buf->options .code  = 0;
00255     return buf;
00256 
00257 drop:
00258     protocol_stats_update(STATS_IP_RX_DROP, 1);
00259     return buffer_free(buf);
00260 }
00261 
00262 static bool always_add_mesh_header_as_originator;
00263 
00264 void force_mesh_headers(bool force)
00265 {
00266     always_add_mesh_header_as_originator = force;
00267 }
00268 
00269 bool mesh_forwardable_address(const protocol_interface_info_entry_t *cur, addrtype_t addr_type, const uint8_t *addr)
00270 {
00271     if (cur->mesh_callbacks) {
00272         if (cur->mesh_callbacks->forwardable_address) {
00273             return cur->mesh_callbacks->forwardable_address(cur, addr_type, addr);
00274         }
00275 
00276         /* Default to true if no callback */
00277         return true;
00278     }
00279 
00280     return false;
00281 }
00282 
00283 bool mesh_address_map(protocol_interface_info_entry_t *cur, addrtype_t *addr_type, uint8_t *addr)
00284 {
00285     if (cur->mesh_callbacks && cur->mesh_callbacks->address_map) {
00286         return cur->mesh_callbacks->address_map(cur, addr_type, addr);
00287     }
00288 
00289     /* Default to true if no callback - address is untouched */
00290     return true;
00291 }
00292 
00293 bool mesh_header_needed(const buffer_t *buf)
00294 {
00295     protocol_interface_info_entry_t *cur;
00296     if (always_add_mesh_header_as_originator) {
00297         return true;
00298     }
00299 
00300     cur = buf->interface ;
00301     if (cur && cur->mesh_callbacks && cur->mesh_callbacks->header_needed) {
00302         if (cur->mesh_callbacks->header_needed(cur, buf)) {
00303             return true;
00304         }
00305     }
00306 
00307     return false;
00308 }
00309 
00310 uint_fast8_t mesh_header_size(const buffer_t *buf)
00311 {
00312     if (!mesh_header_needed(buf)) {
00313         return 0;
00314     }
00315 
00316     uint_fast8_t hdrlen = 1;
00317     if (MESH_DEFAULT_HOPS_LEFT > 14) {
00318         hdrlen++;
00319     }
00320 
00321     if (buf->src_sa .addr_type  == ADDR_802_15_4_LONG ) {
00322         hdrlen += 8;
00323     } else {
00324         hdrlen += 2;
00325     }
00326 
00327     if (buf->dst_sa .addr_type  == ADDR_802_15_4_LONG ) {
00328         hdrlen += 8;
00329     } else {
00330         hdrlen += 2;
00331         if (buf->dst_sa .addr_type  == ADDR_BROADCAST ) {
00332             hdrlen += 2;    // LOWPAN_BC0 header
00333         }
00334     }
00335 
00336     return hdrlen;
00337 }
00338 
00339 uint_fast8_t mesh_header_len_from_type_byte(uint8_t type)
00340 {
00341     if ((type & LOWPAN_MESH_MASK) != LOWPAN_MESH) {
00342         return 0;
00343     }
00344 
00345     uint_fast8_t hdrlen = 1;
00346     hdrlen += type & 0x20 ? 2 : 8;
00347     hdrlen += type & 0x10 ? 2 : 8;
00348     if ((type & 0x0F) == 0x0F) {
00349         hdrlen += 1;
00350     }
00351 
00352     return hdrlen;
00353 }
00354 
00355 uint_fast8_t mesh_header_len_from_buffer_type_byte(const buffer_t *buf)
00356 {
00357     if (buffer_data_length(buf) == 0) {
00358         return 0;
00359     }
00360 
00361     uint8_t type = buffer_data_pointer(buf)[0];
00362     return mesh_header_len_from_type_byte(type);
00363 }
00364 
00365 /* If header points to a Mesh Header, and it has a following BC0 header, give
00366  * it a new sequence number.
00367  */
00368 void mesh_rewrite_bc0_header(uint8_t *header)
00369 {
00370     uint_fast8_t mesh_len = mesh_header_len_from_type_byte(header[0]);
00371     if (mesh_len) {
00372         header += mesh_len;
00373         if (header[0] == LOWPAN_DISPATCH_BC0) {
00374             header[1] = mesh_bc0_sequence++;
00375         }
00376     }
00377 }
00378 
00379 /* On entry, buf is an unfragmented 6LoWPAN packet, starting with an
00380  * IPHC header.
00381  * buf->dst_sa is set, and type may be ADDR_802_15_4_SHORT, LONG or BROADCAST
00382  *   (if BROADCAST, it may contain a RFC 4944 S.9 multicast address)
00383  * buf->src_sa is set, and type may be ADDR_802_15_4_SHORT or LONG
00384  */
00385 buffer_t *mesh_down(buffer_t *buf)
00386 {
00387     protocol_interface_info_entry_t *cur;
00388     uint8_t mesh_sz = mesh_header_size(buf);
00389     if (mesh_sz == 0) {
00390         /* Shouldn't have come here - should have gone straight to MAC */
00391         tr_error("mesh_down unexpected");
00392         return buffer_free(buf);
00393     }
00394     buf = buffer_headroom(buf, mesh_sz);
00395     if (!buf) {
00396         tr_warn("mesh_down headroom");
00397         return NULL;
00398     }
00399 
00400     cur = buf->interface ;
00401     if (!cur) {
00402         return buffer_free(buf);
00403     }
00404 
00405     uint8_t *ptr = buffer_data_reserve_header(buf, mesh_sz);
00406     uint_fast8_t src_addrlen = 8, dst_addrlen = 8;
00407     *ptr = LOWPAN_MESH;
00408     if (buf->src_sa .addr_type  != ADDR_802_15_4_LONG ) {
00409         /* Source is ADDR_802_15_4_SHORT */
00410         *ptr |= 0x20;
00411         src_addrlen = 2;
00412     }
00413     if (buf->dst_sa .addr_type  != ADDR_802_15_4_LONG ) {
00414         /* Dest is ADDR_802_15_4_SHORT or ADDR_BROADCAST */
00415         *ptr |= 0x10;
00416         dst_addrlen = 2;
00417     }
00418     if (MESH_DEFAULT_HOPS_LEFT > 14) {
00419         *ptr++ |= 0xF;
00420         *ptr++ = MESH_DEFAULT_HOPS_LEFT;
00421     } else {
00422         *ptr++ |= MESH_DEFAULT_HOPS_LEFT;
00423     }
00424 
00425     memcpy(ptr, buf->src_sa .address  + 2, src_addrlen);
00426     ptr += src_addrlen;
00427 
00428     memcpy(ptr, buf->dst_sa .address  + 2, dst_addrlen);
00429     ptr += dst_addrlen;
00430 
00431     if (buf->dst_sa .addr_type  == ADDR_BROADCAST ) {
00432         /* Multicast or broadcast */
00433         *ptr++ = LOWPAN_DISPATCH_BC0;
00434         *ptr++ = mesh_bc0_sequence++;
00435 
00436         /* We've noted any multicast address in the mesh header; for the MAC
00437          * it has to be a broadcast. (Actually, in principle could unicast
00438          * if the routing said it was appropriate, but RFC 4944 says broadcast)
00439          */
00440         common_write_16_bit(0xffff, buf->dst_sa .address  + 2);
00441     } else {
00442         /* Determine first hop - default behaviour is to just transmit to the
00443          * final destination (useful for testing). But if we have a first-hop
00444          * function, ask it where to send it. If it doesn't know, then drop the
00445          * packet.
00446          */
00447         if (cur->mesh_callbacks && cur->mesh_callbacks->first_hop) {
00448             mesh_routing_route_response_t route;
00449             if (cur->mesh_callbacks->first_hop(cur, dst_addrlen, buf->dst_sa .address  + 2, &route)) {
00450                 tr_warn("mesh_down no first hop to %s", trace_array(buf->dst_sa .address  + 2, dst_addrlen));
00451                 socket_tx_buffer_event_and_free(buf, SOCKET_NO_ROUTE);
00452                 return NULL;
00453             }
00454 
00455             /* Modify buffer dest MAC address to first hop response */
00456             buf->dst_sa .addr_type  = route.addr_len == 2 ? ADDR_802_15_4_SHORT  : ADDR_802_15_4_LONG ;
00457             memcpy(buf->dst_sa .address  + 2, route.address, route.addr_len);
00458         }
00459     }
00460 
00461     /* We're the originator here, so address in buf->src_sa that we already used
00462      * as in the Mesh header is also what we want in the MAC header */
00463     buf->info  = (buffer_info_t)(B_FROM_MESH_ROUTING | B_TO_MAC | B_DIR_DOWN);
00464     buf->options .code  = 0;
00465 
00466     return buf;
00467 }
00468 
00469 #endif