## Appendix B Contiki-NG Modifications in Detail  
Contiki-NG includes two RPL [4] routing layers: RPL-Lite and RPL-Classic. We used RPL-Classic (in storing mode) because it is the most feature-complete. RPL-Classic defines Objective Functions (OFs) in separate source files. An OF retrieves the link metric towards a neighbor from the link-stats module. In a single-interface solution, this metric is the inferred metric of the sole link towards the neighbor. In our multi-interfaced solution(s), the OF retrieves the normalized metric of the neighbor. The OF (in Contiki-NG) is shielded from normalization/inferred metrics. Instead, DRiPLOF's metric normalization requirements (see Section 4.3) are performed by the link-stats module. This module keeps per-neighbor statistics in the link-stats table. The entries in this table are (indirectly) managed by the MAC layer, which (indirectly) sends status information to the link-stats module after each transmission/reception. Using this information, the link-stats module updates a table entry or creates a new one. With a single-interface implementation, each link-stats table entry contains only a single link metric (amongst other information). Otherwise, each link-stats table entry points to an interface list, of which each entry stores (amongst other things): (1) an identifier that is unique to all interfaces of a certain type; and (2) an inferred metric. An interface list entry is updated when interacting with a known neighbor over an interface of a given type. A new entry is created when a new link-stats table entry is created or when interacting with a neighbor over an interface previously not present in the interface list. As we based DRiPLOF on MRHOF, we noticed that RPL-Classic's implementation did not adhere to RFC 6719 [11] (Section 3.3). That is, a node should set its advertised rank to the maximum of three values:  
1. The rank computed for the path through the preferred parent. 2. The highest rank advertised by any of its parent set members (\(\
eq\)the computed rank for the path through said node), rounded to the next higher integral rank. 3. The largest computed rank through the parent set, minus MaxRankIncrease. Instead, a node simply advertised the rank through the preferred parent (cf., point one). However, notice how Point 2 prevents a situation wherein, e.g., a node forms a parent set and, consequently, may only keep the preferred parent because of rank requirements [4] (Section 8.2.1). Then, if the link to the preferred parent failed, the node's parent set would become empty, resulting in a local repair [41] (Section 7.1.5). Local repairs are a liability and should be avoided at all costs [5]. Instead, advertising conservative ranks to keep a larger parent set (cf. Point 2) and avoid local repairs means less time spent recovering from failures. Hence, we reworked RPL-Classic. Each OF now provides a function, rank_via_dag(), which (for MRHOF-based OFs) returns the rank to be advertised according to [11] (Section 3.3) and assigns \"blame\" to the parent responsible for said rank. For OF0-based OFs, rank_via_dag() returns the rank through the preferred parent. We also redesigned the (ill-named) rpl_parents table, containing an entry for (nearly) every RPL neighbor. Entries now indicate if a neighbor is an eligible parent. The rank returned by rank_via_dag() is based on eligible parents only, and the calling function may mark the responsible parent ineligible if the returned rank is unacceptable according to [4] (Section 8.2.2.4). In addition, the OF can now be called externally to determine whether a neighbor is an acceptable parent (i.e., according to [11] (Section 3.2.2)) via parent_is_acceptable(). Again, this allows marking rpl_parents members as (in-)eligible. Neighbor discovery is not supported with RPL in Contiki-NG. Instead, RPL-Classic populates the neighbor cache, which is only used for next-hop determination. Since all IP addresses are based on link-layer addresses, there is no need for DAD nor address resolution/registration.