Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: TYBLE16_simple_data_logger TYBLE16_MP3_Air
rpl_control.c
00001 /* 00002 * Copyright (c) 2015-2019, 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_control.c deals with packet handling, and management of domains. The 00019 * workings of individual instances are dealt elsewhere. 00020 * 00021 * rpl_domain_t is accessible. 00022 * rpl_instance_t, rpl_dodag_t, rpl_dodag_version_t, rpl_neighbout_t are all opaque 00023 */ 00024 00025 /* 00026 * State machine still not fully developed - we're basically free-running, 00027 * with a simple kick to advance the bootstrap when we first get a DAO-ACK 00028 * on any instance. 00029 * 00030 * A larger set of events is needed, including some sort of policy interaction 00031 * to establish which instances "count" for triggering an overall system (or 00032 * domain) state machine. 00033 */ 00034 #include "nsconfig.h" 00035 00036 #ifdef HAVE_RPL 00037 00038 #include <string.h> 00039 #include "ns_trace.h" 00040 #include "common_functions.h" 00041 #include "nsdynmemLIB.h" 00042 00043 #include "Core/include/ns_buffer.h" 00044 #include "NWK_INTERFACE/Include/protocol.h" 00045 #include "NWK_INTERFACE/Include/protocol_stats.h" 00046 #include "Common_Protocols/ipv6_constants.h" 00047 #include "Common_Protocols/icmpv6.h" 00048 #include "ipv6_stack/protocol_ipv6.h" 00049 #include "Service_Libs/etx/etx.h" /* slight ick */ 00050 00051 #include "net_rpl.h" 00052 #include "RPL/rpl_protocol.h" 00053 #include "RPL/rpl_upward.h" 00054 #include "RPL/rpl_downward.h" 00055 #include "RPL/rpl_policy.h" 00056 #include "RPL/rpl_control.h" 00057 00058 #define TRACE_GROUP "rplc" 00059 00060 const uint8_t ADDR_LINK_LOCAL_ALL_RPL_NODES[16] = { 0xff, 0x02, [15] = 0x1a }; 00061 00062 /* Sensible default limits for a 6LoWPAN-ND node */ 00063 static size_t rpl_purge_threshold = 1 * 1024; 00064 static size_t rpl_alloc_limit = 2 * 1024; // 0 means no limit 00065 00066 static size_t rpl_alloc_total; 00067 #define RPL_ALLOC_OVERHEAD 8 00068 00069 static NS_LIST_DEFINE(rpl_domains, rpl_domain_t, link); 00070 00071 void rpl_control_set_memory_limits(size_t soft_limit, size_t hard_limit) 00072 { 00073 rpl_purge_threshold = soft_limit; 00074 rpl_alloc_limit = hard_limit; 00075 } 00076 00077 /* Send all RPL allocations through central point - gives a way of counting and 00078 * limiting RPL allocations. Allocation rejected if total would go above the 00079 * hard limit rpl_alloc_limit. This should normally be avoided by the timers 00080 * trying to keep allocations below the soft limit rpl_purge_threshold. 00081 */ 00082 void *rpl_realloc(void *p, uint16_t old_size, uint16_t new_size) 00083 { 00084 if (old_size == new_size) { 00085 return p; 00086 } 00087 00088 /* If increasing memory, check if we're going above the hard limit */ 00089 if (rpl_alloc_limit != 0 && new_size > old_size) { 00090 uint16_t size_diff = p ? new_size - old_size : new_size + RPL_ALLOC_OVERHEAD; 00091 00092 if (rpl_alloc_total + size_diff > rpl_alloc_limit) { 00093 protocol_stats_update(STATS_RPL_MEMORY_OVERFLOW, size_diff); 00094 return NULL; 00095 } 00096 } 00097 void *n = ns_dyn_mem_alloc(new_size); 00098 if (n) { 00099 /* rpl_free() below will subtract (old_size + RPL_ALLOC_OVERHEAD) if reallocing */ 00100 rpl_alloc_total += (size_t) new_size + RPL_ALLOC_OVERHEAD; 00101 protocol_stats_update(STATS_RPL_MEMORY_ALLOC, new_size); 00102 if (p) { 00103 memcpy(n, p, old_size < new_size ? old_size : new_size); 00104 } 00105 } else { 00106 protocol_stats_update(STATS_RPL_MEMORY_OVERFLOW, new_size); 00107 } 00108 rpl_free(p, old_size); 00109 return n; 00110 } 00111 00112 void *rpl_alloc(uint16_t size) 00113 { 00114 return rpl_realloc(NULL, 0, size); 00115 } 00116 00117 void rpl_free(void *p, uint16_t size) 00118 { 00119 if (p) { 00120 rpl_alloc_total -= (size_t) size + RPL_ALLOC_OVERHEAD; 00121 protocol_stats_update(STATS_RPL_MEMORY_FREE, size); 00122 } 00123 ns_dyn_mem_free(p); 00124 } 00125 00126 void rpl_control_event(struct rpl_domain *domain, rpl_event_t event) 00127 { 00128 if (domain->callback) { 00129 domain->callback(event, domain->cb_handle); 00130 } 00131 } 00132 00133 00134 /* When we join a new instance, we need to publish existing addresses. 00135 * Later addresses additions/removals are handled by rpl_control_addr_notifier. 00136 */ 00137 static void rpl_control_publish_own_addresses(rpl_domain_t *domain, rpl_instance_t *instance) 00138 { 00139 int8_t last_id = -1; 00140 protocol_interface_info_entry_t *cur; 00141 while ((cur = protocol_stack_interface_info_get_by_rpl_domain(domain, last_id)) != NULL) { 00142 ns_list_foreach(if_address_entry_t, addr, &cur->ip_addresses) { 00143 if (!addr->tentative && !addr_is_ipv6_link_local(addr->address)) { 00144 /* TODO - wouldn't need to publish address if within a prefix published by parent */ 00145 uint32_t descriptor = 0; 00146 bool want_descriptor = rpl_policy_target_descriptor_for_own_address(domain, addr->address, addr->source, addr->data, &descriptor); 00147 rpl_instance_publish_dao_target(instance, addr->address, 128, addr->valid_lifetime, true, want_descriptor, descriptor); 00148 } 00149 } 00150 last_id = cur->id; 00151 } 00152 } 00153 00154 void rpl_control_publish_host_address(rpl_domain_t *domain, const uint8_t addr[16], uint32_t lifetime) 00155 { 00156 ns_list_foreach(rpl_instance_t, instance, &domain->instances) { 00157 if (!rpl_instance_am_root(instance)) { 00158 /* TODO - Wouldn't need to publish host address if within a published prefix */ 00159 uint32_t descriptor = 0; 00160 bool want_descriptor = rpl_policy_target_descriptor_for_host_address(domain, addr, &descriptor); 00161 rpl_instance_publish_dao_target(instance, addr, 128, lifetime, false, want_descriptor, descriptor); 00162 } 00163 } 00164 } 00165 00166 /* Is unpublish a word? */ 00167 void rpl_control_unpublish_address(rpl_domain_t *domain, const uint8_t addr[16]) 00168 { 00169 ns_list_foreach(rpl_instance_t, instance, &domain->instances) { 00170 rpl_instance_delete_published_dao_target(instance, addr, 128); 00171 } 00172 } 00173 00174 void rpl_control_request_parent_link_confirmation(bool requested) 00175 { 00176 rpl_policy_set_parent_confirmation_request(requested); 00177 } 00178 00179 void rpl_control_set_dio_multicast_min_config_advertisment_count(uint8_t min_count) 00180 { 00181 rpl_policy_set_dio_multicast_config_advertisment_min_count(min_count); 00182 } 00183 00184 void rpl_control_set_dao_retry_count(uint8_t count) 00185 { 00186 rpl_policy_set_dao_retry_count(count); 00187 } 00188 00189 void rpl_control_set_initial_dao_ack_wait(uint16_t timeout_in_ms) 00190 { 00191 rpl_policy_set_initial_dao_ack_wait(timeout_in_ms); 00192 } 00193 00194 /* Send address registration to either specified address, or to non-registered address */ 00195 void rpl_control_register_address(protocol_interface_info_entry_t *interface, const uint8_t addr[16]) 00196 { 00197 if (!rpl_policy_parent_confirmation_requested()) { 00198 return; 00199 } 00200 ns_list_foreach(struct rpl_instance, instance, &interface->rpl_domain->instances) { 00201 rpl_instance_send_address_registration(instance, addr); 00202 } 00203 } 00204 00205 void rpl_control_address_register_done(protocol_interface_info_entry_t *interface, const uint8_t ll_addr[16], uint8_t status) 00206 { 00207 if (!interface->rpl_domain) { 00208 return; 00209 } 00210 if (!rpl_policy_parent_confirmation_requested()) { 00211 return; 00212 } 00213 00214 ns_list_foreach(struct rpl_instance, instance, &interface->rpl_domain->instances) { 00215 rpl_neighbour_t *neighbour = rpl_lookup_neighbour_by_ll_address(instance, ll_addr, interface->id); 00216 if (neighbour) { 00217 rpl_instance_address_registration_done(interface, instance, neighbour, status); 00218 } 00219 } 00220 } 00221 00222 bool rpl_control_is_dodag_parent(protocol_interface_info_entry_t *interface, const uint8_t ll_addr[16]) 00223 { 00224 if (!interface->rpl_domain) { 00225 return false; 00226 } 00227 // go through instances and parents and check if they match the address. 00228 ns_list_foreach(struct rpl_instance, instance, &interface->rpl_domain->instances) { 00229 if (rpl_instance_address_is_parent(instance, ll_addr)) { 00230 return true; 00231 } 00232 } 00233 return false; 00234 } 00235 00236 bool rpl_control_is_dodag_parent_candidate(protocol_interface_info_entry_t *interface, const uint8_t ll_addr[16], uint16_t candidate_cmp_limiter) 00237 { 00238 if (!interface->rpl_domain) { 00239 return false; 00240 } 00241 // go through instances and parents and check if they match the address. 00242 ns_list_foreach(struct rpl_instance, instance, &interface->rpl_domain->instances) { 00243 if (rpl_instance_address_is_candidate(instance, ll_addr, candidate_cmp_limiter)) { 00244 return true; 00245 } 00246 } 00247 return false; 00248 } 00249 00250 00251 uint16_t rpl_control_parent_candidate_list_size(protocol_interface_info_entry_t *interface, bool parent_list) 00252 { 00253 if (!interface->rpl_domain) { 00254 return 0; 00255 } 00256 00257 uint16_t parent_list_size = 0; 00258 00259 // go through instances and parents and check if they match the address. 00260 ns_list_foreach(struct rpl_instance, instance, &interface->rpl_domain->instances) { 00261 uint16_t current_size = rpl_instance_address_candidate_count(instance, parent_list); 00262 if (current_size > parent_list_size) { 00263 parent_list_size = current_size; 00264 } 00265 } 00266 return parent_list_size; 00267 } 00268 00269 00270 void rpl_control_neighbor_delete(protocol_interface_info_entry_t *interface, const uint8_t ll_addr[16]) 00271 { 00272 if (!interface->rpl_domain) { 00273 return; 00274 } 00275 // go through instances and delete address. 00276 ns_list_foreach(struct rpl_instance, instance, &interface->rpl_domain->instances) { 00277 00278 rpl_neighbour_t *neighbour = rpl_lookup_neighbour_by_ll_address(instance, ll_addr, interface->id); 00279 if (neighbour) { 00280 rpl_delete_neighbour(instance, neighbour); 00281 } 00282 } 00283 } 00284 00285 /* Address changes need to trigger DAO target re-evaluation */ 00286 static void rpl_control_addr_notifier(struct protocol_interface_info_entry *interface, const if_address_entry_t *addr, if_address_callback_t reason) 00287 { 00288 /* Don't care about link-local addresses */ 00289 if (addr_is_ipv6_link_local(addr->address)) { 00290 return; 00291 } 00292 00293 /* Only publish addresses on the domain attached to their interface */ 00294 if (!interface->rpl_domain) { 00295 return; 00296 } 00297 00298 switch (reason) { 00299 case ADDR_CALLBACK_DELETED: 00300 rpl_control_unpublish_address(interface->rpl_domain, addr->address); 00301 break; 00302 default: 00303 break; 00304 00305 } 00306 } 00307 00308 static void rpl_control_etx_change_callback(int8_t nwk_id, uint16_t previous_etx, uint16_t current_etx, uint8_t attribute_index) 00309 { 00310 (void)previous_etx; 00311 (void)current_etx; 00312 00313 protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(nwk_id); 00314 if (!cur || !cur->rpl_domain) { 00315 return; 00316 } 00317 rpl_domain_t *domain = cur->rpl_domain; 00318 uint16_t delay = rpl_policy_etx_change_parent_selection_delay(domain); 00319 tr_debug("Triggering parent selection due to ETX change on neigh index %u, etx %u", attribute_index, current_etx); 00320 00321 ns_list_foreach(rpl_instance_t, instance, &domain->instances) { 00322 rpl_instance_trigger_parent_selection(instance, delay); 00323 if (rpl_instance_am_root(instance)) { 00324 rpl_downward_paths_invalidate(instance); 00325 } 00326 } 00327 } 00328 00329 /* Create a RPL domain - it can be associated with one or more interfaces */ 00330 rpl_domain_t *rpl_control_create_domain(void) 00331 { 00332 rpl_domain_t *domain = rpl_alloc(sizeof(rpl_domain_t)); 00333 if (!domain) { 00334 return NULL; 00335 } 00336 00337 ns_list_init(&domain->instances); 00338 domain->non_storing_downstream_interface = -1; 00339 domain->callback = NULL; 00340 domain->cb_handle = NULL; 00341 domain->force_leaf = false; 00342 ns_list_add_to_start(&rpl_domains, domain); 00343 00344 addr_notification_register(rpl_control_addr_notifier); 00345 00346 return domain; 00347 } 00348 00349 void rpl_control_delete_domain(rpl_domain_t *domain) 00350 { 00351 ns_list_foreach_safe(rpl_instance_t, instance, &domain->instances) { 00352 rpl_delete_instance(instance); 00353 } 00354 ns_list_remove(&rpl_domains, domain); 00355 rpl_free(domain, sizeof * domain); 00356 } 00357 00358 static void rpl_control_remove_interface_from_domain(protocol_interface_info_entry_t *cur, rpl_domain_t *domain, bool free_instances) 00359 { 00360 ns_list_foreach(rpl_instance_t, instance, &domain->instances) { 00361 rpl_instance_remove_interface(instance, cur->id); 00362 } 00363 00364 ns_list_foreach(if_address_entry_t, addr, &cur->ip_addresses) { 00365 if (!addr_is_ipv6_link_local(addr->address)) { 00366 rpl_control_unpublish_address(domain, addr->address); 00367 } 00368 } 00369 00370 if (free_instances) { 00371 ns_list_foreach_safe(rpl_instance_t, instance, &domain->instances) { 00372 rpl_delete_instance(instance); 00373 } 00374 } 00375 00376 if (domain->non_storing_downstream_interface == cur->id) { 00377 domain->non_storing_downstream_interface = -1; 00378 } 00379 } 00380 00381 void rpl_control_set_domain_on_interface(protocol_interface_info_entry_t *cur, rpl_domain_t *domain, bool downstream) 00382 { 00383 if (cur->rpl_domain != domain) { 00384 rpl_control_remove_domain_from_interface(cur); 00385 cur->rpl_domain = domain; 00386 addr_add_group(cur, ADDR_LINK_LOCAL_ALL_RPL_NODES); 00387 } 00388 00389 if (downstream) { 00390 domain->non_storing_downstream_interface = cur->id; 00391 } 00392 /* This is a bit icky - why assume that our Objective Functions use ETX? */ 00393 /* But this is the easiest place to add an interface registration */ 00394 etx_value_change_callback_register(cur->nwk_id, cur->id, rpl_policy_etx_hysteresis(domain), rpl_control_etx_change_callback); 00395 } 00396 00397 void rpl_control_remove_domain_from_interface(protocol_interface_info_entry_t *cur) 00398 { 00399 if (cur->rpl_domain) { 00400 rpl_control_remove_interface_from_domain(cur, cur->rpl_domain, false); 00401 addr_delete_group(cur, ADDR_LINK_LOCAL_ALL_RPL_NODES); 00402 cur->rpl_domain = NULL; 00403 } 00404 } 00405 00406 void rpl_control_free_domain_instances_from_interface(protocol_interface_info_entry_t *cur) 00407 { 00408 if (cur->rpl_domain) { 00409 rpl_control_remove_interface_from_domain(cur, cur->rpl_domain, true); 00410 addr_delete_group(cur, ADDR_LINK_LOCAL_ALL_RPL_NODES); 00411 cur->rpl_domain = NULL; 00412 } 00413 } 00414 00415 void rpl_control_set_callback(rpl_domain_t *domain, rpl_domain_callback_t callback, rpl_prefix_callback_t prefix_learn_cb, rpl_new_parent_callback_t new_parent_add, void *cb_handle) 00416 { 00417 domain->callback = callback; 00418 domain->prefix_cb = prefix_learn_cb; 00419 domain->cb_handle = cb_handle; 00420 domain->new_parent_add = new_parent_add; 00421 } 00422 00423 /* To do - this should live somewhere nicer. Basically a bootstrap 00424 * thing to stop being a host as soon as we get our first RPL parent 00425 * (any instance?) 00426 */ 00427 void rpl_control_disable_ra_routes(struct rpl_domain *domain) 00428 { 00429 int8_t last_id = -1; 00430 protocol_interface_info_entry_t *cur; 00431 while ((cur = protocol_stack_interface_info_get_by_rpl_domain(domain, last_id)) != NULL) { 00432 icmpv6_recv_ra_routes(cur, false); 00433 last_id = cur->id; 00434 } 00435 } 00436 00437 bool rpl_control_have_dodag(rpl_domain_t *domain) 00438 { 00439 ns_list_foreach(rpl_instance_t, instance, &domain->instances) { 00440 if (rpl_instance_current_dodag(instance)) { 00441 return true; 00442 } 00443 } 00444 return false; 00445 } 00446 00447 typedef void rpl_control_predicate_loop_fn_t(rpl_instance_t *instance, rpl_dodag_version_t *version, void *arg); 00448 00449 /* Callbacks for rpl_control_predicate_loop */ 00450 00451 static void rpl_loopfn_reset_dio_timer(rpl_instance_t *instance, rpl_dodag_version_t *dodag_version, void *handle) 00452 { 00453 (void)dodag_version; 00454 (void)handle; 00455 00456 rpl_instance_inconsistency(instance); 00457 } 00458 00459 typedef struct rpl_loopfn_trigger_unicast_dio_arg { 00460 struct protocol_interface_info_entry *interface; 00461 const uint8_t *dst; 00462 } rpl_loopfn_trigger_unicast_dio_arg_t; 00463 00464 static void rpl_loopfn_trigger_unicast_dio(rpl_instance_t *instance, rpl_dodag_version_t *dodag_version, void *handle) 00465 { 00466 (void)dodag_version; 00467 00468 rpl_loopfn_trigger_unicast_dio_arg_t *arg = handle; 00469 rpl_instance_dio_trigger(instance, arg->interface, arg->dst); 00470 } 00471 00472 /* For each DODAG Version we're a member of, matching the predicates, call the 00473 * provided function. Mainly used for handling DODAG Information Solicitations. 00474 */ 00475 static void rpl_control_predicate_loop(rpl_domain_t *domain, rpl_control_predicate_loop_fn_t *fn, void *fn_arg, uint8_t pred, uint8_t instance_id, const uint8_t *dodagid, uint8_t version_num) 00476 { 00477 ns_list_foreach(rpl_instance_t, instance, &domain->instances) { 00478 rpl_dodag_version_t *version = rpl_instance_predicate_match(instance, pred, instance_id, dodagid, version_num); 00479 if (version) { 00480 fn(instance, version, fn_arg); 00481 } 00482 } 00483 } 00484 00485 /* Manipulation of roots */ 00486 rpl_dodag_t *rpl_control_create_dodag_root(rpl_domain_t *domain, uint8_t instance_id, const uint8_t *dodagid, const rpl_dodag_conf_t *conf, uint16_t rank, uint8_t g_mop_prf) 00487 { 00488 rpl_instance_t *instance = rpl_lookup_instance(domain, instance_id, dodagid); 00489 if (!instance) { 00490 instance = rpl_create_instance(domain, instance_id); 00491 if (!instance) { 00492 return NULL; 00493 } 00494 } 00495 00496 rpl_dodag_t *dodag = rpl_lookup_dodag(instance, dodagid); 00497 if (dodag) { 00498 tr_error("Root DODAG already exists"); 00499 return NULL; 00500 } 00501 dodag = rpl_create_dodag(instance, dodagid, g_mop_prf); 00502 if (!dodag) { 00503 tr_error("No mem for DODAG root"); 00504 return NULL; 00505 } 00506 00507 rpl_dodag_update_config(dodag, conf, NULL, NULL); 00508 rpl_dodag_set_root(dodag, true); 00509 rpl_dodag_version_t *version = rpl_create_dodag_version(dodag, rpl_seq_init()); 00510 if (!version) { 00511 rpl_delete_dodag(dodag); 00512 tr_error("No mem for DODAG root"); 00513 return NULL; 00514 } 00515 rpl_instance_set_dodag_version(instance, version, rank); 00516 00517 return dodag; 00518 } 00519 00520 void rpl_control_delete_dodag_root(rpl_domain_t *domain, rpl_dodag_t *dodag) 00521 { 00522 (void)domain; 00523 00524 rpl_delete_dodag_root(dodag); 00525 } 00526 00527 void rpl_control_update_dodag_route(rpl_dodag_t *dodag, const uint8_t *prefix, uint8_t prefix_len, uint8_t flags, uint32_t lifetime, bool age) 00528 { 00529 /* Not clear if non-root nodes should be able to publish routes */ 00530 if (rpl_dodag_am_root(dodag)) { 00531 rpl_dodag_update_dio_route(dodag, prefix, prefix_len, flags, lifetime, age); 00532 } 00533 } 00534 00535 void rpl_control_update_dodag_prefix(rpl_dodag_t *dodag, const uint8_t *prefix, uint8_t prefix_len, uint8_t flags, uint32_t lifetime, uint32_t preftime, bool age) 00536 { 00537 /* Don't let them set weird flags. We do allow them to add prefixes if not 00538 * a root though - they might want this to add a L prefix? 00539 */ 00540 flags &= (PIO_A | PIO_L); 00541 rpl_dodag_update_dio_prefix(dodag, prefix, prefix_len, flags, lifetime, preftime, /*publish=*/true, age); 00542 } 00543 00544 void rpl_control_increment_dtsn(rpl_dodag_t *dodag) 00545 { 00546 rpl_dodag_increment_dtsn(dodag); 00547 //rpl_dodag_inconsistency(dodag); currently implied by rpl_dodag_increment_dtsn 00548 } 00549 00550 void rpl_control_increment_dodag_version(rpl_dodag_t *dodag) 00551 { 00552 if (rpl_dodag_am_root(dodag)) { 00553 uint8_t new_version = rpl_seq_inc(rpl_dodag_get_version_number_as_root(dodag)); 00554 rpl_dodag_set_version_number_as_root(dodag, new_version); 00555 } 00556 } 00557 void rpl_control_update_dodag_config(struct rpl_dodag *dodag, const rpl_dodag_conf_t *conf) 00558 { 00559 00560 if (rpl_dodag_am_root(dodag)) { 00561 rpl_dodag_update_config(dodag, conf, NULL, NULL); 00562 } 00563 } 00564 00565 00566 void rpl_control_set_dodag_pref(rpl_dodag_t *dodag, uint8_t pref) 00567 { 00568 if (rpl_dodag_am_root(dodag)) { 00569 rpl_dodag_set_pref(dodag, pref); 00570 } 00571 } 00572 00573 void rpl_control_poison(rpl_domain_t *domain, uint8_t count) 00574 { 00575 ns_list_foreach(rpl_instance_t, instance, &domain->instances) { 00576 rpl_instance_poison(instance, count); 00577 } 00578 } 00579 00580 void rpl_control_force_leaf(rpl_domain_t *domain, bool leaf) 00581 { 00582 domain->force_leaf = leaf; 00583 if (leaf) { 00584 ns_list_foreach(rpl_instance_t, instance, &domain->instances) { 00585 rpl_instance_force_leaf(instance); 00586 } 00587 } 00588 } 00589 00590 /* Check whether the options section of a RPL control message is well-formed */ 00591 static bool rpl_control_options_well_formed(const uint8_t *dptr, uint_fast16_t dlen) 00592 { 00593 while (dlen) { 00594 uint_fast16_t opt_len; 00595 00596 if (dptr[0] == RPL_PAD1_OPTION) { 00597 opt_len = 1; 00598 } else { 00599 if (dlen < 2) { 00600 return false; 00601 } 00602 opt_len = 2 + dptr[1]; 00603 } 00604 00605 if (opt_len > dlen) { 00606 return false; 00607 } 00608 00609 dptr += opt_len; 00610 dlen -= opt_len; 00611 } 00612 00613 return true; 00614 } 00615 00616 static bool rpl_control_options_well_formed_in_buffer(const buffer_t *buf, uint16_t offset) 00617 { 00618 if (buffer_data_length(buf) < offset) { 00619 return false; 00620 } 00621 00622 return rpl_control_options_well_formed(buffer_data_pointer(buf) + offset, 00623 buffer_data_length(buf) - offset); 00624 } 00625 00626 /* 00627 * Search for the first option of the specified type (and optionally length). 00628 * Caller must have already checked the options are well-formed. 00629 * Returns pointer to type byte, so length is at +1, data at +2. 00630 */ 00631 static const uint8_t *rpl_control_find_option(const uint8_t *dptr, uint_fast16_t dlen, uint8_t option, uint8_t optlen) 00632 { 00633 while (dlen) { 00634 uint8_t type = dptr[0]; 00635 if (type == RPL_PAD1_OPTION) { 00636 dptr++, dlen--; 00637 continue; 00638 } 00639 uint_fast16_t len = dptr[1]; 00640 if (type == option && (optlen == 0 || optlen == len)) { 00641 return dptr; 00642 } 00643 00644 dlen -= 2 + len; 00645 dptr += 2 + len; 00646 } 00647 return NULL; 00648 } 00649 00650 static const uint8_t *rpl_control_find_option_in_buffer(const buffer_t *buf, uint_fast16_t offset, uint8_t option, uint8_t optlen) 00651 { 00652 return rpl_control_find_option(buffer_data_pointer(buf) + offset, 00653 buffer_data_length(buf) - offset, 00654 option, optlen); 00655 } 00656 00657 /* 0 1 2 3 00658 * 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 00659 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 00660 * | Type = 0x04 |Opt Length = 14| Flags |A| PCS | DIOIntDoubl. | 00661 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 00662 * | DIOIntMin. | DIORedun. | MaxRankIncrease | 00663 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 00664 * | MinHopRankIncrease | OCP | 00665 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 00666 * | Reserved | Def. Lifetime | Lifetime Unit | 00667 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 00668 * 00669 * Figure 24: Format of the DODAG Configuration Option 00670 */ 00671 static const uint8_t *rpl_control_read_conf(rpl_dodag_conf_t *conf_out, const uint8_t *opt) 00672 { 00673 conf_out->authentication = opt[2] & 0x08; 00674 conf_out->path_control_size = opt[2] & 0x07; 00675 conf_out->dio_interval_doublings = opt[3]; 00676 conf_out->dio_interval_min = opt[4]; 00677 conf_out->dio_redundancy_constant = opt[5]; 00678 conf_out->dag_max_rank_increase = common_read_16_bit(opt + 6); 00679 conf_out->min_hop_rank_increase = common_read_16_bit(opt + 8); 00680 conf_out->objective_code_point = common_read_16_bit(opt + 10); 00681 conf_out->default_lifetime = opt[13]; 00682 conf_out->lifetime_unit = common_read_16_bit(opt + 14); 00683 return opt + 16; 00684 } 00685 00686 static uint8_t *rpl_control_write_conf(uint8_t *opt_out, const rpl_dodag_conf_t *conf) 00687 { 00688 opt_out[0] = RPL_DODAG_CONF_OPTION; 00689 opt_out[1] = 14; 00690 opt_out[2] = conf->authentication ? RPL_CONF_FLAG_AUTH : 0; 00691 opt_out[2] |= conf->path_control_size; 00692 opt_out[3] = conf->dio_interval_doublings; 00693 opt_out[4] = conf->dio_interval_min; 00694 opt_out[5] = conf->dio_redundancy_constant; 00695 common_write_16_bit(conf->dag_max_rank_increase, opt_out + 6); 00696 common_write_16_bit(conf->min_hop_rank_increase, opt_out + 8); 00697 common_write_16_bit(conf->objective_code_point, opt_out + 10); 00698 opt_out[12] = 0; // reserved 00699 opt_out[13] = conf->default_lifetime; 00700 common_write_16_bit(conf->lifetime_unit, opt_out + 14); 00701 return opt_out + 16; 00702 } 00703 00704 static uint_fast8_t rpl_control_conf_length(void) 00705 { 00706 return 16; 00707 } 00708 00709 /* 00710 * 0 1 2 3 00711 * 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 00712 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 00713 * | Type = 0x08 |Opt Length = 30| Prefix Length |L|A|R|Reserved1| 00714 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 00715 * | Valid Lifetime | 00716 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 00717 * | Preferred Lifetime | 00718 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 00719 * | Reserved2 | 00720 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 00721 * | | 00722 * + + 00723 * | | 00724 * + Prefix + 00725 * | | 00726 * + + 00727 * | | 00728 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 00729 * 00730 * Figure 29: Format of the Prefix Information Option 00731 */ 00732 static void rpl_control_process_prefix_options(protocol_interface_info_entry_t *cur, rpl_instance_t *instance, rpl_dodag_t *dodag, rpl_neighbour_t *neighbour, const uint8_t *start, const uint8_t *end) 00733 { 00734 (void)cur; 00735 00736 bool router_addr_set = false; 00737 00738 rpl_neighbour_t *pref_parent = rpl_instance_preferred_parent(instance); 00739 if (neighbour == pref_parent) { 00740 rpl_dodag_update_unpublished_dio_prefix_start(dodag); 00741 } 00742 00743 for (;;) { 00744 const uint8_t *ptr = rpl_control_find_option(start, end - start, RPL_PREFIX_INFO_OPTION, 30); 00745 if (!ptr) { 00746 break; 00747 } 00748 uint8_t prefix_len = ptr[2]; 00749 uint8_t flags = ptr[3]; 00750 uint32_t valid = common_read_32_bit(ptr + 4); 00751 uint32_t preferred = common_read_32_bit(ptr + 8); 00752 const uint8_t *prefix = ptr + 16; 00753 00754 if (rpl_upward_accept_prefix_update(dodag, neighbour, pref_parent)) { 00755 00756 /* Store prefixes for possible forwarding */ 00757 /* XXX if leaf - don't bother? Or do we want to remember them for 00758 * when we switch DODAG, as mentioned above? 00759 */ 00760 prefix_entry_t *prefix_entry = rpl_dodag_update_dio_prefix(dodag, prefix, prefix_len, flags, valid, preferred, false, true); 00761 if (prefix_entry && pref_parent) { 00762 rpl_control_process_prefix_option(prefix_entry, cur); 00763 rpl_domain_t *domain = cur->rpl_domain; 00764 if (domain && domain->prefix_cb) { 00765 uint8_t ll_address[16]; 00766 memcpy(ll_address, rpl_neighbour_ll_address(pref_parent), 16); 00767 domain->prefix_cb(prefix_entry, domain->cb_handle, ll_address); 00768 } 00769 } 00770 } 00771 00772 if ((flags & PIO_R) && !router_addr_set) { 00773 /* Routers can have multiple global addresses - one for each 00774 * prefix being advertised. We don't attempt to track this; 00775 * we just remember their first-listed address. 00776 * ( 00777 */ 00778 router_addr_set = true; 00779 rpl_neighbour_update_global_address(neighbour, ptr + 16); 00780 } 00781 00782 start = ptr + 32; 00783 } 00784 if (neighbour == pref_parent) { 00785 rpl_dodag_update_unpublished_dio_prefix_finish(dodag); 00786 } 00787 } 00788 00789 void rpl_control_process_prefix_option(prefix_entry_t *prefix, protocol_interface_info_entry_t *cur) 00790 { 00791 //Check is L Flag active 00792 if (prefix->options & PIO_L) { 00793 //define ONLink Route Information 00794 //tr_debug("Register On Link Prefix to routing table"); 00795 ipv6_route_add(prefix->prefix, prefix->prefix_len, cur->id, NULL, ROUTE_RADV, prefix->lifetime, 0); 00796 } 00797 00798 } 00799 00800 00801 /* 00802 * 0 1 2 3 00803 * 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 00804 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 00805 * | Type = 0x03 | Option Length | Prefix Length |Resvd|Prf|Resvd| 00806 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 00807 * | Route Lifetime | 00808 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 00809 * | | 00810 * . Prefix (Variable Length) . 00811 * . . 00812 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 00813 * 00814 * Figure 23: Format of the Route Information Option 00815 */ 00816 static void rpl_control_process_route_options(rpl_instance_t *instance, rpl_dodag_t *dodag, rpl_dodag_version_t *version, rpl_neighbour_t *neighbour, uint16_t rank, const uint8_t *start, const uint8_t *end) 00817 { 00818 (void)neighbour; 00819 00820 /* For non-current DODAGs, it's simplest to accept routes from anyone. */ 00821 if (rpl_instance_current_dodag(instance) == dodag) { 00822 /* It's for the current DODAG - more care required. Check versions */ 00823 rpl_cmp_t v_cmp = rpl_dodag_version_compare(version, rpl_instance_current_dodag_version(instance)); 00824 if (v_cmp & RPL_CMP_EQUAL) { 00825 /* If coming from a neighbour in the same version, make sure they have lower rank */ 00826 if (!(rpl_rank_compare(dodag, rank, rpl_instance_current_rank(instance)) & RPL_CMP_LESS)) { 00827 return; 00828 } 00829 } else if (v_cmp & RPL_CMP_GREATER) { 00830 /* If coming from a neighbour in a newer version, we'll accept it */ 00831 } else { 00832 /* From older or unknown version, we reject it */ 00833 return; 00834 } 00835 } 00836 00837 for (;;) { 00838 const uint8_t *ptr = rpl_control_find_option(start, end - start, RPL_ROUTE_INFO_OPTION, 0); 00839 if (!ptr) { 00840 break; 00841 } 00842 uint8_t opt_len = ptr[1]; 00843 start = ptr + 2 + opt_len; 00844 if (opt_len < 6) { 00845 tr_warn("Malformed RIO"); 00846 continue; 00847 } 00848 uint8_t prefix_len = ptr[2]; 00849 uint8_t flags = ptr[3]; 00850 uint32_t lifetime = common_read_32_bit(ptr + 4); 00851 const uint8_t *prefix = ptr + 8; 00852 if (opt_len < 6 + (prefix_len + 7u) / 8) { 00853 tr_warn("Malformed RIO"); 00854 continue; 00855 } 00856 rpl_dodag_update_dio_route(dodag, prefix, prefix_len, flags, lifetime, true); 00857 } 00858 00859 /* We do not purge unadvertised routes. Thus if the root wants to purge 00860 * a route before its lifetime is up, stopping advertising it is not 00861 * sufficient, it has to advertise it with low or zero lifetime. This fits 00862 * with ND Router Advertisement behaviour. 00863 */ 00864 } 00865 00866 static void rpl_control_dao_trigger_request(rpl_instance_t *instance, rpl_dodag_t *dodag, rpl_neighbour_t *neighbour) 00867 { 00868 switch (rpl_dodag_mop(dodag)) { 00869 case RPL_MODE_NON_STORING: 00870 rpl_instance_dao_request(instance, NULL); 00871 rpl_dodag_increment_dtsn(dodag); 00872 break; 00873 case RPL_MODE_STORING: 00874 case RPL_MODE_STORING_MULTICAST: 00875 rpl_instance_dao_request(instance, neighbour); 00876 break; 00877 default: 00878 /* Nothing */ 00879 break; 00880 } 00881 } 00882 00883 /* 00884 * 0 1 2 3 00885 * 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 00886 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 00887 * | RPLInstanceID |Version Number | Rank | 00888 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 00889 * |G|0| MOP | Prf | DTSN | Flags | Reserved | 00890 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 00891 * | | 00892 * + + 00893 * | | 00894 * + DODAGID + 00895 * | | 00896 * + + 00897 * | | 00898 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 00899 * | Option(s)... 00900 * +-+-+-+-+-+-+-+-+ 00901 * 00902 * Figure 14: The DIO Base Object 00903 */ 00904 static buffer_t *rpl_control_dio_handler(protocol_interface_info_entry_t *cur, rpl_domain_t *domain, buffer_t *buf) 00905 { 00906 if (!rpl_control_options_well_formed_in_buffer(buf, 24)) { 00907 malformed: 00908 protocol_stats_update(STATS_RPL_MALFORMED_MESSAGE, 1); 00909 return buffer_free(buf); 00910 } 00911 00912 /* Read the base object */ 00913 const uint8_t *ptr = buffer_data_pointer(buf); 00914 uint8_t instance_id, version_num, g_mop_prf, dtsn; 00915 uint16_t rank; 00916 const uint8_t *dodagid; 00917 bool become_leaf = false; 00918 00919 instance_id = ptr[0]; 00920 version_num = ptr[1]; 00921 rank = common_read_16_bit(ptr + 2); 00922 g_mop_prf = ptr[4]; 00923 dtsn = ptr[5]; 00924 dodagid = ptr + 8; 00925 ptr += 24; 00926 tr_info("DIO from %s, rank %x", trace_ipv6(buf->src_sa .address ), rank); 00927 if (addr_is_ipv6_link_local(dodagid) || addr_is_ipv6_multicast(dodagid)) { 00928 tr_error("DIO DODAGID"); 00929 goto malformed; 00930 } 00931 00932 /* Check if this is for an existing RPL Instance - create if necessary */ 00933 rpl_instance_t *instance = rpl_lookup_instance(domain, instance_id, dodagid); 00934 if (!instance) { 00935 /* Policy can gate at this point, by instance ID and DODAG ID */ 00936 if (!rpl_policy_join_instance(domain, instance_id, dodagid)) { 00937 tr_info("Policy ignoring instance (%d,%s)", instance_id, trace_ipv6(dodagid)); 00938 return buffer_free(buf); 00939 } 00940 00941 instance = rpl_create_instance(domain, instance_id); 00942 if (!instance) { 00943 return buffer_free(buf); 00944 } 00945 } 00946 00947 /* Lookup any existing neighbour entry */ 00948 rpl_neighbour_t *neighbour = rpl_lookup_neighbour_by_ll_address(instance, buf->src_sa .address , cur->id); 00949 00950 /* From this point on, we are potentially updating an existing neighbour */ 00951 /* Any decision to reject the DIO, or failure to handle it, means removing that neighbour */ 00952 00953 /* Any DIO with infinite rank is immediate poison - no further analysis required */ 00954 if (rank == RPL_RANK_INFINITE) { 00955 goto invalid_parent; 00956 } 00957 00958 /* Policy can gate by DODAGID and other bits */ 00959 if (!rpl_policy_join_dodag(domain, g_mop_prf, instance_id, dodagid)) { 00960 tr_info("Policy ignoring DODAG (%02x,%s)", g_mop_prf, trace_ipv6(dodagid)); 00961 goto invalid_parent; 00962 } 00963 00964 /* Look up and create the DODAG structure */ 00965 rpl_dodag_t *dodag = rpl_lookup_dodag(instance, dodagid); 00966 if (!dodag) { 00967 /* Policy can gate by DODAGID and other bits */ 00968 if (!rpl_policy_join_dodag(domain, g_mop_prf, instance_id, dodagid)) { 00969 tr_info("Policy ignoring DODAG (%02x,%s)", g_mop_prf, trace_ipv6(dodagid)); 00970 goto invalid_parent; 00971 } 00972 dodag = rpl_create_dodag(instance, dodagid, g_mop_prf); 00973 if (!dodag) { 00974 goto invalid_parent; 00975 } 00976 } 00977 00978 /* Never listen to nodes in a DODAG we're rooting */ 00979 if (rpl_dodag_am_root(dodag)) { 00980 /* TODO - if version is newer or unordered, increment our version to be higher? */ 00981 /* Old code had this trick - actually, would need to go further. Want to listen first, then use a higher 00982 * than existing. */ 00983 /* 00984 uint8_t our_version = rpl_dodag_get_version_number_as_root(dodag); 00985 if (rpl_seq_compare(version_num, our_version) & (RPL_CMP_UNORDERED|RPL_CMP_GREATER)) 00986 */ 00987 goto invalid_parent; 00988 } 00989 00990 /* Even if we're not currently rooting - what if it's our address? Ignore stale info on network */ 00991 if (addr_interface_address_compare(cur, dodagid) == 0) { 00992 tr_info("DIO our DODAGID %s", trace_ipv6(dodagid)); 00993 /* Should we transmit poison? */ 00994 goto invalid_parent; 00995 } 00996 00997 00998 /* Update DODAG config information, if option present, and either we don't have it or version is newer */ 00999 const uint8_t *dodag_conf_ptr = rpl_control_find_option_in_buffer(buf, 24, RPL_DODAG_CONF_OPTION, 14); 01000 if (dodag_conf_ptr) { 01001 rpl_dodag_conf_t conf_buf; 01002 rpl_control_read_conf(&conf_buf, dodag_conf_ptr); 01003 if (!rpl_dodag_update_config(dodag, &conf_buf, buf->src_sa .address , &become_leaf)) { 01004 goto invalid_parent; 01005 } 01006 } 01007 01008 /* If we don't have any DODAG config information, ask by unicast DIS */ 01009 const rpl_dodag_conf_t *conf = rpl_dodag_get_config(dodag); 01010 if (!conf) { 01011 /* TODO - rate limit DIS? */ 01012 if (domain->new_parent_add && !domain->new_parent_add(buf->src_sa .address , domain->cb_handle)) { 01013 goto invalid_parent; 01014 } 01015 rpl_control_transmit_dis(domain, cur, RPL_SOLINFO_PRED_DODAGID | RPL_SOLINFO_PRED_INSTANCEID, instance_id, dodagid, 0, buf->src_sa .address ); 01016 goto invalid_parent; 01017 } 01018 01019 /* Check whether config is acceptable */ 01020 if (!rpl_policy_join_config(domain, conf, &become_leaf)) { 01021 goto invalid_parent; 01022 } 01023 01024 /* Lookup or create DODAG Version state info */ 01025 rpl_dodag_version_t *version = rpl_lookup_dodag_version(dodag, version_num); 01026 if (!version) { 01027 version = rpl_create_dodag_version(dodag, version_num); 01028 if (!version) { 01029 goto invalid_parent; 01030 } 01031 } 01032 01033 const uint8_t *metric_ptr = rpl_control_find_option_in_buffer(buf, 24, RPL_DAG_METRIC_OPTION, 0); 01034 /* We currently don't understand anything about metrics, so to be on the safe side, we don't join */ 01035 if (metric_ptr) { 01036 become_leaf = true; 01037 } 01038 01039 /* We mustn't process DIOs from our potential sub-DODAG, unless local repair is ongoing */ 01040 if (!rpl_instance_local_repair(instance) && rpl_dodag_version_rank_indicates_possible_sub_dodag(version, rank)) { 01041 goto invalid_parent; 01042 } 01043 01044 /* Now we create the neighbour, if we don't already have a record */ 01045 if (!neighbour) { 01046 neighbour = rpl_create_neighbour(version, buf->src_sa .address , cur->id, g_mop_prf, dtsn); 01047 //Call Here new parent create 01048 if (!neighbour) { 01049 goto invalid_parent; 01050 } 01051 01052 if (domain->new_parent_add && !domain->new_parent_add(buf->src_sa .address , domain->cb_handle)) { 01053 goto invalid_parent; 01054 } 01055 01056 } 01057 01058 /* Update neighbour info */ 01059 rpl_neighbour_update_dodag_version(neighbour, version, rank, g_mop_prf); 01060 01061 if (rpl_neighbour_update_dtsn(neighbour, dtsn)) { 01062 tr_info("Parent %s incremented DTSN", trace_ipv6(buf->src_sa .address )); 01063 rpl_control_dao_trigger_request(instance, dodag, neighbour); 01064 } 01065 01066 01067 rpl_control_process_prefix_options(cur, instance, dodag, neighbour, ptr, buffer_data_end(buf)); 01068 //rpl_dodag_update_implicit_system_routes(dodag, neighbour); 01069 rpl_control_process_route_options(instance, dodag, version, neighbour, rank, ptr, buffer_data_end(buf)); 01070 01071 //rpl_control_process_metric_containers(neighbour, ptr, buffer_data_end(buf)) 01072 01073 if (become_leaf) { 01074 rpl_dodag_set_leaf(dodag, true); 01075 } 01076 01077 /* RFC 6550 8.3: A DIO from a sender with lesser DAGRank that causes no 01078 * changes to the recipient's parent set, preferred parent, or Rank SHOULD 01079 * be considered consistent with respect to the Trickle timer. 01080 * 01081 * Now, if we don't run parent selection immediately, how do we know if it's 01082 * consistent or not? Compromise is to treat all lower ranked DIOs as 01083 * consistent, and reset (and hold) the consistent counter to 0 if any of 01084 * the above change. This actually seems better than the RFC 6550 rule, as 01085 * it guarantees we will transmit if those change. The rule as stated 01086 * would mean a large number of parent messages would stop us advertising 01087 * a Rank change. 01088 */ 01089 if (version == rpl_instance_current_dodag_version(instance) && 01090 (rpl_rank_compare(dodag, rank, rpl_instance_current_rank(instance)) & RPL_CMP_LESS)) { 01091 rpl_instance_consistent_rx(instance); 01092 } 01093 01094 rpl_instance_neighbours_changed(instance, dodag); 01095 01096 return buffer_free(buf); 01097 01098 invalid_parent: 01099 if (neighbour) { 01100 rpl_delete_neighbour(instance, neighbour); 01101 } 01102 return buffer_free(buf); 01103 } 01104 01105 static void rpl_control_transmit_one_interface(protocol_interface_info_entry_t *cur, buffer_t *buf) 01106 { 01107 /* If destination is global, this will end up routed, regardless of original interface */ 01108 /* (But we do currently need an interface specified anyway?) */ 01109 if (cur) { 01110 buf->interface = cur; 01111 } 01112 01113 /* RPL requires us to use link-local source for all messages except DAO/DAO-ACK 01114 * in storing mode, which use global source. Default address selection in 01115 * icmpv6_down should do the right thing, as long as the interface does have 01116 * both LL and global, so don't bother to set source here. 01117 */ 01118 01119 protocol_push(buf); 01120 } 01121 01122 static void rpl_control_transmit_all_interfaces(rpl_domain_t *domain, buffer_t *buf) 01123 { 01124 protocol_interface_info_entry_t *first_if = NULL, *cur; 01125 int8_t last_id = -1; 01126 01127 while ((cur = protocol_stack_interface_info_get_by_rpl_domain(domain, last_id)) != NULL) { 01128 if (!first_if) { 01129 /* Note first interface - it will get original buffer after loop */ 01130 first_if = cur; 01131 } else { 01132 /* This is a subsequent interface - send a clone */ 01133 buffer_t *clone = buffer_clone(buf); 01134 if (clone) { 01135 rpl_control_transmit_one_interface(cur, clone); 01136 } 01137 } 01138 last_id = cur->id; 01139 } 01140 01141 if (first_if) { 01142 rpl_control_transmit_one_interface(first_if, buf); 01143 } else { 01144 // RPL domain with no interfaces? Odd... 01145 buffer_free(buf); 01146 } 01147 } 01148 01149 /* Complete and send a RPL control message - all interfaces multicast if dst+cur are NULL, else unicast */ 01150 void rpl_control_transmit(rpl_domain_t *domain, protocol_interface_info_entry_t *cur, uint8_t code, buffer_t *buf, const uint8_t *dst) 01151 { 01152 buf->info = (buffer_info_t)(B_FROM_ICMP | B_TO_ICMP | B_DIR_DOWN); 01153 buf->options .type = ICMPV6_TYPE_INFO_RPL_CONTROL; 01154 buf->options .code = code; 01155 buf->dst_sa .addr_type = ADDR_IPV6 ; 01156 memcpy(buf->dst_sa .address , dst ? dst : ADDR_LINK_LOCAL_ALL_RPL_NODES, 16); 01157 01158 /* Use 255 hop limit for link-local stuff, akin to other ICMP */ 01159 /* Others set "0", which means use interface default */ 01160 buf->options .hop_limit = addr_ipv6_scope(buf->dst_sa .address , cur) <= IPV6_SCOPE_LINK_LOCAL ? 255 : 0; 01161 01162 01163 if (dst == NULL && cur == NULL) { 01164 rpl_control_transmit_all_interfaces(domain, buf); 01165 } else { 01166 /* Fudge - need a dummy interface for non-storing DAO to root - won't 01167 * actually be used as it'll get globally routed. 01168 */ 01169 if (!cur) { 01170 cur = protocol_stack_interface_info_get_by_id(domain->non_storing_downstream_interface); 01171 } 01172 rpl_control_transmit_one_interface(cur, buf); 01173 } 01174 } 01175 01176 01177 /* Transmit a DIO (unicast or multicast); cur may be NULL if multicast */ 01178 void rpl_control_transmit_dio(rpl_domain_t *domain, protocol_interface_info_entry_t *cur, uint8_t instance_id, uint8_t dodag_version, uint16_t rank, uint8_t g_mop_prf, uint8_t dtsn, rpl_dodag_t *dodag, const uint8_t dodagid[16], const rpl_dodag_conf_t *conf, const uint8_t *dst) 01179 { 01180 uint16_t length; 01181 01182 const rpl_dio_route_list_t *routes = rpl_dodag_get_route_list(dodag); 01183 const prefix_list_t *prefixes = rpl_dodag_get_prefix_list(dodag); 01184 01185 tr_debug("transmit dio, rank: %x", rank); 01186 protocol_interface_info_entry_t *downstream_if = protocol_stack_interface_info_get_by_id(domain->non_storing_downstream_interface); 01187 length = 24; 01188 if (conf) { 01189 length += rpl_control_conf_length(); 01190 } 01191 01192 ns_list_foreach(prefix_entry_t, prefix, prefixes) { 01193 /* We must not forward 'L' prefixes */ 01194 if ((prefix->options & (PIO_L | RPL_PIO_PUBLISHED)) == PIO_L) { 01195 continue; 01196 } 01197 01198 /* In storing mode, do not forward a prefix until we have an 01199 * address for it. (RFC 6550 6.7.10 - "A non-storing node SHOULD 01200 * refrain from advertising a prefix until it owns an address of 01201 * that prefix, and then it SHOULD advertise its full address in 01202 * this field, with the 'R' flag set. 01203 */ 01204 /* XXX We must also be advertising the corresponding address as a DAO target */ 01205 const uint8_t *addr = downstream_if ? addr_select_with_prefix(downstream_if, prefix->prefix, prefix->prefix_len, 0) : NULL; 01206 if (addr) { 01207 prefix->options |= PIO_R; 01208 memcpy(prefix->prefix, addr, 16); 01209 } else { 01210 prefix->options &= ~ PIO_R; 01211 01212 if (rpl_dodag_mop(dodag) == RPL_MODE_NON_STORING && (prefix->lifetime != 0 || !(prefix->options & PIO_A))) { 01213 continue; 01214 } 01215 } 01216 length += 32; 01217 } 01218 01219 ns_list_foreach(rpl_dio_route_t, route, routes) { 01220 length += 8 + (route->prefix_len + 7u) / 8; 01221 } 01222 01223 /* Add metric lengths here */ 01224 01225 buffer_t *buf = buffer_get(length); 01226 if (!buf) { 01227 return; 01228 } 01229 uint8_t *ptr = buffer_data_pointer(buf); 01230 ptr[0] = instance_id; 01231 ptr[1] = dodag_version; 01232 common_write_16_bit(rank, ptr + 2); 01233 ptr[4] = g_mop_prf; 01234 ptr[5] = dtsn; 01235 ptr[6] = 0; 01236 ptr[7] = 0; 01237 memcpy(ptr + 8, dodagid, 16); 01238 ptr += 24; 01239 01240 if (conf) { 01241 ptr = rpl_control_write_conf(ptr, conf); 01242 } 01243 01244 /* Write prefix/route/metric options here */ 01245 01246 01247 ns_list_foreach_safe(prefix_entry_t, prefix, prefixes) { 01248 /* See equivalent checks in length calculation above */ 01249 if ((prefix->options & (PIO_L | RPL_PIO_PUBLISHED)) == PIO_L || 01250 (!(prefix->options & PIO_R) && rpl_dodag_mop(dodag) == RPL_MODE_NON_STORING && (prefix->lifetime != 0 || !(prefix->options & PIO_A)))) { 01251 continue; 01252 } 01253 01254 ptr[0] = RPL_PREFIX_INFO_OPTION; 01255 ptr[1] = 30; 01256 ptr[2] = prefix->prefix_len; 01257 ptr[3] = prefix->options & (PIO_R | PIO_A | PIO_L); 01258 common_write_32_bit(prefix->lifetime, ptr + 4); 01259 common_write_32_bit(prefix->preftime, ptr + 8); 01260 common_write_32_bit(0, ptr + 12); // reserved 01261 memcpy(ptr + 16, prefix->prefix, 16); 01262 ptr += 32; 01263 /* Transmitting a multicast DIO decrements the hold count for 0 lifetime prefixes */ 01264 if (dst == NULL && (prefix->options & RPL_PIO_AGE)) { 01265 int hold_count = prefix->options & RPL_PIO_HOLD_MASK; 01266 if (hold_count) { 01267 hold_count--; 01268 prefix->options = (prefix->options & ~RPL_PIO_HOLD_MASK) | hold_count; 01269 } 01270 } 01271 } 01272 01273 ns_list_foreach_safe(rpl_dio_route_t, route, routes) { 01274 uint8_t prefix_bytes = (route->prefix_len + 7u) / 8u; 01275 ptr[0] = RPL_ROUTE_INFO_OPTION; 01276 ptr[1] = 6 + prefix_bytes; 01277 ptr[2] = route->prefix_len; 01278 ptr[3] = route->flags; 01279 common_write_32_bit(route->lifetime, ptr + 4); 01280 bitcopy0(ptr + 8, route->prefix, route->prefix_len); 01281 ptr += 8 + prefix_bytes; 01282 /* Transmitting a multicast DIO decrements the hold count for 0 lifetime routes */ 01283 if (dst == NULL && route->lifetime == 0) { 01284 if (route->hold_count) { 01285 route->hold_count--; 01286 } 01287 if (route->hold_count == 0) { 01288 rpl_dodag_delete_dio_route(dodag, route); 01289 } 01290 } 01291 } 01292 01293 buffer_data_end_set(buf, ptr); 01294 01295 rpl_control_transmit(domain, cur, ICMPV6_CODE_RPL_DIO, buf, dst); 01296 } 01297 01298 /* 0 1 2 01299 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 01300 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 01301 * | Flags | Reserved | Option(s)... 01302 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 01303 * 01304 * Figure 13: The DIS Base Object 01305 * 01306 * 0 1 2 3 01307 * 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 01308 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 01309 * | Type = 0x07 |Opt Length = 19| RPLInstanceID |V|I|D| Flags | 01310 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 01311 * | | 01312 * + + 01313 * | | 01314 * + DODAGID + 01315 * | | 01316 * + + 01317 * | | 01318 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 01319 * |Version Number | 01320 * +-+-+-+-+-+-+-+-+ 01321 * 01322 * Figure 28: Format of the Solicited Information Option 01323 */ 01324 static buffer_t *rpl_control_dis_handler(protocol_interface_info_entry_t *cur, rpl_domain_t *domain, buffer_t *buf, bool multicast) 01325 { 01326 if (!rpl_control_options_well_formed_in_buffer(buf, 2)) { 01327 protocol_stats_update(STATS_RPL_MALFORMED_MESSAGE, 1); 01328 return buffer_free(buf); 01329 } 01330 01331 /* Base object irrelevant - find the Solicited Information option, if any */ 01332 const uint8_t *sol = rpl_control_find_option_in_buffer(buf, 2, RPL_SOL_INFO_OPTION, 19); 01333 uint8_t preds, sol_instance_id, sol_version; 01334 const uint8_t *sol_dodagid; 01335 if (sol) { 01336 preds = sol[3]; 01337 sol_instance_id = sol[2]; 01338 sol_dodagid = sol + 4; 01339 sol_version = sol[20]; 01340 } else { 01341 /* No option present means "match any" */ 01342 preds = 0; 01343 sol_instance_id = 0; 01344 sol_dodagid = NULL; 01345 sol_version = 0; 01346 } 01347 01348 /* If it's a multicast DIS, then we reset trickle timer for each matching 01349 * instances. 01350 * 01351 * If it's a unicast DIS, we unicast a DIO back to the sender for each 01352 * matching instance. 01353 */ 01354 rpl_loopfn_trigger_unicast_dio_arg_t arg; 01355 arg.interface = cur; 01356 arg.dst = buf->src_sa .address ; 01357 01358 rpl_control_predicate_loop(domain, 01359 multicast ? rpl_loopfn_reset_dio_timer : rpl_loopfn_trigger_unicast_dio, 01360 &arg, 01361 preds, sol_instance_id, sol_dodagid, sol_version); 01362 01363 return buffer_free(buf); 01364 } 01365 01366 void rpl_control_transmit_dis(rpl_domain_t *domain, protocol_interface_info_entry_t *cur, uint8_t pred, uint8_t instance_id, const uint8_t *dodagid, const uint8_t version, const uint8_t *dst) 01367 { 01368 uint16_t length = 2; 01369 if (pred) { 01370 length += 2 + 19; 01371 } 01372 buffer_t *buf = buffer_get(length); 01373 if (!buf) { 01374 return; 01375 } 01376 uint8_t *ptr = buffer_data_pointer(buf); 01377 *ptr++ = 0; // flags 01378 *ptr++ = 0; // reserved 01379 if (pred) { 01380 ptr[0] = RPL_SOL_INFO_OPTION; 01381 ptr[1] = 19; 01382 if (pred & RPL_SOLINFO_PRED_INSTANCEID) { 01383 ptr[2] = instance_id; 01384 } else { 01385 ptr[2] = 0; 01386 } 01387 ptr[3] = pred; 01388 if (pred & RPL_SOLINFO_PRED_DODAGID) { 01389 memcpy(ptr + 4, dodagid, 16); 01390 } else { 01391 memset(ptr + 4, 0, 16); 01392 } 01393 if (pred & RPL_SOLINFO_PRED_VERSION) { 01394 ptr[20] = version; 01395 } else { 01396 ptr[20] = 0; 01397 } 01398 ptr += 21; 01399 } 01400 01401 buffer_data_end_set(buf, ptr); 01402 rpl_control_transmit(domain, cur, ICMPV6_CODE_RPL_DIS, buf, dst); 01403 tr_info("Transmit DIS"); 01404 } 01405 01406 #ifdef HAVE_RPL_DAO_HANDLING 01407 /* 01408 * 0 1 2 3 01409 * 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 01410 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 01411 * | RPLInstanceID |D| Reserved | DAOSequence | Status | 01412 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 01413 * | | 01414 * + + 01415 * | | 01416 * + DODAGID* + 01417 * | | 01418 * + + 01419 * | | 01420 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 01421 * | Option(s)... 01422 * +-+-+-+-+-+-+-+-+ 01423 * 01424 * Figure 17: The DAO ACK Base Object 01425 */ 01426 01427 static void rpl_control_transmit_dao_ack(rpl_domain_t *domain, protocol_interface_info_entry_t *cur, uint8_t instance_id, uint8_t dao_sequence, uint8_t status, const uint8_t dodagid[16], const uint8_t *dst) 01428 { 01429 buffer_t *buf = buffer_get(dodagid ? 4 + 20 : 4); 01430 if (!buf) { 01431 return; 01432 } 01433 uint8_t *ptr = buffer_data_pointer(buf); 01434 ptr[0] = instance_id; 01435 ptr[1] = dodagid ? RPL_DAO_ACK_FLAG_DODAGID : 0; 01436 ptr[2] = dao_sequence; 01437 ptr[3] = status; 01438 ptr += 4; 01439 if (dodagid) { 01440 memcpy(ptr, dodagid, 16); 01441 ptr += 16; 01442 } 01443 buffer_data_end_set(buf, ptr); 01444 rpl_control_transmit(domain, cur, ICMPV6_CODE_RPL_DAO_ACK, buf, dst); 01445 tr_info("Transmit DAO-ACK to: %s", trace_ipv6(dst)); 01446 } 01447 #endif // HAVE_RPL_DAO_HANDLING 01448 01449 static buffer_t *rpl_control_dao_ack_handler(protocol_interface_info_entry_t *cur, rpl_domain_t *domain, buffer_t *buf) 01450 { 01451 (void)cur; 01452 01453 if (buffer_data_length(buf) < 4) { 01454 format_error: 01455 protocol_stats_update(STATS_RPL_MALFORMED_MESSAGE, 1); 01456 return buffer_free(buf); 01457 } 01458 const uint8_t *ptr = buffer_data_pointer(buf); 01459 uint8_t instance_id = ptr[0]; 01460 const uint8_t *dodagid; 01461 01462 if (ptr[1] & RPL_DAO_ACK_FLAG_DODAGID) { 01463 if (buffer_data_length(buf) < 4 + 16) { 01464 goto format_error; 01465 } 01466 dodagid = ptr + 4; 01467 } else { 01468 dodagid = NULL; 01469 } 01470 01471 rpl_instance_t *instance = rpl_lookup_instance(domain, instance_id, dodagid); 01472 if (!instance) { 01473 protocol_stats_update(STATS_RPL_UNKNOWN_INSTANCE, 1); 01474 return buffer_free(buf); 01475 } 01476 01477 uint8_t dao_sequence = ptr[2]; 01478 uint8_t status = ptr[3]; 01479 rpl_instance_dao_acked(instance, buf->src_sa .address , buf->interface ->id, dao_sequence, status); 01480 return buffer_free(buf); 01481 } 01482 01483 /* 01484 * 0 1 2 3 01485 * 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 01486 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 01487 * | RPLInstanceID |K|D| Flags | Reserved | DAOSequence | 01488 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 01489 * | | 01490 * + + 01491 * | | 01492 * + DODAGID* + 01493 * | | 01494 * + + 01495 * | | 01496 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 01497 * | Option(s)... 01498 * +-+-+-+-+-+-+-+-+ 01499 * 01500 * Figure 16: The DAO Base Object 01501 */ 01502 bool rpl_control_transmit_dao(rpl_domain_t *domain, protocol_interface_info_entry_t *cur, rpl_instance_t *instance, uint8_t instance_id, uint8_t dao_sequence, const uint8_t dodagid[16], const uint8_t *opts, uint16_t opts_size, const uint8_t *dst) 01503 { 01504 uint8_t dodagid_flag = 0; 01505 if (rpl_instance_id_is_local(instance_id)) { 01506 dodagid_flag = RPL_DAO_FLAG_DODAGID; 01507 } 01508 01509 uint8_t base_size = dodagid_flag ? 4 + 16 : 4; 01510 buffer_t *buf = buffer_get(base_size + opts_size); 01511 if (!buf) { 01512 return true; 01513 } 01514 uint8_t *ptr = buffer_data_pointer(buf); 01515 ptr[0] = instance_id; 01516 ptr[1] = dodagid_flag; 01517 if (rpl_policy_request_dao_acks(domain, rpl_instance_mop(instance))) { 01518 ptr[1] |= RPL_DAO_FLAG_ACK_REQ; 01519 } 01520 ptr[2] = 0; 01521 ptr[3] = dao_sequence; 01522 if (dodagid_flag) { 01523 memcpy(ptr + 4, dodagid, 16); 01524 } 01525 memcpy(ptr + base_size, opts, opts_size); 01526 buffer_data_end_set(buf, ptr + base_size + opts_size); 01527 01528 rpl_control_transmit(domain, cur, ICMPV6_CODE_RPL_DAO, buf, dst); 01529 01530 return ptr[1] & RPL_DAO_FLAG_ACK_REQ; 01531 } 01532 01533 #ifdef HAVE_RPL_DAO_HANDLING 01534 static buffer_t *rpl_control_dao_handler(protocol_interface_info_entry_t *cur, rpl_domain_t *domain, buffer_t *buf, bool multicast) 01535 { 01536 if (buffer_data_length(buf) < 4) { 01537 format_error: 01538 protocol_stats_update(STATS_RPL_MALFORMED_MESSAGE, 1); 01539 return buffer_free(buf); 01540 } 01541 const uint8_t *ptr = buffer_data_pointer(buf); 01542 uint8_t instance_id = ptr[0]; 01543 uint8_t flags = ptr[1]; 01544 uint8_t dao_sequence = ptr[3]; 01545 const uint8_t *dodagid; 01546 tr_info("DAO from %s", trace_ipv6(buf->src_sa .address )); 01547 ptr += 4; 01548 if (flags & RPL_DAO_FLAG_DODAGID) { 01549 if (buffer_data_length(buf) < 4 + 16) { 01550 goto format_error; 01551 } 01552 dodagid = ptr; 01553 ptr += 16; 01554 } else { 01555 dodagid = NULL; 01556 } 01557 01558 rpl_instance_t *instance = rpl_lookup_instance(domain, instance_id, dodagid); 01559 if (!instance) { 01560 protocol_stats_update(STATS_RPL_UNKNOWN_INSTANCE, 1); 01561 return buffer_free(buf); 01562 } 01563 01564 uint16_t opts_len = buffer_data_end(buf) - ptr; 01565 if (!rpl_control_options_well_formed(ptr, opts_len)) { 01566 goto format_error; 01567 } 01568 01569 #if 0 01570 rpl_dodag_t *dodag = rpl_instance_current_dodag(instance); 01571 if (!dodag) { 01572 return buffer_free(buf); 01573 01574 } 01575 uint8_t mode = rpl_dodag_mop(dodag); 01576 switch (mo)!rpl_instance_am_root(instance)) 01577 01578 /* No current processing - pretend to accept */ 01579 uint8_t status = 0; 01580 01581 01582 } 01583 #endif 01584 uint8_t status; 01585 bool reply_ok = rpl_instance_dao_received(instance, buf->src_sa .address , buf->interface ->id, multicast, ptr, opts_len, &status); 01586 01587 /* Ack if requested or non-zero status */ 01588 if (reply_ok && ((flags &RPL_DAO_FLAG_ACK_REQ) || status != 0)) 01589 { 01590 rpl_control_transmit_dao_ack(domain, cur, instance_id, dao_sequence, status, dodagid, buf->src_sa .address ); 01591 } 01592 return buffer_free(buf); 01593 } 01594 #endif // HAVE_RPL_DAO_HANDLING 01595 01596 buffer_t *rpl_control_handler(buffer_t *buf) 01597 { 01598 protocol_interface_info_entry_t *cur = buf->interface ; 01599 rpl_domain_t *domain = cur ? cur->rpl_domain : NULL; 01600 if (!domain) { 01601 tr_warning("RPL control on non-RPL interface"); 01602 return buffer_free(buf); 01603 } 01604 bool multicast = addr_is_ipv6_multicast(buf->dst_sa .address ); 01605 01606 if (addr_is_ipv6_multicast(buf->src_sa .address )) { 01607 protocol_stats_update(STATS_RPL_MALFORMED_MESSAGE, 1); 01608 return buffer_free(buf); 01609 } 01610 01611 switch (buf->options .code ) { 01612 case ICMPV6_CODE_RPL_DIS: 01613 return rpl_control_dis_handler(cur, domain, buf, multicast); 01614 case ICMPV6_CODE_RPL_DIO: 01615 return rpl_control_dio_handler(cur, domain, buf); 01616 #ifdef HAVE_RPL_DAO_HANDLING 01617 case ICMPV6_CODE_RPL_DAO: 01618 return rpl_control_dao_handler(cur, domain, buf, multicast); 01619 #endif 01620 case ICMPV6_CODE_RPL_DAO_ACK: 01621 return rpl_control_dao_ack_handler(cur, domain, buf); 01622 default: 01623 tr_warning("Unknown code 0x%02x", buf->options .code ); 01624 protocol_stats_update(STATS_RPL_MALFORMED_MESSAGE, 1); 01625 return buffer_free(buf); 01626 } 01627 } 01628 01629 #ifdef HAVE_RPL_ROOT 01630 /* Buffer contains ICMP payload, so 4 bytes unused, followed by invoking packet */ 01631 buffer_t *rpl_control_source_route_error_handler(buffer_t *buf, protocol_interface_info_entry_t *cur) 01632 { 01633 if (buffer_data_length(buf) < 40 || !cur->rpl_domain) { 01634 return buf; 01635 } 01636 01637 const uint8_t *target = buffer_data_pointer(buf) + 4 + 24; // Dest in IP header in ICMP invoking packet payload 01638 const uint8_t *transit = buf->src_sa .address ; // Source in IP header of ICMP packet 01639 01640 tr_warn("Source route error: %s->%s", trace_ipv6(transit), trace_ipv6(target)); 01641 /* We can't identify the instance - logically though it's instance-independent. 01642 * If transit can't reach target, that applies to all instances. 01643 */ 01644 ns_list_foreach(rpl_instance_t, instance, &cur->rpl_domain->instances) { 01645 rpl_downward_transit_error(instance, target, transit); 01646 } 01647 01648 return buf; 01649 } 01650 #endif 01651 01652 void rpl_control_fast_timer(uint16_t ticks) 01653 { 01654 ns_list_foreach(rpl_domain_t, domain, &rpl_domains) { 01655 ns_list_foreach(rpl_instance_t, instance, &domain->instances) { 01656 rpl_upward_dio_timer(instance, ticks); 01657 rpl_downward_dao_timer(instance, ticks); 01658 } 01659 } 01660 01661 } 01662 01663 #if 0 01664 static void trace_info_print(const char *fmt, ...) 01665 { 01666 va_list ap; 01667 va_start(ap, fmt); 01668 vtracef(TRACE_LEVEL_INFO, TRACE_GROUP, fmt, ap); 01669 va_end(ap); 01670 } 01671 #endif 01672 void rpl_control_slow_timer(uint16_t seconds) 01673 { 01674 bool purge = rpl_alloc_total > rpl_purge_threshold; 01675 01676 ns_list_foreach(rpl_domain_t, domain, &rpl_domains) { 01677 ns_list_foreach_safe(rpl_instance_t, instance, &domain->instances) { 01678 rpl_control_publish_own_addresses(domain, instance); 01679 rpl_instance_slow_timer(instance, seconds); 01680 rpl_downward_dao_slow_timer(instance, seconds); 01681 /* We purge one item from each instance, so as not to favour one domain or instance */ 01682 if (purge) { 01683 rpl_instance_purge(instance); 01684 } 01685 } 01686 } 01687 01688 #if 0 // If including this, make sure to include the above trace_info_print helper function as well. 01689 static int rpl_print_timer; 01690 if ((rpl_print_timer += seconds) >= 50) { 01691 rpl_print_timer = 0; 01692 void arm_print_routing_table2(void (*print_fn)(const char *fmt, ...)); 01693 protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get(IF_6LoWPAN); 01694 if (cur) { 01695 ipv6_neighbour_cache_print(&cur->ipv6_neighbour_cache, trace_info_print); 01696 } 01697 arm_print_routing_table2(trace_info_print); 01698 rpl_control_print(trace_info_print); 01699 } 01700 #endif 01701 } 01702 01703 rpl_instance_t *rpl_control_enumerate_instances(rpl_domain_t *domain, rpl_instance_t *instance) 01704 { 01705 if (instance) { 01706 return ns_list_get_next(&domain->instances, instance); 01707 } else { 01708 return ns_list_get_first(&domain->instances); 01709 } 01710 } 01711 01712 rpl_instance_t *rpl_control_lookup_instance(rpl_domain_t *domain, uint8_t instance_id, const uint8_t *dodagid) 01713 { 01714 return rpl_lookup_instance(domain, instance_id, dodagid); 01715 } 01716 01717 bool rpl_control_get_instance_dao_target_count(rpl_domain_t *domain, uint8_t instance_id, const uint8_t *dodagid, const uint8_t *prefix, uint16_t *target_count) 01718 { 01719 rpl_instance_t *instance = rpl_lookup_instance(domain, instance_id, dodagid); 01720 if (!instance) { 01721 return false; 01722 } 01723 01724 *target_count = rpl_upward_read_dao_target_list_size(instance, prefix); 01725 return true; 01726 } 01727 01728 /* Backwards-compatibility implementation of net_rpl.h API designed for old implementation */ 01729 bool rpl_control_read_dodag_info(const rpl_instance_t *instance, rpl_dodag_info_t *dodag_info) 01730 { 01731 return rpl_upward_read_dodag_info(instance, dodag_info); 01732 } 01733 01734 const rpl_dodag_conf_t *rpl_control_get_dodag_config(const rpl_instance_t *instance) 01735 { 01736 rpl_dodag_t *dodag = rpl_instance_current_dodag(instance); 01737 if (!dodag) { 01738 return NULL; 01739 } 01740 return rpl_dodag_get_config(dodag); 01741 } 01742 01743 const uint8_t *rpl_control_preferred_parent_addr(const rpl_instance_t *instance, bool global) 01744 { 01745 const rpl_neighbour_t *parent = rpl_instance_preferred_parent(instance); 01746 if (!parent) { 01747 return NULL; 01748 } 01749 if (global) { 01750 return rpl_neighbour_global_address(parent); 01751 } else { 01752 return rpl_neighbour_ll_address(parent); 01753 } 01754 } 01755 01756 uint16_t rpl_control_current_rank(const struct rpl_instance *instance) 01757 { 01758 return rpl_instance_current_rank(instance); 01759 } 01760 01761 01762 static void rpl_domain_print(const rpl_domain_t *domain, route_print_fn_t *print_fn) 01763 { 01764 print_fn("RPL Domain %p", (void *) domain); 01765 ns_list_foreach(rpl_instance_t, instance, &domain->instances) { 01766 rpl_upward_print_instance(instance, print_fn); 01767 rpl_downward_print_instance(instance, print_fn); 01768 } 01769 } 01770 01771 void rpl_control_print(route_print_fn_t *print_fn) 01772 { 01773 print_fn("RPL memory usage %zu", rpl_alloc_total); 01774 ns_list_foreach(rpl_domain_t, domain, &rpl_domains) { 01775 rpl_domain_print(domain, print_fn); 01776 } 01777 } 01778 01779 #ifdef RPL_STRUCTURES_H_ 01780 #error "rpl_structures.h should not be included by rpl_control.c" 01781 #endif 01782 01783 #endif /* HAVE_RPL */
Generated on Tue Jul 12 2022 13:54:47 by
