Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers rpl_downward.c Source File

rpl_downward.c

00001 /*
00002  * Copyright (c) 2015-2017, Arm Limited and affiliates.
00003  * SPDX-License-Identifier: Apache-2.0
00004  *
00005  * Licensed under the Apache License, Version 2.0 (the "License");
00006  * you may not use this file except in compliance with the License.
00007  * You may obtain a copy of the License at
00008  *
00009  *     http://www.apache.org/licenses/LICENSE-2.0
00010  *
00011  * Unless required by applicable law or agreed to in writing, software
00012  * distributed under the License is distributed on an "AS IS" BASIS,
00013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014  * See the License for the specific language governing permissions and
00015  * limitations under the License.
00016  */
00017 
00018 /* rpl_downward.c deals with management of DAO targets, DAO parents, and
00019  * downward routes within an instance.
00020  *
00021  * rpl_domain_t is accessible, but not normally manipulated - all routines in
00022  * this file works on a specific instance.
00023  *
00024  * rpl_instance_t, rpl_dodag_t, rpl_dodag_version_t, rpl_neighbour_t are all accessible.
00025  *
00026  * The rpl_dao_target_t type overloads different needs:
00027  *   1) Non-storing root storage, which needs to record transit addresses.
00028  *   2) Published targets - published either for ourselves or on behalf of
00029  *      connected hosts. Sent to either DAO parents or DODAG root, depending
00030  *      on mode.
00031  *   3) Storing-mode non-owned targets - those we've received from DAO
00032  *      children, and need to forward on.
00033  *
00034  * Flags settings:
00035  *
00036  *   1)  Root non-storing storage:  root=Y   published=N  own=N
00037  *   2)  Published:                 root=N   published=Y  own=Y/N
00038  *   3)  Storing storage:           root=N   published=N  own=N
00039  *
00040  *
00041  * We follow the Path Control logic as follows - we can have up to 8 DAO
00042  * Parents, and they are assigned specific Path Control bits, rather than
00043  * a whole group of parents being assigned to a whole Path Control subfield
00044  * as in RFC 6550. Assignments are derived automatically from the preference
00045  * field set by the objective function, limited by the Path Control Size. There
00046  * is no specific mechanism for the objective function to control DAO parents
00047  * separately from DIO parents.
00048  *
00049  * Examples:
00050  *   Parent prefs      Path Control assignments
00051  *   1                 11111111
00052  *
00053  *   1,2               11000000,00111111
00054  *
00055  *   1,1               10000000,01111111
00056  *
00057  *   1,1,2,3,3         10000000,01000000,00110000,00001000,00000111
00058  *
00059  *   1,1,2             10000000,01000000,00111111
00060  *
00061  *   1,1,1             (treated as 1,1,2)
00062  *
00063  * If a parent is removed in Storing mode, we send it a No-Path for all
00064  * targets. (9.8.4)
00065  *
00066  * If a totally new parent is added to the DAO parent set, we can't really
00067  * do anything if we don't own the target (Storing mode only). I guess we could
00068  * send it an update if it is in a disjoint position?
00069  *
00070  * If we own the target (as we always will Non-Storing), we can trigger a path
00071  * sequence update to change parents - addition or removal.
00072  *
00073  * Targets contain 8-bit bitfields, which indicates which path control bits have
00074  * been registered. Parent choice happens at the instant of registration - we
00075  * just AND together parent and target path control bits.
00076  */
00077 
00078 #include "nsconfig.h"
00079 
00080 #ifdef HAVE_RPL
00081 
00082 #include <string.h>
00083 #include "common_functions.h"
00084 #include "ns_types.h"
00085 #include "ns_list.h"
00086 #include "ns_trace.h"
00087 #include "nsdynmemLIB.h"
00088 #include "randLIB.h"
00089 #include "ip6string.h"
00090 
00091 #include "NWK_INTERFACE/Include/protocol.h"
00092 #include "ipv6_stack/ipv6_routing_table.h"
00093 
00094 #include "net_rpl.h"
00095 #include "RPL/rpl_protocol.h"
00096 #include "RPL/rpl_policy.h"
00097 #include "RPL/rpl_upward.h"
00098 #include "RPL/rpl_downward.h"
00099 #include "RPL/rpl_control.h"
00100 #include "RPL/rpl_data.h"
00101 #include "RPL/rpl_structures.h"
00102 
00103 #define TRACE_GROUP "RPLd"
00104 
00105 #ifdef HAVE_RPL_ROOT
00106 static void rpl_downward_topo_sort_invalidate(rpl_instance_t *instance);
00107 #endif
00108 
00109 #define DEFAULT_DAO_DELAY 10 /* *100ms ticks = 1s */
00110 
00111 //#define MINIMUM_DAO_TARGET_REFRESH (5*60) /* seconds */
00112 
00113 /* Bit <n> of the PC mask */
00114 #define PCBIT(n) (UINT8_C(0x80) >> (n))
00115 
00116 /* The PCS mask */
00117 #define PCSMASK(pcs) ((uint8_t)(0x100 - PCBIT(pcs)))
00118 
00119 
00120 /*
00121  *                                 0 1 2 3 4 5 6 7
00122  *                                +-+-+-+-+-+-+-+-+
00123  *                                |PC1|PC2|PC3|PC4|
00124  *                                +-+-+-+-+-+-+-+-+
00125  *
00126  *          Figure 27: Path Control Preference Subfield Encoding
00127  */
00128 void rpl_downward_convert_dodag_preferences_to_dao_path_control(rpl_dodag_t *dodag)
00129 {
00130     if (!dodag || rpl_dodag_mop(dodag) == RPL_MODE_NO_DOWNWARD) {
00131         return;
00132     }
00133 
00134     rpl_instance_t *instance = dodag->instance;
00135     uint8_t pcs = dodag->config.path_control_size;
00136     uint_fast8_t bit = 0;
00137 
00138     rpl_neighbour_t *last = NULL;
00139     rpl_neighbour_t *neighbour = ns_list_get_first(&instance->candidate_neighbours);
00140     while (neighbour && neighbour->dodag_parent && bit <= pcs) {
00141         rpl_neighbour_t *next = ns_list_get_next(&instance->candidate_neighbours, neighbour);
00142         /* Terminate when we hit a non-DODAG parent */
00143         if (next && !next->dodag_parent) {
00144             next = NULL;
00145         }
00146 
00147         /* If non-storing, neighbours if they don't have a known global address */
00148         if (!neighbour->have_global_address && rpl_dodag_mop(dodag) == RPL_MODE_NON_STORING) {
00149             neighbour = next;
00150             continue;
00151         }
00152 
00153         neighbour->dao_path_control = PCBIT(bit++);
00154         if (bit <= pcs && next && next->dodag_pref > neighbour->dodag_pref && (bit & 1)) {
00155             /* Next neighbour is less-preferred, and would join us in the second
00156              * bit of our subfield. Expand this neighbour to use the second bit,
00157              * so next will be in the next subfield.
00158              */
00159             neighbour->dao_path_control |= PCBIT(bit++);
00160         }
00161         last = neighbour;
00162         neighbour = next;
00163     }
00164 
00165     /* If we didn't fill the Path Control, expand the final neighbour */
00166     if (last) {
00167         while (bit <= pcs) {
00168             last->dao_path_control |= PCBIT(bit++);
00169         }
00170     }
00171 }
00172 
00173 static void rpl_downward_target_refresh(rpl_dao_target_t *target)
00174 {
00175     target->need_seq_inc = true;
00176     target->info.non_root.pc_assigned = 0;
00177     target->info.non_root.pc_assigning = 0;
00178     target->info.non_root.pc_to_retry = 0;
00179     target->info.non_root.path_lifetime = 0;
00180 }
00181 
00182 void rpl_downward_neighbour_gone(rpl_instance_t *instance, rpl_neighbour_t *neighbour)
00183 {
00184     if (neighbour->dao_path_control == 0) {
00185         return;
00186     }
00187     neighbour->old_dao_path_control = neighbour->dao_path_control;
00188     neighbour->dao_path_control = 0;
00189     rpl_downward_process_dao_parent_changes(instance);
00190 }
00191 
00192 void rpl_downward_process_dao_parent_changes(rpl_instance_t *instance)
00193 {
00194     uint8_t mop = rpl_instance_mop(instance);
00195     bool storing;
00196 
00197     switch (mop) {
00198         case RPL_MODE_NON_STORING:
00199             storing = false;
00200             break;
00201         case RPL_MODE_STORING:
00202         case RPL_MODE_STORING_MULTICAST:
00203             storing = true;
00204             break;
00205         default:
00206             return;
00207     }
00208 
00209     bool bits_removed = false;
00210     uint8_t bits_added = 0;
00211     ns_list_foreach(rpl_neighbour_t, neighbour, &instance->candidate_neighbours) {
00212         if (neighbour->old_dao_path_control != neighbour->dao_path_control) {
00213             if (neighbour->old_dao_path_control &~ neighbour->dao_path_control) {
00214                 bits_removed = true;
00215                 break;
00216             } else {
00217                 /* May as well resend all bits for this parent, not just new */
00218                 bits_added |= neighbour->dao_path_control;
00219             }
00220         }
00221     }
00222     tr_debug("removed=%x, added=%x", bits_removed, bits_added);
00223     if (!(bits_removed || bits_added)) {
00224         return;
00225     }
00226 
00227     if (storing) {
00228         /* XXX more complicated - No-Paths to people losing stuff, etc.
00229          * Need to think a bit about what each parent would have had.
00230          * Different handling for stuff we own and stuff we don't. Can
00231          * probably actually unify somewhat, but needs thought.
00232          */
00233     } else {
00234         ns_list_foreach(rpl_dao_target_t, target, &instance->dao_targets) {
00235             if (target->published && target->own) {
00236                 if (bits_removed) {
00237                     /* Simple - just increment Path Sequence and trigger DAO to root */
00238                     rpl_downward_target_refresh(target);
00239                 } else {
00240                     /* Make sure we send the newly-added bits (would previously have been assigned to no-one) */
00241                     target->info.non_root.pc_assigned &= ~bits_added;
00242                 }
00243             }
00244         }
00245         rpl_instance_dao_trigger(instance, 0);
00246     }
00247 }
00248 
00249 rpl_dao_target_t *rpl_create_dao_target(rpl_instance_t *instance, const uint8_t *prefix, uint8_t prefix_len, bool root)
00250 {
00251     rpl_dao_target_t *target = rpl_alloc(sizeof(rpl_dao_target_t));
00252     if (!target) {
00253         tr_warn("RPL DAO overflow (target=%s)", trace_ipv6_prefix(prefix, prefix_len));
00254         return NULL;
00255     }
00256     memset(target, 0, sizeof *target);
00257     bitcopy0(target->prefix, prefix, prefix_len);
00258     target->instance = instance;
00259     target->prefix_len = prefix_len;
00260     target->path_sequence = rpl_seq_init();
00261     target->root = root;
00262 #ifdef HAVE_RPL_ROOT
00263     if (root) {
00264         ns_list_init(&target->info.root.transits);
00265     }
00266     rpl_downward_topo_sort_invalidate(instance);
00267 #endif
00268 
00269     ns_list_add_to_end(&instance->dao_targets, target);
00270     return target;
00271 }
00272 
00273 void rpl_delete_dao_target(rpl_instance_t *instance, rpl_dao_target_t *target)
00274 {
00275     /* XXX For each notified parent, send a No-Path DAO */
00276 
00277     /* TODO - should send a No-Path to root */
00278 
00279     ns_list_remove(&instance->dao_targets, target);
00280 
00281 #ifdef HAVE_RPL_ROOT
00282     if (target->root) {
00283         ns_list_foreach_safe(rpl_dao_root_transit_t, transit, &target->info.root.transits) {
00284             ns_list_remove(&target->info.root.transits, transit);
00285             rpl_free(transit, sizeof *transit);
00286         }
00287         ipv6_route_table_remove_info(-1, ROUTE_RPL_DAO_SR, target);
00288         rpl_downward_topo_sort_invalidate(target->instance);
00289     }
00290 #endif
00291     rpl_free(target, sizeof *target);
00292 }
00293 
00294 rpl_dao_target_t *rpl_instance_lookup_published_dao_target(rpl_instance_t *instance, const uint8_t *prefix, uint8_t prefix_len)
00295 {
00296     ns_list_foreach(rpl_dao_target_t, target, &instance->dao_targets) {
00297         if (target->published && target->prefix_len == prefix_len &&
00298                 bitsequal(target->prefix, prefix, prefix_len)) {
00299             return target;
00300         }
00301     }
00302     return NULL;
00303 }
00304 
00305 rpl_dao_target_t *rpl_instance_lookup_dao_target(rpl_instance_t *instance, const uint8_t *prefix, uint8_t prefix_len)
00306 {
00307     ns_list_foreach(rpl_dao_target_t, target, &instance->dao_targets) {
00308         if (target->prefix_len == prefix_len &&
00309                 bitsequal(target->prefix, prefix, prefix_len)) {
00310             return target;
00311         }
00312     }
00313     return NULL;
00314 }
00315 
00316 rpl_dao_target_t *rpl_instance_match_dao_target(rpl_instance_t *instance, const uint8_t *prefix, uint8_t prefix_len)
00317 {
00318     rpl_dao_target_t *longest = NULL;
00319     int_fast16_t longest_len = -1;
00320 
00321     ns_list_foreach(rpl_dao_target_t, target, &instance->dao_targets) {
00322         if (target->prefix_len >= longest_len && target->prefix_len <= prefix_len &&
00323                 bitsequal(target->prefix, prefix, target->prefix_len)) {
00324             longest = target;
00325             longest_len = target->prefix_len;
00326             if (longest_len == 128) {
00327                 break;
00328             }
00329         }
00330     }
00331     return longest;
00332 }
00333 void rpl_instance_delete_published_dao_target(rpl_instance_t *instance, const uint8_t *prefix, uint8_t prefix_len)
00334 {
00335     rpl_dao_target_t *target = rpl_instance_lookup_published_dao_target(instance, prefix, prefix_len);
00336     if (target) {
00337         rpl_delete_dao_target(instance, target);
00338     }
00339 }
00340 
00341 void rpl_instance_publish_dao_target(rpl_instance_t *instance, const uint8_t *prefix, uint8_t prefix_len, uint32_t valid_lifetime, bool own, bool want_descriptor, uint32_t descriptor)
00342 {
00343     rpl_dao_target_t *target = rpl_instance_lookup_published_dao_target(instance, prefix, prefix_len);
00344     if (target) {
00345         target->lifetime = valid_lifetime;
00346         if (!own) {
00347             /* For non-owned targets, publish triggers a refresh */
00348             rpl_downward_target_refresh(target);
00349             rpl_instance_dao_trigger(instance, 0);
00350         }
00351         return;
00352     }
00353     target = rpl_create_dao_target(instance, prefix, prefix_len, false);
00354     if (!target) {
00355         tr_warn("Failed to publish DAO target %s", trace_ipv6_prefix(prefix, prefix_len));
00356         return;
00357     }
00358     target->interface_id = -1;
00359     target->published = true;
00360     target->own = own;
00361     target->external = !own;
00362     target->lifetime = valid_lifetime;
00363     if (own) {
00364         target->info.non_root.refresh_timer = 0; /* Auto-refresh */
00365     } else {
00366         target->info.non_root.refresh_timer = 0xFFFFFFFF; /* Do not refresh - require republishing */
00367     }
00368     target->descriptor_present = want_descriptor;
00369     target->descriptor = descriptor;
00370     target->path_control = 0xFF; /* Use as much path control as we can (PCS limits) */
00371     /* Path lifetime left as 0 for now - will be filled in on transmission, along with refresh timer */
00372     rpl_instance_dao_trigger(instance, 0);
00373 }
00374 
00375 void rpl_instance_dao_trigger(rpl_instance_t *instance, uint16_t delay)
00376 {
00377     if (delay == 0) {
00378         delay = randLIB_randomise_base(DEFAULT_DAO_DELAY, 0x4000, 0xC000);
00379     }
00380     if (instance->delay_dao_timer == 0 || instance->delay_dao_timer > delay) {
00381         instance->delay_dao_timer = delay;
00382         tr_debug("DAO trigger %" PRIu16, delay);
00383     }
00384 }
00385 
00386 /*
00387  *    0                   1                   2                   3
00388  *    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
00389  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
00390  *   |   Type = 0x05 | Option Length |     Flags     | Prefix Length |
00391  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
00392  *   |                                                               |
00393  *   +                                                               +
00394  *   |                Target Prefix (Variable Length)                |
00395  *   .                                                               .
00396  *   .                                                               .
00397  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
00398  *
00399  *            Figure 25: Format of the RPL Target Option
00400  *
00401  *    0                   1                   2                   3
00402  *    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
00403  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
00404  *   |   Type = 0x09 |Opt Length = 4 |           Descriptor
00405  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
00406  *          Descriptor (cont.)       |
00407  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
00408  *
00409  *       Figure 30: Format of the RPL Target Descriptor Option
00410  */
00411 static uint8_t *rpl_downward_write_target(uint8_t *ptr, rpl_dao_target_t *target)
00412 {
00413     uint8_t byte_len = (target->prefix_len + 7u) / 8u;
00414     *ptr++ = RPL_TARGET_OPTION;
00415     *ptr++ = 2 + byte_len;
00416     *ptr++ = 0; // flags
00417     *ptr++ = target->prefix_len;
00418     bitcopy0(ptr, target->prefix, target->prefix_len);
00419     ptr += byte_len;
00420 
00421     if (target->descriptor_present) {
00422         *ptr++ = RPL_TARGET_DESC_OPTION;
00423         *ptr++ = 4;
00424         ptr = common_write_32_bit(target->descriptor, ptr);
00425     }
00426 
00427     return ptr;
00428 }
00429 /*
00430  *    0                   1                   2                   3
00431  *    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
00432  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
00433  *   |   Type = 0x06 | Option Length |E|    Flags    | Path Control  |
00434  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
00435  *   | Path Sequence | Path Lifetime |                               |
00436  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
00437  *   |                                                               |
00438  *   +                                                               +
00439  *   |                                                               |
00440  *   +                        Parent Address*                        +
00441  *   |                                                               |
00442  *   +                               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
00443  *   |                               |
00444  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
00445  *
00446  *        Figure 26: Format of the Transit Information Option
00447  *
00448  */
00449 static uint8_t *rpl_downward_write_transit(uint8_t *ptr, rpl_dao_target_t *target, uint8_t path_control, const uint8_t *parent, bool no_path)
00450 {
00451     *ptr++ = RPL_TRANSIT_OPTION;
00452     *ptr++ = parent ? 16 + 4 : 4;
00453     *ptr++ = target->external ? TRANSIT_FLAG_EXTERNAL : 0;
00454     *ptr++ = path_control;
00455     *ptr++ = target->path_sequence;
00456     *ptr++ = no_path ? 0 : target->info.non_root.path_lifetime;
00457     if (parent) {
00458         ptr = (uint8_t *) memcpy(ptr, parent, 16) + 16;
00459     }
00460 
00461     return ptr;
00462 }
00463 
00464 static bool rpl_instance_clear_target_pc_to_retry(rpl_instance_t *instance)
00465 {
00466     bool had_retry = false;
00467     ns_list_foreach(rpl_dao_target_t, target, &instance->dao_targets) {
00468         if (!target->root && target->info.non_root.pc_to_retry) {
00469             target->info.non_root.pc_to_retry = 0;
00470             had_retry = true;
00471         }
00472     }
00473 
00474     return had_retry;
00475 }
00476 
00477 /* Find a target that needs updating. For storing mode, after first is found,
00478  * subsequent must be for the same parent.
00479  */
00480 static rpl_dao_target_t *rpl_instance_choose_target_to_assign(rpl_instance_t *instance, bool storing, rpl_neighbour_t **parent, uint8_t *path_control, rpl_dao_target_t *t1)
00481 {
00482 retry:
00483     ns_list_foreach(rpl_dao_target_t, target, &instance->dao_targets) {
00484         if (target->root || target == t1) {
00485             continue;
00486         }
00487 
00488         /* Check if this target has any unassigned path control bits */
00489         uint8_t unassigned_pc = target->path_control & ~(target->info.non_root.pc_assigned|target->info.non_root.pc_assigning|target->info.non_root.pc_to_retry);
00490         if (!unassigned_pc) {
00491             continue;
00492         }
00493 
00494         /* If we are looking for a follow-up target to share transit, transit data must match */
00495         if (t1) {
00496             uint8_t target_seq = target->path_sequence;
00497             if (target->need_seq_inc) {
00498                 target_seq = rpl_seq_inc(target_seq);
00499             }
00500             if (target->external != t1->external || target->own != t1->own ||
00501                     target_seq != t1->path_sequence ||
00502                     target->info.non_root.path_lifetime != t1->info.non_root.path_lifetime) {
00503                 continue;
00504             }
00505         }
00506 
00507         /* unassigned_pc is the total path control needing assignment */
00508         if (!storing) {
00509             /* In non-storing mode, any number of targets+transits can be output to root in 1 DAO */
00510             /* Leave unassigned_pc as the entire path control across all parents */
00511         } else if (*parent == NULL) {
00512             /* In storing mode, need to choose a parent, if we haven't already */
00513             /* This is the very first target for the DAO - we now choose a parent that wants
00514              * the bits, and output that parent's path control so we use it for future targets.
00515              */
00516             ns_list_foreach(rpl_neighbour_t, neighbour, &instance->candidate_neighbours) {
00517                 if (neighbour->dao_path_control & unassigned_pc) {
00518                     unassigned_pc &= neighbour->dao_path_control;
00519                     *path_control = unassigned_pc;
00520                     *parent = neighbour;
00521                     return target;
00522                 }
00523             }
00524         } else {
00525             /* This is not the first target - we must be picking subsequent
00526              * targets with unassigned bits for the parent we chose last time.
00527              */
00528             unassigned_pc &= (*parent)->dao_path_control;
00529             if (!unassigned_pc) {
00530                 continue;
00531             }
00532         }
00533 
00534         /* If looking for a follow-up target, final path control must match */
00535         if (t1) {
00536             if (unassigned_pc != *path_control) {
00537                 continue;
00538             }
00539         } else {
00540             *path_control = unassigned_pc;
00541         }
00542         return target;
00543     }
00544 
00545     if (!t1) {
00546         /* If found nothing on initial search, it would appear we're done. However,
00547          * we were skipping "to_retry" assignments. Clear to_retry flags, and if
00548          * there were any, retry. We currently retry indefinitely (but with
00549          * exponential backoff).
00550          */
00551         if (rpl_instance_clear_target_pc_to_retry(instance)) {
00552             if (instance->dao_attempt < 255) {
00553                 ++instance->dao_attempt;
00554             }
00555             tr_warn("DAO retry, attempt %d", instance->dao_attempt);
00556             goto retry;
00557         }
00558     }
00559     return NULL;
00560 }
00561 
00562 static void rpl_downward_reset_assigning(rpl_instance_t *instance, uint8_t pcs_mask)
00563 {
00564     uint8_t parent_mask = 0;
00565     /* Check to see if we're short of parent mask coverage. If so, remove bits from the mask */
00566     ns_list_foreach(rpl_neighbour_t, neighbour, &instance->candidate_neighbours) {
00567         parent_mask |= neighbour->dao_path_control;
00568     }
00569     pcs_mask &= parent_mask;
00570 
00571     ns_list_foreach(rpl_dao_target_t, target, &instance->dao_targets) {
00572         target->info.non_root.pc_assigning = 0;
00573         /* For ease of processing, we allow target path control to have bits
00574          * beyond the mask. In this pass, we quietly mark those bits as
00575          * "assigned", as if we've sent them to an invisible parent.
00576          */
00577         target->info.non_root.pc_assigned |= (target->path_control & ~pcs_mask);
00578         target->info.non_root.pc_to_retry &= pcs_mask;
00579     }
00580 }
00581 
00582 
00583 /* We are optimised for sending updates to existing targets to current parents;
00584  * we track the state of what information DAO parents have, and manage the
00585  * updates together with message coalescing and ack tracking.
00586  *
00587  * No-Paths are handled separately, and not tracked - we spit out No-Paths
00588  * at the moment targets or parents are deleted, 1 attempt only.
00589  *
00590  * This function only has to deals with updating our active state.
00591  */
00592 void rpl_instance_send_dao_update(rpl_instance_t *instance)
00593 {
00594     instance->delay_dao_timer = 0;
00595 
00596     rpl_dodag_t *dodag = rpl_instance_current_dodag(instance);
00597     if (!dodag || rpl_dodag_am_root(dodag)) {
00598         return;
00599     }
00600 
00601     uint8_t mop = rpl_dodag_mop(dodag);
00602     bool storing;
00603 
00604     switch (mop) {
00605         case RPL_MODE_NON_STORING:
00606             storing = false;
00607             break;
00608         case RPL_MODE_STORING:
00609         case RPL_MODE_STORING_MULTICAST:
00610             storing = true;
00611             break;
00612         default:
00613             return;
00614     }
00615 
00616     if (instance->dao_in_transit) {
00617         // Force current DAO timeout to be cut short, then
00618         // when it times out, it will re-evaluate the situation,
00619         // and come back back here.
00620         uint16_t delay = rpl_policy_initial_dao_ack_wait(instance->domain, mop);
00621         if (instance->dao_retry_timer > delay) {
00622             instance->dao_retry_timer = delay;
00623         }
00624         return;
00625     }
00626 
00627 
00628     /* Which parent this DAO will be for if storing */
00629     rpl_neighbour_t *parent = NULL;
00630 
00631     /* Need our address to publish DAOs of attached hosts */
00632     const uint8_t *our_addr = NULL;
00633     if (!storing) {
00634         ns_list_foreach(rpl_dao_target_t, t, &instance->dao_targets) {
00635             if (t->published && t->own && t->prefix_len == 128) {
00636                 our_addr = t->prefix;
00637                 break;
00638             }
00639         }
00640     }
00641 
00642     /* To avoid packet overflow, we set a fairly conservative limit of how
00643      * many targets to put in a message.
00644      *
00645      * For storing mode, format is:
00646      *  Base (4-20)
00647      *  //Target (4-20, typically 20)
00648      *  |\Descriptor (0-6)
00649      *  |(^Repeat if more targets with same transit info)
00650      *  \ Transit (6)
00651      *  (^ Repeat if more targets for same parent, with different transit info)
00652      *
00653      * For non-storing mode, format is:
00654      *  Base
00655      *  //Target (4-20, typically 20)
00656      *  |\Descriptor (0-6)
00657      *  |(^Repeat if more targets with same transit info)
00658      *  | Transit for parent 1 (22)
00659      *  | Transit for parent 2 (22)
00660      *  \ Transit...           (22) (max 8 = 176 per target set)
00661      *  (^ Repeat if more targets with different transit info/parents)
00662      */
00663 
00664 
00665     uint8_t *opts = ns_dyn_mem_temporary_alloc(1280);
00666     if (!opts) {
00667         rpl_instance_dao_trigger(instance, 0);
00668         return;
00669     }
00670     uint8_t *ptr = opts;
00671 
00672     rpl_downward_reset_assigning(instance, PCSMASK(dodag->config.path_control_size));
00673 
00674     ns_list_foreach(rpl_dao_target_t, t, &instance->dao_targets) {
00675         /* Self-published targets can defer path lifetime choice */
00676         if (t->info.non_root.path_lifetime == 0) {
00677             uint32_t lifetime = t->lifetime;
00678             const rpl_dodag_conf_t *conf = rpl_dodag_get_config(dodag);
00679             uint16_t unit = conf->lifetime_unit;
00680             uint8_t def = conf->default_lifetime;
00681             if (lifetime != 0xFFFFFFFF) {
00682                 lifetime = (lifetime + unit - 1) / unit;
00683             }
00684             if (lifetime > def) {
00685                 lifetime = def;
00686             }
00687             t->info.non_root.path_lifetime = lifetime;
00688         }
00689     }
00690 
00691 
00692     /* We keep going until size exceeds 768. This gives plenty of slop to fit
00693      * in a 1280-byte packet.
00694      */
00695     while (ptr < opts + 768) {
00696         uint8_t path_control;
00697         /* Find a target that needs an update - after the first, it must be for the current parent */
00698         rpl_dao_target_t *target = rpl_instance_choose_target_to_assign(instance, storing, &parent, &path_control, NULL);
00699         if (!target) {
00700             break;
00701         }
00702 
00703         /* Stupid error case - can't publish non-owned addresses if we don't know our own address */
00704         if (!storing && !target->own && !our_addr) {
00705             target->info.non_root.pc_assigned |= path_control;
00706             continue;
00707         }
00708 
00709         if (target->need_seq_inc) {
00710             target->path_sequence = rpl_seq_inc(target->path_sequence);
00711             target->need_seq_inc = false;
00712         }
00713 
00714         ptr = rpl_downward_write_target(ptr, target);
00715         target->info.non_root.pc_assigning = path_control;
00716 
00717         /* Then find more targets with the same transit info - can compress */
00718         while (ptr < opts + 768) {
00719             rpl_dao_target_t *t2 = rpl_instance_choose_target_to_assign(instance, storing, &parent, &path_control, target);
00720             if (!t2) {
00721                 break;
00722             }
00723             t2->path_sequence = target->path_sequence;
00724             t2->need_seq_inc = false;
00725             t2->info.non_root.pc_assigning = path_control;
00726             ptr = rpl_downward_write_target(ptr, t2);
00727         }
00728 
00729         /* Then output the transit information for the original target */
00730         if (storing) {
00731             /* Just one transit info */
00732             ptr = rpl_downward_write_transit(ptr, target, path_control, NULL, false);
00733         } else if (target->own) {
00734             /* One transit info for each DAO parent */
00735             ns_list_foreach(rpl_neighbour_t, neighbour, &instance->candidate_neighbours) {
00736                 if (neighbour->dao_path_control & path_control) {
00737                     ptr = rpl_downward_write_transit(ptr, target, neighbour->dao_path_control & path_control, neighbour->global_address, false);
00738                 }
00739             }
00740         } else {
00741             /* Attached host - single transit is us */
00742             ptr = rpl_downward_write_transit(ptr, target, path_control, our_addr, false);
00743         }
00744     }
00745 
00746     if (ptr == opts) {
00747         /* Had nothing... */
00748         ns_dyn_mem_free(opts);
00749         return;
00750     }
00751 
00752     const uint8_t *dst;
00753     protocol_interface_info_entry_t *cur;
00754     if (storing) {
00755         dst = parent->ll_address;
00756         cur = protocol_stack_interface_info_get_by_id(parent->interface_id);
00757     } else {
00758         dst = dodag->id;
00759         cur = NULL;
00760     }
00761 
00762     bool need_ack = rpl_control_transmit_dao(instance->domain, cur, instance, instance->id, instance->dao_sequence, dodag->id, opts, ptr - opts, dst);
00763     ns_dyn_mem_free(opts);
00764 
00765     instance->dao_sequence_in_transit = instance->dao_sequence;
00766     instance->dao_sequence = rpl_seq_inc(instance->dao_sequence);
00767     instance->requested_dao_ack = need_ack;
00768     instance->dao_in_transit = true;
00769     if (instance->dao_attempt < 16) {
00770         uint32_t t = (uint32_t) rpl_policy_initial_dao_ack_wait(instance->domain, mop) << instance->dao_attempt;
00771         t = randLIB_randomise_base(t, 0x4000, 0xC000);
00772         instance->dao_retry_timer = t <= 0xffff ? t : 0xffff;
00773     } else {
00774         instance->dao_retry_timer = 0xffff;
00775     }
00776     tr_info("DAO tx %u seq attempts %u retry-timer %u", instance->dao_sequence_in_transit,instance->dao_attempt, instance->dao_retry_timer);
00777 }
00778 
00779 #if 0
00780 /* This only sends a specific No-Path for one target, to one neighbour, in storing mode */
00781 void rpl_instance_send_dao_no_path(rpl_instance_t *instance, rpl_dao_target_t *target, rpl_neighbour_t *neighbour)
00782 {
00783     //rpl_control_transmit(domain, NULL, ICMPV6_CODE_RPL_DAO, buf, dst);
00784     uint8_t dodagid = rpl_instance_id_is_local(instance->id) ? RPL_DAO_FLAG_DODAGID : 0;
00785     uint8_t base_size = dodagid ? 4 + 16 : 4;
00786     uint16_t opts_size = 20 + 6 + 6; /* Worst case - Target/Desc/Transit */
00787     buffer_t *buf = buffer_get(base_size + opts_size);
00788     if (!buf) {
00789         /* Retrigger? */
00790         return;
00791     }
00792     uint8_t *ptr = buffer_data_pointer(buf);
00793 
00794     ptr[0] = instance->id;
00795     ptr[1] = dodagid;
00796     ptr[2] = 0;
00797     ptr[3] = instance->dao_sequence = rpl_seq_inc(instance->dao_sequence);
00798     if (dodagid) {
00799         memcpy(ptr + 4, dodag->id, 16);
00800         ptr += 16;
00801     }
00802     ptr = rpl_downward_write_target(ptr, target);
00803     ptr = rpl_downward_write_transit(ptr, target, path_control?, NULL, false);
00804     memcpy(buf + base_size, ptr, opts_size);
00805     const uint8_t *dst;
00806     if (storing) {
00807         dst = get_parent_ll_address(parent_idx);
00808     } else {
00809         dst = dodag->id;
00810     }
00811     rpl_control_transmit(domain, NULL, ICMPV6_CODE_RPL_DAO, buf, neighbour->ll_address);
00812 }
00813 #endif
00814 
00815 #ifdef HAVE_RPL_ROOT
00816 static uint_fast8_t rpl_downward_path_control_to_preference(uint8_t pc)
00817 {
00818     if (pc >= 0x40) {
00819         return 1;
00820     } else if (pc >= 0x10) {
00821         return 2;
00822     } else if (pc >= 0x04) {
00823         return 3;
00824     } else {
00825         return 4;
00826     }
00827 }
00828 
00829 static rpl_dao_root_transit_t *rpl_downward_add_root_transit(rpl_dao_target_t *target, const uint8_t parent[16], uint8_t path_control)
00830 {
00831     //rpl_dao_root_transit_t *old_first = ns_list_get_first(&target->info.root.transits);
00832     rpl_dao_root_transit_t *transit = NULL;
00833     ns_list_foreach(rpl_dao_root_transit_t, t, &target->info.root.transits) {
00834         if (addr_ipv6_equal(t->transit, parent)) {
00835             ns_list_remove(&target->info.root.transits, t);
00836             transit = t;
00837             /* Updating existing transit - invalidates costs only */
00838             rpl_downward_paths_invalidate(target->instance);
00839             break;
00840         }
00841     }
00842 
00843     if (!transit) {
00844         transit = rpl_alloc(sizeof(rpl_dao_root_transit_t));
00845         if (!transit) {
00846             tr_warn("RPL DAO overflow (target=%s,transit=%s)", trace_ipv6_prefix(target->prefix, target->prefix_len), trace_ipv6(parent));
00847             goto out;
00848         }
00849         transit->path_control = 0;
00850         /* A new transit invalidates the topo sort */
00851         rpl_downward_topo_sort_invalidate(target->instance);
00852     }
00853 
00854     transit->target = target;
00855     transit->path_control |= path_control;
00856     /* Initial transit cost is 1-4, depending on preference in Path Control.
00857      * Source routing errors from intermediate nodes may increase this. For
00858      * directly connected nodes, rpl_downward_compute_paths asks policy
00859      * to modify according to ETX (or whatever).
00860      */
00861     transit->cost = rpl_downward_path_control_to_preference(transit->path_control);
00862 
00863     memcpy(transit->transit, parent, 16);
00864     ns_list_add_to_end(&target->info.root.transits, transit);
00865 
00866 out:
00867     return ns_list_get_first(&target->info.root.transits);
00868 }
00869 
00870 static rpl_dao_target_t *rpl_downward_delete_root_transit(rpl_dao_target_t *target, rpl_dao_root_transit_t *transit)
00871 {
00872     ns_list_remove(&target->info.root.transits, transit);
00873     rpl_free(transit, sizeof *transit);
00874     if (ns_list_is_empty(&target->info.root.transits)) {
00875         rpl_delete_dao_target(target->instance, target);
00876         return NULL;
00877     }
00878 
00879     rpl_downward_topo_sort_invalidate(target->instance);
00880     return target;
00881 }
00882 
00883 void rpl_downward_transit_error(rpl_instance_t *instance, const uint8_t *target_addr, const uint8_t *transit_addr)
00884 {
00885     ns_list_foreach_safe(rpl_dao_target_t, target, &instance->dao_targets) {
00886         if (!target->root) {
00887             continue;
00888         }
00889         if (!bitsequal(target_addr, target->prefix, target->prefix_len)) {
00890             continue;
00891         }
00892         ns_list_foreach_safe(rpl_dao_root_transit_t, transit, &target->info.root.transits) {
00893             if (addr_ipv6_equal(transit_addr, transit->transit)) {
00894                 /* 4 bit Path Control gives us an initial 1-4 cost. We then add something for every error. */
00895                 /* This should make lowest path cost algorithm cycle through alternatives */
00896                 /* When the DAO is refreshed, the cost is reset, so we forget accumulated errors. */
00897                 if (transit->cost < 0xFFFC) {
00898                     transit->cost += 4;
00899                 } else {
00900                     transit->cost = 0xFFFF;
00901                 }
00902                 rpl_downward_paths_invalidate(instance);
00903                 instance->srh_error_count++;
00904                 if (rpl_policy_dao_trigger_after_srh_error(instance->domain, (protocol_core_monotonic_time - instance->last_dao_trigger_time) / 10, instance->srh_error_count, ns_list_count(&instance->dao_targets))) {
00905                     rpl_instance_increment_dtsn(instance);
00906                 }
00907                 break;
00908             }
00909         }
00910     }
00911 }
00912 #endif // HAVE_RPL_ROOT
00913 
00914 #ifdef HAVE_RPL_DAO_HANDLING
00915 static bool rpl_downward_process_targets_for_transit(rpl_dodag_t *dodag, bool storing, const uint8_t *src, int8_t interface_id, const uint8_t *target_start, const uint8_t *target_end, const uint8_t *transit_opt, bool *new_info, uint8_t *status)
00916 {
00917     (void) status;
00918     const uint8_t *parent;
00919     /* Check transit length */
00920     if (storing) {
00921         if (transit_opt[1] != 4) {
00922             return false;
00923         }
00924         parent = NULL;
00925     } else {
00926         if (transit_opt[1] != 20) {
00927             return false;
00928         }
00929         parent = transit_opt + 6;
00930     }
00931     bool external = transit_opt[2] & TRANSIT_FLAG_EXTERNAL;
00932     uint8_t path_control = transit_opt[3];
00933     uint8_t path_sequence = transit_opt[4];
00934     uint8_t path_lifetime = transit_opt[5];
00935 
00936     uint32_t lifetime;
00937     if (path_lifetime == 0xFF) {
00938         lifetime = 0xFFFFFFFF;
00939     } else {
00940         lifetime = (uint32_t) path_lifetime * dodag->config.lifetime_unit;
00941     }
00942 
00943     rpl_dao_target_t *last_target = NULL;
00944     while (target_start < target_end) {
00945         switch (target_start[0]) {
00946             case RPL_TARGET_OPTION:
00947             {
00948                 last_target = NULL;
00949                 uint8_t prefix_len = target_start[3];
00950                 if (prefix_len > 128 || prefix_len > (target_start[1] - 2) * 8) {
00951                     return false;
00952                 }
00953                 const uint8_t *prefix = target_start + 4;
00954                 rpl_dao_target_t *target = rpl_instance_lookup_dao_target(dodag->instance, prefix, prefix_len);
00955                 if (target) {
00956                     /* Ignore DAOs for targets we're publishing ourselves */
00957                     if (target->published) {
00958                         break;
00959                     }
00960                     /* No-Paths are special: version number isn't significant */
00961                     if (path_lifetime == 0) {
00962                         tr_info("No-Path %s->%s", parent ? trace_ipv6(parent) : "", trace_ipv6_prefix(prefix, prefix_len));
00963                         if (storing) {
00964                             ipv6_route_delete_with_info(prefix, prefix_len, interface_id, src, ROUTE_RPL_DAO, target, 0);
00965                             /* If we have no DAO routes left for this target, kill it (we don't track who sends individual
00966                              * DAOs in our target database - the only record we have is in the system routing table
00967                              */
00968                             if (!ipv6_route_lookup_with_info(prefix, prefix_len, interface_id, NULL, ROUTE_RPL_DAO, target, 0)) {
00969                                 rpl_delete_dao_target(dodag->instance, target);
00970                                 *new_info = true;
00971                             }
00972                         } else {
00973                             ns_list_foreach(rpl_dao_root_transit_t, transit, &target->info.root.transits) {
00974                                 if (addr_ipv6_equal(transit->transit, parent)) {
00975                                     target = rpl_downward_delete_root_transit(target, transit);
00976                                     *new_info = true;
00977                                     break;
00978                                 }
00979                             }
00980                         }
00981                         /* No more processing on this target - go to next option */
00982                         break;
00983                     }
00984                     /* A real path. Compare path sequence. */
00985                     rpl_cmp_t seq_cmp = rpl_seq_compare(path_sequence, target->path_sequence);
00986 
00987                     bool accept;
00988                     if (storing) {
00989                         /* For storing, follow the letter of spec. Can't afford for old route propagation to happen. */
00990                         accept = seq_cmp & (RPL_CMP_GREATER|RPL_CMP_EQUAL);
00991                     } else {
00992                         /* Lollipop counters don't necessarily work brilliantly after reboot - the path
00993                          * sequence causes more problems than it solves for non-storing modes, where it's
00994                          * the actual target owner sending the info. We don't have to worry about the
00995                          * network storing stale data. So we're more flexible.
00996                          */
00997                         if (path_sequence >= 128) {
00998                             /* Always accept anything with sequence in the lollipop counter restart region */
00999                             accept = true;
01000                             /* Also, we always refresh lifetime, even if sequence number is the same as stored */
01001                             target->lifetime = lifetime;
01002                         } else if (external) {
01003                             /* ZigBee IP requires external targets to use latest info and ignore sequence -
01004                              * publishers can't really keep them in sync. We go along with this.
01005                              */
01006                             accept = true;
01007                             target->lifetime = lifetime;
01008                         } else {
01009                             accept = seq_cmp & (RPL_CMP_GREATER|RPL_CMP_EQUAL);
01010                         }
01011                     }
01012                     if (!accept) {
01013                         tr_info("Ignoring stale path %s->%s (seq=%d vs %d)", parent ? trace_ipv6(parent) : "", trace_ipv6_prefix(prefix, prefix_len), path_sequence, target->path_sequence);
01014                         break;
01015                     }
01016                     /* If path sequence is different, we clear existing transits for this target */
01017                     if (!(seq_cmp & RPL_CMP_EQUAL)) {
01018                         if (target->root) {
01019                             ns_list_foreach_safe(rpl_dao_root_transit_t, transit, &target->info.root.transits) {
01020                                 ns_list_remove(&target->info.root.transits, transit);
01021                                 rpl_free(transit, sizeof *transit);
01022                             }
01023                         }
01024                         if (storing) {
01025                             ipv6_route_table_remove_info(-1, ROUTE_RPL_DAO, target);
01026                         }
01027                         target->path_control = 0;
01028                         target->path_sequence = path_sequence;
01029                         target->lifetime = lifetime;
01030                         *new_info = true;
01031                     }
01032                     /* Then we proceed to add this transit to the target below */
01033                 } else if (path_lifetime != 0) {
01034                     target = rpl_create_dao_target(dodag->instance, prefix, prefix_len, !storing);
01035                     if (target) {
01036                         target->path_sequence = path_sequence;
01037                         target->lifetime = lifetime;
01038                     }
01039                 }
01040 
01041                 /* No-Paths don't reach here - we break out above */
01042                 if (target) {
01043                     if (path_control &~ target->path_control) {
01044                         target->path_control |= path_control;
01045                         *new_info = true;
01046                     }
01047                     target->external = external;
01048                     target->interface_id = interface_id;
01049                     if (storing) {
01050                         target->info.non_root.path_lifetime = path_lifetime;
01051                     }
01052 
01053                     if (storing) {
01054                         /* In Storing mode, add a route immediately */
01055                         ipv6_route_add_with_info(prefix, prefix_len, interface_id, src, ROUTE_RPL_DAO, target, 0, target->lifetime, 0);
01056                     } else {
01057                         rpl_dao_root_transit_t *transit = rpl_downward_add_root_transit(target, parent, path_control);
01058 #if 0
01059                         /* In Non-Storing mode, add the transit to the target, and we'll re-evaluate system routes later */
01060                         ipv6_route_table_remove_info(-1, ROUTE_RPL_DAO_SR, target);
01061                         if (transit_opt) {
01062                             if (protcol_interface_address_compare(NULL, parent) == 0) {
01063                                 /* If we're transit, it's on-link */
01064                                 ipv6_route_add_with_info(prefix, prefix_len, interface_id, NULL, ROUTE_RPL_DAO_SR, target, 0, target->lifetime, 0);
01065                             } else {
01066                                 ipv6_route_add_with_info(prefix, prefix_len, interface_id, parent, ROUTE_RPL_DAO_SR, target, 0, target->lifetime, 0);
01067                             }
01068                         }
01069 #else
01070                         if (transit) {
01071                             ipv6_route_add_with_info(prefix, prefix_len, interface_id, ADDR_UNSPECIFIED, ROUTE_RPL_DAO_SR, target, 0, target->lifetime, 0);
01072                         }
01073 #endif
01074                     }
01075                 }
01076 
01077                 last_target = target;
01078                 break;
01079             }
01080             case RPL_TARGET_DESC_OPTION:
01081                 if (target_start[1] == 4 && last_target) {
01082                     last_target->descriptor_present = true;
01083                     last_target->descriptor = common_read_32_bit(target_start + 2);
01084                 }
01085                 break;
01086             case RPL_PAD1_OPTION:
01087                 target_start++;
01088                 continue;
01089         }
01090         target_start += 2 + target_start[1];
01091     }
01092 
01093     return true;
01094 }
01095 #endif // HAVE_RPL_DAO_HANDLING
01096 
01097 #ifdef HAVE_RPL_ROOT
01098 /* Link the graph ready for routing. "Canonical" database information stores
01099  * transits per target - in effect edges from children to parents.
01100  * For our path finding we need to match transits by prefix - eg all 2002::xx
01101  * transits might go via one 2002::/64 target - and we want to turn it around
01102  * so that our edges point from parents to children.
01103  *
01104  * This fills in (from scratch):
01105  *
01106  *     transit::parent   :-> matched target, or NULL for disconnected/DODAG root (us)
01107  *
01108  *     target::connected :=  true for targets directly connected to DODAG root
01109  *
01110  *     target::info.root.children
01111  * and instance::root_children    := list of transits with this target/root as parent
01112  *
01113  *     target::info.root.cost := number of transits connected to parent targets (connections to root not included)
01114  */
01115 static void rpl_downward_link_transits_to_targets(rpl_instance_t *instance)
01116 {
01117     ns_list_init(&instance->root_children);
01118     ns_list_foreach(rpl_dao_target_t, target, &instance->dao_targets) {
01119         target->info.root.cost = 0;
01120         target->connected = false;
01121         ns_list_init(&target->info.root.children);
01122     }
01123     ns_list_foreach(rpl_dao_target_t, target, &instance->dao_targets) {
01124         ns_list_foreach(rpl_dao_root_transit_t, transit, &target->info.root.transits) {
01125             if (protcol_interface_address_compare(NULL, transit->transit) == 0) {
01126                 /* It points to us (the DODAG root) - mark this with NULL */
01127                 transit->parent = NULL;
01128                 target->connected = true;
01129                 /* Links to the root don't count as incoming transits */
01130                 ns_list_add_to_end(&instance->root_children, transit);
01131             } else {
01132                 transit->parent = rpl_instance_match_dao_target(instance, transit->transit, 128);
01133                 if (transit->parent) {
01134                     target->info.root.cost++;
01135                     ns_list_add_to_end(&transit->parent->info.root.children, transit);
01136                 }
01137             }
01138          }
01139     }
01140 }
01141 
01142 /* Subroutine for topo sort - an edge has been removed, either because the
01143  * parent is moved to the sorted list, or we're breaking a loop. Update
01144  * the "incoming edges" count in the child, and maybe move it to the top nodes list.
01145  */
01146 static void rpl_downward_topo_sort_edge_removed(rpl_dao_root_transit_t *transit, rpl_dao_target_list_t *graph, rpl_dao_target_list_t *top_nodes)
01147 {
01148     rpl_dao_target_t *child = transit->target;
01149 
01150     if (child->info.root.cost > 0) {
01151         child->info.root.cost--;
01152     } else {
01153         tr_err("topo sort count error");
01154     }
01155     /* If this child has no more incoming, move it onto the "top nodes" list */
01156     if (child->info.root.cost == 0) {
01157         ns_list_remove(graph, child);
01158         ns_list_add_to_end(top_nodes, child);
01159     }
01160 }
01161 
01162 static void rpl_downward_topo_sort_break_loop(rpl_dao_target_list_t *graph, rpl_dao_target_list_t *top_nodes)
01163 {
01164     rpl_dao_root_transit_t *kill_transit = NULL;
01165 
01166     /* Don't expect this to happen much, so not particularly optimised - we kill 1 transit to break the loop */
01167     /* First choose a target with the most transits - we want to delete spare ones. */
01168     ns_list_foreach(rpl_dao_target_t, target, graph) {
01169         ns_list_foreach(rpl_dao_root_transit_t, transit, &target->info.root.children) {
01170             if (!kill_transit) {
01171                 goto kill_candidate;
01172             }
01173             /* Prefer to delete transits to already-connected targets. In a
01174              * simple scenario with one loop, for example:
01175              *
01176              *     Root--->A--->B--->C--->D
01177              *                   ^------ /
01178              *
01179              * the initial pass will prune to:
01180              *
01181              *                  B--->C--->D
01182              *                   ^-------/
01183              *
01184              * and only B will be marked "connected". D->B is the link to
01185              * kill to get everyone else connected. (Deleting B->C would
01186              * leave C unconnected. Deleting C->D would leave D unconnected.)
01187              *
01188              * With alternate paths like:
01189              *
01190              *              /--------v
01191              *     Root--->A--->B--->C--->D
01192              *                   ^------ /
01193              *
01194              * it would prune to
01195              *
01196              *                  B--->C--->D
01197              *                   ^------ /
01198              *
01199              * but this time both B and C would be connected. Deleting
01200              * either D->B or B->C would result in valid acyclic graphs, although
01201              * an optimal link might be lost.
01202              *
01203              *              /--------v
01204              *     Root--->A--->B--->C--->D
01205              *
01206              *              /--------v
01207              *     Root--->A--->B    C--->D
01208              *                   ^-------/
01209              */
01210             if (!kill_transit->target->connected && transit->target->connected) {
01211                 goto kill_candidate;
01212             } else if (kill_transit->target->connected && !transit->target->connected) {
01213                 continue;
01214             }
01215 
01216             /* Prefer to kill a higher-cost link */
01217             if (kill_transit->cost < transit->cost) {
01218                 goto kill_candidate;
01219             } else if (kill_transit->cost > transit->cost) {
01220                 continue;
01221             }
01222         kill_candidate:
01223             kill_transit = transit;
01224         }
01225     }
01226 
01227     /* Hopefully we killed found transit to a connected node to kill. */
01228     /* If we didn't, it means we're on an isolated island, so we're dooomed anyway... */
01229 
01230     /* This removes it from our routing graph, but not from the master database */
01231     ns_list_remove(&kill_transit->parent->info.root.children, kill_transit);
01232     rpl_downward_topo_sort_edge_removed(kill_transit, graph, top_nodes);
01233 }
01234 
01235 /* Topologically sort instance->dao_targets - closest to border router placed at start */
01236 static void rpl_downward_topo_sort(rpl_instance_t *instance)
01237 {
01238     if (instance->root_topo_sort_valid) {
01239         return;
01240     }
01241 
01242     rpl_downward_link_transits_to_targets(instance);
01243 
01244     rpl_dao_target_list_t sorted = NS_LIST_INIT(sorted);
01245     rpl_dao_target_list_t top_nodes = NS_LIST_INIT(top_nodes);
01246 
01247     /* Find all the topmost targets - most should have been marked "connected", ie they
01248      * have exactly 1 link to the DODAG root. Some may be disconnected. */
01249     ns_list_foreach_safe(rpl_dao_target_t, target, &instance->dao_targets) {
01250         if (target->info.root.cost == 0) {
01251             ns_list_remove(&instance->dao_targets, target);
01252             ns_list_add_to_end(&top_nodes, target);
01253         }
01254     }
01255 
01256 retry_after_loop_break:;
01257     /* Run the sort - targets are pulled off 'instance->dao_targets', and placed onto 'sorted' */
01258 
01259     rpl_dao_target_t *target;
01260     while ((target = ns_list_get_first(&top_nodes)) != NULL) {
01261         /* Take any topmost node, place on the end of the sorted list */
01262         ns_list_remove(&top_nodes, target);
01263         ns_list_add_to_end(&sorted, target);
01264 
01265         /* Decrement incoming link count on all children */
01266         ns_list_foreach(rpl_dao_root_transit_t, transit, &target->info.root.children) {
01267             rpl_downward_topo_sort_edge_removed(transit, &instance->dao_targets, &top_nodes);
01268             /* If this node is connected, the child is connected */
01269             if (target->connected) {
01270                 transit->target->connected = true;
01271             }
01272 
01273         }
01274     }
01275 
01276     if (!ns_list_is_empty(&instance->dao_targets)) {
01277         /* Didn't manage to empty the graph, so we have a loop - not a DAG */
01278         do {
01279             rpl_downward_topo_sort_break_loop(&instance->dao_targets, &top_nodes);
01280         } while (ns_list_is_empty(&top_nodes));
01281         goto retry_after_loop_break;
01282     }
01283 
01284     /* Transfer sorted list back onto instance (dao_targets must be empty at this point) */
01285     ns_list_concatenate(&instance->dao_targets, &sorted);
01286     instance->root_topo_sort_valid = true;
01287 }
01288 
01289 /* Call when topo sort may have changed (or child links broken) - this invalidates everything */
01290 static void rpl_downward_topo_sort_invalidate(rpl_instance_t *instance)
01291 {
01292     instance->root_topo_sort_valid = false;
01293     rpl_downward_paths_invalidate(instance);
01294 }
01295 
01296 static void rpl_downward_update_path_cost_to_children(rpl_dao_root_transit_children_list_t *children, uint16_t parent_cost)
01297 {
01298     ns_list_foreach(rpl_dao_root_transit_t, transit, children) {
01299         rpl_dao_target_t *child = transit->target;
01300         uint16_t transit_cost = transit->cost;
01301         /* For directly-connected paths, modify for ETX or similar */
01302         if (parent_cost == 0 && child->prefix_len == 128) {
01303             transit_cost = rpl_policy_modify_downward_cost_to_root_neighbour(child->instance->domain, child->interface_id, child->prefix, transit->cost);
01304         }
01305         if (child->info.root.cost > parent_cost + transit_cost) {
01306             /* Note new best cost to child, and make this transit the child's first/best */
01307             child->info.root.cost = parent_cost + transit_cost;
01308             if (transit != ns_list_get_first(&child->info.root.transits)) {
01309                 ns_list_remove(&child->info.root.transits, transit);
01310                 ns_list_add_to_start(&child->info.root.transits, transit);
01311             }
01312         }
01313     }
01314 }
01315 
01316 void rpl_downward_compute_paths(rpl_instance_t *instance)
01317 {
01318     if (instance->root_paths_valid) {
01319         return;
01320     }
01321 
01322     /* First get targets into a topological sort - also breaks loops */
01323     rpl_downward_topo_sort(instance);
01324 
01325     ns_list_foreach(rpl_dao_target_t, target, &instance->dao_targets) {
01326         target->info.root.cost = 0xFFFFFFFF;
01327     }
01328 
01329     /* First process the direct root->child links, giving inital link costs */
01330     rpl_downward_update_path_cost_to_children(&instance->root_children, 0);
01331 
01332     /* Now process every node in turn */
01333     ns_list_foreach(rpl_dao_target_t, target, &instance->dao_targets) {
01334         /* Update connected flag - could be invalid due to node removal that didn't redo topo sort */
01335         target->connected = target->info.root.cost != 0xFFFFFFFF;
01336         if (target->connected) {
01337             rpl_downward_update_path_cost_to_children(&target->info.root.children, target->info.root.cost);
01338         }
01339     }
01340 
01341     instance->root_paths_valid = true;
01342 }
01343 
01344 /* Called when path costs may have changed (but not topo sort) */
01345 void rpl_downward_paths_invalidate(rpl_instance_t *instance)
01346 {
01347     instance->root_paths_valid = false;
01348     rpl_data_sr_invalidate();
01349 }
01350 #endif // HAVE_RPL_ROOT
01351 
01352 #ifdef HAVE_RPL_DAO_HANDLING
01353 bool rpl_instance_dao_received(rpl_instance_t *instance, const uint8_t src[16], int8_t interface_id, bool multicast, const uint8_t *opts, uint16_t opts_len, uint8_t *status)
01354 {
01355     rpl_dodag_t *dodag = rpl_instance_current_dodag(instance);
01356     if (!dodag) {
01357         return false;
01358     }
01359     if (multicast) {
01360         /* We don't handle multicast DAOs at all yet */
01361         return false;
01362     }
01363     bool storing;
01364     switch (rpl_dodag_mop(dodag)) {
01365         default:
01366         case RPL_MODE_NO_DOWNWARD:
01367             return false;
01368         case RPL_MODE_NON_STORING:
01369             if (!rpl_dodag_am_root(dodag) || addr_is_ipv6_link_local(src)) {
01370                 return false;
01371             }
01372             storing = false;
01373             break;
01374         case RPL_MODE_STORING:
01375         case RPL_MODE_STORING_MULTICAST:
01376             if (instance->current_rank == RPL_RANK_INFINITE || !addr_is_ipv6_link_local(src)) {
01377                 return false;
01378             }
01379             storing = true;
01380             break;
01381     }
01382 
01383     const uint8_t *start = opts, *end = opts + opts_len;
01384 
01385     /* Basic format is ("group of targets", "group of transits"), repeated.
01386      * All the transits apply to all the preceding targets. So parsing is:
01387      *    1) When we see next target, and target group is closed, remember start of target group, open end.
01388      *    2) When we see a transit, mark end of target group if not already closed.
01389      *    3) Then for any transit, process the entire target group.
01390      */
01391     const uint8_t *target_start = NULL, *target_end = opts;
01392 
01393     bool new_info = false;
01394     *status = 0;
01395 
01396     while (start < end) {
01397         switch (start[0]) {
01398             case RPL_TARGET_OPTION:
01399                 if (target_end) {
01400                     target_start = start;
01401                     target_end = NULL;
01402                 }
01403                 break;
01404             case RPL_TRANSIT_OPTION:
01405                 if (target_start) {
01406                     if (!target_end) {
01407                         target_end = start;
01408                     }
01409                     rpl_downward_process_targets_for_transit(dodag, storing, src, interface_id, target_start, target_end, start, &new_info, status);
01410                 } else {
01411                     tr_warn("Transit without Targets");
01412                 }
01413                 break;
01414             case RPL_PAD1_OPTION:
01415                 start++;
01416                 continue;
01417         }
01418         start += 2 + start[1];
01419     }
01420 
01421     if (new_info && storing) {
01422         rpl_instance_dao_trigger(instance, 0);
01423     }
01424 
01425     return true;
01426 }
01427 #endif // HAVE_RPL_DAO_HANDLING
01428 
01429 void rpl_instance_dao_acked(rpl_instance_t *instance, const uint8_t src[16], int8_t interface_id, uint8_t dao_sequence, uint8_t status)
01430 {
01431     if (!instance->dao_in_transit || dao_sequence != instance->dao_sequence_in_transit) {
01432         return;
01433     }
01434 
01435     if (src) {
01436         ipv6_neighbour_reachability_confirmation(src, interface_id);
01437     }
01438 
01439     bool retry = false;
01440     if (status == 0) {
01441         tr_debug("DAO-ACK RX"); /* Some tests rely on this debug */
01442     } else {
01443         if (src) {
01444             tr_warn("DAO rejection from %s: status=%d", trace_ipv6(src), status);
01445         } else {
01446             tr_warn("DAO timeout");
01447             retry = true;
01448         }
01449     }
01450 
01451     rpl_dodag_t *dodag = rpl_instance_current_dodag(instance);
01452     const rpl_dodag_conf_t *conf = dodag? rpl_dodag_get_config(dodag) : NULL;
01453     instance->dao_in_transit = false;
01454     instance->dao_retry_timer = 0;
01455     if (!retry) {
01456         instance->dao_attempt = 0;
01457     }
01458 
01459     bool more_to_do = false;
01460     ns_list_foreach(rpl_dao_target_t, target, &instance->dao_targets) {
01461         if (target->root) {
01462             continue;
01463         }
01464         tr_debug("tgt %s - pc %02x, assigned %02x, assigning %02x, life %02x, rfr %"PRIu32,
01465                  trace_ipv6_prefix(target->prefix, target->prefix_len),
01466                  target->path_control,
01467                  target->info.non_root.pc_assigned,
01468                  target->info.non_root.pc_assigning,
01469                  target->info.non_root.path_lifetime,
01470                  target->info.non_root.refresh_timer);
01471         target->info.non_root.pc_assigning &= target->path_control;
01472         if (target->info.non_root.pc_assigning) {
01473             if (!retry) {
01474                 target->info.non_root.pc_assigned |= target->info.non_root.pc_assigning;
01475             } else {
01476                 target->info.non_root.pc_to_retry |= target->info.non_root.pc_assigning;
01477             }
01478             target->info.non_root.pc_assigning = 0;
01479         }
01480         target->info.non_root.pc_assigned &= target->path_control;
01481         if (target->info.non_root.pc_assigned != target->path_control) {
01482             more_to_do = true;
01483         } else {
01484             if (target->published && target->info.non_root.refresh_timer == 0) {
01485                 uint32_t t;
01486                 if (conf && target->info.non_root.path_lifetime != 0xFF) {
01487                     t = (uint32_t) target->info.non_root.path_lifetime * conf->lifetime_unit;
01488                     /* Refresh between 1/2 and 3/4 of lifetime */
01489                     t = randLIB_randomise_base(t, 0x4000, 0x6000);
01490                 } else {
01491                     t = 0xFFFFFFFF;
01492                 }
01493 #ifdef MINIMUM_DAO_TARGET_REFRESH
01494                 if (t > MINIMUM_DAO_TARGET_REFRESH) {
01495                     t = randLIB_randomise_base(MINIMUM_DAO_TARGET_REFRESH, 0x7333, 0x8CCD); /* +/- 10% */
01496                 }
01497 #endif
01498                 target->info.non_root.refresh_timer = t;
01499                 tr_debug("set rfr to %"PRIu32, t);
01500             }
01501         }
01502     }
01503 
01504     if (more_to_do) {
01505         rpl_instance_dao_trigger(instance, 1);
01506     } else {
01507         rpl_control_event(instance->domain, RPL_EVENT_DAO_DONE);
01508     }
01509 }
01510 
01511 void rpl_instance_dao_request(struct rpl_instance *instance, struct rpl_neighbour *neighbour)
01512 {
01513     uint8_t pc_mask = neighbour ? neighbour->dao_path_control : 0xFF;
01514 
01515     if (!pc_mask) {
01516         return;
01517     }
01518 
01519     ns_list_foreach(rpl_dao_target_t, target, &instance->dao_targets) {
01520         if (!target->root) {
01521             target->info.non_root.pc_assigned &= ~pc_mask;
01522             target->info.non_root.pc_to_retry &= ~pc_mask;
01523         }
01524     }
01525 
01526     rpl_instance_dao_trigger(instance, 0);
01527 }
01528 
01529 
01530 void rpl_downward_dao_slow_timer(rpl_instance_t *instance, uint16_t seconds)
01531 {
01532     if (!instance) {
01533         return;
01534     }
01535     /* Process lifetimes on all targets for expiry */
01536     ns_list_foreach_safe(rpl_dao_target_t, target, &instance->dao_targets) {
01537         if (target->lifetime == 0xFFFFFFFF) {
01538             continue;
01539         }
01540         if (target->lifetime > seconds) {
01541             target->lifetime -= seconds;
01542             continue;
01543         }
01544         rpl_delete_dao_target(instance, target);
01545     }
01546 
01547     /* Perform target auto-refresh for published targets */
01548     ns_list_foreach_safe(rpl_dao_target_t, target, &instance->dao_targets) {
01549         if (!target->published) {
01550             continue;
01551         }
01552         if (target->info.non_root.refresh_timer == 0xFFFFFFFF || target->info.non_root.refresh_timer == 0) {
01553             continue;
01554         }
01555         if (target->info.non_root.refresh_timer > seconds) {
01556             target->info.non_root.refresh_timer -= seconds;
01557             continue;
01558         }
01559         /* Refresh the DAO target */
01560         target->info.non_root.refresh_timer = 0;
01561         rpl_downward_target_refresh(target);
01562         rpl_instance_dao_trigger(instance, 0);
01563     }
01564 }
01565 
01566 void rpl_downward_dao_timer(rpl_instance_t *instance, uint16_t ticks)
01567 {
01568     if (instance->dao_retry_timer) {
01569         if (instance->dao_retry_timer > ticks) {
01570             instance->dao_retry_timer -= ticks;
01571         } else {
01572             instance->dao_retry_timer = 0;
01573             if (!instance->requested_dao_ack) {
01574                 /* Act as if ACK arrived at first retry point (gives them
01575                  * time to send a failure).
01576                  */
01577                 rpl_instance_dao_acked(instance, NULL, -1, instance->dao_sequence_in_transit, 0);
01578             } else {
01579                 rpl_instance_dao_acked(instance, NULL, -1, instance->dao_sequence_in_transit, 0xFF);
01580             }
01581         }
01582     }
01583 
01584     if (instance->delay_dao_timer) {
01585         if (instance->delay_dao_timer > ticks) {
01586             instance->delay_dao_timer -= ticks;
01587         } else {
01588             instance->delay_dao_timer = 0;
01589             rpl_instance_send_dao_update(instance);
01590         }
01591     }
01592 }
01593 
01594 void rpl_downward_print_instance(rpl_instance_t *instance, route_print_fn_t *print_fn)
01595 {
01596     if (ns_list_is_empty(&instance->dao_targets)) {
01597         return;
01598     }
01599     print_fn("DAO Targets:");
01600     if (rpl_instance_am_root(instance)) {
01601         rpl_downward_compute_paths(instance);
01602     }
01603     ns_list_foreach(rpl_dao_target_t, target, &instance->dao_targets) {
01604 
01605         char str_buf[44];
01606         ip6_prefix_tos(target->prefix, target->prefix_len, str_buf);
01607 #ifdef HAVE_RPL_ROOT
01608         if (target->root) {
01609             print_fn("  %-40s %02x seq=%d%s cost=%"PRIu32"%s%s%s",
01610                        str_buf,
01611                        target->path_control, target->path_sequence, target->need_seq_inc ? "+" : "",
01612                        target->info.root.cost,
01613                        target->published ? " (pub)" : "",
01614                        target->external ? " (E)" : "",
01615                        target->connected ? "" : " (disconnected)");
01616             ns_list_foreach(rpl_dao_root_transit_t, transit, &target->info.root.transits) {
01617                 // Reuse str_buf as it's no longer needed and it's large enough for ROUTE_PRINT_ADDR_STR_FORMAT.
01618                 print_fn("    ->%-36s %02x cost=%"PRIu16, ROUTE_PRINT_ADDR_STR_FORMAT(str_buf, transit->transit), transit->path_control, transit->cost);
01619             }
01620         } else
01621 #endif
01622         {
01623             print_fn("  %-40s %02x seq=%d%s%s%s",
01624                        str_buf,
01625                        target->path_control, target->path_sequence, target->need_seq_inc ? "+" : "",
01626                        target->published ? " (pub)" : "",
01627                        target->external ? " (E)" : "");
01628         }
01629     }
01630 }
01631 
01632 #endif /* HAVE_RPL */