diff --git a/sys/include/net/ng_ipv6/nc.h b/sys/include/net/ng_ipv6/nc.h index 0421705bfe1810779b8639b3b6b69ee24686d943..46d09af883961bfea5d8510178565ee6364ce417 100644 --- a/sys/include/net/ng_ipv6/nc.h +++ b/sys/include/net/ng_ipv6/nc.h @@ -175,6 +175,24 @@ void ng_ipv6_nc_remove(kernel_pid_t iface, const ng_ipv6_addr_t *ipv6_addr); */ ng_ipv6_nc_t *ng_ipv6_nc_get(kernel_pid_t iface, const ng_ipv6_addr_t *ipv6_addr); +/** + * @brief Gets next entry in neighbor cache after @p prev. + * + * @param[in] prev Previous entry. NULL to start iteration. + * + * @return The next entry in neighbor cache. + */ +ng_ipv6_nc_t *ng_ipv6_nc_get_next(ng_ipv6_nc_t *prev); + +/** + * @brief Gets next reachable router entry in neighbor cache after @p prev. + * + * @param[in] prev Previous router entry. NULL to start iteration. + * + * @return The next reachable router entry in neighbor cache. + */ +ng_ipv6_nc_t *ng_ipv6_nc_get_next_router(ng_ipv6_nc_t *prev); + /** * @brief Searches for any neighbor cache entry fitting the @p ipv6_addr, * where you currently can send a packet to (do not confuse with diff --git a/sys/net/network_layer/ng_ipv6/nc/ng_ipv6_nc.c b/sys/net/network_layer/ng_ipv6/nc/ng_ipv6_nc.c index 6aeb5fec0b78ae3e61f03479688b891d54aaf8bd..39ce430a734f29842bcc6c6e347562b8d995e609 100644 --- a/sys/net/network_layer/ng_ipv6/nc/ng_ipv6_nc.c +++ b/sys/net/network_layer/ng_ipv6/nc/ng_ipv6_nc.c @@ -136,6 +136,50 @@ ng_ipv6_nc_t *ng_ipv6_nc_get(kernel_pid_t iface, const ng_ipv6_addr_t *ipv6_addr return NULL; } +ng_ipv6_nc_t *ng_ipv6_nc_get_next(ng_ipv6_nc_t *prev) +{ + if (prev == NULL) { + prev = ncache; + } + else { + prev++; /* get next entry */ + } + + while (prev < (ncache + NG_IPV6_NC_SIZE)) { /* while not reached end */ + if (!ng_ipv6_addr_is_unspecified(&(prev->ipv6_addr))) { + return prev; + } + + prev++; + } + + return NULL; +} + +static inline bool _is_reachable(ng_ipv6_nc_t *entry) +{ + switch ((entry->flags & NG_IPV6_NC_STATE_MASK) >> NG_IPV6_NC_STATE_POS) { + case NG_IPV6_NC_STATE_UNREACHABLE: + case NG_IPV6_NC_STATE_INCOMPLETE: + return false; + + default: + return true; + } +} + +ng_ipv6_nc_t *ng_ipv6_nc_get_next_router(ng_ipv6_nc_t *prev) +{ + for (ng_ipv6_nc_t *router = ng_ipv6_nc_get_next(prev); router != NULL; + router = ng_ipv6_nc_get_next(router)) { + if (router->flags & NG_IPV6_NC_IS_ROUTER) { + return router; + } + } + + return NULL; +} + ng_ipv6_nc_t *ng_ipv6_nc_get_reachable(kernel_pid_t iface, const ng_ipv6_addr_t *ipv6_addr) { @@ -148,17 +192,11 @@ ng_ipv6_nc_t *ng_ipv6_nc_get_reachable(kernel_pid_t iface, return NULL; } - switch ((entry->flags & NG_IPV6_NC_STATE_MASK) >> NG_IPV6_NC_STATE_POS) { - case NG_IPV6_NC_STATE_UNREACHABLE: - case NG_IPV6_NC_STATE_INCOMPLETE: - DEBUG("ipv6_nc: Entry %s is unreachable (flags = 0x%02x)\n", - ng_ipv6_addr_to_str(addr_str, ipv6_addr, sizeof(addr_str)), - entry->flags); - return NULL; - - default: - return entry; + if (_is_reachable(entry)) { + return entry; } + + return NULL; } ng_ipv6_nc_t *ng_ipv6_nc_still_reachable(const ng_ipv6_addr_t *ipv6_addr) diff --git a/sys/shell/commands/sc_ipv6_nc.c b/sys/shell/commands/sc_ipv6_nc.c index 032466100d66530e6c7f8002af08a72e9a741a35..615acf902892ae3afd62961ef414aee097339290 100644 --- a/sys/shell/commands/sc_ipv6_nc.c +++ b/sys/shell/commands/sc_ipv6_nc.c @@ -26,6 +26,64 @@ /* maximum length of L2 address */ #define MAX_L2_ADDR_LEN (8U) +static void _print_nc_state(ng_ipv6_nc_t *entry) +{ + switch (entry->flags & NG_IPV6_NC_STATE_MASK) { + case NG_IPV6_NC_STATE_UNMANAGED: + printf("UNMANAGED"); + break; + + case NG_IPV6_NC_STATE_UNREACHABLE: + printf("UNREACHABLE"); + break; + + case NG_IPV6_NC_STATE_INCOMPLETE: + printf("INCOMPLETE"); + break; + + case NG_IPV6_NC_STATE_STALE: + printf("STALE"); + break; + + case NG_IPV6_NC_STATE_DELAY: + printf("DELAY"); + break; + + case NG_IPV6_NC_STATE_PROBE: + printf("PROBE"); + break; + + case NG_IPV6_NC_STATE_REACHABLE: + printf("REACHABLE"); + break; + + default: + printf("UNKNOWN"); + break; + } +} + +static void _print_nc_type(ng_ipv6_nc_t *entry) +{ + switch (entry->flags & NG_IPV6_NC_TYPE_MASK) { + case NG_IPV6_NC_TYPE_GC: + printf("GC"); + break; + + case NG_IPV6_NC_TYPE_TENTATIVE: + printf("T"); + break; + + case NG_IPV6_NC_TYPE_REGISTERED: + printf("R"); + break; + + default: + printf("-"); + break; + } +} + static bool _is_iface(kernel_pid_t iface) { #ifdef MODULE_NG_NETIF @@ -44,6 +102,30 @@ static bool _is_iface(kernel_pid_t iface) #endif } +static int _ipv6_nc_list(void) +{ + char ipv6_str[NG_IPV6_ADDR_MAX_STR_LEN]; + char l2addr_str[3 * MAX_L2_ADDR_LEN]; + + puts("IPv6 address if L2 address state type"); + puts("-----------------------------------------------------------------------------"); + + for (ng_ipv6_nc_t *entry = ng_ipv6_nc_get_next(NULL); + entry != NULL; + entry = ng_ipv6_nc_get_next(entry)) { + printf("%-30s %2" PRIkernel_pid " %-24s ", + ng_ipv6_addr_to_str(ipv6_str, &entry->ipv6_addr, sizeof(ipv6_str)), + entry->iface, + ng_netif_addr_to_str(l2addr_str, sizeof(l2addr_str), + entry->l2_addr, entry->l2_addr_len)); + _print_nc_state(entry); + _print_nc_type(entry); + puts(""); + } + + return 0; +} + static int _ipv6_nc_add(kernel_pid_t iface, char *ipv6_addr_str, char *l2_addr_str) { @@ -88,6 +170,10 @@ static int _ipv6_nc_del(char *ipv6_addr_str) int _ipv6_nc_manage(int argc, char **argv) { + if ((argc == 1) || (strcmp("list", argv[1]) == 0)) { + return _ipv6_nc_list(); + } + if (argc > 2) { if ((argc > 4) && (strcmp("add", argv[1]) == 0)) { kernel_pid_t iface = (kernel_pid_t)atoi(argv[2]); @@ -105,11 +191,46 @@ int _ipv6_nc_manage(int argc, char **argv) } } - printf("usage: %s add <iface pid> <ipv6_addr> <l2_addr>\n" - " or: %s del <ipv6_addr>\n", argv[0], argv[0]); + printf("usage: %s [list]\n" + " or: %s add <iface pid> <ipv6_addr> <l2_addr>\n" + " or: %s del <ipv6_addr>\n", argv[0], argv[0], argv[0]); return 1; } +int _ipv6_nc_routers(int argc, char **argv) +{ + kernel_pid_t iface = KERNEL_PID_UNDEF; + char ipv6_str[NG_IPV6_ADDR_MAX_STR_LEN]; + + if (argc > 1) { + iface = atoi(argv[1]); + + if (!_is_iface(iface)) { + printf("usage: %s [<iface pid>]\n", argv[0]); + return 1; + } + } + + puts("if Router state type"); + puts("---------------------------------------------------"); + + for (ng_ipv6_nc_t *entry = ng_ipv6_nc_get_next_router(NULL); + entry != NULL; + entry = ng_ipv6_nc_get_next_router(entry)) { + if ((iface != KERNEL_PID_UNDEF) && (iface != entry->iface)) { + continue; + } + + printf("%2" PRIkernel_pid " %-30s ", entry->iface, + ng_ipv6_addr_to_str(ipv6_str, &entry->ipv6_addr, sizeof(ipv6_str))); + _print_nc_state(entry); + _print_nc_type(entry); + puts(""); + } + + return 0; +} + /** * @} */ diff --git a/sys/shell/commands/shell_commands.c b/sys/shell/commands/shell_commands.c index 87ec5baa6da87bb55cd0dfa225ed01eee895a609..dc0714d500c7c86e46ae65c9aa1988e7fae7dbbb 100644 --- a/sys/shell/commands/shell_commands.c +++ b/sys/shell/commands/shell_commands.c @@ -165,6 +165,7 @@ extern int _fib_route_handler(int argc, char **argv); #ifdef MODULE_NG_IPV6_NC extern int _ipv6_nc_manage(int argc, char **argv); +extern int _ipv6_nc_routers(int argc, char **argv); #endif const shell_command_t _shell_command_list[] = { @@ -273,6 +274,7 @@ const shell_command_t _shell_command_list[] = { #endif #ifdef MODULE_NG_IPV6_NC {"ncache", "manage neighbor cache by hand", _ipv6_nc_manage }, + {"routers", "IPv6 default router list", _ipv6_nc_routers }, #endif {NULL, NULL, NULL} }; diff --git a/tests/unittests/tests-ipv6_nc/tests-ipv6_nc.c b/tests/unittests/tests-ipv6_nc/tests-ipv6_nc.c index 3576a70ca983893613433bcda0f44fb3c571c6ca..93312386db98eccfb9218fef69a5f3a4c6395246 100644 --- a/tests/unittests/tests-ipv6_nc/tests-ipv6_nc.c +++ b/tests/unittests/tests-ipv6_nc/tests-ipv6_nc.c @@ -40,6 +40,13 @@ } \ } +/* a third IPv6 addr for testing */ +#define THIRD_TEST_IPV6_ADDR { { \ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, \ + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f \ + } \ + } + static void set_up(void) { ng_ipv6_nc_init(); @@ -207,6 +214,91 @@ static void test_ipv6_nc_get__success_if_global(void) TEST_ASSERT_EQUAL_INT(0, entry->flags); } +static void test_ipv6_nc_get_next__empty(void) +{ + TEST_ASSERT_NULL(ng_ipv6_nc_get_next(NULL)); +} + +static void test_ipv6_nc_get_next__1_entry(void) +{ + ng_ipv6_nc_t *entry = NULL; + + test_ipv6_nc_add__success(); /* adds DEFAULT_TEST_IPV6_ADDR to DEFAULT_TEST_NETIF */ + + TEST_ASSERT_NOT_NULL((entry = ng_ipv6_nc_get_next(NULL))); + TEST_ASSERT_NULL(ng_ipv6_nc_get_next(entry)); +} + +static void test_ipv6_nc_get_next__2_entries(void) +{ + ng_ipv6_addr_t addr = OTHER_TEST_IPV6_ADDR; + ng_ipv6_nc_t *entry = NULL; + + test_ipv6_nc_add__success(); /* adds DEFAULT_TEST_IPV6_ADDR to DEFAULT_TEST_NETIF */ + TEST_ASSERT_EQUAL_INT(0, ng_ipv6_nc_add(DEFAULT_TEST_NETIF, &addr, + TEST_STRING8, sizeof(TEST_STRING8) - 1, 0)); + + + TEST_ASSERT_NOT_NULL((entry = ng_ipv6_nc_get_next(NULL))); + TEST_ASSERT_NOT_NULL((entry = ng_ipv6_nc_get_next(entry))); + TEST_ASSERT_NULL(ng_ipv6_nc_get_next(entry)); +} + +static void test_ipv6_nc_get_next__holey(void) +{ + ng_ipv6_addr_t addr1 = OTHER_TEST_IPV6_ADDR; + ng_ipv6_addr_t addr2 = THIRD_TEST_IPV6_ADDR; + ng_ipv6_nc_t *entry = NULL, *exp_entry = NULL; + + /* adds DEFAULT_TEST_IPV6_ADDR and OTHER_TEST_IPV6_ADDR to DEFAULT_TEST_NETIF */ + test_ipv6_nc_get_next__2_entries(); + TEST_ASSERT_EQUAL_INT(0, ng_ipv6_nc_add(DEFAULT_TEST_NETIF, &addr2, + TEST_STRING8, + sizeof(TEST_STRING8) - 2, 0)); + TEST_ASSERT_NOT_NULL((exp_entry = ng_ipv6_nc_get(DEFAULT_TEST_NETIF, &addr2))); + ng_ipv6_nc_remove(DEFAULT_TEST_NETIF, &addr1); + + TEST_ASSERT_NOT_NULL((entry = ng_ipv6_nc_get_next(NULL))); + TEST_ASSERT_NOT_NULL((entry = ng_ipv6_nc_get_next(entry))); + TEST_ASSERT(exp_entry == entry); + TEST_ASSERT_NULL(ng_ipv6_nc_get_next(entry)); +} + +static void test_ipv6_nc_get_next_router__empty(void) +{ + TEST_ASSERT_NULL(ng_ipv6_nc_get_next_router(NULL)); +} + +static void test_ipv6_nc_get_next_router__first_entry(void) +{ + ng_ipv6_nc_t *entry = NULL; + + /* adds DEFAULT_TEST_IPV6_ADDR and OTHER_TEST_IPV6_ADDR to DEFAULT_TEST_NETIF */ + test_ipv6_nc_get_next__2_entries(); + TEST_ASSERT_NOT_NULL((entry = ng_ipv6_nc_get_next(NULL))); + entry->flags = (NG_IPV6_NC_STATE_REACHABLE << NG_IPV6_NC_STATE_POS); + entry->flags |= NG_IPV6_NC_IS_ROUTER; + + TEST_ASSERT_NOT_NULL((entry = ng_ipv6_nc_get_next_router(NULL))); + TEST_ASSERT_NULL(ng_ipv6_nc_get_next_router(entry)); +} + +static void test_ipv6_nc_get_next_router__second_entry(void) +{ + ng_ipv6_nc_t *entry1 = NULL, *entry2 = NULL; + + /* adds DEFAULT_TEST_IPV6_ADDR and OTHER_TEST_IPV6_ADDR to DEFAULT_TEST_NETIF */ + test_ipv6_nc_get_next__2_entries(); + TEST_ASSERT_NOT_NULL((entry1 = ng_ipv6_nc_get_next(NULL))); + TEST_ASSERT_NOT_NULL((entry2 = ng_ipv6_nc_get_next(entry1))); + entry2->flags = (NG_IPV6_NC_STATE_REACHABLE << NG_IPV6_NC_STATE_POS); + entry2->flags |= NG_IPV6_NC_IS_ROUTER; + + TEST_ASSERT_NOT_NULL((entry1 = ng_ipv6_nc_get_next_router(NULL))); + TEST_ASSERT(entry2 == entry1); + TEST_ASSERT_NULL(ng_ipv6_nc_get_next_router(entry1)); +} + static void test_ipv6_nc_get_reachable__incomplete_if_local(void) { ng_ipv6_addr_t addr = DEFAULT_TEST_IPV6_ADDR; @@ -318,6 +410,13 @@ Test *tests_ipv6_nc_tests(void) new_TestFixture(test_ipv6_nc_get__different_addr), new_TestFixture(test_ipv6_nc_get__success_if_local), new_TestFixture(test_ipv6_nc_get__success_if_global), + new_TestFixture(test_ipv6_nc_get_next__empty), + new_TestFixture(test_ipv6_nc_get_next__1_entry), + new_TestFixture(test_ipv6_nc_get_next__2_entries), + new_TestFixture(test_ipv6_nc_get_next__holey), + new_TestFixture(test_ipv6_nc_get_next_router__empty), + new_TestFixture(test_ipv6_nc_get_next_router__first_entry), + new_TestFixture(test_ipv6_nc_get_next_router__second_entry), new_TestFixture(test_ipv6_nc_get_reachable__incomplete_if_local), new_TestFixture(test_ipv6_nc_get_reachable__incomplete_if_global), new_TestFixture(test_ipv6_nc_get_reachable__reachable_if_local),