Merge pull request #585 from g-oikonomou/generic-icmp6-in-hooks

Generic ICMPv6 input hooks
This commit is contained in:
Nicolas Tsiftes 2014-04-14 16:12:10 +02:00
commit ce2ed95b93
10 changed files with 245 additions and 163 deletions

View File

@ -48,6 +48,7 @@
#include "contiki.h"
#include "contiki-lib.h"
#include "contiki-net.h"
#include "net/ipv6/uip-icmp6.h"
#include "net/ipv6/multicast/uip-mcast6.h"
#include "net/ipv6/multicast/roll-tm.h"
#include "dev/watchdog.h"
@ -473,11 +474,16 @@ extern uint16_t uip_slen;
/*---------------------------------------------------------------------------*/
/* Local function prototypes */
/*---------------------------------------------------------------------------*/
static void icmp_output();
static void window_update_bounds();
static void icmp_input(void);
static void icmp_output(void);
static void window_update_bounds(void);
static void reset_trickle_timer(uint8_t);
static void handle_timer(void *);
/*---------------------------------------------------------------------------*/
/* ROLL TM ICMPv6 handler declaration */
UIP_ICMP6_HANDLER(roll_tm_icmp_handler, ICMP6_ROLL_TM,
UIP_ICMP6_HANDLER_CODE_ANY, icmp_input);
/*---------------------------------------------------------------------------*/
/* Return a random number in [I/2, I), for a timer with Imin when the timer's
* current number of doublings is d */
static clock_time_t
@ -1090,8 +1096,9 @@ accept(uint8_t in)
return UIP_MCAST6_ACCEPT;
}
/*---------------------------------------------------------------------------*/
void
roll_tm_icmp_input()
/* ROLL TM ICMPv6 Input Handler */
static void
icmp_input()
{
uint8_t inconsistency;
uint16_t *seq_ptr;
@ -1417,6 +1424,9 @@ init()
ROLL_TM_STATS_INIT();
UIP_MCAST6_STATS_INIT(&stats);
/* Register the ICMPv6 input handler */
uip_icmp6_register_input_handler(&roll_tm_icmp_handler);
for(iterswptr = &windows[ROLL_TM_WINS - 1]; iterswptr >= windows;
iterswptr--) {
iterswptr->lower_bound = -1;

View File

@ -213,14 +213,6 @@
#define ROLL_TM_SET_M_BIT 1
#endif
/*---------------------------------------------------------------------------*/
/* Prototypes of additional Trickle Multicast functions */
/*---------------------------------------------------------------------------*/
/**
* \brief Called by the uIPv6 engine when it receives a Trickle Multicast
* ICMPv6 datagram
*/
void roll_tm_icmp_input();
/*---------------------------------------------------------------------------*/
/* Stats datatype */
/*---------------------------------------------------------------------------*/
struct roll_tm_stats {

View File

@ -74,10 +74,53 @@
static uip_ipaddr_t tmp_ipaddr;
LIST(echo_reply_callback_list);
/*---------------------------------------------------------------------------*/
/* List of input handlers */
LIST(input_handler_list);
/*---------------------------------------------------------------------------*/
static uip_icmp6_input_handler_t *
input_handler_lookup(uint8_t type, uint8_t icode)
{
uip_icmp6_input_handler_t *handler = NULL;
for(handler = list_head(input_handler_list);
handler != NULL;
handler = list_item_next(handler)) {
if(handler->type == type &&
(handler->icode == icode ||
handler->icode == UIP_ICMP6_HANDLER_CODE_ANY)) {
return handler;
}
}
return NULL;
}
/*---------------------------------------------------------------------------*/
uint8_t
uip_icmp6_input(uint8_t type, uint8_t icode)
{
uip_icmp6_input_handler_t *handler = input_handler_lookup(type, icode);
if(handler == NULL) {
return UIP_ICMP6_INPUT_ERROR;
}
if(handler->handler == NULL) {
return UIP_ICMP6_INPUT_ERROR;
}
handler->handler();
return UIP_ICMP6_INPUT_SUCCESS;
}
/*---------------------------------------------------------------------------*/
void
uip_icmp6_echo_request_input(void)
uip_icmp6_register_input_handler(uip_icmp6_input_handler_t *handler)
{
list_add(input_handler_list, handler);
}
/*---------------------------------------------------------------------------*/
static void
echo_request_input(void)
{
#if UIP_CONF_IPV6_RPL
uint8_t temp_ext_len;
@ -275,8 +318,8 @@ uip_icmp6_send(const uip_ipaddr_t *dest, int type, int code, int payload_len)
tcpip_ipv6_output();
}
/*---------------------------------------------------------------------------*/
void
uip_icmp6_echo_reply_input(void)
static void
echo_reply_input(void)
{
int ttl;
uip_ipaddr_t sender;
@ -343,6 +386,8 @@ uip_icmp6_echo_reply_input(void)
}
}
}
uip_len = 0;
return;
}
/*---------------------------------------------------------------------------*/
@ -362,5 +407,18 @@ uip_icmp6_echo_reply_callback_rm(struct uip_icmp6_echo_reply_notification *n)
list_remove(echo_reply_callback_list, n);
}
/*---------------------------------------------------------------------------*/
UIP_ICMP6_HANDLER(echo_request_handler, ICMP6_ECHO_REQUEST,
UIP_ICMP6_HANDLER_CODE_ANY, echo_request_input);
UIP_ICMP6_HANDLER(echo_reply_handler, ICMP6_ECHO_REPLY,
UIP_ICMP6_HANDLER_CODE_ANY, echo_reply_input);
/*---------------------------------------------------------------------------*/
void
uip_icmp6_init()
{
/* Register Echo Request and Reply handlers */
uip_icmp6_register_input_handler(&echo_request_handler);
uip_icmp6_register_input_handler(&echo_reply_handler);
}
/*---------------------------------------------------------------------------*/
/** @} */
#endif /* UIP_CONF_IPV6 */

