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.
Dependents: cobaLCDJoyMotor_Thread odometry_omni_3roda_v3 odometry_omni_3roda_v1 odometry_omni_3roda_v2 ... more
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 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
Generated on Tue Jul 12 2022 13:03:04 by
