From 21840252e4178531fbe7206871213faf0b70f19f Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Tue, 8 Aug 2017 11:03:21 +0300 Subject: [PATCH 1/8] net: rpl: DAO message was discarded too early The commit b14586c3cac3 ("net: rpl: RPL route entry was fetched too late") dropped the DAO packet too early which prevents the RPL root node functionality. Rework the earlier commit so that Coverity issues are fixed but the RPL DAO message is also properly handled. Signed-off-by: Jukka Rissanen --- subsys/net/ip/route.c | 4 +++- subsys/net/ip/rpl.c | 23 ++++++++--------------- 2 files changed, 11 insertions(+), 16 deletions(-) diff --git a/subsys/net/ip/route.c b/subsys/net/ip/route.c index 48807359dc6e9..b5c82f9405da4 100644 --- a/subsys/net/ip/route.c +++ b/subsys/net/ip/route.c @@ -554,7 +554,9 @@ struct in6_addr *net_route_get_nexthop(struct net_route_entry *route) struct net_route_nexthop *nexthop_route; struct net_ipv6_nbr_data *ipv6_nbr_data; - NET_ASSERT(route); + if (!route) { + return NULL; + } SYS_SLIST_FOR_EACH_CONTAINER(&route->nexthop, nexthop_route, node) { struct in6_addr *addr; diff --git a/subsys/net/ip/rpl.c b/subsys/net/ip/rpl.c index c5b630775319b..0d9f03e40e6e2 100644 --- a/subsys/net/ip/rpl.c +++ b/subsys/net/ip/rpl.c @@ -3290,10 +3290,10 @@ static int forwarding_dao(struct net_rpl_instance *instance, static enum net_verdict handle_dao(struct net_pkt *pkt) { struct in6_addr *dao_sender = &NET_IPV6_HDR(pkt)->src; + struct net_rpl_route_entry *extra = NULL; struct net_rpl_parent *parent = NULL; enum net_rpl_route_source learned_from; struct net_rpl_instance *instance; - struct net_rpl_route_entry *extra; struct net_route_entry *route; struct net_rpl_dag *dag; struct net_buf *frag; @@ -3458,25 +3458,17 @@ static enum net_verdict handle_dao(struct net_pkt *pkt) } #endif - route = net_route_lookup(net_pkt_iface(pkt), &addr); - if (!route) { - NET_DBG("No route to %s for iface %p", - net_sprint_ipv6_addr(&addr), net_pkt_iface(pkt)); - return NET_DROP; - } - - nbr = net_route_get_nbr(route); - if (!nbr) { - return NET_DROP; - } - - extra = net_nbr_extra_data(nbr); - if (lifetime == NET_RPL_ZERO_LIFETIME) { struct in6_addr *nexthop; NET_DBG("No-Path DAO received"); + route = net_route_lookup(net_pkt_iface(pkt), &addr); + nbr = net_route_get_nbr(route); + if (nbr) { + extra = net_nbr_extra_data(nbr); + } + nexthop = net_route_get_nexthop(route); /* No-Path DAO received; invoke the route purging routine. */ @@ -3551,6 +3543,7 @@ static enum net_verdict handle_dao(struct net_pkt *pkt) return NET_DROP; } + extra = net_nbr_extra_data(nbr); if (extra) { extra->lifetime = net_rpl_lifetime(instance, lifetime); extra->route_source = learned_from; From cb7a38316a9bae408cc62b8fbd97337a476ca9c6 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Tue, 1 Aug 2017 12:46:18 +0300 Subject: [PATCH 2/8] net: rpl: Repair root functions are made global The net_rpl_repair_root() and net_rpl_set_root_with_version() functions were static which prevented global repair when using an instance id. Making those functions global allows RPL network repairing from shell for example. Signed-off-by: Jukka Rissanen --- subsys/net/ip/rpl.c | 3 +-- subsys/net/ip/rpl.h | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/subsys/net/ip/rpl.c b/subsys/net/ip/rpl.c index 0d9f03e40e6e2..d3e5be56e9d42 100644 --- a/subsys/net/ip/rpl.c +++ b/subsys/net/ip/rpl.c @@ -1285,7 +1285,6 @@ static void net_rpl_reset_dio_timer(struct net_rpl_instance *instance) net_stats_update_rpl_resets(); } -static struct net_rpl_dag *net_rpl_set_root_with_version(struct net_if *iface, u8_t instance_id, struct in6_addr *dag_id, @@ -2044,7 +2043,7 @@ static bool net_rpl_process_parent_event(struct net_if *iface, return ret; } -static bool net_rpl_repair_root(u8_t instance_id) +bool net_rpl_repair_root(u8_t instance_id) { struct net_rpl_instance *instance; diff --git a/subsys/net/ip/rpl.h b/subsys/net/ip/rpl.h index cae99881fcbe3..70c0428673cf1 100644 --- a/subsys/net/ip/rpl.h +++ b/subsys/net/ip/rpl.h @@ -887,6 +887,21 @@ struct net_rpl_dag *net_rpl_set_root(struct net_if *iface, u8_t instance_id, struct in6_addr *dag_id); +/** + * @brief Set the root DAG with version. + * + * @param iface Network interface to use. + * @param instance Pointer to instance object. + * @param dag_id IPv6 address of the DAG. + * @param version Version number to use. + * + * @return DAG object or NULL if creation failed. + */ +struct net_rpl_dag *net_rpl_set_root_with_version(struct net_if *iface, + u8_t instance_id, + struct in6_addr *dag_id, + u8_t version); + /** * @brief Get first available DAG. * @@ -916,6 +931,13 @@ bool net_rpl_set_prefix(struct net_if *iface, */ void net_rpl_global_repair(struct net_route_entry *route); +/** + * @brief Do global repair for this instance. + * + * @param instance RPL instance id. + */ +bool net_rpl_repair_root(u8_t instance_id); + /** * @brief Update RPL headers in IPv6 packet. * From 8ab612ba319d8249c7a10afbf589fce417de6b53 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Tue, 1 Aug 2017 14:30:57 +0300 Subject: [PATCH 3/8] net: rpl: Fix unused variable warnings If debug level was low but debugging was activated, then some of the debug variables were left unused. Signed-off-by: Jukka Rissanen --- subsys/net/ip/rpl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/subsys/net/ip/rpl.c b/subsys/net/ip/rpl.c index d3e5be56e9d42..07e95fb0ad112 100644 --- a/subsys/net/ip/rpl.c +++ b/subsys/net/ip/rpl.c @@ -345,7 +345,7 @@ struct in6_addr *net_rpl_get_parent_addr(struct net_if *iface, return net_ipv6_nbr_lookup_by_index(iface, nbr->idx); } -#if defined(CONFIG_NET_DEBUG_RPL) +#if defined(CONFIG_NET_DEBUG_RPL) && (CONFIG_SYS_LOG_NET_LEVEL > 3) static void net_rpl_print_neighbors(void) { if (rpl_default_instance && rpl_default_instance->current_dag) { @@ -1459,7 +1459,7 @@ static void net_rpl_nullify_parent(struct net_if *iface, struct net_rpl_parent *parent) { struct net_rpl_dag *dag = parent->dag; -#if defined(CONFIG_NET_DEBUG_RPL) +#if defined(CONFIG_NET_DEBUG_RPL) && (CONFIG_SYS_LOG_NET_LEVEL > 3) struct in6_addr *addr = net_rpl_get_parent_addr(iface, parent); #endif From 8b1f675152ce2077dcb919bc9c7a3ace5999f371 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Mon, 7 Aug 2017 12:23:07 +0300 Subject: [PATCH 4/8] net: rpl: Send DAO-ACK if we are the root node Instead of always forwarding the DAO, send DAO-ACK if we are the root node. Signed-off-by: Jukka Rissanen --- subsys/net/ip/rpl.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/subsys/net/ip/rpl.c b/subsys/net/ip/rpl.c index 07e95fb0ad112..56753d419e952 100644 --- a/subsys/net/ip/rpl.c +++ b/subsys/net/ip/rpl.c @@ -3286,6 +3286,23 @@ static int forwarding_dao(struct net_rpl_instance *instance, return r; } +static bool is_root(struct net_rpl_instance *instance) +{ + if (!(instance && instance->current_dag)) { + return false; + } + + if (instance->current_dag->preferred_parent) { + return false; + } + + if (instance->current_dag->rank != NET_RPL_ROOT_RANK(instance)) { + return false; + } + + return true; +} + static enum net_verdict handle_dao(struct net_pkt *pkt) { struct in6_addr *dao_sender = &NET_IPV6_HDR(pkt)->src; @@ -3567,6 +3584,22 @@ static enum net_verdict handle_dao(struct net_pkt *pkt) net_pkt_unref(pkt); return NET_OK; } + } else { + if (IS_ENABLED(CONFIG_NET_RPL_DAO_ACK) && + (flags & NET_RPL_DAO_K_FLAG) && + is_root(instance)) { + r = dao_ack_send(&NET_IPV6_HDR(pkt)->dst, + &NET_IPV6_HDR(pkt)->src, + net_pkt_iface(pkt), + instance, sequence, 0); + if (r >= 0) { + NET_DBG("Sending DAO-ACK to %s", + net_sprint_ipv6_addr( + &NET_IPV6_HDR(pkt)->src)); + net_pkt_unref(pkt); + return NET_OK; + } + } } } From daecc7b9758b7fc5e9a7262ae8b548a01e03f5df Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Wed, 2 Aug 2017 16:14:15 +0300 Subject: [PATCH 5/8] net: rpl: Add helper to return parent information Create net_rpl_foreach_parent() function that will traverse through all the parents and return their information via callback. This is needed by net-shell in later commit. Signed-off-by: Jukka Rissanen --- subsys/net/ip/rpl.c | 19 +++++++++++++++++++ subsys/net/ip/rpl.h | 14 ++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/subsys/net/ip/rpl.c b/subsys/net/ip/rpl.c index 56753d419e952..d5d942d2ef1df 100644 --- a/subsys/net/ip/rpl.c +++ b/subsys/net/ip/rpl.c @@ -345,6 +345,25 @@ struct in6_addr *net_rpl_get_parent_addr(struct net_if *iface, return net_ipv6_nbr_lookup_by_index(iface, nbr->idx); } +int net_rpl_foreach_parent(net_rpl_parent_cb_t cb, void *user_data) +{ + int i, ret = 0; + + for (i = 0; i < CONFIG_NET_IPV6_MAX_NEIGHBORS; i++) { + struct net_nbr *nbr = get_nbr(i); + + if (!nbr->ref) { + continue; + } + + cb(nbr_data(nbr), user_data); + + ret++; + } + + return ret; +} + #if defined(CONFIG_NET_DEBUG_RPL) && (CONFIG_SYS_LOG_NET_LEVEL > 3) static void net_rpl_print_neighbors(void) { diff --git a/subsys/net/ip/rpl.h b/subsys/net/ip/rpl.h index 70c0428673cf1..5e7652e8dab6d 100644 --- a/subsys/net/ip/rpl.h +++ b/subsys/net/ip/rpl.h @@ -995,6 +995,20 @@ int net_rpl_revert_header(struct net_pkt *pkt, u16_t offset, u16_t *pos); struct in6_addr *net_rpl_get_parent_addr(struct net_if *iface, struct net_rpl_parent *parent); +typedef void (*net_rpl_parent_cb_t)(struct net_rpl_parent *parent, + void *user_data); + +/** + * @brief Go through all the parents entries and call callback + * for each entry that is in use. + * + * @param cb User supplied callback function to call. + * @param user_data User specified data. + * + * @return Total number of parents found. + */ +int net_rpl_foreach_parent(net_rpl_parent_cb_t cb, void *user_data); + /** * @brief Set the RPL mode (mesh or leaf) of this node. * From fa7d58464a0cc8ff5120cfe4ec4522f95040cb97 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Wed, 2 Aug 2017 16:15:45 +0300 Subject: [PATCH 6/8] net: shell: Add command to return RPL information Add "net rpl" command to net-shell which will return both static RPL configuration from Kconfig, and dynamic run time configuration of the nodes and parents. Signed-off-by: Jukka Rissanen --- subsys/net/ip/net_shell.c | 183 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 183 insertions(+) diff --git a/subsys/net/ip/net_shell.c b/subsys/net/ip/net_shell.c index 961f26abd9820..a964d8262d622 100644 --- a/subsys/net/ip/net_shell.c +++ b/subsys/net/ip/net_shell.c @@ -39,6 +39,10 @@ #include #endif +#if defined(CONFIG_NET_RPL) +#include "rpl.h" +#endif + #include "net_shell.h" #include "net_stats.h" @@ -1648,6 +1652,184 @@ int net_shell_cmd_route(int argc, char *argv[]) return 0; } +#if defined(CONFIG_NET_RPL) +static int power(int base, unsigned int exp) +{ + int i, result = 1; + + for (i = 0; i < exp; i++) { + result *= base; + } + + return result; +} + +static void rpl_parent(struct net_rpl_parent *parent, void *user_data) +{ + int *count = user_data; + + if (*count == 0) { + printk(" Parent Last TX Rank DTSN Flags\tAddress\n"); + } + + (*count)++; + + if (parent->dag) { + printk("[%2d] %p %10d %2d %d 0x%08x %s\n", + *count, parent, parent->last_tx_time, parent->rank, + parent->dtsn, parent->flags, + net_sprint_ipv6_addr(&parent->dag->dag_id)); + } +} + +#endif /* CONFIG_NET_RPL */ + +int net_shell_cmd_rpl(int argc, char *argv[]) +{ + ARG_UNUSED(argc); + ARG_UNUSED(argv); + +#if defined(CONFIG_NET_RPL) + struct net_rpl_instance *instance; + enum net_rpl_mode mode; + int i, count; + + mode = net_rpl_get_mode(); + printk("RPL Configuration\n"); + printk("=================\n"); + printk("RPL mode : %s\n", + mode == NET_RPL_MODE_MESH ? "mesh" : + (mode == NET_RPL_MODE_FEATHER ? "feather" : + (mode == NET_RPL_MODE_LEAF ? "leaf" : ""))); + printk("Used objective function : %s\n", + IS_ENABLED(CONFIG_NET_RPL_MRHOF) ? "MRHOF" : + (IS_ENABLED(CONFIG_NET_RPL_OF0) ? "OF0" : "")); + printk("Used routing metric : %s\n", + IS_ENABLED(CONFIG_NET_RPL_MC_NONE) ? "none" : + (IS_ENABLED(CONFIG_NET_RPL_MC_ETX) ? "estimated num of TX" : + (IS_ENABLED(CONFIG_NET_RPL_MC_ENERGY) ? "energy based" : + ""))); + printk("Mode of operation (MOP) : %s\n", + IS_ENABLED(CONFIG_NET_RPL_MOP2) ? "Storing, no mcast (MOP2)" : + (IS_ENABLED(CONFIG_NET_RPL_MOP3) ? "Storing (MOP3)" : + "")); + printk("Send probes to nodes : %s\n", + IS_ENABLED(CONFIG_NET_RPL_PROBING) ? "enabled" : "disabled"); + printk("Max instances : %d\n", + CONFIG_NET_RPL_MAX_INSTANCES); + printk("Max DAG / instance : %d\n", + CONFIG_NET_RPL_MAX_DAG_PER_INSTANCE); + + printk("Min hop rank increment : %d\n", + CONFIG_NET_RPL_MIN_HOP_RANK_INC); + printk("Initial link metric : %d\n", + CONFIG_NET_RPL_INIT_LINK_METRIC); + printk("RPL preference value : %d\n", + CONFIG_NET_RPL_PREFERENCE); + printk("DAG grounded by default : %s\n", + IS_ENABLED(CONFIG_NET_RPL_GROUNDED) ? "yes" : "no"); + printk("Default instance id : %d (0x%02x)\n", + CONFIG_NET_RPL_DEFAULT_INSTANCE, + CONFIG_NET_RPL_DEFAULT_INSTANCE); + printk("Insert Hop-by-hop option : %s\n", + IS_ENABLED(CONFIG_NET_RPL_INSERT_HBH_OPTION) ? "yes" : "no"); + + printk("Specify DAG when sending DAO : %s\n", + IS_ENABLED(CONFIG_NET_RPL_DAO_SPECIFY_DAG) ? "yes" : "no"); + printk("DIO min interval : %d (%d ms)\n", + CONFIG_NET_RPL_DIO_INTERVAL_MIN, + power(2, CONFIG_NET_RPL_DIO_INTERVAL_MIN)); + printk("DIO doublings interval : %d\n", + CONFIG_NET_RPL_DIO_INTERVAL_DOUBLINGS); + printk("DIO redundancy value : %d\n", + CONFIG_NET_RPL_DIO_REDUNDANCY); + + printk("DAO sending timer value : %d sec\n", + CONFIG_NET_RPL_DAO_TIMER); + printk("DAO max retransmissions : %d\n", + CONFIG_NET_RPL_DAO_MAX_RETRANSMISSIONS); + printk("Node expecting DAO ack : %s\n", + IS_ENABLED(CONFIG_NET_RPL_DAO_ACK) ? "yes" : "no"); + + printk("Send DIS periodically : %s\n", + IS_ENABLED(CONFIG_NET_RPL_DIS_SEND) ? "yes" : "no"); +#if defined(CONFIG_NET_RPL_DIS_SEND) + printk("DIS interval : %d sec\n", + CONFIG_NET_RPL_DIS_INTERVAL); +#endif + + printk("Default route lifetime unit : %d sec\n", + CONFIG_NET_RPL_DEFAULT_LIFETIME_UNIT); + printk("Default route lifetime : %d\n", + CONFIG_NET_RPL_DEFAULT_LIFETIME); +#if defined(CONFIG_NET_RPL_MOP3) + printk("Multicast route lifetime : %d\n", + CONFIG_NET_RPL_MCAST_LIFETIME); +#endif + printk("\nRuntime status\n"); + printk("==============\n"); + + instance = net_rpl_get_default_instance(); + if (!instance) { + printk("No default RPL instance found.\n"); + return 0; + } + + printk("Default instance (id %d) : %p (%s)\n", instance->instance_id, + instance, instance->is_used ? "active" : "disabled"); + + if (instance->default_route) { + printk("Default route : %s\n", + net_sprint_ipv6_addr( + &instance->default_route->address.in6_addr)); + } + +#if defined(CONFIG_NET_STATISTICS_RPL) + printk("DIO statistics : intervals %d sent %d recv %d\n", + instance->dio_intervals, instance->dio_send_pkt, + instance->dio_recv_pkt); +#endif /* CONFIG_NET_STATISTICS_RPL */ + + printk("Instance DAGs :\n"); + for (i = 0, count = 0; i < CONFIG_NET_RPL_MAX_DAG_PER_INSTANCE; i++) { + char prefix[NET_IPV6_ADDR_LEN]; + + if (!instance->dags[i].is_used) { + continue; + } + + snprintk(prefix, sizeof(prefix), "%s", + net_sprint_ipv6_addr( + &instance->dags[i].prefix_info.prefix)); + + printk("[%2d]%s %s prefix %s/%d rank %d/%d ver %d flags %c%c " + "parent %p\n", + ++count, + &instance->dags[i] == instance->current_dag ? "*" : " ", + net_sprint_ipv6_addr(&instance->dags[i].dag_id), + prefix, instance->dags[i].prefix_info.length, + instance->dags[i].rank, instance->dags[i].min_rank, + instance->dags[i].version, + instance->dags[i].is_grounded ? 'G' : 'g', + instance->dags[i].is_joined ? 'J' : 'j', + instance->dags[i].preferred_parent); + } + printk("\n"); + + count = 0; + i = net_rpl_foreach_parent(rpl_parent, &count); + if (i == 0) { + printk("No parents found.\n"); + } + + printk("\n"); +#else + printk("RPL not enabled, set CONFIG_NET_RPL to enable it.\n"); +#endif + + return 0; +} + #if defined(CONFIG_INIT_STACKS) extern K_THREAD_STACK_DEFINE(_main_stack, CONFIG_MAIN_STACK_SIZE); extern K_THREAD_STACK_DEFINE(_interrupt_stack, CONFIG_ISR_STACK_SIZE); @@ -2018,6 +2200,7 @@ static struct shell_cmd net_commands[] = { "nbr rm \n\tRemove neighbor from cache" }, { "ping", net_shell_cmd_ping, "\n\tPing a network host" }, { "route", net_shell_cmd_route, "\n\tShow network route" }, + { "rpl", net_shell_cmd_rpl, "\n\tShow RPL mesh routing status" }, { "stacks", net_shell_cmd_stacks, "\n\tShow network stacks information" }, { "stats", net_shell_cmd_stats, "\n\tShow network statistics" }, From 177380ed9e93f0ed75faab60c821362f4b29504a Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Mon, 7 Aug 2017 13:56:00 +0300 Subject: [PATCH 7/8] net: shell: Fix the output of route command Print route information by groupping them for each network interface like this: IPv6 routes for interface 0xa8007140 ==================================== IPv6 prefix : 2001:db8::212:4b00:0:3/128 neighbor : 0xa80065e0 link addr : 00:12:4B:00:00:00:00:03 IPv6 prefix : 2001:db8::212:4b00:0:1/128 neighbor : 0xa8006660 link addr : 00:12:4B:00:00:00:00:01 Signed-off-by: Jukka Rissanen --- subsys/net/ip/net_shell.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/subsys/net/ip/net_shell.c b/subsys/net/ip/net_shell.c index a964d8262d622..9c1b5379f9784 100644 --- a/subsys/net/ip/net_shell.c +++ b/subsys/net/ip/net_shell.c @@ -269,17 +269,12 @@ static void route_cb(struct net_route_entry *entry, void *user_data) return; } - printk("IPv6 Route %p for interface %p\n", entry, iface); - printk("==============================================\n"); - printk("IPv6 prefix : %s/%d\n", net_sprint_ipv6_addr(&entry->addr), entry->prefix_len); count = 0; - printk("Next hops :\n"); - SYS_SLIST_FOR_EACH_CONTAINER(&entry->nexthop, nexthop_route, node) { struct net_linkaddr_storage *lladdr; @@ -311,6 +306,9 @@ static void iface_per_route_cb(struct net_if *iface, void *user_data) { ARG_UNUSED(user_data); + printk("IPv6 routes for interface %p\n", iface); + printk("====================================\n"); + net_route_foreach(route_cb, iface); } #endif /* CONFIG_NET_ROUTE */ From 274eedee404dfd712b75ca5abe2876b9eaac1b58 Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Mon, 7 Aug 2017 14:14:18 +0300 Subject: [PATCH 8/8] net: shell: Fix neighbor printing for IEEE 802.15.4 networks The "net nbr" command was printing the heading of neighbor list incorrectly. Signed-off-by: Jukka Rissanen --- subsys/net/ip/net_shell.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/subsys/net/ip/net_shell.c b/subsys/net/ip/net_shell.c index 9c1b5379f9784..ab073db0367a5 100644 --- a/subsys/net/ip/net_shell.c +++ b/subsys/net/ip/net_shell.c @@ -1393,8 +1393,14 @@ static void nbr_cb(struct net_nbr *nbr, void *user_data) int *count = user_data; if (*count == 0) { + char *padding = ""; + + if (net_nbr_get_lladdr(nbr->idx)->len == 8) { + padding = " "; + } + printk(" Neighbor Flags Interface State\t" - "Remain\tLink Address\n"); + "Remain\tLink %sAddress\n", padding); } (*count)++;