Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: nRF51_Vdd TextLCD BME280
mesh.c
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
Generated on Tue Jul 12 2022 15:15:52 by
