Knight KE / Mbed OS Game_Master
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     buf->src_sa .addr_type  = ADDR_NONE ;
00247     if (!mac_helper_write_our_addr(cur, &buf->src_sa )) {
00248         goto drop;
00249     }
00250 
00251     /* Send back down to MAC */
00252     buf->ip_routed_up = true;
00253     buf->info  = (buffer_info_t)(B_FROM_MESH_ROUTING | B_TO_MAC);
00254 
00255     buf->options .code  = 0;
00256     return buf;
00257 
00258 drop:
00259     protocol_stats_update(STATS_IP_RX_DROP, 1);
00260     return buffer_free(buf);
00261 }
00262 
00263 static bool always_add_mesh_header_as_originator;
00264 
00265 void force_mesh_headers(bool force)
00266 {
00267     always_add_mesh_header_as_originator = force;
00268 }
00269 
00270 bool mesh_forwardable_address(const protocol_interface_info_entry_t *cur, addrtype_t addr_type, const uint8_t *addr)
00271 {
00272     if (cur->mesh_callbacks) {
00273         if (cur->mesh_callbacks->forwardable_address) {
00274             return cur->mesh_callbacks->forwardable_address(cur, addr_type, addr);
00275         }
00276 
00277         /* Default to true if no callback */
00278         return true;
00279     }
00280 
00281     return false;
00282 }
00283 
00284 bool mesh_address_map(protocol_interface_info_entry_t *cur, addrtype_t *addr_type, uint8_t *addr)
00285 {
00286     if (cur->mesh_callbacks && cur->mesh_callbacks->address_map) {
00287         return cur->mesh_callbacks->address_map(cur, addr_type, addr);
00288     }
00289 
00290     /* Default to true if no callback - address is untouched */
00291     return true;
00292 }
00293 
00294 bool mesh_header_needed(const buffer_t *buf)
00295 {
00296     protocol_interface_info_entry_t *cur;
00297     if (always_add_mesh_header_as_originator) {
00298         return true;
00299     }
00300 
00301     cur = buf->interface ;
00302     if (cur && cur->mesh_callbacks && cur->mesh_callbacks->header_needed) {
00303         if (cur->mesh_callbacks->header_needed(cur, buf)) {
00304             return true;
00305         }
00306     }
00307 
00308     return false;
00309 }
00310 
00311 uint_fast8_t mesh_header_size(const buffer_t *buf)
00312 {
00313     if (!mesh_header_needed(buf)) {
00314         return 0;
00315     }
00316 
00317     uint_fast8_t hdrlen = 1;
00318     if (MESH_DEFAULT_HOPS_LEFT > 14) {
00319         hdrlen++;
00320     }
00321 
00322     if (buf->src_sa .addr_type  == ADDR_802_15_4_LONG ) {
00323         hdrlen += 8;
00324     } else {
00325         hdrlen += 2;
00326     }
00327 
00328     if (buf->dst_sa .addr_type  == ADDR_802_15_4_LONG ) {
00329         hdrlen += 8;
00330     } else {
00331         hdrlen += 2;
00332         if (buf->dst_sa .addr_type  == ADDR_BROADCAST ) {
00333             hdrlen += 2;    // LOWPAN_BC0 header
00334         }
00335     }
00336 
00337     return hdrlen;
00338 }
00339 
00340 uint_fast8_t mesh_header_len_from_type_byte(uint8_t type)
00341 {
00342     if ((type & LOWPAN_MESH_MASK) != LOWPAN_MESH) {
00343         return 0;
00344     }
00345 
00346     uint_fast8_t hdrlen = 1;
00347     hdrlen += type & 0x20 ? 2 : 8;
00348     hdrlen += type & 0x10 ? 2 : 8;
00349     if ((type & 0x0F) == 0x0F) {
00350         hdrlen += 1;
00351     }
00352 
00353     return hdrlen;
00354 }
00355 
00356 uint_fast8_t mesh_header_len_from_buffer_type_byte(const buffer_t *buf)
00357 {
00358     if (buffer_data_length(buf) == 0) {
00359         return 0;
00360     }
00361 
00362     uint8_t type = buffer_data_pointer(buf)[0];
00363     return mesh_header_len_from_type_byte(type);
00364 }
00365 
00366 /* If header points to a Mesh Header, and it has a following BC0 header, give
00367  * it a new sequence number.
00368  */
00369 void mesh_rewrite_bc0_header(uint8_t *header)
00370 {
00371     uint_fast8_t mesh_len = mesh_header_len_from_type_byte(header[0]);
00372     if (mesh_len) {
00373         header += mesh_len;
00374         if (header[0] == LOWPAN_DISPATCH_BC0) {
00375             header[1] = mesh_bc0_sequence++;
00376         }
00377     }
00378 }
00379 
00380 /* On entry, buf is an unfragmented 6LoWPAN packet, starting with an
00381  * IPHC header.
00382  * buf->dst_sa is set, and type may be ADDR_802_15_4_SHORT, LONG or BROADCAST
00383  *   (if BROADCAST, it may contain a RFC 4944 S.9 multicast address)
00384  * buf->src_sa is set, and type may be ADDR_802_15_4_SHORT or LONG
00385  */
00386 buffer_t *mesh_down(buffer_t *buf)
00387 {
00388     protocol_interface_info_entry_t *cur;
00389     uint8_t mesh_sz = mesh_header_size(buf);
00390     if (mesh_sz == 0) {
00391         /* Shouldn't have come here - should have gone straight to MAC */
00392         tr_error("mesh_down unexpected");
00393         return buffer_free(buf);
00394     }
00395     buf = buffer_headroom(buf, mesh_sz);
00396     if (!buf) {
00397         tr_warn("mesh_down headroom");
00398         return NULL;
00399     }
00400 
00401     cur = buf->interface ;
00402     if (!cur) {
00403         return buffer_free(buf);
00404     }
00405 
00406     uint8_t *ptr = buffer_data_reserve_header(buf, mesh_sz);
00407     uint_fast8_t src_addrlen = 8, dst_addrlen = 8;
00408     *ptr = LOWPAN_MESH;
00409     if (buf->src_sa .addr_type  != ADDR_802_15_4_LONG ) {
00410         /* Source is ADDR_802_15_4_SHORT */
00411         *ptr |= 0x20;
00412         src_addrlen = 2;
00413     }
00414     if (buf->dst_sa .addr_type  != ADDR_802_15_4_LONG ) {
00415         /* Dest is ADDR_802_15_4_SHORT or ADDR_BROADCAST */
00416         *ptr |= 0x10;
00417         dst_addrlen = 2;
00418     }
00419     if (MESH_DEFAULT_HOPS_LEFT > 14) {
00420         *ptr++ |= 0xF;
00421         *ptr++ = MESH_DEFAULT_HOPS_LEFT;
00422     } else {
00423         *ptr++ |= MESH_DEFAULT_HOPS_LEFT;
00424     }
00425 
00426     memcpy(ptr, buf->src_sa .address  + 2, src_addrlen);
00427     ptr += src_addrlen;
00428 
00429     memcpy(ptr, buf->dst_sa .address  + 2, dst_addrlen);
00430     ptr += dst_addrlen;
00431 
00432     if (buf->dst_sa .addr_type  == ADDR_BROADCAST ) {
00433         /* Multicast or broadcast */
00434         *ptr++ = LOWPAN_DISPATCH_BC0;
00435         *ptr++ = mesh_bc0_sequence++;
00436 
00437         /* We've noted any multicast address in the mesh header; for the MAC
00438          * it has to be a broadcast. (Actually, in principle could unicast
00439          * if the routing said it was appropriate, but RFC 4944 says broadcast)
00440          */
00441         common_write_16_bit(0xffff, buf->dst_sa .address  + 2);
00442     } else {
00443         /* Determine first hop - default behaviour is to just transmit to the
00444          * final destination (useful for testing). But if we have a first-hop
00445          * function, ask it where to send it. If it doesn't know, then drop the
00446          * packet.
00447          */
00448         if (cur->mesh_callbacks && cur->mesh_callbacks->first_hop) {
00449             mesh_routing_route_response_t route;
00450             if (cur->mesh_callbacks->first_hop(cur, dst_addrlen, buf->dst_sa .address  + 2, &route)) {
00451                 tr_warn("mesh_down no first hop to %s", trace_array(buf->dst_sa .address  + 2, dst_addrlen));
00452                 socket_tx_buffer_event_and_free(buf, SOCKET_NO_ROUTE);
00453                 return NULL;
00454             }
00455 
00456             /* Modify buffer dest MAC address to first hop response */
00457             buf->dst_sa .addr_type  = route.addr_len == 2 ? ADDR_802_15_4_SHORT  : ADDR_802_15_4_LONG ;
00458             memcpy(buf->dst_sa .address  + 2, route.address, route.addr_len);
00459         }
00460     }
00461 
00462     /* We're the originator here, so address in buf->src_sa that we already used
00463      * as in the Mesh header is also what we want in the MAC header */
00464     buf->info  = (buffer_info_t)(B_FROM_MESH_ROUTING | B_TO_MAC | B_DIR_DOWN);
00465     buf->options .code  = 0;
00466 
00467     return buf;
00468 }
00469 
00470 #endif