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