View File

@ -109,24 +109,6 @@ typedef struct uip_icmp6_error{
/** \name ICMPv6 RFC4443 Message processing and sending */
/** @{ */
/** \
* brief Process an echo request
*
* Perform a few checks, then send an Echo reply. The reply is
* built here.
*/
void
uip_icmp6_echo_request_input(void);
/** \
* brief Process an echo reply
*
* Perform a few checks, then call applications to inform that an echo
* reply has been received.
*/
void
uip_icmp6_echo_reply_input(void);
/**
* \brief Send an icmpv6 error message
* \param type type of the error message
@ -192,8 +174,66 @@ uip_icmp6_echo_reply_callback_add(struct uip_icmp6_echo_reply_notification *n,
void
uip_icmp6_echo_reply_callback_rm(struct uip_icmp6_echo_reply_notification *n);
/* Generic ICMPv6 input handers */
typedef struct uip_icmp6_input_handler {
struct uip_icmp6_input_handler *next;
uint8_t type;
uint8_t icode;
void (*handler)(void);
} uip_icmp6_input_handler_t;
#define UIP_ICMP6_INPUT_SUCCESS 0
#define UIP_ICMP6_INPUT_ERROR 1
#define UIP_ICMP6_HANDLER_CODE_ANY 0xFF /* Handle all codes for this type */
/*
* Initialise a variable of type uip_icmp6_input_handler, to be used later as
* the argument to uip_icmp6_register_input_handler
*
* The function pointer stored in this variable will get called and will be
* expected to handle incoming ICMPv6 datagrams of the specified type/code
*
* If code has a value of UIP_ICMP6_HANDLER_CODE_ANY, the same function
* will handle all codes for this type. In other words, the ICMPv6
* message's code is "don't care"
*/
#define UIP_ICMP6_HANDLER(name, type, code, func) \
static uip_icmp6_input_handler_t name = { NULL, type, code, func }
/**
* \brief Handle an incoming ICMPv6 message
* \param type The ICMPv6 message type
* \param icode The ICMPv6 message code
* \return Success: UIP_ICMP6_INPUT_SUCCESS, Error: UIP_ICMP6_INPUT_ERROR
*
* Generic handler for unknown ICMPv6 types. It will lookup for a registered
* function capable of handing this message type. The function must have first
* been registered with uip_icmp6_register_input_handler. The function is in
* charge of setting uip_len to 0, otherwise the uIPv6 core will attempt to
* send whatever remains in the UIP_IP_BUF.
*
* A return value of UIP_ICMP6_INPUT_ERROR means that a handler could not be
* invoked. This is most likely because the ICMPv6 type does not have a valid
* handler associated with it.
* UIP_ICMP6_INPUT_SUCCESS signifies that a handler was found for this ICMPv6
* type and that it was invoked. It does NOT provide any indication whatsoever
* regarding whether the handler itself succeeded.
*/
uint8_t uip_icmp6_input(uint8_t type, uint8_t icode);
/**
* \brief Register a handler which can handle a specific ICMPv6 message type
* \param handler A pointer to the handler
*/
void uip_icmp6_register_input_handler(uip_icmp6_input_handler_t *handler);
/**
* \brief Initialise the uIP ICMPv6 core
*/
void uip_icmp6_init(void);
/** @} */

View File

@ -126,8 +126,6 @@ static uip_ds6_prefix_t *prefix; /** Pointer to a prefix list entry */
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 */
/*------------------------------------------------------------------*/
/* create a llao */
static void
@ -143,8 +141,8 @@ create_llao(uint8_t *llao, uint8_t type) {
/*------------------------------------------------------------------*/
void
uip_nd6_ns_input(void)
static void
ns_input(void)
{
uint8_t flags;
PRINTF("Received NS from ");
@ -388,12 +386,26 @@ uip_nd6_ns_output(uip_ipaddr_t * src, uip_ipaddr_t * dest, uip_ipaddr_t * tgt)
PRINTF("\n");
return;
}
/*------------------------------------------------------------------*/
void
uip_nd6_na_input(void)
/**
* 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;
@ -548,8 +560,8 @@ discard:
#if UIP_CONF_ROUTER
#if UIP_ND6_SEND_RA
/*---------------------------------------------------------------------------*/
void
uip_nd6_rs_input(void)
static void
rs_input(void)
{
PRINTF("Received RS from");
@ -761,11 +773,18 @@ uip_nd6_rs_output(void)
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
uip_nd6_ra_input(void)
ra_input(void)
{
PRINTF("Received RA from");
PRINT6ADDR(&UIP_IP_BUF->srcipaddr);
@ -969,6 +988,52 @@ discard:
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 */

View File

@ -337,34 +337,8 @@ uip_nd6_ns_input(void);
void
uip_nd6_ns_output(uip_ipaddr_t *src, uip_ipaddr_t *dest, uip_ipaddr_t *tgt);
/**
* \brief Process a Neighbor Advertisement
*
* 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
*
*/
void
uip_nd6_na_input(void);
#if UIP_CONF_ROUTER
#if UIP_ND6_SEND_RA
/**
* \brief Process a Router Solicitation
*
*/
void uip_nd6_rs_input(void);
/**
* \brief send a Router Advertisement
*
@ -388,17 +362,9 @@ void uip_nd6_ra_output(uip_ipaddr_t *dest);
void uip_nd6_rs_output(void);
/**
*
* \brief 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
* \brief Initialise the uIP ND core
*/
void
uip_nd6_ra_input(void);
void uip_nd6_init(void);
/** @} */

View File

@ -411,6 +411,8 @@ uip_init(void)
{
uip_ds6_init();
uip_icmp6_init();
uip_nd6_init();
#if UIP_TCP
for(c = 0; c < UIP_LISTENPORTS; ++c) {
@ -1420,67 +1422,17 @@ uip_process(uint8_t flag)
UIP_ICMP6_APPCALL(UIP_ICMP_BUF->type);
#endif /*UIP_CONF_ICMP6*/
switch(UIP_ICMP_BUF->type) {
case ICMP6_NS:
#if UIP_ND6_SEND_NA
uip_nd6_ns_input();
#else /* UIP_ND6_SEND_NA */
UIP_STAT(++uip_stat.icmp.drop);
uip_len = 0;
#endif /* UIP_ND6_SEND_NA */
break;
case ICMP6_NA:
#if UIP_ND6_SEND_NA
uip_nd6_na_input();
#else /* UIP_ND6_SEND_NA */
UIP_STAT(++uip_stat.icmp.drop);
uip_len = 0;
#endif /* UIP_ND6_SEND_NA */
break;
case ICMP6_RS:
#if UIP_CONF_ROUTER && UIP_ND6_SEND_RA
uip_nd6_rs_input();
#else /* UIP_CONF_ROUTER && UIP_ND6_SEND_RA */
/*
* Search generic input handlers.
* The handler is in charge of setting uip_len to 0
*/
if(uip_icmp6_input(UIP_ICMP_BUF->type,
UIP_ICMP_BUF->icode) == UIP_ICMP6_INPUT_ERROR) {
PRINTF("Unknown ICMPv6 message type/code %d\n", UIP_ICMP_BUF->type);
UIP_STAT(++uip_stat.icmp.drop);
UIP_STAT(++uip_stat.icmp.typeerr);
UIP_LOG("icmp6: unknown ICMPv6 message.");
uip_len = 0;
#endif /* UIP_CONF_ROUTER && UIP_ND6_SEND_RA */
break;
case ICMP6_RA:
#if UIP_CONF_ROUTER
UIP_STAT(++uip_stat.icmp.drop);
uip_len = 0;
#else /* UIP_CONF_ROUTER */
uip_nd6_ra_input();
#endif /* UIP_CONF_ROUTER */
break;
#if UIP_CONF_IPV6_RPL
case ICMP6_RPL:
uip_rpl_input();
break;
#endif /* UIP_CONF_IPV6_RPL */
case ICMP6_ECHO_REQUEST:
uip_icmp6_echo_request_input();
break;
case ICMP6_ECHO_REPLY:
/** Call echo reply input function. */
uip_icmp6_echo_reply_input();
PRINTF("Received an icmp6 echo reply\n");
UIP_STAT(++uip_stat.icmp.recv);
uip_len = 0;
break;
#if UIP_CONF_IPV6_ROLL_TM
case ICMP6_ROLL_TM:
roll_tm_icmp_input();
uip_len = 0;
break;
#endif
default:
PRINTF("Unknown icmp6 message type %d\n", UIP_ICMP_BUF->type);
UIP_STAT(++uip_stat.icmp.drop);
UIP_STAT(++uip_stat.icmp.typeerr);
UIP_LOG("icmp6: unknown ICMP message.");
uip_len = 0;
break;
}
if(uip_len > 0) {

View File

@ -92,6 +92,12 @@ extern rpl_of_t RPL_OF;
static uip_mcast6_route_t *mcast_group;
#endif
/*---------------------------------------------------------------------------*/
/* Initialise RPL ICMPv6 message handlers */
UIP_ICMP6_HANDLER(dis_handler, ICMP6_RPL, RPL_CODE_DIS, dis_input);
UIP_ICMP6_HANDLER(dio_handler, ICMP6_RPL, RPL_CODE_DIO, dio_input);
UIP_ICMP6_HANDLER(dao_handler, ICMP6_RPL, RPL_CODE_DAO, dao_input);
UIP_ICMP6_HANDLER(dao_ack_handler, ICMP6_RPL, RPL_CODE_DAO_ACK, dao_ack_input);
/*---------------------------------------------------------------------------*/
static int
get_global_addr(uip_ipaddr_t *addr)
{
@ -168,6 +174,7 @@ dis_input(void)
}
}
}
uip_len = 0;
}
/*---------------------------------------------------------------------------*/
void
@ -409,6 +416,8 @@ dio_input(void)
#endif
rpl_process_dio(&from, &dio);
uip_len = 0;
}
/*---------------------------------------------------------------------------*/
void
@ -786,6 +795,7 @@ fwd_dao:
dao_ack_output(instance, &dao_sender_addr, sequence);
}
}
uip_len = 0;
}
/*---------------------------------------------------------------------------*/
void
@ -915,6 +925,7 @@ dao_ack_input(void)
PRINT6ADDR(&UIP_IP_BUF->srcipaddr);
PRINTF("\n");
#endif /* DEBUG */
uip_len = 0;
}
/*---------------------------------------------------------------------------*/
void
@ -937,27 +948,12 @@ dao_ack_output(rpl_instance_t *instance, uip_ipaddr_t *dest, uint8_t sequence)
}
/*---------------------------------------------------------------------------*/
void
uip_rpl_input(void)
rpl_icmp6_register_handlers()
{
PRINTF("Received an RPL control message\n");
switch(UIP_ICMP_BUF->icode) {
case RPL_CODE_DIO:
dio_input();
break;
case RPL_CODE_DIS:
dis_input();
break;
case RPL_CODE_DAO:
dao_input();
break;
case RPL_CODE_DAO_ACK:
dao_ack_input();
break;
default:
PRINTF("RPL: received an unknown ICMP6 code (%u)\n", UIP_ICMP_BUF->icode);
break;
}
uip_len = 0;
uip_icmp6_register_input_handler(&dis_handler);
uip_icmp6_register_input_handler(&dio_handler);
uip_icmp6_register_input_handler(&dao_handler);
uip_icmp6_register_input_handler(&dao_ack_handler);
}
/*---------------------------------------------------------------------------*/
#endif /* UIP_CONF_IPV6 */

View File

@ -289,6 +289,7 @@ void dio_output(rpl_instance_t *, uip_ipaddr_t *uc_addr);
void dao_output(rpl_parent_t *, uint8_t lifetime);
void dao_output_target(rpl_parent_t *, uip_ipaddr_t *, uint8_t lifetime);
void dao_ack_output(rpl_instance_t *, uip_ipaddr_t *, uint8_t);
void rpl_icmp6_register_handlers(void);
/* RPL logic functions. */
void rpl_join_dag(uip_ipaddr_t *from, rpl_dio_t *dio);

View File

@ -43,6 +43,7 @@
#include "net/ip/uip.h"
#include "net/ip/tcpip.h"
#include "net/ipv6/uip-ds6.h"
#include "net/ipv6/uip-icmp6.h"
#include "net/rpl/rpl-private.h"
#include "net/ipv6/multicast/uip-mcast6.h"
@ -300,6 +301,7 @@ rpl_init(void)
rpl_dag_init();
rpl_reset_periodic_timer();
rpl_icmp6_register_handlers();
/* add rpl multicast address */
uip_create_linklocal_rplnodes_mcast(&rplmaddr);