From fdcea157a2dc649c2ff8b5a96c9f2511466ba589 Mon Sep 17 00:00:00 2001 From: Mohamed seliem Date: Mon, 4 Jul 2016 19:09:04 +0200 Subject: [PATCH] implementation of ND-6loWPAN [RFC 6775] The commit of this pull is to update the neighbor discovery files to implement the new optimized version of neighbor discovery which suggested by IETF in RFC 6775. IPv6 Neighbor Discovery (ND) based on RFC4861 was developed primarily for wired traffic on the shared medium. Its heavily use the multicast transmission in periodic router-advertisement multicast addresses with router solicitation, neighbor solicitation, address resolution, and duplicate-address detection. While periodic multicast signaling and solicited-node multicast signaling are useful for network stability in the standard Ethernet-based shared network, the limited-lifetime, battery-operated devices in the IEEE 802.15.4 network conserve energy with less signaling and by sending broadcast messages only once in a while. That makes it inefficient and sometimes impractical for IPv6 over Low power Wireless Personal Area Networks (6LoWPAN). (https://tools.ietf.org/html/rfc6775) optimizes multicast messages to uni-cast messages. It eliminates the need for relatively expensive address resolution by sending a neighbor registration option along with a neighbor solicitation; it supports sleepy nodes in the networks; and it optimizes the protocol constants while eliminating periodic router-advertisement messages. You could find all details in the following paper http://eece.cu.edu.eg/~akhattab/files/ND.pdf update tcpip.c to handle ND timers --- core/net/ip/tcpip.c | 2 +- core/net/ipv6/uip-6lowpan-nd6.c | 1317 +++++++++++++++++++++++++++++++ core/net/ipv6/uip-6lowpan-nd6.h | 645 +++++++++++++++ core/net/ipv6/uip-ds6-reg.c | 192 +++++ core/net/ipv6/uip-ds6-reg.h | 181 +++++ core/net/ipv6/uip-ds6-route.h | 4 + core/net/ipv6/uip-ds6.c | 18 +- core/net/ipv6/uip-ds6.h | 15 +- core/net/ipv6/uip-nd6.c | 2 +- 9 files changed, 2368 insertions(+), 8 deletions(-) create mode 100644 core/net/ipv6/uip-6lowpan-nd6.c create mode 100644 core/net/ipv6/uip-6lowpan-nd6.h create mode 100644 core/net/ipv6/uip-ds6-reg.c create mode 100644 core/net/ipv6/uip-ds6-reg.h diff --git a/core/net/ip/tcpip.c b/core/net/ip/tcpip.c index df3f0608d89..420148bd5b3 100644 --- a/core/net/ip/tcpip.c +++ b/core/net/ip/tcpip.c @@ -467,7 +467,7 @@ eventhandler(process_event_t ev, process_data_t data) #if !UIP_CONF_ROUTER if(data == &uip_ds6_timer_rs && etimer_expired(&uip_ds6_timer_rs)) { - uip_ds6_send_rs(); + uip_ds6_send_rs(NULL); tcpip_ipv6_output(); } #endif /* !UIP_CONF_ROUTER */ diff --git a/core/net/ipv6/uip-6lowpan-nd6.c b/core/net/ipv6/uip-6lowpan-nd6.c new file mode 100644 index 00000000000..290878ae83f --- /dev/null +++ b/core/net/ipv6/uip-6lowpan-nd6.c @@ -0,0 +1,1317 @@ +/* + * Copyright (c) 2006, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + * + */ + +/** + * \addtogroup uip6 + * @{ + */ + +/** + * \file + * Header file for IPv6 Neighbor discovery (RFC 4861) + * \author Mohamed Seliem + */ +#include +#include "net/ipv6/uip-icmp6.h" +#include "net/ipv6/uip-6lowpan-nd6.h" +#include "net/ipv6/uip-ds6-reg.h" +#include "net/ipv6/uip-ds6.h" +#include "net/ip/uip-nameserver.h" +#include "lib/random.h" + +/*------------------------------------------------------------------*/ +#define DEBUG 0 +#include "net/ip/uip-debug.h" + +#if UIP_LOGGING +#include +void uip_log(char *msg); + +#define UIP_LOG(m) uip_log(m) +#else +#define UIP_LOG(m) +#endif /* UIP_LOGGING == 1 */ + +#if UIP_CONF_IPV6_LOWPAN_ND +/*------------------------------------------------------------------*/ +/** @{ */ +/** \name Pointers to the header structures. + * All pointers except UIP_IP_BUF depend on uip_ext_len, which at + * packet reception, is the total length of the extension headers. + * + * The pointer to ND6 options header also depends on nd6_opt_offset, + * which we set in each function. + * + * Care should be taken when manipulating these buffers about the + * value of these length variables + */ +#define UIP_IP_BUF ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN]) /**< Pointer to IP header */ +#define UIP_ICMP_BUF ((struct uip_icmp_hdr *)&uip_buf[uip_l2_l3_hdr_len]) /**< Pointer to ICMP header*/ +/**@{ Pointers to messages just after icmp header */ +#define UIP_ND6_RS_BUF ((uip_nd6_rs *)&uip_buf[uip_l2_l3_icmp_hdr_len]) +#define UIP_ND6_RA_BUF ((uip_nd6_ra *)&uip_buf[uip_l2_l3_icmp_hdr_len]) +#define UIP_ND6_NS_BUF ((uip_nd6_ns *)&uip_buf[uip_l2_l3_icmp_hdr_len]) +#define UIP_ND6_NA_BUF ((uip_nd6_na *)&uip_buf[uip_l2_l3_icmp_hdr_len]) +/** @} */ +/** Pointer to ND option */ +#define UIP_ND6_OPT_HDR_BUF ((uip_nd6_opt_hdr *)&uip_buf[uip_l2_l3_icmp_hdr_len + nd6_opt_offset]) +#define UIP_ND6_OPT_PREFIX_BUF ((uip_nd6_opt_prefix_info *)&uip_buf[uip_l2_l3_icmp_hdr_len + nd6_opt_offset]) +#define UIP_ND6_OPT_MTU_BUF ((uip_nd6_opt_mtu *)&uip_buf[uip_l2_l3_icmp_hdr_len + nd6_opt_offset]) +#define UIP_ND6_OPT_RDNSS_BUF ((uip_nd6_opt_dns *)&uip_buf[uip_l2_l3_icmp_hdr_len + nd6_opt_offset]) +#define UIP_ND6_OPT_ARO_BUF ((uip_nd6_opt_aro *)&uip_buf[uip_l2_l3_icmp_hdr_len + nd6_opt_offset]) +#define UIP_ND6_OPT_6CO_BUF ((uip_nd6_opt_6co *)&uip_buf[uip_l2_l3_icmp_hdr_len + nd6_opt_offset]) +#define UIP_ND6_OPT_ABRO_BUF ((uip_nd6_opt_abro *)&uip_buf[uip_l2_l3_icmp_hdr_len + nd6_opt_offset]) +/** @} */ + +#if UIP_ND6_SEND_NA || UIP_ND6_SEND_RA || !UIP_CONF_ROUTER +static uint8_t nd6_opt_offset; /** Offset from the end of the icmpv6 header to the option in uip_buf*/ +static uint8_t *nd6_opt_llao; /** Pointer to llao option in uip_buf */ +static uip_nd6_opt_aro * nd6_opt_aro; /** Pointer to aro option in uip_buf */ +static uip_ds6_nbr_t *nbr; /** Pointer to a nbr cache entry*/ +static uip_ds6_defrt_t *defrt; /** Pointer to a router list entry */ +static uip_ds6_addr_t *addr; /** Pointer to an interface address */ +static uip_ds6_reg_t *reg; /** Pointer to an address registration list entry */ +#endif /* UIP_ND6_SEND_NA || UIP_ND6_SEND_RA || !UIP_CONF_ROUTER */ + +#if !UIP_CONF_ROUTER // TBD see if we move it to ra_input +static uip_nd6_opt_prefix_info *nd6_opt_prefix_info; /** Pointer to prefix information option in uip_buf */ +static uip_ipaddr_t ipaddr; +#endif +#if (!UIP_CONF_ROUTER || UIP_ND6_SEND_RA) +static uip_ds6_prefix_t *prefix; /** Pointer to a prefix list entry */ +#endif + +#if UIP_ND6_SEND_NA || UIP_ND6_SEND_RA || !UIP_CONF_ROUTER +/*------------------------------------------------------------------*/ +/* Copy link-layer address from LLAO option to a word-aligned uip_lladdr_t */ +static int +extract_lladdr_from_llao_aligned(uip_lladdr_t *dest) { + if(dest != NULL && nd6_opt_llao != NULL) { + memcpy(dest, &nd6_opt_llao[UIP_ND6_OPT_DATA_OFFSET], UIP_LLADDR_LEN); + return 1; + } + return 0; +} +#endif /* UIP_ND6_SEND_NA || UIP_ND6_SEND_RA || !UIP_CONF_ROUTER */ +/*------------------------------------------------------------------*/ +/* create a llao */ +static void +create_llao(uint8_t *llao, uint8_t type) { + llao[UIP_ND6_OPT_TYPE_OFFSET] = type; + llao[UIP_ND6_OPT_LEN_OFFSET] = UIP_ND6_OPT_LLAO_LEN >> 3; + memcpy(&llao[UIP_ND6_OPT_DATA_OFFSET], &uip_lladdr, UIP_LLADDR_LEN); + /* padding on some */ + memset(&llao[UIP_ND6_OPT_DATA_OFFSET + UIP_LLADDR_LEN], 0, + UIP_ND6_OPT_LLAO_LEN - 2 - UIP_LLADDR_LEN); +} + +/*------------------------------------------------------------------*/ +static void +create_aro(uip_nd6_opt_aro * aro, uint16_t lifetime, uint8_t status) { + aro->type =(uint8_t)UIP_ND6_OPT_ARO; + aro->len =(uint8_t) UIP_ND6_OPT_ARO_LEN; + aro->reserved1=(uint8_t)0; + aro->reserved2=(uint16_t)0; + aro->status = status; /* Status: must be set to 0 in NS */ + aro->lifetime = uip_htons(lifetime); + memcpy(&(((uip_nd6_opt_aro*)aro)->eui64), &uip_lladdr, UIP_LLADDR_LEN); +} +/*------------------------------------------------------------------*/ + +#if UIP_ND6_SEND_NA +static void +ns_input(void) +{ + uint8_t flags; + PRINTF("Received NS from "); + PRINT6ADDR(&UIP_IP_BUF->srcipaddr); + PRINTF(" to "); + PRINT6ADDR(&UIP_IP_BUF->destipaddr); + PRINTF(" with target address "); + PRINT6ADDR((uip_ipaddr_t *) (&UIP_ND6_NS_BUF->tgtipaddr)); + PRINTF("\n"); + UIP_STAT(++uip_stat.nd6.recv); + +#if UIP_CONF_IPV6_CHECKS + if((UIP_IP_BUF->ttl != UIP_ND6_HOP_LIMIT) || + (uip_is_addr_mcast(&UIP_ND6_NS_BUF->tgtipaddr)) || + (UIP_ICMP_BUF->icode != 0)) { + PRINTF("NS received is bad\n"); + goto discard; + } +#endif /* UIP_CONF_IPV6_CHECKS */ + + /* Options processing */ + nd6_opt_llao = NULL; + nd6_opt_aro=NULL; + nd6_opt_offset = UIP_ND6_NS_LEN; + while(uip_l3_icmp_hdr_len + nd6_opt_offset < uip_len) { +#if UIP_CONF_IPV6_CHECKS + if(UIP_ND6_OPT_HDR_BUF->len == 0) { + PRINTF("NS received is bad\n"); + goto discard; + } +#endif /* UIP_CONF_IPV6_CHECKS */ + switch (UIP_ND6_OPT_HDR_BUF->type) { + case UIP_ND6_OPT_SLLAO: + nd6_opt_llao = &uip_buf[uip_l2_l3_icmp_hdr_len + nd6_opt_offset]; +#if UIP_CONF_IPV6_CHECKS + /* There must be NO option in a DAD NS */ + if(uip_is_addr_unspecified(&UIP_IP_BUF->srcipaddr)) { + PRINTF("NS received is bad\n"); + goto discard; + } else { +#endif /*UIP_CONF_IPV6_CHECKS */ + uip_lladdr_t lladdr_aligned; + extract_lladdr_from_llao_aligned(&lladdr_aligned); + nbr = uip_ds6_nbr_lookup(&UIP_IP_BUF->srcipaddr); +#if UIP_CONF_ROUTER + if(nbr == NULL) { + uip_ds6_nbr_add(&UIP_IP_BUF->srcipaddr, &lladdr_aligned, + 0, NBR_STALE, NBR_TABLE_REASON_IPV6_ND, NULL); + } else { + const uip_lladdr_t *lladdr = uip_ds6_nbr_get_ll(nbr); + if(lladdr == NULL) { + goto discard; + } + 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) { + /* failed to update the lladdr */ + goto discard; + } + nbr->state = NBR_STALE; + } else { + if(nbr->state == NBR_INCOMPLETE) { + nbr->state = NBR_STALE; + } + } + } +#endif +#if UIP_CONF_IPV6_CHECKS + } +#endif /*UIP_CONF_IPV6_CHECKS */ + break; + /** A router handles NS messages as specified in [RFC4861], with added +logic described in RfC 6775 section 6.5. for handling the ARO.*/ + case UIP_ND6_OPT_ARO: + nd6_opt_aro = (uip_nd6_opt_aro *)UIP_ND6_OPT_HDR_BUF; +#if UIP_CONF_IPV6_CHECKS + if((nd6_opt_aro->len != UIP_ND6_OPT_ARO_LEN) + ||(nd6_opt_aro->status != 0)||(nd6_opt_llao == NULL)) { + + /* If the source address of the NS is the unspecified address, or if no + * SLLAO is included, then any included ARO is ignored, that is, the NS + * is processed as if it did not contain an ARO.ignore this option */ + nd6_opt_aro = NULL; + PRINTF("ND ARO option is not supported in received NS\n"); + }else{ + PRINTF("ND ARO option is supported in received NS\n"); + } + +#endif /* UIP_CONF_IPV6_CHECKS */ + reg = uip_ds6_reg_lookup(&UIP_IP_BUF->srcipaddr,&UIP_IP_BUF->destipaddr); + if(reg == NULL) { + uip_ds6_reg_add(&UIP_IP_BUF->srcipaddr, + (uip_ds6_defrt_t*)(&UIP_IP_BUF->destipaddr), REG_REGISTERED,nd6_opt_aro->lifetime); + } else{ + if (nd6_opt_aro->lifetime == 0) { + + /* If the lifetime is 0, this means that the un-registration is required; + * we can delete the registration entry safely */ + reg->state = REG_TO_BE_UNREGISTERED; + uip_ds6_reg_rm(reg); /* Remove entry */ + } + /**else update the registery timer;*/ + else{ + uip_ds6_reg_update(&UIP_IP_BUF->srcipaddr, + (uip_ds6_defrt_t*)(&UIP_IP_BUF->destipaddr),nd6_opt_aro->lifetime); + } + } + break; + default: + PRINTF("ND option not supported in NS"); + break; + } + nd6_opt_offset += (UIP_ND6_OPT_HDR_BUF->len << 3); + } + + addr = uip_ds6_addr_lookup(&UIP_ND6_NS_BUF->tgtipaddr); + if(addr != NULL) { + if(uip_is_addr_unspecified(&UIP_IP_BUF->srcipaddr)) { + /* DAD CASE */ +#if UIP_ND6_DEF_MAXDADNS > 0 +#if UIP_CONF_IPV6_CHECKS + if(!uip_is_addr_solicited_node(&UIP_IP_BUF->destipaddr)) { + PRINTF("NS received is bad\n"); + goto discard; + } +#endif /* UIP_CONF_IPV6_CHECKS */ + if(addr->state != ADDR_TENTATIVE) { + uip_create_linklocal_allnodes_mcast(&UIP_IP_BUF->destipaddr); + uip_ds6_select_src(&UIP_IP_BUF->srcipaddr, &UIP_IP_BUF->destipaddr); + flags = UIP_ND6_NA_FLAG_OVERRIDE; + goto create_na; + } else { + /** \todo if I sent a NS before him, I win */ + uip_ds6_dad_failed(addr); + goto discard; + } +#else /* UIP_ND6_DEF_MAXDADNS > 0 */ + goto discard; /* DAD CASE */ +#endif /* UIP_ND6_DEF_MAXDADNS > 0 */ + } +#if UIP_CONF_IPV6_CHECKS + if(uip_ds6_is_my_addr(&UIP_IP_BUF->srcipaddr)) { + /** + * \NOTE do we do something here? we both are using the same address. + * If we are doing dad, we could cancel it, though we should receive a + * NA in response of DAD NS we sent, hence DAD will fail anyway. If we + * were not doing DAD, it means there is a duplicate in the network! + */ + PRINTF("NS received is bad\n"); + goto discard; + } +#endif /*UIP_CONF_IPV6_CHECKS */ + + /* NUD CASE */ + if(uip_ds6_addr_lookup(&UIP_IP_BUF->destipaddr) == addr) { + uip_ipaddr_copy(&UIP_IP_BUF->destipaddr, &UIP_IP_BUF->srcipaddr); + uip_ipaddr_copy(&UIP_IP_BUF->srcipaddr, &UIP_ND6_NS_BUF->tgtipaddr); + flags = UIP_ND6_NA_FLAG_SOLICITED | UIP_ND6_NA_FLAG_OVERRIDE; + goto create_na; + } else { +#if UIP_CONF_IPV6_CHECKS + PRINTF("NS received is bad\n"); + goto discard; +#endif /* UIP_CONF_IPV6_CHECKS */ + } + } else { + goto discard; + } + + +create_na: + /* If the node is a router it should set R flag in NAs */ +#if UIP_CONF_ROUTER + flags = flags | UIP_ND6_NA_FLAG_ROUTER; +#endif + uip_ext_len = 0; + UIP_IP_BUF->vtc = 0x60; + UIP_IP_BUF->tcflow = 0; + UIP_IP_BUF->flow = 0; + UIP_IP_BUF->len[0] = 0; /* length will not be more than 255 */ +#if UIP_CONF_ROUTER +/**in case of ARO included */ + if(flags==(UIP_ND6_NA_FLAG_SOLICITED | UIP_ND6_NA_FLAG_OVERRIDE |UIP_ND6_NA_FLAG_ROUTER)){ + UIP_IP_BUF->len[1] = UIP_ICMPH_LEN + UIP_ND6_NA_LEN + UIP_ND6_OPT_LLAO_LEN+(UIP_ND6_OPT_ARO_LEN<<3); + } + else{ + UIP_IP_BUF->len[1] = UIP_ICMPH_LEN + UIP_ND6_NA_LEN + UIP_ND6_OPT_LLAO_LEN; + } +#else + UIP_IP_BUF->len[1] = UIP_ICMPH_LEN + UIP_ND6_NA_LEN + UIP_ND6_OPT_LLAO_LEN; +#endif + + UIP_IP_BUF->proto = UIP_PROTO_ICMP6; + UIP_IP_BUF->ttl = UIP_ND6_HOP_LIMIT; + + UIP_ICMP_BUF->type = ICMP6_NA; + UIP_ICMP_BUF->icode = 0; + + UIP_ND6_NA_BUF->flagsreserved = flags; + memcpy(&UIP_ND6_NA_BUF->tgtipaddr, &addr->ipaddr, sizeof(uip_ipaddr_t)); + + create_llao(&uip_buf[uip_l2_l3_icmp_hdr_len + UIP_ND6_NA_LEN], + UIP_ND6_OPT_TLLAO); +#if UIP_CONF_ROUTER +/**in case of ARO included */ + if(uip_is_addr_unspecified(&UIP_IP_BUF->srcipaddr)){ + create_aro(&uip_buf[uip_l2_l3_icmp_hdr_len + UIP_ND6_NA_LEN+UIP_ND6_OPT_LLAO_LEN], + UIP_ND6_REGISTRATION_LIFETIME, UIP_ND6_ARO_DUPLICATE_ADDRESS); + } + else if(uip_ds6_addr_lookup(&UIP_IP_BUF->destipaddr) == addr){ + create_aro(&uip_buf[uip_l2_l3_icmp_hdr_len + UIP_ND6_NA_LEN+UIP_ND6_OPT_LLAO_LEN], + UIP_ND6_REGISTRATION_LIFETIME, UIP_ND6_ARO_SUCCESS); + } + else{ + /** \todo check for full cache */ + create_aro(&uip_buf[uip_l2_l3_icmp_hdr_len + UIP_ND6_NA_LEN+UIP_ND6_OPT_LLAO_LEN], + UIP_ND6_REGISTRATION_LIFETIME, UIP_ND6_ARO_NCE_FULL); + } +#endif + UIP_ICMP_BUF->icmpchksum = 0; + UIP_ICMP_BUF->icmpchksum = ~uip_icmp6chksum(); + +#if UIP_CONF_ROUTER +/**in case of ARO included */ + if(flags==(UIP_ND6_NA_FLAG_SOLICITED | UIP_ND6_NA_FLAG_OVERRIDE |UIP_ND6_NA_FLAG_ROUTER)){ + uip_len = + UIP_IPH_LEN + UIP_ICMPH_LEN + UIP_ND6_NA_LEN + UIP_ND6_OPT_LLAO_LEN+UIP_ND6_OPT_ARO_LEN; + PRINTF("ARO supported in NA message \n"); + } + else{ + uip_len = + UIP_IPH_LEN + UIP_ICMPH_LEN + UIP_ND6_NA_LEN + UIP_ND6_OPT_LLAO_LEN; + PRINTF("ARO not supported in NA message \n"); + } +#else + uip_len = + UIP_IPH_LEN + UIP_ICMPH_LEN + UIP_ND6_NA_LEN + UIP_ND6_OPT_LLAO_LEN; +#endif + + UIP_STAT(++uip_stat.nd6.sent); + PRINTF("Sending NA to "); + PRINT6ADDR(&UIP_IP_BUF->destipaddr); + PRINTF(" from "); + PRINT6ADDR(&UIP_IP_BUF->srcipaddr); + PRINTF(" with target address "); + PRINT6ADDR(&UIP_ND6_NA_BUF->tgtipaddr); + PRINTF("\n"); + return; + +discard: + uip_clear_buf(); + return; +} +#endif /* UIP_ND6_SEND_NA */ + +/*------------------------------------------------------------------*/ +void +uip_nd6_ns_output(uip_ipaddr_t * src, uip_ipaddr_t * dest, uip_ipaddr_t * tgt,uint8_t aro, uint16_t lifetime) +{ + uip_ext_len = 0; + UIP_IP_BUF->vtc = 0x60; + UIP_IP_BUF->tcflow = 0; + UIP_IP_BUF->flow = 0; + UIP_IP_BUF->proto = UIP_PROTO_ICMP6; + UIP_IP_BUF->ttl = UIP_ND6_HOP_LIMIT; + + if(dest == NULL) { + uip_create_solicited_node(tgt, &UIP_IP_BUF->destipaddr); + } else { + uip_ipaddr_copy(&UIP_IP_BUF->destipaddr, dest); + } + UIP_ICMP_BUF->type = ICMP6_NS; + UIP_ICMP_BUF->icode = 0; + UIP_ND6_NS_BUF->reserved = 0; + uip_ipaddr_copy((uip_ipaddr_t *) &UIP_ND6_NS_BUF->tgtipaddr, tgt); + UIP_IP_BUF->len[0] = 0; /* length will not be more than 255 */ + /* + * check if we add a SLLAO option: for DAD, MUST NOT, for NUD, MAY + * (here yes), for Address resolution , MUST + */ + if(!(uip_ds6_is_my_addr(tgt))) { + if(src != NULL) { + uip_ipaddr_copy(&UIP_IP_BUF->srcipaddr, src); + } else { + uip_ds6_select_src(&UIP_IP_BUF->srcipaddr, &UIP_IP_BUF->destipaddr); + } + if (uip_is_addr_unspecified(&UIP_IP_BUF->srcipaddr)) { + PRINTF("Dropping NS due to no suitable source address\n"); + uip_clear_buf(); + return; + } + if (aro) { + UIP_IP_BUF->len[1] = + UIP_ICMPH_LEN + UIP_ND6_NS_LEN + UIP_ND6_OPT_LLAO_LEN+ (UIP_ND6_OPT_ARO_LEN<<3); + create_llao(&uip_buf[uip_l2_l3_icmp_hdr_len + UIP_ND6_NS_LEN], + UIP_ND6_OPT_SLLAO); + create_aro((uip_nd6_opt_aro *)&uip_buf[uip_l2_l3_icmp_hdr_len + UIP_ND6_NS_LEN + UIP_ND6_OPT_LLAO_LEN], + lifetime, UIP_ND6_ARO_SUCCESS);/*status field must be set to 0 in ns messages*/ + uip_len = + UIP_IPH_LEN + UIP_ICMPH_LEN + UIP_ND6_NS_LEN + UIP_ND6_OPT_LLAO_LEN+ (UIP_ND6_OPT_ARO_LEN<<3); + PRINTF("ARO supported in this message\n"); + } + else { + PRINTF("ARO is not supported in this message\n"); + UIP_IP_BUF->len[1] = + UIP_ICMPH_LEN + UIP_ND6_NS_LEN + UIP_ND6_OPT_LLAO_LEN; + create_llao(&uip_buf[uip_l2_l3_icmp_hdr_len + UIP_ND6_NS_LEN], + UIP_ND6_OPT_SLLAO); + uip_len = + UIP_IPH_LEN + UIP_ICMPH_LEN + UIP_ND6_NS_LEN + UIP_ND6_OPT_LLAO_LEN; + } + } else { + uip_create_unspecified(&UIP_IP_BUF->srcipaddr); + UIP_IP_BUF->len[1] = UIP_ICMPH_LEN + UIP_ND6_NS_LEN; + uip_len = UIP_IPH_LEN + UIP_ICMPH_LEN + UIP_ND6_NS_LEN; + } + + UIP_ICMP_BUF->icmpchksum = 0; + UIP_ICMP_BUF->icmpchksum = ~uip_icmp6chksum(); + + UIP_STAT(++uip_stat.nd6.sent); + PRINTF("Sending NS to "); + PRINT6ADDR(&UIP_IP_BUF->destipaddr); + PRINTF(" from "); + PRINT6ADDR(&UIP_IP_BUF->srcipaddr); + PRINTF(" with target address "); + PRINT6ADDR(tgt); + PRINTF("\n"); + return; +} +#if UIP_ND6_SEND_NA +/*------------------------------------------------------------------*/ +/** + * Neighbor Advertisement Processing + * + * we might have to send a pkt that had been buffered while address + * resolution was performed (if we support buffering, see UIP_CONF_QUEUE_PKT) + * + * As per RFC 4861, on link layer that have addresses, TLLAO options MUST be + * included when responding to multicast solicitations, SHOULD be included in + * response to unicast (here we assume it is for now) + * + * NA can be received after sending NS for DAD, Address resolution or NUD. Can + * be unsolicited as well. + * It can trigger update of the state of the neighbor in the neighbor cache, + * router in the router list. + * If the NS was for DAD, it means DAD failed + * + */ +static void +na_input(void) +{ + uint8_t is_llchange; + uint8_t is_router; + uint8_t is_solicited; + uint8_t is_override; + uip_lladdr_t lladdr_aligned; + + PRINTF("Received NA from "); + PRINT6ADDR(&UIP_IP_BUF->srcipaddr); + PRINTF(" to "); + PRINT6ADDR(&UIP_IP_BUF->destipaddr); + PRINTF(" with target address "); + PRINT6ADDR((uip_ipaddr_t *) (&UIP_ND6_NA_BUF->tgtipaddr)); + PRINTF("\n"); + UIP_STAT(++uip_stat.nd6.recv); + + /* + * booleans. the three last one are not 0 or 1 but 0 or 0x80, 0x40, 0x20 + * but it works. Be careful though, do not use tests such as is_router == 1 + */ + is_llchange = 0; + is_router = ((UIP_ND6_NA_BUF->flagsreserved & UIP_ND6_NA_FLAG_ROUTER)); + is_solicited = + ((UIP_ND6_NA_BUF->flagsreserved & UIP_ND6_NA_FLAG_SOLICITED)); + is_override = + ((UIP_ND6_NA_BUF->flagsreserved & UIP_ND6_NA_FLAG_OVERRIDE)); + +#if UIP_CONF_IPV6_CHECKS + if((UIP_IP_BUF->ttl != UIP_ND6_HOP_LIMIT) || + (UIP_ICMP_BUF->icode != 0) || + (uip_is_addr_mcast(&UIP_ND6_NA_BUF->tgtipaddr)) || + (is_solicited && uip_is_addr_mcast(&UIP_IP_BUF->destipaddr))) { + PRINTF("NA received is bad\n"); + goto discard; + } +#endif /*UIP_CONF_IPV6_CHECKS */ + +#if !UIP_CONF_ROUTER +/* We are not interested in NA messages not coming from a router */ + if (!is_router) { + nbr = uip_ds6_nbr_lookup(&UIP_IP_BUF->srcipaddr); + if (nbr != NULL) { + uip_ds6_nbr_rm(nbr); + } + defrt = uip_ds6_defrt_lookup(&UIP_IP_BUF->srcipaddr); + if (defrt != NULL) { + uip_ds6_defrt_rm(defrt); + /* Since we are deleting a default router, we must delete also all + * registrations with that router. */ + uip_ds6_reg_cleanup_defrt(defrt); + /* We will also need to start sending RS, as specified in RFC 6775 + * for a router that has become unreachable */ + uip_ds6_send_rs(NULL); + } + goto discard; + } +#endif /* !UIP_CONF_ROUTER */ + + /* Options processing: we handle TLLAO, (if RFC6775 is used) ARO, + * and must ignore others */ + nd6_opt_offset = UIP_ND6_NA_LEN; + nd6_opt_llao = NULL; + nd6_opt_aro = NULL; + while(uip_l3_icmp_hdr_len + nd6_opt_offset < uip_len) { +#if UIP_CONF_IPV6_CHECKS + if(UIP_ND6_OPT_HDR_BUF->len == 0) { + PRINTF("NA received is bad\n"); + goto discard; + } +#endif /*UIP_CONF_IPV6_CHECKS */ + switch (UIP_ND6_OPT_HDR_BUF->type) { + case UIP_ND6_OPT_TLLAO: + nd6_opt_llao = (uint8_t *)UIP_ND6_OPT_HDR_BUF; + break; + case UIP_ND6_OPT_ARO: + nd6_opt_aro = (uip_nd6_opt_aro *)UIP_ND6_OPT_HDR_BUF; +#if UIP_CONF_IPV6_CHECKS + if((nd6_opt_aro->len != UIP_ND6_OPT_ARO_LEN) || + (memcmp(&nd6_opt_aro->eui64, &uip_lladdr, UIP_LLADDR_LEN) != 0)) { + /* ignore this option */ + nd6_opt_aro = NULL; + } +#endif /* UIP_CONF_IPV6_CHECKS */ + break; + default: + PRINTF("ND option not supported in NA\n"); + break; + } + nd6_opt_offset += (UIP_ND6_OPT_HDR_BUF->len << 3); + } + addr = uip_ds6_addr_lookup(&UIP_ND6_NA_BUF->tgtipaddr); + /* Message processing, including TLLAO if any */ + if(addr != NULL) { +#if UIP_ND6_DEF_MAXDADNS > 0 + if(addr->state == ADDR_TENTATIVE) { + uip_ds6_dad_failed(addr); + } +#endif /*UIP_ND6_DEF_MAXDADNS > 0 */ + PRINTF("NA received is bad\n"); + goto discard; + } else { + const uip_lladdr_t *lladdr; + nbr = uip_ds6_nbr_lookup(&UIP_ND6_NA_BUF->tgtipaddr); + if(nbr == NULL) { + goto discard; + } + lladdr = uip_ds6_nbr_get_ll(nbr); + if(lladdr == NULL) { + goto discard; + } + if(nd6_opt_llao != NULL) { + is_llchange = + memcmp(&nd6_opt_llao[UIP_ND6_OPT_DATA_OFFSET], lladdr, + UIP_LLADDR_LEN); + } + if(nd6_opt_aro != NULL) { +#if UIP_CONF_ROUTER +#if UIP_CONF_IPV6_LOWPAN_ND + reg = uip_ds6_if.registration_in_progress; +#endif + if (reg != NULL) { + if ((nd6_opt_aro->lifetime == 0) && + (reg->state == REG_TO_BE_UNREGISTERED)) { + /** If the lifetime is 0, + this means that the un-registration was successful; + we can delete the registration entry safely */ + uip_ds6_reg_rm(reg); /* Remove entry */ + } + else + { + addr = uip_ds6_addr_lookup(&UIP_IP_BUF->destipaddr); + switch(nd6_opt_aro->status) { + case UIP_ND6_ARO_SUCCESS: + /* Make sure this is actually the address we are registering */ + if (reg->addr == addr) { + /* Clear the NS count */ + addr->state = ADDR_PREFERRED; + reg->state = REG_REGISTERED; + reg->reg_count = 0; + stimer_set(®->reg_lifetime, uip_ntohs(nd6_opt_aro->lifetime) * 60); +#if UIP_CONF_IPV6_LOWPAN_ND + uip_ds6_if.registration_in_progress = NULL; +#endif + } + break; + case UIP_ND6_ARO_DUPLICATE_ADDRESS: + /* Remove the address */ + uip_ds6_addr_rm(addr); + /* Clear registration_in_progress so that other registrations can occur */ +#if UIP_CONF_IPV6_LOWPAN_ND + uip_ds6_if.registration_in_progress = NULL; +#endif + /* If we have registered the address with any other router, we must void + * such registrations by sending a ns with ARO with 0 lifetime */ + uip_ds6_reg_cleanup_addr(addr); + break; + case UIP_ND6_ARO_NCE_FULL: + /* Remove entry. uip_ds6_periodic will try with other def. router + * if possible */ + uip_ds6_reg_rm(reg); +#if UIP_CONF_IPV6_LOWPAN_ND + uip_ds6_if.registration_in_progress = NULL; +#endif + break; + default: + break; + + } + } + } +#else +switch(nd6_opt_aro->status) { + case UIP_ND6_ARO_SUCCESS: + /* Make sure this is actually my address */ + if (uip_ds6_is_my_addr(&UIP_ND6_NA_BUF->tgtipaddr)) { + PRINTF("ARO supported in this message\n"); + } + break; + case UIP_ND6_ARO_DUPLICATE_ADDRESS: + PRINTF("Duplicate address, received is bad\n"); + goto discard; + break; + case UIP_ND6_ARO_NCE_FULL: + PRINTF("RTR cache is full, NA received is bad\n"); + goto discard; + break; + default: + break; + } + +#endif /*UIP_CONF_ROUTER*/ + } + /* NBR can not be INCOMPLETE in 6lowpan-nd*/ + if(!is_override && is_llchange) { + if(nbr->state == NBR_REACHABLE) { + nbr->state = NBR_STALE; + } + goto discard; + } else { + /** + * If this is an cache override, or same lladdr, or no llao - + * do updates of nbr states. + */ + 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) { + /* failed to update the lladdr */ + goto discard; + } + } + if(is_solicited) { + nbr->state = NBR_REACHABLE; + /* reachable time is stored in ms */ + stimer_set(&(nbr->reachable), uip_ds6_if.reachable_time / 1000); + } + } + } + if(nbr->isrouter && !is_router) { + defrt = uip_ds6_defrt_lookup(&UIP_IP_BUF->srcipaddr); + if(defrt != NULL) { + uip_ds6_defrt_rm(defrt); + } + } + nbr->isrouter = is_router; + } +#if UIP_CONF_IPV6_QUEUE_PKT + /* The nbr is now reachable, check if we had buffered a pkt for it */ + /*if(nbr->queue_buf_len != 0) { + uip_len = nbr->queue_buf_len; + memcpy(UIP_IP_BUF, nbr->queue_buf, uip_len); + nbr->queue_buf_len = 0; + return; + }*/ + if(uip_packetqueue_buflen(&nbr->packethandle) != 0) { + uip_len = uip_packetqueue_buflen(&nbr->packethandle); + memcpy(UIP_IP_BUF, uip_packetqueue_buf(&nbr->packethandle), uip_len); + uip_packetqueue_free(&nbr->packethandle); + return; + } + +#endif /*UIP_CONF_IPV6_QUEUE_PKT */ + +discard: + uip_clear_buf(); + return; +} +#endif /* UIP_ND6_SEND_NA */ + + +#if UIP_CONF_ROUTER +#if UIP_ND6_SEND_RA +/*---------------------------------------------------------------------------*/ +static void +rs_input(void) +{ + + PRINTF("Received RS from "); + PRINT6ADDR(&UIP_IP_BUF->srcipaddr); + PRINTF(" to "); + PRINT6ADDR(&UIP_IP_BUF->destipaddr); + PRINTF("\n"); + UIP_STAT(++uip_stat.nd6.recv); + + +#if UIP_CONF_IPV6_CHECKS + /* + * Check hop limit / icmp code + * target address must not be multicast + * if the NA is solicited, dest must not be multicast + */ + if((UIP_IP_BUF->ttl != UIP_ND6_HOP_LIMIT) || (UIP_ICMP_BUF->icode != 0)) { + PRINTF("RS received is bad\n"); + goto discard; + } +#endif /*UIP_CONF_IPV6_CHECKS */ + + /* Only valid option is Source Link-Layer Address option any thing + else is discarded */ + nd6_opt_offset = UIP_ND6_RS_LEN; + nd6_opt_llao = NULL; + + while(uip_l3_icmp_hdr_len + nd6_opt_offset < uip_len) { +#if UIP_CONF_IPV6_CHECKS + if(UIP_ND6_OPT_HDR_BUF->len == 0) { + PRINTF("RS received is bad\n"); + goto discard; + } +#endif /*UIP_CONF_IPV6_CHECKS */ + switch (UIP_ND6_OPT_HDR_BUF->type) { + case UIP_ND6_OPT_SLLAO: + nd6_opt_llao = (uint8_t *)UIP_ND6_OPT_HDR_BUF; + break; + default: + PRINTF("ND option not supported in RS\n"); + break; + } + nd6_opt_offset += (UIP_ND6_OPT_HDR_BUF->len << 3); + } + /* Options processing: only SLLAO */ + if(nd6_opt_llao != NULL) { +#if UIP_CONF_IPV6_CHECKS + if(uip_is_addr_unspecified(&UIP_IP_BUF->srcipaddr)) { + PRINTF("RS received is bad\n"); + goto discard; + } else { +#endif /*UIP_CONF_IPV6_CHECKS */ + uip_lladdr_t lladdr_aligned; + extract_lladdr_from_llao_aligned(&lladdr_aligned); + if((nbr = uip_ds6_nbr_lookup(&UIP_IP_BUF->srcipaddr)) == NULL) { + /* we need to add the neighbor */ + uip_ds6_nbr_add(&UIP_IP_BUF->srcipaddr, &lladdr_aligned, + 0, NBR_STALE, NBR_TABLE_REASON_IPV6_ND, NULL); + } else { + /* If LL address changed, set neighbor state to stale */ + const uip_lladdr_t *lladdr = uip_ds6_nbr_get_ll(nbr); + if(lladdr == NULL) { + goto discard; + } + if(memcmp(&nd6_opt_llao[UIP_ND6_OPT_DATA_OFFSET], + lladdr, UIP_LLADDR_LEN) != 0) { + uip_ds6_nbr_t nbr_data = *nbr; + uip_ds6_nbr_rm(nbr); + nbr = uip_ds6_nbr_add(&UIP_IP_BUF->srcipaddr, &lladdr_aligned, + 0, NBR_STALE, NBR_TABLE_REASON_IPV6_ND, NULL); + nbr->reachable = nbr_data.reachable; + nbr->sendns = nbr_data.sendns; + nbr->nscount = nbr_data.nscount; + } + nbr->isrouter = 0; + } +#if UIP_CONF_IPV6_CHECKS + } +#endif /*UIP_CONF_IPV6_CHECKS */ + } + + /* Schedule a sollicited RA */ + uip_ds6_send_ra_sollicited(&UIP_IP_BUF->srcipaddr); + +discard: + uip_clear_buf(); + return; +} + +/*---------------------------------------------------------------------------*/ +void +uip_nd6_ra_output(uip_ipaddr_t * dest) +{ + + UIP_IP_BUF->vtc = 0x60; + UIP_IP_BUF->tcflow = 0; + UIP_IP_BUF->flow = 0; + UIP_IP_BUF->proto = UIP_PROTO_ICMP6; + UIP_IP_BUF->ttl = UIP_ND6_HOP_LIMIT; + + if(dest == NULL) { + uip_create_linklocal_allnodes_mcast(&UIP_IP_BUF->destipaddr); + } else { + /* For sollicited RA */ + uip_ipaddr_copy(&UIP_IP_BUF->destipaddr, dest); + } + uip_ds6_select_src(&UIP_IP_BUF->srcipaddr, &UIP_IP_BUF->destipaddr); + + UIP_ICMP_BUF->type = ICMP6_RA; + UIP_ICMP_BUF->icode = 0; + + UIP_ND6_RA_BUF->cur_ttl = uip_ds6_if.cur_hop_limit; + + UIP_ND6_RA_BUF->flags_reserved = + (UIP_ND6_M_FLAG << 7) | (UIP_ND6_O_FLAG << 6); + + UIP_ND6_RA_BUF->router_lifetime = uip_htons(UIP_ND6_ROUTER_LIFETIME); + //UIP_ND6_RA_BUF->reachable_time = uip_htonl(uip_ds6_if.reachable_time); + //UIP_ND6_RA_BUF->retrans_timer = uip_htonl(uip_ds6_if.retrans_timer); + UIP_ND6_RA_BUF->reachable_time = 0; + UIP_ND6_RA_BUF->retrans_timer = 0; + + uip_len = UIP_IPH_LEN + UIP_ICMPH_LEN + UIP_ND6_RA_LEN; + nd6_opt_offset = UIP_ND6_RA_LEN; + + + /* Prefix list */ + for(prefix = uip_ds6_prefix_list; + prefix < uip_ds6_prefix_list + UIP_DS6_PREFIX_NB; prefix++) { + if((prefix->isused) && (prefix->advertise)) { + UIP_ND6_OPT_PREFIX_BUF->type = UIP_ND6_OPT_PREFIX_INFO; + UIP_ND6_OPT_PREFIX_BUF->len = UIP_ND6_OPT_PREFIX_INFO_LEN / 8; + UIP_ND6_OPT_PREFIX_BUF->preflen = prefix->length; + UIP_ND6_OPT_PREFIX_BUF->flagsreserved1 = prefix->l_a_reserved; + UIP_ND6_OPT_PREFIX_BUF->validlt = uip_htonl(prefix->vlifetime); + UIP_ND6_OPT_PREFIX_BUF->preferredlt = uip_htonl(prefix->plifetime); + UIP_ND6_OPT_PREFIX_BUF->reserved2 = 0; + uip_ipaddr_copy(&(UIP_ND6_OPT_PREFIX_BUF->prefix), &(prefix->ipaddr)); + nd6_opt_offset += UIP_ND6_OPT_PREFIX_INFO_LEN; + uip_len += UIP_ND6_OPT_PREFIX_INFO_LEN; + } + } + + /* context list */ +#if UIP_ND6_RA_6CO +/* + for(context = uip_ds6_context_list; + context < uip_ds6_context_list + UIP_DS6_CONTEXT_NB; context++) { + if((prefix->isused) && (prefix->advertise)) { + UIP_ND6_OPT_CONTEXT_BUF->type = UIP_ND6_OPT_6CO; + UIP_ND6_OPT_CONTEXT_BUF->len = UIP_ND6_OPT_6CO_LEN ; + UIP_ND6_OPT_CONTEXT_BUF->context_len = context->length; + UIP_ND6_OPT_CONTEXT_BUF->valid_lifetime = uip_htonl(context->vlifetime); + UIP_ND6_OPT_CONTEXT_BUF->reserved = 0; + uip_ipaddr_copy(&(UIP_ND6_OPT_PREFIX_BUF->prefix), &(context->ipaddr)); + nd6_opt_offset += (UIP_ND6_OPT_CONTEXT_INFO_LEN<<8); + uip_len += (UIP_ND6_OPT_CONTEXT_INFO_LEN<<8); + } + } + + +*/ +#endif + /* Source link-layer option */ + create_llao((uint8_t *)UIP_ND6_OPT_HDR_BUF, UIP_ND6_OPT_SLLAO); + + uip_len += UIP_ND6_OPT_LLAO_LEN; + nd6_opt_offset += UIP_ND6_OPT_LLAO_LEN; + + /* MTU */ + UIP_ND6_OPT_MTU_BUF->type = UIP_ND6_OPT_MTU; + UIP_ND6_OPT_MTU_BUF->len = UIP_ND6_OPT_MTU_LEN >> 3; + UIP_ND6_OPT_MTU_BUF->reserved = 0; + //UIP_ND6_OPT_MTU_BUF->mtu = uip_htonl(uip_ds6_if.link_mtu); + UIP_ND6_OPT_MTU_BUF->mtu = uip_htonl(1500); + + uip_len += UIP_ND6_OPT_MTU_LEN; + nd6_opt_offset += UIP_ND6_OPT_MTU_LEN; + +#if UIP_ND6_RA_RDNSS + if(uip_nameserver_count() > 0) { + uint8_t i = 0; + uip_ipaddr_t *ip = &UIP_ND6_OPT_RDNSS_BUF->ip; + uip_ipaddr_t *dns = NULL; + UIP_ND6_OPT_RDNSS_BUF->type = UIP_ND6_OPT_RDNSS; + UIP_ND6_OPT_RDNSS_BUF->reserved = 0; + UIP_ND6_OPT_RDNSS_BUF->lifetime = uip_nameserver_next_expiration(); + if(UIP_ND6_OPT_RDNSS_BUF->lifetime != UIP_NAMESERVER_INFINITE_LIFETIME) { + UIP_ND6_OPT_RDNSS_BUF->lifetime -= clock_seconds(); + } + while((dns = uip_nameserver_get(i)) != NULL) { + uip_ipaddr_copy(ip++, dns); + i++; + } + UIP_ND6_OPT_RDNSS_BUF->len = UIP_ND6_OPT_RDNSS_LEN + (i << 1); + PRINTF("%d nameservers reported\n", i); + uip_len += UIP_ND6_OPT_RDNSS_BUF->len << 3; + nd6_opt_offset += UIP_ND6_OPT_RDNSS_BUF->len << 3; + } +#endif /* UIP_ND6_RA_RDNSS */ + + UIP_IP_BUF->len[0] = ((uip_len - UIP_IPH_LEN) >> 8); + UIP_IP_BUF->len[1] = ((uip_len - UIP_IPH_LEN) & 0xff); + + /*ICMP checksum */ + UIP_ICMP_BUF->icmpchksum = 0; + UIP_ICMP_BUF->icmpchksum = ~uip_icmp6chksum(); + + UIP_STAT(++uip_stat.nd6.sent); + PRINTF("Sending RA to "); + PRINT6ADDR(&UIP_IP_BUF->destipaddr); + PRINTF(" from "); + PRINT6ADDR(&UIP_IP_BUF->srcipaddr); + PRINTF("\n"); + return; +} +#endif /* UIP_ND6_SEND_RA */ +#endif /* UIP_CONF_ROUTER */ + +#if !UIP_CONF_ROUTER +/*---------------------------------------------------------------------------*/ +void +uip_nd6_rs_output(uip_ipaddr_t* rtr_ipaddr) +{ + UIP_IP_BUF->vtc = 0x60; + UIP_IP_BUF->tcflow = 0; + UIP_IP_BUF->flow = 0; + UIP_IP_BUF->proto = UIP_PROTO_ICMP6; + UIP_IP_BUF->ttl = UIP_ND6_HOP_LIMIT; + if (rtr_ipaddr != NULL) { + uip_ipaddr_copy(&UIP_IP_BUF->destipaddr, rtr_ipaddr); + } else { + uip_create_linklocal_allrouters_mcast(&UIP_IP_BUF->destipaddr); + } + uip_ds6_select_src(&UIP_IP_BUF->srcipaddr, &UIP_IP_BUF->destipaddr); + UIP_ICMP_BUF->type = ICMP6_RS; + UIP_ICMP_BUF->icode = 0; + UIP_IP_BUF->len[0] = 0; /* length will not be more than 255 */ + + /*An unspecified source address MUST NOT be used in RS messages.*/ + if(uip_is_addr_unspecified(&UIP_IP_BUF->srcipaddr)) { + PRINTF("RS message does not have specified source addres \n"); + return; + } else { + uip_len = uip_l3_icmp_hdr_len + UIP_ND6_RS_LEN + UIP_ND6_OPT_LLAO_LEN; + UIP_IP_BUF->len[1] = + UIP_ICMPH_LEN + UIP_ND6_RS_LEN + UIP_ND6_OPT_LLAO_LEN; + + create_llao(&uip_buf[uip_l2_l3_icmp_hdr_len + UIP_ND6_RS_LEN], + UIP_ND6_OPT_SLLAO); + } + + UIP_ICMP_BUF->icmpchksum = 0; + UIP_ICMP_BUF->icmpchksum = ~uip_icmp6chksum(); + + UIP_STAT(++uip_stat.nd6.sent); + PRINTF("Sendin RS to "); + PRINT6ADDR(&UIP_IP_BUF->destipaddr); + PRINTF(" from "); + PRINT6ADDR(&UIP_IP_BUF->srcipaddr); + PRINTF("\n"); + return; +} +/*---------------------------------------------------------------------------*/ +/** + * Process a Router Advertisement + * + * - Possible actions when receiving a RA: add router to router list, + * recalculate reachable time, update link hop limit, update retrans timer. + * - If MTU option: update MTU. + * - If SLLAO option: update entry in neighbor cache + * - If prefix option: start autoconf, add prefix to prefix list + */ +void +ra_input(void) +{ + uip_lladdr_t lladdr_aligned; + + PRINTF("Received RA from "); + PRINT6ADDR(&UIP_IP_BUF->srcipaddr); + PRINTF(" to "); + PRINT6ADDR(&UIP_IP_BUF->destipaddr); + PRINTF("\n"); + UIP_STAT(++uip_stat.nd6.recv); + +#if UIP_CONF_IPV6_CHECKS + if((UIP_IP_BUF->ttl != UIP_ND6_HOP_LIMIT) || + (!uip_is_addr_linklocal(&UIP_IP_BUF->srcipaddr)) || + (UIP_ICMP_BUF->icode != 0)) { + PRINTF("RA received is bad"); + goto discard; + } +#endif /*UIP_CONF_IPV6_CHECKS */ + + if(UIP_ND6_RA_BUF->cur_ttl != 0) { + uip_ds6_if.cur_hop_limit = UIP_ND6_RA_BUF->cur_ttl; + PRINTF("uip_ds6_if.cur_hop_limit %u\n", uip_ds6_if.cur_hop_limit); + } + + if(UIP_ND6_RA_BUF->reachable_time != 0) { + if(uip_ds6_if.base_reachable_time != + uip_ntohl(UIP_ND6_RA_BUF->reachable_time)) { + uip_ds6_if.base_reachable_time = uip_ntohl(UIP_ND6_RA_BUF->reachable_time); + uip_ds6_if.reachable_time = uip_ds6_compute_reachable_time(); + } + } + if(UIP_ND6_RA_BUF->retrans_timer != 0) { + uip_ds6_if.retrans_timer = uip_ntohl(UIP_ND6_RA_BUF->retrans_timer); + } + + /* Options processing */ + nd6_opt_offset = UIP_ND6_RA_LEN; + while(uip_l3_icmp_hdr_len + nd6_opt_offset < uip_len) { + if(UIP_ND6_OPT_HDR_BUF->len == 0) { + PRINTF("RA received is bad"); + goto discard; + } + switch (UIP_ND6_OPT_HDR_BUF->type) { + case UIP_ND6_OPT_SLLAO: + PRINTF("Processing SLLAO option in RA\n"); + nd6_opt_llao = (uint8_t *) UIP_ND6_OPT_HDR_BUF; + nbr = uip_ds6_nbr_lookup(&UIP_IP_BUF->srcipaddr); + if(!extract_lladdr_from_llao_aligned(&lladdr_aligned)) { + /* failed to extract llao - discard packet */ + goto discard; + } + if(nbr == NULL) { + nbr = uip_ds6_nbr_add(&UIP_IP_BUF->srcipaddr, &lladdr_aligned, + 1, NBR_STALE, NBR_TABLE_REASON_IPV6_ND, NULL); + } else { + const uip_lladdr_t *lladdr = uip_ds6_nbr_get_ll(nbr); + if(lladdr == NULL) { + goto discard; + } + if(nbr->state == NBR_INCOMPLETE) { + nbr->state = NBR_STALE; + } + 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) { + /* failed to update the lladdr */ + goto discard; + } + nbr->state = NBR_STALE; + } + nbr->isrouter = 1; + } + break; + case UIP_ND6_OPT_MTU: + PRINTF("Processing MTU option in RA\n"); + uip_ds6_if.link_mtu = + uip_ntohl(((uip_nd6_opt_mtu *) UIP_ND6_OPT_HDR_BUF)->mtu); + break; + case UIP_ND6_OPT_PREFIX_INFO: + PRINTF("Processing PREFIX option in RA\n"); + nd6_opt_prefix_info = (uip_nd6_opt_prefix_info *) UIP_ND6_OPT_HDR_BUF; + if((uip_ntohl(nd6_opt_prefix_info->validlt) >= + uip_ntohl(nd6_opt_prefix_info->preferredlt)) + && (!uip_is_addr_linklocal(&nd6_opt_prefix_info->prefix))) { + /* on-link flag related processing */ + if(nd6_opt_prefix_info->flagsreserved1 & UIP_ND6_RA_FLAG_ONLINK) { + prefix = + uip_ds6_prefix_lookup(&nd6_opt_prefix_info->prefix, + nd6_opt_prefix_info->preflen); + if(prefix == NULL) { + if(nd6_opt_prefix_info->validlt != 0) { + if(nd6_opt_prefix_info->validlt != UIP_ND6_INFINITE_LIFETIME) { + prefix = uip_ds6_prefix_add(&nd6_opt_prefix_info->prefix, + nd6_opt_prefix_info->preflen, + uip_ntohl(nd6_opt_prefix_info-> + validlt)); + } else { + prefix = uip_ds6_prefix_add(&nd6_opt_prefix_info->prefix, + nd6_opt_prefix_info->preflen, 0); + } + } + } else { + switch (nd6_opt_prefix_info->validlt) { + case 0: + uip_ds6_prefix_rm(prefix); + break; + case UIP_ND6_INFINITE_LIFETIME: + prefix->isinfinite = 1; + break; + default: + PRINTF("Updating timer of prefix "); + PRINT6ADDR(&prefix->ipaddr); + PRINTF(" new value %lu\n", uip_ntohl(nd6_opt_prefix_info->validlt)); + stimer_set(&prefix->vlifetime, + uip_ntohl(nd6_opt_prefix_info->validlt)); + prefix->isinfinite = 0; + break; + } + } + } + /* End of on-link flag related processing */ + /* autonomous flag related processing */ + if((nd6_opt_prefix_info->flagsreserved1 & UIP_ND6_RA_FLAG_AUTONOMOUS) + && (nd6_opt_prefix_info->validlt != 0) + && (nd6_opt_prefix_info->preflen == UIP_DEFAULT_PREFIX_LEN)) { + + uip_ipaddr_copy(&ipaddr, &nd6_opt_prefix_info->prefix); + uip_ds6_set_addr_iid(&ipaddr, &uip_lladdr); + addr = uip_ds6_addr_lookup(&ipaddr); + if((addr != NULL) && (addr->type == ADDR_AUTOCONF)) { + if(nd6_opt_prefix_info->validlt != UIP_ND6_INFINITE_LIFETIME) { + /* The processing below is defined in RFC4862 section 5.5.3 e */ + if((uip_ntohl(nd6_opt_prefix_info->validlt) > 2 * 60 * 60) || + (uip_ntohl(nd6_opt_prefix_info->validlt) > + stimer_remaining(&addr->vlifetime))) { + PRINTF("Updating timer of address "); + PRINT6ADDR(&addr->ipaddr); + PRINTF(" new value %lu\n", + uip_ntohl(nd6_opt_prefix_info->validlt)); + stimer_set(&addr->vlifetime, + uip_ntohl(nd6_opt_prefix_info->validlt)); + } else { + stimer_set(&addr->vlifetime, 2 * 60 * 60); + PRINTF("Updating timer of address "); + PRINT6ADDR(&addr->ipaddr); + PRINTF(" new value %lu\n", (unsigned long)(2 * 60 * 60)); + } + addr->isinfinite = 0; + } else { + addr->isinfinite = 1; + } + } else { + if(uip_ntohl(nd6_opt_prefix_info->validlt) == + UIP_ND6_INFINITE_LIFETIME) { + uip_ds6_addr_add(&ipaddr, 0, ADDR_AUTOCONF); + } else { + uip_ds6_addr_add(&ipaddr, uip_ntohl(nd6_opt_prefix_info->validlt), + ADDR_AUTOCONF); + } + } + } + /* End of autonomous flag related processing */ + } + break; +#if UIP_ND6_RA_RDNSS + case UIP_ND6_OPT_RDNSS: + if(UIP_ND6_RA_BUF->flags_reserved & (UIP_ND6_O_FLAG << 6)) { + PRINTF("Processing RDNSS option\n"); + uint8_t naddr = (UIP_ND6_OPT_RDNSS_BUF->len - 1) / 2; + uip_ipaddr_t *ip = (uip_ipaddr_t *)(&UIP_ND6_OPT_RDNSS_BUF->ip); + PRINTF("got %d nameservers\n", naddr); + while(naddr-- > 0) { + PRINTF(" nameserver: "); + PRINT6ADDR(ip); + PRINTF(" lifetime: %lx\n", uip_ntohl(UIP_ND6_OPT_RDNSS_BUF->lifetime)); + uip_nameserver_update(ip, uip_ntohl(UIP_ND6_OPT_RDNSS_BUF->lifetime)); + ip++; + } + } + break; +#endif /* UIP_ND6_RA_RDNSS */ + default: + PRINTF("ND option not supported in RA"); + break; + } + nd6_opt_offset += (UIP_ND6_OPT_HDR_BUF->len << 3); + } + + defrt = uip_ds6_defrt_lookup(&UIP_IP_BUF->srcipaddr); + if(UIP_ND6_RA_BUF->router_lifetime != 0) { + if(nbr != NULL) { + nbr->isrouter = 1; + } + if(defrt == NULL) { + uip_ds6_defrt_add(&UIP_IP_BUF->srcipaddr, + (unsigned + long)(uip_ntohs(UIP_ND6_RA_BUF->router_lifetime))); + /*The host triggers sending NS messages containing an ARO when a new + * address is configured, when it discovers a new default router,*/ + uip_nd6_ns_output(&UIP_IP_BUF->destipaddr, &UIP_IP_BUF->srcipaddr, + &UIP_IP_BUF->srcipaddr); + } else { + stimer_set(&(defrt->lifetime), + (unsigned long)(uip_ntohs(UIP_ND6_RA_BUF->router_lifetime))); + } + } else { + if(defrt != NULL) { + uip_ds6_defrt_rm(defrt); + } + } + +#if UIP_CONF_IPV6_QUEUE_PKT + /* If the nbr just became reachable (e.g. it was in NBR_INCOMPLETE state + * and we got a SLLAO), check if we had buffered a pkt for it */ + /* if((nbr != NULL) && (nbr->queue_buf_len != 0)) { + uip_len = nbr->queue_buf_len; + memcpy(UIP_IP_BUF, nbr->queue_buf, uip_len); + nbr->queue_buf_len = 0; + return; + }*/ + if(nbr != NULL && uip_packetqueue_buflen(&nbr->packethandle) != 0) { + uip_len = uip_packetqueue_buflen(&nbr->packethandle); + memcpy(UIP_IP_BUF, uip_packetqueue_buf(&nbr->packethandle), uip_len); + uip_packetqueue_free(&nbr->packethandle); + return; + } + +#endif /*UIP_CONF_IPV6_QUEUE_PKT */ + etimer_stop(&uip_ds6_timer_rs); +discard: + uip_clear_buf(); + return; +} +#endif /* !UIP_CONF_ROUTER */ +/*------------------------------------------------------------------*/ +/* ICMPv6 input handlers */ +#if UIP_ND6_SEND_NA +UIP_ICMP6_HANDLER(ns_input_handler, ICMP6_NS, UIP_ICMP6_HANDLER_CODE_ANY, + ns_input); +UIP_ICMP6_HANDLER(na_input_handler, ICMP6_NA, UIP_ICMP6_HANDLER_CODE_ANY, + na_input); +#endif + +#if UIP_CONF_ROUTER && UIP_ND6_SEND_RA +UIP_ICMP6_HANDLER(rs_input_handler, ICMP6_RS, UIP_ICMP6_HANDLER_CODE_ANY, + rs_input); +#endif + +#if !UIP_CONF_ROUTER +UIP_ICMP6_HANDLER(ra_input_handler, ICMP6_RA, UIP_ICMP6_HANDLER_CODE_ANY, + ra_input); +#endif +/*---------------------------------------------------------------------------*/ +void +uip_nd6_init() +{ + +#if UIP_ND6_SEND_NA + /* Only handle NSs if we are prepared to send out NAs */ + uip_icmp6_register_input_handler(&ns_input_handler); + + /* + * Only handle NAs if we are prepared to send out NAs. + * This is perhaps logically incorrect, but this condition was present in + * uip_process and we keep it until proven wrong + */ + uip_icmp6_register_input_handler(&na_input_handler); +#endif + + +#if UIP_CONF_ROUTER && UIP_ND6_SEND_RA + /* Only accept RS if we are a router and happy to send out RAs */ + uip_icmp6_register_input_handler(&rs_input_handler); +#endif + +#if !UIP_CONF_ROUTER + /* Only process RAs if we are not a router */ + uip_icmp6_register_input_handler(&ra_input_handler); +#endif +} +#endif /*UIP_CONF_IPV6_LOWPAN_ND*/ +/*---------------------------------------------------------------------------*/ + /** @} */ diff --git a/core/net/ipv6/uip-6lowpan-nd6.h b/core/net/ipv6/uip-6lowpan-nd6.h new file mode 100644 index 00000000000..f049778927e --- /dev/null +++ b/core/net/ipv6/uip-6lowpan-nd6.h @@ -0,0 +1,645 @@ +/* + * Copyright (c) 2006, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + * + */ + +/** + * \addtogroup uip6 + * @{ + */ + +/** + * \file + * Header file for IPv6 Neighbor discovery (RFC 4861) + * \author Mohamed Seliem + */ +#ifndef UIP_6LOWPAN_ND6_H_ +#define UIP_6LOWPAN_ND6_H_ +#if UIP_CONF_IPV6_LOWPAN_ND +#include "net/ip/uip.h" +#include "sys/stimer.h" + +/** + * \name General + * @{ + */ +/** \brief HOP LIMIT to be used when sending ND messages (255) */ +#define UIP_ND6_HOP_LIMIT 255 +/** \brief INFINITE lifetime */ +#define UIP_ND6_INFINITE_LIFETIME 0xFFFFFFFF + +/** @} */ + +/** \name RFC 4861 Host constant */ +/** @{ */ +/** \brief Maximum router solicitation delay */ +#define UIP_ND6_MAX_RTR_SOLICITATION_DELAY 1 +/** \brief Router solicitation interval */ +#define UIP_ND6_RTR_SOLICITATION_INTERVAL 10 +/** \brief Maximum router solicitations */ +#define UIP_ND6_MAX_RTR_SOLICITATIONS 3 +/** \brief Maximum router solicitations interval*/ +#define UIP_ND6_MAX_RTR_SOLICITATION_INTERVAL 60 +/** @} */ + +/** \name RFC 4861 Router constants */ +/** @{ */ +#ifndef UIP_CONF_ND6_SEND_RA +#define UIP_ND6_SEND_RA 1 /* enable/disable RA sending */ +#else +#define UIP_ND6_SEND_RA UIP_CONF_ND6_SEND_RA +#endif +#ifndef UIP_CONF_ND6_SEND_NA +#define UIP_ND6_SEND_NA 1 /* enable/disable NA sending */ +#else +#define UIP_ND6_SEND_NA UIP_CONF_ND6_SEND_NA +#endif +#ifndef UIP_CONF_ND6_MAX_RA_INTERVAL +#define UIP_ND6_MAX_RA_INTERVAL 600 +#else +#define UIP_ND6_MAX_RA_INTERVAL UIP_CONF_ND6_MAX_RA_INTERVAL +#endif +#ifndef UIP_CONF_ND6_MIN_RA_INTERVAL +#define UIP_ND6_MIN_RA_INTERVAL (UIP_ND6_MAX_RA_INTERVAL / 3) +#else +#define UIP_ND6_MIN_RA_INTERVAL UIP_CONF_ND6_MIN_RA_INTERVAL +#endif +#define UIP_ND6_M_FLAG 0 +#define UIP_ND6_O_FLAG (UIP_ND6_RA_RDNSS || UIP_ND6_RA_DNSSL) +#define UIP_ND6_ROUTER_LIFETIME 3 * UIP_ND6_MAX_RA_INTERVAL + +#define UIP_ND6_MAX_INITIAL_RA_INTERVAL 16 /*seconds*/ +#define UIP_ND6_MAX_INITIAL_RAS 3 /*transmissions*/ +#ifndef UIP_CONF_ND6_MIN_DELAY_BETWEEN_RAS +#define UIP_ND6_MIN_DELAY_BETWEEN_RAS 10 /*seconds*/ +#else +#define UIP_ND6_MIN_DELAY_BETWEEN_RAS UIP_CONF_ND6_MIN_DELAY_BETWEEN_RAS +#endif +#define UIP_ND6_TENTATIVE_NCE_LIFETIME 20 +//#define UIP_ND6_MAX_RA_DELAY_TIME 2 /*seconds*/ +#define UIP_ND6_MAX_RA_DELAY_TIME_MS 2000 /*milli seconds*/ + +#define UIP_ND6_MULTIHOP_HOPLIMIT 64 + +#ifndef UIP_ND6_MIN_CONTEXT_CHANGE_DELAY +#define UIP_ND6_MIN_CONTEXT_CHANGE_DELAY 300 +#else +#define UIP_ND6_MIN_CONTEXT_CHANGE_DELAY UIP_ND6_MIN_CONTEXT_CHANGE_DELAY +#endif + +#ifndef UIP_ND6_CONTEXT_VALID_LIFETIME +#define UIP_ND6_CONTEXT_VALID_LIFETIME 2 /*minutes*/ +#else +#define UIP_ND6_CONTEXT_VALID_LIFETIME UIP_ND6_CONTEXT_VALID_LIFETIME +#endif + +#ifndef UIP_ND6_ROUTER_INFO_VALID_LIFETIME +#define UIP_ND6_ROUTER_INFO_VALID_LIFETIME 2 /*minutes*/ +#else +#define UIP_ND6_ROUTER_INFO_VALID_LIFETIME UIP_ND6_ROUTER_INFO_VALID_LIFETIME +#endif + +/** @} */ + +#ifndef UIP_CONF_ND6_DEF_MAXDADNS +/** \brief Do not try DAD when using EUI-64 as allowed by draft-ietf-6lowpan-nd-15 section 8.2 */ +#if UIP_CONF_LL_802154 +#define UIP_ND6_DEF_MAXDADNS 0 +#else /* UIP_CONF_LL_802154 */ +#define UIP_ND6_DEF_MAXDADNS UIP_ND6_SEND_NA +#endif /* UIP_CONF_LL_802154 */ +#else /* UIP_CONF_ND6_DEF_MAXDADNS */ +#define UIP_ND6_DEF_MAXDADNS UIP_CONF_ND6_DEF_MAXDADNS +#endif /* UIP_CONF_ND6_DEF_MAXDADNS */ + +/** \name RFC 4861 Node constant */ +/** @{ */ +#define UIP_ND6_MAX_MULTICAST_SOLICIT 3 + +#ifdef UIP_CONF_ND6_MAX_UNICAST_SOLICIT +#define UIP_ND6_MAX_UNICAST_SOLICIT UIP_CONF_ND6_MAX_UNICAST_SOLICIT +#else /* UIP_CONF_ND6_MAX_UNICAST_SOLICIT */ +#define UIP_ND6_MAX_UNICAST_SOLICIT 3 +#endif /* UIP_CONF_ND6_MAX_UNICAST_SOLICIT */ + +#ifdef UIP_CONF_ND6_REACHABLE_TIME +#define UIP_ND6_REACHABLE_TIME UIP_CONF_ND6_REACHABLE_TIME +#else +#define UIP_ND6_REACHABLE_TIME 30000 +#endif + +#ifdef UIP_CONF_ND6_RETRANS_TIMER +#define UIP_ND6_RETRANS_TIMER UIP_CONF_ND6_RETRANS_TIMER +#else +#define UIP_ND6_RETRANS_TIMER 1000 +#endif + +#ifndef UIP_ND6_REGISTRATION_LIFETIME +#define UIP_ND6_REGISTRATION_LIFETIME 2 /*minutes*/ +#else +#define UIP_ND6_REGISTRATION_LIFETIME UIP_ND6_REGISTRATION_LIFETIME +#endif + +#define UIP_ND6_DELAY_FIRST_PROBE_TIME 5 +#define UIP_ND6_MIN_RANDOM_FACTOR(x) (x / 2) +#define UIP_ND6_MAX_RANDOM_FACTOR(x) ((x) + (x) / 2) +/** @} */ + + +/** \brief The Status values used in NAs */ +#define UIP_ND6_ARO_SUCCESS 0 +#define UIP_ND6_ARO_DUPLICATE_ADDRESS 1 +#define UIP_ND6_ARO_NCE_FULL 2 + + +/** \name RFC 6106 RA DNS Options Constants */ +/** @{ */ +#ifndef UIP_CONF_ND6_RA_RDNSS +#define UIP_ND6_RA_RDNSS 0 +#else +#define UIP_ND6_RA_RDNSS UIP_CONF_ND6_RA_RDNSS +#endif + +#ifndef UIP_CONF_ND6_RA_DNSSL +#define UIP_ND6_RA_DNSSL 0 +#else +#error Not implemented +#define UIP_ND6_RA_DNSSL UIP_CONF_ND6_RA_DNSSL +#endif +/** @} */ +/** \name RFC 6775 RA 6co,abro Options Constants */ +/** @{ */ +#ifndef UIP_CONF_ND6_RA_6CO +#define UIP_ND6_RA_6CO 0 +#else +#define UIP_ND6_RA_6CO UIP_CONF_ND6_RA_6CO +#endif + +#ifndef UIP_CONF_ND6_RA_ABRO +#define UIP_ND6_RA_ABRO 0 +#else +#define UIP_ND6_RA_ABRO UIP_CONF_ND6_RA_ABRO +#endif +/** @} */ + +/** \name ND6 option types */ +/** @{ */ +#define UIP_ND6_OPT_SLLAO 1 +#define UIP_ND6_OPT_TLLAO 2 +#define UIP_ND6_OPT_PREFIX_INFO 3 +#define UIP_ND6_OPT_REDIRECTED_HDR 4 +#define UIP_ND6_OPT_MTU 5 +#define UIP_ND6_OPT_RDNSS 25 +#define UIP_ND6_OPT_DNSSL 31 +#define UIP_ND6_OPT_ARO 32 +#define UIP_ND6_OPT_6CO 33 +#define UIP_ND6_OPT_ABRO 34 +/** @} */ + +/** \name ND6 option types */ +/** @{ */ +#define UIP_ND6_OPT_TYPE_OFFSET 0 +#define UIP_ND6_OPT_LEN_OFFSET 1 +#define UIP_ND6_OPT_DATA_OFFSET 2 +/** @} */ + +/** \name ND6 message length (excluding options) */ +/** @{ */ +#define UIP_ND6_NA_LEN 20 +#define UIP_ND6_NS_LEN 20 +#define UIP_ND6_RA_LEN 12 +#define UIP_ND6_RS_LEN 4 +/** @} */ + + +/** \name ND6 option length in bytes */ +/** @{ */ +#define UIP_ND6_OPT_HDR_LEN 2 +#define UIP_ND6_OPT_PREFIX_INFO_LEN 32 +#define UIP_ND6_OPT_MTU_LEN 8 +#define UIP_ND6_OPT_RDNSS_LEN 1 +#define UIP_ND6_OPT_DNSSL_LEN 1 +#define UIP_ND6_OPT_ARO_LEN 2 +#define UIP_ND6_OPT_6CO_LEN 3 +#define UIP_ND6_OPT_ABRO_LEN 3 + +/* Length of TLLAO and SLLAO options, it is L2 dependant */ +#if UIP_CONF_LL_802154 +/* If the interface is 802.15.4. For now we use only long addresses */ +#define UIP_ND6_OPT_SHORT_LLAO_LEN 8 +#define UIP_ND6_OPT_LONG_LLAO_LEN 16 +/** \brief length of a ND6 LLAO option for 802.15.4 */ +#define UIP_ND6_OPT_LLAO_LEN UIP_ND6_OPT_LONG_LLAO_LEN +#else /*UIP_CONF_LL_802154*/ +#if UIP_CONF_LL_80211 +/* If the interface is 802.11 */ +/** \brief length of a ND6 LLAO option for 802.11 */ +#define UIP_ND6_OPT_LLAO_LEN 8 +#else /*UIP_CONF_LL_80211*/ +/** \brief length of a ND6 LLAO option for default L2 type (e.g. Ethernet) */ +#define UIP_ND6_OPT_LLAO_LEN 8 +#endif /*UIP_CONF_LL_80211*/ +#endif /*UIP_CONF_LL_802154*/ +/** @} */ + +/** \name Neighbor Advertisement flags masks */ +/** @{ */ +#define UIP_ND6_NA_FLAG_ROUTER 0x80 +#define UIP_ND6_NA_FLAG_SOLICITED 0x40 +#define UIP_ND6_NA_FLAG_OVERRIDE 0x20 +#define UIP_ND6_RA_FLAG_ONLINK 0x80 +#define UIP_ND6_RA_FLAG_AUTONOMOUS 0x40 +/** @} */ + +/** + * \name ND message structures + ** @{ + */ + +/** + * \brief A neighbor solicitation constant part + * + * Possible option is: SLLAO,ARO + */ +typedef struct uip_nd6_ns { + uint32_t reserved; + uip_ipaddr_t tgtipaddr; +} uip_nd6_ns; + +/** + * \brief A neighbor advertisement constant part. + * + * Possible option is: TLLAO,ARO + */ +typedef struct uip_nd6_na { + uint8_t flagsreserved; + uint8_t reserved[3]; + uip_ipaddr_t tgtipaddr; +} uip_nd6_na; + +/** + * \brief A router solicitation constant part + * + * Possible option is: SLLAO + */ +typedef struct uip_nd6_rs { + uint32_t reserved; +} uip_nd6_rs; + +/** + * \brief A router advertisement constant part + * + * Possible options are: SLLAO, MTU, Prefix Information, 6CO, ABRO + */ +typedef struct uip_nd6_ra { + uint8_t cur_ttl; + uint8_t flags_reserved; + uint16_t router_lifetime; + uint32_t reachable_time; + uint32_t retrans_timer; +} uip_nd6_ra; + +/** + * \brief A redirect message constant part + * + * Possible options are: TLLAO, redirected header + */ +typedef struct uip_nd6_redirect { + uint32_t reserved; + uip_ipaddr_t tgtipaddress; + uip_ipaddr_t destipaddress; +} uip_nd6_redirect; +/** @} */ + +/** + * \name ND Option structures + * @{ + */ + +/** \brief ND option header */ +typedef struct uip_nd6_opt_hdr { + uint8_t type; + uint8_t len; +} uip_nd6_opt_hdr; + +/** \brief ND option prefix information */ +typedef struct uip_nd6_opt_prefix_info { + uint8_t type; + uint8_t len; + uint8_t preflen; + uint8_t flagsreserved1; + uint32_t validlt; + uint32_t preferredlt; + uint32_t reserved2; + uip_ipaddr_t prefix; +} uip_nd6_opt_prefix_info ; + +/** \brief ND option MTU */ +typedef struct uip_nd6_opt_mtu { + uint8_t type; + uint8_t len; + uint16_t reserved; + uint32_t mtu; +} uip_nd6_opt_mtu; + +/** \brief ND option RDNSS */ +typedef struct uip_nd6_opt_dns { + uint8_t type; + uint8_t len; + uint16_t reserved; + uint32_t lifetime; + uip_ipaddr_t ip; +} uip_nd6_opt_dns; + +/** \brief ND option ARO */ +typedef struct uip_nd6_opt_aro { + uint8_t type; + uint8_t len; + uint8_t status; + uint8_t reserved1; + uint16_t reserved2; + uint16_t lifetime; + uip_lladdr_t eui64; +} uip_nd6_opt_aro; + +/** \brief ND option 6CO */ +typedef struct uip_nd6_opt_6co { + uint8_t type; + uint8_t len; + uint8_t context_len; + uint8_t res[3]; + uint8_t c; + uint8_t cid[4]; + uint16_t reserved; + uint16_t valid_lifetime; + uip_ipaddr_t prefix; +} uip_nd6_opt_6co; + +/** \brief ND option ABRO */ +typedef struct uip_nd6_opt_abro { + uint8_t type; + uint8_t len; + uint16_t v_low; + uint16_t v_high; + uint16_t valid_lifetime; + uip_ipaddr_t ip; +} uip_nd6_opt_abro; + +/** \struct Redirected header option */ +typedef struct uip_nd6_opt_redirected_hdr { + uint8_t type; + uint8_t len; + uint8_t reserved[6]; +} uip_nd6_opt_redirected_hdr; + +/** @} */ + +/** + * \name ND Messages Processing and Generation + * @{ + */ +/** + * \brief Send a neighbor solicitation, send a Neighbor Advertisement + * \param src pointer to the src of the NS if known + * \param dest pointer to ip address to send the NS, for DAD or ADDR Resol, + * MUST be NULL, for NUD, must be correct unicast dest + * \param tgt pointer to ip address to fill the target address field, must + * not be NULL + * \param aro set if the aro included in the ns message + * \param lifetime the required registeration lifetime + * - RFC 4861, 7.2.2 : + * "If the source address of the packet prompting the solicitation is the + * same as one of the addresses assigned to the outgoing interface, that + * address SHOULD be placed in the IP Source Address of the outgoing + * solicitation. Otherwise, any one of the addresses assigned to the + * interface should be used." + * This is why we have a src ip address as argument. If NULL, we will do + * src address selection, otherwise we use the argument. + * + * - we check if it is a NS for Address resolution or NUD, if yes we include + * a SLLAO option, otherwise no. + */ +void +uip_nd6_ns_output(uip_ipaddr_t *src, uip_ipaddr_t *dest, uip_ipaddr_t *tgt,uint8_t aro, uint16_t lifetime); + +#if UIP_CONF_ROUTER +#if UIP_ND6_SEND_RA +/** + * \brief send a Router Advertisement + * + * Only for router, for periodic as well as sollicited RA + */ +void uip_nd6_ra_output(uip_ipaddr_t *dest); +#endif /* UIP_ND6_SEND_RA */ +#endif /*UIP_CONF_ROUTER*/ + +/** + * \brief Send a Router Solicitation + * + * src is chosen through the uip_netif_select_src function. If src is + * unspecified (i.e. we do not have a preferred address yet), then we do not + * put a SLLAO option (MUST NOT in RFC 4861). Otherwise we do. + * + * RS message format, + * possible option is SLLAO, MUST NOT be included if source = unspecified + * SHOULD be included otherwise + */ +void uip_nd6_rs_output(uip_ipaddr_t *rtr_ipaddr); + +/** + * \brief Initialise the uIP ND core + */ +void uip_nd6_init(void); +/** @} */ + + +void +uip_appserver_addr_get(uip_ipaddr_t *ipaddr); +/*--------------------------------------*/ +/******* ANNEX - message formats ********/ +/*--------------------------------------*/ + +/* + * RS format. possible option is SLLAO + * 0 1 2 3 + * 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 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type | Code | Checksum | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Reserved | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Options ... + * +-+-+-+-+-+-+-+-+-+-+-+- + * + * + * RA format. possible options: prefix information, MTU, SLLAO + * 0 1 2 3 + * 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 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type | Code | Checksum | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Cur Hop Limit |M|O| Reserved | Router Lifetime | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Reachable Time | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Retrans Timer | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Options ... + * +-+-+-+-+-+-+-+-+-+-+-+- + * + * + * NS format: options should be SLLAO + * 0 1 2 3 + * 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 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type | Code | Checksum | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Reserved | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | + * + + + * | | + * + Target Address + + * | | + * + + + * | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Options ... + * +-+-+-+-+-+-+-+-+-+-+-+- + * + * + * NA message format. possible options is TLLAO + * + * 0 1 2 3 + * 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 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type | Code | Checksum | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |R|S|O| Reserved | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | + * + + + * | | + * + Target Address + + * | | + * + + + * | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Options ... + * +-+-+-+-+-+-+-+-+-+-+-+- + * + * + * Redirect message format. Possible options are TLLAO and Redirected header + * + * 0 1 2 3 + * 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 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type | Code | Checksum | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Reserved | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | + * + + + * | | + * + Target Address + + * | | + * + + + * | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | + * + + + * | | + * + Destination Address + + * | | + * + + + * | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Options ... + * +-+-+-+-+-+-+-+-+-+-+-+- + * + * + * SLLAO/TLLAO option: + * 0 1 2 3 + * 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 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type | Length | Link-Layer Address ... + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * + * Prefix information option + * 0 1 2 3 + * 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 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type | Length | Prefix Length |L|A| Reserved1 | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Valid Lifetime | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Preferred Lifetime | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Reserved2 | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | + * + + + * | | + * + Prefix + + * | | + * + + + * | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * + * MTU option + * 0 1 2 3 + * 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 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type | Length | Reserved | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | MTU | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * + * Redirected header option + * + * 0 1 2 3 + * 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 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type | Length | Reserved | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Reserved | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | + * ~ IP header + data ~ + * | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + */ +#endif /*UIP_CONF_IPV6_LOWPAN_ND*/ +#endif /*UIP_6LOWPAN_ND6_H_ */ +/** @} */ diff --git a/core/net/ipv6/uip-ds6-reg.c b/core/net/ipv6/uip-ds6-reg.c new file mode 100644 index 00000000000..c8180b5825f --- /dev/null +++ b/core/net/ipv6/uip-ds6-reg.c @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2006, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +/** + * \addtogroup uip6 + * @{ + */ + +/** + * \file + * IPv6 address registration list manuiplation + * \author Mohamed Seliem + * + */ +#if UIP_CONF_IPV6_LOWPAN_ND +#include +#include +#include +#include "lib/random.h" +#include "net/ipv6/uip-6lowpan-nd6.h" +#include "net/ipv6/uip-ds6.h" +#include "net/ipv6/multicast/uip-mcast6.h" +#include "net/ip/uip-packetqueue.h" +#include "net/ipv6/uip-ds6-reg.h" + +#define DEBUG DEBUG_NONE +#include "net/ip/uip-debug.h" +uip_ds6_reg_t uip_ds6_reg_list[UIP_DS6_REG_LIST_SIZE]; /**< Registrations list */ + +static uip_ds6_reg_t *locreg; +static uip_ds6_defrt_t *min_defrt; /* default router with minimum lifetime */ +static unsigned long min_lifetime; /* minimum lifetime */ + +/*---------------------------------------------------------------------------*/ +uip_ds6_reg_t* +uip_ds6_reg_add(uip_ds6_addr_t* addr, uip_ds6_defrt_t* defrt, uint8_t state, uint16_t lifetime) { + + uip_ds6_reg_t* candidate = NULL; + + for (locreg = uip_ds6_reg_list; + locreg < uip_ds6_reg_list + UIP_DS6_REG_LIST_SIZE; locreg++) { + if (!locreg->isused) { + candidate = locreg; + break; + } else if (locreg->state == REG_GARBAGE_COLLECTIBLE) { + candidate = locreg; + } + } + /* If there was an entry not in use, use it; otherwise overwrite + * our canditate entry in Garbage-collectible state*/ + if (candidate != NULL) { + candidate->isused = 1; + candidate->addr = addr; + candidate->defrt = defrt; + candidate->state = state; + timer_set(&candidate->registration_timer, 0); + candidate->reg_count = 0; + if(candidate->state == REG_GARBAGE_COLLECTIBLE) { + stimer_set(&candidate->reg_lifetime, UIP_DS6_GARBAGE_COLLECTIBLE_REG_LIFETIME); + } else if (candidate->state == REG_TENTATIVE) { + stimer_set(&candidate->reg_lifetime, UIP_DS6_TENTATIVE_REG_LIFETIME); + } + else{ + stimer_set(&candidate->reg_lifetime, lifetime); + } + defrt->registrations++; + return candidate; + } + return NULL; +} +/*---------------------------------------------------------------------------*/ +void +uip_ds6_reg_rm(uip_ds6_reg_t* reg){ + + reg->defrt->registrations--; + reg->isused = 0; + +} + +/*---------------------------------------------------------------------------*/ +uip_ds6_reg_t* +uip_ds6_reg_lookup(uip_ds6_addr_t* addr, uip_ds6_defrt_t* defrt){ + + uip_ds6_reg_t* reg; + + for (reg = uip_ds6_reg_list; + reg < uip_ds6_reg_list + UIP_DS6_REG_LIST_SIZE; reg++) { + if ((reg->isused) && (reg->addr == addr) && (reg->defrt == defrt)) { + return reg; + } + } + return NULL; +} +/*---------------------------------------------------------------------------*/ +void +uip_ds6_reg_cleanup_defrt(uip_ds6_defrt_t* defrt) { + + uip_ds6_reg_t* reg; + + for (reg = uip_ds6_reg_list; + reg < uip_ds6_reg_list + UIP_DS6_REG_LIST_SIZE; reg++) { + if ((reg->isused) && (reg->defrt == defrt)) { + uip_ds6_reg_rm(reg); + } + } +} + +/*---------------------------------------------------------------------------*/ +void +uip_ds6_reg_cleanup_addr(uip_ds6_addr_t* addr) { + + uip_ds6_reg_t* reg; + + for (reg = uip_ds6_reg_list; + reg < uip_ds6_reg_list + UIP_DS6_REG_LIST_SIZE; reg++) { + if ((reg->isused) && (reg->addr == addr)) { + if (reg->state != REG_REGISTERED) { + uip_ds6_reg_rm(reg); + } else { + /* Mark it as TO_BE_UNREGISTERED */ + reg->state = REG_TO_BE_UNREGISTERED; + } + } + } +} + +/*---------------------------------------------------------------------------*/ + +uint8_t uip_ds6_get_registrations(uip_ds6_defrt_t *defrt) { + + if ((defrt == NULL) || (!defrt->isused)) { + return 0; + } + + return defrt->registrations; +} + +/*---------------------------------------------------------------------------*/ +uip_ds6_defrt_t* +uip_ds6_defrt_choose_min_reg(uip_ds6_addr_t* addr) +{ + uint8_t min = 0; + uip_ds6_defrt_t* min_defrt = NULL; + + for(locdefrt = uip_ds6_defrt_list; + locdefrt < uip_ds6_defrt_list + UIP_DS6_DEFRT_NB; locdefrt++) { + if (locdefrt->isused) { + if (NULL == uip_ds6_reg_lookup(addr, locdefrt)) { + if ((min_defrt == NULL) || + ((min_defrt != NULL) && (uip_ds6_get_registrations(locdefrt) < min))) { + min_defrt = locdefrt; + min = uip_ds6_get_registrations(locdefrt); + if (min == 0) { + /* We are not going to find a better candidate */ + return min_defrt; + } + } + } + } + } + return min_defrt; +} +#endif + +/** @}*/ diff --git a/core/net/ipv6/uip-ds6-reg.h b/core/net/ipv6/uip-ds6-reg.h new file mode 100644 index 00000000000..4b68d277a51 --- /dev/null +++ b/core/net/ipv6/uip-ds6-reg.h @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2013, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * + */ + +/** + * \addtogroup uip6 + * @{ + */ + +/** + * \file + * IPv6 address registration list + * \author Mohamed Seliem + * + */ +#ifndef UIP_DS6_REG_H_ +#define UIP_DS6_REG_H_ + +#include "net/ip/uip.h" +#include "net/nbr-table.h" +#include "sys/stimer.h" +#include "net/ipv6/uip-ds6.h" +#include "net/ipv6/uip-ds6-nbr.h" +#include "net/ipv6/uip-ds6-route.h" + +#if UIP_CONF_IPV6_QUEUE_PKT +#include "net/ip/uip-packetqueue.h" +#endif /*UIP_CONF_QUEUE_PKT */ + +/* The host SHOULD start sending Router Solicitations "well before the + * minimum of those lifetimes" (across all the prefixes and all the + * contexts) expire. RFC 6775. We define thus a threshold + * value to start sending RS messages (in seconds).*/ +#ifdef UIP_DS6_CONF_LIFETIME_THRESHOLD +#define UIP_DS6_LIFETIME_THRESHOLD UIP_DS6_CONF_LIFETIME_THRESHOLD +#else +#define UIP_DS6_LIFETIME_THRESHOLD 60 +#endif + +/* 6lowpan-nd default lifetimes (in seconds)*/ +#ifdef UIP_DS6_GARBAGE_COLLECTIBLE_REG_LIFETIME +#define UIP_DS6_GARBAGE_COLLECTIBLE_REG_LIFETIME UIP_DS6_GARBAGE_COLLECTIBLE_REG_LIFETIME +#else +#define UIP_DS6_GARBAGE_COLLECTIBLE_REG_LIFETIME 20 +#endif +#ifdef UIP_DS6_TENTATIVE_REG_LIFETIME +#define UIP_DS6_TENTATIVE_REG_LIFETIME UIP_DS6_TENTATIVE_REG_LIFETIME +#else +#define UIP_DS6_TENTATIVE_REG_LIFETIME 20 /* Default value in RFC 6775*/ +#endif + +/** \brief Possible states for the nbr cache entries, + * if 6lowpan-nd is used, new states are defined (new states are + * orthogonal to those defined in rfc4861) */ +#define REG_GARBAGE_COLLECTIBLE 0 +#define REG_TENTATIVE 1 +#define REG_REGISTERED 2 +#define REG_TO_BE_UNREGISTERED 3 /* Auxiliary registration entry state */ + +/*registration list*/ +#ifdef UIP_DS6_CONF_REGS_PER_ADDR +#define UIP_DS6_REGS_PER_ADDR UID_DS6_CONF_REGS_PER_ADDR +#else +#define UIP_DS6_REGS_PER_ADDR UIP_DS6_NBR_NB +#endif +#define UIP_DS6_REG_LIST_SIZE UIP_DS6_REGS_PER_ADDR * UIP_DS6_ADDR_NB + +/* Structure to handle 6lowpan-nd registrations */ +typedef struct uip_ds6_reg { + uint8_t isused; + uint8_t state; + uip_ds6_addr_t* addr; + uip_ds6_defrt_t* defrt; + struct stimer reg_lifetime; + struct timer registration_timer; + uint8_t reg_count; +} uip_ds6_reg_t; + +/** + * \brief Adds a registration to the registrations list. It also + *increases the value of the number of registrations of + *the corresponding default router. + * + * \param addr The address for which we are adding the registration + * \param defrt The default router with which we are registering the address + * \param state The state of the registration we are adding (defined in RFC 6775-6lowpan-nd). + * \param lifetime registration life time + * + * \return A pointer to the newly create registration if the + *registration was successfull, otherwise NULL. + */ +uip_ds6_reg_t* uip_ds6_reg_add(uip_ds6_addr_t* addr, uip_ds6_defrt_t* defrt, uint8_t state, uint16_t lifetime); + +/** + * \brief Removes a registration from the registrations list. It also + * decreases the value of the number of registrations of + * the corresponding default router. + * + * \param reg The registration to be deleted. + */ + +void uip_ds6_reg_rm(uip_ds6_reg_t* reg); +/** + * \brief Looks for a registration in the registrations list. + * \param addr The address whose registration we are looking for. + * \param defrt The default router with which the address is registered. + * + * \returns reg The registration matching the search. + * NULL if there are no matches. + */ +uip_ds6_reg_t *uip_ds6_reg_lookup(uip_ds6_addr_t* addr, uip_ds6_defrt_t* defrt); + +void uip_ds6_reg_update(uip_ds6_addr_t* addr, uip_ds6_defrt_t* defrt, uint16_t lifetime); + +/** + * \brief Removes all registrations with defrt from the registration + * list. + * + * \param defrt The router whose registrations we want to remove. + * + */ +void uip_ds6_reg_cleanup_defrt(uip_ds6_defrt_t* defrt); +/** + * \brief Removes all resgitrations of address addr from the + * registration list. If the registration is in REGISTERED + * state, we can not just delete it, but we MUST first send + * a NS with ARO lifetime = 0. As there may be more than one, + * we mark it as TO_BE_UNREGISTERED so uip_ds6_periodic can + * process them properly. + * + * \param addr The address whose registrationes we want to remove. + * + */ +void uip_ds6_reg_cleanup_addr(uip_ds6_addr_t* addr); +/** + * \brief Returns the number of addresses that are registered (or + * pending to be registered) with a router. + * + * \param defrt The router whose number of registrations we want to check. + * + * \returns The number of addresses registered (or pending to be + * registered) with defrt. + */ +uint8_t uip_ds6_get_registrations(uip_ds6_defrt_t *defrt); +/** + * \brief Returns a default router that meets: + * - has the minimum number of registrations + * - addr is not registered with it + * \param addr The address whose registrationes we want to chose. + */ +uip_ds6_defrt_t* uip_ds6_defrt_choose_min_reg(uip_ds6_addr_t* addr); + +#endif /* UIP_DS6_REG_H_ */ +/** @} */ diff --git a/core/net/ipv6/uip-ds6-route.h b/core/net/ipv6/uip-ds6-route.h index 6855fc2cd3d..3051c193037 100644 --- a/core/net/ipv6/uip-ds6-route.h +++ b/core/net/ipv6/uip-ds6-route.h @@ -177,6 +177,10 @@ typedef struct uip_ds6_defrt { uip_ipaddr_t ipaddr; struct stimer lifetime; uint8_t isinfinite; +#if UIP_CONF_IPV6_LOWPAN_ND + /* The number of registrations with a router */ + uint8_t registrations; +#endif } uip_ds6_defrt_t; /** \name Default router list basic routines */ diff --git a/core/net/ipv6/uip-ds6.c b/core/net/ipv6/uip-ds6.c index 9b690ab8c1e..b169b6fbf80 100644 --- a/core/net/ipv6/uip-ds6.c +++ b/core/net/ipv6/uip-ds6.c @@ -46,7 +46,12 @@ #include #include #include "lib/random.h" +#if !(UIP_CONF_IPv6_LOWPAN_ND) #include "net/ipv6/uip-nd6.h" +#else +#include "net/ipv6/uip-6lowpan-nd6.h" +#include "net/ipv6/uip-ds6-reg.h" +#endif #include "net/ipv6/uip-ds6.h" #include "net/ipv6/multicast/uip-mcast6.h" #include "net/ip/uip-packetqueue.h" @@ -129,8 +134,10 @@ uip_ds6_init(void) #if UIP_CONF_ROUTER uip_create_linklocal_allrouters_mcast(&loc_fipaddr); uip_ds6_maddr_add(&loc_fipaddr); +#if !(UIP_CONF_IPV6_LOWPAN_ND) #if UIP_ND6_SEND_RA stimer_set(&uip_ds6_timer_ra, 2); /* wait to have a link local IP address */ +#endif #endif /* UIP_ND6_SEND_RA */ #else /* UIP_CONF_ROUTER */ etimer_set(&uip_ds6_timer_rs, @@ -189,14 +196,16 @@ uip_ds6_periodic(void) #if UIP_ND6_SEND_NA uip_ds6_neighbor_periodic(); -#endif /* UIP_ND6_SEND_RA */ +#endif /* UIP_ND6_SEND_NA */ +#if !(UIP_CONF_IPV6_LOWPAN_ND) #if UIP_CONF_ROUTER && UIP_ND6_SEND_RA /* Periodic RA sending */ if(stimer_expired(&uip_ds6_timer_ra) && (uip_len == 0)) { uip_ds6_send_ra_periodic(); } #endif /* UIP_CONF_ROUTER && UIP_ND6_SEND_RA */ +#endif etimer_reset(&uip_ds6_timer_periodic); return; } @@ -630,7 +639,7 @@ uip_ds6_dad_failed(uip_ds6_addr_t *addr) #if UIP_CONF_ROUTER #if UIP_ND6_SEND_RA void -uip_ds6_send_ra_sollicited(void) +uip_ds6_send_ra_sollicited(uip_ipaddr_t * dest) { /* We have a pb here: RA timer max possible value is 1800s, * hence we have to use stimers. However, when receiving a RS, we @@ -654,6 +663,7 @@ uip_ds6_send_ra_sollicited(void) } /*---------------------------------------------------------------------------*/ +#if !(UIP_CONF_IPV6_LOWPAN_ND) void uip_ds6_send_ra_periodic(void) { @@ -677,12 +687,12 @@ uip_ds6_send_ra_periodic(void) PRINTF("Random time 3 = %u\n", rand_time); stimer_set(&uip_ds6_timer_ra, rand_time); } - +#endif #endif /* UIP_ND6_SEND_RA */ #else /* UIP_CONF_ROUTER */ /*---------------------------------------------------------------------------*/ void -uip_ds6_send_rs(void) +uip_ds6_send_rs(uip_ds6_defrt_t *defrt) { if((uip_ds6_defrt_choose() == NULL) && (rscount < UIP_ND6_MAX_RTR_SOLICITATIONS)) { diff --git a/core/net/ipv6/uip-ds6.h b/core/net/ipv6/uip-ds6.h index 294eb230c94..73108b6d273 100644 --- a/core/net/ipv6/uip-ds6.h +++ b/core/net/ipv6/uip-ds6.h @@ -45,7 +45,12 @@ #include "net/ip/uip.h" #include "sys/stimer.h" /* The size of uip_ds6_addr_t depends on UIP_ND6_DEF_MAXDADNS. Include uip-nd6.h to define it. */ +#if !(UIP_CONF_IPv6_LOWPAN_ND) #include "net/ipv6/uip-nd6.h" +#else +#include "net/ipv6/uip-6lowpan-nd6.h" +#include "net/ipv6/uip-ds6-reg.h" +#endif #include "net/ipv6/uip-ds6-route.h" #include "net/ipv6/uip-ds6-nbr.h" @@ -245,6 +250,9 @@ typedef struct uip_ds6_netif { uint32_t base_reachable_time; /* in msec */ uint32_t reachable_time; /* in msec */ uint32_t retrans_timer; /* in msec */ +#if UIP_CONF_IPv6_LOWPAN_ND + uip_ds6_reg_t* registration_in_progress; +#endif uint8_t maxdadns; #if UIP_DS6_ADDR_NB uip_ds6_addr_t addr_list[UIP_DS6_ADDR_NB]; @@ -359,14 +367,17 @@ void uip_ds6_select_src(uip_ipaddr_t *src, uip_ipaddr_t *dst); #if UIP_CONF_ROUTER #if UIP_ND6_SEND_RA /** \brief Send a RA as an asnwer to a RS */ -void uip_ds6_send_ra_sollicited(void); +void uip_ds6_send_ra_sollicited(uip_ipaddr_t * dest); +#if !(UIP_CONF_IPV6_LOWPAN_ND) /** \brief Send a periodic RA */ void uip_ds6_send_ra_periodic(void); +#endif + #endif /* UIP_ND6_SEND_RA */ #else /* UIP_CONF_ROUTER */ /** \brief Send periodic RS to find router */ -void uip_ds6_send_rs(void); +void uip_ds6_send_rs(uip_ds6_defrt_t *defrt); #endif /* UIP_CONF_ROUTER */ /** \brief Compute the reachable time based on base reachable time, see RFC 4861*/ diff --git a/core/net/ipv6/uip-nd6.c b/core/net/ipv6/uip-nd6.c index 218507228d1..98057652bc2 100644 --- a/core/net/ipv6/uip-nd6.c +++ b/core/net/ipv6/uip-nd6.c @@ -678,7 +678,7 @@ rs_input(void) } /* Schedule a sollicited RA */ - uip_ds6_send_ra_sollicited(); + uip_ds6_send_ra_sollicited(NULL); discard: uip_clear_buf();