From 601e14ebc7b588489e271c284b8993ada5cf0504 Mon Sep 17 00:00:00 2001 From: Yasuyuki Tanaka Date: Fri, 23 Mar 2018 13:51:27 +0000 Subject: [PATCH] uip-nd6: bugfix on address resolution by Neighbor Discovery protocol nbr_table_update_lladdr() fails to update the lladdr of a nbr with a new one when the new lladdr is used in nbr_table. This causes communication errors when NS/NA is employed. uip_ds6_nbr_update_ll() is introduced to resolve this issue. And nbr_table_update_lladdr() is removed since it's not used any more. --- os/net/ipv6/uip-ds6-nbr.c | 35 +++++++++++++++++++++++++++++++++++ os/net/ipv6/uip-ds6-nbr.h | 1 + os/net/ipv6/uip-nd6.c | 14 ++++++++++---- os/net/nbr-table.c | 33 --------------------------------- os/net/nbr-table.h | 1 - 5 files changed, 46 insertions(+), 38 deletions(-) diff --git a/os/net/ipv6/uip-ds6-nbr.c b/os/net/ipv6/uip-ds6-nbr.c index e49125548..f937986b5 100644 --- a/os/net/ipv6/uip-ds6-nbr.c +++ b/os/net/ipv6/uip-ds6-nbr.c @@ -127,6 +127,41 @@ uip_ds6_nbr_rm(uip_ds6_nbr_t *nbr) return 0; } +/*---------------------------------------------------------------------------*/ +int +uip_ds6_nbr_update_ll(uip_ds6_nbr_t **nbr_pp, const uip_lladdr_t *new_ll_addr) +{ + uip_ds6_nbr_t nbr_backup; + + if(nbr_pp == NULL || new_ll_addr == NULL) { + LOG_ERR("%s: invalid argument\n", __func__); + return -1; + } + + /* make sure new_ll_addr is not used in some other nbr */ + if(uip_ds6_nbr_ll_lookup(new_ll_addr) != NULL) { + LOG_ERR("%s: new_ll_addr, ", __func__); + LOG_ERR_LLADDR((const linkaddr_t *)new_ll_addr); + LOG_ERR_(", is already used in another nbr\n"); + return -1; + } + + memcpy(&nbr_backup, *nbr_pp, sizeof(uip_ds6_nbr_t)); + if(uip_ds6_nbr_rm(*nbr_pp) == 0) { + LOG_ERR("%s: input nbr cannot be removed\n", __func__); + return -1; + } + + if((*nbr_pp = uip_ds6_nbr_add(&nbr_backup.ipaddr, new_ll_addr, + nbr_backup.isrouter, nbr_backup.state, + NBR_TABLE_REASON_IPV6_ND, NULL)) == NULL) { + LOG_ERR("%s: cannot allocate a new nbr for new_ll_addr\n", __func__); + return -1; + } + memcpy(*nbr_pp, &nbr_backup, sizeof(uip_ds6_nbr_t)); + + return 0; +} /*---------------------------------------------------------------------------*/ const uip_ipaddr_t * uip_ds6_nbr_get_ipaddr(const uip_ds6_nbr_t *nbr) diff --git a/os/net/ipv6/uip-ds6-nbr.h b/os/net/ipv6/uip-ds6-nbr.h index 9aec47b4a..d645ac627 100644 --- a/os/net/ipv6/uip-ds6-nbr.h +++ b/os/net/ipv6/uip-ds6-nbr.h @@ -90,6 +90,7 @@ uip_ds6_nbr_t *uip_ds6_nbr_add(const uip_ipaddr_t *ipaddr, nbr_table_reason_t reason, void *data); int uip_ds6_nbr_rm(uip_ds6_nbr_t *nbr); const uip_lladdr_t *uip_ds6_nbr_get_ll(const uip_ds6_nbr_t *nbr); +int uip_ds6_nbr_update_ll(uip_ds6_nbr_t **nbr, const uip_lladdr_t *new_ll_addr); const uip_ipaddr_t *uip_ds6_nbr_get_ipaddr(const uip_ds6_nbr_t *nbr); uip_ds6_nbr_t *uip_ds6_nbr_lookup(const uip_ipaddr_t *ipaddr); uip_ds6_nbr_t *uip_ds6_nbr_ll_lookup(const uip_lladdr_t *lladdr); diff --git a/os/net/ipv6/uip-nd6.c b/os/net/ipv6/uip-nd6.c index ce555ed53..7a5724308 100644 --- a/os/net/ipv6/uip-nd6.c +++ b/os/net/ipv6/uip-nd6.c @@ -230,7 +230,9 @@ ns_input(void) } if(memcmp(&nd6_opt_llao[UIP_ND6_OPT_DATA_OFFSET], lladdr, UIP_LLADDR_LEN) != 0) { - if(nbr_table_update_lladdr((const linkaddr_t *)lladdr, (const linkaddr_t *)&lladdr_aligned, 1) == 0) { + if(uip_ds6_nbr_update_ll(&nbr, + (const uip_lladdr_t *)&lladdr_aligned) + < 0) { /* failed to update the lladdr */ goto discard; } @@ -534,7 +536,8 @@ na_input(void) if(nd6_opt_llao == NULL || !extract_lladdr_from_llao_aligned(&lladdr_aligned)) { goto discard; } - if(nbr_table_update_lladdr((const linkaddr_t *)lladdr, (const linkaddr_t *)&lladdr_aligned, 1) == 0) { + if(uip_ds6_nbr_update_ll(&nbr, + (const uip_lladdr_t *)&lladdr_aligned) < 0) { /* failed to update the lladdr */ goto discard; } @@ -561,7 +564,9 @@ na_input(void) if(is_override || !is_llchange || nd6_opt_llao == NULL) { if(nd6_opt_llao != NULL && is_llchange) { if(!extract_lladdr_from_llao_aligned(&lladdr_aligned) || - nbr_table_update_lladdr((const linkaddr_t *) lladdr, (const linkaddr_t *) &lladdr_aligned, 1) == 0) { + uip_ds6_nbr_update_ll(&nbr, + (const uip_lladdr_t *)&lladdr_aligned) + < 0) { /* failed to update the lladdr */ goto discard; } @@ -925,7 +930,8 @@ ra_input(void) if(memcmp(&nd6_opt_llao[UIP_ND6_OPT_DATA_OFFSET], lladdr, UIP_LLADDR_LEN) != 0) { /* change of link layer address */ - if(nbr_table_update_lladdr((const linkaddr_t *)lladdr, (const linkaddr_t *)&lladdr_aligned, 1) == 0) { + if(uip_ds6_nbr_update_ll(&nbr, + (const uip_lladdr_t *)&lladdr_aligned) < 0) { /* failed to update the lladdr */ goto discard; } diff --git a/os/net/nbr-table.c b/os/net/nbr-table.c index 77d3cb07d..8a8eaeb78 100644 --- a/os/net/nbr-table.c +++ b/os/net/nbr-table.c @@ -439,39 +439,6 @@ nbr_table_get_lladdr(nbr_table_t *table, const void *item) return key != NULL ? &key->lladdr : NULL; } /*---------------------------------------------------------------------------*/ -/* Update link-layer address of an item */ -int -nbr_table_update_lladdr(const linkaddr_t *old_addr, const linkaddr_t *new_addr, - int remove_if_duplicate) -{ - int index; - int new_index; - nbr_table_key_t *key; - index = index_from_lladdr(old_addr); - if(index == -1) { - /* Failure to change since there is nothing to change. */ - return 0; - } - if((new_index = index_from_lladdr(new_addr)) != -1) { - /* check if it is a change or not - do not remove / fail if same */ - if(new_index == index) { - return 1; - } - /* This new entry already exists - failure! - remove if requested. */ - if(remove_if_duplicate) { - remove_key(key_from_index(index)); - } - return 0; - } - key = key_from_index(index); - /** - * Copy the new lladdr into the key - since we know that there is no - * conflicting entry. - */ - memcpy(&key->lladdr, new_addr, sizeof(linkaddr_t)); - return 1; -} -/*---------------------------------------------------------------------------*/ #if DEBUG static void print_table() diff --git a/os/net/nbr-table.h b/os/net/nbr-table.h index d7fad5267..0dccd1092 100644 --- a/os/net/nbr-table.h +++ b/os/net/nbr-table.h @@ -113,7 +113,6 @@ int nbr_table_unlock(nbr_table_t *table, nbr_table_item_t *item); /** \name Neighbor tables: address manipulation */ /** @{ */ linkaddr_t *nbr_table_get_lladdr(nbr_table_t *table, const nbr_table_item_t *item); -int nbr_table_update_lladdr(const linkaddr_t *old_addr, const linkaddr_t *new_addr, int remove_if_duplicate); /** @} */ #endif /* NBR_TABLE_H_ */