2013-06-22 05:11:53 +02:00
|
|
|
/*
|
2013-08-08 13:39:00 +02:00
|
|
|
* 6lowpan neighbor discovery
|
2013-06-22 05:11:53 +02:00
|
|
|
*
|
|
|
|
* Copyright (C) 2013 INRIA.
|
|
|
|
*
|
2013-11-22 20:47:05 +01:00
|
|
|
* This file is subject to the terms and conditions of the GNU Lesser General
|
2013-06-22 05:11:53 +02:00
|
|
|
* Public License. See the file LICENSE in the top level directory for more
|
|
|
|
* details.
|
|
|
|
*
|
|
|
|
* @ingroup sixlowpan
|
|
|
|
* @{
|
|
|
|
* @file sixlownd.c
|
2013-08-08 13:39:00 +02:00
|
|
|
* @brief 6lowpan neighbor discovery functions
|
2013-06-22 05:11:53 +02:00
|
|
|
* @author Stephan Zeisberg <zeisberg@mi.fu-berlin.de>
|
|
|
|
* @author Martin Lenders <mlenders@inf.fu-berlin.de>
|
|
|
|
* @author Oliver Gesch <oliver.gesch@googlemail.com>
|
2013-09-17 19:46:50 +02:00
|
|
|
* @author Oliver Hahm <oliver.hahm@inria.fr>
|
2013-06-22 05:11:53 +02:00
|
|
|
* @}
|
|
|
|
*/
|
|
|
|
|
2013-07-24 00:02:44 +02:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
2013-08-08 13:22:24 +02:00
|
|
|
|
2013-09-12 16:09:18 +02:00
|
|
|
#include "malloc.h"
|
2013-08-08 13:39:00 +02:00
|
|
|
#include "vtimer.h"
|
|
|
|
#include "mutex.h"
|
2013-08-08 13:22:24 +02:00
|
|
|
#include "sixlowpan/error.h"
|
2013-08-08 16:22:37 +02:00
|
|
|
#include "sixlowpan/mac.h"
|
2013-08-08 13:22:24 +02:00
|
|
|
|
2013-08-05 16:10:54 +02:00
|
|
|
#include "ip.h"
|
|
|
|
#include "icmp.h"
|
|
|
|
#include "lowpan.h"
|
2011-06-18 23:33:27 +02:00
|
|
|
#include "serialnumber.h"
|
2013-10-15 13:50:11 +02:00
|
|
|
#include "net_help.h"
|
2011-05-16 14:26:42 +02:00
|
|
|
|
2013-07-24 00:36:06 +02:00
|
|
|
#define ENABLE_DEBUG (0)
|
2013-07-24 00:44:28 +02:00
|
|
|
#include "debug.h"
|
2013-07-24 00:36:06 +02:00
|
|
|
|
2013-08-13 06:41:05 +02:00
|
|
|
#define LLHDR_ICMPV6HDR_LEN (LL_HDR_LEN + IPV6_HDR_LEN + ICMPV6_HDR_LEN)
|
|
|
|
#define ND_HOPLIMIT (0xFF)
|
|
|
|
|
2013-08-14 04:35:58 +02:00
|
|
|
/* parameter problem [rfc4443] */
|
|
|
|
#define PARA_PROB_LEN (8)
|
|
|
|
/* echo request */
|
|
|
|
#define ECHO_REQ_LEN (4)
|
|
|
|
/* echo reply */
|
|
|
|
#define ECHO_REPL_LEN (4)
|
|
|
|
/* router solicitation */
|
|
|
|
#define RTR_SOL_LEN (4)
|
|
|
|
#define RTR_SOL_INTERVAL (4)
|
|
|
|
#define RTR_SOL_MAX (3)
|
|
|
|
/* router advertisment */
|
|
|
|
#define RTR_ADV_MAX (3)
|
|
|
|
#define RTR_ADV_MAX_INTERVAL (600)
|
|
|
|
#define RTR_ADV_LEN (12)
|
|
|
|
/* neighbour solicitation */
|
|
|
|
#define NBR_SOL_LEN (20)
|
|
|
|
/* neighbour advertisement */
|
|
|
|
#define NBR_ADV_LEN (20)
|
|
|
|
/* stllao option rfc4861 4.6.1 */
|
|
|
|
#define OPT_STLLAO_MIN_LEN (8)
|
|
|
|
#define OPT_STLLAO_MAX_LEN (16)
|
|
|
|
/* prefix info option rfc 4.6.2 */
|
|
|
|
#define OPT_PI_LIST_LEN (5) //TODO: initalwert suchen
|
|
|
|
#define OPT_PI_TYPE (3)
|
|
|
|
#define OPT_PI_LEN (4)
|
|
|
|
#define OPT_PI_HDR_LEN (32)
|
|
|
|
/* mtu option rfc4861 4.6.4 */
|
|
|
|
#define OPT_MTU_TYPE (5)
|
|
|
|
#define OPT_MTU_LEN (1)
|
|
|
|
#define OPT_MTU_HDR_LEN (8)
|
|
|
|
/* aro - address registration option rfc6775 4.1 */
|
2013-08-15 20:29:38 +02:00
|
|
|
#define OPT_ARO_TYPE (33)
|
2013-08-14 04:35:58 +02:00
|
|
|
#define OPT_ARO_LEN (2)
|
|
|
|
#define OPT_ARO_HDR_LEN (16)
|
|
|
|
#define OPT_ARO_LTIME (300) /* TODO: geeigneten wert finden */
|
|
|
|
/* 6lowpan context option */
|
2013-08-15 20:29:38 +02:00
|
|
|
#define OPT_6CO_TYPE (34)
|
2013-08-14 04:35:58 +02:00
|
|
|
#define OPT_6CO_MIN_LEN (2)
|
|
|
|
#define OPT_6CO_MAX_LEN (3)
|
|
|
|
#define OPT_6CO_HDR_LEN (8)
|
|
|
|
#define OPT_6CO_LTIME (5) /* TODO geeigneten Wert finden */
|
|
|
|
/* authoritative border router option */
|
2013-08-15 20:29:38 +02:00
|
|
|
#define OPT_ABRO_TYPE (35)
|
2013-08-14 04:35:58 +02:00
|
|
|
#define OPT_ABRO_LEN (3)
|
|
|
|
#define OPT_ABRO_HDR_LEN (24)
|
|
|
|
/* authoritive border router cache size */
|
|
|
|
#define ABR_CACHE_SIZE (2)
|
|
|
|
/* neighbor cache size */
|
|
|
|
#define NBR_CACHE_SIZE (8)
|
|
|
|
#define NBR_CACHE_LTIME_TEN (20)
|
|
|
|
/* default router list size */
|
|
|
|
#define DEF_RTR_LST_SIZE (3) /* geeigneten wert finden */
|
|
|
|
|
2011-01-18 11:02:48 +01:00
|
|
|
/* extern variables */
|
2010-10-19 14:38:44 +02:00
|
|
|
uint8_t ipv6_ext_hdr_len = 0;
|
2011-01-18 11:02:48 +01:00
|
|
|
|
|
|
|
/* counter */
|
2011-06-18 23:33:27 +02:00
|
|
|
uint8_t abr_count = 0;
|
2011-01-18 11:02:48 +01:00
|
|
|
uint8_t nbr_count = 0;
|
|
|
|
uint8_t def_rtr_count = 0;
|
|
|
|
uint8_t rtr_sol_count = 0;
|
|
|
|
uint8_t prefix_count = 0;
|
|
|
|
|
|
|
|
/* datastructures */
|
2013-08-14 04:35:58 +02:00
|
|
|
ndp_a6br_cache_t abr_cache[ABR_CACHE_SIZE];
|
|
|
|
ndp_neighbor_cache_t nbr_cache[NBR_CACHE_SIZE];
|
|
|
|
ndp_default_router_list_t def_rtr_lst[DEF_RTR_LST_SIZE];
|
|
|
|
ndp_prefix_list_t plist[OPT_PI_LIST_LEN];
|
2011-01-18 11:02:48 +01:00
|
|
|
|
|
|
|
/* pointer */
|
|
|
|
static uint8_t *llao;
|
|
|
|
addr_list_t *addr_list_ptr;
|
|
|
|
|
2013-06-24 14:11:30 +02:00
|
|
|
static ipv6_hdr_t *ipv6_buf;
|
2013-08-13 06:41:05 +02:00
|
|
|
static icmpv6_hdr_t *icmp_buf;
|
2013-08-14 04:35:58 +02:00
|
|
|
static icmpv6_router_adv_hdr_t *rtr_adv_buf;
|
|
|
|
static icmpv6_neighbor_sol_hdr_t *nbr_sol_buf;
|
|
|
|
static icmpv6_neighbor_adv_hdr_t *nbr_adv_buf;
|
|
|
|
static icmpv6_ndp_opt_hdr_t *opt_buf;
|
|
|
|
static icmpv6_ndp_opt_stllao_t *opt_stllao_buf;
|
|
|
|
static icmpv6_ndp_opt_mtu_t *opt_mtu_buf;
|
|
|
|
static icmpv6_ndp_opt_abro_t *opt_abro_buf;
|
|
|
|
static icmpv6_ndp_opt_6co_hdr_t *opt_6co_hdr_buf;
|
2011-06-18 23:33:47 +02:00
|
|
|
static uint8_t *opt_6co_prefix_buf;
|
2013-08-14 04:35:58 +02:00
|
|
|
static icmpv6_ndp_opt_pi_t *opt_pi_buf;
|
|
|
|
static icmpv6_ndp_opt_aro_t *opt_aro_buf;
|
2011-01-18 11:02:48 +01:00
|
|
|
|
2013-08-14 04:35:58 +02:00
|
|
|
ndp_neighbor_cache_t *nbr_entry;
|
|
|
|
ndp_default_router_list_t *def_rtr_entry;
|
2011-01-18 11:02:48 +01:00
|
|
|
|
|
|
|
/* elements */
|
2011-01-24 22:41:32 +01:00
|
|
|
//ipv6_addr_t tmpaddr;
|
2011-01-18 11:02:48 +01:00
|
|
|
|
2013-08-14 04:35:58 +02:00
|
|
|
uint8_t recvd_cids[NDP_6LOWPAN_CONTEXT_MAX];
|
2013-08-13 06:41:05 +02:00
|
|
|
uint8_t icmpv6_opt_hdr_len = 0;
|
2011-07-26 13:35:58 +02:00
|
|
|
uint8_t recvd_cids_len = 0;
|
2013-08-14 04:35:58 +02:00
|
|
|
ndp_prefix_list_t *recvd_prefixes[OPT_PI_LIST_LEN];
|
2011-06-24 02:40:25 +02:00
|
|
|
uint8_t recvd_pref_len = 0;
|
|
|
|
|
2013-08-14 04:35:58 +02:00
|
|
|
void def_rtr_lst_add(ipv6_addr_t *ipaddr, uint32_t rtr_ltime);
|
|
|
|
void def_rtr_lst_rem(ndp_default_router_list_t *entry);
|
|
|
|
uint8_t nbr_cache_add(ipv6_addr_t *ipaddr, ieee_802154_long_t *laddr,
|
2013-08-14 17:04:17 +02:00
|
|
|
uint8_t isrouter, ndp_nce_state_t state,
|
|
|
|
ndp_nce_type_t type, uint16_t ltime,
|
|
|
|
ieee_802154_short_t *saddr);
|
2013-08-14 04:35:58 +02:00
|
|
|
void nbr_cache_rem(ipv6_addr_t *addr);
|
2011-06-18 23:33:27 +02:00
|
|
|
|
2013-08-14 21:48:36 +02:00
|
|
|
/**
|
|
|
|
* @brief Set Source link-layer address option according to interface
|
|
|
|
* configuration.
|
|
|
|
*
|
|
|
|
* @param[out] sllao The SLLAO to set.
|
|
|
|
* @param[in] type The value for the type field of the SLLAO.
|
2013-08-15 09:48:53 +02:00
|
|
|
* @param[in] length The value for the length field of the SLLAO
|
2013-08-14 21:48:36 +02:00
|
|
|
*/
|
|
|
|
void icmpv6_ndp_set_sllao(icmpv6_ndp_opt_stllao_t *sllao, uint8_t type,
|
|
|
|
uint8_t length);
|
|
|
|
|
2013-06-22 05:11:53 +02:00
|
|
|
int min(int a, int b)
|
|
|
|
{
|
2013-06-24 22:37:35 +02:00
|
|
|
if (a < b) {
|
2011-07-05 03:50:08 +02:00
|
|
|
return a;
|
2013-06-22 05:11:53 +02:00
|
|
|
}
|
|
|
|
else {
|
2011-07-05 03:50:08 +02:00
|
|
|
return b;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-14 04:35:58 +02:00
|
|
|
static icmpv6_parameter_prob_hdr_t *get_para_prob_buf(uint8_t ext_len)
|
|
|
|
{
|
2013-08-15 11:27:30 +02:00
|
|
|
return ((icmpv6_parameter_prob_hdr_t *) &buffer[LLHDR_ICMPV6HDR_LEN + ext_len]);
|
2011-07-05 03:50:08 +02:00
|
|
|
}
|
|
|
|
|
2013-08-14 04:35:58 +02:00
|
|
|
static icmpv6_echo_request_hdr_t *get_echo_req_buf(uint8_t ext_len)
|
|
|
|
{
|
2013-08-15 11:27:30 +02:00
|
|
|
return ((icmpv6_echo_request_hdr_t *) &buffer[LLHDR_ICMPV6HDR_LEN + ext_len]);
|
2013-07-24 17:06:25 +02:00
|
|
|
}
|
|
|
|
|
2013-08-14 04:35:58 +02:00
|
|
|
static icmpv6_echo_reply_hdr_t *get_echo_repl_buf(uint8_t ext_len)
|
|
|
|
{
|
2013-08-15 11:27:30 +02:00
|
|
|
return ((icmpv6_echo_reply_hdr_t *) &buffer[LLHDR_ICMPV6HDR_LEN + ext_len]);
|
2013-07-24 17:06:25 +02:00
|
|
|
}
|
|
|
|
|
2013-08-14 04:35:58 +02:00
|
|
|
static icmpv6_router_adv_hdr_t *get_rtr_adv_buf(uint8_t ext_len)
|
|
|
|
{
|
2013-08-15 11:27:30 +02:00
|
|
|
return ((icmpv6_router_adv_hdr_t *) &buffer[LLHDR_ICMPV6HDR_LEN + ext_len]);
|
2010-11-22 12:52:56 +01:00
|
|
|
}
|
|
|
|
|
2013-08-14 04:35:58 +02:00
|
|
|
static icmpv6_neighbor_sol_hdr_t *get_nbr_sol_buf(uint8_t ext_len)
|
|
|
|
{
|
2013-08-15 11:27:30 +02:00
|
|
|
return ((icmpv6_neighbor_sol_hdr_t *) &buffer[LLHDR_ICMPV6HDR_LEN + ext_len]);
|
2010-11-22 12:52:56 +01:00
|
|
|
}
|
|
|
|
|
2013-08-14 04:35:58 +02:00
|
|
|
static icmpv6_neighbor_adv_hdr_t *get_nbr_adv_buf(uint8_t ext_len)
|
|
|
|
{
|
2013-08-15 11:27:30 +02:00
|
|
|
return ((icmpv6_neighbor_adv_hdr_t *) &buffer[LLHDR_ICMPV6HDR_LEN + ext_len]);
|
2011-01-24 22:41:32 +01:00
|
|
|
}
|
|
|
|
|
2013-08-14 04:35:58 +02:00
|
|
|
static icmpv6_ndp_opt_hdr_t *get_opt_buf(uint8_t ext_len, uint8_t opt_len)
|
2013-06-22 05:11:53 +02:00
|
|
|
{
|
2013-08-15 11:27:30 +02:00
|
|
|
return ((icmpv6_ndp_opt_hdr_t *) &buffer[LLHDR_ICMPV6HDR_LEN + ext_len + opt_len]);
|
2011-01-18 11:02:48 +01:00
|
|
|
}
|
|
|
|
|
2013-08-14 04:35:58 +02:00
|
|
|
static icmpv6_ndp_opt_stllao_t *get_opt_stllao_buf(uint8_t ext_len, uint8_t opt_len)
|
2013-06-22 05:11:53 +02:00
|
|
|
{
|
2013-08-15 11:27:30 +02:00
|
|
|
return ((icmpv6_ndp_opt_stllao_t *) &buffer[LLHDR_ICMPV6HDR_LEN + ext_len + opt_len]);
|
2010-11-22 12:52:56 +01:00
|
|
|
}
|
|
|
|
|
2013-08-14 04:35:58 +02:00
|
|
|
static icmpv6_ndp_opt_mtu_t *get_opt_mtu_buf(uint8_t ext_len, uint8_t opt_len)
|
2013-06-22 05:11:53 +02:00
|
|
|
{
|
2013-08-15 11:27:30 +02:00
|
|
|
return ((icmpv6_ndp_opt_mtu_t *) &buffer[LLHDR_ICMPV6HDR_LEN + ext_len + opt_len]);
|
2010-11-22 12:52:56 +01:00
|
|
|
}
|
|
|
|
|
2013-08-14 04:35:58 +02:00
|
|
|
static icmpv6_ndp_opt_abro_t *get_opt_abro_buf(uint8_t ext_len, uint8_t opt_len)
|
2013-06-22 05:11:53 +02:00
|
|
|
{
|
2013-08-15 11:27:30 +02:00
|
|
|
return ((icmpv6_ndp_opt_abro_t *) &buffer[LLHDR_ICMPV6HDR_LEN + ext_len + opt_len]);
|
2011-06-18 23:33:27 +02:00
|
|
|
}
|
|
|
|
|
2013-08-14 04:35:58 +02:00
|
|
|
static icmpv6_ndp_opt_6co_hdr_t *get_opt_6co_hdr_buf(uint8_t ext_len, uint8_t opt_len)
|
2013-06-22 05:11:53 +02:00
|
|
|
{
|
2013-08-15 11:27:30 +02:00
|
|
|
return ((icmpv6_ndp_opt_6co_hdr_t *) &buffer[LLHDR_ICMPV6HDR_LEN + ext_len + opt_len]);
|
2011-06-18 23:33:47 +02:00
|
|
|
}
|
|
|
|
|
2013-06-22 05:11:53 +02:00
|
|
|
static uint8_t *get_opt_6co_prefix_buf(uint8_t ext_len, uint8_t opt_len)
|
|
|
|
{
|
2013-08-15 11:27:30 +02:00
|
|
|
return ((uint8_t *) &buffer[LLHDR_ICMPV6HDR_LEN + ext_len + opt_len]);
|
2011-06-18 23:33:47 +02:00
|
|
|
}
|
|
|
|
|
2013-08-14 04:35:58 +02:00
|
|
|
static icmpv6_ndp_opt_pi_t *get_opt_pi_buf(uint8_t ext_len, uint8_t opt_len)
|
2013-06-22 05:11:53 +02:00
|
|
|
{
|
2013-08-15 11:27:30 +02:00
|
|
|
return ((icmpv6_ndp_opt_pi_t *) &buffer[LLHDR_ICMPV6HDR_LEN + ext_len + opt_len]);
|
2010-11-22 12:52:56 +01:00
|
|
|
}
|
|
|
|
|
2013-08-14 04:35:58 +02:00
|
|
|
static icmpv6_ndp_opt_aro_t *get_opt_aro_buf(uint8_t ext_len, uint8_t opt_len)
|
2013-06-22 05:11:53 +02:00
|
|
|
{
|
2013-08-15 11:27:30 +02:00
|
|
|
return ((icmpv6_ndp_opt_aro_t *) &buffer[LLHDR_ICMPV6HDR_LEN + ext_len + opt_len]);
|
2010-11-22 12:52:56 +01:00
|
|
|
}
|
|
|
|
|
2013-08-14 04:35:58 +02:00
|
|
|
void icmpv6_send_echo_request(ipv6_addr_t *destaddr, uint16_t id, uint16_t seq, char *data, size_t data_len)
|
2013-07-24 17:06:25 +02:00
|
|
|
{
|
2013-08-09 03:13:37 +02:00
|
|
|
uint16_t packet_length;
|
|
|
|
|
2013-08-13 06:41:05 +02:00
|
|
|
ipv6_buf = ipv6_get_buf();
|
2013-07-24 17:06:25 +02:00
|
|
|
icmp_buf = get_icmpv6_buf(ipv6_ext_hdr_len);
|
2013-08-14 04:35:58 +02:00
|
|
|
icmpv6_echo_request_hdr_t *echo_buf = get_echo_req_buf(ipv6_ext_hdr_len);
|
|
|
|
char *echo_data_buf = ((char *)echo_buf) + sizeof(icmpv6_echo_request_hdr_t);
|
2013-08-08 13:39:00 +02:00
|
|
|
|
2013-08-14 04:35:58 +02:00
|
|
|
icmp_buf->type = ICMPV6_TYPE_ECHO_REQUEST;
|
2013-07-24 17:06:25 +02:00
|
|
|
icmp_buf->code = 0;
|
|
|
|
ipv6_buf->version_trafficclass = IPV6_VER;
|
|
|
|
ipv6_buf->trafficclass_flowlabel = 0;
|
|
|
|
ipv6_buf->flowlabel = 0;
|
2013-08-13 06:41:05 +02:00
|
|
|
ipv6_buf->nextheader = IPV6_PROTO_NUM_ICMPV6;
|
2013-07-24 17:06:25 +02:00
|
|
|
ipv6_buf->hoplimit = 0xff;
|
2013-08-08 13:39:00 +02:00
|
|
|
|
|
|
|
memcpy(&ipv6_buf->destaddr, destaddr, sizeof(ipv6_addr_t));
|
2013-08-13 06:41:05 +02:00
|
|
|
ipv6_iface_get_best_src_addr(&ipv6_buf->srcaddr, &ipv6_buf->destaddr);
|
2013-07-24 17:06:25 +02:00
|
|
|
echo_buf->id = id;
|
|
|
|
echo_buf->seq = seq;
|
2013-08-08 13:39:00 +02:00
|
|
|
|
2013-07-24 17:06:25 +02:00
|
|
|
memcpy(echo_data_buf, data, data_len);
|
|
|
|
packet_length = IPV6_HDR_LEN + ICMPV6_HDR_LEN + ipv6_ext_hdr_len +
|
|
|
|
ECHO_REQ_LEN + data_len;
|
|
|
|
|
2013-08-08 13:39:00 +02:00
|
|
|
ipv6_buf->length = packet_length - IPV6_HDR_LEN;
|
2013-07-24 17:06:25 +02:00
|
|
|
|
|
|
|
icmp_buf->checksum = 0;
|
2013-08-13 06:41:05 +02:00
|
|
|
icmp_buf->checksum = ~icmpv6_csum(IPV6_PROTO_NUM_ICMPV6);
|
2013-08-08 13:39:00 +02:00
|
|
|
|
2013-07-24 17:06:25 +02:00
|
|
|
#ifdef ENABLE_DEBUG
|
2013-08-13 06:41:05 +02:00
|
|
|
char addr_str[IPV6_MAX_ADDR_STR_LEN];
|
|
|
|
printf("INFO: send echo request to: %s\n",
|
|
|
|
ipv6_addr_to_str(addr_str, &ipv6_buf->destaddr));
|
2013-07-24 17:06:25 +02:00
|
|
|
#endif
|
2013-08-15 11:27:30 +02:00
|
|
|
sixlowpan_lowpan_sendto((ieee_802154_long_t *) &ipv6_buf->destaddr.uint16[4], (uint8_t *)ipv6_buf, packet_length);
|
2013-07-24 17:06:25 +02:00
|
|
|
}
|
|
|
|
|
2013-08-14 04:35:58 +02:00
|
|
|
void icmpv6_send_echo_reply(ipv6_addr_t *destaddr, uint16_t id, uint16_t seq, char *data, size_t data_len)
|
2013-07-24 17:06:25 +02:00
|
|
|
{
|
2013-08-09 03:13:37 +02:00
|
|
|
uint16_t packet_length;
|
|
|
|
|
2013-08-13 06:41:05 +02:00
|
|
|
ipv6_buf = ipv6_get_buf();
|
2013-07-24 17:06:25 +02:00
|
|
|
icmp_buf = get_icmpv6_buf(ipv6_ext_hdr_len);
|
2013-08-14 04:35:58 +02:00
|
|
|
icmpv6_echo_reply_hdr_t *echo_buf = get_echo_repl_buf(ipv6_ext_hdr_len);
|
|
|
|
char *echo_data_buf = ((char *)echo_buf) + sizeof(icmpv6_echo_reply_hdr_t);
|
2013-08-08 13:39:00 +02:00
|
|
|
|
2013-08-14 04:35:58 +02:00
|
|
|
icmp_buf->type = ICMPV6_TYPE_ECHO_REPLY;
|
2013-07-24 17:06:25 +02:00
|
|
|
icmp_buf->code = 0;
|
|
|
|
ipv6_buf->version_trafficclass = IPV6_VER;
|
|
|
|
ipv6_buf->trafficclass_flowlabel = 0;
|
|
|
|
ipv6_buf->flowlabel = 0;
|
2013-08-13 06:41:05 +02:00
|
|
|
ipv6_buf->nextheader = IPV6_PROTO_NUM_ICMPV6;
|
2013-07-24 17:06:25 +02:00
|
|
|
ipv6_buf->hoplimit = 0xff;
|
2013-08-08 13:39:00 +02:00
|
|
|
|
|
|
|
memcpy(&ipv6_buf->destaddr, destaddr, sizeof(ipv6_addr_t));
|
2013-08-13 06:41:05 +02:00
|
|
|
ipv6_iface_get_best_src_addr(&ipv6_buf->srcaddr, &ipv6_buf->destaddr);
|
2013-07-24 17:06:25 +02:00
|
|
|
echo_buf->id = id;
|
|
|
|
echo_buf->seq = seq;
|
2013-08-08 13:39:00 +02:00
|
|
|
|
2013-07-24 17:06:25 +02:00
|
|
|
memcpy(echo_data_buf, data, data_len);
|
|
|
|
packet_length = IPV6_HDR_LEN + ICMPV6_HDR_LEN + ipv6_ext_hdr_len +
|
|
|
|
ECHO_REPL_LEN + data_len;
|
2013-08-08 13:39:00 +02:00
|
|
|
|
|
|
|
ipv6_buf->length = packet_length - IPV6_HDR_LEN;
|
2013-07-24 17:06:25 +02:00
|
|
|
|
|
|
|
icmp_buf->checksum = 0;
|
2013-08-13 06:41:05 +02:00
|
|
|
icmp_buf->checksum = ~icmpv6_csum(IPV6_PROTO_NUM_ICMPV6);
|
2013-08-08 13:39:00 +02:00
|
|
|
|
2013-07-24 17:06:25 +02:00
|
|
|
#ifdef ENABLE_DEBUG
|
2013-08-13 06:41:05 +02:00
|
|
|
char addr_str[IPV6_MAX_ADDR_STR_LEN];
|
|
|
|
printf("INFO: send echo request to: %s\n",
|
|
|
|
ipv6_addr_to_str(addr_str, &ipv6_buf->destaddr));
|
2013-07-24 17:06:25 +02:00
|
|
|
#endif
|
2013-08-15 11:27:30 +02:00
|
|
|
sixlowpan_lowpan_sendto((ieee_802154_long_t *) &ipv6_buf->destaddr.uint16[4],
|
2013-08-09 03:13:37 +02:00
|
|
|
(uint8_t *)ipv6_buf,
|
|
|
|
packet_length);
|
2013-07-24 17:06:25 +02:00
|
|
|
}
|
|
|
|
|
2010-10-12 21:42:03 +02:00
|
|
|
/* send router solicitation message - RFC4861 section 4.1 */
|
2013-08-14 04:35:58 +02:00
|
|
|
void icmpv6_send_router_sol(uint8_t sllao)
|
2013-06-22 05:11:53 +02:00
|
|
|
{
|
2013-08-09 03:13:37 +02:00
|
|
|
uint16_t packet_length;
|
|
|
|
|
2013-08-13 06:41:05 +02:00
|
|
|
ipv6_buf = ipv6_get_buf();
|
2013-06-22 05:11:53 +02:00
|
|
|
icmp_buf = get_icmpv6_buf(ipv6_ext_hdr_len);
|
|
|
|
|
2013-08-14 04:35:58 +02:00
|
|
|
icmp_buf->type = ICMPV6_TYPE_ROUTER_SOL;
|
2011-01-24 22:41:32 +01:00
|
|
|
icmp_buf->code = 0;
|
|
|
|
ipv6_buf->version_trafficclass = IPV6_VER;
|
|
|
|
ipv6_buf->trafficclass_flowlabel = 0;
|
|
|
|
ipv6_buf->flowlabel = 0;
|
2013-08-13 06:41:05 +02:00
|
|
|
ipv6_buf->nextheader = IPV6_PROTO_NUM_ICMPV6;
|
2011-01-24 22:41:32 +01:00
|
|
|
ipv6_buf->hoplimit = ND_HOPLIMIT;
|
|
|
|
|
2013-08-13 06:41:05 +02:00
|
|
|
ipv6_addr_set_all_routers_addr(&ipv6_buf->destaddr);
|
|
|
|
//iface_find_src_ipaddr(&ipv6_buf->srcaddr, NDP_ADDR_STATE_PREFERRED,
|
|
|
|
/* IPV6_ADDR_TYPE_MULTICAST); */
|
2011-01-24 22:41:32 +01:00
|
|
|
|
2013-08-13 06:41:05 +02:00
|
|
|
ipv6_iface_get_best_src_addr(&(ipv6_buf->srcaddr), &(ipv6_buf->destaddr));
|
2011-01-24 22:41:32 +01:00
|
|
|
|
2013-08-13 06:41:05 +02:00
|
|
|
icmpv6_opt_hdr_len = RTR_SOL_LEN;
|
2013-08-02 01:19:20 +02:00
|
|
|
ipv6_buf->length = HTONS(ICMPV6_HDR_LEN + RTR_SOL_LEN + OPT_STLLAO_MAX_LEN);
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (sllao == OPT_SLLAO) {
|
2013-08-13 06:41:05 +02:00
|
|
|
opt_stllao_buf = get_opt_stllao_buf(ipv6_ext_hdr_len, icmpv6_opt_hdr_len);
|
2013-08-14 21:48:36 +02:00
|
|
|
icmpv6_ndp_set_sllao(opt_stllao_buf, NDP_OPT_SLLAO_TYPE, 2);
|
2011-01-24 22:41:32 +01:00
|
|
|
packet_length = IPV6_HDR_LEN + ICMPV6_HDR_LEN + ipv6_ext_hdr_len +
|
2011-07-04 16:47:06 +02:00
|
|
|
RTR_SOL_LEN + OPT_STLLAO_MAX_LEN;
|
2011-01-24 22:41:32 +01:00
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
else {
|
|
|
|
packet_length = IPV6_HDR_LEN + ICMPV6_HDR_LEN + ipv6_ext_hdr_len +
|
|
|
|
RTR_SOL_LEN;
|
|
|
|
}
|
|
|
|
|
2011-01-24 22:41:32 +01:00
|
|
|
icmp_buf->checksum = 0;
|
2013-08-13 06:41:05 +02:00
|
|
|
icmp_buf->checksum = ~icmpv6_csum(IPV6_PROTO_NUM_ICMPV6);
|
2011-01-24 22:41:32 +01:00
|
|
|
|
2013-07-24 00:36:06 +02:00
|
|
|
#if ENABLE_DEBUG
|
2013-08-13 06:41:05 +02:00
|
|
|
char addr_str[IPV6_MAX_ADDR_STR_LEN];
|
|
|
|
printf("INFO: send router solicitation to: %s\n",
|
|
|
|
ipv6_addr_to_str(addr_str, &ipv6_buf->destaddr));
|
2011-05-16 14:26:42 +02:00
|
|
|
#endif
|
2013-08-15 11:27:30 +02:00
|
|
|
sixlowpan_lowpan_sendto((ieee_802154_long_t *) &ipv6_buf->destaddr.uint16[4],
|
2013-08-09 03:13:37 +02:00
|
|
|
(uint8_t *)ipv6_buf,
|
|
|
|
packet_length);
|
2010-10-17 16:05:46 +02:00
|
|
|
}
|
|
|
|
|
2013-07-24 17:06:25 +02:00
|
|
|
void recv_echo_req(void)
|
|
|
|
{
|
2013-08-13 06:41:05 +02:00
|
|
|
ipv6_buf = ipv6_get_buf();
|
2013-08-14 04:35:58 +02:00
|
|
|
icmpv6_echo_request_hdr_t *echo_buf = get_echo_req_buf(ipv6_ext_hdr_len);
|
|
|
|
char *echo_data_buf = ((char *)echo_buf) + sizeof(icmpv6_echo_reply_hdr_t);
|
2013-07-24 17:06:25 +02:00
|
|
|
size_t data_len = ipv6_buf->length - (IPV6_HDR_LEN + ICMPV6_HDR_LEN +
|
2013-08-08 13:39:00 +02:00
|
|
|
ipv6_ext_hdr_len + ECHO_REQ_LEN);
|
2013-07-24 17:06:25 +02:00
|
|
|
#ifdef ENABLE_DEBUG
|
2013-08-13 06:41:05 +02:00
|
|
|
char addr_str[IPV6_MAX_ADDR_STR_LEN];
|
|
|
|
printf("INFO: received echo request from: %s\n",
|
|
|
|
ipv6_addr_to_str(addr_str, &ipv6_buf->srcaddr));
|
2013-07-24 17:06:25 +02:00
|
|
|
printf("\n");
|
|
|
|
printf("id = 0x%04x, seq = %d\n", echo_buf->id, echo_buf->seq);
|
2013-08-08 13:39:00 +02:00
|
|
|
|
2013-07-24 17:06:25 +02:00
|
|
|
for (int i = 0; i < data_len; i++) {
|
|
|
|
printf("%02x ", echo_data_buf[i]);
|
2013-08-08 13:39:00 +02:00
|
|
|
|
|
|
|
if ((i + 1) % 16 || i == data_len - 1) {
|
2013-07-24 17:06:25 +02:00
|
|
|
printf("\n");
|
|
|
|
}
|
|
|
|
}
|
2013-08-08 13:39:00 +02:00
|
|
|
|
2013-07-24 17:06:25 +02:00
|
|
|
#endif
|
2013-08-14 04:35:58 +02:00
|
|
|
icmpv6_send_echo_reply(&ipv6_buf->srcaddr, echo_buf->id, echo_buf->seq,
|
|
|
|
echo_data_buf, data_len);
|
2013-07-24 17:06:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void recv_echo_repl(void)
|
|
|
|
{
|
2013-08-13 06:41:05 +02:00
|
|
|
ipv6_buf = ipv6_get_buf();
|
2013-08-14 04:35:58 +02:00
|
|
|
icmpv6_echo_reply_hdr_t *echo_buf = get_echo_repl_buf(ipv6_ext_hdr_len);
|
|
|
|
char *echo_data_buf = ((char *)echo_buf) + sizeof(icmpv6_echo_reply_hdr_t);
|
2013-07-24 17:06:25 +02:00
|
|
|
size_t data_len = ipv6_buf->length - (IPV6_HDR_LEN + ICMPV6_HDR_LEN +
|
2013-08-08 13:39:00 +02:00
|
|
|
ipv6_ext_hdr_len + ECHO_REPL_LEN);
|
2013-07-24 17:06:25 +02:00
|
|
|
#ifdef ENABLE_DEBUG
|
2013-08-13 06:41:05 +02:00
|
|
|
char addr_str[IPV6_MAX_ADDR_STR_LEN];
|
|
|
|
printf("INFO: received echo reply from: %s\n",
|
|
|
|
ipv6_addr_to_str(addr_str, &ipv6_buf->srcaddr));
|
2013-07-24 17:06:25 +02:00
|
|
|
printf("\n");
|
|
|
|
printf("id = 0x%04x, seq = %d\n", echo_buf->id, echo_buf->seq);
|
2013-08-08 13:39:00 +02:00
|
|
|
|
2013-07-24 17:06:25 +02:00
|
|
|
for (int i = 0; i < data_len; i++) {
|
|
|
|
printf("%02x ", echo_data_buf[i]);
|
2013-08-08 13:39:00 +02:00
|
|
|
|
|
|
|
if ((i + 1) % 16 || i == data_len - 1) {
|
2013-07-24 17:06:25 +02:00
|
|
|
printf("\n");
|
|
|
|
}
|
|
|
|
}
|
2013-08-08 13:39:00 +02:00
|
|
|
|
2013-07-24 17:06:25 +02:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2013-06-22 05:11:53 +02:00
|
|
|
void recv_rtr_sol(void)
|
|
|
|
{
|
2013-08-13 06:41:05 +02:00
|
|
|
icmpv6_opt_hdr_len = RTR_SOL_LEN;
|
|
|
|
ipv6_buf = ipv6_get_buf();
|
2011-01-18 11:02:48 +01:00
|
|
|
|
|
|
|
/* check if source option is set*/
|
2013-08-14 04:35:58 +02:00
|
|
|
if (opt_stllao_buf->type == NDP_OPT_SLLAO_TYPE) {
|
2013-08-13 06:41:05 +02:00
|
|
|
opt_stllao_buf = get_opt_stllao_buf(ipv6_ext_hdr_len, icmpv6_opt_hdr_len);
|
2013-06-22 05:11:53 +02:00
|
|
|
llao = (uint8_t *)opt_stllao_buf;
|
2013-08-13 06:41:05 +02:00
|
|
|
icmpv6_opt_hdr_len += (opt_stllao_buf->length) << 3;
|
2010-10-17 16:05:46 +02:00
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (llao != NULL) {
|
2013-08-14 04:35:58 +02:00
|
|
|
nbr_entry = ndp_neighbor_cache_search(&ipv6_buf->srcaddr);
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (nbr_entry != NULL) {
|
2011-01-18 11:02:48 +01:00
|
|
|
/* found neighbor in cache, update values and check long addr */
|
2013-06-24 22:37:35 +02:00
|
|
|
if (memcmp(&llao[2], &nbr_entry->laddr, 8) == 0) {
|
2011-01-18 11:02:48 +01:00
|
|
|
nbr_entry->isrouter = 0;
|
2013-06-22 05:11:53 +02:00
|
|
|
}
|
|
|
|
else {
|
2011-01-18 11:02:48 +01:00
|
|
|
/* new long addr found, update */
|
2013-06-22 05:11:53 +02:00
|
|
|
memcpy(&nbr_entry->laddr, &llao[2], 8);
|
2013-08-14 17:04:17 +02:00
|
|
|
nbr_entry->state = NDP_NCE_STATUS_STALE;
|
2011-01-18 11:02:48 +01:00
|
|
|
nbr_entry->isrouter = 0;
|
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
}
|
|
|
|
else {
|
2011-01-18 11:02:48 +01:00
|
|
|
/* nothing found, add neigbor into cache*/
|
2013-06-22 05:11:53 +02:00
|
|
|
nbr_cache_add(&ipv6_buf->srcaddr, (ieee_802154_long_t *)&llao[2],
|
2013-08-14 17:04:17 +02:00
|
|
|
0, NDP_NCE_STATUS_STALE, NDP_NCE_TYPE_TENTATIVE,
|
2011-01-24 22:41:32 +01:00
|
|
|
NBR_CACHE_LTIME_TEN, NULL);
|
2011-01-18 11:02:48 +01:00
|
|
|
}
|
2010-10-17 16:05:46 +02:00
|
|
|
}
|
|
|
|
|
2011-01-18 11:02:48 +01:00
|
|
|
/* send solicited router advertisment */
|
2013-06-24 22:37:35 +02:00
|
|
|
if (abr_count > 0) {
|
2013-08-14 04:35:58 +02:00
|
|
|
icmpv6_send_router_adv(&ipv6_buf->srcaddr, 0, 0, OPT_PI, OPT_6CO, OPT_ABRO);
|
2013-06-22 05:11:53 +02:00
|
|
|
}
|
|
|
|
else {
|
2013-08-14 04:35:58 +02:00
|
|
|
icmpv6_send_router_adv(&ipv6_buf->srcaddr, 0, 0, OPT_PI, 0, 0);
|
2011-06-18 23:33:27 +02:00
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-07-24 00:36:06 +02:00
|
|
|
#if ENABLE_DEBUG
|
2013-08-13 06:41:05 +02:00
|
|
|
char addr_str[IPV6_MAX_ADDR_STR_LEN];
|
|
|
|
printf("INFO: send router advertisment to: %s\n",
|
|
|
|
ipv6_addr_to_str(addr_str, &ipv6_buf->destaddr));
|
2011-05-16 14:26:42 +02:00
|
|
|
#endif
|
2013-08-15 11:27:30 +02:00
|
|
|
sixlowpan_lowpan_sendto((ieee_802154_long_t *) &ipv6_buf->destaddr.uint16[4],
|
2013-08-09 03:13:37 +02:00
|
|
|
(uint8_t *)ipv6_buf,
|
|
|
|
IPV6_HDR_LEN + NTOHS(ipv6_buf->length));
|
2011-01-24 22:41:32 +01:00
|
|
|
|
2010-10-14 13:10:52 +02:00
|
|
|
}
|
|
|
|
|
2013-06-22 05:11:53 +02:00
|
|
|
uint8_t set_opt_6co_flags(uint8_t compression_flag, uint8_t cid)
|
|
|
|
{
|
2011-06-18 23:33:47 +02:00
|
|
|
uint8_t flags;
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (compression_flag) {
|
2013-08-14 04:35:58 +02:00
|
|
|
flags = ICMPV6_NDP_OPT_6CO_FLAG_CCOMPR;
|
2013-06-22 05:11:53 +02:00
|
|
|
}
|
|
|
|
else {
|
2011-06-18 23:33:47 +02:00
|
|
|
flags = 0;
|
2013-06-22 05:11:53 +02:00
|
|
|
}
|
|
|
|
|
2013-08-14 04:35:58 +02:00
|
|
|
flags |= cid & ICMPV6_NDP_OPT_6CO_FLAG_CID;
|
2011-06-18 23:33:47 +02:00
|
|
|
return flags;
|
|
|
|
}
|
|
|
|
|
2013-06-22 05:11:53 +02:00
|
|
|
void get_opt_6co_flags(uint8_t *compression_flag, uint8_t *cid, uint8_t flags)
|
|
|
|
{
|
2013-08-14 04:35:58 +02:00
|
|
|
compression_flag[0] = flags & ICMPV6_NDP_OPT_6CO_FLAG_CID;
|
2011-06-18 23:33:47 +02:00
|
|
|
compression_flag[0] = compression_flag[0] != 0;
|
2013-08-14 04:35:58 +02:00
|
|
|
cid[0] = flags & ICMPV6_NDP_OPT_6CO_FLAG_CID;
|
2011-06-18 23:33:47 +02:00
|
|
|
}
|
|
|
|
|
2013-08-14 04:35:58 +02:00
|
|
|
lowpan_context_t *abr_get_context(ndp_a6br_cache_t *abr, uint8_t cid);
|
2011-07-26 13:35:58 +02:00
|
|
|
|
2013-08-14 04:35:58 +02:00
|
|
|
void icmpv6_send_router_adv(ipv6_addr_t *addr, uint8_t sllao, uint8_t mtu, uint8_t pi,
|
|
|
|
uint8_t sixco, uint8_t abro)
|
2013-06-22 05:11:53 +02:00
|
|
|
{
|
2013-08-09 03:13:37 +02:00
|
|
|
uint16_t packet_length;
|
2011-06-24 02:40:25 +02:00
|
|
|
lowpan_context_t *contexts = NULL;
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-08-14 04:35:58 +02:00
|
|
|
ndp_a6br_cache_t *msg_abr = NULL;
|
2013-08-13 06:41:05 +02:00
|
|
|
ipv6_buf = ipv6_get_buf();
|
2013-06-22 05:11:53 +02:00
|
|
|
icmp_buf = get_icmpv6_buf(ipv6_ext_hdr_len);
|
2010-11-22 12:52:56 +01:00
|
|
|
|
2010-11-09 22:20:26 +01:00
|
|
|
ipv6_buf->version_trafficclass = IPV6_VER;
|
|
|
|
ipv6_buf->trafficclass_flowlabel = 0;
|
|
|
|
ipv6_buf->flowlabel = 0;
|
2013-08-13 06:41:05 +02:00
|
|
|
ipv6_buf->nextheader = IPV6_PROTO_NUM_ICMPV6;
|
2010-11-09 22:20:26 +01:00
|
|
|
ipv6_buf->hoplimit = ND_HOPLIMIT;
|
2011-01-18 11:02:48 +01:00
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (addr == NULL) {
|
2011-01-18 11:02:48 +01:00
|
|
|
/* not solicited */
|
2013-08-13 06:41:05 +02:00
|
|
|
ipv6_addr_set_all_nodes_addr(&ipv6_buf->destaddr);
|
2013-06-22 05:11:53 +02:00
|
|
|
}
|
|
|
|
else {
|
2011-01-18 11:02:48 +01:00
|
|
|
memcpy(&ipv6_buf->destaddr, addr, 16);
|
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-08-13 06:41:05 +02:00
|
|
|
ipv6_iface_get_best_src_addr(&(ipv6_buf->srcaddr), &(ipv6_buf->destaddr));
|
2011-01-24 22:41:32 +01:00
|
|
|
|
2013-08-14 04:35:58 +02:00
|
|
|
icmp_buf->type = ICMPV6_TYPE_ROUTER_ADV;
|
2010-11-09 22:20:26 +01:00
|
|
|
icmp_buf->code = 0;
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2010-11-22 12:52:56 +01:00
|
|
|
//TODO: gethoplimit func, set current ttl
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2010-11-22 12:52:56 +01:00
|
|
|
rtr_adv_buf = get_rtr_adv_buf(ipv6_ext_hdr_len);
|
2010-11-09 22:20:26 +01:00
|
|
|
rtr_adv_buf->hoplimit = MULTIHOP_HOPLIMIT;
|
2010-11-22 12:52:56 +01:00
|
|
|
/* set M and O flag, last 6 bits are zero */
|
2013-08-14 04:35:58 +02:00
|
|
|
rtr_adv_buf->autoconfig_flags = ICMPV6_ROUTER_ADV_FLAG_MANAGED | ICMPV6_ROUTER_ADV_FLAG_OTHER;
|
2011-01-18 11:02:48 +01:00
|
|
|
rtr_adv_buf->router_lifetime = HTONS(RTR_ADV_MAX_INTERVAL * RTR_ADV_MAX);
|
2010-11-09 22:20:26 +01:00
|
|
|
rtr_adv_buf->reachable_time = 0;
|
|
|
|
rtr_adv_buf->retrans_timer = 0;
|
2013-08-13 06:41:05 +02:00
|
|
|
icmpv6_opt_hdr_len = RTR_ADV_LEN;
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2011-01-18 11:02:48 +01:00
|
|
|
packet_length = IPV6_HDR_LEN + ICMPV6_HDR_LEN + RTR_ADV_LEN;
|
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (sllao == OPT_SLLAO) {
|
2011-01-18 11:02:48 +01:00
|
|
|
/* set link layer address option */
|
2013-08-13 06:41:05 +02:00
|
|
|
opt_stllao_buf = get_opt_stllao_buf(ipv6_ext_hdr_len, icmpv6_opt_hdr_len);
|
2013-08-14 21:48:36 +02:00
|
|
|
icmpv6_ndp_set_sllao(opt_stllao_buf, NDP_OPT_SLLAO_TYPE, 2);
|
2013-08-13 06:41:05 +02:00
|
|
|
icmpv6_opt_hdr_len += OPT_STLLAO_MAX_LEN;
|
2011-07-04 16:47:06 +02:00
|
|
|
packet_length += OPT_STLLAO_MAX_LEN;
|
2011-01-18 11:02:48 +01:00
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (mtu == OPT_MTU) {
|
2011-01-18 11:02:48 +01:00
|
|
|
/* set MTU options */
|
2013-08-13 06:41:05 +02:00
|
|
|
opt_mtu_buf = get_opt_mtu_buf(ipv6_ext_hdr_len, icmpv6_opt_hdr_len);
|
2011-01-18 11:02:48 +01:00
|
|
|
opt_mtu_buf->type = OPT_MTU_TYPE;
|
|
|
|
opt_mtu_buf->length = OPT_MTU_LEN;
|
|
|
|
opt_mtu_buf->reserved = 0;
|
|
|
|
opt_mtu_buf->mtu = HTONL(1500);
|
2013-08-13 06:41:05 +02:00
|
|
|
icmpv6_opt_hdr_len += OPT_MTU_HDR_LEN;
|
2011-01-18 11:02:48 +01:00
|
|
|
packet_length += OPT_MTU_HDR_LEN;
|
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2010-11-08 10:33:23 +01:00
|
|
|
/* set payload length field */
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (abro == OPT_ABRO) {
|
2011-06-18 23:33:27 +02:00
|
|
|
/* set authoritive border router option */
|
2013-06-24 22:37:35 +02:00
|
|
|
if (abr_count > 0) {
|
2013-08-14 04:35:58 +02:00
|
|
|
msg_abr = ndp_a6br_cache_get_most_current();
|
2013-08-13 06:41:05 +02:00
|
|
|
opt_abro_buf = get_opt_abro_buf(ipv6_ext_hdr_len, icmpv6_opt_hdr_len);
|
2011-06-18 23:33:27 +02:00
|
|
|
opt_abro_buf->type = OPT_ABRO_TYPE;
|
|
|
|
opt_abro_buf->length = OPT_ABRO_LEN;
|
2011-06-24 01:48:41 +02:00
|
|
|
opt_abro_buf->version = HTONS(msg_abr->version);
|
2011-06-18 23:33:27 +02:00
|
|
|
opt_abro_buf->reserved = 0;
|
2013-06-22 05:11:53 +02:00
|
|
|
memcpy(&(opt_abro_buf->addr), &(msg_abr->abr_addr), sizeof(ipv6_addr_t));
|
2011-06-18 23:33:27 +02:00
|
|
|
}
|
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (sixco == OPT_6CO) {
|
2011-06-18 23:33:47 +02:00
|
|
|
/* set 6lowpan context option */
|
|
|
|
int contexts_len = 0;
|
2011-06-24 01:48:41 +02:00
|
|
|
mutex_lock(&lowpan_context_mutex);
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (msg_abr == NULL) {
|
2011-06-18 23:33:47 +02:00
|
|
|
contexts = lowpan_context_get();
|
|
|
|
contexts_len = lowpan_context_len();
|
2013-06-22 05:11:53 +02:00
|
|
|
}
|
|
|
|
else {
|
2013-08-14 04:35:58 +02:00
|
|
|
lowpan_context_t c_tmp[NDP_6LOWPAN_CONTEXT_MAX];
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2011-07-26 13:35:58 +02:00
|
|
|
contexts_len = 0;
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-08-14 04:35:58 +02:00
|
|
|
for (int i = 0; i < NDP_6LOWPAN_CONTEXT_MAX; i++) {
|
2011-07-26 13:35:58 +02:00
|
|
|
lowpan_context_t *ctx = abr_get_context(msg_abr, i);
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (ctx != NULL) {
|
2013-06-22 05:11:53 +02:00
|
|
|
memcpy(&(c_tmp[contexts_len++]), ctx, sizeof(lowpan_context_t));
|
2011-07-26 13:35:58 +02:00
|
|
|
}
|
2011-06-18 23:33:47 +02:00
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
|
|
|
|
contexts = (lowpan_context_t *)calloc(contexts_len, sizeof(lowpan_context_t));
|
|
|
|
memcpy(contexts, c_tmp, contexts_len);
|
2011-06-18 23:33:47 +02:00
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
for (int i = 0; i < contexts_len; i++) {
|
2013-08-13 06:41:05 +02:00
|
|
|
opt_6co_hdr_buf = get_opt_6co_hdr_buf(ipv6_ext_hdr_len, icmpv6_opt_hdr_len);
|
2011-06-18 23:33:47 +02:00
|
|
|
opt_6co_hdr_buf->type = OPT_6CO_TYPE;
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (contexts[i].length > 64) {
|
2011-06-18 23:33:47 +02:00
|
|
|
opt_6co_hdr_buf->length = OPT_6CO_MAX_LEN;
|
2013-06-22 05:11:53 +02:00
|
|
|
}
|
|
|
|
else {
|
2011-06-18 23:33:47 +02:00
|
|
|
opt_6co_hdr_buf->length = OPT_6CO_MIN_LEN;
|
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2011-06-23 03:42:39 +02:00
|
|
|
opt_6co_hdr_buf->c_length = contexts[i].length;
|
2013-06-22 05:11:53 +02:00
|
|
|
opt_6co_hdr_buf->c_flags = set_opt_6co_flags(contexts[i].comp, contexts[i].num);
|
2011-06-18 23:33:47 +02:00
|
|
|
opt_6co_hdr_buf->reserved = 0;
|
2011-06-24 01:48:41 +02:00
|
|
|
opt_6co_hdr_buf->val_ltime = HTONS(contexts[i].lifetime);
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-08-13 06:41:05 +02:00
|
|
|
icmpv6_opt_hdr_len += OPT_6CO_HDR_LEN;
|
2011-06-18 23:33:47 +02:00
|
|
|
packet_length += OPT_6CO_HDR_LEN;
|
2013-06-22 05:11:53 +02:00
|
|
|
/* attach prefixes */
|
2013-08-13 06:41:05 +02:00
|
|
|
opt_6co_prefix_buf = get_opt_6co_prefix_buf(ipv6_ext_hdr_len, icmpv6_opt_hdr_len);
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (opt_6co_hdr_buf->c_length > 64) {
|
2013-06-22 05:11:53 +02:00
|
|
|
memset((void *)opt_6co_prefix_buf, 0, 16);
|
2013-08-15 11:27:30 +02:00
|
|
|
memcpy((void *)opt_6co_prefix_buf, (void *) &contexts[i].prefix.uint8[0], opt_6co_hdr_buf->c_length / 8);
|
2013-08-13 06:41:05 +02:00
|
|
|
icmpv6_opt_hdr_len += 16;
|
2011-06-24 02:40:25 +02:00
|
|
|
packet_length += 16;
|
2013-06-22 05:11:53 +02:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
memset((void *)opt_6co_prefix_buf, 0, 8);
|
2013-08-15 11:27:30 +02:00
|
|
|
memcpy((void *)opt_6co_prefix_buf, (void *) &contexts[i].prefix.uint8[0], opt_6co_hdr_buf->c_length / 8);
|
2013-08-13 06:41:05 +02:00
|
|
|
icmpv6_opt_hdr_len += 8;
|
2011-06-24 02:40:25 +02:00
|
|
|
packet_length += 8;
|
2011-06-18 23:33:47 +02:00
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2011-06-18 23:33:47 +02:00
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (msg_abr != NULL && contexts != NULL) {
|
2011-06-18 23:33:47 +02:00
|
|
|
free(contexts);
|
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-08-04 04:06:31 +02:00
|
|
|
mutex_unlock(&lowpan_context_mutex);
|
2011-06-18 23:33:47 +02:00
|
|
|
}
|
2010-11-08 10:33:23 +01:00
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (pi == OPT_PI) {
|
2011-01-18 11:02:48 +01:00
|
|
|
/* set prefix option */
|
2013-06-24 22:37:35 +02:00
|
|
|
for (int i = 0; i < OPT_PI_LIST_LEN; i++) {
|
|
|
|
if (plist[i].inuse && plist[i].adv) {
|
2013-08-13 06:41:05 +02:00
|
|
|
opt_pi_buf = get_opt_pi_buf(ipv6_ext_hdr_len, icmpv6_opt_hdr_len);
|
2011-06-24 14:39:24 +02:00
|
|
|
memcpy(&(opt_pi_buf->addr.uint8[0]), &(plist[i].addr.uint8[0]), 16);
|
2010-11-22 12:52:56 +01:00
|
|
|
opt_pi_buf->type = OPT_PI_TYPE;
|
|
|
|
opt_pi_buf->length = OPT_PI_LEN;
|
2011-06-24 14:39:24 +02:00
|
|
|
opt_pi_buf->prefix_length = plist[i].length;
|
|
|
|
opt_pi_buf->l_a_reserved1 = plist[i].l_a_reserved1;
|
|
|
|
opt_pi_buf->val_ltime = HTONL(plist[i].val_ltime);
|
|
|
|
opt_pi_buf->pref_ltime = HTONL(plist[i].pref_ltime);
|
2010-11-22 12:52:56 +01:00
|
|
|
opt_pi_buf->reserved2 = 0;
|
|
|
|
packet_length += OPT_PI_HDR_LEN;
|
2013-08-13 06:41:05 +02:00
|
|
|
icmpv6_opt_hdr_len += OPT_PI_HDR_LEN;
|
2011-06-18 23:33:27 +02:00
|
|
|
}
|
|
|
|
}
|
2010-11-22 12:52:56 +01:00
|
|
|
}
|
2010-11-08 10:33:23 +01:00
|
|
|
|
2013-08-02 01:19:20 +02:00
|
|
|
ipv6_buf->length = HTONS(packet_length - IPV6_HDR_LEN);
|
2010-11-08 10:33:23 +01:00
|
|
|
|
|
|
|
/* calculate checksum */
|
2010-11-09 22:20:26 +01:00
|
|
|
icmp_buf->checksum = 0;
|
2013-08-13 06:41:05 +02:00
|
|
|
icmp_buf->checksum = ~icmpv6_csum(IPV6_PROTO_NUM_ICMPV6);
|
2010-11-22 12:52:56 +01:00
|
|
|
}
|
|
|
|
|
2013-06-22 05:11:53 +02:00
|
|
|
void recv_rtr_adv(void)
|
|
|
|
{
|
2011-01-24 22:41:32 +01:00
|
|
|
int8_t trigger_ns = -1;
|
2011-06-18 23:33:27 +02:00
|
|
|
int8_t abro_found = 0;
|
2013-06-22 05:11:53 +02:00
|
|
|
int16_t abro_version = 0; /* later replaced, just to supress warnings */
|
2013-08-09 03:13:37 +02:00
|
|
|
uint16_t packet_length;
|
2011-06-18 23:33:27 +02:00
|
|
|
ipv6_addr_t abro_addr;
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-08-13 06:41:05 +02:00
|
|
|
ipv6_buf = ipv6_get_buf();
|
2013-08-09 03:13:37 +02:00
|
|
|
packet_length = IPV6_HDR_LEN + ipv6_buf->length;
|
2013-08-13 06:41:05 +02:00
|
|
|
icmpv6_opt_hdr_len = RTR_ADV_LEN;
|
2011-06-24 02:40:25 +02:00
|
|
|
rtr_adv_buf = get_rtr_adv_buf(ipv6_ext_hdr_len);
|
|
|
|
ipv6_addr_t newaddr;
|
2011-07-26 13:35:58 +02:00
|
|
|
recvd_cids_len = 0;
|
2011-01-18 11:02:48 +01:00
|
|
|
|
|
|
|
/* update interface reachable time and retrans timer */
|
2013-06-24 22:37:35 +02:00
|
|
|
if (rtr_adv_buf->reachable_time != 0) {
|
2013-06-22 05:11:53 +02:00
|
|
|
iface.adv_reachable_time = HTONL(rtr_adv_buf->reachable_time);
|
2011-01-18 11:02:48 +01:00
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (rtr_adv_buf->retrans_timer != 0) {
|
2011-01-18 11:02:48 +01:00
|
|
|
iface.adv_retrans_timer = HTONL(rtr_adv_buf->retrans_timer);
|
|
|
|
}
|
|
|
|
|
2013-08-14 04:35:58 +02:00
|
|
|
def_rtr_entry = ndp_default_router_list_search(&ipv6_buf->srcaddr);
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (rtr_adv_buf->router_lifetime != 0) {
|
|
|
|
if (def_rtr_entry != NULL) {
|
2012-01-11 17:02:43 +01:00
|
|
|
set_remaining_time(&(def_rtr_entry->inval_time), HTONL(rtr_adv_buf->router_lifetime));
|
2013-06-22 05:11:53 +02:00
|
|
|
}
|
2012-01-11 17:02:43 +01:00
|
|
|
else {
|
|
|
|
def_rtr_lst_add(&(ipv6_buf->srcaddr), HTONL(rtr_adv_buf->router_lifetime));
|
2011-01-24 22:41:32 +01:00
|
|
|
trigger_ns = 1;
|
2011-01-18 11:02:48 +01:00
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
}
|
|
|
|
else {
|
2011-01-18 11:02:48 +01:00
|
|
|
/* remove router from default router list */
|
2013-06-24 22:37:35 +02:00
|
|
|
if (def_rtr_entry != NULL) {
|
2011-01-18 11:02:48 +01:00
|
|
|
def_rtr_lst_rem(def_rtr_entry);
|
2013-06-22 05:11:53 +02:00
|
|
|
}
|
2011-01-18 11:02:48 +01:00
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2011-06-24 01:48:41 +02:00
|
|
|
mutex_lock(&lowpan_context_mutex);
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2011-01-18 11:02:48 +01:00
|
|
|
/* read options */
|
2013-09-17 19:46:50 +02:00
|
|
|
while (packet_length > IPV6_HDR_LEN + ICMPV6_HDR_LEN + icmpv6_opt_hdr_len) {
|
2013-08-13 06:41:05 +02:00
|
|
|
opt_buf = get_opt_buf(ipv6_ext_hdr_len, icmpv6_opt_hdr_len);
|
2011-01-18 11:02:48 +01:00
|
|
|
|
2013-08-08 13:39:00 +02:00
|
|
|
switch (opt_buf->type) {
|
2013-08-14 04:35:58 +02:00
|
|
|
case (NDP_OPT_SLLAO_TYPE): {
|
2011-01-18 11:02:48 +01:00
|
|
|
break;
|
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
case (OPT_MTU_TYPE): {
|
2011-01-18 11:02:48 +01:00
|
|
|
break;
|
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2011-01-18 11:02:48 +01:00
|
|
|
/* rfc 4862 section 5.5.3 */
|
2013-06-24 22:37:35 +02:00
|
|
|
case (OPT_PI_TYPE): {
|
2013-08-13 06:41:05 +02:00
|
|
|
opt_pi_buf = get_opt_pi_buf(ipv6_ext_hdr_len, icmpv6_opt_hdr_len);
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2011-01-18 11:02:48 +01:00
|
|
|
/* crazy condition, read 5.5.3a-b-c for further information */
|
2013-08-13 06:41:05 +02:00
|
|
|
if (ipv6_addr_is_link_local(&opt_pi_buf->addr) ||
|
2013-08-08 13:39:00 +02:00
|
|
|
(HTONL(opt_pi_buf->pref_ltime) >
|
|
|
|
HTONL(opt_pi_buf->val_ltime))) {
|
2011-01-18 11:02:48 +01:00
|
|
|
break;
|
2013-06-22 05:11:53 +02:00
|
|
|
}
|
2012-01-11 17:02:43 +01:00
|
|
|
else {
|
2011-01-24 22:41:32 +01:00
|
|
|
/* check if on-link flag is set */
|
2013-08-14 04:35:58 +02:00
|
|
|
if (opt_pi_buf->l_a_reserved1 & ICMPV6_NDP_OPT_PI_FLAG_ON_LINK) {
|
2011-01-24 22:41:32 +01:00
|
|
|
/* TODO: do on-link pi handling */
|
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-08-14 04:35:58 +02:00
|
|
|
if (opt_pi_buf->l_a_reserved1 & ICMPV6_NDP_OPT_PI_FLAG_AUTONOM) {
|
2012-01-11 17:02:43 +01:00
|
|
|
addr_list_ptr = ipv6_iface_addr_prefix_eq(&opt_pi_buf->addr);
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (addr_list_ptr == NULL) {
|
2011-01-24 22:41:32 +01:00
|
|
|
/* 5.5.3d */
|
2013-06-24 22:37:35 +02:00
|
|
|
if (opt_pi_buf->val_ltime != 0) {
|
2011-01-24 22:41:32 +01:00
|
|
|
/* iid will also be added here */
|
2013-08-13 06:41:05 +02:00
|
|
|
ipv6_addr_set_by_eui64(&newaddr,
|
|
|
|
&opt_pi_buf->addr);
|
2013-06-22 05:11:53 +02:00
|
|
|
/* add into address list
|
|
|
|
* TODO: duplicate address detection is not
|
|
|
|
* implementet yet, so all new addresse will
|
2011-01-24 22:41:32 +01:00
|
|
|
* be added with state PREFFERED */
|
|
|
|
ipv6_iface_add_addr(&newaddr,
|
2013-08-13 06:41:05 +02:00
|
|
|
IPV6_ADDR_TYPE_UNICAST,
|
|
|
|
NDP_ADDR_STATE_PREFERRED,
|
2011-01-24 22:41:32 +01:00
|
|
|
opt_pi_buf->val_ltime,
|
2013-08-13 06:41:05 +02:00
|
|
|
opt_pi_buf->pref_ltime);
|
2013-11-21 00:21:01 +01:00
|
|
|
DEBUG("INFO: added address to interface\n");
|
2011-01-24 22:41:32 +01:00
|
|
|
trigger_ns = 1;
|
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
}
|
2012-01-11 17:02:43 +01:00
|
|
|
else {
|
2013-06-22 05:11:53 +02:00
|
|
|
/* 5.5.3e */
|
2012-01-11 17:02:43 +01:00
|
|
|
set_remaining_time(&(addr_list_ptr->pref_ltime), opt_pi_buf->pref_ltime);
|
2011-01-24 22:41:32 +01:00
|
|
|
|
|
|
|
/* 7200 = 2hours in seconds */
|
2013-06-24 22:37:35 +02:00
|
|
|
if (HTONL(opt_pi_buf->val_ltime) > 7200 ||
|
2013-08-08 13:39:00 +02:00
|
|
|
HTONL(opt_pi_buf->val_ltime) >
|
|
|
|
get_remaining_time(&(addr_list_ptr->val_ltime))) {
|
2012-01-11 17:02:43 +01:00
|
|
|
set_remaining_time(&(addr_list_ptr->val_ltime), HTONL(opt_pi_buf->val_ltime));
|
|
|
|
}
|
|
|
|
else {
|
2011-01-24 22:41:32 +01:00
|
|
|
/* reset valid lifetime to 2 hours */
|
|
|
|
set_remaining_time(&(addr_list_ptr->val_ltime), 7200);
|
|
|
|
}
|
2011-01-18 11:02:48 +01:00
|
|
|
}
|
2011-01-24 22:41:32 +01:00
|
|
|
}
|
2011-01-18 11:02:48 +01:00
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
|
|
|
|
/* TODO: save found prefixes */
|
2011-01-18 11:02:48 +01:00
|
|
|
break;
|
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
case (OPT_6CO_TYPE): {
|
2011-06-18 23:33:47 +02:00
|
|
|
uint8_t comp;
|
|
|
|
uint8_t num;
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-08-13 06:41:05 +02:00
|
|
|
opt_6co_hdr_buf = get_opt_6co_hdr_buf(ipv6_ext_hdr_len, icmpv6_opt_hdr_len);
|
2013-06-22 05:11:53 +02:00
|
|
|
|
|
|
|
get_opt_6co_flags(&comp, &num, opt_6co_hdr_buf->c_flags);
|
|
|
|
|
2011-06-18 23:33:47 +02:00
|
|
|
ipv6_addr_t prefix;
|
|
|
|
memset(&prefix, 0, 16);
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-08-13 06:41:05 +02:00
|
|
|
opt_6co_prefix_buf = get_opt_6co_prefix_buf(ipv6_ext_hdr_len, icmpv6_opt_hdr_len + OPT_6CO_HDR_LEN);
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2011-06-24 01:48:41 +02:00
|
|
|
memcpy(&prefix, opt_6co_prefix_buf, opt_6co_hdr_buf->c_length);
|
2013-06-22 05:11:53 +02:00
|
|
|
|
|
|
|
lowpan_context_update(
|
|
|
|
num,
|
|
|
|
&prefix,
|
|
|
|
opt_6co_hdr_buf->c_length,
|
|
|
|
comp,
|
|
|
|
HTONS(opt_6co_hdr_buf->val_ltime)
|
|
|
|
);
|
2011-07-26 13:35:58 +02:00
|
|
|
recvd_cids[recvd_cids_len] = num;
|
2013-08-14 04:35:58 +02:00
|
|
|
recvd_cids_len = (recvd_cids_len + 1) % NDP_6LOWPAN_CONTEXT_MAX;
|
2011-01-18 11:02:48 +01:00
|
|
|
break;
|
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
case (OPT_ABRO_TYPE): {
|
2013-08-13 06:41:05 +02:00
|
|
|
opt_abro_buf = get_opt_abro_buf(ipv6_ext_hdr_len, icmpv6_opt_hdr_len);
|
2011-06-18 23:33:27 +02:00
|
|
|
abro_found = 1;
|
2011-06-24 01:48:41 +02:00
|
|
|
abro_version = HTONS(opt_abro_buf->version);
|
2011-06-18 23:33:27 +02:00
|
|
|
memcpy(&(abro_addr), &(opt_abro_buf->addr), sizeof(ipv6_addr_t));
|
2013-06-22 05:11:53 +02:00
|
|
|
break;
|
2011-01-18 11:02:48 +01:00
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2011-01-18 11:02:48 +01:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2011-01-18 11:02:48 +01:00
|
|
|
/* multiplied with 8 because options length is in units of 8 bytes */
|
2013-08-13 06:41:05 +02:00
|
|
|
icmpv6_opt_hdr_len += (opt_buf->length * 8);
|
2011-01-18 11:02:48 +01:00
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (abro_found) {
|
2011-07-26 13:35:58 +02:00
|
|
|
int i;
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
for (i = 0; i < recvd_cids_len; i++) {
|
2013-06-22 05:11:53 +02:00
|
|
|
abr_add_context(abro_version, &abro_addr, recvd_cids[i]);
|
2011-07-26 13:35:58 +02:00
|
|
|
}
|
2011-06-18 23:33:27 +02:00
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-08-04 04:06:31 +02:00
|
|
|
mutex_unlock(&lowpan_context_mutex);
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (trigger_ns >= 0) {
|
2013-06-22 05:11:53 +02:00
|
|
|
/* send ns - draft-ietf-6lowpan-nd-15#section-5.5.1
|
|
|
|
*
|
|
|
|
* section-10.2.4
|
2011-01-24 22:41:32 +01:00
|
|
|
* "Next the 6LN registers that address with one or more of its
|
|
|
|
* default routers by sending a unicast NS message with an ARO
|
|
|
|
* containing its tentative global IPv6 address to register
|
|
|
|
*
|
2013-06-22 05:11:53 +02:00
|
|
|
* if new address was configured, set src to newaddr(gp16) */
|
2013-08-14 04:35:58 +02:00
|
|
|
icmpv6_send_neighbor_sol(&newaddr, &(ipv6_buf->srcaddr), &(ipv6_buf->srcaddr), OPT_SLLAO, OPT_ARO);
|
2013-07-24 00:36:06 +02:00
|
|
|
#if ENABLE_DEBUG
|
2013-08-13 06:41:05 +02:00
|
|
|
char addr_str[IPV6_MAX_ADDR_STR_LEN];
|
|
|
|
printf("INFO: send neighbor solicitation to: %s\n",
|
|
|
|
ipv6_addr_to_str(addr_str, &(ipv6_buf->destaddr)));
|
2011-05-16 14:26:42 +02:00
|
|
|
#endif
|
2013-08-15 11:27:30 +02:00
|
|
|
sixlowpan_lowpan_sendto((ieee_802154_long_t *) &ipv6_buf->destaddr.uint16[4],
|
2013-08-09 03:13:37 +02:00
|
|
|
(uint8_t *)ipv6_buf,
|
|
|
|
packet_length);
|
2011-01-24 22:41:32 +01:00
|
|
|
}
|
2011-01-18 11:02:48 +01:00
|
|
|
}
|
|
|
|
|
2013-08-14 04:35:58 +02:00
|
|
|
void icmpv6_send_neighbor_sol(ipv6_addr_t *src, ipv6_addr_t *dest, ipv6_addr_t *targ,
|
|
|
|
uint8_t sllao, uint8_t aro)
|
2013-06-22 05:11:53 +02:00
|
|
|
{
|
2013-08-09 03:13:37 +02:00
|
|
|
uint16_t packet_length;
|
|
|
|
|
2013-08-13 06:41:05 +02:00
|
|
|
ipv6_buf = ipv6_get_buf();
|
2010-11-22 12:52:56 +01:00
|
|
|
ipv6_buf->version_trafficclass = IPV6_VER;
|
|
|
|
ipv6_buf->trafficclass_flowlabel = 0;
|
|
|
|
ipv6_buf->flowlabel = 0;
|
2013-08-13 06:41:05 +02:00
|
|
|
ipv6_buf->nextheader = IPV6_PROTO_NUM_ICMPV6;
|
2010-11-22 12:52:56 +01:00
|
|
|
ipv6_buf->hoplimit = ND_HOPLIMIT;
|
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (dest == NULL) {
|
2013-08-13 06:41:05 +02:00
|
|
|
ipv6_addr_set_solicited_node_addr(&(ipv6_buf->destaddr), targ);
|
2013-06-22 05:11:53 +02:00
|
|
|
}
|
|
|
|
else {
|
2011-01-18 11:02:48 +01:00
|
|
|
memcpy(&(ipv6_buf->destaddr.uint8[0]), &(dest->uint8[0]), 16);
|
2010-11-22 12:52:56 +01:00
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
|
|
|
|
ipv6_ext_hdr_len = 0;
|
2010-11-22 12:52:56 +01:00
|
|
|
icmp_buf = get_icmpv6_buf(ipv6_ext_hdr_len);
|
2013-08-14 04:35:58 +02:00
|
|
|
icmp_buf->type = ICMPV6_TYPE_NEIGHBOR_SOL;
|
2010-11-22 12:52:56 +01:00
|
|
|
icmp_buf->code = 0;
|
2013-06-22 05:11:53 +02:00
|
|
|
|
|
|
|
nbr_sol_buf = get_nbr_sol_buf(ipv6_ext_hdr_len);
|
|
|
|
nbr_sol_buf->reserved = 0;
|
2013-08-14 04:35:58 +02:00
|
|
|
memcpy(&(nbr_sol_buf->target_addr), targ, 16);
|
2013-08-13 06:41:05 +02:00
|
|
|
icmpv6_opt_hdr_len = NBR_SOL_LEN;
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2011-01-18 11:02:48 +01:00
|
|
|
packet_length = IPV6_HDR_LEN + ICMPV6_HDR_LEN + NBR_SOL_LEN;
|
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (ipv6_iface_addr_match(targ) == NULL) {
|
|
|
|
if (src == NULL) {
|
2013-08-13 06:41:05 +02:00
|
|
|
ipv6_iface_get_best_src_addr(&(ipv6_buf->srcaddr), &(ipv6_buf->destaddr));
|
2013-06-22 05:11:53 +02:00
|
|
|
}
|
|
|
|
else {
|
2011-01-24 22:41:32 +01:00
|
|
|
memcpy(&(ipv6_buf->srcaddr), src, 16);
|
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (sllao == OPT_SLLAO) {
|
2011-01-24 22:41:32 +01:00
|
|
|
/* set sllao option */
|
2013-08-13 06:41:05 +02:00
|
|
|
opt_stllao_buf = get_opt_stllao_buf(ipv6_ext_hdr_len, icmpv6_opt_hdr_len);
|
2013-08-14 21:48:36 +02:00
|
|
|
icmpv6_ndp_set_sllao(opt_stllao_buf, NDP_OPT_SLLAO_TYPE, 1);
|
2013-08-13 06:41:05 +02:00
|
|
|
icmpv6_opt_hdr_len += OPT_STLLAO_MIN_LEN;
|
2011-01-24 22:41:32 +01:00
|
|
|
|
2011-07-04 16:47:06 +02:00
|
|
|
packet_length += OPT_STLLAO_MIN_LEN;
|
2011-01-24 22:41:32 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (aro == OPT_ARO) {
|
2011-01-24 22:41:32 +01:00
|
|
|
/* set aro option */
|
2013-08-13 06:41:05 +02:00
|
|
|
opt_aro_buf = get_opt_aro_buf(ipv6_ext_hdr_len, icmpv6_opt_hdr_len);
|
2011-01-24 22:41:32 +01:00
|
|
|
opt_aro_buf->type = OPT_ARO_TYPE;
|
|
|
|
opt_aro_buf->length = OPT_ARO_LEN;
|
|
|
|
opt_aro_buf->status = 0;
|
|
|
|
opt_aro_buf->reserved1 = 0;
|
|
|
|
opt_aro_buf->reserved2 = 0;
|
2013-08-08 16:22:37 +02:00
|
|
|
memcpy(&(opt_aro_buf->eui64), sixlowpan_mac_get_eui64(src), 8);
|
2013-08-13 06:41:05 +02:00
|
|
|
icmpv6_opt_hdr_len += OPT_ARO_HDR_LEN;
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2011-01-24 22:41:32 +01:00
|
|
|
packet_length += OPT_ARO_HDR_LEN;
|
|
|
|
}
|
|
|
|
|
2013-08-02 01:19:20 +02:00
|
|
|
ipv6_buf->length = HTONS(packet_length - IPV6_HDR_LEN);
|
2011-01-24 22:41:32 +01:00
|
|
|
|
|
|
|
icmp_buf->checksum = 0;
|
2013-08-13 06:41:05 +02:00
|
|
|
icmp_buf->checksum = ~icmpv6_csum(IPV6_PROTO_NUM_ICMPV6);
|
2011-01-24 22:41:32 +01:00
|
|
|
}
|
|
|
|
|
2013-06-22 05:11:53 +02:00
|
|
|
void recv_nbr_sol(void)
|
|
|
|
{
|
2013-08-13 06:41:05 +02:00
|
|
|
ipv6_buf = ipv6_get_buf();
|
2011-01-24 22:41:32 +01:00
|
|
|
llao = NULL;
|
2013-08-13 06:41:05 +02:00
|
|
|
icmpv6_opt_hdr_len = NBR_SOL_LEN;
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2011-01-24 22:41:32 +01:00
|
|
|
uint8_t send_na = 0;
|
|
|
|
uint8_t sllao_set = 0;
|
2013-08-14 04:35:58 +02:00
|
|
|
uint8_t aro_state = NDP_OPT_ARO_STATE_SUCCESS;
|
2013-08-09 03:13:37 +02:00
|
|
|
uint16_t packet_length = IPV6_HDR_LEN + ipv6_buf->length;
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2011-01-24 22:41:32 +01:00
|
|
|
/* check whick options are set, we need that because an aro
|
2013-06-22 05:11:53 +02:00
|
|
|
* option condition is that a sllao option is set. thus that we don't
|
2011-01-24 22:41:32 +01:00
|
|
|
* know which option comes first we need to this here */
|
|
|
|
|
2013-09-17 19:46:50 +02:00
|
|
|
while (packet_length > IPV6_HDR_LEN + ICMPV6_HDR_LEN + icmpv6_opt_hdr_len) {
|
2013-08-13 06:41:05 +02:00
|
|
|
opt_buf = get_opt_buf(ipv6_ext_hdr_len, icmpv6_opt_hdr_len);
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-08-14 04:35:58 +02:00
|
|
|
if (opt_buf->type == NDP_OPT_SLLAO_TYPE) {
|
2011-01-24 22:41:32 +01:00
|
|
|
sllao_set = 1;
|
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-08-13 06:41:05 +02:00
|
|
|
icmpv6_opt_hdr_len += (opt_buf->length * 8);
|
2013-06-22 05:11:53 +02:00
|
|
|
}
|
|
|
|
|
2013-08-13 06:41:05 +02:00
|
|
|
icmpv6_opt_hdr_len = NBR_SOL_LEN;
|
2011-01-24 22:41:32 +01:00
|
|
|
|
2013-09-17 19:46:50 +02:00
|
|
|
while (packet_length > IPV6_HDR_LEN + ICMPV6_HDR_LEN + icmpv6_opt_hdr_len) {
|
2013-08-13 06:41:05 +02:00
|
|
|
opt_buf = get_opt_buf(ipv6_ext_hdr_len, icmpv6_opt_hdr_len);
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-08-08 13:39:00 +02:00
|
|
|
switch (opt_buf->type) {
|
2013-08-14 04:35:58 +02:00
|
|
|
case (NDP_OPT_SLLAO_TYPE): {
|
2011-01-24 22:41:32 +01:00
|
|
|
opt_stllao_buf = get_opt_stllao_buf(ipv6_ext_hdr_len,
|
2013-08-13 06:41:05 +02:00
|
|
|
icmpv6_opt_hdr_len);
|
2013-06-22 05:11:53 +02:00
|
|
|
llao = (uint8_t *)opt_stllao_buf;
|
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (llao != NULL &&
|
2013-08-13 06:41:05 +02:00
|
|
|
!(ipv6_addr_is_unspecified(&ipv6_buf->srcaddr))) {
|
2013-08-14 04:35:58 +02:00
|
|
|
nbr_entry = ndp_neighbor_cache_search(&(ipv6_buf->srcaddr));
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (nbr_entry != NULL) {
|
2013-08-08 13:39:00 +02:00
|
|
|
switch (opt_stllao_buf->length) {
|
2013-06-24 22:37:35 +02:00
|
|
|
case (1): {
|
|
|
|
if (memcmp(&llao[2], &(nbr_entry->saddr), 2) == 0) {
|
2011-01-24 22:41:32 +01:00
|
|
|
nbr_entry->isrouter = 0;
|
2013-06-22 05:11:53 +02:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
memcpy(&nbr_entry->saddr, &llao[2], 2);
|
2013-08-14 17:04:17 +02:00
|
|
|
nbr_entry->state = NDP_NCE_STATUS_STALE;
|
2011-01-24 22:41:32 +01:00
|
|
|
nbr_entry->isrouter = 0;
|
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2011-01-24 22:41:32 +01:00
|
|
|
break;
|
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
case (2): {
|
|
|
|
if (memcmp(&llao[2], &(nbr_entry->laddr), 8) == 0) {
|
2011-01-24 22:41:32 +01:00
|
|
|
nbr_entry->isrouter = 0;
|
2013-06-22 05:11:53 +02:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
memcpy(&nbr_entry->laddr, &llao[2], 8);
|
2013-08-14 17:04:17 +02:00
|
|
|
nbr_entry->state = NDP_NCE_STATUS_STALE;
|
2011-01-24 22:41:32 +01:00
|
|
|
nbr_entry->isrouter = 0;
|
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2011-01-24 22:41:32 +01:00
|
|
|
break;
|
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2011-01-24 22:41:32 +01:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
}
|
|
|
|
else {
|
2013-08-08 13:39:00 +02:00
|
|
|
switch (opt_stllao_buf->length) {
|
2013-06-24 22:37:35 +02:00
|
|
|
case (1): {
|
2011-01-24 22:41:32 +01:00
|
|
|
nbr_cache_add(&ipv6_buf->srcaddr,
|
2013-08-14 17:04:17 +02:00
|
|
|
NULL , 0, NDP_NCE_STATUS_STALE,
|
|
|
|
NDP_NCE_TYPE_TENTATIVE,
|
2013-06-22 05:11:53 +02:00
|
|
|
NBR_CACHE_LTIME_TEN,
|
|
|
|
(ieee_802154_short_t *)&llao[2]);
|
2011-01-24 22:41:32 +01:00
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
case (2): {
|
2011-01-24 22:41:32 +01:00
|
|
|
nbr_cache_add(&ipv6_buf->srcaddr,
|
2013-06-22 05:11:53 +02:00
|
|
|
(ieee_802154_long_t *)&llao[2], 0,
|
2013-08-14 17:04:17 +02:00
|
|
|
NDP_NCE_STATUS_STALE,
|
|
|
|
NDP_NCE_TYPE_TENTATIVE,
|
2011-01-24 22:41:32 +01:00
|
|
|
NBR_CACHE_LTIME_TEN, NULL);
|
|
|
|
break;
|
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2011-01-24 22:41:32 +01:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2011-01-24 22:41:32 +01:00
|
|
|
break;
|
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
case (OPT_ARO_TYPE): {
|
2013-06-22 05:11:53 +02:00
|
|
|
/* check if sllao option is set, and if address src address
|
|
|
|
* isn't unspecified - draft-ietf-6lowpan-nd-15#section-6.5 */
|
2013-08-13 06:41:05 +02:00
|
|
|
if (!(ipv6_addr_is_unspecified(&ipv6_buf->srcaddr)) &&
|
2013-08-08 13:39:00 +02:00
|
|
|
sllao_set == 1) {
|
2013-06-22 05:11:53 +02:00
|
|
|
opt_aro_buf = get_opt_aro_buf(ipv6_ext_hdr_len,
|
2013-08-13 06:41:05 +02:00
|
|
|
icmpv6_opt_hdr_len);
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if ((opt_aro_buf->length == 2) &&
|
2013-08-08 13:39:00 +02:00
|
|
|
(opt_aro_buf->status == 0)) {
|
2011-01-24 22:41:32 +01:00
|
|
|
/* check neighbor cache for duplicates */
|
2013-08-14 04:35:58 +02:00
|
|
|
nbr_entry = ndp_neighbor_cache_search(&(ipv6_buf->srcaddr));
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (nbr_entry == NULL) {
|
2011-01-24 22:41:32 +01:00
|
|
|
/* create neighbor cache */
|
2011-06-22 11:49:29 +02:00
|
|
|
aro_state = nbr_cache_add(&ipv6_buf->srcaddr,
|
2013-06-22 05:11:53 +02:00
|
|
|
&(opt_aro_buf->eui64), 0,
|
2013-08-14 17:04:17 +02:00
|
|
|
NDP_NCE_STATUS_STALE, NDP_NCE_TYPE_TENTATIVE,
|
2011-06-22 11:49:29 +02:00
|
|
|
opt_aro_buf->reg_ltime, NULL);
|
2013-06-22 05:11:53 +02:00
|
|
|
}
|
|
|
|
else {
|
2013-06-24 22:37:35 +02:00
|
|
|
if (memcmp(&(nbr_entry->addr.uint16[4]),
|
2013-08-08 13:39:00 +02:00
|
|
|
&(opt_aro_buf->eui64.uint16[0]), 8) == 0) {
|
2011-01-24 22:41:32 +01:00
|
|
|
/* update neighbor cache entry */
|
2013-06-24 22:37:35 +02:00
|
|
|
if (opt_aro_buf->reg_ltime == 0) {
|
2011-01-24 22:41:32 +01:00
|
|
|
/* delete neighbor cache entry */
|
2013-06-22 05:11:53 +02:00
|
|
|
nbr_cache_rem(&nbr_entry->addr);
|
|
|
|
}
|
|
|
|
else {
|
2012-01-11 17:02:43 +01:00
|
|
|
set_remaining_time(&(nbr_entry->ltime), (uint32_t)opt_aro_buf->reg_ltime);
|
2013-08-14 17:04:17 +02:00
|
|
|
nbr_entry->state = NDP_NCE_STATUS_STALE;
|
2011-01-24 22:41:32 +01:00
|
|
|
nbr_entry->isrouter = 0;
|
|
|
|
memcpy(&(nbr_entry->addr.uint8[0]),
|
2013-06-22 05:11:53 +02:00
|
|
|
&(ipv6_buf->srcaddr.uint8[0]), 16);
|
2011-06-22 11:49:29 +02:00
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-08-14 04:35:58 +02:00
|
|
|
aro_state = NDP_OPT_ARO_STATE_SUCCESS;
|
2013-06-22 05:11:53 +02:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* duplicate found */
|
2013-08-14 04:35:58 +02:00
|
|
|
aro_state = NDP_OPT_ARO_STATE_DUP_ADDR;
|
2011-01-24 22:41:32 +01:00
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
}
|
2011-01-24 22:41:32 +01:00
|
|
|
}
|
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2011-01-24 22:41:32 +01:00
|
|
|
break;
|
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2011-01-24 22:41:32 +01:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-08-13 06:41:05 +02:00
|
|
|
icmpv6_opt_hdr_len += (opt_buf->length * 8);
|
2011-01-24 22:41:32 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
addr_list_t *alist_targ, *alist_dest;
|
|
|
|
|
|
|
|
nbr_sol_buf = get_nbr_sol_buf(ipv6_ext_hdr_len);
|
2013-08-14 04:35:58 +02:00
|
|
|
alist_targ = ipv6_iface_addr_match(&(nbr_sol_buf->target_addr));
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (alist_targ != NULL) {
|
2011-01-24 22:41:32 +01:00
|
|
|
alist_dest = ipv6_iface_addr_match(&(ipv6_buf->destaddr));
|
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if ((memcmp(&(alist_targ->addr), &(alist_dest->addr), 16) == 0) ||
|
2013-08-13 06:41:05 +02:00
|
|
|
ipv6_addr_is_solicited_node(&ipv6_buf->destaddr)) {
|
2011-01-24 22:41:32 +01:00
|
|
|
memcpy(&(ipv6_buf->destaddr.uint8[0]),
|
2013-06-22 05:11:53 +02:00
|
|
|
&(ipv6_buf->srcaddr.uint8[0]), 16);
|
2011-01-24 22:41:32 +01:00
|
|
|
memcpy(&(ipv6_buf->srcaddr.uint8[0]),
|
2013-08-14 04:35:58 +02:00
|
|
|
&(nbr_sol_buf->target_addr.uint8[0]), 16);
|
2011-01-24 22:41:32 +01:00
|
|
|
send_na = 1;
|
|
|
|
}
|
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (send_na) {
|
2011-01-24 22:41:32 +01:00
|
|
|
/* solicited na */
|
2013-08-14 04:35:58 +02:00
|
|
|
uint8_t flags = (ICMPV6_NEIGHBOR_ADV_FLAG_OVERRIDE | ICMPV6_NEIGHBOR_ADV_FLAG_SOLICITED);
|
|
|
|
icmpv6_send_neighbor_adv(&(ipv6_buf->srcaddr), &(ipv6_buf->destaddr),
|
2013-08-14 21:48:36 +02:00
|
|
|
&(alist_targ->addr), flags, 0, OPT_ARO);
|
2013-07-24 00:36:06 +02:00
|
|
|
#if ENABLE_DEBUG
|
2013-08-13 06:41:05 +02:00
|
|
|
char addr_str[IPV6_MAX_ADDR_STR_LEN];
|
|
|
|
printf("INFO: send neighbor advertisment to: %s\n",
|
|
|
|
ipv6_addr_to_str(addr_str, &ipv6_buf->destaddr));
|
2011-05-16 14:26:42 +02:00
|
|
|
#endif
|
2013-08-15 11:27:30 +02:00
|
|
|
sixlowpan_lowpan_sendto((ieee_802154_long_t *) &ipv6_buf->destaddr.uint16[4],
|
2013-08-09 03:13:37 +02:00
|
|
|
(uint8_t *)ipv6_buf,
|
|
|
|
packet_length);
|
2011-01-24 22:41:32 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-14 04:35:58 +02:00
|
|
|
void icmpv6_send_neighbor_adv(ipv6_addr_t *src, ipv6_addr_t *dst, ipv6_addr_t *tgt,
|
2013-08-14 21:48:36 +02:00
|
|
|
uint8_t rso, uint8_t sllao, uint8_t aro)
|
2013-06-22 05:11:53 +02:00
|
|
|
{
|
2013-08-09 03:13:37 +02:00
|
|
|
uint16_t packet_length;
|
|
|
|
|
2013-08-13 06:41:05 +02:00
|
|
|
ipv6_buf = ipv6_get_buf();
|
2011-01-24 22:41:32 +01:00
|
|
|
ipv6_buf->version_trafficclass = IPV6_VER;
|
|
|
|
ipv6_buf->trafficclass_flowlabel = 0;
|
|
|
|
ipv6_buf->flowlabel = 0;
|
2013-08-13 06:41:05 +02:00
|
|
|
ipv6_buf->nextheader = IPV6_PROTO_NUM_ICMPV6;
|
2011-01-24 22:41:32 +01:00
|
|
|
ipv6_buf->hoplimit = ND_HOPLIMIT;
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2011-01-24 22:41:32 +01:00
|
|
|
ipv6_ext_hdr_len = 0;
|
|
|
|
icmp_buf = get_icmpv6_buf(ipv6_ext_hdr_len);
|
2013-08-14 04:35:58 +02:00
|
|
|
icmp_buf->type = ICMPV6_TYPE_NEIGHBOR_ADV;
|
2011-01-24 22:41:32 +01:00
|
|
|
icmp_buf->code = 0;
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2011-01-24 22:41:32 +01:00
|
|
|
memcpy(&(ipv6_buf->destaddr.uint8[0]), &(dst->uint8[0]), 16);
|
|
|
|
memcpy(&(ipv6_buf->srcaddr.uint8[0]), &(src->uint8[0]), 16);
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2011-01-24 22:41:32 +01:00
|
|
|
nbr_adv_buf = get_nbr_adv_buf(ipv6_ext_hdr_len);
|
|
|
|
nbr_adv_buf->rso = rso;
|
2013-06-22 05:11:53 +02:00
|
|
|
|
|
|
|
memset(&(nbr_adv_buf->reserved[0]), 0, 3);
|
2013-08-14 04:35:58 +02:00
|
|
|
memcpy(&(nbr_adv_buf->target_addr.uint8[0]), &(tgt->uint8[0]), 16);
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2011-01-24 22:41:32 +01:00
|
|
|
packet_length = IPV6_HDR_LEN + ICMPV6_HDR_LEN + NBR_ADV_LEN;
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (sllao == OPT_SLLAO) {
|
2011-06-23 03:42:39 +02:00
|
|
|
/* set sllao option */
|
2013-08-13 06:41:05 +02:00
|
|
|
opt_stllao_buf = get_opt_stllao_buf(ipv6_ext_hdr_len, icmpv6_opt_hdr_len);
|
2013-08-14 21:48:36 +02:00
|
|
|
icmpv6_ndp_set_sllao(opt_stllao_buf, NDP_OPT_SLLAO_TYPE, 1);
|
2013-08-13 06:41:05 +02:00
|
|
|
icmpv6_opt_hdr_len += OPT_STLLAO_MIN_LEN;
|
2011-01-24 22:41:32 +01:00
|
|
|
|
2011-07-04 16:47:06 +02:00
|
|
|
packet_length += OPT_STLLAO_MIN_LEN;
|
2011-01-18 11:02:48 +01:00
|
|
|
}
|
2011-01-24 22:41:32 +01:00
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (aro == OPT_ARO) {
|
2011-01-18 11:02:48 +01:00
|
|
|
/* set aro option */
|
2013-08-13 06:41:05 +02:00
|
|
|
opt_aro_buf = get_opt_aro_buf(ipv6_ext_hdr_len, icmpv6_opt_hdr_len);
|
2011-01-18 11:02:48 +01:00
|
|
|
opt_aro_buf->type = OPT_ARO_TYPE;
|
|
|
|
opt_aro_buf->length = OPT_ARO_LEN;
|
2013-06-22 05:11:53 +02:00
|
|
|
opt_aro_buf->status = 0; /* TODO */
|
2011-01-18 11:02:48 +01:00
|
|
|
opt_aro_buf->reserved1 = 0;
|
|
|
|
opt_aro_buf->reserved2 = 0;
|
2013-08-08 16:22:37 +02:00
|
|
|
memcpy(&(opt_aro_buf->eui64), sixlowpan_mac_get_eui64(dst), 8);
|
2013-08-13 06:41:05 +02:00
|
|
|
icmpv6_opt_hdr_len += OPT_ARO_HDR_LEN;
|
2011-01-24 22:41:32 +01:00
|
|
|
|
2011-01-18 11:02:48 +01:00
|
|
|
packet_length += OPT_ARO_HDR_LEN;
|
2010-11-22 12:52:56 +01:00
|
|
|
}
|
|
|
|
|
2013-08-02 01:19:20 +02:00
|
|
|
ipv6_buf->length = HTONS(packet_length - IPV6_HDR_LEN);
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2011-01-24 22:41:32 +01:00
|
|
|
icmp_buf->checksum = 0;
|
2013-08-13 06:41:05 +02:00
|
|
|
icmp_buf->checksum = ~icmpv6_csum(IPV6_PROTO_NUM_ICMPV6);
|
2011-01-24 22:41:32 +01:00
|
|
|
}
|
|
|
|
|
2013-06-22 05:11:53 +02:00
|
|
|
void recv_nbr_adv(void)
|
|
|
|
{
|
2013-08-13 06:41:05 +02:00
|
|
|
ipv6_buf = ipv6_get_buf();
|
2013-08-09 03:13:37 +02:00
|
|
|
uint16_t packet_length = IPV6_HDR_LEN + ipv6_buf->length;
|
2013-08-13 06:41:05 +02:00
|
|
|
icmpv6_opt_hdr_len = NBR_ADV_LEN;
|
2011-01-24 22:41:32 +01:00
|
|
|
llao = NULL;
|
|
|
|
nbr_entry = NULL;
|
|
|
|
int8_t new_ll = -1;
|
|
|
|
nbr_adv_buf = get_nbr_adv_buf(ipv6_ext_hdr_len);
|
|
|
|
|
|
|
|
/* check if options are present */
|
2013-09-17 19:46:50 +02:00
|
|
|
while (packet_length > IPV6_HDR_LEN + ICMPV6_HDR_LEN + icmpv6_opt_hdr_len) {
|
2013-08-13 06:41:05 +02:00
|
|
|
opt_buf = get_opt_buf(ipv6_ext_hdr_len, icmpv6_opt_hdr_len);
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-08-08 13:39:00 +02:00
|
|
|
switch (opt_buf->type) {
|
2013-08-14 04:35:58 +02:00
|
|
|
case (NDP_OPT_TLLAO_TYPE): {
|
2013-06-22 05:11:53 +02:00
|
|
|
llao = (uint8_t *)get_opt_stllao_buf(ipv6_ext_hdr_len,
|
2013-08-13 06:41:05 +02:00
|
|
|
icmpv6_opt_hdr_len);
|
2011-01-24 22:41:32 +01:00
|
|
|
break;
|
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
case (OPT_ARO_TYPE): {
|
2011-01-24 22:41:32 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-08-13 06:41:05 +02:00
|
|
|
icmpv6_opt_hdr_len += (opt_buf->length * 8);
|
2011-01-24 22:41:32 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
addr_list_t *addr;
|
2013-08-14 04:35:58 +02:00
|
|
|
addr = ipv6_iface_addr_match(&nbr_adv_buf->target_addr);
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (addr == NULL) {
|
2013-08-14 04:35:58 +02:00
|
|
|
nbr_entry = ndp_neighbor_cache_search(&nbr_adv_buf->target_addr);
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (nbr_entry != NULL) {
|
|
|
|
if (llao != 0) {
|
2011-01-24 22:41:32 +01:00
|
|
|
/* TODO: untersheiden zwischen short und long stllao option */
|
2013-06-22 05:11:53 +02:00
|
|
|
new_ll = memcmp(&llao[2], &(nbr_entry->laddr), 8);
|
2011-01-24 22:41:32 +01:00
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-08-14 17:04:17 +02:00
|
|
|
if (nbr_entry->state == NDP_NCE_STATUS_INCOMPLETE) {
|
2013-06-24 22:37:35 +02:00
|
|
|
if (llao == NULL) {
|
2011-01-24 22:41:32 +01:00
|
|
|
return;
|
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2011-01-24 22:41:32 +01:00
|
|
|
/* TODO: untersheiden zwischen short und long stllao option */
|
|
|
|
memcpy(&nbr_entry->laddr, &llao[2], 8);
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-08-14 04:35:58 +02:00
|
|
|
if (nbr_adv_buf->rso & ICMPV6_NEIGHBOR_ADV_FLAG_SOLICITED) {
|
2013-08-14 17:04:17 +02:00
|
|
|
nbr_entry->state = NDP_NCE_STATUS_REACHABLE;
|
2011-01-24 22:41:32 +01:00
|
|
|
/* TODO: set rechability */
|
2013-06-22 05:11:53 +02:00
|
|
|
}
|
|
|
|
else {
|
2013-08-14 17:04:17 +02:00
|
|
|
nbr_entry->state = NDP_NCE_STATUS_STALE;
|
2011-01-24 22:41:32 +01:00
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-08-14 04:35:58 +02:00
|
|
|
nbr_entry->isrouter = nbr_adv_buf->rso & ICMPV6_NEIGHBOR_ADV_FLAG_ROUTER;
|
2013-06-22 05:11:53 +02:00
|
|
|
}
|
|
|
|
else {
|
2013-08-14 04:35:58 +02:00
|
|
|
if (new_ll && !(nbr_adv_buf->rso & ICMPV6_NEIGHBOR_ADV_FLAG_OVERRIDE)) {
|
2013-08-14 17:04:17 +02:00
|
|
|
if (nbr_entry->state == NDP_NCE_STATUS_REACHABLE) {
|
|
|
|
nbr_entry->state = NDP_NCE_STATUS_STALE;
|
2011-01-24 22:41:32 +01:00
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2011-01-24 22:41:32 +01:00
|
|
|
return;
|
2013-06-22 05:11:53 +02:00
|
|
|
}
|
|
|
|
else {
|
2013-08-14 04:35:58 +02:00
|
|
|
if ((nbr_adv_buf->rso & ICMPV6_NEIGHBOR_ADV_FLAG_OVERRIDE) ||
|
|
|
|
(!(nbr_adv_buf->rso & ICMPV6_NEIGHBOR_ADV_FLAG_OVERRIDE) && llao != 0 &&
|
2013-08-08 13:39:00 +02:00
|
|
|
!new_ll)) {
|
2013-06-24 22:37:35 +02:00
|
|
|
if (llao != 0) {
|
2011-01-24 22:41:32 +01:00
|
|
|
memcpy(&nbr_entry->laddr, &llao[2], 8);
|
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-08-14 04:35:58 +02:00
|
|
|
if (nbr_adv_buf->rso & ICMPV6_NEIGHBOR_ADV_FLAG_SOLICITED) {
|
2013-08-14 17:04:17 +02:00
|
|
|
nbr_entry->state = NDP_NCE_STATUS_REACHABLE;
|
2011-01-24 22:41:32 +01:00
|
|
|
/* TODO: set rechablility */
|
2013-06-22 05:11:53 +02:00
|
|
|
}
|
|
|
|
else {
|
2013-06-24 22:37:35 +02:00
|
|
|
if (llao != 0 && new_ll) {
|
2013-08-14 17:04:17 +02:00
|
|
|
nbr_entry->state = NDP_NCE_STATUS_STALE;
|
2011-01-24 22:41:32 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
}
|
2011-01-24 22:41:32 +01:00
|
|
|
}
|
|
|
|
}
|
2010-10-12 21:42:03 +02:00
|
|
|
}
|
|
|
|
|
2010-10-17 16:05:46 +02:00
|
|
|
/* link-layer address option - RFC4861 section 4.6.1/ RFC4944 8. */
|
2013-08-14 21:48:36 +02:00
|
|
|
void icmpv6_ndp_set_sllao(icmpv6_ndp_opt_stllao_t *sllao, uint8_t type, uint8_t length)
|
2013-06-22 05:11:53 +02:00
|
|
|
{
|
2011-01-18 11:02:48 +01:00
|
|
|
sllao->type = type;
|
|
|
|
sllao->length = length;
|
2013-06-22 05:11:53 +02:00
|
|
|
|
|
|
|
uint8_t *llao = (uint8_t *)sllao;
|
|
|
|
|
|
|
|
/* get link layer address */
|
2013-08-08 13:39:00 +02:00
|
|
|
switch (length) {
|
2013-06-24 22:37:35 +02:00
|
|
|
case (1): {
|
2011-01-07 23:38:42 +01:00
|
|
|
memcpy(&llao[2], &(iface.saddr), 2);
|
|
|
|
memset(&llao[4], 0, 4);
|
|
|
|
break;
|
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
case (2): {
|
2013-06-22 05:11:53 +02:00
|
|
|
memcpy(&llao[2], &(iface.laddr), 8);
|
2011-01-07 23:38:42 +01:00
|
|
|
memset(&llao[10], 0, 6);
|
2011-01-18 11:02:48 +01:00
|
|
|
break;
|
2011-01-07 23:38:42 +01:00
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
|
|
|
|
default: {
|
2011-01-07 23:38:42 +01:00
|
|
|
printf("ERROR: llao not set\n");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2010-10-12 21:42:03 +02:00
|
|
|
}
|
|
|
|
|
2013-06-22 05:11:53 +02:00
|
|
|
uint16_t icmpv6_csum(uint8_t proto)
|
|
|
|
{
|
2013-08-13 06:41:05 +02:00
|
|
|
ipv6_buf = ipv6_get_buf();
|
2010-11-30 10:21:29 +01:00
|
|
|
uint16_t sum;
|
2013-08-02 01:19:20 +02:00
|
|
|
uint16_t len = NTOHS(ipv6_buf->length);
|
2010-11-30 10:21:29 +01:00
|
|
|
sum = len + proto;
|
2011-01-18 11:02:48 +01:00
|
|
|
|
2010-11-30 10:21:29 +01:00
|
|
|
sum = csum(sum, (uint8_t *)&ipv6_buf->srcaddr, 2 * sizeof(ipv6_addr_t));
|
2013-06-22 05:11:53 +02:00
|
|
|
sum = csum(sum, (uint8_t *)get_icmpv6_buf(0), len);
|
|
|
|
|
2010-11-30 10:21:29 +01:00
|
|
|
return (sum == 0) ? 0xffff : HTONS(sum);
|
|
|
|
}
|
|
|
|
|
2011-07-05 03:50:08 +02:00
|
|
|
|
2013-08-14 20:32:09 +02:00
|
|
|
void icmpv6_send_parameter_prob(ipv6_addr_t *src, ipv6_addr_t *dest,
|
2013-08-15 09:48:53 +02:00
|
|
|
uint8_t code, uint32_t pointer,
|
2013-08-14 20:32:09 +02:00
|
|
|
uint8_t *packet, uint8_t packet_len)
|
2013-06-22 05:11:53 +02:00
|
|
|
{
|
2013-08-09 03:13:37 +02:00
|
|
|
uint16_t packet_length = IPV6_HDR_LEN + ICMPV6_HDR_LEN + PARA_PROB_LEN;
|
2013-08-14 04:35:58 +02:00
|
|
|
icmpv6_parameter_prob_hdr_t *para_prob_buf;
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-08-13 06:41:05 +02:00
|
|
|
memcpy(&(ipv6_buf[packet_length]), packet, min(IPV6_MTU - packet_length, packet_len));
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-08-13 06:41:05 +02:00
|
|
|
ipv6_buf = ipv6_get_buf();
|
2011-07-05 03:50:08 +02:00
|
|
|
ipv6_buf->version_trafficclass = IPV6_VER;
|
|
|
|
ipv6_buf->trafficclass_flowlabel = 0;
|
|
|
|
ipv6_buf->flowlabel = 0;
|
2013-08-13 06:41:05 +02:00
|
|
|
ipv6_buf->nextheader = IPV6_PROTO_NUM_ICMPV6;
|
2011-07-05 03:50:08 +02:00
|
|
|
ipv6_buf->hoplimit = ND_HOPLIMIT;
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2011-07-05 03:50:08 +02:00
|
|
|
ipv6_ext_hdr_len = 0;
|
|
|
|
icmp_buf = get_icmpv6_buf(ipv6_ext_hdr_len);
|
2013-08-14 04:35:58 +02:00
|
|
|
icmp_buf->type = ICMPV6_TYPE_PARAMETER_PROB;
|
2011-07-05 03:50:08 +02:00
|
|
|
icmp_buf->code = code;
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2011-07-05 03:50:08 +02:00
|
|
|
memcpy(&(ipv6_buf->destaddr.uint8[0]), &(dest->uint8[0]), 16);
|
|
|
|
memcpy(&(ipv6_buf->srcaddr.uint8[0]), &(src->uint8[0]), 16);
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2011-07-05 03:50:08 +02:00
|
|
|
para_prob_buf = get_para_prob_buf(ipv6_ext_hdr_len);
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2011-07-05 03:50:08 +02:00
|
|
|
para_prob_buf->pointer = pointer;
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-08-13 06:41:05 +02:00
|
|
|
packet_length += min(IPV6_MTU - packet_length, packet_len);
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-08-02 01:19:20 +02:00
|
|
|
ipv6_buf->length = HTONS(packet_length - IPV6_HDR_LEN);
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2011-07-05 03:50:08 +02:00
|
|
|
icmp_buf->checksum = 0;
|
2013-08-13 06:41:05 +02:00
|
|
|
icmp_buf->checksum = ~icmpv6_csum(IPV6_PROTO_NUM_ICMPV6);
|
2011-07-05 03:50:08 +02:00
|
|
|
}
|
|
|
|
|
2011-01-18 11:02:48 +01:00
|
|
|
//------------------------------------------------------------------------------
|
2013-06-22 05:11:53 +02:00
|
|
|
/* neighbor cache functions */
|
2011-01-18 11:02:48 +01:00
|
|
|
|
2013-08-14 04:35:58 +02:00
|
|
|
ndp_neighbor_cache_t *ndp_neighbor_cache_search(ipv6_addr_t *ipaddr)
|
2013-06-22 05:11:53 +02:00
|
|
|
{
|
2011-01-18 11:02:48 +01:00
|
|
|
int i;
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
for (i = 0; i < NBR_CACHE_SIZE; i++) {
|
|
|
|
if (memcmp(&(nbr_cache[i].addr.uint8[0]), &(ipaddr->uint8[0]), 16) == 0) {
|
2011-01-18 11:02:48 +01:00
|
|
|
return &nbr_cache[i];
|
2013-06-22 05:11:53 +02:00
|
|
|
}
|
2011-01-18 11:02:48 +01:00
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2011-01-18 11:02:48 +01:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2013-06-22 05:11:53 +02:00
|
|
|
uint8_t nbr_cache_add(ipv6_addr_t *ipaddr, ieee_802154_long_t *laddr,
|
2013-08-14 17:04:17 +02:00
|
|
|
uint8_t isrouter, ndp_nce_state_t state,
|
|
|
|
ndp_nce_type_t type, uint16_t ltime,
|
|
|
|
ieee_802154_short_t *saddr)
|
2013-06-22 05:11:53 +02:00
|
|
|
{
|
2013-06-24 22:37:35 +02:00
|
|
|
if (nbr_count == NBR_CACHE_SIZE) {
|
2011-01-18 11:02:48 +01:00
|
|
|
printf("ERROR: neighbor cache full\n");
|
2013-08-14 04:35:58 +02:00
|
|
|
return NDP_OPT_ARO_STATE_NBR_CACHE_FULL;
|
2011-01-18 11:02:48 +01:00
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2011-06-22 11:49:29 +02:00
|
|
|
memcpy(&(nbr_cache[nbr_count].addr), ipaddr, 16);
|
|
|
|
memcpy(&(nbr_cache[nbr_count].laddr), laddr, 8);
|
|
|
|
nbr_cache[nbr_count].isrouter = isrouter;
|
|
|
|
nbr_cache[nbr_count].state = state;
|
|
|
|
nbr_cache[nbr_count].type = type;
|
2013-06-22 05:11:53 +02:00
|
|
|
|
|
|
|
//vtimer_set_wakeup(&(nbr_cache[nbr_count].ltime), t,
|
|
|
|
/* nd_nbr_cache_rem_pid); */
|
2011-06-22 11:49:29 +02:00
|
|
|
|
|
|
|
nbr_count++;
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-08-14 04:35:58 +02:00
|
|
|
return NDP_OPT_ARO_STATE_SUCCESS;
|
2011-01-18 11:02:48 +01:00
|
|
|
}
|
|
|
|
|
2013-06-22 05:11:53 +02:00
|
|
|
void nbr_cache_auto_rem(void)
|
|
|
|
{
|
2011-01-24 22:41:32 +01:00
|
|
|
int i;
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
for (i = 0; i < NBR_CACHE_SIZE; i++) {
|
|
|
|
if (get_remaining_time(&(nbr_cache[i].ltime)) == 0 &&
|
2013-08-14 17:04:17 +02:00
|
|
|
nbr_cache[i].type == NDP_NCE_TYPE_TENTATIVE) {
|
2013-06-22 05:11:53 +02:00
|
|
|
memmove(&(nbr_cache[i]), &(nbr_cache[nbr_count]),
|
2013-08-14 04:35:58 +02:00
|
|
|
sizeof(ndp_neighbor_cache_t));
|
|
|
|
memset(&(nbr_cache[nbr_count]), 0, sizeof(ndp_neighbor_cache_t));
|
2011-06-24 01:48:41 +02:00
|
|
|
nbr_count--;
|
2011-01-24 22:41:32 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-22 05:11:53 +02:00
|
|
|
void nbr_cache_rem(ipv6_addr_t *addr)
|
|
|
|
{
|
2011-01-24 22:41:32 +01:00
|
|
|
int i;
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
for (i = 0; i < NBR_CACHE_SIZE; i++) {
|
|
|
|
if (memcmp(&(nbr_cache[i].addr.uint8[0]), &(addr->uint8[0]), 16) == 0) {
|
2013-06-22 05:11:53 +02:00
|
|
|
memmove(&(nbr_cache[i]), &(nbr_cache[nbr_count]),
|
2013-08-14 04:35:58 +02:00
|
|
|
sizeof(ndp_neighbor_cache_t));
|
|
|
|
memset(&(nbr_cache[nbr_count]), 0, sizeof(ndp_neighbor_cache_t));
|
2013-06-22 05:11:53 +02:00
|
|
|
nbr_count--;
|
2011-01-24 22:41:32 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-18 23:33:27 +02:00
|
|
|
//------------------------------------------------------------------------------
|
2013-06-22 05:11:53 +02:00
|
|
|
/* authoritive border router list functions */
|
|
|
|
/**
|
2011-06-18 23:33:27 +02:00
|
|
|
* @brief Finds the most current (by version number) authoritive border
|
|
|
|
* router information.
|
|
|
|
* @pre assumes that abro versions are centrally managed
|
|
|
|
* @return The most current authoritive border router information, NULL
|
|
|
|
* if no such information is given.
|
|
|
|
*/
|
2013-08-14 04:35:58 +02:00
|
|
|
ndp_a6br_cache_t *ndp_a6br_cache_get_most_current(void)
|
2013-06-22 05:11:53 +02:00
|
|
|
{
|
2013-08-14 04:35:58 +02:00
|
|
|
ndp_a6br_cache_t *abr = NULL;
|
2011-06-18 23:33:27 +02:00
|
|
|
int i;
|
|
|
|
int version = abr_cache[0].version;
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
for (i = 0; i < abr_count; i++) {
|
|
|
|
if (serial_comp16(version, abr_cache[i].version) == GREATER) {
|
2011-06-18 23:33:27 +02:00
|
|
|
abr = &(abr_cache[i]);
|
|
|
|
version = abr_cache[i].version;
|
|
|
|
}
|
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2011-06-18 23:33:27 +02:00
|
|
|
return abr;
|
|
|
|
}
|
|
|
|
|
2013-08-14 04:35:58 +02:00
|
|
|
ndp_a6br_cache_t *ndp_a6br_cache_get_oldest(void)
|
2013-06-22 05:11:53 +02:00
|
|
|
{
|
2013-08-14 04:35:58 +02:00
|
|
|
ndp_a6br_cache_t *abr = NULL;
|
2011-06-18 23:33:27 +02:00
|
|
|
int i;
|
|
|
|
int version = abr_cache[0].version;
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
for (i = 0; i < abr_count; i++) {
|
|
|
|
if (serial_comp16(version, abr_cache[i].version) == LESS) {
|
2011-06-18 23:33:27 +02:00
|
|
|
abr = &(abr_cache[i]);
|
|
|
|
version = abr_cache[i].version;
|
|
|
|
}
|
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2011-06-18 23:33:27 +02:00
|
|
|
return abr;
|
|
|
|
}
|
|
|
|
|
2013-08-14 04:35:58 +02:00
|
|
|
ndp_a6br_cache_t *abr_get_version(uint16_t version, ipv6_addr_t *abr_addr)
|
2013-06-22 05:11:53 +02:00
|
|
|
{
|
2011-07-26 13:35:58 +02:00
|
|
|
int i = 0;
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
for (i = 0; i < ABR_CACHE_SIZE; i++) {
|
|
|
|
if (abr_cache[i].version == version &&
|
2013-08-08 13:39:00 +02:00
|
|
|
memcmp(&(abr_cache[i].abr_addr.uint8[0]),
|
|
|
|
&(abr_addr->uint8[0]), 16
|
|
|
|
) == 0) {
|
2011-07-26 13:35:58 +02:00
|
|
|
return &(abr_cache[i]);
|
|
|
|
}
|
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2011-07-26 13:35:58 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2013-08-14 04:35:58 +02:00
|
|
|
lowpan_context_t *abr_get_context(ndp_a6br_cache_t *abr, uint8_t cid)
|
2013-06-22 05:11:53 +02:00
|
|
|
{
|
2013-06-24 22:37:35 +02:00
|
|
|
if (abr->cids[cid] != cid) {
|
2011-07-26 13:35:58 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2011-07-26 13:35:58 +02:00
|
|
|
return lowpan_context_num_lookup(abr->cids[cid]);
|
|
|
|
}
|
|
|
|
|
2013-08-14 04:35:58 +02:00
|
|
|
ndp_a6br_cache_t *abr_add_context(uint16_t version, ipv6_addr_t *abr_addr,
|
2013-08-14 17:04:17 +02:00
|
|
|
uint8_t cid)
|
2013-06-22 05:11:53 +02:00
|
|
|
{
|
2013-08-14 04:35:58 +02:00
|
|
|
ndp_a6br_cache_t *abr = abr_get_version(version, abr_addr);
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
if (abr == NULL) {
|
|
|
|
if (abr_count == ABR_CACHE_SIZE) {
|
2013-08-14 04:35:58 +02:00
|
|
|
abr = ndp_a6br_cache_get_oldest();
|
2013-06-22 05:11:53 +02:00
|
|
|
}
|
|
|
|
else {
|
2011-07-26 13:35:58 +02:00
|
|
|
abr = &(abr_cache[abr_count++]);
|
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2011-07-26 13:35:58 +02:00
|
|
|
abr->version = version;
|
2013-06-22 05:11:53 +02:00
|
|
|
memcpy(&(abr->abr_addr), abr_addr, sizeof(ipv6_addr_t));
|
2013-08-14 04:35:58 +02:00
|
|
|
memset(abr->cids, 0xFF, NDP_6LOWPAN_CONTEXT_MAX);
|
2011-06-18 23:33:27 +02:00
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2011-07-26 13:35:58 +02:00
|
|
|
abr->cids[cid] = cid;
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2011-06-18 23:33:27 +02:00
|
|
|
return abr;
|
|
|
|
}
|
|
|
|
|
2013-06-22 05:11:53 +02:00
|
|
|
void abr_remove_context(uint8_t cid)
|
|
|
|
{
|
2011-07-26 13:35:58 +02:00
|
|
|
int i;
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
for (i = 0; i < abr_count; i++) {
|
2011-07-26 13:35:58 +02:00
|
|
|
abr_cache[i].cids[cid] = 0xFF;
|
2011-06-24 01:48:41 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-01-18 11:02:48 +01:00
|
|
|
//------------------------------------------------------------------------------
|
2013-06-22 05:11:53 +02:00
|
|
|
/* default router list functions */
|
2011-01-18 11:02:48 +01:00
|
|
|
|
2013-08-14 04:35:58 +02:00
|
|
|
ndp_default_router_list_t *ndp_default_router_list_search(ipv6_addr_t *ipaddr)
|
2013-06-22 05:11:53 +02:00
|
|
|
{
|
2011-01-18 11:02:48 +01:00
|
|
|
int i;
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
for (i = 0; i < DEF_RTR_LST_SIZE; i++) {
|
|
|
|
if (memcmp(&def_rtr_lst[i].addr.uint8[0],
|
2013-08-08 13:39:00 +02:00
|
|
|
&(ipaddr->uint8[0]), 16) == 0) {
|
2011-01-18 11:02:48 +01:00
|
|
|
return &def_rtr_lst[i];
|
|
|
|
}
|
|
|
|
}
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2011-01-18 11:02:48 +01:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2013-06-22 05:11:53 +02:00
|
|
|
void def_rtr_lst_add(ipv6_addr_t *ipaddr, uint32_t rtr_ltime)
|
|
|
|
{
|
2013-06-24 22:37:35 +02:00
|
|
|
if (def_rtr_count == DEF_RTR_LST_SIZE) {
|
2011-01-18 11:02:48 +01:00
|
|
|
DEBUG("ERROR: default router list full\n");
|
2013-06-22 05:11:53 +02:00
|
|
|
}
|
|
|
|
else {
|
2011-01-18 11:02:48 +01:00
|
|
|
memcpy(&(def_rtr_lst[def_rtr_count].addr), ipaddr, 16);
|
2012-01-11 17:02:43 +01:00
|
|
|
timex_t rltime = {rtr_ltime, 0};
|
2013-06-13 10:22:55 +02:00
|
|
|
timex_t now;
|
|
|
|
vtimer_now(&now);
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2012-01-11 17:02:43 +01:00
|
|
|
def_rtr_lst[def_rtr_count].inval_time = timex_add(now, rltime);
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2011-01-18 11:02:48 +01:00
|
|
|
def_rtr_count++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-14 04:35:58 +02:00
|
|
|
void def_rtr_lst_rem(ndp_default_router_list_t *entry)
|
2013-06-22 05:11:53 +02:00
|
|
|
{
|
2011-01-18 11:02:48 +01:00
|
|
|
int i;
|
2013-06-22 05:11:53 +02:00
|
|
|
|
2013-06-24 22:37:35 +02:00
|
|
|
for (i = 0; i < DEF_RTR_LST_SIZE; i++) {
|
|
|
|
if (&def_rtr_lst[i] == entry) {
|
2011-01-18 11:02:48 +01:00
|
|
|
/* search the to deleted item, then memmove the last item to its
|
|
|
|
* position, and decrement array count */
|
2013-08-14 04:35:58 +02:00
|
|
|
memmove(entry, &def_rtr_lst[def_rtr_count], sizeof(ndp_default_router_list_t));
|
|
|
|
memset(&def_rtr_lst[def_rtr_count], 0, sizeof(ndp_default_router_list_t));
|
2011-01-18 11:02:48 +01:00
|
|
|
def_rtr_count--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
2013-06-22 05:11:53 +02:00
|
|
|
/* prefix list functions */
|
2011-01-18 11:02:48 +01:00
|
|
|
|
2011-06-24 14:39:24 +02:00
|
|
|
int8_t plist_add(ipv6_addr_t *addr, uint8_t size, uint32_t val_ltime,
|
2013-06-22 05:11:53 +02:00
|
|
|
uint32_t pref_ltime, uint8_t adv_opt, uint8_t l_a_reserved1)
|
|
|
|
{
|
2013-06-24 22:37:35 +02:00
|
|
|
if (prefix_count == OPT_PI_LIST_LEN) {
|
2011-06-24 14:39:24 +02:00
|
|
|
return SIXLOWERROR_ARRAYFULL;
|
2013-06-22 05:11:53 +02:00
|
|
|
}
|
|
|
|
else {
|
2011-01-18 11:02:48 +01:00
|
|
|
plist[prefix_count].inuse = 1;
|
|
|
|
plist[prefix_count].length = size;
|
|
|
|
plist[prefix_count].adv = adv_opt;
|
|
|
|
plist[prefix_count].l_a_reserved1 = l_a_reserved1;
|
2011-01-24 22:41:32 +01:00
|
|
|
plist[prefix_count].val_ltime = HTONL(val_ltime);
|
|
|
|
plist[prefix_count].pref_ltime = HTONL(pref_ltime);
|
2011-01-18 11:02:48 +01:00
|
|
|
memcpy(&(plist[prefix_count].addr.uint8[0]), &(addr->uint8[0]), 16);
|
|
|
|
|
2013-09-23 18:01:23 +02:00
|
|
|
return SIXLOWERROR_SUCCESS;
|
2011-01-18 11:02:48 +01:00
|
|
|
}
|
|
|
|
}
|