Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers rpl_control.c Source File

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 */