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: TYBLE16_simple_data_logger TYBLE16_MP3_Air
rpl_data.c
00001 /* 00002 * Copyright (c) 2015-2018, 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 /* rpl_data.c deals with handling of the packet data (hop-by-hop header) 00019 * and Source Routing headers in RPL-routed packets. 00020 * 00021 * rpl_domain_t is accessible, but not normally manipulated - all routines in 00022 * this file works on a specific instance. 00023 * 00024 * rpl_instance_t, rpl_dodag_t, rpl_dodag_version_t, rpl_neighbour_t are all accessible. 00025 */ 00026 00027 #include "nsconfig.h" 00028 00029 #ifdef HAVE_RPL 00030 00031 #include "common_functions.h" 00032 #include "nsdynmemLIB.h" 00033 #include "ns_trace.h" 00034 #include <string.h> 00035 00036 #include "Core/include/ns_buffer.h" 00037 #include "NWK_INTERFACE/Include/protocol.h" 00038 #include "NWK_INTERFACE/Include/protocol_stats.h" 00039 #include "Common_Protocols/ipv6.h" 00040 #include "Common_Protocols/ipv6_resolution.h" 00041 #include "Common_Protocols/icmpv6.h" 00042 00043 #include "RPL/rpl_protocol.h" 00044 #include "RPL/rpl_upward.h" 00045 #include "RPL/rpl_downward.h" 00046 #include "RPL/rpl_structures.h" 00047 #include "RPL/rpl_policy.h" 00048 #include "RPL/rpl_data.h" 00049 00050 #define TRACE_GROUP "RPLa" 00051 00052 #define RPL_DATA_SR_INIT_SIZE (16*4) 00053 00054 #ifdef HAVE_RPL_ROOT 00055 typedef struct rpl_data_sr { 00056 rpl_dao_target_t *target; /* Target - note may be a prefix */ 00057 uint16_t iaddr_size; 00058 uint8_t ihops; /* Number of intermediate hops (= addresses in SRH) */ 00059 uint8_t final_dest[16]; /* Final destination (used only temporarily during header construction) */ 00060 uint8_t iaddr[]; /* Intermediate address list is built backwards, contiguous with final_dest */ 00061 } rpl_data_sr_t; 00062 00063 static rpl_data_sr_t *rpl_data_sr; 00064 #endif 00065 00066 static const uint8_t *rpl_data_get_dodagid(const buffer_t *buf); 00067 00068 bool rpl_data_is_rpl_route(ipv6_route_src_t source) 00069 { 00070 switch (source) { 00071 case ROUTE_RPL_DAO: 00072 case ROUTE_RPL_DAO_SR: 00073 case ROUTE_RPL_SRH: 00074 case ROUTE_RPL_DIO: 00075 case ROUTE_RPL_INSTANCE: 00076 case ROUTE_RPL_ROOT: 00077 case ROUTE_RPL_FWD_ERROR: 00078 return true; 00079 default: 00080 return false; 00081 } 00082 } 00083 00084 bool rpl_data_is_rpl_parent_route(ipv6_route_src_t source) 00085 { 00086 switch (source) { 00087 case ROUTE_RPL_DIO: 00088 case ROUTE_RPL_INSTANCE: 00089 case ROUTE_RPL_ROOT: 00090 return true; 00091 default: 00092 return false; 00093 } 00094 } 00095 00096 static bool rpl_data_is_rpl_downward_route(ipv6_route_src_t source) 00097 { 00098 switch (source) { 00099 case ROUTE_RPL_DAO: 00100 case ROUTE_RPL_DAO_SR: 00101 case ROUTE_RPL_SRH: 00102 return true; 00103 default: 00104 return false; 00105 } 00106 } 00107 00108 static bool rpl_data_handle_fwd_error(buffer_t *buf, protocol_interface_info_entry_t *cur, uint8_t *opt, const sockaddr_t *ll_src) 00109 { 00110 if (!ll_src) { 00111 tr_warn("Forwarding-Error - dst=%s, neighbour unknown", trace_ipv6(buf->dst_sa .address )); 00112 return false; 00113 } else { 00114 tr_warn("Forwarding-Error - dst=%s, neighbour=%s", trace_ipv6(buf->dst_sa .address ), trace_sockaddr(ll_src, true)); 00115 } 00116 00117 rpl_instance_t *instance = rpl_lookup_instance(cur->rpl_domain, opt[1], rpl_data_get_dodagid(buf)); 00118 if (!instance) { 00119 return false; 00120 } 00121 00122 #if 1 00123 return false; 00124 #else 00125 /* Work needed */ 00126 if (rpl_instance_am_root(instance)) { 00127 /* We are looking for a target that has us as its transit */ 00128 } 00129 bool deleted = ipv6_route_delete_by_info_and_ll(buf->dst_sa .address , ROUTE_RPL_DAO, ll_src); 00130 deleted |= ipv6_route_delete_by_info_and_ll(buf->dst_sa .address , ROUTE_RPL_DAO_SR, ll_src); 00131 opt[0] &= ~ RPL_OPT_FWD_ERROR; 00132 00133 return true; 00134 #endif 00135 } 00136 00137 bool rpl_data_process_hbh(buffer_t *buf, protocol_interface_info_entry_t *cur, uint8_t *opt, const sockaddr_t *ll_src) 00138 { 00139 buf->rpl_instance = opt[1]; 00140 buf->rpl_instance_known = true; 00141 00142 /* Act on the forwarding error */ 00143 if (opt[0] & RPL_OPT_FWD_ERROR) { 00144 if (!rpl_data_handle_fwd_error(buf, cur, opt, ll_src)) { 00145 return false; 00146 } 00147 } 00148 00149 /* We don't actually do much now. If the packet is addressed 00150 * to us, we don't need really need much (or any) info. 00151 * 00152 * If we are going to forward forwarding_down will find the option 00153 * manually. If we come to unwrap the tunnel, then we need to take a 00154 * copy before the outer IP header is stripped. 00155 */ 00156 buf->options .ip_extflags |= IPEXT_HBH_RPL; 00157 buf->options .need_predecessor = true; 00158 buf->rpl_flag_error = opt[0]; 00159 00160 return true; 00161 } 00162 00163 /* We assume the packet is basically well-formed, as it will have either 00164 * cleared initial input parsing, or we formed it ourselves. hbh and srh 00165 * are set to point to the RPL Hop-by-Hop option and/or RPL Source Routing 00166 * Header, if present. 00167 */ 00168 static void rpl_data_locate_info(buffer_t *buf, uint8_t **hbh, uint8_t **srh) 00169 { 00170 uint8_t *ptr = buffer_data_pointer(buf); 00171 uint16_t len = buffer_data_length(buf); 00172 00173 if (hbh) { 00174 *hbh = NULL; 00175 } 00176 if (srh) { 00177 *srh = NULL; 00178 } 00179 00180 if (len < IPV6_HDRLEN) { 00181 return; 00182 } 00183 uint16_t ip_len = common_read_16_bit(ptr + IPV6_HDROFF_PAYLOAD_LENGTH); 00184 uint8_t nh = ptr[6]; 00185 ptr += IPV6_HDRLEN; 00186 len -= IPV6_HDRLEN; 00187 if (ip_len > len) { 00188 return; 00189 } 00190 len = ip_len; 00191 while (len) { 00192 uint16_t hdrlen; 00193 switch (nh) { 00194 case IPV6_NH_HOP_BY_HOP: { 00195 if (len < 8) { 00196 return; 00197 } 00198 nh = ptr[0]; 00199 hdrlen = (ptr[1] + 1) * 8; 00200 /* Move on if they're not interested in HbH (looking for SRH) */ 00201 if (!hbh) { 00202 break; 00203 } 00204 if (hdrlen > len) { 00205 return; 00206 } 00207 uint8_t *opt_ptr = ptr + 2; 00208 uint8_t *opt_end = ptr + hdrlen; 00209 while (opt_ptr < opt_end) { 00210 switch (opt_ptr[0]) { 00211 case IPV6_OPTION_PAD1: 00212 opt_ptr++; 00213 break; 00214 case IPV6_OPTION_RPL: 00215 *hbh = opt_ptr; 00216 goto found_option; 00217 default: 00218 opt_ptr += 2 + opt_ptr[1]; 00219 break; 00220 } 00221 } 00222 found_option: 00223 /* If they're not looking for SRH, finish now */ 00224 if (!srh) { 00225 return; 00226 } 00227 break; 00228 } 00229 case IPV6_NH_DEST_OPT: 00230 // Destination option permitted to appear before routing 00231 if (len < 8) { 00232 return; 00233 } 00234 nh = ptr[0]; 00235 hdrlen = (ptr[1] + 1) * 8; 00236 /* If they're not looking for SRH, finish now - past HbH */ 00237 if (!srh) { 00238 return; 00239 } 00240 break; 00241 case IPV6_NH_ROUTING: 00242 if (!srh) { 00243 return; 00244 } 00245 if (ptr[2] == IPV6_ROUTING_TYPE_RPL) { 00246 *srh = ptr; 00247 } 00248 // No need to examine past routing header 00249 return; 00250 default: 00251 // No other headers can appear before routing - last we care about 00252 return; 00253 } 00254 if (hdrlen > len) { 00255 return; 00256 } 00257 ptr += hdrlen; 00258 len -= hdrlen; 00259 } 00260 return; 00261 } 00262 00263 bool rpl_data_remember_outer(buffer_t *buf) 00264 { 00265 /* We're stripping the IP header - need the HBH header for future reference */ 00266 uint8_t *hbh; 00267 rpl_data_locate_info(buf, &hbh, NULL); 00268 if (hbh) { 00269 uint8_t instance_id = hbh[3]; 00270 /* For local instances, also need to extract the DODAG ID from src/dst */ 00271 bool local = rpl_instance_id_is_local(instance_id); 00272 /* Copy the length byte and the option data (and optionally DODAG ID) */ 00273 buf->rpl_option = ns_dyn_mem_temporary_alloc(hbh[1] + 1 + (local ? 16 : 0)); 00274 if (buf->rpl_option) { 00275 memcpy(buf->rpl_option, hbh + 1, hbh[1] + 1); 00276 if (local) { 00277 uint8_t *dodagid = instance_id & RPL_INSTANCE_DEST ? buf->dst_sa .address : buf->src_sa .address ; 00278 memcpy(buf->rpl_option + hbh[1] + 1, dodagid, 16); 00279 } 00280 } 00281 } 00282 00283 if ((buf->options .ip_extflags & IPEXT_HBH_RPL) && !buf->rpl_option) { 00284 tr_warn("RPL tunnel exit HbH fail"); 00285 return false; 00286 } 00287 00288 return true; 00289 } 00290 00291 /* Get the DODAG ID if it's a local DODAG packet */ 00292 static const uint8_t *rpl_data_get_dodagid(const buffer_t *buf) 00293 { 00294 if (!buf->rpl_instance_known || rpl_instance_id_is_global(buf->rpl_instance)) { 00295 return NULL; 00296 } 00297 /* rpl_data_remember_outer() stores it in the rpl_option metatdata */ 00298 if (buf->rpl_option) { 00299 return buf->rpl_option + 1 + buf->rpl_option[1]; 00300 } else { 00301 return buf->rpl_instance & RPL_INSTANCE_DEST ? buf->dst_sa .address 00302 : buf->src_sa .address ; 00303 } 00304 } 00305 00306 /* 00307 * 0 1 2 3 00308 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 00309 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 00310 * | Option Type | Opt Data Len | 00311 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 00312 * |O|R|F|0|0|0|0|0| RPLInstanceID | SenderRank | 00313 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 00314 * | (sub-TLVs) | 00315 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 00316 * 00317 * Figure 1: RPL Option 00318 */ 00319 static buffer_t *rpl_data_exthdr_provider_hbh_2(buffer_t *buf, rpl_instance_t *instance, rpl_neighbour_t *neighbour, ipv6_exthdr_stage_t stage, int16_t *result) 00320 { 00321 ipv6_route_info_t *route_info = &buf->route->route_info; 00322 00323 /* This can be called both for routes which only use HbH headers (eg DIO) 00324 * as well as one-hop DAO_SR routes which would normally use source routing 00325 * headers, if there was more than one hop. For DAO_SR, neighbour will be 00326 * NULL. 00327 */ 00328 00329 rpl_dodag_t *dodag = rpl_instance_current_dodag(instance); 00330 if (!dodag) { 00331 *result = -1; 00332 return buf; 00333 } 00334 00335 bool destination_in_instance = false; 00336 uint16_t ext_size = 0; 00337 if (addr_ipv6_equal(route_info->next_hop_addr, buf->dst_sa .address ) || 00338 addr_ipv6_equal(buf->dst_sa .address , dodag->id)) { 00339 destination_in_instance = true; 00340 00341 if (buf->rpl_option) { 00342 /* Forwarding an existing option - preserve it */ 00343 uint8_t opt_size = buf->rpl_option[0]; 00344 ext_size = 2 + opt_size; 00345 ext_size = (ext_size + 7) & ~ 7; 00346 } else { 00347 /* Generating our own option - fixed size, no TLVs */ 00348 ext_size = 8; 00349 } 00350 } 00351 00352 switch (stage) { 00353 case IPV6_EXTHDR_SIZE: 00354 *result = ext_size; 00355 return buf; 00356 00357 case IPV6_EXTHDR_INSERT: { 00358 if (!destination_in_instance) { 00359 /* We don't add a header - we'll do it on the tunnel */ 00360 *result = 0; 00361 return buf; 00362 } 00363 buf = buffer_headroom(buf, ext_size); 00364 if (!buf) { 00365 return NULL; 00366 } 00367 uint8_t *ext = buffer_data_reserve_header(buf, ext_size); 00368 ext[0] = buf->options .type ; 00369 buf->options .type = IPV6_NH_HOP_BY_HOP; 00370 ext[1] = ext_size / 8 - 1; 00371 uint8_t *opt = ext + 2; 00372 opt[0] = IPV6_OPTION_RPL; 00373 if (buf->rpl_option) { 00374 /* Get back the RPL option we stripped off an outer IP header */ 00375 memcpy(opt + 1, buf->rpl_option, 1 + buf->rpl_option[0]); 00376 ns_dyn_mem_free(buf->rpl_option); 00377 buf->rpl_option = NULL; 00378 } else { 00379 opt[1] = 4; // option length 00380 opt[2] = 0; // placeholder 00381 opt[3] = instance->id; 00382 /* For upwards routes we can deduce that DODAGID must be 00383 * the destination, so set the D flag. 00384 */ 00385 if (rpl_instance_id_is_local(instance->id) && !rpl_data_is_rpl_downward_route(route_info->source)) { 00386 opt[3] |= RPL_INSTANCE_DEST; 00387 } 00388 common_write_16_bit(RPL_RANK_INFINITE, opt + 4); // SenderRank (placeholder) 00389 } 00390 /* Pad HbH header if necessary. */ 00391 uint8_t pad_len = ext + ext_size - (opt + 2 + opt[1]); 00392 if (pad_len == 1) { 00393 opt[0] = IPV6_OPTION_PAD1; 00394 } else if (pad_len > 1) { 00395 opt[0] = IPV6_OPTION_PADN; 00396 opt[1] = pad_len - 2; 00397 memset(opt + 2, 0, pad_len - 2); 00398 } 00399 // don't forget to set the "RPL option present" marker 00400 buf->options .ip_extflags |= IPEXT_HBH_RPL; 00401 *result = 0; 00402 return buf; 00403 } 00404 00405 case IPV6_EXTHDR_MODIFY: { 00406 uint8_t *opt; 00407 uint16_t sender_rank; 00408 00409 rpl_data_locate_info(buf, &opt, NULL); 00410 if (!opt) { 00411 *result = IPV6_EXTHDR_MODIFY_TUNNEL; 00412 // Tunnel to next hop in general case, but if going to DODAGID, 00413 // it can tunnel all the way (and it HAS to if it is a local 00414 // DODAG). 00415 if (!addr_ipv6_equal(buf->dst_sa .address , dodag->id)) { 00416 memcpy(buf->dst_sa .address , route_info->next_hop_addr, 16); 00417 } 00418 buf->src_sa .addr_type = ADDR_NONE ; // force auto-selection 00419 return buf; 00420 } 00421 00422 if (buf->ip_routed_up) { 00423 /* Check for rank errors - RFC 6550 11.2.2.2. */ 00424 /* Note that RPL spec does not say that packets from nodes of 00425 * equal rank are errors, but we treat them as such to get 00426 * reliable sibling loop detection - we require sender rank to be 00427 * strictly less for Down packets and strictly greater for Up. 00428 */ 00429 sender_rank = common_read_16_bit(opt + 4); 00430 rpl_cmp_t cmp = rpl_rank_compare_dagrank_rank(dodag, sender_rank, instance->current_rank); 00431 rpl_cmp_t expected_cmp = (opt[2] & RPL_OPT_DOWN) ? RPL_CMP_LESS : RPL_CMP_GREATER; 00432 if (cmp != expected_cmp) { 00433 /* Set the Rank-Error bit; if already set, drop */ 00434 if (opt[2] & RPL_OPT_RANK_ERROR) { 00435 protocol_stats_update(STATS_RPL_ROUTELOOP, 1); 00436 tr_info("Forwarding inconsistency R"); 00437 rpl_instance_inconsistency(instance); 00438 *result = -1; 00439 return buf; 00440 } else { 00441 opt[2] |= RPL_OPT_RANK_ERROR; 00442 } 00443 } 00444 } 00445 00446 if (buf->rpl_flag_error & RPL_OPT_FWD_ERROR) { 00447 opt[2] |= RPL_OPT_FWD_ERROR; 00448 } else if (rpl_data_is_rpl_downward_route(route_info->source)) { 00449 opt[2] |= RPL_OPT_DOWN; 00450 } else { 00451 opt[2] &= ~RPL_OPT_DOWN; 00452 } 00453 00454 /* Set the D flag for local instances */ 00455 if (rpl_instance_id_is_local(instance->id)) { 00456 if (addr_ipv6_equal(dodag->id, buf->dst_sa .address )) { 00457 opt[3] |= RPL_INSTANCE_DEST; 00458 } else if (addr_ipv6_equal(dodag->id, buf->src_sa .address )) { 00459 opt[3] &= ~ RPL_INSTANCE_DEST; 00460 } else { 00461 tr_error("Local instance invalid %s[%d]: %s -> %s", trace_ipv6(dodag->id), instance->id, trace_ipv6(buf->src_sa .address ), trace_ipv6(buf->dst_sa .address )); 00462 *result = -1; 00463 return buf; 00464 } 00465 } 00466 00467 /* RPL 11.2.2.2. says we set SenderRank to infinite when forwarding 00468 * across a version discontinuity. (Must be up - we don't know versions 00469 * of downward routes). 00470 */ 00471 if ((buf->rpl_flag_error & RPL_OPT_FWD_ERROR) || rpl_data_is_rpl_downward_route(route_info->source) || !neighbour || neighbour->dodag_version == instance->current_dodag_version) { 00472 sender_rank = nrpl_dag_rank(dodag, instance->current_rank); 00473 } else { 00474 sender_rank = RPL_RANK_INFINITE; 00475 } 00476 common_write_16_bit(sender_rank, opt + 4); 00477 *result = 0; 00478 return buf; 00479 } 00480 default: 00481 return buffer_free(buf); 00482 } 00483 } 00484 00485 static buffer_t *rpl_data_exthdr_provider_hbh(buffer_t *buf, ipv6_exthdr_stage_t stage, int16_t *result) 00486 { 00487 ipv6_route_info_t *route_info = &buf->route->route_info; 00488 rpl_neighbour_t *neighbour = route_info->info; 00489 00490 rpl_instance_t *instance = rpl_neighbour_instance(neighbour); 00491 if (!instance) { 00492 *result = -1; 00493 return buf; 00494 } 00495 00496 return rpl_data_exthdr_provider_hbh_2(buf, instance, neighbour, stage, result); 00497 } 00498 00499 static buffer_t *rpl_data_exthdr_provider_fwd_error_hbh(buffer_t *buf, ipv6_exthdr_stage_t stage, int16_t *result) 00500 { 00501 ipv6_route_info_t *route_info = &buf->route->route_info; 00502 rpl_instance_t *instance = route_info->info; 00503 00504 return rpl_data_exthdr_provider_hbh_2(buf, instance, NULL, stage, result); 00505 00506 } 00507 00508 /* This could live in address.c or ipv6.c */ 00509 /* Can get false negatives if we don't already have a neighbour cache entry, but in practice 00510 * will be solid as we are basically matching link-local 6LoWPAN addresses, which can be mapped 00511 * to link-layer without an existing entry. Could conceivably get a false positive if we have 00512 * a stale entry and MAC addresses have been reassigned, but very unlikely. 00513 */ 00514 static bool rpl_downward_ip_addr_matches_ll_addr(protocol_interface_info_entry_t *cur, const uint8_t ip_addr_a[static 16], const sockaddr_t *ll_addr_b) 00515 { 00516 if (!ll_addr_b) { 00517 return false; 00518 } 00519 addrtype_t ll_type_a; 00520 const uint8_t *ll_addr_a; 00521 if (!ipv6_map_ip_to_ll(cur, NULL, ip_addr_a, &ll_type_a, &ll_addr_a)) { 00522 return false; 00523 } 00524 00525 return ll_type_a == ll_addr_b->addr_type && 00526 memcmp(ll_addr_a, ll_addr_b->address , addr_len_from_type(ll_type_a)) == 0; 00527 } 00528 00529 /* ROUTE_RPL_INSTANCE routes are the default for the instance - not valid, unless 00530 * instance is already known. 00531 */ 00532 static bool rpl_data_route_predicate_instance_default(const ipv6_route_info_t *route, bool valid) 00533 { 00534 (void)route; 00535 (void)valid; 00536 00537 return false; 00538 } 00539 00540 static rpl_instance_t *predicate_instance; 00541 static bool predicate_down; 00542 static const sockaddr_t *predicate_predecessor; 00543 00544 /* Override predicate for choosing routes given a specific instance (ie when 00545 * forwarding a packet that had a specified instance ID). That instance is 00546 * loaded into the static predicate_instance above. 00547 */ 00548 static bool rpl_data_route_predicate_specific_instance(const ipv6_route_info_t *route, bool valid) 00549 { 00550 /* We will permit forwarding out of RPL into a non-RPL interface (eg border routers) */ 00551 /* XXX - what if we're the boundary between two RPL domains? */ 00552 protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(route->interface_id); 00553 if (!cur || !cur->rpl_domain) { 00554 return valid; 00555 } 00556 00557 /* If forwarding onto the same interface, think more */ 00558 switch (route->source) { 00559 /* These are the type of routes we will forward onto out of RPL - they 00560 * must include all types of non-owned routes that could be advertised 00561 * through a DAO. 00562 */ 00563 case ROUTE_ARO: 00564 return valid; 00565 00566 /* Upward routes */ 00567 case ROUTE_RPL_DIO: 00568 case ROUTE_RPL_INSTANCE: 00569 case ROUTE_RPL_ROOT: { 00570 /* Packets going down can't go back up */ 00571 if (predicate_down) { 00572 return false; 00573 } 00574 /* Never route to predecessor */ 00575 if (rpl_downward_ip_addr_matches_ll_addr(cur, route->next_hop_addr, predicate_predecessor)) { 00576 return false; 00577 } 00578 /* Info for these upward routes is a back pointer to the neighbour */ 00579 rpl_neighbour_t *neighbour = route->info; 00580 /* From there, we can get the instance info */ 00581 rpl_instance_t *instance = rpl_neighbour_instance(neighbour); 00582 /* Note that this overrides the default "false" for INSTANCE routes */ 00583 return instance == predicate_instance; 00584 } 00585 00586 /* Downward routes */ 00587 case ROUTE_RPL_DAO: 00588 case ROUTE_RPL_DAO_SR: { 00589 /* Info for these downward routes is a back pointer to the target */ 00590 rpl_dao_target_t *target = route->info; 00591 /* Going to predecessor is fine if it was going up - we are reversing to down. Otherwise block */ 00592 if (predicate_down) { 00593 if (rpl_downward_ip_addr_matches_ll_addr(cur, route->next_hop_addr, predicate_predecessor)) { 00594 return false; 00595 } 00596 } 00597 return target->instance == predicate_instance; 00598 } 00599 /* Unknown */ 00600 default: 00601 return false; 00602 } 00603 } 00604 00605 ipv6_route_predicate_fn_t *rpl_data_get_route_predicate(rpl_domain_t *domain, const buffer_t *buf) 00606 { 00607 const uint8_t *dodagid = rpl_data_get_dodagid(buf); 00608 00609 predicate_instance = rpl_lookup_instance(domain, buf->rpl_instance, dodagid); 00610 predicate_down = buf->rpl_flag_error & RPL_OPT_DOWN; 00611 predicate_predecessor = buf->predecessor ; 00612 00613 return rpl_data_route_predicate_specific_instance; 00614 } 00615 00616 /* Returns true if we are going to pass this back with the 'F' bit set */ 00617 /* If we return false, a "no route" ICMP error will occur as normal */ 00618 /* For the ICMP error case, we may treat as a DIO Trickle inconsistency, as 00619 * suggested by RFC 6550 11.1(8) */ 00620 bool rpl_data_forwarding_error(buffer_t *buf) 00621 { 00622 /* This is called when we have no route to send a packet - first check 00623 * if we were forwarding it for RPL - indicated by rpl_instance_known. 00624 */ 00625 if (!buf->rpl_instance_known) { 00626 return false; 00627 } 00628 00629 protocol_interface_info_entry_t *cur = buf->interface ; 00630 if (!cur) { 00631 return false; 00632 } 00633 00634 rpl_instance_t *instance = rpl_lookup_instance(cur->rpl_domain, buf->rpl_instance, rpl_data_get_dodagid(buf)); 00635 if (!instance) { 00636 tr_err("rpl_data_forwarding_error: unknown instance"); 00637 return false; 00638 } 00639 00640 /* To use Forwarding-Error, packet must be Down, and must know predecessor */ 00641 if (!((buf->rpl_flag_error & RPL_OPT_DOWN) && buf->predecessor )) { 00642 goto not_forwarding_error; 00643 } 00644 00645 /* Must then be able to map predecessor to IP address */ 00646 uint8_t predecessor_ip[16]; 00647 if (!ipv6_map_ll_to_ip_link_local(cur, buf->predecessor ->addr_type , buf->predecessor ->address , predecessor_ip)) { 00648 return false; 00649 } 00650 00651 buf->rpl_flag_error |= RPL_OPT_FWD_ERROR; 00652 buffer_free_route(buf); 00653 if (!ipv6_buffer_route_to(buf, predecessor_ip, buf->interface )) { 00654 return false; 00655 } 00656 00657 buf->route->route_info.info = instance; 00658 buf->route->route_info.source = ROUTE_RPL_FWD_ERROR; 00659 00660 return true; 00661 00662 not_forwarding_error: 00663 /* If we're not signalling a Forwarding-Error, we will be sending 00664 * an ICMP Destination Unreachable to the source as normal. But we 00665 * may still want to attempt some sort of RPL repair. If it was coming 00666 * upwards, and we're _not_ the root of the instance, a failure to 00667 * pass it on can only mean some sort of RPL routing problem (eg refusing 00668 * to pass to the predecessor), as we should normally be able to send 00669 * towards the DODAG root. We attempt to aid repair by triggering 00670 * a DIO inconsistency. 00671 * 00672 * If we are the root, then it will just be a perfectly normal 00673 * "destination unreachable" - it doesn't suggest a RPL repair is needed. 00674 */ 00675 if (!(buf->rpl_flag_error & RPL_OPT_DOWN) && !rpl_instance_am_root(instance)) { 00676 protocol_stats_update(STATS_RPL_ROUTELOOP, 1); 00677 tr_info("Forwarding inconsistency 2"); 00678 rpl_instance_inconsistency(instance); 00679 } 00680 return false; 00681 } 00682 00683 #ifdef HAVE_RPL_ROOT 00684 /* TODO - every target involved here should be non-External. Add checks */ 00685 static bool rpl_data_compute_source_route(const uint8_t *final_dest, rpl_dao_target_t *const target) 00686 { 00687 if (!rpl_data_sr) { 00688 rpl_data_sr = rpl_alloc(sizeof(rpl_data_sr_t) + RPL_DATA_SR_INIT_SIZE); 00689 if (!rpl_data_sr) { 00690 return false; 00691 } 00692 rpl_data_sr->iaddr_size = RPL_DATA_SR_INIT_SIZE; 00693 rpl_data_sr->target = NULL; 00694 } else if (rpl_data_sr->target == target && addr_ipv6_equal(rpl_data_sr->final_dest, final_dest)) { 00695 return true; 00696 } 00697 00698 /* This does all the heavy lifting - after running, the optimum path from 00699 * every target node is at the front of the transit list, and the connected 00700 * flag is set if we've any prospect. 00701 */ 00702 rpl_downward_compute_paths(target->instance); 00703 if (!target->connected) { 00704 return false; 00705 } 00706 00707 /* Wipe the "data valid" marker */ 00708 rpl_data_sr->target = NULL; 00709 rpl_data_sr->ihops = 0; 00710 00711 /* Final destination written explicitly (last target could be a prefix) */ 00712 memcpy(rpl_data_sr->final_dest, final_dest, 16); 00713 00714 /* We just work backwards from the target, following the first transit 00715 * each time, which is the shortest path after the compute_paths call. 00716 */ 00717 rpl_dao_target_t *t = target; 00718 for (;;) { 00719 /* First transit is best path, thanks to root computation above */ 00720 rpl_dao_root_transit_t *transit = ns_list_get_first(&t->info.root.transits); 00721 rpl_dao_target_t *parent = transit->parent; 00722 /* Finished if we hit NULL - ourselves */ 00723 if (parent == NULL) { 00724 /* Mark "valid" */ 00725 rpl_data_sr->target = target; 00726 return true; 00727 } 00728 if (!parent->connected) { 00729 tr_err("Parent %s disconnected", trace_ipv6_prefix(parent->prefix, parent->prefix_len)); 00730 return false; 00731 } 00732 /* Check transit address isn't already in table. Should not be possible */ 00733 for (int i = 16 * rpl_data_sr->ihops; i >= 0; i -= 16) { 00734 if (addr_ipv6_equal(rpl_data_sr->final_dest + i, transit->transit)) { 00735 protocol_stats_update(STATS_RPL_ROUTELOOP, 1); 00736 tr_err("SR loop %s->%s", trace_ipv6_prefix(t->prefix, t->prefix_len), trace_ipv6(transit->transit)); 00737 return false; 00738 } 00739 } 00740 /* Increase size of table if necessary */ 00741 if (16 * (rpl_data_sr->ihops + 1) > rpl_data_sr->iaddr_size) { 00742 rpl_data_sr = rpl_realloc(rpl_data_sr, sizeof(rpl_data_sr_t) + rpl_data_sr->iaddr_size, sizeof(rpl_data_sr_t) + 2 * rpl_data_sr->iaddr_size); 00743 if (!rpl_data_sr) { 00744 return false; 00745 } 00746 rpl_data_sr->iaddr_size *= 2; 00747 } 00748 memcpy(rpl_data_sr->iaddr + 16 * rpl_data_sr->ihops, transit->transit, 16); 00749 rpl_data_sr->ihops += 1; 00750 00751 t = parent; 00752 } 00753 } 00754 00755 /* Return the next hop, if there is an intermediate. If it's direct, NULL 00756 * is returned. This call must follow a successful call to 00757 * rpl_data_compute_source_route(). 00758 */ 00759 const uint8_t *rpl_data_sr_next_hop(void) 00760 { 00761 if (rpl_data_sr->ihops == 0) { 00762 return NULL; 00763 } 00764 return rpl_data_sr->iaddr + 16 * (rpl_data_sr->ihops - 1); 00765 } 00766 00767 static bool rpl_data_route_next_hop(const uint8_t *dest, ipv6_route_info_t *route) 00768 { 00769 rpl_dao_target_t *target = route->info; 00770 00771 if (!rpl_data_compute_source_route(dest, target)) { 00772 return false; 00773 } 00774 00775 const uint8_t *next_hop = rpl_data_sr_next_hop(); 00776 if (next_hop) { 00777 memcpy(route->next_hop_addr, next_hop, 16); 00778 } else { 00779 memcpy(route->next_hop_addr, dest, 16); 00780 } 00781 00782 return true; 00783 } 00784 00785 void rpl_data_sr_invalidate(void) 00786 { 00787 if (rpl_data_sr) { 00788 rpl_data_sr->target = NULL; 00789 rpl_data_sr->ihops = 0; 00790 } 00791 /* We could invalidate the next hops remembered in the system routing table. 00792 * but it's not necessary - recomputation happens every time. Does mean that 00793 * the routing table printout may contain stale info, though. 00794 */ 00795 } 00796 00797 typedef struct rpl_srh_info { 00798 uint8_t hlen; 00799 uint8_t segments; 00800 uint8_t cmprI; 00801 uint8_t cmprE; 00802 uint8_t pad; 00803 } rpl_srh_info_t; 00804 00805 /* Count matching bytes (max 15) for SRH compression */ 00806 static uint_fast8_t rpl_data_matching_addr_bytes(const uint8_t *a, const uint8_t *b, uint_fast8_t len) 00807 { 00808 uint_fast8_t m = 0; 00809 while (m < len && a[m] == b[m]) { 00810 m++; 00811 } 00812 return m; 00813 } 00814 00815 static const rpl_srh_info_t *rpl_data_sr_compute_header_size(const uint8_t final_dest[16], uint8_t hop_limit) 00816 { 00817 static rpl_srh_info_t info; 00818 uint8_t hops = 1 + rpl_data_sr->ihops; 00819 if (hops > hop_limit) { 00820 hops = hop_limit; 00821 } 00822 if (hops <= 1) { 00823 return NULL; 00824 } 00825 memcpy(rpl_data_sr->final_dest, final_dest, 16); 00826 /* first_hop is the address that will go into the IP destination */ 00827 const uint8_t *first_hop = rpl_data_sr->iaddr + 16 * (rpl_data_sr->ihops - 1); 00828 /* addr is the first address for the SRH */ 00829 const uint8_t *addr = first_hop - 16; 00830 00831 /* Must be at least 2 hops, so at least 1 segment in the SRH */ 00832 info.segments = hops - 1; 00833 00834 /* First, scan for compression of all except last against initial destination */ 00835 /* (CmprI bytes will remain unchanged at each hop, rest can change) */ 00836 info.cmprI = 15; 00837 for (uint8_t seg = 0; seg < info.segments - 1; seg++) { 00838 info.cmprI = rpl_data_matching_addr_bytes(addr, first_hop, info.cmprI); 00839 hops--; 00840 addr -= 16; 00841 } 00842 00843 /* Compress last hop against previous destination */ 00844 /* Debatable whether we should let cmprE be > cmprI - it means the final 00845 * address won't be IP_dest[0:cmprI)+Address_n[cmprI:64) until the final 00846 * hop (segments left = 1): 00847 * 00848 * CmprI = 14, CmprE = 15 00849 * IP dest Segs Left Addresses 00850 * x:1234 3 2345, 3456, 22 <- meaning "3422", not "1222" 00851 * x:2345 2 1234, 3456, 22 00852 * x:3456 1 1234, 2345, 22 00853 * x:3422 0 1234, 2345, 56 00854 * 00855 * But then similar issues arise if cmprE < cmprI: 00856 * 00857 * CmprI = 15, CmprE = 14 00858 * IP dest Segs Left Addresses 00859 * x:1234 3 45, 56, ABCD 00860 * x:1245 2 34, 56, ABCD 00861 * x:1256 1 34, 45, ABCD 00862 * x:ABCD 0 34, 45, 1256 <- "45" means "1245", not "AB45" 00863 * 00864 * Basically, there's no loss of information, but it's not as straightforward 00865 * as RFC 6554 says. If cmprI != cmprE, not all Address entries represent 00866 * addresses with the same prefix as the IP destination at any given 00867 * instant. (But the next address to process does line up with the current 00868 * IP destination). 00869 * 00870 */ 00871 info.cmprE = rpl_data_matching_addr_bytes(addr, addr + 16, 15 /* info.cmprI */); 00872 00873 uint16_t total_size; 00874 00875 total_size = (16 - info.cmprE) + (16 - info.cmprI) * (info.segments - 1); 00876 if (total_size & 7) { 00877 info.pad = 8 - (total_size & 7); 00878 total_size += info.pad; 00879 } else { 00880 info.pad = 0; 00881 } 00882 info.hlen = total_size >> 3; 00883 00884 return &info; 00885 } 00886 00887 /* 00888 * 0 1 2 3 00889 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 00890 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 00891 * | Next Header | Hdr Ext Len | Routing Type | Segments Left | 00892 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 00893 * | CmprI | CmprE | Pad | Reserved | 00894 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 00895 * | | 00896 * . . 00897 * . Addresses[1..n] . 00898 * . . 00899 * | | 00900 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 00901 */ 00902 static uint8_t *rpl_data_sr_write_header(const rpl_srh_info_t *info, uint8_t *ptr, uint8_t nh) 00903 { 00904 ptr[0] = nh; 00905 ptr[1] = info->hlen; 00906 ptr[2] = IPV6_ROUTING_TYPE_RPL; 00907 ptr[3] = info->segments; 00908 ptr[4] = (info->cmprI << 4) | info->cmprE; 00909 ptr[5] = (info->pad << 4); 00910 common_write_16_bit(0, ptr + 6); 00911 ptr += 8; 00912 const uint8_t *addr = rpl_data_sr->iaddr + 16 * (rpl_data_sr->ihops - 2); 00913 for (int n = 0; n < info->segments - 1; n++) { 00914 memcpy(ptr, addr + info->cmprI, 16 - info->cmprI); 00915 ptr += 16 - info->cmprI; 00916 addr -= 16; 00917 } 00918 memcpy(ptr, addr + info->cmprE, 16 - info->cmprE); 00919 ptr += 16 - info->cmprE; 00920 if (info->pad) { 00921 memset(ptr, 0, info->pad); 00922 ptr += info->pad; 00923 } 00924 return ptr; 00925 } 00926 00927 static buffer_t *rpl_data_exthdr_provider_srh(buffer_t *buf, ipv6_exthdr_stage_t stage, int16_t *result) 00928 { 00929 ipv6_route_info_t *route_info = &buf->route->route_info; 00930 rpl_dao_target_t *target = route_info->info; 00931 rpl_instance_t *instance = target->instance; 00932 if (!instance) { 00933 *result = -1; 00934 return buf; 00935 } 00936 00937 uint16_t ext_size = 0; 00938 const rpl_srh_info_t *srh_info = NULL; 00939 00940 const uint8_t *final_rpl_dest = buf->dst_sa .address ; 00941 00942 if (target->external) { 00943 /* If we haven't yet tunnelled, then there's no insertion */ 00944 if (!buf->options .tunnelled ) { 00945 if (stage == IPV6_EXTHDR_SIZE || stage == IPV6_EXTHDR_INSERT) { 00946 *result = 0; 00947 return buf; 00948 } 00949 } 00950 00951 /* If it's an external target, we need to only go as far as its transit */ 00952 /* Modify target to point to that instead */ 00953 rpl_dao_root_transit_t *transit = ns_list_get_first(&target->info.root.transits); 00954 if (!transit) { 00955 *result = -1; 00956 return buf; 00957 } 00958 final_rpl_dest = transit->transit; 00959 target = rpl_instance_match_dao_target(instance, final_rpl_dest, 128); 00960 if (!target) { 00961 *result = -1; 00962 return buf; 00963 } 00964 } 00965 00966 if (!rpl_data_compute_source_route(final_rpl_dest, target)) { 00967 *result = -1; 00968 return buf; 00969 } 00970 00971 /* When tunnelling (only), we truncate the route in the outer packet, 00972 * according to the hop limit, so it exits the tunnel at the hop limit - 00973 * that router will then generate "time exceeded" on the inner packet. 00974 * (RFC 6554 4.1). When not tunnelling, we include all hops regardless, 00975 * which means the final destination is there as needed. 00976 */ 00977 srh_info = rpl_data_sr_compute_header_size(final_rpl_dest, buf->options .tunnelled && buf->options .type == IPV6_NH_IPV6 ? buf->options .hop_limit : 0xFF); 00978 if (!srh_info) { 00979 /* No source routing header required - this must be because it's one hop. */ 00980 /* In this case, we do need to add a HbH option header */ 00981 return rpl_data_exthdr_provider_hbh_2(buf, instance, NULL, stage, result); 00982 } 00983 ext_size = 8 * (srh_info->hlen + 1); 00984 00985 switch (stage) { 00986 case IPV6_EXTHDR_SIZE: 00987 *result = ext_size; 00988 return buf; 00989 00990 case IPV6_EXTHDR_INSERT: { 00991 buf = buffer_headroom(buf, ext_size); 00992 if (!buf) { 00993 return NULL; 00994 } 00995 uint8_t *ext = buffer_data_reserve_header(buf, ext_size); 00996 rpl_data_sr_write_header(srh_info, ext, buf->options .type ); 00997 buf->route->ip_dest = rpl_data_sr_next_hop(); 00998 buf->options .type = IPV6_NH_ROUTING; 00999 // don't forget to set the "RPL option present" marker 01000 buf->options .ip_extflags |= IPEXT_SRH_RPL; 01001 *result = 0; 01002 return buf; 01003 } 01004 01005 case IPV6_EXTHDR_MODIFY: 01006 if (buf->options .ip_extflags & IPEXT_SRH_RPL) { 01007 *result = 0; 01008 return buf; 01009 } 01010 if (final_rpl_dest != buf->dst_sa .address ) { 01011 memcpy(buf->dst_sa .address , final_rpl_dest, 16); 01012 } 01013 *result = IPV6_EXTHDR_MODIFY_TUNNEL; 01014 buf->src_sa .addr_type = ADDR_NONE ; // force auto-selection 01015 return buf; 01016 01017 default: 01018 return buffer_free(buf); 01019 } 01020 } 01021 #endif // HAVE_RPL_ROOT 01022 01023 buffer_t *rpl_data_process_routing_header(buffer_t *buf, protocol_interface_info_entry_t *cur, uint8_t *ptr, uint16_t *hdrlen_out, bool *forward_out) 01024 { 01025 /* Handling procedures based on RFC 6554 4.2 */ 01026 01027 /* Do not process RPL source routing headers unless they arrive on a RPL interface */ 01028 if (!cur->rpl_domain) { 01029 tr_warn("SRH RX non-RPL if"); 01030 drop: 01031 protocol_stats_update(STATS_IP_RX_DROP, 1); 01032 return buffer_free(buf); 01033 } 01034 01035 buf->options .ip_extflags |= IPEXT_SRH_RPL; 01036 01037 uint16_t hlen = (ptr[1] + 1) * 8; 01038 uint8_t segs_left = ptr[3]; 01039 01040 if (segs_left == 0) { 01041 *hdrlen_out = hlen; 01042 return buf; 01043 } 01044 uint8_t cmprI = ptr[4] >> 4; 01045 uint8_t cmprE = ptr[4] & 0xF; 01046 uint8_t pad = ptr[5] >> 4; 01047 01048 01049 /* Should really be more rigorous here */ 01050 uint_fast16_t n_addrs = ((hlen - 8 - pad - (16 - cmprE)) / (16 - cmprI)) + 1; 01051 if (segs_left > n_addrs) { 01052 return icmpv6_error(buf, cur, ICMPV6_TYPE_ERROR_PARAMETER_PROBLEM, ICMPV6_CODE_PARAM_PRB_HDR_ERR, (ptr + 3) - buffer_data_pointer(buf)); 01053 } 01054 01055 uint8_t *ip_dst = buffer_data_pointer(buf) + 24; 01056 01057 /* Decrement segments left */ 01058 segs_left = --ptr[3]; 01059 01060 if (addr_is_ipv6_multicast(buf->dst_sa .address )) { 01061 goto drop; 01062 } 01063 01064 /* Next address index (starting at 1, as per RFC 6554) */ 01065 uint_fast16_t next_addr_i = n_addrs - segs_left; 01066 01067 /* Locate next address: aptr -> Address[i] */ 01068 uint8_t *aptr = ptr + 8 + (next_addr_i - 1) * (16 - cmprI); 01069 uint8_t cmpr = next_addr_i == n_addrs ? cmprE : cmprI; 01070 uint8_t asize = 16 - cmpr; 01071 01072 /* Next address can only be multicast if compression is 0, otherwise 01073 * it inherits an already-checked non-0xFF start byte from IP destination 01074 */ 01075 if (cmpr == 0 && addr_is_ipv6_multicast(aptr)) { 01076 goto drop; 01077 } 01078 01079 /* Look for a loop. Scanning all addresses 1..n would be a pain, given 01080 * the possibility of weird cmprI/E combinations. But there's logically 01081 * no need to look at _previous_ addresses. And we know the packet was 01082 * addressed to us to reach us - Address[i-1] must have been ours. So 01083 * to ensure we do the test in RFC 6554: 01084 * 01085 * if 2 or more entries in Address[1..n] are assigned to 01086 * local interface and are separated by at least one 01087 * address not assigned to local interface 01088 * 01089 * We just check Address[i..n], knowing that i-1 was ours. It's impossible 01090 * for anything older than i-1 to be ours, as we would have failed the 01091 * check previously... 01092 * 01093 * There need to be at least 2 more addresses (i and i+1) for this check 01094 * to be useful. 01095 */ 01096 if (next_addr_i + 1 <= n_addrs) { 01097 uint8_t addr[16]; 01098 /* We know Address[i-1] was ours */ 01099 bool prev_was_local = true; 01100 /* Initialise pointers to examine Address[i] */ 01101 memcpy(addr, ip_dst, 16); 01102 const uint8_t *a = aptr; 01103 /* Then scan remaining */ 01104 for (uint_fast16_t i = next_addr_i; i <= n_addrs; i++) { 01105 uint8_t cpr = i == n_addrs ? cmprE : cmprI; 01106 uint8_t asz = 16 - cpr; 01107 memcpy(addr + cpr, a, asz); 01108 a += asz; 01109 bool local_addr = addr_interface_address_compare(cur, addr) == 0; 01110 if (local_addr) { 01111 if (!prev_was_local) { 01112 protocol_stats_update(STATS_RPL_ROUTELOOP, 1); 01113 tr_warn("SRH loop"); 01114 return icmpv6_error(buf, cur, ICMPV6_TYPE_ERROR_PARAMETER_PROBLEM, ICMPV6_CODE_PARAM_PRB_HDR_ERR, aptr - buffer_data_pointer(buf)); 01115 } 01116 } 01117 prev_was_local = local_addr; 01118 } 01119 } 01120 01121 /* Swap the destination and Address[i] */ 01122 memswap(ip_dst + cmpr, aptr, asize); 01123 01124 /* And update the metadata */ 01125 memcpy(buf->dst_sa .address , ip_dst, 16); 01126 01127 /* Need to fake up routing here. Basically, for the common (shared-prefix) 01128 * case, we have to assume that the destination is on-link, on an assumed 01129 * interface. We have no direct record of the people trying to use us 01130 * as DAO parents, so we will get totally unknown addresses in SRHs. 01131 * We add routing info to the buffer to say that the IP destination is 01132 * the next hop, and the source being "SRH" is the IP layer's cue to send 01133 * "Error in Source Routing Header" codes instead of "Address Unreachable". 01134 */ 01135 buffer_free_route(buf); 01136 01137 /* THINK: May want to check to see if the address is already known to be on-link on 01138 * an interface. Won't be the usual 6LoWPAN case though. 01139 */ 01140 01141 /* Policy gets to decide whether we will take this - it can do neighbour state checks */ 01142 protocol_interface_info_entry_t *next_if = 01143 protocol_stack_interface_info_get_by_id( 01144 rpl_policy_srh_next_hop_interface(cur->rpl_domain, cur->id, 01145 buf->dst_sa .address )); 01146 if (!next_if) { 01147 goto error; 01148 } 01149 01150 buffer_routing_info_t *route = ipv6_buffer_route_to(buf, buf->dst_sa .address , next_if); 01151 if (!route) { 01152 /* Shouldn't happen here? Out of memory case? */ 01153 goto error; 01154 } 01155 route->route_info.source = ROUTE_RPL_SRH; 01156 01157 *forward_out = true; 01158 return buf; 01159 01160 error: 01161 return icmpv6_error(buf, cur, ICMPV6_TYPE_ERROR_DESTINATION_UNREACH, ICMPV6_CODE_DST_UNREACH_SRC_RTE_HDR_ERR, 0); 01162 } 01163 01164 bool rpl_data_get_srh_last_address(const uint8_t *rh, uint8_t *addr_out) 01165 { 01166 uint_fast8_t len = rh[1]; 01167 uint_fast8_t segs_left = rh[3]; 01168 uint_fast8_t cmpr_i = rh[4] >> 4; 01169 uint_fast8_t cmpr_e = rh[4] & 0xF; 01170 uint_fast8_t pad = rh[5] >> 4; 01171 01172 const uint8_t *last_addr_ptr = rh + 8 + (len * 8) - pad - (16 - cmpr_e); 01173 01174 if (segs_left == 0) { 01175 return true; 01176 } 01177 01178 if (segs_left > 1) { 01179 /* Get last "I" destination in */ 01180 memcpy(addr_out + cmpr_i, last_addr_ptr - (16 - cmpr_i), 16 - cmpr_i); 01181 } 01182 01183 /* Then modify "E" destination */ 01184 memcpy(addr_out + cmpr_e, last_addr_ptr, 16 - cmpr_e); 01185 return true; 01186 } 01187 01188 /* Set up handlers for general RPL nodes (hop-by-hop headers, DIO routes) */ 01189 void rpl_data_init(void) 01190 { 01191 ipv6_route_table_set_predicate_fn(ROUTE_RPL_INSTANCE, rpl_data_route_predicate_instance_default); 01192 ipv6_set_exthdr_provider(ROUTE_RPL_INSTANCE, rpl_data_exthdr_provider_hbh); 01193 ipv6_set_exthdr_provider(ROUTE_RPL_DIO, rpl_data_exthdr_provider_hbh); 01194 ipv6_set_exthdr_provider(ROUTE_RPL_ROOT, rpl_data_exthdr_provider_hbh); 01195 ipv6_set_exthdr_provider(ROUTE_RPL_FWD_ERROR, rpl_data_exthdr_provider_fwd_error_hbh); 01196 } 01197 01198 #ifdef HAVE_RPL_ROOT 01199 /* Set up handlers for DODAG root (creation of source routing headers) */ 01200 void rpl_data_init_root(void) 01201 { 01202 ipv6_set_exthdr_provider(ROUTE_RPL_DAO_SR, rpl_data_exthdr_provider_srh); 01203 ipv6_route_table_set_next_hop_fn(ROUTE_RPL_DAO_SR, rpl_data_route_next_hop); 01204 } 01205 #endif 01206 01207 #endif /* HAVE_RPL */
Generated on Tue Jul 12 2022 13:54:47 by
