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.
rpl_upward.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_upward.c deals with management of the DODAG and upward routes within an 00019 * instance. 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 #include "ns_types.h" 00031 #include "ns_list.h" 00032 #include "ns_trace.h" 00033 #include "common_functions.h" 00034 #include "randLIB.h" 00035 #include "nsdynmemLIB.h" 00036 #include <string.h> 00037 #include "ip6string.h" 00038 00039 #include "net_interface.h" 00040 00041 #include "Core/include/address.h" 00042 #include "Common_Protocols/icmpv6.h" 00043 #include "Common_Protocols/icmpv6_prefix.h" 00044 #include "NWK_INTERFACE/Include/protocol_abstract.h" 00045 #include "NWK_INTERFACE/Include/protocol_stats.h" 00046 #include "Service_Libs/Trickle/trickle.h" 00047 #include "ipv6_stack/ipv6_routing_table.h" 00048 #include "6LoWPAN/Bootstraps/protocol_6lowpan.h" 00049 #include "Common_Protocols/ipv6_resolution.h" 00050 00051 #include "RPL/rpl_protocol.h" 00052 #include "RPL/rpl_policy.h" 00053 #include "RPL/rpl_control.h" 00054 #include "RPL/rpl_objective.h" 00055 #include "RPL/rpl_upward.h" 00056 #include "RPL/rpl_downward.h" 00057 #include "RPL/rpl_structures.h" 00058 00059 #include "net_rpl.h" 00060 00061 #define TRACE_GROUP "rplu" 00062 00063 /* How many times to transmit/retransmit a zero-lifetime route */ 00064 #define RPL_MAX_FINAL_RTR_ADVERTISEMENTS 3 00065 00066 #define RPL_DEFAULT_DIO_INTERVAL_MIN 3 00067 #define RPL_DEFAULT_DIO_INTERVAL_DOUBLINGS 20 00068 00069 #define RPL_DEFAULT_IMIN_TICKS (((1ull << RPL_DEFAULT_DIO_INTERVAL_MIN) + 99) / 100) 00070 #define RPL_DEFAULT_IMAX_TICKS (((1ull << (RPL_DEFAULT_DIO_INTERVAL_MIN+RPL_DEFAULT_DIO_INTERVAL_DOUBLINGS)) + 99) / 100) 00071 00072 static NS_LIST_DEFINE(rpl_candidate_neighbour_set, rpl_neighbour_t, candidate_neighbour_link); 00073 00074 static void rpl_instance_remove_parents(rpl_instance_t *instance); 00075 static void rpl_instance_remove_system_routes_through_parent(rpl_instance_t *instance, rpl_neighbour_t *parent); 00076 static void rpl_dodag_update_system_route(rpl_dodag_t *dodag, rpl_dio_route_t *route); 00077 00078 /* Rank comparison, and DAGRank(rank) */ 00079 uint16_t nrpl_dag_rank(const rpl_dodag_t *dodag, uint16_t rank) 00080 { 00081 return rank == RPL_RANK_INFINITE ? rank : rank / dodag->config.min_hop_rank_increase; 00082 } 00083 00084 /* Silly function needed because RPL HbH option includes dagrank directly */ 00085 rpl_cmp_t rpl_rank_compare_dagrank_rank(const rpl_dodag_t *dodag, uint16_t dag_rank_a, uint16_t b) 00086 { 00087 /* Special infinity handling makes sure we're absolutely solid, but callers 00088 * do need to then consider the (faint) possibility of unordered. 00089 */ 00090 if (dag_rank_a == RPL_RANK_INFINITE) { 00091 return b == RPL_RANK_INFINITE ? RPL_CMP_UNORDERED : RPL_CMP_GREATER; 00092 } else if (b == RPL_RANK_INFINITE) { 00093 return RPL_CMP_LESS; 00094 } 00095 00096 if (!dodag) { 00097 return RPL_CMP_UNORDERED; 00098 } 00099 00100 uint16_t dag_rank_b = nrpl_dag_rank(dodag, b); 00101 if (dag_rank_a < dag_rank_b) { 00102 return RPL_CMP_LESS; 00103 } else if (dag_rank_a == dag_rank_b) { 00104 return RPL_CMP_EQUAL; 00105 } else { 00106 return RPL_CMP_GREATER; 00107 } 00108 } 00109 00110 rpl_cmp_t rpl_rank_compare(const rpl_dodag_t *dodag, uint16_t a, uint16_t b) 00111 { 00112 uint16_t dag_rank_a = nrpl_dag_rank(dodag, a); 00113 return rpl_rank_compare_dagrank_rank(dodag, dag_rank_a, b); 00114 } 00115 00116 /* Given a Rank, round up to the next higher integral rank */ 00117 uint16_t rpl_rank_next_level(const rpl_dodag_t *dodag, uint16_t a) 00118 { 00119 uint16_t r = dodag->config.min_hop_rank_increase * (1 + nrpl_dag_rank(dodag, a)); 00120 return r >= a ? r : RPL_RANK_INFINITE; 00121 } 00122 00123 /* Given a Rank, return the maximum Rank with equal DAGRank */ 00124 uint16_t rpl_rank_max_at_level(const rpl_dodag_t *dodag, uint16_t a) 00125 { 00126 uint16_t r = dodag->config.min_hop_rank_increase * (1 + nrpl_dag_rank(dodag, a)) - 1; 00127 return r >= a ? r : RPL_RANK_INFINITE; 00128 } 00129 00130 /* Add two ranks, checking for overflow */ 00131 uint16_t rpl_rank_add(uint16_t a, uint16_t b) 00132 { 00133 uint16_t r = a + b; 00134 return r >= a ? r : RPL_RANK_INFINITE; 00135 } 00136 00137 /* Subtract two ranks, checking for overflow */ 00138 uint16_t rpl_rank_sub(uint16_t a, uint16_t b) 00139 { 00140 uint16_t r = a - b; 00141 return r <= a ? r : 0; 00142 } 00143 00144 /* Sequence counter operations (RFC 6550 S7.2) */ 00145 #define RPL_SEQUENCE_WINDOW 16 00146 00147 uint8_t rpl_seq_init(void) 00148 { 00149 return 256 - RPL_SEQUENCE_WINDOW; 00150 } 00151 00152 uint8_t rpl_seq_inc(uint8_t seq) 00153 { 00154 return seq == 127 ? 0 : (uint8_t)(seq+1); 00155 } 00156 00157 rpl_cmp_t rpl_seq_compare(uint8_t a, uint8_t b) 00158 { 00159 if (a == b) { 00160 return RPL_CMP_EQUAL; 00161 } else if (a >= 128 && b < 128) { 00162 if (256 + b - a <= RPL_SEQUENCE_WINDOW) { 00163 return RPL_CMP_LESS; 00164 } else { 00165 return RPL_CMP_GREATER; 00166 } 00167 } else if (b >= 128 && a < 128) { 00168 if (256 + a - b <= RPL_SEQUENCE_WINDOW) { 00169 return RPL_CMP_GREATER; 00170 } else { 00171 return RPL_CMP_LESS; 00172 } 00173 } else if (a < 128) /* so both <= 127 */ { 00174 /* RFC 6550 description is wrong/misleading ("If the absolute magnitude 00175 * of difference between the two sequence counters is less than or 00176 * equal to SEQUENCE_WINDOW...)". This doesn't cover the wrap 00177 * at the end of the circular region - the difference has to 00178 * be computed modulo-128.. 00179 */ 00180 uint8_t diff = (a - b) & 127; 00181 if (diff <= RPL_SEQUENCE_WINDOW) { 00182 return RPL_CMP_GREATER; 00183 } else if (diff >= 128 - RPL_SEQUENCE_WINDOW) { 00184 return RPL_CMP_LESS; 00185 } else { 00186 return RPL_CMP_UNORDERED; 00187 } 00188 } else /* both >= 128 */ { 00189 /* In this case, there's no wrap, so absolute difference being bigger 00190 * than SEQUENCE_WINDOW is unordered, as the RFC says (230 could be 00191 * newer than 250 due to reboot, or could be old). 00192 */ 00193 uint8_t abs_diff = a > b ? a - b : b - a; 00194 if (abs_diff > RPL_SEQUENCE_WINDOW) { 00195 return RPL_CMP_UNORDERED; 00196 } else if (a > b) { 00197 return RPL_CMP_GREATER; 00198 } else { 00199 return RPL_CMP_LESS; 00200 } 00201 } 00202 } 00203 00204 void rpl_instance_set_dodag_version(rpl_instance_t *instance, rpl_dodag_version_t *version, uint16_t rank) 00205 { 00206 if (!version || rpl_dodag_am_leaf(version->dodag)) { 00207 if (!version) { 00208 tr_debug("No version -> set RPL_RANK_INFINITE"); 00209 } else { 00210 tr_debug("Leaf -> set RPL_RANK_INFINITE"); 00211 } 00212 rank = RPL_RANK_INFINITE; 00213 } 00214 00215 instance->current_rank = rank; 00216 00217 rpl_dodag_version_t *old_version = instance->current_dodag_version; 00218 if (old_version == version) { 00219 return; 00220 } 00221 00222 instance->current_dodag_version = version; 00223 if (version) { 00224 version->dodag->used = true; 00225 if (version->dodag->root) { 00226 rpl_instance_remove_parents(instance); 00227 } 00228 00229 /* Need to call trickle_start somewhere (to avoid uninitialised variables) - this is it */ 00230 if (!old_version || old_version->dodag != version->dodag) { 00231 trickle_start(&instance->dio_timer, &version->dodag->dio_timer_params); 00232 } 00233 } 00234 00235 /* Then changing dodag version is an inconsistency. We may be changing from non-NULL to NULL, in which case we use old parameters to do poison */ 00236 trickle_inconsistent_heard(&instance->dio_timer, version ? &version->dodag->dio_timer_params : &old_version->dodag->dio_timer_params); 00237 } 00238 00239 rpl_dodag_version_t *rpl_instance_current_dodag_version(const rpl_instance_t *instance) { 00240 return instance->current_dodag_version; 00241 } 00242 00243 rpl_dodag_t *rpl_instance_current_dodag(const rpl_instance_t *instance) { 00244 return instance->current_dodag_version ? instance->current_dodag_version->dodag : NULL; 00245 } 00246 00247 #ifdef HAVE_RPL_ROOT 00248 bool rpl_instance_am_root(const rpl_instance_t *instance) 00249 { 00250 rpl_dodag_t *dodag = rpl_instance_current_dodag(instance); 00251 return dodag ? rpl_dodag_am_root(dodag) : false; 00252 } 00253 #endif 00254 00255 uint8_t rpl_instance_mop(const rpl_instance_t *instance) 00256 { 00257 rpl_dodag_t *dodag = rpl_instance_current_dodag(instance); 00258 /* MOP is supposed to be the same for all DODAGs, so take any */ 00259 if (!dodag) { 00260 dodag = ns_list_get_first(&instance->dodags); 00261 } 00262 return dodag ? rpl_dodag_mop(dodag) : RPL_MODE_NO_DOWNWARD; 00263 } 00264 00265 rpl_neighbour_t *rpl_instance_preferred_parent(const rpl_instance_t *instance) 00266 { 00267 /* DODAG parents are first in the neighbour list, and preferred is first. 00268 * So if we have a preferred parent, it's the first entry, and its 00269 * dodag_parent (or was_dodag_parent) flag is set. 00270 */ 00271 rpl_neighbour_t *neighbour = ns_list_get_first(&instance->candidate_neighbours); 00272 if (!neighbour || (!neighbour->dodag_parent && !neighbour->was_dodag_parent)) { 00273 return NULL; 00274 } 00275 return neighbour; 00276 } 00277 00278 /* If we're a member of a DODAG Version matching the predicate in this instance, 00279 * return it. Mainly used for handling DODAG Information Solicitations. 00280 */ 00281 rpl_dodag_version_t *rpl_instance_predicate_match(rpl_instance_t *instance, uint8_t pred, uint8_t instance_id, const uint8_t *dodagid, uint8_t version_num) 00282 { 00283 rpl_dodag_version_t *dodag_version = instance->current_dodag_version; 00284 if (!dodag_version) { 00285 return NULL; 00286 } 00287 if ((pred & RPL_SOLINFO_PRED_INSTANCEID) && (instance->id != instance_id)) { 00288 return NULL; 00289 } 00290 if ((pred & RPL_SOLINFO_PRED_DODAGID) && !addr_ipv6_equal(dodag_version->dodag->id, dodagid)) { 00291 return NULL; 00292 } 00293 if ((pred & RPL_SOLINFO_PRED_VERSION) && dodag_version->number != version_num) { 00294 return NULL; 00295 } 00296 return dodag_version; 00297 } 00298 00299 void rpl_instance_inconsistency(rpl_instance_t *instance) 00300 { 00301 if (instance->current_dodag_version) { 00302 trickle_inconsistent_heard(&instance->dio_timer, &instance->current_dodag_version->dodag->dio_timer_params); 00303 } 00304 } 00305 00306 void rpl_instance_consistent_rx(rpl_instance_t *instance) 00307 { 00308 if (!instance->dio_not_consistent) { 00309 trickle_consistent_heard(&instance->dio_timer); 00310 } 00311 } 00312 00313 void rpl_instance_increment_dtsn(rpl_instance_t *instance) 00314 { 00315 instance->dtsn = rpl_seq_inc(instance->dtsn); 00316 instance->last_dao_trigger_time = protocol_core_monotonic_time; 00317 instance->srh_error_count = 0; 00318 /* Should a DTSN increment trigger DIOs, thus? */ 00319 rpl_instance_inconsistency(instance); 00320 } 00321 00322 void rpl_instance_poison(rpl_instance_t *instance, uint8_t count) 00323 { 00324 if (instance->poison_count < count) { 00325 instance->poison_count = count; 00326 } 00327 rpl_instance_inconsistency(instance); 00328 } 00329 00330 void rpl_instance_force_leaf(rpl_instance_t *instance) 00331 { 00332 instance->current_rank = RPL_RANK_INFINITE; 00333 } 00334 00335 void rpl_instance_trigger_parent_selection(rpl_instance_t *instance, uint16_t delay) 00336 { 00337 if (instance->parent_selection_timer == 0 || instance->parent_selection_timer > delay) { 00338 instance->parent_selection_timer = randLIB_randomise_base(delay, 0x7333, 0x8CCD) /* +/- 10% */; 00339 } 00340 } 00341 00342 static void rpl_instance_parent_selection_timer(rpl_instance_t *instance, uint16_t seconds) 00343 { 00344 if (instance->parent_selection_timer > seconds) { 00345 instance->parent_selection_timer -= seconds; 00346 } else if (instance->parent_selection_timer != 0){ 00347 tr_debug("Timed parent selection"); 00348 rpl_instance_run_parent_selection(instance); 00349 } 00350 } 00351 00352 rpl_dodag_t *rpl_lookup_dodag(const rpl_instance_t *instance, const uint8_t *dodagid) 00353 { 00354 ns_list_foreach(rpl_dodag_t, dodag, &instance->dodags) { 00355 if (addr_ipv6_equal(dodag->id, dodagid)) { 00356 dodag->timestamp = protocol_core_monotonic_time; 00357 return dodag; 00358 } 00359 } 00360 return NULL; 00361 } 00362 00363 rpl_dodag_version_t *rpl_lookup_dodag_version(const rpl_dodag_t *dodag, uint8_t version_num) 00364 { 00365 ns_list_foreach(rpl_dodag_version_t, dodag_version, &dodag->versions) { 00366 if (dodag_version->number == version_num) { 00367 return dodag_version; 00368 } 00369 } 00370 return NULL; 00371 } 00372 00373 rpl_neighbour_t *rpl_lookup_neighbour_by_ll_address(const rpl_instance_t *instance, const uint8_t *addr, int8_t if_id) 00374 { 00375 ns_list_foreach(rpl_neighbour_t, neighbour, &instance->candidate_neighbours) { 00376 if (neighbour->interface_id == if_id && addr_ipv6_equal(neighbour->ll_address, addr)) { 00377 return neighbour; 00378 } 00379 } 00380 return NULL; 00381 } 00382 00383 rpl_neighbour_t *rpl_create_neighbour(rpl_dodag_version_t *version, const uint8_t *addr, int8_t if_id, uint8_t g_mop_prf, uint8_t dtsn) 00384 { 00385 /* Should gate higher-rank neighbours here - ignore higher-rank neighbours 00386 * unless in some sort of local repair. 00387 */ 00388 00389 rpl_neighbour_t *neighbour = rpl_alloc(sizeof(rpl_neighbour_t)); 00390 if (!neighbour) { 00391 return NULL; 00392 } 00393 00394 rpl_instance_t *instance = version->dodag->instance; 00395 neighbour->dodag_version = version; 00396 memcpy(neighbour->ll_address, addr, 16); 00397 memset(neighbour->global_address, 0, 16); 00398 neighbour->have_global_address = false; 00399 neighbour->dodag_parent = neighbour->was_dodag_parent = false; 00400 neighbour->considered = false; 00401 neighbour->interface_id = if_id; 00402 neighbour->rank = 0xffff; 00403 neighbour->g_mop_prf = g_mop_prf; 00404 neighbour->dtsn = dtsn; 00405 neighbour->dao_path_control = 0; 00406 00407 /* Need to limit number of neighbours here - chucking worst neighbour */ 00408 00409 /* Neighbour list wants parents at the front of the list; slot new 00410 * people in after the parents. Then old neighbours get pushed to the end. 00411 */ 00412 ns_list_foreach(rpl_neighbour_t, n, &instance->candidate_neighbours) { 00413 if (!n->dodag_parent) { 00414 ns_list_add_before(&instance->candidate_neighbours, n, neighbour); 00415 return neighbour; 00416 } 00417 } 00418 ns_list_add_to_end(&instance->candidate_neighbours, neighbour); 00419 return neighbour; 00420 } 00421 00422 void rpl_delete_neighbour(rpl_instance_t *instance, rpl_neighbour_t *neighbour) 00423 { 00424 rpl_downward_neighbour_gone(instance, neighbour); 00425 ns_list_remove(&instance->candidate_neighbours, neighbour); 00426 if (neighbour->dao_path_control) { 00427 } 00428 if (neighbour->dodag_parent) { 00429 rpl_instance_remove_system_routes_through_parent(instance, neighbour); 00430 rpl_instance_neighbours_changed(instance); 00431 } 00432 00433 rpl_free(neighbour, sizeof *neighbour); 00434 } 00435 00436 const uint8_t *rpl_neighbour_ll_address(const rpl_neighbour_t *neighbour) 00437 { 00438 return neighbour->ll_address; 00439 } 00440 00441 const uint8_t *rpl_neighbour_global_address(const rpl_neighbour_t *neighbour) 00442 { 00443 return neighbour->have_global_address ? neighbour->global_address : NULL; 00444 } 00445 00446 void rpl_neighbour_update_global_address(rpl_neighbour_t *neighbour, const uint8_t *addr) 00447 { 00448 if (!addr_ipv6_equal(neighbour->global_address, addr)) { 00449 memcpy(neighbour->global_address, addr, 16); 00450 neighbour->have_global_address = true; 00451 //neighbour->down_change = true; 00452 } 00453 } 00454 00455 void rpl_neighbour_update_dodag_version(rpl_neighbour_t *neighbour, rpl_dodag_version_t *version, uint16_t rank, uint8_t g_mop_prf) 00456 { 00457 /* DODAG follows G/MOP/Prf of preferred parent if it isn't moving */ 00458 if (g_mop_prf != version->dodag->g_mop_prf && 00459 (rpl_dodag_version_compare(version, neighbour->dodag_version) & (RPL_CMP_GREATER|RPL_CMP_EQUAL)) && 00460 neighbour == rpl_instance_preferred_parent(version->dodag->instance)) { 00461 version->dodag->g_mop_prf = g_mop_prf; 00462 rpl_dodag_inconsistency(version->dodag); 00463 } 00464 neighbour->g_mop_prf = g_mop_prf; 00465 neighbour->dodag_version = version; 00466 neighbour->rank = rank; 00467 neighbour->dio_timestamp = protocol_core_monotonic_time; 00468 } 00469 00470 bool rpl_neighbour_update_dtsn(rpl_neighbour_t *neighbour, uint8_t dtsn) 00471 { 00472 uint8_t old_dtsn = neighbour->dtsn; 00473 00474 neighbour->dtsn = dtsn; 00475 00476 return neighbour->dodag_parent && (rpl_seq_compare(dtsn, old_dtsn) & RPL_CMP_GREATER); 00477 } 00478 00479 rpl_instance_t *rpl_neighbour_instance(const rpl_neighbour_t *neighbour) 00480 { 00481 return neighbour->dodag_version->dodag->instance; 00482 } 00483 00484 rpl_dodag_version_t *rpl_create_dodag_version(rpl_dodag_t *dodag, uint8_t version_num) 00485 { 00486 rpl_dodag_version_t *version = rpl_alloc(sizeof(rpl_dodag_version_t)); 00487 if (!version) { 00488 return NULL; 00489 } 00490 00491 version->dodag = dodag; 00492 version->number = version_num; 00493 version->last_advertised_rank = RPL_RANK_INFINITE; 00494 version->lowest_advertised_rank = RPL_RANK_INFINITE; 00495 version->greediness_rank_limit = RPL_RANK_INFINITE; 00496 version->hard_rank_limit = RPL_RANK_INFINITE; 00497 00498 if (!ns_list_is_empty(&dodag->versions)) { 00499 protocol_stats_update(STATS_RPL_GLOBAL_REPAIR, 1); 00500 } 00501 00502 /* Maintain the version list newest first, taking care on ordering */ 00503 bool inserted = false; 00504 ns_list_foreach_safe(rpl_dodag_version_t, v, &dodag->versions) { 00505 rpl_cmp_t cmp = rpl_seq_compare(version_num, v->number); 00506 if (cmp & (RPL_CMP_GREATER|RPL_CMP_UNORDERED)) { 00507 /* "Unordered" is treated as newest (as per RFC 6550 7.2 rule 4?) */ 00508 ns_list_add_before(&dodag->versions, v, version); 00509 inserted = true; 00510 break; 00511 } 00512 } 00513 if (!inserted) { 00514 ns_list_add_to_end(&dodag->versions, version); 00515 } 00516 00517 /* Now a clean-up to guarantee we have a completely comparable list. 00518 * Starting from the newest, check every other element is "less" than the 00519 * newest. If we hit one that isn't, chuck that, and all subsequent ones. 00520 */ 00521 rpl_dodag_version_t *newest = ns_list_get_first(&dodag->versions); 00522 for (rpl_dodag_version_t *v = ns_list_get_next(&dodag->versions, newest); v; v = ns_list_get_next(&dodag->versions, v)) { 00523 if (rpl_seq_compare(v->number, newest->number) & RPL_CMP_LESS) { 00524 continue; 00525 } else { 00526 do { 00527 rpl_dodag_version_t *next = ns_list_get_next(&dodag->versions, v); 00528 rpl_delete_dodag_version(v); 00529 v = next; 00530 } while (v); 00531 break; 00532 } 00533 } 00534 00535 00536 00537 return version; 00538 } 00539 00540 void rpl_delete_dodag_version(rpl_dodag_version_t *version) 00541 { 00542 rpl_dodag_t *dodag = version->dodag; 00543 rpl_instance_t *instance = dodag->instance; 00544 00545 if (instance->current_dodag_version == version) { 00546 // Don't call rpl_instance_set_dodag_version(NULL) - that would pre-empt parent reselection, 00547 // triggering poison immediately. 00548 // Give parent selection a chance to select another version (but will it have any info on-hand?) 00549 instance->current_dodag_version = NULL; 00550 rpl_instance_trigger_parent_selection(instance, 5); 00551 } 00552 00553 ns_list_foreach_safe(rpl_neighbour_t, neighbour, &instance->candidate_neighbours) { 00554 if (neighbour->dodag_version == version) { 00555 rpl_delete_neighbour(instance, neighbour); 00556 } 00557 } 00558 ns_list_remove(&dodag->versions, version); 00559 rpl_free(version, sizeof(*version)); 00560 } 00561 00562 bool rpl_dodag_version_is_current(const rpl_dodag_version_t *version) 00563 { 00564 return version->dodag->instance->current_dodag_version == version; 00565 } 00566 00567 bool rpl_dodag_version_rank_indicates_possible_sub_dodag(const rpl_dodag_version_t *version, uint16_t rank) 00568 { 00569 if (!rpl_dodag_version_is_current(version)) { 00570 return false; 00571 } 00572 rpl_cmp_t cmp = rpl_rank_compare(version->dodag, rank, version->dodag->instance->current_rank); 00573 return cmp & RPL_CMP_GREATER; 00574 } 00575 00576 rpl_cmp_t rpl_dodag_version_compare(const rpl_dodag_version_t *a, const rpl_dodag_version_t *b) 00577 { 00578 if (a == NULL || b == NULL) { 00579 return RPL_CMP_UNORDERED; 00580 } 00581 if (a == b) { 00582 return RPL_CMP_EQUAL; 00583 } 00584 if (a->dodag != b->dodag) { 00585 return RPL_CMP_UNORDERED; 00586 } 00587 return rpl_seq_compare(a->number, b->number); 00588 } 00589 00590 void rpl_dodag_version_limit_greediness(rpl_dodag_version_t *version, uint16_t rank) 00591 { 00592 /* Apply RPL greediness limit rule - after we've joined a DODAG version, 00593 * we don't increase rank unless required to by an existing parent. 00594 */ 00595 if (rank != RPL_RANK_INFINITE && version->greediness_rank_limit == RPL_RANK_INFINITE) { 00596 version->greediness_rank_limit = rpl_rank_max_at_level(version->dodag, rank); 00597 } 00598 } 00599 00600 void rpl_dodag_version_raise_greediness(rpl_dodag_version_t *version, uint16_t pref_rank) 00601 { 00602 /* This can be called during parent selection, after preferred parent is chosen, 00603 * to potentially increase the greediness limit considering the new parent circumstance. 00604 * Eg, if our initial and current Rank was 1, our greediness limit would have 00605 * been 1.99. But if we've just had to increase Rank to 2 for an existing 00606 * parent, then we can raise the limit. 00607 */ 00608 if (version->greediness_rank_limit < pref_rank) { 00609 version->greediness_rank_limit = rpl_rank_max_at_level(version->dodag, pref_rank); 00610 } 00611 } 00612 00613 rpl_dodag_t *rpl_create_dodag(rpl_instance_t *instance, const uint8_t *dodagid, uint8_t g_mop_prf) 00614 { 00615 rpl_dodag_t *dodag = rpl_alloc(sizeof(rpl_dodag_t)); 00616 if (!dodag) { 00617 return NULL; 00618 } 00619 00620 dodag->instance = instance; 00621 dodag->timestamp = protocol_core_monotonic_time; 00622 memcpy(dodag->id, dodagid, 16); 00623 dodag->leaf = false; 00624 dodag->root = false; 00625 dodag->have_config = false; 00626 dodag->used = false; 00627 dodag->g_mop_prf = g_mop_prf; 00628 // Default timer parameters and trickle start should never normally 00629 // be used - we would set the parameters from the DODAG Config and start 00630 // as we join a version. But initialising here catches odd cases where 00631 // we end up sending poison DIOs before we get any config. 00632 dodag->dio_timer_params.Imin = RPL_DEFAULT_IMIN_TICKS; 00633 dodag->dio_timer_params.Imax = (trickle_time_t) (RPL_DEFAULT_IMAX_TICKS < TRICKLE_TIME_MAX ? RPL_DEFAULT_IMAX_TICKS : TRICKLE_TIME_MAX); 00634 dodag->dio_timer_params.k = 10; 00635 trickle_start(&instance->dio_timer, &dodag->dio_timer_params); 00636 ns_list_init(&dodag->versions); 00637 ns_list_init(&dodag->routes); 00638 ns_list_init(&dodag->prefixes); 00639 00640 ns_list_add_to_start(&instance->dodags, dodag); 00641 return dodag; 00642 } 00643 00644 void rpl_delete_dodag(rpl_dodag_t *dodag) 00645 { 00646 rpl_instance_t *instance = dodag->instance; 00647 ns_list_foreach_safe(rpl_dodag_version_t, version, &dodag->versions) { 00648 rpl_delete_dodag_version(version); 00649 } 00650 ns_list_foreach_safe(rpl_dio_route_t, route, &dodag->routes) { 00651 rpl_dodag_delete_dio_route(dodag, route); 00652 } 00653 ns_list_foreach_safe(prefix_entry_t, prefix, &dodag->prefixes) { 00654 rpl_dodag_delete_dio_prefix(dodag, prefix); 00655 } 00656 ns_list_remove(&instance->dodags, dodag); 00657 rpl_free(dodag, sizeof(*dodag)); 00658 } 00659 00660 void rpl_delete_dodag_root(rpl_dodag_t *dodag) 00661 { 00662 // This should trigger immediate poison 00663 rpl_instance_set_dodag_version(dodag->instance, NULL, RPL_RANK_INFINITE); 00664 // Deleting DODAG is not ideal - we will just pick up adverts from our 00665 // former children, and recreate, possibly violating the MaxRankIncrease. 00666 // Should retain DODAG version info and just unset root flag, which will 00667 // limit what happens when we hear adverts. 00668 // Problem is rpl_control_create_dodag_root which can't handle the 00669 // case where DODAG already exists. This would always be a problem if 00670 // we'd heard adverts in between delete and create, but would be an instant 00671 // problem without this delete. Need to fix. 00672 rpl_delete_dodag(dodag); 00673 } 00674 00675 /* Convert RPL configuration to generic trickle parameters. Returns true if 00676 * the value in the generic object has changed. 00677 */ 00678 static bool rpl_dodag_conf_convert_trickle_parameters(trickle_params_t *params_out, const rpl_dodag_conf_t *conf) 00679 { 00680 /* Convert trickle parameters into 100ms ticks */ 00681 uint32_t Imin_ms = conf->dio_interval_min < 32 ? (1ul << conf->dio_interval_min) : 0xfffffffful; 00682 uint32_t Imin_ticks = (Imin_ms + 99) / 100; 00683 uint32_t Imax_ms = (conf->dio_interval_min + conf->dio_interval_doublings) < 32 ? 00684 (1ul << (conf->dio_interval_min + conf->dio_interval_doublings)) : 0xfffffffful; 00685 uint32_t Imax_ticks = (Imax_ms + 99) / 100; 00686 trickle_time_t Imin = (trickle_time_t) (Imin_ticks <= TRICKLE_TIME_MAX ? Imin_ticks : TRICKLE_TIME_MAX); 00687 trickle_time_t Imax = (trickle_time_t) (Imax_ticks <= TRICKLE_TIME_MAX ? Imax_ticks : TRICKLE_TIME_MAX); 00688 uint8_t k = conf->dio_redundancy_constant; 00689 if (params_out->Imin != Imin || params_out->Imax != Imax || params_out->k != k) { 00690 params_out->Imin = Imin; 00691 params_out->Imax = Imax; 00692 params_out->k = k; 00693 params_out->TimerExpirations = TRICKLE_EXPIRATIONS_INFINITE; 00694 return true; 00695 } else { 00696 return false; 00697 } 00698 } 00699 00700 uint8_t rpl_dodag_mop(const rpl_dodag_t *dodag) 00701 { 00702 return dodag->g_mop_prf & RPL_MODE_MASK; 00703 } 00704 00705 bool rpl_dodag_update_config(rpl_dodag_t *dodag, const rpl_dodag_conf_t *conf, const uint8_t *src, bool *become_leaf) 00706 { 00707 /* If already have config, don't update unless it's coming from preferred parent */ 00708 if (dodag->have_config) { 00709 rpl_neighbour_t *parent = rpl_instance_preferred_parent(dodag->instance); 00710 if (parent && src && !addr_ipv6_equal(src, parent->ll_address)) { 00711 return true; 00712 } 00713 } 00714 dodag->config = *conf; 00715 bool restart_timer = rpl_dodag_conf_convert_trickle_parameters(&dodag->dio_timer_params, conf); 00716 dodag->have_config = true; 00717 if (restart_timer && rpl_instance_current_dodag(dodag->instance) == dodag) { 00718 /* They've changed the timing parameters for our currently-in-use trickle timer! */ 00719 tr_warn("Trickle parameters changed"); 00720 trickle_start(&dodag->instance->dio_timer, &dodag->dio_timer_params); 00721 } 00722 dodag->instance->of = rpl_objective_lookup(conf->objective_code_point); 00723 /* We could be a leaf of an unknown OCP. Still need an OF to choose parents */ 00724 if (!dodag->instance->of) { 00725 dodag->instance->of = rpl_objective_lookup(RPL_OCP_OF0); 00726 if (!dodag->instance->of) { 00727 return false; 00728 } 00729 if (become_leaf) { 00730 *become_leaf = true; 00731 } 00732 } 00733 return true; 00734 } 00735 00736 /* If we're currently a member of this DODAG, kick the DIO timers */ 00737 void rpl_dodag_inconsistency(rpl_dodag_t *dodag) 00738 { 00739 if (rpl_instance_current_dodag(dodag->instance) == dodag) { 00740 trickle_inconsistent_heard(&dodag->instance->dio_timer, &dodag->dio_timer_params); 00741 } 00742 } 00743 00744 void rpl_dodag_increment_dtsn(rpl_dodag_t *dodag) 00745 { 00746 if (rpl_instance_current_dodag(dodag->instance) == dodag) { 00747 rpl_instance_increment_dtsn(dodag->instance); 00748 } 00749 } 00750 00751 void rpl_dodag_set_pref(rpl_dodag_t *dodag, uint8_t pref) 00752 { 00753 dodag->g_mop_prf &= ~RPL_DODAG_PREF_MASK; 00754 dodag->g_mop_prf |= pref; 00755 } 00756 00757 rpl_cmp_t rpl_dodag_pref_compare(const rpl_dodag_t *a, const rpl_dodag_t *b) 00758 { 00759 uint8_t pref_a, pref_b; 00760 pref_a = a->g_mop_prf & RPL_DODAG_PREF_MASK; 00761 pref_b = b->g_mop_prf & RPL_DODAG_PREF_MASK; 00762 if (pref_a == pref_b) { 00763 return RPL_CMP_EQUAL; 00764 } else if (pref_a < pref_b) { 00765 return RPL_CMP_LESS; 00766 } else { 00767 return RPL_CMP_GREATER; 00768 } 00769 } 00770 00771 void rpl_dodag_set_root(rpl_dodag_t *dodag, bool root) 00772 { 00773 if (root != dodag->root) { 00774 dodag->root = root; 00775 if (root) { 00776 rpl_instance_remove_parents(dodag->instance); 00777 } else { 00778 rpl_instance_run_parent_selection(dodag->instance); 00779 } 00780 } 00781 } 00782 00783 #ifdef HAVE_RPL_ROOT 00784 bool rpl_dodag_am_root(const rpl_dodag_t *dodag) 00785 { 00786 return dodag->root; 00787 } 00788 #endif 00789 00790 void rpl_dodag_set_leaf(rpl_dodag_t *dodag, bool leaf) 00791 { 00792 dodag->leaf = leaf; 00793 } 00794 00795 bool rpl_dodag_am_leaf(const rpl_dodag_t *dodag) 00796 { 00797 return dodag->leaf || dodag->instance->domain->force_leaf; 00798 } 00799 00800 bool rpl_dodag_is_current(const rpl_dodag_t *dodag) 00801 { 00802 return dodag->instance->current_dodag_version && dodag->instance->current_dodag_version->dodag == dodag; 00803 } 00804 00805 const rpl_dodag_conf_t *rpl_dodag_get_config(const rpl_dodag_t *dodag) 00806 { 00807 return dodag->have_config ? &dodag->config : NULL; 00808 } 00809 00810 uint8_t rpl_dodag_get_version_number_as_root(const rpl_dodag_t *dodag) 00811 { 00812 return dodag->instance->current_dodag_version->number; 00813 } 00814 00815 void rpl_dodag_set_version_number_as_root(rpl_dodag_t *dodag, uint8_t number) 00816 { 00817 /* As root, unlike other nodes, we don't need to worry about maintaining 00818 * multiple rpl_dodag_version_t to track neighbours in each version and 00819 * our ranks in each version. We'll just quietly change the version number 00820 * of our only, always-current version. 00821 */ 00822 rpl_dodag_version_t *version = dodag->instance->current_dodag_version; 00823 version->number = number; 00824 rpl_dodag_inconsistency(dodag); 00825 #if defined FEA_TRACE_SUPPORT && defined EXTRA_CONSISTENCY_CHECKS 00826 /* Sanity check that the above assertion is true - as root we shouldn't have 00827 * any neighbours referring to this version. 00828 */ 00829 ns_list_foreach(rpl_neighbour_t, n, &dodag->instance->candidate_neighbours) { 00830 if (n->dodag_version == version) { 00831 tr_err("Root DODAG version had neighbour"); 00832 break; 00833 } 00834 } 00835 #endif 00836 protocol_stats_update(STATS_RPL_GLOBAL_REPAIR, 1); 00837 } 00838 00839 static bool rpl_dodag_in_use(const rpl_dodag_t *dodag) 00840 { 00841 if (dodag->root) { 00842 return true; 00843 } 00844 00845 if (!dodag->have_config) { 00846 return false; 00847 } 00848 00849 rpl_instance_t *instance = dodag->instance; 00850 ns_list_foreach(rpl_neighbour_t, neighbour, &instance->candidate_neighbours) { 00851 if (neighbour->dodag_version->dodag == dodag) { 00852 return true; 00853 } 00854 } 00855 00856 return false; 00857 } 00858 00859 const rpl_dio_route_list_t *rpl_dodag_get_route_list(const rpl_dodag_t *dodag) 00860 { 00861 return &dodag->routes; 00862 } 00863 00864 rpl_dio_route_t *rpl_dodag_update_dio_route(rpl_dodag_t *dodag, const uint8_t *prefix, uint8_t prefix_len, uint8_t flags, uint32_t lifetime, bool age) 00865 { 00866 rpl_dio_route_t *route = NULL; 00867 bool update = false; 00868 00869 /* First look for matching prefix */ 00870 ns_list_foreach(rpl_dio_route_t, r, &dodag->routes) { 00871 if (r->prefix_len == prefix_len && bitsequal(r->prefix, prefix, prefix_len)) { 00872 route = r; 00873 break; 00874 } 00875 } 00876 00877 /* If not found, create a new one */ 00878 if (!route) { 00879 uint_fast8_t prefix_bytes = (prefix_len + 7u) / 8u; 00880 route = rpl_alloc(sizeof(rpl_dio_route_t) + prefix_bytes); 00881 if (!route) { 00882 return NULL; 00883 } 00884 00885 route->prefix_len = prefix_len; 00886 bitcopy0(route->prefix, prefix, prefix_len); 00887 ns_list_add_to_end(&dodag->routes, route); 00888 update = true; 00889 } else { 00890 if (lifetime != route->lifetime || route->flags != flags) { 00891 update = true; 00892 } 00893 } 00894 00895 /* Update other info */ 00896 route->lifetime = lifetime; 00897 route->hold_count = lifetime ? 0 : RPL_MAX_FINAL_RTR_ADVERTISEMENTS; 00898 route->flags = flags; 00899 route->age = age; 00900 if (update) { 00901 rpl_dodag_update_system_route(dodag, route); 00902 } 00903 return route; 00904 } 00905 00906 void rpl_dodag_delete_dio_route(rpl_dodag_t *dodag, rpl_dio_route_t *route) 00907 { 00908 ns_list_remove(&dodag->routes, route); 00909 uint_fast8_t prefix_bytes = (route->prefix_len + 7u) / 8u; 00910 rpl_free(route, sizeof *route + prefix_bytes); 00911 } 00912 00913 static void rpl_dodag_age_routes(rpl_dodag_t *dodag, uint16_t seconds) 00914 { 00915 ns_list_foreach_safe(rpl_dio_route_t, route, &dodag->routes) { 00916 if (route->age && route->lifetime != 0xFFFFFFFF) { 00917 if (route->lifetime > seconds) { 00918 route->lifetime -= seconds; 00919 } else { 00920 route->lifetime = 0; 00921 if (route->hold_count == 0) { 00922 rpl_dodag_delete_dio_route(dodag, route); 00923 } 00924 } 00925 } 00926 } 00927 } 00928 00929 const prefix_list_t *rpl_dodag_get_prefix_list(const rpl_dodag_t *dodag) 00930 { 00931 return &dodag->prefixes; 00932 } 00933 prefix_entry_t *rpl_dodag_update_dio_prefix(rpl_dodag_t *dodag, const uint8_t *prefix, uint8_t prefix_len, uint8_t flags, uint32_t lifetime, uint32_t preftime, bool publish, bool age) 00934 { 00935 /* Don't let them set funny flags - we won't propagate them either. 00936 * Is not propagating them sensible? RFC isn't clear. Anyway, we use 00937 * the spare 5 flag bits internally... 00938 */ 00939 flags &= (PIO_R|PIO_A|PIO_L); 00940 00941 if (publish) { 00942 flags |= RPL_PIO_PUBLISHED; 00943 } 00944 00945 if (age) { 00946 flags |= RPL_PIO_AGE; 00947 } 00948 00949 if (lifetime == 0) { 00950 flags |= RPL_MAX_FINAL_RTR_ADVERTISEMENTS; 00951 } 00952 00953 prefix_entry_t *entry = icmpv6_prefix_add(&dodag->prefixes, prefix, prefix_len, lifetime, preftime, flags); 00954 /* icmpv6_prefix_add indicates a new entry by leaving options set to 0xFF */ 00955 if (entry) { 00956 entry->options = flags; 00957 } 00958 return entry; 00959 } 00960 00961 void rpl_dodag_delete_dio_prefix(rpl_dodag_t *dodag, prefix_entry_t *prefix) 00962 { 00963 ns_list_remove(&dodag->prefixes, prefix); 00964 ns_dyn_mem_free(prefix); 00965 } 00966 00967 static void rpl_dodag_age_prefixes(rpl_dodag_t *dodag, uint16_t seconds) 00968 { 00969 ns_list_foreach_safe(prefix_entry_t, prefix, &dodag->prefixes) { 00970 if (!(prefix->options & RPL_PIO_AGE)) { 00971 continue; 00972 } 00973 if (prefix->preftime != 0xFFFFFFFF) { 00974 if (prefix->preftime > seconds) { 00975 prefix->preftime -= seconds; 00976 } else { 00977 prefix->preftime = 0; 00978 } 00979 } 00980 if (prefix->lifetime != 0xFFFFFFFF) { 00981 if (prefix->lifetime > seconds) { 00982 prefix->lifetime -= seconds; 00983 } else { 00984 prefix->lifetime = 0; 00985 if ((prefix->options & RPL_PIO_HOLD_MASK) == 0) { 00986 rpl_dodag_delete_dio_prefix(dodag, prefix); 00987 } 00988 } 00989 } 00990 } 00991 } 00992 00993 static void rpl_dodag_slow_timer(rpl_dodag_t *dodag, uint16_t seconds) 00994 { 00995 rpl_dodag_age_routes(dodag, seconds); 00996 rpl_dodag_age_prefixes(dodag, seconds); 00997 } 00998 00999 01000 /* Look up a RPL instance by identifier. If the ID is local, addr must 01001 * identify the root - eg by providing either the source destination address of 01002 * a packet (depending on the 'O' flag). 01003 */ 01004 rpl_instance_t *rpl_lookup_instance(const rpl_domain_t *domain, uint8_t instance_id, const uint8_t *addr) 01005 { 01006 if (rpl_instance_id_is_local(instance_id)) { 01007 instance_id &= ~RPL_INSTANCE_DEST; 01008 } 01009 01010 ns_list_foreach(rpl_instance_t, instance, &domain->instances) { 01011 /* First match the instance ID */ 01012 if (instance->id != instance_id) { 01013 continue; 01014 } 01015 /* If it's a global ID, this is a match */ 01016 if (rpl_instance_id_is_global(instance_id)) { 01017 return instance; 01018 } 01019 /* If it's a local ID, address must match */ 01020 const rpl_dodag_t *dodag = ns_list_get_first(&instance->dodags); 01021 if (addr && dodag && addr_ipv6_equal(dodag->id, addr)) { 01022 return instance; 01023 } 01024 } 01025 return NULL; 01026 } 01027 01028 rpl_instance_t *rpl_create_instance(rpl_domain_t *domain, uint8_t instance_id) 01029 { 01030 rpl_instance_t *instance = rpl_alloc(sizeof(rpl_instance_t)); 01031 if (!instance) { 01032 return NULL; 01033 } 01034 memset(instance, 0, sizeof(rpl_instance_t)); 01035 ns_list_init(&instance->dodags); 01036 ns_list_init(&instance->candidate_neighbours); 01037 ns_list_init(&instance->dao_targets); 01038 instance->dtsn = rpl_seq_init(); 01039 instance->last_dao_trigger_time = protocol_core_monotonic_time; 01040 instance->dao_sequence = rpl_seq_init(); 01041 instance->id = instance_id; 01042 instance->domain = domain; 01043 01044 ns_list_add_to_start(&domain->instances, instance); 01045 return instance; 01046 } 01047 01048 void rpl_delete_instance(rpl_instance_t *instance) { 01049 rpl_domain_t *domain = instance->domain; 01050 ns_list_foreach_safe(rpl_neighbour_t, neighbour, &instance->candidate_neighbours) { 01051 rpl_delete_neighbour(instance, neighbour); 01052 } 01053 ns_list_foreach_safe(rpl_dodag_t, dodag, &instance->dodags) { 01054 rpl_delete_dodag(dodag); 01055 } 01056 ns_list_foreach_safe(rpl_dao_target_t, target, &instance->dao_targets) { 01057 rpl_delete_dao_target(instance, target); 01058 } 01059 ns_list_remove(&domain->instances, instance); 01060 rpl_free(instance, sizeof *instance); 01061 } 01062 01063 /* Don't purge a DODAG we've used unless it's been gone for 15 minutes */ 01064 #define DODAG_MIN_PURGE_AGE (15*60*10) // 15 minutes 01065 01066 /* Choose worst DODAG in an instance - will be purgeable */ 01067 static rpl_dodag_t *rpl_instance_choose_dodag_to_purge(const rpl_instance_t *instance) 01068 { 01069 rpl_dodag_t *worst = NULL; 01070 01071 ns_list_foreach_reverse(rpl_dodag_t, dodag, &instance->dodags) { 01072 uint32_t dodag_age = protocol_core_monotonic_time - dodag->timestamp; 01073 if (rpl_dodag_in_use(dodag)) { 01074 continue; 01075 } 01076 01077 if (dodag_age < DODAG_MIN_PURGE_AGE && dodag->used) { 01078 continue; 01079 } 01080 01081 if (!worst) { 01082 goto new_worst; 01083 } 01084 01085 /* Prefer to purge least-recently-heard-from */ 01086 uint32_t worst_age = protocol_core_monotonic_time - worst->timestamp; 01087 if (dodag_age <= worst_age) { 01088 continue; 01089 } else { 01090 goto new_worst; 01091 } 01092 01093 new_worst: 01094 worst = dodag; 01095 worst_age = dodag_age; 01096 } 01097 01098 return worst; 01099 } 01100 01101 /* Choose worst neighbour in an instance - may be a candidate for purging */ 01102 static rpl_neighbour_t *rpl_instance_choose_worst_neighbour(const rpl_instance_t *instance) 01103 { 01104 rpl_neighbour_t *worst = NULL; 01105 bool worst_acceptable = false; 01106 01107 /* Parents will be first - loop backwards so we take non-parents first */ 01108 ns_list_foreach_reverse(rpl_neighbour_t, neighbour, &instance->candidate_neighbours) { 01109 bool acceptable = instance->of->neighbour_acceptable(instance, neighbour); 01110 if (!worst) { 01111 goto new_worst; 01112 } 01113 01114 /* Stop if crossing from non-parents to parents - parents can't be worse */ 01115 if (neighbour->dodag_parent && !worst->dodag_parent) { 01116 break; 01117 } 01118 01119 /* Prefer to purge "unacceptable" neighbours according to OF */ 01120 if (acceptable && !worst_acceptable) { 01121 continue; 01122 } else if (!acceptable && worst_acceptable) { 01123 goto new_worst; 01124 } 01125 01126 /* Prefer to purge least-recently-heard-from */ 01127 uint32_t neighbour_age = protocol_core_monotonic_time - neighbour->dio_timestamp; 01128 uint32_t worst_age = protocol_core_monotonic_time - worst->dio_timestamp; 01129 if (neighbour_age <= worst_age) { 01130 continue; 01131 } else { 01132 goto new_worst; 01133 } 01134 01135 new_worst: 01136 worst = neighbour; 01137 worst_acceptable = acceptable; 01138 } 01139 01140 return worst; 01141 } 01142 01143 /* Purge one item from an instance */ 01144 bool rpl_instance_purge(rpl_instance_t *instance) 01145 { 01146 /* Purge this instance itself if no remaining neighbours or DODAGs 01147 * (time restrictions on those are sufficient - no need for extra) 01148 */ 01149 if (ns_list_is_empty(&instance->candidate_neighbours) && 01150 ns_list_is_empty(&instance->dodags)) { 01151 rpl_delete_instance(instance); 01152 return true; 01153 } 01154 01155 /* May purge a DODAG if not used for some time, and no remaining neighbours */ 01156 rpl_dodag_t *dodag = rpl_instance_choose_dodag_to_purge(instance); 01157 if (dodag) { 01158 rpl_delete_dodag(dodag); 01159 return true; 01160 } 01161 01162 /* Otherwise, delete a non-parent neighbour we've considered at least once. 01163 * (We don't want to delete a new neighbour before it gets a chance to 01164 * become a new parent) 01165 */ 01166 rpl_neighbour_t *neighbour = rpl_instance_choose_worst_neighbour(instance); 01167 if (neighbour && neighbour->considered && !neighbour->dodag_parent && neighbour->dao_path_control == 0) { 01168 rpl_delete_neighbour(instance, neighbour); 01169 return true; 01170 } 01171 return false; 01172 } 01173 01174 void rpl_instance_neighbours_changed(rpl_instance_t *instance) 01175 { 01176 instance->neighbours_changed = true; 01177 if (!rpl_instance_preferred_parent(instance)) { 01178 rpl_instance_set_local_repair(instance, true); 01179 } 01180 rpl_instance_trigger_parent_selection(instance, rpl_policy_dio_parent_selection_delay(instance->domain)); 01181 } 01182 01183 static void rpl_instance_remove_parents(rpl_instance_t *instance) 01184 { 01185 ns_list_foreach(rpl_neighbour_t, n, &instance->candidate_neighbours) { 01186 n->dodag_parent = false; 01187 } 01188 } 01189 01190 /* Convert RPL lifetime (8-bit in units) to core lifetime (32-bit seconds) */ 01191 static uint32_t rpl_lifetime(uint8_t lifetime, uint16_t lifetime_unit) 01192 { 01193 return lifetime == 0xff ? 0xffffffff : lifetime * (uint32_t) lifetime_unit; 01194 } 01195 01196 static uint32_t rpl_default_lifetime(rpl_dodag_t *dodag) 01197 { 01198 return rpl_lifetime(dodag->config.default_lifetime, dodag->config.lifetime_unit); 01199 } 01200 01201 /* Adjust a lifetime (in seconds) downwards to account for its age */ 01202 static uint32_t rpl_aged_lifetime(uint32_t lifetime, uint32_t timestamp) 01203 { 01204 if (lifetime != 0xffffffff) { 01205 uint32_t age = (protocol_core_monotonic_time - timestamp) / 10; 01206 if (age < lifetime) { 01207 lifetime -= age; 01208 } else { 01209 lifetime = 0; 01210 } 01211 } 01212 return lifetime; 01213 } 01214 01215 static void rpl_instance_update_system_dio_route(rpl_instance_t *instance, rpl_neighbour_t *parent, rpl_dio_route_t *route) 01216 { 01217 int8_t pref; 01218 switch (route->flags & RA_PRF_MASK) { 01219 case RA_PRF_LOW: pref = -1; break; 01220 case RA_PRF_MEDIUM: pref = 0; break; 01221 case RA_PRF_HIGH: pref = 1; break; 01222 default: return; 01223 } 01224 01225 uint8_t metric = ipv6_route_pref_to_metric(pref) + parent->dodag_pref; 01226 01227 ipv6_route_add_metric(route->prefix, route->prefix_len, parent->interface_id, parent->ll_address, ROUTE_RPL_DIO, parent, instance->id, rpl_aged_lifetime(route->lifetime, parent->dio_timestamp), metric); 01228 } 01229 01230 /* Called when a DIO has been received */ 01231 void rpl_dodag_update_implicit_system_routes(rpl_dodag_t *dodag, rpl_neighbour_t *parent) 01232 { 01233 if (!rpl_dodag_is_current(dodag) || !parent->dodag_parent) { 01234 return; 01235 } 01236 01237 uint32_t aged_default = rpl_aged_lifetime(rpl_default_lifetime(dodag), parent->dio_timestamp); 01238 uint8_t metric = IPV6_ROUTE_DEFAULT_METRIC + parent->dodag_pref; 01239 01240 /* Always add the "root" default route - only used for per-instance lookup */ 01241 ipv6_route_add_metric(NULL, 0, parent->interface_id, parent->ll_address, ROUTE_RPL_INSTANCE, parent, dodag->instance->id, aged_default, metric); 01242 01243 /* Also add a specific route to the DODAGID */ 01244 ipv6_route_add_metric(dodag->id, 128, parent->interface_id, parent->ll_address, ROUTE_RPL_ROOT, parent, dodag->instance->id, aged_default, metric); 01245 01246 } 01247 01248 /* Called when a DIO RIO route has been updated (but not the parent list) */ 01249 static void rpl_dodag_update_system_route(rpl_dodag_t *dodag, rpl_dio_route_t *route) 01250 { 01251 if (!rpl_dodag_is_current(dodag)) { 01252 return; 01253 } 01254 01255 rpl_instance_t *instance = dodag->instance; 01256 01257 ns_list_foreach(rpl_neighbour_t, neighbour, &instance->candidate_neighbours) { 01258 if (neighbour->dodag_parent) { 01259 rpl_instance_update_system_dio_route(instance, neighbour, route); 01260 } 01261 } 01262 } 01263 01264 /* Called when a parent has been added/updated (but not the DIO route list) */ 01265 static void rpl_instance_update_system_routes_through_parent(rpl_instance_t *instance, rpl_neighbour_t *parent) 01266 { 01267 rpl_dodag_t *dodag = parent->dodag_version->dodag; 01268 01269 rpl_dodag_update_implicit_system_routes(dodag, parent); 01270 01271 /* Then add the specific routes listed in the DIO as ROUTE_RPL_DIO */ 01272 ns_list_foreach(rpl_dio_route_t, route, &dodag->routes) { 01273 rpl_instance_update_system_dio_route(instance, parent, route); 01274 } 01275 } 01276 01277 static void rpl_instance_remove_system_routes_through_parent(rpl_instance_t *instance, rpl_neighbour_t *parent) 01278 { 01279 (void)instance; 01280 01281 ipv6_route_table_remove_info(parent->interface_id, ROUTE_RPL_INSTANCE, parent); 01282 ipv6_route_table_remove_info(parent->interface_id, ROUTE_RPL_DIO, parent); 01283 ipv6_route_table_remove_info(parent->interface_id, ROUTE_RPL_ROOT, parent); 01284 } 01285 01286 static void trace_info_print(const char *fmt, ...) 01287 { 01288 va_list ap; 01289 va_start(ap, fmt); 01290 vtracef(TRACE_LEVEL_INFO, TRACE_GROUP, fmt, ap); 01291 va_end(ap); 01292 } 01293 01294 01295 void rpl_instance_run_parent_selection(rpl_instance_t *instance) 01296 { 01297 bool parent_set_change = false; 01298 rpl_dodag_version_t *original_version = instance->current_dodag_version; 01299 uint16_t original_rank = instance->current_rank; 01300 01301 instance->parent_selection_timer = rpl_policy_parent_selection_period(instance->domain); 01302 01303 if (!instance->of) { 01304 return; 01305 } 01306 01307 if (instance->current_dodag_version && instance->current_dodag_version->dodag->root) { 01308 return; 01309 } 01310 01311 ns_list_foreach_safe(rpl_neighbour_t, n, &instance->candidate_neighbours) { 01312 if (rpl_aged_lifetime(rpl_default_lifetime(n->dodag_version->dodag), n->dio_timestamp) == 0) { 01313 rpl_delete_neighbour(instance, n); 01314 continue; 01315 } 01316 n->old_dao_path_control = n->dao_path_control; 01317 n->dao_path_control = 0; 01318 n->was_dodag_parent = n->dodag_parent; 01319 n->dodag_parent = false; 01320 n->considered = true; 01321 } 01322 01323 rpl_neighbour_t *original_preferred = rpl_instance_preferred_parent(instance); 01324 01325 instance->of->parent_selection(instance); 01326 01327 ns_list_foreach(rpl_neighbour_t, n, &instance->candidate_neighbours) { 01328 if (n->was_dodag_parent != n->dodag_parent) { 01329 tr_info("%s parent %s", n->dodag_parent ? "Added" : "Removed", trace_ipv6(n->ll_address)); 01330 parent_set_change = true; 01331 /* Remove routes through a deselected parent */ 01332 if (!n->dodag_parent) { 01333 rpl_instance_remove_system_routes_through_parent(instance, n); 01334 } 01335 } 01336 /* Always re-run route update (in case of changed preference values) */ 01337 if (n->dodag_parent) { 01338 rpl_instance_update_system_routes_through_parent(instance, n); 01339 } 01340 n->was_dodag_parent = false; 01341 } 01342 01343 rpl_neighbour_t *preferred_parent = rpl_instance_preferred_parent(instance); 01344 01345 if (preferred_parent) { 01346 rpl_control_disable_ra_routes(instance->domain); 01347 } else { 01348 rpl_instance_poison(instance, rpl_policy_repair_poison_count(instance->domain)); 01349 } 01350 01351 if (original_preferred != preferred_parent) { 01352 protocol_stats_update(STATS_RPL_PARENT_CHANGE, 1); 01353 } 01354 01355 // Sets new preferred parent 01356 if (preferred_parent) { 01357 ipv6_map_ip_to_ll_and_call_ll_addr_handler(NULL, preferred_parent->interface_id, NULL, preferred_parent->ll_address, 01358 protocol_6lowpan_neighbor_priority_set); 01359 // Sets secondary parent 01360 rpl_neighbour_t *sec_parent = ns_list_get_next(&instance->candidate_neighbours, preferred_parent); 01361 if (sec_parent && sec_parent->dodag_parent) { 01362 ipv6_map_ip_to_ll_and_call_ll_addr_handler(NULL, sec_parent->interface_id, NULL, sec_parent->ll_address, 01363 protocol_6lowpan_neighbor_second_priority_set); 01364 } else { 01365 protocol_6lowpan_neighbor_priority_clear_all(preferred_parent->interface_id, PRIORITY_2ND); 01366 } 01367 } 01368 01369 rpl_instance_set_local_repair(instance, preferred_parent == NULL); 01370 01371 if (rpl_instance_mop(instance) != RPL_MODE_NO_DOWNWARD) { 01372 rpl_downward_process_dao_parent_changes(instance); 01373 } 01374 01375 /* Anyone who's not a parent can be pruned now (eg bad link cost) */ 01376 ns_list_foreach_safe(rpl_neighbour_t, n, &instance->candidate_neighbours) { 01377 if (n->dodag_parent) { 01378 continue; 01379 } 01380 if (!instance->of->neighbour_acceptable(instance, n)) { 01381 rpl_delete_neighbour(instance, n); 01382 } 01383 } 01384 rpl_control_print(trace_info_print); 01385 /* Changing DODAG version is an inconsistency */ 01386 if (original_version != instance->current_dodag_version) { 01387 rpl_instance_inconsistency(instance); 01388 return; 01389 } 01390 01391 /* Check for "consistent" indication as per RFC 6550 8.3 - if not 01392 * "consistent" by this definition, we reset Trickle consistency counter, 01393 * and do not process any more consistency events this interval. 01394 * See comments in rpl_control_dio_handler() for more info. 01395 */ 01396 if (parent_set_change || 01397 original_preferred != preferred_parent || 01398 !(instance->current_dodag_version && 01399 (rpl_rank_compare(instance->current_dodag_version->dodag, original_rank, instance->current_rank) & RPL_CMP_EQUAL))) { 01400 instance->dio_not_consistent = true; 01401 instance->dio_timer.c = 0; 01402 } 01403 } 01404 01405 void rpl_instance_remove_interface(rpl_instance_t *instance, int8_t if_id) 01406 { 01407 ns_list_foreach_safe(rpl_neighbour_t, neighbour, &instance->candidate_neighbours) { 01408 if (neighbour->interface_id == if_id) { 01409 rpl_delete_neighbour(instance, neighbour); 01410 } 01411 } 01412 } 01413 01414 /* Trigger DIO transmission - all interfaces multicast if addr+cur are NULL, else unicast */ 01415 void rpl_instance_dio_trigger(rpl_instance_t *instance, protocol_interface_info_entry_t *cur, const uint8_t *addr) 01416 { 01417 uint16_t rank = instance->current_rank; 01418 rpl_dodag_version_t *dodag_version = instance->current_dodag_version; 01419 rpl_dodag_t *dodag; 01420 if (dodag_version) { 01421 dodag = dodag_version->dodag; 01422 } else if (instance->poison_count) { 01423 /* When poisoning, we can send using data from an arbitrary DODAG/version */ 01424 dodag = ns_list_get_first(&instance->dodags); 01425 if (dodag) { 01426 dodag_version = ns_list_get_first(&dodag->versions); 01427 } 01428 } else { 01429 dodag = NULL; 01430 } 01431 01432 if (!dodag || !dodag_version) { 01433 return; 01434 } 01435 01436 if (instance->poison_count) { 01437 instance->poison_count--; 01438 rank = RPL_RANK_INFINITE; 01439 tr_debug("Poison count -> set RPL_RANK_INFINITE"); 01440 } 01441 01442 // Always send config in unicasts (as required), never in multicasts (optional) 01443 rpl_dodag_conf_t *conf = addr ? &dodag->config : NULL; 01444 01445 rpl_control_transmit_dio(instance->domain, cur, instance->id, dodag_version->number, rank, dodag->g_mop_prf, instance->dtsn, dodag, dodag->id, conf, addr); 01446 01447 dodag_version->last_advertised_rank = rank; 01448 01449 /* When we advertise a new lowest rank, need to re-evaluate our rank limits */ 01450 if (rank < dodag_version->lowest_advertised_rank) { 01451 dodag_version->lowest_advertised_rank = rank; 01452 dodag_version->hard_rank_limit = rpl_rank_add(rank, dodag->config.dag_max_rank_increase); 01453 } 01454 rpl_dodag_version_limit_greediness(dodag_version, rank); 01455 01456 instance->last_advertised_dodag_version = dodag_version; 01457 } 01458 01459 static void rpl_instance_dis_timer(rpl_instance_t *instance, uint16_t seconds) 01460 { 01461 if (instance->repair_dis_timer > seconds) { 01462 instance->repair_dis_timer -= seconds; 01463 } else if (instance->repair_dis_timer != 0){ 01464 tr_debug("Timed repair DIS %d", instance->id); 01465 instance->repair_dis_timer = 0; 01466 instance->repair_dis_count++; 01467 rpl_control_transmit_dis(instance->domain, NULL, RPL_SOLINFO_PRED_INSTANCEID, instance->id, NULL, 0, NULL); 01468 if (instance->repair_dis_count < rpl_policy_repair_dis_count(instance->domain)) { 01469 uint16_t t = rpl_policy_repair_initial_dis_delay(instance->domain); 01470 uint16_t max = rpl_policy_repair_maximum_dis_interval(instance->domain); 01471 for (uint_fast8_t n = instance->repair_dis_count; n; n--) { 01472 if (t < 0x8000 && t < max) { 01473 t <<= 1; 01474 } else { 01475 t = max; 01476 break; 01477 } 01478 } 01479 if (t > max) { 01480 t = max; 01481 } 01482 instance->repair_dis_timer = t; 01483 } else { 01484 rpl_control_event(instance->domain, RPL_EVENT_LOCAL_REPAIR_NO_MORE_DIS); 01485 } 01486 } 01487 } 01488 01489 void rpl_instance_set_local_repair(rpl_instance_t *instance, bool repair) 01490 { 01491 if (instance->local_repair == repair) { 01492 return; 01493 } 01494 01495 instance->local_repair = repair; 01496 01497 if (repair) { 01498 /* Notify RPL user to state switch */ 01499 rpl_control_event(instance->domain, RPL_EVENT_LOCAL_REPAIR_START); 01500 protocol_stats_update(STATS_RPL_LOCAL_REPAIR, 1); 01501 instance->repair_dis_timer = rpl_policy_repair_initial_dis_delay(instance->domain); 01502 instance->repair_dis_count = 0; 01503 } else { 01504 instance->repair_dis_timer = 0; 01505 } 01506 01507 /* When repair ends, eliminate all higher-rank neighbours (potential sub-DODAG) from table */ 01508 if (!repair && instance->current_dodag_version) { 01509 ns_list_foreach_safe(rpl_neighbour_t, neighbour, &instance->candidate_neighbours) { 01510 if (rpl_dodag_version_rank_indicates_possible_sub_dodag(neighbour->dodag_version, neighbour->rank)) { 01511 rpl_delete_neighbour(instance, neighbour); 01512 } 01513 } 01514 } 01515 } 01516 01517 bool rpl_instance_local_repair(const rpl_instance_t *instance) 01518 { 01519 return instance->local_repair; 01520 } 01521 01522 uint16_t rpl_instance_current_rank(const rpl_instance_t *instance) 01523 { 01524 return instance->current_rank; 01525 } 01526 01527 void rpl_instance_slow_timer(rpl_instance_t *instance, uint16_t seconds) 01528 { 01529 ns_list_foreach(rpl_dodag_t, dodag, &instance->dodags) { 01530 rpl_dodag_slow_timer(dodag, seconds); 01531 } 01532 rpl_instance_parent_selection_timer(instance, seconds); 01533 if (!rpl_instance_preferred_parent(instance)) { 01534 protocol_stats_update(STATS_RPL_TIME_NO_NEXT_HOP, 1); 01535 rpl_instance_dis_timer(instance, seconds); 01536 } 01537 } 01538 01539 void rpl_upward_dio_timer(rpl_instance_t *instance, uint16_t ticks) 01540 { 01541 rpl_dodag_version_t *dodag_version = instance->current_dodag_version; 01542 rpl_dodag_t *dodag; 01543 if (dodag_version) { 01544 dodag = dodag_version->dodag; 01545 } else if (instance->poison_count) { 01546 /* When poisoning, we can send using data from an arbitrary DODAG/version */ 01547 dodag = ns_list_get_first(&instance->dodags); 01548 if (dodag) { 01549 dodag_version = ns_list_get_first(&dodag->versions); 01550 } 01551 } else { 01552 dodag = NULL; 01553 } 01554 01555 if (!dodag || !dodag_version) { 01556 return; 01557 } 01558 01559 /* Leaves don't send normal periodic DIOs */ 01560 if (rpl_dodag_am_leaf(dodag) && !instance->poison_count) { 01561 return; 01562 } 01563 if (trickle_timer(&instance->dio_timer, &dodag->dio_timer_params, ticks)) { 01564 instance->dio_not_consistent = false; 01565 rpl_instance_dio_trigger(instance, NULL, NULL); 01566 } 01567 } 01568 01569 void rpl_upward_print_neighbour(const rpl_neighbour_t *neighbour, route_print_fn_t *print_fn) 01570 { 01571 uint16_t path_cost; 01572 if (neighbour->dodag_version->dodag->instance->of) { 01573 path_cost = neighbour->dodag_version->dodag->instance->of->path_cost(neighbour); 01574 } else { 01575 path_cost = 0xFFFF; 01576 } 01577 01578 ROUTE_PRINT_ADDR_STR_BUFFER_INIT(addr_str_ll); 01579 ROUTE_PRINT_ADDR_STR_BUFFER_INIT(addr_str_global); 01580 print_fn(" %2.0d%c%04x %04x %02x %s%%%d (%s)", 01581 neighbour->dodag_parent ? neighbour->dodag_pref + 1 : 0, 01582 neighbour->dodag_version && rpl_instance_preferred_parent(neighbour->dodag_version->dodag->instance) == neighbour ? '*' : ' ', 01583 neighbour->rank, 01584 path_cost, 01585 neighbour->dao_path_control, 01586 ROUTE_PRINT_ADDR_STR_FORMAT(addr_str_ll, neighbour->ll_address), neighbour->interface_id, 01587 ROUTE_PRINT_ADDR_STR_FORMAT(addr_str_global, neighbour->global_address)); 01588 } 01589 01590 void rpl_upward_print_neighbours_in_version(const rpl_neighbour_list_t *list, const rpl_dodag_version_t *version, route_print_fn_t *print_fn) 01591 { 01592 ns_list_foreach(rpl_neighbour_t, neighbour, list) { 01593 if (neighbour->dodag_version == version) { 01594 rpl_upward_print_neighbour(neighbour, print_fn); 01595 } 01596 } 01597 } 01598 01599 void rpl_upward_print_dodag(rpl_instance_t *instance, rpl_dodag_t *dodag, route_print_fn_t *print_fn) 01600 { 01601 /* Summary */ 01602 ROUTE_PRINT_ADDR_STR_BUFFER_INIT(addr_str); 01603 print_fn("DODAG %s", ROUTE_PRINT_ADDR_STR_FORMAT(addr_str, dodag->id)); 01604 print_fn(" G=%d MOP=%d Prf=%d", dodag->g_mop_prf & RPL_GROUNDED ? 1 : 0, 01605 (dodag->g_mop_prf & RPL_MODE_MASK) >> RPL_MODE_SHIFT, 01606 (dodag->g_mop_prf & RPL_DODAG_PREF_MASK)); 01607 /* Routes */ 01608 ns_list_foreach(rpl_dio_route_t, route, &dodag->routes) { 01609 uint8_t addr[16] = { 0 } ; 01610 int_fast8_t pref; 01611 switch (route->flags & RA_PRF_MASK) { 01612 case RA_PRF_LOW: pref = -1; break; 01613 case RA_PRF_MEDIUM: pref = 0; break; 01614 case RA_PRF_HIGH: pref = 1; break; 01615 default: pref = 2; break; 01616 } 01617 bitcopy(addr, route->prefix, route->prefix_len); 01618 if (route->lifetime == 0xFFFFFFFF) { 01619 print_fn("%24s/%-3u lifetime:infinite pref:%"PRIdFAST8, 01620 ROUTE_PRINT_ADDR_STR_FORMAT(addr_str, addr), route->prefix_len, pref); 01621 01622 } else { 01623 print_fn("%24s/%-3u lifetime:%"PRIu32" pref:%"PRIdFAST8, 01624 ROUTE_PRINT_ADDR_STR_FORMAT(addr_str, addr), route->prefix_len, route->lifetime, pref); 01625 } 01626 } 01627 /* Prefixes */ 01628 ns_list_foreach(prefix_entry_t, prefix, &dodag->prefixes) { 01629 uint8_t addr[16] = { 0 } ; 01630 bitcopy(addr, prefix->prefix, prefix->prefix_len); 01631 if (prefix->lifetime == 0xFFFFFFFF) { 01632 print_fn("%24s/%-3u lifetime:infinite flags:%c%c%c", 01633 ROUTE_PRINT_ADDR_STR_FORMAT(addr_str, addr), prefix->prefix_len, 01634 prefix->options & PIO_L ? 'L' : '-', 01635 prefix->options & PIO_A ? 'A' : '-', 01636 prefix->options & RPL_PIO_PUBLISHED ? '*' : ' ' 01637 ); 01638 } else { 01639 print_fn("%24s/%-3u lifetime:%"PRIu32" flags:%c%c%c", 01640 ROUTE_PRINT_ADDR_STR_FORMAT(addr_str, addr), prefix->prefix_len, prefix->lifetime, 01641 prefix->options & PIO_L ? 'L' : '-', 01642 prefix->options & PIO_A ? 'A' : '-', 01643 prefix->options & RPL_PIO_PUBLISHED ? '*' : ' ' 01644 ); 01645 } 01646 } 01647 /* Versions */ 01648 ns_list_foreach(rpl_dodag_version_t, version, &dodag->versions) { 01649 print_fn(" Version %d", version->number); 01650 if (version == instance->current_dodag_version) { 01651 print_fn (" *Current version* Rank=%04x", instance->current_rank); 01652 } 01653 rpl_upward_print_neighbours_in_version(&instance->candidate_neighbours, version, print_fn); 01654 } 01655 } 01656 01657 void rpl_upward_print_instance(rpl_instance_t *instance, route_print_fn_t *print_fn) 01658 { 01659 print_fn("RPL Instance %d", instance->id); 01660 print_fn("---------------"); 01661 ns_list_foreach(rpl_dodag_t, dodag, &instance->dodags) { 01662 rpl_upward_print_dodag(instance, dodag, print_fn); 01663 } 01664 if (instance->current_dodag_version) { 01665 const trickle_params_t *params = &instance->current_dodag_version->dodag->dio_timer_params; 01666 const trickle_t *timer = &instance->dio_timer; 01667 01668 print_fn("DIO trickle Imin=%d, Imax=%d, k=%d", params->Imin, params->Imax, params->k); 01669 print_fn(" I=%d, now=%d, t=%d, c=%d", timer->I, timer->now, timer->t, timer->c); 01670 } 01671 } 01672 01673 uint16_t rpl_upward_read_dao_target_list_size(const rpl_instance_t *instance) 01674 { 01675 return ns_list_count(&instance->dao_targets); 01676 } 01677 01678 /* Backwards-compatibility implementation of net_rpl.h API designed for old implementation */ 01679 bool rpl_upward_read_dodag_info(const rpl_instance_t *instance, rpl_dodag_info_t *dodag_info) 01680 { 01681 rpl_dodag_version_t *version = rpl_instance_current_dodag_version(instance); 01682 if (!version) { 01683 return false; 01684 } 01685 01686 rpl_dodag_t *dodag = version->dodag; 01687 01688 memcpy(dodag_info->dodag_id, dodag->id, 16); 01689 dodag_info->instance_id = instance->id; 01690 dodag_info->flags = dodag->g_mop_prf; 01691 dodag_info->version_num = version->number; 01692 dodag_info->DTSN = instance->dtsn; 01693 dodag_info->curent_rank = instance->current_rank; 01694 dodag_info->parent_flags = 0; 01695 dodag_info->dag_min_hop_rank_inc = dodag->config.min_hop_rank_increase; 01696 01697 rpl_neighbour_t *pref_parent = rpl_instance_preferred_parent(instance); 01698 if (!pref_parent) { 01699 return true; 01700 } 01701 01702 dodag_info->parent_flags |= RPL_PRIMARY_PARENT_SET; 01703 memcpy(dodag_info->primary_parent, 01704 pref_parent->have_global_address ? pref_parent->global_address 01705 : pref_parent->ll_address, 01706 16); 01707 dodag_info->primary_parent_rank = pref_parent->rank; 01708 01709 rpl_neighbour_t *sec_parent = ns_list_get_next(&instance->candidate_neighbours, pref_parent); 01710 if (!sec_parent || !sec_parent->dodag_parent) { 01711 return true; 01712 } 01713 01714 dodag_info->parent_flags |= RPL_SECONDARY_PARENT_SET; 01715 memcpy(dodag_info->secondary_parent, 01716 sec_parent->have_global_address ? sec_parent->global_address 01717 : sec_parent->ll_address, 01718 16); 01719 dodag_info->secondary_parent_rank = sec_parent->rank; 01720 01721 return true; 01722 } 01723 01724 #endif /* HAVE_RPL */
Generated on Tue Aug 9 2022 00:37:18 by
1.7.2