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.
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 14:24:27 by
