diff --git a/core/net/ip/uip-udp-packet.c b/core/net/ip/uip-udp-packet.c index 5b03be54b..b327b652d 100644 --- a/core/net/ip/uip-udp-packet.c +++ b/core/net/ip/uip-udp-packet.c @@ -42,6 +42,7 @@ extern uint16_t uip_slen; #include "net/ip/uip-udp-packet.h" +#include "net/ipv6/multicast/uip-mcast6.h" #include @@ -57,6 +58,14 @@ uip_udp_packet_send(struct uip_udp_conn *c, const void *data, int len) len > UIP_BUFSIZE - UIP_LLH_LEN - UIP_IPUDPH_LEN? UIP_BUFSIZE - UIP_LLH_LEN - UIP_IPUDPH_LEN: len); uip_process(UIP_UDP_SEND_CONN); + +#if UIP_CONF_IPV6_MULTICAST + /* Let the multicast engine process the datagram before we send it */ + if(uip_is_addr_mcast_routable(&uip_udp_conn->ripaddr)) { + UIP_MCAST6.out(); + } +#endif /* UIP_IPV6_MULTICAST */ + #if UIP_CONF_IPV6 tcpip_ipv6_output(); #else diff --git a/core/net/ip/uip.h b/core/net/ip/uip.h index 076734396..c6a50d699 100644 --- a/core/net/ip/uip.h +++ b/core/net/ip/uip.h @@ -2093,6 +2093,35 @@ CCIF extern uip_lladdr_t uip_lladdr; #define uip_is_addr_mcast(a) \ (((a)->u8[0]) == 0xFF) +/** + * \brief is address a global multicast address (FFxE::/16), + * a is of type uip_ip6addr_t* + * */ +#define uip_is_addr_mcast_global(a) \ + ((((a)->u8[0]) == 0xFF) && \ + (((a)->u8[1] & 0x0F) == 0x0E)) + +/** + * \brief is address a non-routable multicast address. + * Scopes 1 (interface-local) and 2 (link-local) are non-routable + * See RFC4291 and draft-ietf-6man-multicast-scopes + * a is of type uip_ip6addr_t* + * */ +#define uip_is_addr_mcast_non_routable(a) \ + ((((a)->u8[0]) == 0xFF) && \ + (((a)->u8[1] & 0x0F) <= 0x02)) + +/** + * \brief is address a routable multicast address. + * Scope 3 (Realm-Local) or higher are routable + * Realm-Local scope is defined in draft-ietf-6man-multicast-scopes + * See RFC4291 and draft-ietf-6man-multicast-scopes + * a is of type uip_ip6addr_t* + * */ +#define uip_is_addr_mcast_routable(a) \ + ((((a)->u8[0]) == 0xFF) && \ + (((a)->u8[1] & 0x0F) > 0x02)) + /** * \brief is group-id of multicast address a * the all nodes group-id diff --git a/core/net/ipv6/multicast/README.md b/core/net/ipv6/multicast/README.md new file mode 100644 index 000000000..2108b92f2 --- /dev/null +++ b/core/net/ipv6/multicast/README.md @@ -0,0 +1,114 @@ +README file for Contiki's IPv6 multicast core + +Author: George Oikonomou + +What does it do +=============== +These files, alongside some core modifications, add support for IPv6 multicast +to contiki's uIPv6 engine. + +Currently, two modes are supported: + +* 'Stateless Multicast RPL Forwarding' (SMRF) + RPL in MOP 3 handles group management as per the RPL docs, + SMRF is a lightweight engine which handles datagram forwarding. + SMRF is documented here: + http://dx.doi.org/10.1007/s11277-013-1250-5 + and here: + http://dx.doi.org/10.1109/PerComW.2012.6197494 +* 'Multicast Forwarding with Trickle' according to the algorithm described + in the internet draft: + http://tools.ietf.org/html/draft-ietf-roll-trickle-mcast + The version of this draft that's currently implementated is documented + in `roll-tm.h` + +More engines can (and hopefully will) be added in the future. The first +addition is most likely going to be an updated implementation of MPL + +The Big Gotcha +============== +Currently we only support traffic originating and destined inside a single 6LoWPAN +To be able to send multicast traffic from the internet to 6LoWPAN nodes or the other +way round, we need border routers or other gateway devices to be able to achieve +the following: + +* Add/Remove Trickle Multicast, RPL or other HBHO headers as necessary for datagrams + entering / exiting the 6LoWPAN +* Advertise multicast group membership to the internet (e.g. with MLD) + +These are currently not implemented and are in the ToDo list. Contributions welcome. + +Where to Start +============== +The best place in `examples/ipv6/multicast` + +There is a cooja example demonstrating basic functionality + +How to Use +========== +Look in `core/net/ipv6/multicast/uip-mcast6-engines.h` for a list of supported +multicast engines. + +To turn on multicast support, add this line in your `project-` or `contiki-conf.h` + + #define UIP_MCAST6_CONF_ENGINE xyz + + where xyz is a value from `uip-mcast6-engines.h` + +To disable: + + #define UIP_MCAST6_CONF_ENGINE 0 + +You also need to make sure the multicast code gets built. Your example's +(or platform's) Makefile should include this: + + MODULES += core/net/ipv6/multicast + +How to extend +============= +Let's assume you want to write an engine called foo. +The multicast API defines a multicast engine driver in a fashion similar to +the various NETSTACK layer drivers. This API defines functions for basic +multicast operations (init, in, out). +In order to extend multicast with a new engine, perform the following steps: + +- Open `uip-mcast6-engines.h` and assign a unique integer code to your engine + + #define UIP_MCAST6_ENGINE_FOO xyz + + - Include your engine's `foo.h` + +- In `foo.c`, implement: + * `init()` + * `in()` + * `out()` + * Define your driver like so: + + `const struct uip_mcast6_driver foo_driver = { ... }` + +- If you want to maintain stats: + * Standard multicast stats are maintained in `uip_mcast6_stats`. Don't access + this struct directly, use the macros provided in `uip-mcast6-stats.h` instead + * You can add your own stats extensions. To do so, declare your own stats + struct in your engine's module, e.g `struct foo_stats` + * When you initialise the stats module with `UIP_MCAST6_STATS_INIT`, pass + a pointer to your stats variable as the macro's argument. + An example of how to extend multicast stats, look at the ROLL TM engine + +- Open `uip-mcast6.h` and add a section in the `#if` spree. This aims to + configure the uIPv6 core. More specifically, you need to: + * Specify if you want to put RPL in MOP3 by defining + `RPL_CONF_MULTICAST`: 1: MOP 3, 0: non-multicast MOP + * Define your engine details + + #define UIP_MCAST6 foo_driver + #define UIP_MCAST6_STATS foo_stats + typedef struct foo_stats uip_mcast6_stats_t; + + * Optionally, add a configuration check block to stop builds when the + configuration is not sane. + +If you need your engine to perform operations not supported by the generic +UIP_MCAST6 API, you will have to hook those in the uip core manually. As an +example, see how the core is modified so that it can deliver ICMPv6 datagrams +to the ROLL TM engine. diff --git a/core/net/ipv6/multicast/roll-tm.c b/core/net/ipv6/multicast/roll-tm.c new file mode 100644 index 000000000..3fa2d58e3 --- /dev/null +++ b/core/net/ipv6/multicast/roll-tm.c @@ -0,0 +1,1442 @@ +/* + * Copyright (c) 2010, Loughborough University - Computer Science + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + */ + +/** + * \file + * This file implements IPv6 MCAST forwarding according to the + * algorithm described in the "MCAST Forwarding Using Trickle" + * internet draft. + * + * The current version of the draft can always be found in + * http://tools.ietf.org/html/draft-ietf-roll-trickle-mcast + * + * This implementation is based on the draft version stored in + * ROLL_TM_VER + * + * \author + * George Oikonomou - + */ + +#include "contiki.h" +#include "contiki-lib.h" +#include "contiki-net.h" +#include "net/ipv6/multicast/uip-mcast6.h" +#include "net/ipv6/multicast/roll-tm.h" +#include "dev/watchdog.h" +#include + +#define DEBUG DEBUG_NONE +#include "net/ip/uip-debug.h" + +#define TRICKLE_VERBOSE 0 + +#if DEBUG && TRICKLE_VERBOSE +#define VERBOSE_PRINTF(...) PRINTF(__VA_ARGS__) +#define VERBOSE_PRINT_SEED(s) PRINT_SEED(s) +#else +#define VERBOSE_PRINTF(...) +#define VERBOSE_PRINT_SEED(...) +#endif + +#if UIP_CONF_IPV6 +/*---------------------------------------------------------------------------*/ +/* Data Representation */ +/*---------------------------------------------------------------------------*/ +#if ROLL_TM_SHORT_SEEDS +typedef union seed_id_u { + uint8_t u8[2]; + uint16_t id; /* Big Endian */ +} seed_id_t; + +#define seed_is_null(s) ((s)->id == 0) +#define PRINT_SEED(s) PRINTF("0x%02x%02x", (s)->u8[0], (s)->u8[1]) +#else /* ROLL_TM_SHORT_SEEDS */ +typedef uip_ip6addr_t seed_id_t; + +#define seed_is_null(s) uip_is_addr_unspecified(s) +#define PRINT_SEED(s) PRINT6ADDR(s) +#endif /* ROLL_TM_SHORT_SEEDS */ +#define seed_id_cmp(a, b) (memcmp((a), (b), sizeof(seed_id_t)) == 0) +#define seed_id_cpy(a, b) (memcpy((a), (b), sizeof(seed_id_t))) + +/* Trickle Timers */ +struct trickle_param { + clock_time_t i_min; /* Clock ticks */ + clock_time_t t_start; /* Start of the interval (absolute clock_time) */ + clock_time_t t_end; /* End of the interval (absolute clock_time) */ + clock_time_t t_next; /* Clock ticks, randomised in [I/2, I) */ + clock_time_t t_last_trigger; + struct ctimer ct; + uint8_t i_current; /* Current doublings from i_min */ + uint8_t i_max; /* Max number of doublings */ + uint8_t k; /* Redundancy Constant */ + uint8_t t_active; /* Units of Imax */ + uint8_t t_dwell; /* Units of Imax */ + uint8_t c; /* Consistency Counter */ + uint8_t inconsistency; +}; + +/** + * \brief Convert a timer to a sane clock_time_t value after d doublings + * m is a value of Imin, d is a number of doublings + * Careful of overflows + */ +#define TRICKLE_TIME(m, d) ((clock_time_t)((m) << (d))) + +/** + * \brief Convert Imax from number of doublings to clock_time_t units for + * trickle_param t. Again, watch out for overflows */ +#define TRICKLE_IMAX(t) ((uint32_t)((t)->i_min << (t)->i_max)) + +/** + * \brief Convert Tactive for a trickle timer to a sane clock_time_t value + * t is a pointer to the timer + * Careful of overflows + */ +#define TRICKLE_ACTIVE(t) ((uint32_t)(TRICKLE_IMAX(t) * t->t_active)) + +/** + * \brief Convert Tdwell for a trickle timer to a sane clock_time_t value + * t is a pointer to the timer + * Careful of overflows + */ +#define TRICKLE_DWELL(t) ((uint32_t)(TRICKLE_IMAX(t) * t->t_dwell)) + +/** + * \brief Check if suppression is enabled for trickle_param t + * t is a pointer to the timer + */ +#define SUPPRESSION_ENABLED(t) ((t)->k != ROLL_TM_INFINITE_REDUNDANCY) + +/** + * \brief Check if suppression is disabled for trickle_param t + * t is a pointer to the timer + */ +#define SUPPRESSION_DISABLED(t) ((t)->k == ROLL_TM_INFINITE_REDUNDANCY) + +/** + * \brief Init trickle_timer[m] + */ +#define TIMER_CONFIGURE(m) do { \ + t[m].i_min = ROLL_TM_IMIN_##m; \ + t[m].i_max = ROLL_TM_IMAX_##m; \ + t[m].k = ROLL_TM_K_##m; \ + t[m].t_active = ROLL_TM_T_ACTIVE_##m; \ + t[m].t_dwell = ROLL_TM_T_DWELL_##m; \ + t[m].t_last_trigger = clock_time(); \ +} while(0) +/*---------------------------------------------------------------------------*/ +/* Sequence Values and Serial Number Arithmetic + * + * Sequence Number Comparisons as per RFC1982 "Serial Number Arithmetic" + * Our 'SERIAL_BITS' value is 15 here + * + * NOTE: There can be pairs of sequence numbers s1 and s2 with an undefined + * ordering. All three macros would evaluate as 0, as in: + * SEQ_VAL_IS_EQUAL(s1, s2) == 0 and + * SEQ_VAL_IS_GT(s1, s2) == 0 and + * SEQ_VAL_IS_LT(s1, s2) == 0 + * + * This is not a bug of this implementation, it's an RFC design choice + */ + +/** + * \brief s1 is said to be equal s2 iif SEQ_VAL_IS_EQ(s1, s2) == 1 + */ +#define SEQ_VAL_IS_EQ(i1, i2) ((i1) == (i2)) + +/** + * \brief s1 is said to be less than s2 iif SEQ_VAL_IS_LT(s1, s2) == 1 + */ +#define SEQ_VAL_IS_LT(i1, i2) \ + ( \ + ((i1) != (i2)) && \ + ((((i1) < (i2)) && ((int16_t)((i2) - (i1)) < 0x4000)) || \ + (((i1) > (i2)) && ((int16_t)((i1) - (i2)) > 0x4000))) \ + ) + +/** + * \brief s1 is said to be greater than s2 iif SEQ_VAL_IS_LT(s1, s2) == 1 + */ +#define SEQ_VAL_IS_GT(i1, i2) \ +( \ + ((i1) != (i2)) && \ + ((((i1) < (i2)) && ((int16_t)((i2) - (i1)) > 0x4000)) || \ + (((i1) > (i2)) && ((int16_t)((i1) - (i2)) < 0x4000))) \ +) + +/** + * \brief Add n to s: (s + n) modulo (2 ^ SERIAL_BITS) => ((s + n) % 0x8000) + */ +#define SEQ_VAL_ADD(s, n) (((s) + (n)) % 0x8000) +/*---------------------------------------------------------------------------*/ +/* Sliding Windows */ +struct sliding_window { + seed_id_t seed_id; + int16_t lower_bound; /* lolipop */ + int16_t upper_bound; /* lolipop */ + int16_t min_listed; /* lolipop */ + uint8_t flags; /* Is used, Trickle param, Is listed */ + uint8_t count; +}; + +#define SLIDING_WINDOW_U_BIT 0x80 /* Is used */ +#define SLIDING_WINDOW_M_BIT 0x40 /* Window trickle parametrization */ +#define SLIDING_WINDOW_L_BIT 0x20 /* Current ICMP message lists us */ +#define SLIDING_WINDOW_B_BIT 0x10 /* Used when updating bounds */ + +/** + * \brief Is Occupied sliding window location w + * w: pointer to a sliding window + */ +#define SLIDING_WINDOW_IS_USED(w) ((w)->flags & SLIDING_WINDOW_U_BIT) + +/** + * \brief Set 'Is Used' bit for window w + * w: pointer to a sliding window + */ +#define SLIDING_WINDOW_IS_USED_SET(w) ((w)->flags |= SLIDING_WINDOW_U_BIT) + +/** + * \brief Clear 'Is Used' bit for window w + * w: pointer to a sliding window + */ +#define SLIDING_WINDOW_IS_USED_CLR(w) ((w)->flags &= ~SLIDING_WINDOW_U_BIT) +#define window_free(w) SLIDING_WINDOW_IS_USED_CLR(w) + +/** + * \brief Set 'Is Seen' bit for window w + * w: pointer to a sliding window + */ +#define SLIDING_WINDOW_LISTED_SET(w) ((w)->flags |= SLIDING_WINDOW_L_BIT) + +/** + * \brief Clear 'Is Seen' bit for window w + * w: pointer to a sliding window + */ +#define SLIDING_WINDOW_LISTED_CLR(w) ((w)->flags &= ~SLIDING_WINDOW_L_BIT) + +/** + * \brief Is the sliding window at location w listed in current ICMP message? + * w: pointer to a sliding window + */ +#define SLIDING_WINDOW_IS_LISTED(w) ((w)->flags & SLIDING_WINDOW_L_BIT) + +/** + * \brief Set M bit for window w + * w: pointer to a sliding window + */ +#define SLIDING_WINDOW_M_SET(w) ((w)->flags |= SLIDING_WINDOW_M_BIT) + +/** + * \brief Clear M bit for window w + * w: pointer to a sliding window + */ +#define SLIDING_WINDOW_M_CLR(w) ((w)->flags &= ~SLIDING_WINDOW_M_BIT) + +/** + * \brief Retrieve trickle parametrization for sliding window at location w + * w: pointer to a sliding window + */ +#define SLIDING_WINDOW_GET_M(w) \ + ((uint8_t)(((w)->flags & SLIDING_WINDOW_M_BIT) == SLIDING_WINDOW_M_BIT)) +/*---------------------------------------------------------------------------*/ +/* Multicast Packet Buffers */ +struct mcast_packet { +#if ROLL_TM_SHORT_SEEDS + /* Short seeds are stored inside the message */ + seed_id_t seed_id; +#endif + uint32_t active; /* Starts at 0 and increments */ + uint32_t dwell; /* Starts at 0 and increments */ + uint16_t buff_len; + uint16_t seq_val; /* host-byte order */ + struct sliding_window *sw; /* Pointer to the SW this packet belongs to */ + uint8_t flags; /* Is-Used, Must Send, Is Listed */ + uint8_t buff[UIP_BUFSIZE - UIP_LLH_LEN]; +}; + +/* Flag bits */ +#define MCAST_PACKET_U_BIT 0x80 /* Is Used */ +#define MCAST_PACKET_S_BIT 0x20 /* Must Send Next Pass */ +#define MCAST_PACKET_L_BIT 0x10 /* Is listed in ICMP message */ + +/* Fetch a pointer to the Seed ID of a buffered message p */ +#if ROLL_TM_SHORT_SEEDS +#define MCAST_PACKET_GET_SEED(p) ((seed_id_t *)&((p)->seed_id)) +#else +#define MCAST_PACKET_GET_SEED(p) \ + ((seed_id_t *)&((struct uip_ip_hdr *)&(p)->buff[UIP_LLH_LEN])->srcipaddr) +#endif + +/** + * \brief Get the TTL of a buffered packet + * p: pointer to a packet buffer + */ +#define MCAST_PACKET_TTL(p) \ + (((struct uip_ip_hdr *)(p)->buff)->ttl) + +/** + * \brief Set 'Is Used' bit for packet p + * p: pointer to a packet buffer + */ +#define MCAST_PACKET_USED_SET(p) ((p)->flags |= MCAST_PACKET_U_BIT) + +/** + * \brief Clear 'Is Used' bit for packet p + * p: pointer to a packet buffer + */ +#define MCAST_PACKET_USED_CLR(p) ((p)->flags &= ~MCAST_PACKET_U_BIT) + +/** + * \brief Is Occupied buffer location p + */ +#define MCAST_PACKET_IS_USED(p) ((p)->flags & MCAST_PACKET_U_BIT) + +/** + * \brief Must we send this message this pass? + */ +#define MCAST_PACKET_MUST_SEND(p) ((p)->flags & MCAST_PACKET_S_BIT) + +/** + * \brief Set 'Must Send' bit for message p + * p: pointer to a struct mcast_packet + */ +#define MCAST_PACKET_SEND_SET(p) ((p)->flags |= MCAST_PACKET_S_BIT) + +/** + * \brief Clear 'Must Send' bit for message p + * p: pointer to a struct mcast_packet + */ +#define MCAST_PACKET_SEND_CLR(p) ((p)->flags &= ~MCAST_PACKET_S_BIT) + +/** + * \brief Is the message p listed in current ICMP message? + * p: pointer to a struct mcast_packet + */ +#define MCAST_PACKET_IS_LISTED(p) ((p)->flags & MCAST_PACKET_L_BIT) + +/** + * \brief Set 'Is Listed' bit for message p + * p: pointer to a struct mcast_packet + */ +#define MCAST_PACKET_LISTED_SET(p) ((p)->flags |= MCAST_PACKET_L_BIT) + +/** + * \brief Clear 'Is Listed' bit for message p + * p: pointer to a struct mcast_packet + */ +#define MCAST_PACKET_LISTED_CLR(p) ((p)->flags &= ~MCAST_PACKET_L_BIT) + +/** + * \brief Free a multicast packet buffer + * p: pointer to a struct mcast_packet + */ +#define MCAST_PACKET_FREE(p) ((p)->flags = 0) +/*---------------------------------------------------------------------------*/ +/* Sequence Lists in Multicast Trickle ICMP messages */ +struct sequence_list_header { + uint8_t flags; /* S: Seed ID length, M: Trickle parametrization */ + uint8_t seq_len; + seed_id_t seed_id; +}; + +#define SEQUENCE_LIST_S_BIT 0x80 +#define SEQUENCE_LIST_M_BIT 0x40 +#define SEQUENCE_LIST_RES 0x3F + +/** + * \brief Get the Trickle Parametrization for an ICMPv6 sequence list + * l: pointer to a sequence list structure + */ +#define SEQUENCE_LIST_GET_M(l) \ + ((uint8_t)(((l)->flags & SEQUENCE_LIST_M_BIT) == SEQUENCE_LIST_M_BIT)) + +/** + * \brief Get the Seed ID Length for an ICMPv6 sequence list + * l: pointer to a sequence list structure + */ +#define SEQUENCE_LIST_GET_S(l) \ + ((uint8_t)(((l)->flags & SEQUENCE_LIST_S_BIT) == SEQUENCE_LIST_S_BIT)) +/*---------------------------------------------------------------------------*/ +/* Trickle Multicast HBH Option */ +struct hbho_mcast { + uint8_t type; + uint8_t len; +#if ROLL_TM_SHORT_SEEDS + seed_id_t seed_id; +#endif + uint8_t flags; /* M, Seq ID MSB */ + uint8_t seq_id_lsb; +#if !ROLL_TM_SHORT_SEEDS + /* Need to Pad to 8 bytes with PadN */ + uint8_t padn_type; /* 1: PadN */ + uint8_t padn_len; /* 0->2 bytes */ +#endif +}; + +#define HBHO_OPT_TYPE_TRICKLE 0x0C +#define HBHO_LEN_LONG_SEED 2 +#define HBHO_LEN_SHORT_SEED 4 +#define HBHO_TOTAL_LEN 8 +/** + * \brief Get the Trickle Parametrization for a multicast HBHO header + * m: pointer to the HBHO header + */ +#define HBH_GET_M(h) (((h)->flags & 0x80) == 0x80) + +/** + * \brief Set the Trickle Parametrization bit for a multicast HBHO header + * m: pointer to the HBHO header + */ +#define HBH_SET_M(h) ((h)->flags |= 0x80) + +/** + * \brief Retrieve the Sequence Value MSB from a multicast HBHO header + * m: pointer to the HBHO header + */ +#define HBH_GET_SV_MSB(h) ((h)->flags & 0x7F) +/*---------------------------------------------------------------------------*/ +/* Destination for our ICMPv6 datagrams */ +#if ROLL_TM_CONF_DEST_ALL_NODES +#define roll_tm_create_dest(a) uip_create_linklocal_allnodes_mcast(a) +#else +#define roll_tm_create_dest(a) uip_create_linklocal_allrouters_mcast(a) +#endif +/*---------------------------------------------------------------------------*/ +/* Maintain Stats */ +#if UIP_MCAST6_STATS +static struct roll_tm_stats stats; + +#define ROLL_TM_STATS_ADD(x) stats.x++ +#define ROLL_TM_STATS_INIT() do { memset(&stats, 0, sizeof(stats)); } while(0) +#else /* UIP_MCAST6_STATS */ +#define ROLL_TM_STATS_ADD(x) +#define ROLL_TM_STATS_INIT() +#endif +/*---------------------------------------------------------------------------*/ +/* Internal Data Structures */ +/*---------------------------------------------------------------------------*/ +static struct trickle_param t[2]; +static struct sliding_window windows[ROLL_TM_WINS]; +static struct mcast_packet buffered_msgs[ROLL_TM_BUFF_NUM]; +/*---------------------------------------------------------------------------*/ +/* Temporary Stores */ +/*---------------------------------------------------------------------------*/ +static struct trickle_param *loctpptr; +static struct sequence_list_header *locslhptr; +static struct sliding_window *locswptr; +static struct sliding_window *iterswptr; +static struct mcast_packet *locmpptr; +static struct hbho_mcast *lochbhmptr; +static uint16_t last_seq; +/*---------------------------------------------------------------------------*/ +/* uIPv6 Pointers */ +/*---------------------------------------------------------------------------*/ +#define UIP_DATA_BUF ((uint8_t *)&uip_buf[uip_l2_l3_hdr_len + UIP_UDPH_LEN]) +#define UIP_UDP_BUF ((struct uip_udp_hdr *)&uip_buf[uip_l2_l3_hdr_len]) +#define UIP_EXT_BUF ((struct uip_ext_hdr *)&uip_buf[UIP_LLH_LEN + UIP_IPH_LEN]) +#define UIP_EXT_BUF_NEXT ((uint8_t *)&uip_buf[UIP_LLH_LEN + UIP_IPH_LEN + HBHO_TOTAL_LEN]) +#define UIP_EXT_OPT_FIRST ((struct hbho_mcast *)&uip_buf[UIP_LLH_LEN + UIP_IPH_LEN + 2]) +#define UIP_IP_BUF ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN]) +#define UIP_ICMP_BUF ((struct uip_icmp_hdr *)&uip_buf[uip_l2_l3_hdr_len]) +#define UIP_ICMP_PAYLOAD ((unsigned char *)&uip_buf[uip_l2_l3_icmp_hdr_len]) +extern uint16_t uip_slen; +/*---------------------------------------------------------------------------*/ +/* Local function prototypes */ +/*---------------------------------------------------------------------------*/ +static void icmp_output(); +static void window_update_bounds(); +static void reset_trickle_timer(uint8_t); +static void handle_timer(void *); +/*---------------------------------------------------------------------------*/ +/* 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 +random_interval(clock_time_t i_min, uint8_t d) +{ + clock_time_t min = TRICKLE_TIME(i_min >> 1, d); + + VERBOSE_PRINTF("ROLL TM: Random [%lu, %lu)\n", (unsigned long)min, + (unsigned long)(TRICKLE_TIME(i_min, d))); + + return min + (random_rand() % (TRICKLE_TIME(i_min, d) - 1 - min)); +} +/*---------------------------------------------------------------------------*/ +/* Called at the end of the current interval for timer ptr */ +static void +double_interval(void *ptr) +{ + struct trickle_param *param = (struct trickle_param *)ptr; + int16_t offset; + clock_time_t next; + + /* + * If we got called long past our expiration, store the offset and try to + * compensate this period + */ + offset = (int16_t)(clock_time() - param->t_end); + + /* Calculate next interval */ + if(param->i_current < param->i_max) { + param->i_current++; + } + + param->t_start = param->t_end; + param->t_end = param->t_start + (param->i_min << param->i_current); + + next = random_interval(param->i_min, param->i_current); + if(next > offset) { + next -= offset; + } else { + next = 0; + } + param->t_next = next; + ctimer_set(¶m->ct, param->t_next, handle_timer, (void *)param); + + VERBOSE_PRINTF("ROLL TM: Doubling at %lu (offset %d), Start %lu, End %lu," + " Periodic in %lu\n", clock_time(), offset, + (unsigned long)param->t_start, + (unsigned long)param->t_end, (unsigned long)param->t_next); +} +/*---------------------------------------------------------------------------*/ +/* + * Called at a random point in [I/2,I) of the current interval for ptr + * PARAM is a pointer to the timer that triggered the callback (&t[index]) + */ +static void +handle_timer(void *ptr) +{ + struct trickle_param *param; + clock_time_t diff_last; /* Time diff from last pass */ + clock_time_t diff_start; /* Time diff from interval start */ + uint8_t m; + + param = (struct trickle_param *)ptr; + if(param == &t[0]) { + m = 0; + } else if(param == &t[1]) { + m = 1; + } else { + /* This is an ooops and a serious one too */ + return; + } + + /* Bail out pronto if our uIPv6 stack is not ready to send messages */ + if(uip_ds6_get_link_local(ADDR_PREFERRED) == NULL) { + VERBOSE_PRINTF + ("ROLL TM: Suppressing timer processing. Stack not ready\n"); + reset_trickle_timer(m); + return; + } + + VERBOSE_PRINTF("ROLL TM: M=%u Periodic at %lu, last=%lu\n", + m, (unsigned long)clock_time(), + (unsigned long)param->t_last_trigger); + + /* Temporarily store 'now' in t_next and calculate diffs */ + param->t_next = clock_time(); + diff_last = param->t_next - param->t_last_trigger; + diff_start = param->t_next - param->t_start; + param->t_last_trigger = param->t_next; + + VERBOSE_PRINTF + ("ROLL TM: M=%u Periodic diff from last %lu, from start %lu\n", m, + (unsigned long)diff_last, (unsigned long)diff_start); + + /* Handle all buffered messages */ + for(locmpptr = &buffered_msgs[ROLL_TM_BUFF_NUM - 1]; + locmpptr >= buffered_msgs; locmpptr--) { + if(MCAST_PACKET_IS_USED(locmpptr) + && (SLIDING_WINDOW_GET_M(locmpptr->sw) == m)) { + + /* + * if() + * If the packet was received during the last interval, its reception + * caused an inconsistency (and thus a timer reset). This means that + * the packet was received at about t_start, we increment by diff_start + * + * else() + * If the packet was not received during the last window, it is safe to + * increase its lifetime counters by the time diff from last pass + * + * if active == dwell == 0 but i_current != 0, this is an oops + * (new packet that didn't reset us). We don't handle it + */ + if(locmpptr->active == 0) { + locmpptr->active += diff_start; + locmpptr->dwell += diff_start; + } else { + locmpptr->active += diff_last; + locmpptr->dwell += diff_last; + } + + VERBOSE_PRINTF("ROLL TM: M=%u Packet %u active %lu of %lu\n", + m, locmpptr->seq_val, locmpptr->active, + TRICKLE_ACTIVE(param)); + + if(locmpptr->dwell > TRICKLE_DWELL(param)) { + locmpptr->sw->count--; + PRINTF("ROLL TM: M=%u Free Packet %u (%lu > %lu), Window now at %u\n", + m, locmpptr->seq_val, locmpptr->dwell, + TRICKLE_DWELL(param), locmpptr->sw->count); + if(locmpptr->sw->count == 0) { + PRINTF("ROLL TM: M=%u Free Window ", m); + PRINT_SEED(&locmpptr->sw->seed_id); + PRINTF("\n"); + window_free(locmpptr->sw); + } + MCAST_PACKET_FREE(locmpptr); + } else if(MCAST_PACKET_TTL(locmpptr) > 0) { + /* Handle multicast transmissions */ + if(locmpptr->active < TRICKLE_ACTIVE(param) && + ((SUPPRESSION_ENABLED(param) && MCAST_PACKET_MUST_SEND(locmpptr)) || + SUPPRESSION_DISABLED(param))) { + PRINTF("ROLL TM: M=%u Periodic - Sending packet from Seed ", m); + PRINT_SEED(&locmpptr->sw->seed_id); + PRINTF(" seq %u\n", locmpptr->seq_val); + uip_len = locmpptr->buff_len; + memcpy(UIP_IP_BUF, &locmpptr->buff, uip_len); + + UIP_MCAST6_STATS_ADD(mcast_fwd); + tcpip_output(NULL); + MCAST_PACKET_SEND_CLR(locmpptr); + watchdog_periodic(); + } + } + } + } + + /* Suppression Enabled - Send an ICMP */ + if(SUPPRESSION_ENABLED(param)) { + if(param->c < param->k) { + icmp_output(); + } + } + + /* Done handling inconsistencies for this timer */ + param->inconsistency = 0; + param->c = 0; + + window_update_bounds(); + + /* Temporarily store 'now' in t_next */ + param->t_next = clock_time(); + if(param->t_next >= param->t_end) { + /* took us too long to process things, double interval asap */ + param->t_next = 0; + } else { + param->t_next = param->t_end - param->t_next; + } + VERBOSE_PRINTF + ("ROLL TM: M=%u Periodic at %lu, Interval End at %lu in %lu\n", m, + (unsigned long)clock_time(), (unsigned long)param->t_end, + (unsigned long)param->t_next); + ctimer_set(¶m->ct, param->t_next, double_interval, (void *)param); + + return; +} +/*---------------------------------------------------------------------------*/ +static void +reset_trickle_timer(uint8_t index) +{ + t[index].t_start = clock_time(); + t[index].t_end = t[index].t_start + (t[index].i_min); + t[index].i_current = 0; + t[index].c = 0; + t[index].t_next = random_interval(t[index].i_min, t[index].i_current); + + VERBOSE_PRINTF + ("ROLL TM: M=%u Reset at %lu, Start %lu, End %lu, New Interval %lu\n", + index, (unsigned long)t[index].t_start, (unsigned long)t[index].t_start, + (unsigned long)t[index].t_end, (unsigned long)t[index].t_next); + + ctimer_set(&t[index].ct, t[index].t_next, handle_timer, (void *)&t[index]); +} +/*---------------------------------------------------------------------------*/ +static struct sliding_window * +window_allocate() +{ + for(iterswptr = &windows[ROLL_TM_WINS - 1]; iterswptr >= windows; + iterswptr--) { + if(!SLIDING_WINDOW_IS_USED(iterswptr)) { + iterswptr->count = 0; + iterswptr->lower_bound = -1; + iterswptr->upper_bound = -1; + iterswptr->min_listed = -1; + return iterswptr; + } + } + return NULL; +} +/*---------------------------------------------------------------------------*/ +static struct sliding_window * +window_lookup(seed_id_t *s, uint8_t m) +{ + for(iterswptr = &windows[ROLL_TM_WINS - 1]; iterswptr >= windows; + iterswptr--) { + VERBOSE_PRINTF("ROLL TM: M=%u (%u) ", SLIDING_WINDOW_GET_M(iterswptr), m); + VERBOSE_PRINT_SEED(&iterswptr->seed_id); + VERBOSE_PRINTF("\n"); + if(seed_id_cmp(s, &iterswptr->seed_id) && + SLIDING_WINDOW_GET_M(iterswptr) == m) { + return iterswptr; + } + } + return NULL; +} +/*---------------------------------------------------------------------------*/ +static void +window_update_bounds() +{ + for(iterswptr = &windows[ROLL_TM_WINS - 1]; iterswptr >= windows; + iterswptr--) { + iterswptr->lower_bound = -1; + } + + for(locmpptr = &buffered_msgs[ROLL_TM_BUFF_NUM - 1]; + locmpptr >= buffered_msgs; locmpptr--) { + if(MCAST_PACKET_IS_USED(locmpptr)) { + iterswptr = locmpptr->sw; + VERBOSE_PRINTF("ROLL TM: Update Bounds: [%d - %d] vs %u\n", + iterswptr->lower_bound, iterswptr->upper_bound, + locmpptr->seq_val); + if(iterswptr->lower_bound < 0 + || SEQ_VAL_IS_LT(locmpptr->seq_val, iterswptr->lower_bound)) { + iterswptr->lower_bound = locmpptr->seq_val; + } + if(iterswptr->upper_bound < 0 || + SEQ_VAL_IS_GT(locmpptr->seq_val, iterswptr->upper_bound)) { + iterswptr->upper_bound = locmpptr->seq_val; + } + } + } +} +/*---------------------------------------------------------------------------*/ +static struct mcast_packet * +buffer_reclaim() +{ + struct sliding_window *largest = windows; + struct mcast_packet *rv; + + for(iterswptr = &windows[ROLL_TM_WINS - 1]; iterswptr >= windows; + iterswptr--) { + if(iterswptr->count > largest->count) { + largest = iterswptr; + } + } + + if(largest->count == 1) { + /* Can't reclaim last entry for a window and this is the largest window */ + return NULL; + } + + PRINTF("ROLL TM: Reclaim from Seed "); + PRINT_SEED(&largest->seed_id); + PRINTF(" M=%u, count was %u\n", + SLIDING_WINDOW_GET_M(largest), largest->count); + /* Find the packet at the lowest bound for the largest window */ + for(locmpptr = &buffered_msgs[ROLL_TM_BUFF_NUM - 1]; + locmpptr >= buffered_msgs; locmpptr--) { + if(MCAST_PACKET_IS_USED(locmpptr) && (locmpptr->sw == largest) && + SEQ_VAL_IS_EQ(locmpptr->seq_val, largest->lower_bound)) { + rv = locmpptr; + PRINTF("ROLL TM: Reclaim seq. val %u\n", locmpptr->seq_val); + MCAST_PACKET_FREE(rv); + largest->count--; + window_update_bounds(); + VERBOSE_PRINTF("ROLL TM: Reclaim - new bounds [%u , %u]\n", + largest->lower_bound, largest->upper_bound); + return rv; + } + } + + /* oops */ + return NULL; +} +/*---------------------------------------------------------------------------*/ +static struct mcast_packet * +buffer_allocate() +{ + for(locmpptr = &buffered_msgs[ROLL_TM_BUFF_NUM - 1]; + locmpptr >= buffered_msgs; locmpptr--) { + if(!MCAST_PACKET_IS_USED(locmpptr)) { + return locmpptr; + } + } + return NULL; +} +/*---------------------------------------------------------------------------*/ +static void +icmp_output() +{ + struct sequence_list_header *sl; + uint8_t *buffer; + uint16_t payload_len; + + PRINTF("ROLL TM: ICMPv6 Out\n"); + + UIP_IP_BUF->vtc = 0x60; + UIP_IP_BUF->tcflow = 0; + UIP_IP_BUF->flow = 0; + UIP_IP_BUF->proto = UIP_PROTO_ICMP6; + UIP_IP_BUF->ttl = ROLL_TM_IP_HOP_LIMIT; + + sl = (struct sequence_list_header *)UIP_ICMP_PAYLOAD; + payload_len = 0; + + VERBOSE_PRINTF("ROLL TM: ICMPv6 Out - Hdr @ %p, payload @ %p\n", UIP_ICMP_BUF, sl); + + for(iterswptr = &windows[ROLL_TM_WINS - 1]; iterswptr >= windows; + iterswptr--) { + if(SLIDING_WINDOW_IS_USED(iterswptr) && iterswptr->count > 0) { + memset(sl, 0, sizeof(struct sequence_list_header)); +#if ROLL_TM_SHORT_SEEDS + sl->flags = SEQUENCE_LIST_S_BIT; +#endif + if(SLIDING_WINDOW_GET_M(iterswptr)) { + sl->flags |= SEQUENCE_LIST_M_BIT; + } + seed_id_cpy(&sl->seed_id, &iterswptr->seed_id); + + PRINTF("ROLL TM: ICMPv6 Out - Seq. F=0x%02x, Seed ID=", sl->flags); + PRINT_SEED(&sl->seed_id); + + buffer = (uint8_t *)sl + sizeof(struct sequence_list_header); + + for(locmpptr = &buffered_msgs[ROLL_TM_BUFF_NUM - 1]; + locmpptr >= buffered_msgs; locmpptr--) { + if(MCAST_PACKET_IS_USED(locmpptr) && + locmpptr->active < TRICKLE_ACTIVE((&t[SLIDING_WINDOW_GET_M(iterswptr)]))) { + if(locmpptr->sw == iterswptr) { + sl->seq_len++; + PRINTF(", %u", locmpptr->seq_val); + *buffer = (uint8_t)(locmpptr->seq_val >> 8); + buffer++; + *buffer = (uint8_t)(locmpptr->seq_val & 0xFF); + buffer++; + } + } + } + PRINTF(", Len=%u\n", sl->seq_len); + + /* Scrap the entire window if it has no content */ + if(sl->seq_len > 0) { + payload_len += sizeof(struct sequence_list_header) + sl->seq_len * 2; + sl = (struct sequence_list_header *)buffer; + } + } + } + + if(payload_len == 0) { + VERBOSE_PRINTF("ROLL TM: ICMPv6 Out - nothing to send\n"); + return; + } + + roll_tm_create_dest(&UIP_IP_BUF->destipaddr); + uip_ds6_select_src(&UIP_IP_BUF->srcipaddr, &UIP_IP_BUF->destipaddr); + + UIP_IP_BUF->len[0] = (UIP_ICMPH_LEN + payload_len) >> 8; + UIP_IP_BUF->len[1] = (UIP_ICMPH_LEN + payload_len) & 0xff; + + UIP_ICMP_BUF->type = ICMP6_ROLL_TM; + UIP_ICMP_BUF->icode = ROLL_TM_ICMP_CODE; + + UIP_ICMP_BUF->icmpchksum = 0; + UIP_ICMP_BUF->icmpchksum = ~uip_icmp6chksum(); + + uip_len = UIP_IPH_LEN + UIP_ICMPH_LEN + payload_len; + + VERBOSE_PRINTF("ROLL TM: ICMPv6 Out - %u bytes\n", payload_len); + + tcpip_ipv6_output(); + ROLL_TM_STATS_ADD(icmp_out); + return; +} +/*---------------------------------------------------------------------------*/ +/** + * \brief Processes an incoming or outgoing multicast message and determines + * whether it should be dropped or accepted + * + * \param in 1: Incoming packet, 0: Outgoing (we are the seed) + * + * \return 0: Drop, 1: Accept + */ +static uint8_t +accept(uint8_t in) +{ + seed_id_t *seed_ptr; + uint8_t m; + uint16_t seq_val; + + PRINTF("ROLL TM: Multicast I/O\n"); + +#if UIP_CONF_IPV6_CHECKS + if(uip_is_addr_mcast_non_routable(&UIP_IP_BUF->destipaddr)) { + PRINTF("ROLL TM: Mcast I/O, bad destination\n"); + UIP_MCAST6_STATS_ADD(mcast_bad); + return UIP_MCAST6_DROP; + } + /* + * Abort transmission if the v6 src is unspecified. This may happen if the + * seed tries to TX while it's still performing DAD or waiting for a prefix + */ + if(uip_is_addr_unspecified(&UIP_IP_BUF->srcipaddr)) { + PRINTF("ROLL TM: Mcast I/O, bad source\n"); + UIP_MCAST6_STATS_ADD(mcast_bad); + return UIP_MCAST6_DROP; + } +#endif + + /* Check the Next Header field: Must be HBHO */ + if(UIP_IP_BUF->proto != UIP_PROTO_HBHO) { + PRINTF("ROLL TM: Mcast I/O, bad proto\n"); + UIP_MCAST6_STATS_ADD(mcast_bad); + return UIP_MCAST6_DROP; + } else { + /* Check the Option Type */ + if(UIP_EXT_OPT_FIRST->type != HBHO_OPT_TYPE_TRICKLE) { + PRINTF("ROLL TM: Mcast I/O, bad HBHO type\n"); + UIP_MCAST6_STATS_ADD(mcast_bad); + return UIP_MCAST6_DROP; + } + } + lochbhmptr = UIP_EXT_OPT_FIRST; + + PRINTF("ROLL TM: HBHO T=%u, L=%u, M=%u, S=0x%02x%02x\n", + lochbhmptr->type, lochbhmptr->len, HBH_GET_M(lochbhmptr), + HBH_GET_SV_MSB(lochbhmptr), lochbhmptr->seq_id_lsb); + + /* Drop unsupported Seed ID Lengths. S bit: 0->short, 1->long */ +#if ROLL_TM_SHORT_SEEDS + /* Short Seed ID: Len MUST be 4 */ + if(lochbhmptr->len != HBHO_LEN_SHORT_SEED) { + PRINTF("ROLL TM: Mcast I/O, bad length\n"); + UIP_MCAST6_STATS_ADD(mcast_bad); + return UIP_MCAST6_DROP; + } +#else + /* Long Seed ID: Len MUST be 2 (Seed ID is elided) */ + if(lochbhmptr->len != HBHO_LEN_LONG_SEED) { + PRINTF("ROLL TM: Mcast I/O, bad length\n"); + UIP_MCAST6_STATS_ADD(mcast_bad); + return UIP_MCAST6_DROP; + } +#endif + +#if UIP_MCAST6_STATS + if(in == ROLL_TM_DGRAM_IN) { + UIP_MCAST6_STATS_ADD(mcast_in_all); + } +#endif + + /* Is this for a known window? */ +#if ROLL_TM_SHORT_SEEDS + seed_ptr = &lochbhmptr->seed_id; +#else + seed_ptr = &UIP_IP_BUF->srcipaddr; +#endif + m = HBH_GET_M(lochbhmptr); + + locswptr = window_lookup(seed_ptr, m); + + seq_val = lochbhmptr->seq_id_lsb; + seq_val |= HBH_GET_SV_MSB(lochbhmptr) << 8; + + if(locswptr) { + if(SEQ_VAL_IS_LT(seq_val, locswptr->lower_bound)) { + /* Too old, drop */ + PRINTF("ROLL TM: Too old\n"); + UIP_MCAST6_STATS_ADD(mcast_dropped); + return UIP_MCAST6_DROP; + } + for(locmpptr = &buffered_msgs[ROLL_TM_BUFF_NUM - 1]; + locmpptr >= buffered_msgs; locmpptr--) { + if(MCAST_PACKET_IS_USED(locmpptr) && + locmpptr->sw == locswptr && + SLIDING_WINDOW_GET_M(locmpptr->sw) == m && + SEQ_VAL_IS_EQ(seq_val, locmpptr->seq_val)) { + /* Seen before , drop */ + PRINTF("ROLL TM: Seen before\n"); + UIP_MCAST6_STATS_ADD(mcast_dropped); + return UIP_MCAST6_DROP; + } + } + } + + PRINTF("ROLL TM: New message\n"); + + /* We have not seen this message before */ + /* Allocate a window if we have to */ + if(!locswptr) { + locswptr = window_allocate(); + PRINTF("ROLL TM: New seed\n"); + } + if(!locswptr) { + /* Couldn't allocate window, drop */ + PRINTF("ROLL TM: Failed to allocate window\n"); + UIP_MCAST6_STATS_ADD(mcast_dropped); + return UIP_MCAST6_DROP; + } + + /* Allocate a buffer */ + locmpptr = buffer_allocate(); + if(!locmpptr) { + PRINTF("ROLL TM: Buffer allocation failed, reclaiming\n"); + locmpptr = buffer_reclaim(); + } + + if(!locmpptr) { + /* Failed to allocate / reclaim a buffer. If the window has only just been + * allocated, free it before dropping */ + PRINTF("ROLL TM: Buffer reclaim failed\n"); + if(locswptr->count == 0) { + window_free(locswptr); + UIP_MCAST6_STATS_ADD(mcast_dropped); + return UIP_MCAST6_DROP; + } + } +#if UIP_MCAST6_STATS + if(in == ROLL_TM_DGRAM_IN) { + UIP_MCAST6_STATS_ADD(mcast_in_unique); + } +#endif + + /* We have a window and we have a buffer. Accept this message */ + /* Set the seed ID and correct M for this window */ + SLIDING_WINDOW_M_CLR(locswptr); + if(m) { + SLIDING_WINDOW_M_SET(locswptr); + } + SLIDING_WINDOW_IS_USED_SET(locswptr); + seed_id_cpy(&locswptr->seed_id, seed_ptr); + PRINTF("ROLL TM: Window for seed "); + PRINT_SEED(&locswptr->seed_id); + PRINTF(" M=%u, count=%u\n", + SLIDING_WINDOW_GET_M(locswptr), locswptr->count); + + /* If this window was previously empty, set its lower bound to this packet */ + if(locswptr->count == 0) { + locswptr->lower_bound = seq_val; + VERBOSE_PRINTF("ROLL TM: New Lower Bound %u\n", locswptr->lower_bound); + } + + /* If this is a new Seq Num, update the window upper bound */ + if(locswptr->count == 0 || SEQ_VAL_IS_GT(seq_val, locswptr->upper_bound)) { + locswptr->upper_bound = seq_val; + VERBOSE_PRINTF("ROLL TM: New Upper Bound %u\n", locswptr->upper_bound); + } + + locswptr->count++; + + memset(locmpptr, 0, sizeof(struct mcast_packet)); + memcpy(&locmpptr->buff, UIP_IP_BUF, uip_len); + locmpptr->sw = locswptr; + locmpptr->buff_len = uip_len; + locmpptr->seq_val = seq_val; + MCAST_PACKET_USED_SET(locmpptr); + + PRINTF("ROLL TM: Window for seed "); + PRINT_SEED(&locswptr->seed_id); + PRINTF(" M=%u, %u values within [%u , %u]\n", + SLIDING_WINDOW_GET_M(locswptr), locswptr->count, + locswptr->lower_bound, locswptr->upper_bound); + + /* + * If this is an incoming packet, it is inconsistent and we need to decrement + * its TTL before we start forwarding it. + * If on the other hand we are the seed, the caller will trigger a + * transmission so we don't flag inconsistency and we leave the TTL alone + */ + if(in == ROLL_TM_DGRAM_IN) { + MCAST_PACKET_SEND_SET(locmpptr); + MCAST_PACKET_TTL(locmpptr)--; + + t[m].inconsistency = 1; + + PRINTF("ROLL TM: Inconsistency. Reset T%u\n", m); + reset_trickle_timer(m); + } + + /* Deliver if necessary */ + return UIP_MCAST6_ACCEPT; +} +/*---------------------------------------------------------------------------*/ +void +roll_tm_icmp_input() +{ + uint8_t inconsistency; + uint16_t *seq_ptr; + uint16_t *end_ptr; + uint16_t val; + +#if UIP_CONF_IPV6_CHECKS + if(!uip_is_addr_link_local(&UIP_IP_BUF->srcipaddr)) { + PRINTF("ROLL TM: ICMPv6 In, bad source "); + PRINT6ADDR(&UIP_IP_BUF->srcipaddr); + PRINTF(" to "); + PRINT6ADDR(&UIP_IP_BUF->destipaddr); + PRINTF("\n"); + ROLL_TM_STATS_ADD(icmp_bad); + return; + } + + if(!uip_is_addr_linklocal_allnodes_mcast(&UIP_IP_BUF->destipaddr) + && !uip_is_addr_linklocal_allrouters_mcast(&UIP_IP_BUF->destipaddr)) { + PRINTF("ROLL TM: ICMPv6 In, bad destination\n"); + ROLL_TM_STATS_ADD(icmp_bad); + return; + } + + if(UIP_ICMP_BUF->icode != ROLL_TM_ICMP_CODE) { + PRINTF("ROLL TM: ICMPv6 In, bad ICMP code\n"); + ROLL_TM_STATS_ADD(icmp_bad); + return; + } + + if(UIP_IP_BUF->ttl != ROLL_TM_IP_HOP_LIMIT) { + PRINTF("ROLL TM: ICMPv6 In, bad TTL\n"); + ROLL_TM_STATS_ADD(icmp_bad); + return; + } +#endif + + PRINTF("ROLL TM: ICMPv6 In from "); + PRINT6ADDR(&UIP_IP_BUF->srcipaddr); + PRINTF(" len %u, ext %u\n", uip_len, uip_ext_len); + + ROLL_TM_STATS_ADD(icmp_in); + + /* Reset Is-Listed bit for all windows */ + for(iterswptr = &windows[ROLL_TM_WINS - 1]; iterswptr >= windows; + iterswptr--) { + SLIDING_WINDOW_LISTED_CLR(iterswptr); + } + + /* Reset Is-Listed bit for all cached packets */ + for(locmpptr = &buffered_msgs[ROLL_TM_BUFF_NUM - 1]; + locmpptr >= buffered_msgs; locmpptr--) { + MCAST_PACKET_LISTED_CLR(locmpptr); + } + + locslhptr = (struct sequence_list_header *)UIP_ICMP_PAYLOAD; + + VERBOSE_PRINTF("ROLL TM: ICMPv6 In, parse from %p to %p\n", + UIP_ICMP_PAYLOAD, + (uint8_t *)UIP_ICMP_PAYLOAD + uip_len - + uip_l2_l3_icmp_hdr_len); + while(locslhptr < + (struct sequence_list_header *)((uint8_t *)UIP_ICMP_PAYLOAD + + uip_len - uip_l2_l3_icmp_hdr_len)) { + VERBOSE_PRINTF("ROLL TM: ICMPv6 In, seq hdr @ %p\n", locslhptr); + + if((locslhptr->flags & SEQUENCE_LIST_RES) != 0) { + PRINTF("ROLL TM: ICMPv6 In, non-zero reserved bits\n"); + goto drop; + } + + /* Drop unsupported Seed ID Lengths. S bit: 0->short, 1->long */ +#if ROLL_TM_SHORT_SEEDS + if(!SEQUENCE_LIST_GET_S(locslhptr)) { + ROLL_TM_STATS_ADD(icmp_bad); + goto drop; + } +#else + if(SEQUENCE_LIST_GET_S(locslhptr)) { + ROLL_TM_STATS_ADD(icmp_bad); + goto drop; + } +#endif + + PRINTF("ROLL TM: ICMPv6 In, Sequence List for Seed ID "); + PRINT_SEED(&locslhptr->seed_id); + PRINTF(" M=%u, S=%u, Len=%u\n", SEQUENCE_LIST_GET_M(locslhptr), + SEQUENCE_LIST_GET_S(locslhptr), locslhptr->seq_len); + + seq_ptr = (uint16_t *)((uint8_t *)locslhptr + + sizeof(struct sequence_list_header)); + end_ptr = (uint16_t *)((uint8_t *)locslhptr + + sizeof(struct sequence_list_header) + + locslhptr->seq_len * 2); + + /* Fetch a pointer to the corresponding trickle timer */ + loctpptr = &t[SEQUENCE_LIST_GET_M(locslhptr)]; + + locswptr = NULL; + + /* Find the sliding window for this Seed ID */ + locswptr = window_lookup(&locslhptr->seed_id, + SEQUENCE_LIST_GET_M(locslhptr)); + + /* If we have a window, iterate sequence values and check consistency */ + if(locswptr) { + SLIDING_WINDOW_LISTED_SET(locswptr); + locswptr->min_listed = -1; + PRINTF("ROLL TM: ICMPv6 In, Window bounds [%u , %u]\n", + locswptr->lower_bound, locswptr->upper_bound); + for(; seq_ptr < end_ptr; seq_ptr++) { + /* Check for "They have new" */ + /* If an advertised seq. val is GT our upper bound */ + val = uip_htons(*seq_ptr); + PRINTF("ROLL TM: ICMPv6 In, Check seq %u @ %p\n", val, seq_ptr); + if(SEQ_VAL_IS_GT(val, locswptr->upper_bound)) { + PRINTF("ROLL TM: Inconsistency - Advertised Seq. ID %u GT upper" + " bound %u\n", val, locswptr->upper_bound); + loctpptr->inconsistency = 1; + } + + /* If an advertised seq. val is within our bounds */ + if((SEQ_VAL_IS_LT(val, locswptr->upper_bound) || + SEQ_VAL_IS_EQ(val, locswptr->upper_bound)) && + (SEQ_VAL_IS_GT(val, locswptr->lower_bound) || + SEQ_VAL_IS_EQ(val, locswptr->lower_bound))) { + + inconsistency = 1; + /* Check if the advertised sequence is in our buffer */ + for(locmpptr = &buffered_msgs[ROLL_TM_BUFF_NUM - 1]; + locmpptr >= buffered_msgs; locmpptr--) { + if(MCAST_PACKET_IS_USED(locmpptr) && locmpptr->sw == locswptr) { + if(SEQ_VAL_IS_EQ(locmpptr->seq_val, val)) { + + inconsistency = 0; + MCAST_PACKET_LISTED_SET(locmpptr); + PRINTF("ROLL TM: ICMPv6 In, %u listed\n", locmpptr->seq_val); + + /* Update lowest seq. num listed for this window + * We need this to check for "we have new" */ + if(locswptr->min_listed == -1 || + SEQ_VAL_IS_LT(val, locswptr->min_listed)) { + locswptr->min_listed = val; + } + break; + } + } + } + if(inconsistency) { + PRINTF("ROLL TM: Inconsistency - "); + PRINTF("Advertised Seq. ID %u within bounds", val); + PRINTF(" [%u, %u] but no matching entry\n", + locswptr->lower_bound, locswptr->upper_bound); + loctpptr->inconsistency = 1; + } + } + } + } else { + /* A new sliding window in an ICMP message is not explicitly stated + * in the draft as inconsistency. Until this is clarified, we consider + * this to be a point where we diverge from the draft for performance + * improvement reasons (or as some would say, 'this is an extension') */ + PRINTF("ROLL TM: Inconsistency - Advertised window unknown to us\n"); + loctpptr->inconsistency = 1; + } + locslhptr = (struct sequence_list_header *)(((uint8_t *)locslhptr) + + sizeof(struct sequence_list_header) + (2 * locslhptr->seq_len)); + } + /* Done parsing the message */ + + /* Check for "We have new */ + PRINTF("ROLL TM: ICMPv6 In, Check our buffer\n"); + for(locmpptr = &buffered_msgs[ROLL_TM_BUFF_NUM - 1]; + locmpptr >= buffered_msgs; locmpptr--) { + if(MCAST_PACKET_IS_USED(locmpptr)) { + locswptr = locmpptr->sw; + PRINTF("ROLL TM: ICMPv6 In, "); + PRINTF("Check %u, Seed L: %u, This L: %u Min L: %d\n", + locmpptr->seq_val, SLIDING_WINDOW_IS_LISTED(locswptr), + MCAST_PACKET_IS_LISTED(locmpptr), locswptr->min_listed); + + /* Point to the sliding window's trickle param */ + loctpptr = &t[SLIDING_WINDOW_GET_M(locswptr)]; + if(!SLIDING_WINDOW_IS_LISTED(locswptr)) { + /* If a buffered packet's Seed ID was not listed */ + PRINTF("ROLL TM: Inconsistency - Seed ID "); + PRINT_SEED(&locswptr->seed_id); + PRINTF(" was not listed\n"); + loctpptr->inconsistency = 1; + MCAST_PACKET_SEND_SET(locmpptr); + } else { + /* This packet was not listed but a prior one was */ + if(!MCAST_PACKET_IS_LISTED(locmpptr) && + (locswptr->min_listed >= 0) && + SEQ_VAL_IS_GT(locmpptr->seq_val, locswptr->min_listed)) { + PRINTF("ROLL TM: Inconsistency - "); + PRINTF("Seq. %u was not listed but %u was\n", + locmpptr->seq_val, locswptr->min_listed); + loctpptr->inconsistency = 1; + MCAST_PACKET_SEND_SET(locmpptr); + } + } + } + } + +drop: + + if(t[0].inconsistency) { + reset_trickle_timer(0); + } else { + t[0].c++; + } + if(t[1].inconsistency) { + reset_trickle_timer(1); + } else { + t[1].c++; + } + + return; +} +/*---------------------------------------------------------------------------*/ +static void +out() +{ + + if(uip_len + HBHO_TOTAL_LEN > UIP_BUFSIZE) { + PRINTF("ROLL TM: Multicast Out can not add HBHO. Packet too long\n"); + goto drop; + } + + /* Slide 'right' by HBHO_TOTAL_LEN bytes */ + memmove(UIP_EXT_BUF_NEXT, UIP_EXT_BUF, uip_len - UIP_IPH_LEN); + memset(UIP_EXT_BUF, 0, HBHO_TOTAL_LEN); + + UIP_EXT_BUF->next = UIP_IP_BUF->proto; + UIP_EXT_BUF->len = 0; + + lochbhmptr = UIP_EXT_OPT_FIRST; + lochbhmptr->type = HBHO_OPT_TYPE_TRICKLE; + + /* Set the sequence ID */ + last_seq = SEQ_VAL_ADD(last_seq, 1); + lochbhmptr->flags = last_seq >> 8; + lochbhmptr->seq_id_lsb = last_seq & 0xFF; +#if ROLL_TM_SHORT_SEEDS + seed_id_cpy(&lochbhmptr->seed_id, &uip_lladdr.addr[UIP_LLADDR_LEN - 2]); + lochbhmptr->len = HBHO_LEN_SHORT_SEED; +#else + lochbhmptr->len = HBHO_LEN_LONG_SEED; + /* PadN */ + lochbhmptr->padn_type = UIP_EXT_HDR_OPT_PADN; + lochbhmptr->padn_len = 0; +#endif + + /* Set the M bit for our outgoing messages, if necessary */ +#if ROLL_TM_SET_M_BIT + HBH_SET_M(lochbhmptr); +#endif + + uip_ext_len += HBHO_TOTAL_LEN; + uip_len += HBHO_TOTAL_LEN; + + /* Update the proto and length field in the v6 header */ + UIP_IP_BUF->proto = UIP_PROTO_HBHO; + UIP_IP_BUF->len[0] = ((uip_len - UIP_IPH_LEN) >> 8); + UIP_IP_BUF->len[1] = ((uip_len - UIP_IPH_LEN) & 0xff); + + PRINTF("ROLL TM: Multicast Out, HBHO: T=%u, L=%u, M=%u, S=0x%02x%02x\n", + lochbhmptr->type, lochbhmptr->len, HBH_GET_M(lochbhmptr), + HBH_GET_SV_MSB(lochbhmptr), lochbhmptr->seq_id_lsb); + + /* + * We need to remember this message and advertise it in subsequent ICMP + * messages. Otherwise, our neighs will think we are inconsistent and will + * bounce it back to us. + * + * Queue this message but don't set its MUST_SEND flag. We reset the trickle + * timer and we send it immediately. We then set uip_len = 0 to stop the core + * from re-sending it. + */ + if(accept(ROLL_TM_DGRAM_OUT)) { + tcpip_output(NULL); + UIP_MCAST6_STATS_ADD(mcast_out); + } + +drop: + uip_slen = 0; + uip_len = 0; + uip_ext_len = 0; +} +/*---------------------------------------------------------------------------*/ +static uint8_t +in() +{ + /* + * We call accept() which will sort out caching and forwarding. Depending + * on accept()'s return value, we then need to signal the core + * whether to deliver this to higher layers + */ + if(accept(ROLL_TM_DGRAM_IN) == UIP_MCAST6_DROP) { + return UIP_MCAST6_DROP; + } + + if(!uip_ds6_is_my_maddr(&UIP_IP_BUF->destipaddr)) { + PRINTF("ROLL TM: Not a group member. No further processing\n"); + return UIP_MCAST6_DROP; + } else { + PRINTF("ROLL TM: Ours. Deliver to upper layers\n"); + UIP_MCAST6_STATS_ADD(mcast_in_ours); + return UIP_MCAST6_ACCEPT; + } +} +/*---------------------------------------------------------------------------*/ +static void +init() +{ + PRINTF("ROLL TM: ROLL Multicast - Draft #%u\n", ROLL_TM_VER); + + memset(windows, 0, sizeof(windows)); + memset(buffered_msgs, 0, sizeof(buffered_msgs)); + memset(t, 0, sizeof(t)); + + ROLL_TM_STATS_INIT(); + UIP_MCAST6_STATS_INIT(&stats); + + for(iterswptr = &windows[ROLL_TM_WINS - 1]; iterswptr >= windows; + iterswptr--) { + iterswptr->lower_bound = -1; + iterswptr->upper_bound = -1; + iterswptr->min_listed = -1; + } + + TIMER_CONFIGURE(0); + reset_trickle_timer(0); + TIMER_CONFIGURE(1); + reset_trickle_timer(1); + return; +} +/*---------------------------------------------------------------------------*/ +const struct uip_mcast6_driver roll_tm_driver = { + "ROLL TM", + init, + out, + in, +}; +/*---------------------------------------------------------------------------*/ + +#endif /* UIP_CONF_IPV6 */ diff --git a/core/net/ipv6/multicast/roll-tm.h b/core/net/ipv6/multicast/roll-tm.h new file mode 100644 index 000000000..2f7c88387 --- /dev/null +++ b/core/net/ipv6/multicast/roll-tm.h @@ -0,0 +1,232 @@ +/* + * Copyright (c) 2011, Loughborough University - Computer Science + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + */ + +/** + * \file + * Header file for IPv6 multicast according to the algorithm in the + * "MCAST Forwarding Using Trickle" internet draft. + * + * The current version of the draft can always be found in + * http://tools.ietf.org/html/draft-ietf-roll-trickle-mcast + * + * This implementation is based on the draft version stored in + * ROLL_TM_VER. + * + * In draft v2, the document was renamed to + * "Multicast Protocol for Low power and Lossy Networks (MPL)" + * Due to very significant changes between draft versions 1 and 2, + * MPL will be implemented as a separate engine and this file here + * will provide legacy support for Draft v1. + * + * \author + * George Oikonomou - + */ + +#ifndef ROLL_TM_H_ +#define ROLL_TM_H_ + +#include "contiki-conf.h" +#include "net/ipv6/multicast/uip-mcast6-stats.h" + +#include +/*---------------------------------------------------------------------------*/ +/* Protocol Constants */ +/*---------------------------------------------------------------------------*/ +#define ROLL_TM_VER 1 /* Supported Draft Version */ +#define ROLL_TM_ICMP_CODE 0 /* ICMPv6 code field */ +#define ROLL_TM_IP_HOP_LIMIT 0xFF /* Hop limit for ICMP messages */ +#define ROLL_TM_INFINITE_REDUNDANCY 0xFF +#define ROLL_TM_DGRAM_OUT 0 +#define ROLL_TM_DGRAM_IN 1 + +/* + * The draft does not currently specify a default number for the trickle + * interval nor a way to derive it. Examples however hint at 100 msec. + * + * In draft terminology, we use an 'aggressive' policy (M=0) and a conservative + * one (M=1). + * + * When experimenting with the two policies on the sky platform, + * an interval of 125ms proves to be way too low: When we have traffic, + * doublings happen after the interval end and periodics fire after point T + * within the interval (and sometimes even after interval end). When traffic + * settles down, the code compensates the offsets. + * + * We consider 125, 250ms etc because they are nice divisors of 1 sec + * (quotient is power of two). For some machines (e.g sky/msp430, + * sensinode/cc243x), this is also a nice number of clock ticks + * + * After experimentation, the values of Imin leading to best performance are: + * ContikiMAC: Imin=64 (500ms) + * Null RDC: imin=16 (125ms) + */ + +/* Configuration for Timer with M=0 (aggressive) */ +#ifdef ROLL_TM_CONF_IMIN_0 +#define ROLL_TM_IMIN_0 ROLL_TM_CONF_IMIN_0 +#else +#define ROLL_TM_IMIN_0 32 /* 250 msec */ +#endif + +#ifdef ROLL_TM_CONF_IMAX_0 +#define ROLL_TM_IMAX_0 ROLL_TM_CONF_IMAX_0 +#else +#define ROLL_TM_IMAX_0 1 /* Imax = 500ms */ +#endif + +#ifdef ROLL_TM_CONF_K_0 +#define ROLL_TM_K_0 ROLL_TM_CONF_K_0 +#else +#define ROLL_TM_K_0 ROLL_TM_INFINITE_REDUNDANCY +#endif + +#ifdef ROLL_TM_CONF_T_ACTIVE_0 +#define ROLL_TM_T_ACTIVE_0 ROLL_TM_CONF_T_ACTIVE_0 +#else +#define ROLL_TM_T_ACTIVE_0 3 +#endif + +#ifdef ROLL_TM_CONF_T_DWELL_0 +#define ROLL_TM_T_DWELL_0 ROLL_TM_CONF_T_DWELL_0 +#else +#define ROLL_TM_T_DWELL_0 11 +#endif + +/* Configuration for Timer with M=1 (conservative) */ +#ifdef ROLL_TM_CONF_IMIN_1 +#define ROLL_TM_IMIN_1 ROLL_TM_CONF_IMIN_1 +#else +#define ROLL_TM_IMIN_1 64 /* 500 msec */ +#endif + +#ifdef ROLL_TM_CONF_IMAX_1 +#define ROLL_TM_IMAX_1 ROLL_TM_CONF_IMAX_1 +#else +#define ROLL_TM_IMAX_1 9 /* Imax = 256 secs */ +#endif + +#ifdef ROLL_TM_CONF_K_1 +#define ROLL_TM_K_1 ROLL_TM_CONF_K_1 +#else +#define ROLL_TM_K_1 1 +#endif + +#ifdef ROLL_TM_CONF_T_ACTIVE_1 +#define ROLL_TM_T_ACTIVE_1 ROLL_TM_CONF_T_ACTIVE_1 +#else +#define ROLL_TM_T_ACTIVE_1 3 +#endif + +#ifdef ROLL_TM_CONF_T_DWELL_1 +#define ROLL_TM_T_DWELL_1 ROLL_TM_CONF_T_DWELL_1 +#else +#define ROLL_TM_T_DWELL_1 12 +#endif +/*---------------------------------------------------------------------------*/ +/* Configuration */ +/*---------------------------------------------------------------------------*/ +/* + * Number of Sliding Windows + * In essence: How many unique sources of simultaneous multicast traffic do we + * want to support for our lowpan + * If a node is seeding two multicast streams, parametrized on different M + * values, then this seed will occupy two different sliding windows + */ +#ifdef ROLL_TM_CONF_WINS +#define ROLL_TM_WINS ROLL_TM_CONF_WINS +#else +#define ROLL_TM_WINS 2 +#endif +/*---------------------------------------------------------------------------*/ +/* + * Maximum Number of Buffered Multicast Messages + * This buffer is shared across all Seed IDs, therefore a new very active Seed + * may eventually occupy all slots. It would make little sense (if any) to + * define support for fewer buffered messages than seeds*2 + */ +#ifdef ROLL_TM_CONF_BUFF_NUM +#define ROLL_TM_BUFF_NUM ROLL_TM_CONF_BUFF_NUM +#else +#define ROLL_TM_BUFF_NUM 6 +#endif +/*---------------------------------------------------------------------------*/ +/* + * Use Short Seed IDs [short: 2, long: 16 (default)] + * It can be argued that we should (and it would be easy to) support both at + * the same time but the draft doesn't list this as a MUST so we opt for + * code/ram savings + */ +#ifdef ROLL_TM_CONF_SHORT_SEEDS +#define ROLL_TM_SHORT_SEEDS ROLL_TM_CONF_SHORT_SEEDS +#else +#define ROLL_TM_SHORT_SEEDS 0 +#endif +/*---------------------------------------------------------------------------*/ +/* + * Destination address for our ICMPv6 advertisements. The draft gives us a + * choice between LL all-nodes or LL all-routers + * + * We use allrouters unless a conf directive chooses otherwise + */ +#ifdef ROLL_TM_CONF_DEST_ALL_NODES +#define ROLL_TM_DEST_ALL_NODES ROLL_TM_CONF_DEST_ALL_NODES +#else +#define ROLL_TM_DEST_ALL_NODES 0 +#endif +/*---------------------------------------------------------------------------*/ +/* + * M param for our outgoing messages + * By default, we set the M bit (conservative). Define this as 0 to clear the + * M bit in our outgoing messages (aggressive) + */ +#ifdef ROLL_TM_CONF_SET_M_BIT +#define ROLL_TM_SET_M_BIT ROLL_TM_CONF_SET_M_BIT +#else +#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 { + UIP_MCAST6_STATS_DATATYPE icmp_in; + UIP_MCAST6_STATS_DATATYPE icmp_out; + UIP_MCAST6_STATS_DATATYPE icmp_bad; +}; + +#endif /* ROLL_TM_H_ */ diff --git a/core/net/ipv6/multicast/smrf.c b/core/net/ipv6/multicast/smrf.c new file mode 100644 index 000000000..8a80a4142 --- /dev/null +++ b/core/net/ipv6/multicast/smrf.c @@ -0,0 +1,211 @@ +/* + * Copyright (c) 2010, Loughborough University - Computer Science + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + */ + +/** + * \file + * This file implements 'Stateless Multicast RPL Forwarding' (SMRF) + * + * It will only work in RPL networks in MOP 3 "Storing with Multicast" + * + * \author + * George Oikonomou - + */ + +#include "contiki.h" +#include "contiki-net.h" +#include "net/ipv6/multicast/uip-mcast6.h" +#include "net/ipv6/multicast/uip-mcast6-route.h" +#include "net/ipv6/multicast/uip-mcast6-stats.h" +#include "net/ipv6/multicast/smrf.h" +#include "net/rpl/rpl.h" +#include "net/netstack.h" +#include + +#define DEBUG DEBUG_NONE +#include "net/ip/uip-debug.h" + +#if UIP_CONF_IPV6 +/*---------------------------------------------------------------------------*/ +/* Macros */ +/*---------------------------------------------------------------------------*/ +/* CCI */ +#define SMRF_FWD_DELAY() NETSTACK_RDC.channel_check_interval() +/* Number of slots in the next 500ms */ +#define SMRF_INTERVAL_COUNT ((CLOCK_SECOND >> 2) / fwd_delay) +/*---------------------------------------------------------------------------*/ +/* Internal Data */ +/*---------------------------------------------------------------------------*/ +static struct ctimer mcast_periodic; +static uint8_t mcast_len; +static uip_buf_t mcast_buf; +static uint8_t fwd_delay; +static uint8_t fwd_spread; +/*---------------------------------------------------------------------------*/ +/* uIPv6 Pointers */ +/*---------------------------------------------------------------------------*/ +#define UIP_IP_BUF ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN]) +/*---------------------------------------------------------------------------*/ +static void +mcast_fwd(void *p) +{ + memcpy(uip_buf, &mcast_buf, mcast_len); + uip_len = mcast_len; + UIP_IP_BUF->ttl--; + tcpip_output(NULL); + uip_len = 0; +} +/*---------------------------------------------------------------------------*/ +static uint8_t +in() +{ + rpl_dag_t *d; /* Our DODAG */ + uip_ipaddr_t *parent_ipaddr; /* Our pref. parent's IPv6 address */ + const uip_lladdr_t *parent_lladdr; /* Our pref. parent's LL address */ + + /* + * Fetch a pointer to the LL address of our preferred parent + * + * ToDo: This rpl_get_any_dag() call is a dirty replacement of the previous + * rpl_get_dag(RPL_DEFAULT_INSTANCE); + * so that things can compile with the new RPL code. This needs updated to + * read instance ID from the RPL HBHO and use the correct parent accordingly + */ + d = rpl_get_any_dag(); + if(!d) { + UIP_MCAST6_STATS_ADD(mcast_dropped); + return UIP_MCAST6_DROP; + } + + /* Retrieve our preferred parent's LL address */ + parent_ipaddr = rpl_get_parent_ipaddr(d->preferred_parent); + parent_lladdr = uip_ds6_nbr_lladdr_from_ipaddr(parent_ipaddr); + + if(parent_lladdr == NULL) { + UIP_MCAST6_STATS_ADD(mcast_dropped); + return UIP_MCAST6_DROP; + } + + /* + * We accept a datagram if it arrived from our preferred parent, discard + * otherwise. + */ + if(memcmp(parent_lladdr, packetbuf_addr(PACKETBUF_ADDR_SENDER), + UIP_LLADDR_LEN)) { + PRINTF("SMRF: Routable in but SMRF ignored it\n"); + UIP_MCAST6_STATS_ADD(mcast_dropped); + return UIP_MCAST6_DROP; + } + + if(UIP_IP_BUF->ttl <= 1) { + UIP_MCAST6_STATS_ADD(mcast_dropped); + return UIP_MCAST6_DROP; + } + + UIP_MCAST6_STATS_ADD(mcast_in_all); + UIP_MCAST6_STATS_ADD(mcast_in_unique); + + /* If we have an entry in the mcast routing table, something with + * a higher RPL rank (somewhere down the tree) is a group member */ + if(uip_mcast6_route_lookup(&UIP_IP_BUF->destipaddr)) { + /* If we enter here, we will definitely forward */ + UIP_MCAST6_STATS_ADD(mcast_fwd); + + /* + * Add a delay (D) of at least SMRF_FWD_DELAY() to compensate for how + * contikimac handles broadcasts. We can't start our TX before the sender + * has finished its own. + */ + fwd_delay = SMRF_FWD_DELAY(); + + /* Finalise D: D = min(SMRF_FWD_DELAY(), SMRF_MIN_FWD_DELAY) */ +#if SMRF_MIN_FWD_DELAY + if(fwd_delay < SMRF_MIN_FWD_DELAY) { + fwd_delay = SMRF_MIN_FWD_DELAY; + } +#endif + + if(fwd_delay == 0) { + /* No delay required, send it, do it now, why wait? */ + UIP_IP_BUF->ttl--; + tcpip_output(NULL); + UIP_IP_BUF->ttl++; /* Restore before potential upstack delivery */ + } else { + /* Randomise final delay in [D , D*Spread], step D */ + fwd_spread = SMRF_INTERVAL_COUNT; + if(fwd_spread > SMRF_MAX_SPREAD) { + fwd_spread = SMRF_MAX_SPREAD; + } + if(fwd_spread) { + fwd_delay = fwd_delay * (1 + ((random_rand() >> 11) % fwd_spread)); + } + + memcpy(&mcast_buf, uip_buf, uip_len); + mcast_len = uip_len; + ctimer_set(&mcast_periodic, fwd_delay, mcast_fwd, NULL); + } + PRINTF("SMRF: %u bytes: fwd in %u [%u]\n", + uip_len, fwd_delay, fwd_spread); + } + + /* Done with this packet unless we are a member of the mcast group */ + if(!uip_ds6_is_my_maddr(&UIP_IP_BUF->destipaddr)) { + PRINTF("SMRF: Not a group member. No further processing\n"); + return UIP_MCAST6_DROP; + } else { + PRINTF("SMRF: Ours. Deliver to upper layers\n"); + UIP_MCAST6_STATS_ADD(mcast_in_ours); + return UIP_MCAST6_ACCEPT; + } +} +/*---------------------------------------------------------------------------*/ +static void +init() +{ + UIP_MCAST6_STATS_INIT(NULL); + + uip_mcast6_route_init(); +} +/*---------------------------------------------------------------------------*/ +static void +out() +{ + return; +} +/*---------------------------------------------------------------------------*/ +const struct uip_mcast6_driver smrf_driver = { + "SMRF", + init, + out, + in, +}; +/*---------------------------------------------------------------------------*/ + +#endif /* UIP_CONF_IPV6 */ diff --git a/core/net/ipv6/multicast/smrf.h b/core/net/ipv6/multicast/smrf.h new file mode 100644 index 000000000..d19fd6de8 --- /dev/null +++ b/core/net/ipv6/multicast/smrf.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2011, Loughborough University - Computer Science + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + */ + +/** + * \file + * Header file for 'Stateless Multicast RPL Forwarding' (SMRF) + * + * \author + * George Oikonomou - + */ + +#ifndef SMRF_H_ +#define SMRF_H_ + +#include "contiki-conf.h" + +#include +/*---------------------------------------------------------------------------*/ +/* Configuration */ +/*---------------------------------------------------------------------------*/ +/* Fmin */ +#ifdef SMRF_CONF_MIN_FWD_DELAY +#define SMRF_MIN_FWD_DELAY SMRF_CONF_MIN_FWD_DELAY +#else +#define SMRF_MIN_FWD_DELAY 4 +#endif + +/* Max Spread */ +#ifdef SMRF_CONF_MAX_SPREAD +#define SMRF_MAX_SPREAD SMRF_CONF_MAX_SPREAD +#else +#define SMRF_MAX_SPREAD 4 +#endif +/*---------------------------------------------------------------------------*/ +/* Stats datatype */ +/*---------------------------------------------------------------------------*/ +struct smrf_stats { + uint16_t mcast_in_unique; + uint16_t mcast_in_all; /* At layer 3 */ + uint16_t mcast_in_ours; /* Unique and we are a group member */ + uint16_t mcast_fwd; /* Forwarded by us but we are not the seed */ + uint16_t mcast_out; /* We are the seed */ + uint16_t mcast_bad; + uint16_t mcast_dropped; +}; + +#endif /* SMRF_H_ */ diff --git a/core/net/ipv6/multicast/uip-mcast6-engines.h b/core/net/ipv6/multicast/uip-mcast6-engines.h new file mode 100644 index 000000000..cea3c9ecc --- /dev/null +++ b/core/net/ipv6/multicast/uip-mcast6-engines.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2011, Loughborough University - Computer Science + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + */ + +/** + * \file + * Header file with definition of multicast engine constants + * + * When writing a new engine, add it here with a unique number and + * then modify uip-mcast6.h accordingly + * + * \author + * George Oikonomou - + */ + +#ifndef UIP_MCAST6_ENGINES_H_ +#define UIP_MCAST6_ENGINES_H_ + +#define UIP_MCAST6_ENGINE_NONE 0 /* Selecting this disables mcast */ +#define UIP_MCAST6_ENGINE_SMRF 1 +#define UIP_MCAST6_ENGINE_ROLL_TM 2 + +#endif /* UIP_MCAST6_ENGINES_H_ */ diff --git a/core/net/ipv6/multicast/uip-mcast6-route.c b/core/net/ipv6/multicast/uip-mcast6-route.c new file mode 100644 index 000000000..f99a92818 --- /dev/null +++ b/core/net/ipv6/multicast/uip-mcast6-route.c @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2011, Loughborough University - Computer Science + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/** + * \file + * Multicast routing table manipulation + * + * \author + * George Oikonomou - + */ + +#include "contiki.h" +#include "lib/list.h" +#include "lib/memb.h" +#include "net/ip/uip.h" +#include "net/ipv6/multicast/uip-mcast6-route.h" + +#include +#include + +#if UIP_CONF_IPV6 +/*---------------------------------------------------------------------------*/ +/* Size of the multicast routing table */ +#ifdef UIP_MCAST6_ROUTE_CONF_ROUTES +#define UIP_MCAST6_ROUTE_ROUTES UIP_MCAST6_ROUTE_CONF_ROUTES +#else +#define UIP_MCAST6_ROUTE_ROUTES 1 +#endif /* UIP_CONF_DS6_MCAST_ROUTES */ +/*---------------------------------------------------------------------------*/ +LIST(mcast_route_list); +MEMB(mcast_route_memb, uip_mcast6_route_t, UIP_MCAST6_ROUTE_ROUTES); + +static uip_mcast6_route_t *locmcastrt; +/*---------------------------------------------------------------------------*/ +uip_mcast6_route_t * +uip_mcast6_route_lookup(uip_ipaddr_t *group) +{ + locmcastrt = NULL; + for(locmcastrt = list_head(mcast_route_list); + locmcastrt != NULL; + locmcastrt = list_item_next(locmcastrt)) { + if(uip_ipaddr_cmp(&locmcastrt->group, group)) { + return locmcastrt; + } + } + + return NULL; +} +/*---------------------------------------------------------------------------*/ +uip_mcast6_route_t * +uip_mcast6_route_add(uip_ipaddr_t *group) +{ + /* _lookup must return NULL, i.e. the prefix does not exist in our table */ + locmcastrt = uip_mcast6_route_lookup(group); + if(locmcastrt == NULL) { + /* Allocate an entry and add the group to the list */ + locmcastrt = memb_alloc(&mcast_route_memb); + if(locmcastrt == NULL) { + return NULL; + } + list_add(mcast_route_list, locmcastrt); + } + + /* Reaching here means we either found the prefix or allocated a new one */ + + uip_ipaddr_copy(&(locmcastrt->group), group); + + return locmcastrt; +} +/*---------------------------------------------------------------------------*/ +void +uip_mcast6_route_rm(uip_mcast6_route_t *route) +{ + /* Make sure it's actually in the list */ + for(locmcastrt = list_head(mcast_route_list); + locmcastrt != NULL; + locmcastrt = list_item_next(locmcastrt)) { + if(locmcastrt == route) { + list_remove(mcast_route_list, route); + memb_free(&mcast_route_memb, route); + return; + } + } +} +/*---------------------------------------------------------------------------*/ +uip_mcast6_route_t * +uip_mcast6_route_list_head(void) +{ + return list_head(mcast_route_list); +} +/*---------------------------------------------------------------------------*/ +int +uip_mcast6_route_count(void) +{ + return list_length(mcast_route_list); +} +/*---------------------------------------------------------------------------*/ +void +uip_mcast6_route_init() +{ + memb_init(&mcast_route_memb); + list_init(mcast_route_list); +} +/*---------------------------------------------------------------------------*/ + +#endif /* UIP_CONF_IPV6 */ diff --git a/core/net/ipv6/multicast/uip-mcast6-route.h b/core/net/ipv6/multicast/uip-mcast6-route.h new file mode 100644 index 000000000..ef5d43f77 --- /dev/null +++ b/core/net/ipv6/multicast/uip-mcast6-route.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2011, Loughborough University - Computer Science + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/** + * \file + * Multicast routing table manipulation + * + * \author + * George Oikonomou - + */ +#ifndef UIP_MCAST6_ROUTE_H_ +#define UIP_MCAST6_ROUTE_H_ + +#include "contiki.h" +#include "net/ip/uip.h" + +#include +/*---------------------------------------------------------------------------*/ +/** \brief An entry in the multicast routing table */ +typedef struct uip_mcast6_route { + struct uip_mcast6_route *next; + uip_ipaddr_t group; + uint32_t lifetime; /* seconds */ + void *dag; /* Pointer to an rpl_dag_t struct */ +} uip_mcast6_route_t; +/*---------------------------------------------------------------------------*/ +/** \name Multicast Routing Table Manipulation */ +/** @{ */ +uip_mcast6_route_t *uip_mcast6_route_lookup(uip_ipaddr_t *group); +uip_mcast6_route_t *uip_mcast6_route_add(uip_ipaddr_t *group); +void uip_mcast6_route_rm(uip_mcast6_route_t *defrt); +int uip_mcast6_route_count(void); +uip_mcast6_route_t *uip_mcast6_route_list_head(void); +/*---------------------------------------------------------------------------*/ +/** + * \brief Multicast routing table init routine + * + * Multicast routing tables are not necessarily required by all + * multicast engines. For instance, trickle multicast does not rely on + * the existence of a routing table. Therefore, this function here + * should be invoked by each engine's init routine only if the relevant + * functionality is required. This is also why this function should not + * get hooked into the uip-ds6 core. + */ +void uip_mcast6_route_init(void); +/** @} */ + +#endif /* UIP_MCAST6_ROUTE_H_ */ diff --git a/core/net/ipv6/multicast/uip-mcast6-stats.c b/core/net/ipv6/multicast/uip-mcast6-stats.c new file mode 100644 index 000000000..ed23747f1 --- /dev/null +++ b/core/net/ipv6/multicast/uip-mcast6-stats.c @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2014, University of Bristol - http://www.bris.ac.uk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/** + * \file + * IPv6 multicast forwarding stats maintenance + * + * \author + * George Oikonomou - + */ +#include "net/ipv6/multicast/uip-mcast6-stats.h" + +#include +/*---------------------------------------------------------------------------*/ +uip_mcast6_stats_t uip_mcast6_stats; +/*---------------------------------------------------------------------------*/ +void +uip_mcast6_stats_init(void *stats) +{ + memset(&uip_mcast6_stats, 0, sizeof(uip_mcast6_stats)); + uip_mcast6_stats.engine_stats = stats; +} +/*---------------------------------------------------------------------------*/ diff --git a/core/net/ipv6/multicast/uip-mcast6-stats.h b/core/net/ipv6/multicast/uip-mcast6-stats.h new file mode 100644 index 000000000..1e3775934 --- /dev/null +++ b/core/net/ipv6/multicast/uip-mcast6-stats.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2014, University of Bristol - http://www.bris.ac.uk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/** + * \file + * Header file for IPv6 multicast forwarding stats maintenance + * + * \author + * George Oikonomou - + */ +#ifndef UIP_MCAST6_STATS_H_ +#define UIP_MCAST6_STATS_H_ +/*---------------------------------------------------------------------------*/ +#include "contiki-conf.h" + +#include +/*---------------------------------------------------------------------------*/ +/* The platform can override the stats datatype */ +#ifdef UIP_MCAST6_CONF_STATS_DATATYPE +#define UIP_MCAST6_STATS_DATATYPE UIP_MCAST6_CONF_STATS_DATATYPE +#else +#define UIP_MCAST6_STATS_DATATYPE uint16_t +#endif +/*---------------------------------------------------------------------------*/ +#ifdef UIP_MCAST6_CONF_STATS +#define UIP_MCAST6_STATS UIP_MCAST6_CONF_STATS +#else +#define UIP_MCAST6_STATS 0 +#endif +/*---------------------------------------------------------------------------*/ +/* Stats datatype */ +/*---------------------------------------------------------------------------*/ +typedef struct uip_mcast6_stats { + UIP_MCAST6_STATS_DATATYPE mcast_in_unique; + UIP_MCAST6_STATS_DATATYPE mcast_in_all; /* At layer 3 */ + UIP_MCAST6_STATS_DATATYPE mcast_in_ours; /* Unique and we are a group member */ + UIP_MCAST6_STATS_DATATYPE mcast_fwd; /* Forwarded by us but we are not the seed */ + UIP_MCAST6_STATS_DATATYPE mcast_out; /* We are the seed */ + UIP_MCAST6_STATS_DATATYPE mcast_bad; + UIP_MCAST6_STATS_DATATYPE mcast_dropped; + void *engine_stats; /* Opaque pointer to an engine's additional stats */ +} uip_mcast6_stats_t; +/*---------------------------------------------------------------------------*/ +/* Access macros */ +/*---------------------------------------------------------------------------*/ +#if UIP_MCAST6_STATS +/* Don't access this variable directly, use the macros below */ +extern uip_mcast6_stats_t uip_mcast6_stats; + +#define UIP_MCAST6_STATS_ADD(x) uip_mcast6_stats.x++ +#define UIP_MCAST6_STATS_GET(x) uip_mcast6_stats.x +#define UIP_MCAST6_STATS_INIT(s) uip_mcast6_stats_init(s) +#else /* UIP_MCAST6_STATS */ +#define UIP_MCAST6_STATS_ADD(x) +#define UIP_MCAST6_STATS_GET(x) 0 +#define UIP_MCAST6_STATS_INIT(s) +#endif /* UIP_MCAST6_STATS */ +/*---------------------------------------------------------------------------*/ +/** + * \brief Initialise multicast stats + * \param stats A pointer to a struct holding an engine's additional statistics + */ +void uip_mcast6_stats_init(void *stats); +/*---------------------------------------------------------------------------*/ +#endif /* UIP_MCAST6_STATS_H_ */ diff --git a/core/net/ipv6/multicast/uip-mcast6.h b/core/net/ipv6/multicast/uip-mcast6.h new file mode 100644 index 000000000..9bd2b2b2d --- /dev/null +++ b/core/net/ipv6/multicast/uip-mcast6.h @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2011, Loughborough University - Computer Science + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + */ + +/** + * \file + * This header file contains configuration directives for uIPv6 + * multicast support. + * + * We currently support 2 engines: + * - 'Stateless Multicast RPL Forwarding' (SMRF) + * RPL does group management as per the RPL docs, SMRF handles datagram + * forwarding + * - 'Multicast Forwarding with Trickle' according to the algorithm described + * in the internet draft: + * http://tools.ietf.org/html/draft-ietf-roll-trickle-mcast + * + * \author + * George Oikonomou - + */ + +#ifndef UIP_MCAST6_H_ +#define UIP_MCAST6_H_ + +#include "contiki-conf.h" +#include "net/ipv6/multicast/uip-mcast6-engines.h" +#include "net/ipv6/multicast/uip-mcast6-route.h" +#include "net/ipv6/multicast/smrf.h" +#include "net/ipv6/multicast/roll-tm.h" + +#include +/*---------------------------------------------------------------------------*/ +/* Constants */ +/*---------------------------------------------------------------------------*/ +#define UIP_MCAST6_DROP 0 +#define UIP_MCAST6_ACCEPT 1 +/*---------------------------------------------------------------------------*/ +/* Multicast Address Scopes (RFC 4291 & draft-ietf-6man-multicast-scopes) */ +#define UIP_MCAST6_SCOPE_INTERFACE 0x01 +#define UIP_MCAST6_SCOPE_LINK_LOCAL 0x02 +#define UIP_MCAST6_SCOPE_REALM_LOCAL 0x03 /* draft-ietf-6man-multicast-scopes */ +#define UIP_MCAST6_SCOPE_ADMIN_LOCAL 0x04 +#define UIP_MCAST6_SCOPE_SITE_LOCAL 0x05 +#define UIP_MCAST6_SCOPE_ORG_LOCAL 0x08 +#define UIP_MCAST6_SCOPE_GLOBAL 0x0E +/*---------------------------------------------------------------------------*/ +/* Choose an engine or turn off based on user configuration */ +/*---------------------------------------------------------------------------*/ +#ifdef UIP_MCAST6_CONF_ENGINE +#define UIP_MCAST6_ENGINE UIP_MCAST6_CONF_ENGINE +#else +#define UIP_MCAST6_ENGINE UIP_MCAST6_ENGINE_NONE +#endif +/*---------------------------------------------------------------------------*/ +/* + * Multicast API. Similar to NETSTACK, each engine must define a driver and + * populate the fields with suitable function pointers + */ +struct uip_mcast6_driver { + char *name; + + /** Initialize the multicast engine */ + void (* init)(void); + + /** + * \brief Process an outgoing datagram with a multicast IPv6 destination + * address + * + * This may be needed if the multicast engine needs to, for example, + * add IPv6 extension headers to the datagram, cache it, decide it + * needs dropped etc. + * + * It is sometimes desirable to let the engine handle datagram + * dispatch instead of letting the networking core do it. If the + * engine decides to send the datagram itself, it must afterwards + * set uip_len = 0 to prevent the networking core from sending too + */ + void (* out)(void); + + /** + * \brief Process an incoming multicast datagram and determine whether it + * should be delivered up the stack or not. + * + * \return 0: Drop, 1: Deliver + * + * When a datagram with a multicast destination address is received, + * the forwarding logic in core is bypassed. Instead, we let the + * multicast engine handle forwarding internally if and as necessary. + * This function is where forwarding logic must be hooked in. + * + * Once the engine is done with forwarding, it must signal via the + * return value whether the datagram needs delivered up the network + * stack. + */ + uint8_t (* in)(void); +}; +/*---------------------------------------------------------------------------*/ +/** + * \brief Get a multicast address' scope. + * a is of type uip_ip6addr_t* + */ +#define uip_mcast6_get_address_scope(a) ((a)->u8[1] & 0x0F) +/*---------------------------------------------------------------------------*/ +/* Configure multicast and core/net to play nicely with the selected engine */ +#if UIP_MCAST6_ENGINE + +/* Enable Multicast hooks in the uip6 core */ +#define UIP_CONF_IPV6_MULTICAST 1 + +#if UIP_MCAST6_ENGINE == UIP_MCAST6_ENGINE_ROLL_TM +#define RPL_CONF_MULTICAST 0 /* Not used by trickle */ +#define UIP_CONF_IPV6_ROLL_TM 1 /* ROLL Trickle ICMP type support */ + +#define UIP_MCAST6 roll_tm_driver +#elif UIP_MCAST6_ENGINE == UIP_MCAST6_ENGINE_SMRF +#define RPL_CONF_MULTICAST 1 + +#define UIP_MCAST6 smrf_driver +#else +#error "Multicast Enabled with an Unknown Engine." +#error "Check the value of UIP_MCAST6_CONF_ENGINE in conf files." +#endif +#endif /* UIP_MCAST6_ENGINE */ + +extern const struct uip_mcast6_driver UIP_MCAST6; +/*---------------------------------------------------------------------------*/ +/* Configuration Checks */ +/*---------------------------------------------------------------------------*/ +#if RPL_CONF_MULTICAST && (!UIP_CONF_IPV6_RPL) +#error "The selected Multicast mode requires UIP_CONF_IPV6_RPL != 0" +#error "Check the value of UIP_CONF_IPV6_RPL in conf files." +#endif +/*---------------------------------------------------------------------------*/ + +#endif /* UIP_MCAST6_H_ */ diff --git a/core/net/ipv6/uip-ds6.c b/core/net/ipv6/uip-ds6.c index 3594f46e1..c5c169afe 100644 --- a/core/net/ipv6/uip-ds6.c +++ b/core/net/ipv6/uip-ds6.c @@ -512,6 +512,10 @@ uip_ds6_select_src(uip_ipaddr_t *src, uip_ipaddr_t *dst) } } } +#if UIP_IPV6_MULTICAST + } else if(uip_is_addr_mcast_routable(dst)) { + matchaddr = uip_ds6_get_global(ADDR_PREFERRED); +#endif } else { matchaddr = uip_ds6_get_link_local(ADDR_PREFERRED); } diff --git a/core/net/ipv6/uip-icmp6.h b/core/net/ipv6/uip-icmp6.h index 9441cbc0e..fd5f7136f 100644 --- a/core/net/ipv6/uip-icmp6.h +++ b/core/net/ipv6/uip-icmp6.h @@ -65,6 +65,11 @@ #define ICMP6_REDIRECT 137 /**< Redirect */ #define ICMP6_RPL 155 /**< RPL */ +#define ICMP6_PRIV_EXP_100 100 /**< Private Experimentation */ +#define ICMP6_PRIV_EXP_101 101 /**< Private Experimentation */ +#define ICMP6_PRIV_EXP_200 200 /**< Private Experimentation */ +#define ICMP6_PRIV_EXP_201 201 /**< Private Experimentation */ +#define ICMP6_ROLL_TM ICMP6_PRIV_EXP_200 /**< ROLL Trickle Multicast */ /** @} */ diff --git a/core/net/ipv6/uip6.c b/core/net/ipv6/uip6.c index fc3d244d2..f8553a336 100644 --- a/core/net/ipv6/uip6.c +++ b/core/net/ipv6/uip6.c @@ -75,6 +75,7 @@ #include "net/ipv6/uip-icmp6.h" #include "net/ipv6/uip-nd6.h" #include "net/ipv6/uip-ds6.h" +#include "net/ipv6/multicast/uip-mcast6.h" #include @@ -429,6 +430,10 @@ uip_init(void) uip_udp_conns[c].lport = 0; } #endif /* UIP_UDP */ + +#if UIP_CONF_IPV6_MULTICAST + UIP_MCAST6.init(); +#endif } /*---------------------------------------------------------------------------*/ #if UIP_TCP && UIP_ACTIVE_OPEN @@ -1151,6 +1156,28 @@ uip_process(uint8_t flag) } } + /* + * Process Packets with a routable multicast destination: + * - We invoke the multicast engine and let it do its thing + * (cache, forward etc). + * - We never execute the datagram forwarding logic in this file here. When + * the engine returns, forwarding has been handled if and as required. + * - Depending on the return value, we either discard or deliver up the stack + * + * All multicast engines must hook in here. After this function returns, we + * expect UIP_BUF to be unmodified + */ +#if UIP_CONF_IPV6_MULTICAST + if(uip_is_addr_mcast_routable(&UIP_IP_BUF->destipaddr)) { + if(UIP_MCAST6.in() == UIP_MCAST6_ACCEPT) { + /* Deliver up the stack */ + goto process; + } else { + /* Don't deliver up the stack */ + goto drop; + } + } +#endif /* UIP_IPV6_CONF_MULTICAST */ /* TBD Some Parameter problem messages */ if(!uip_ds6_is_my_addr(&UIP_IP_BUF->destipaddr) && @@ -1220,6 +1247,10 @@ uip_process(uint8_t flag) uip_ext_bitmap = 0; #endif /* UIP_CONF_ROUTER */ +#if UIP_CONF_IPV6_MULTICAST + process: +#endif + while(1) { switch(*uip_next_hdr){ #if UIP_TCP @@ -1437,6 +1468,12 @@ uip_process(uint8_t flag) 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); diff --git a/core/net/rpl/rpl-dag.c b/core/net/rpl/rpl-dag.c index e83e790bc..e103d65f9 100644 --- a/core/net/rpl/rpl-dag.c +++ b/core/net/rpl/rpl-dag.c @@ -38,6 +38,7 @@ * Logic for Directed Acyclic Graphs in RPL. * * \author Joakim Eriksson , Nicolas Tsiftes + * Contributors: George Oikonomou (multicast) */ @@ -46,6 +47,7 @@ #include "net/ip/uip.h" #include "net/ipv6/uip-nd6.h" #include "net/nbr-table.h" +#include "net/ipv6/multicast/uip-mcast6.h" #include "lib/list.h" #include "lib/memb.h" #include "sys/ctimer.h" @@ -1147,7 +1149,13 @@ rpl_process_dio(uip_ipaddr_t *from, rpl_dio_t *dio) rpl_dag_t *dag, *previous_dag; rpl_parent_t *p; +#if RPL_CONF_MULTICAST + /* If the root is advertising MOP 2 but we support MOP 3 we can still join + * In that scenario, we suppress DAOs for multicast targets */ + if(dio->mop < RPL_MOP_STORING_NO_MULTICAST) { +#else if(dio->mop != RPL_MOP_DEFAULT) { +#endif PRINTF("RPL: Ignoring a DIO with an unsupported MOP: %d\n", dio->mop); return; } diff --git a/core/net/rpl/rpl-icmp6.c b/core/net/rpl/rpl-icmp6.c index 1ee1678b1..c1cc6060b 100644 --- a/core/net/rpl/rpl-icmp6.c +++ b/core/net/rpl/rpl-icmp6.c @@ -40,6 +40,7 @@ * \author Joakim Eriksson , Nicolas Tsiftes * Contributors: Niclas Finne , Joel Hoglund , * Mathieu Pouillot + * George Oikonomou (multicast) */ #include "net/ip/tcpip.h" @@ -49,6 +50,7 @@ #include "net/ipv6/uip-icmp6.h" #include "net/rpl/rpl-private.h" #include "net/packetbuf.h" +#include "net/ipv6/multicast/uip-mcast6.h" #include #include @@ -86,6 +88,9 @@ static uint8_t dao_sequence = RPL_LOLLIPOP_INIT; extern rpl_of_t RPL_OF; +#if RPL_CONF_MULTICAST +static uip_mcast6_route_t *mcast_group; +#endif /*---------------------------------------------------------------------------*/ static int get_global_addr(uip_ipaddr_t *addr) @@ -622,6 +627,34 @@ dao_input(void) /* Perhaps, there are verification to do but ... */ } + learned_from = uip_is_addr_mcast(&dao_sender_addr) ? + RPL_ROUTE_FROM_MULTICAST_DAO : RPL_ROUTE_FROM_UNICAST_DAO; + + PRINTF("RPL: DAO from %s\n", + learned_from == RPL_ROUTE_FROM_UNICAST_DAO? "unicast": "multicast"); + if(learned_from == RPL_ROUTE_FROM_UNICAST_DAO) { + /* Check whether this is a DAO forwarding loop. */ + p = rpl_find_parent(dag, &dao_sender_addr); + /* check if this is a new DAO registration with an "illegal" rank */ + /* if we already route to this node it is likely */ + if(p != NULL && + DAG_RANK(p->rank, instance) < DAG_RANK(dag->rank, instance)) { + PRINTF("RPL: Loop detected when receiving a unicast DAO from a node with a lower rank! (%u < %u)\n", + DAG_RANK(p->rank, instance), DAG_RANK(dag->rank, instance)); + p->rank = INFINITE_RANK; + p->updated = 1; + return; + } + + /* If we get the DAO from our parent, we also have a loop. */ + if(p != NULL && p == dag->preferred_parent) { + PRINTF("RPL: Loop detected when receiving a unicast DAO from our parent\n"); + p->rank = INFINITE_RANK; + p->updated = 1; + return; + } + } + /* Check if there are any RPL options present. */ for(i = pos; i < buffer_length; i += len) { subopt_type = buffer[i]; @@ -654,6 +687,17 @@ dao_input(void) PRINT6ADDR(&prefix); PRINTF("\n"); +#if RPL_CONF_MULTICAST + if(uip_is_addr_mcast_global(&prefix)) { + mcast_group = uip_mcast6_route_add(&prefix); + if(mcast_group) { + mcast_group->dag = dag; + mcast_group->lifetime = RPL_LIFETIME(instance, lifetime); + } + goto fwd_dao; + } +#endif + rep = uip_ds6_route_lookup(&prefix); if(lifetime == RPL_ZERO_LIFETIME) { @@ -687,34 +731,6 @@ dao_input(void) return; } - learned_from = uip_is_addr_mcast(&dao_sender_addr) ? - RPL_ROUTE_FROM_MULTICAST_DAO : RPL_ROUTE_FROM_UNICAST_DAO; - - PRINTF("RPL: DAO from %s\n", - learned_from == RPL_ROUTE_FROM_UNICAST_DAO? "unicast": "multicast"); - if(learned_from == RPL_ROUTE_FROM_UNICAST_DAO) { - /* Check whether this is a DAO forwarding loop. */ - p = rpl_find_parent(dag, &dao_sender_addr); - /* check if this is a new DAO registration with an "illegal" rank */ - /* if we already route to this node it is likely */ - if(p != NULL && - DAG_RANK(p->rank, instance) < DAG_RANK(dag->rank, instance)) { - PRINTF("RPL: Loop detected when receiving a unicast DAO from a node with a lower rank! (%u < %u)\n", - DAG_RANK(p->rank, instance), DAG_RANK(dag->rank, instance)); - p->rank = INFINITE_RANK; - p->updated = 1; - return; - } - - /* If we get the DAO from our parent, we also have a loop. */ - if(p != NULL && p == dag->preferred_parent) { - PRINTF("RPL: Loop detected when receiving a unicast DAO from our parent\n"); - p->rank = INFINITE_RANK; - p->updated = 1; - return; - } - } - PRINTF("RPL: adding DAO route\n"); if((nbr = uip_ds6_nbr_lookup(&dao_sender_addr)) == NULL) { @@ -752,6 +768,10 @@ dao_input(void) rep->state.lifetime = RPL_LIFETIME(instance, lifetime); rep->state.learned_from = learned_from; +#if RPL_CONF_MULTICAST +fwd_dao: +#endif + if(learned_from == RPL_ROUTE_FROM_UNICAST_DAO) { if(dag->preferred_parent != NULL && rpl_get_parent_ipaddr(dag->preferred_parent) != NULL) { diff --git a/core/net/rpl/rpl-private.h b/core/net/rpl/rpl-private.h index acabda4b7..0df8a91ca 100644 --- a/core/net/rpl/rpl-private.h +++ b/core/net/rpl/rpl-private.h @@ -44,6 +44,7 @@ #include "sys/clock.h" #include "sys/ctimer.h" #include "net/ipv6/uip-ds6.h" +#include "net/ipv6/multicast/uip-mcast6.h" /*---------------------------------------------------------------------------*/ /** \brief Is IPv6 address addr the link-local, all-RPL-nodes @@ -177,8 +178,24 @@ #ifdef RPL_CONF_MOP #define RPL_MOP_DEFAULT RPL_CONF_MOP +#else /* RPL_CONF_MOP */ +#if RPL_CONF_MULTICAST +#define RPL_MOP_DEFAULT RPL_MOP_STORING_MULTICAST #else #define RPL_MOP_DEFAULT RPL_MOP_STORING_NO_MULTICAST +#endif /* UIP_IPV6_MULTICAST_RPL */ +#endif /* RPL_CONF_MOP */ + +/* Emit a pre-processor error if the user configured multicast with bad MOP */ +#if RPL_CONF_MULTICAST && (RPL_MOP_DEFAULT != RPL_MOP_STORING_MULTICAST) +#error "RPL Multicast requires RPL_MOP_DEFAULT==3. Check contiki-conf.h" +#endif + +/* Multicast Route Lifetime as a multiple of the lifetime unit */ +#ifdef RPL_CONF_MCAST_LIFETIME +#define RPL_MCAST_LIFETIME RPL_CONF_MCAST_LIFETIME +#else +#define RPL_MCAST_LIFETIME 3 #endif /* diff --git a/core/net/rpl/rpl-timers.c b/core/net/rpl/rpl-timers.c index 4465bd81b..b4c25df19 100644 --- a/core/net/rpl/rpl-timers.c +++ b/core/net/rpl/rpl-timers.c @@ -41,6 +41,7 @@ #include "contiki-conf.h" #include "net/rpl/rpl-private.h" +#include "net/ipv6/multicast/uip-mcast6.h" #include "lib/random.h" #include "sys/ctimer.h" @@ -220,6 +221,10 @@ static void handle_dao_timer(void *ptr) { rpl_instance_t *instance; +#if RPL_CONF_MULTICAST + uip_mcast6_route_t *mcast_route; + uint8_t i; +#endif instance = (rpl_instance_t *)ptr; @@ -234,6 +239,31 @@ handle_dao_timer(void *ptr) PRINTF("RPL: handle_dao_timer - sending DAO\n"); /* Set the route lifetime to the default value. */ dao_output(instance->current_dag->preferred_parent, instance->default_lifetime); + +#if RPL_CONF_MULTICAST + /* Send DAOs for multicast prefixes only if the instance is in MOP 3 */ + if(instance->mop == RPL_MOP_STORING_MULTICAST) { + /* Send a DAO for own multicast addresses */ + for(i = 0; i < UIP_DS6_MADDR_NB; i++) { + if(uip_ds6_if.maddr_list[i].isused + && uip_is_addr_mcast_global(&uip_ds6_if.maddr_list[i].ipaddr)) { + dao_output_target(instance->current_dag->preferred_parent, + &uip_ds6_if.maddr_list[i].ipaddr, RPL_MCAST_LIFETIME); + } + } + + /* Iterate over multicast routes and send DAOs */ + mcast_route = uip_mcast6_route_list_head(); + while(mcast_route != NULL) { + /* Don't send if it's also our own address, done that already */ + if(uip_ds6_maddr_lookup(&mcast_route->group) == NULL) { + dao_output_target(instance->current_dag->preferred_parent, + &mcast_route->group, RPL_MCAST_LIFETIME); + } + mcast_route = list_item_next(mcast_route); + } + } +#endif } else { PRINTF("RPL: No suitable DAO parent\n"); } diff --git a/core/net/rpl/rpl.c b/core/net/rpl/rpl.c index 574497235..9fca4c28e 100644 --- a/core/net/rpl/rpl.c +++ b/core/net/rpl/rpl.c @@ -44,6 +44,7 @@ #include "net/ip/tcpip.h" #include "net/ipv6/uip-ds6.h" #include "net/rpl/rpl-private.h" +#include "net/ipv6/multicast/uip-mcast6.h" #define DEBUG DEBUG_NONE #include "net/ip/uip-debug.h" @@ -105,6 +106,9 @@ rpl_purge_routes(void) uip_ds6_route_t *r; uip_ipaddr_t prefix; rpl_dag_t *dag; +#if RPL_CONF_MULTICAST + uip_mcast6_route_t *mcast_route; +#endif /* First pass, decrement lifetime */ r = uip_ds6_route_head(); @@ -146,12 +150,29 @@ rpl_purge_routes(void) r = uip_ds6_route_next(r); } } + +#if RPL_CONF_MULTICAST + mcast_route = uip_mcast6_route_list_head(); + + while(mcast_route != NULL) { + if(mcast_route->lifetime <= 1) { + uip_mcast6_route_rm(mcast_route); + mcast_route = uip_mcast6_route_list_head(); + } else { + mcast_route->lifetime--; + mcast_route = list_item_next(mcast_route); + } + } +#endif } /*---------------------------------------------------------------------------*/ void rpl_remove_routes(rpl_dag_t *dag) { uip_ds6_route_t *r; +#if RPL_CONF_MULTICAST + uip_mcast6_route_t *mcast_route; +#endif r = uip_ds6_route_head(); @@ -163,6 +184,19 @@ rpl_remove_routes(rpl_dag_t *dag) r = uip_ds6_route_next(r); } } + +#if RPL_CONF_MULTICAST + mcast_route = uip_mcast6_route_list_head(); + + while(mcast_route != NULL) { + if(mcast_route->dag == dag) { + uip_mcast6_route_rm(mcast_route); + mcast_route = uip_mcast6_route_list_head(); + } else { + mcast_route = list_item_next(mcast_route); + } + } +#endif } /*---------------------------------------------------------------------------*/ void diff --git a/examples/ipv6/multicast/Makefile b/examples/ipv6/multicast/Makefile new file mode 100644 index 000000000..4bd9ce515 --- /dev/null +++ b/examples/ipv6/multicast/Makefile @@ -0,0 +1,11 @@ +DEFINES+=PROJECT_CONF_H=\"project-conf.h\" +UIP_CONF_IPV6=1 + +CONTIKI_PROJECT = root intermediate sink +all: $(CONTIKI_PROJECT) + +CONTIKI = ../../.. + +MODULES += core/net/ipv6/multicast + +include $(CONTIKI)/Makefile.include diff --git a/examples/ipv6/multicast/intermediate.c b/examples/ipv6/multicast/intermediate.c new file mode 100644 index 000000000..6d8f27284 --- /dev/null +++ b/examples/ipv6/multicast/intermediate.c @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2010, Loughborough University - Computer Science + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + */ + +/** + * \file + * This node is part of the RPL multicast example. It basically + * represents a node that does not join the multicast group + * but still knows how to forward multicast packets + * The example will work with or without any number of these nodes + * + * Also, performs some sanity checks for the contiki configuration + * and generates an error if the conf is bad + * + * \author + * George Oikonomou - + */ + +#include "contiki.h" +#include "contiki-net.h" +#include "net/ipv6/multicast/uip-mcast6.h" + +#if !UIP_CONF_IPV6 || !UIP_CONF_ROUTER || !UIP_CONF_IPV6_MULTICAST || !UIP_CONF_IPV6_RPL +#error "This example can not work with the current contiki configuration" +#error "Check the values of: UIP_CONF_IPV6, UIP_CONF_ROUTER, UIP_CONF_IPV6_RPL" +#endif +/*---------------------------------------------------------------------------*/ +PROCESS(mcast_intermediate_process, "Intermediate Process"); +AUTOSTART_PROCESSES(&mcast_intermediate_process); +/*---------------------------------------------------------------------------*/ +PROCESS_THREAD(mcast_intermediate_process, ev, data) +{ + PROCESS_BEGIN(); + + PROCESS_END(); +} +/*---------------------------------------------------------------------------*/ diff --git a/examples/ipv6/multicast/multicast.csc b/examples/ipv6/multicast/multicast.csc new file mode 100644 index 000000000..5339f0351 --- /dev/null +++ b/examples/ipv6/multicast/multicast.csc @@ -0,0 +1,257 @@ + + + [APPS_DIR]/mrm + [APPS_DIR]/mspsim + [APPS_DIR]/avrora + [APPS_DIR]/serial_socket + [APPS_DIR]/collect-view + [APPS_DIR]/powertracker + + Example of a uIPv6 network with multicast support + 123456 + 1000000 + + org.contikios.cooja.radiomediums.UDGM + 50.0 + 50.0 + 1.0 + 1.0 + + + 40000 + + + org.contikios.cooja.mspmote.SkyMoteType + sky1 + root + [CONTIKI_DIR]/examples/ipv6/multicast/root.c + make root.sky TARGET=sky + [CONTIKI_DIR]/examples/ipv6/multicast/root.sky + org.contikios.cooja.interfaces.Position + org.contikios.cooja.interfaces.RimeAddress + org.contikios.cooja.interfaces.IPAddress + org.contikios.cooja.interfaces.Mote2MoteRelations + org.contikios.cooja.interfaces.MoteAttributes + org.contikios.cooja.mspmote.interfaces.MspClock + org.contikios.cooja.mspmote.interfaces.MspMoteID + org.contikios.cooja.mspmote.interfaces.SkyButton + org.contikios.cooja.mspmote.interfaces.SkyFlash + org.contikios.cooja.mspmote.interfaces.SkyCoffeeFilesystem + org.contikios.cooja.mspmote.interfaces.Msp802154Radio + org.contikios.cooja.mspmote.interfaces.MspSerial + org.contikios.cooja.mspmote.interfaces.SkyLED + org.contikios.cooja.mspmote.interfaces.MspDebugOutput + org.contikios.cooja.mspmote.interfaces.SkyTemperature + + + org.contikios.cooja.mspmote.SkyMoteType + sky2 + intermediate + [CONTIKI_DIR]/examples/ipv6/multicast/intermediate.c + make intermediate.sky TARGET=sky + [CONTIKI_DIR]/examples/ipv6/multicast/intermediate.sky + org.contikios.cooja.interfaces.Position + org.contikios.cooja.interfaces.RimeAddress + org.contikios.cooja.interfaces.IPAddress + org.contikios.cooja.interfaces.Mote2MoteRelations + org.contikios.cooja.interfaces.MoteAttributes + org.contikios.cooja.mspmote.interfaces.MspClock + org.contikios.cooja.mspmote.interfaces.MspMoteID + org.contikios.cooja.mspmote.interfaces.SkyButton + org.contikios.cooja.mspmote.interfaces.SkyFlash + org.contikios.cooja.mspmote.interfaces.SkyCoffeeFilesystem + org.contikios.cooja.mspmote.interfaces.Msp802154Radio + org.contikios.cooja.mspmote.interfaces.MspSerial + org.contikios.cooja.mspmote.interfaces.SkyLED + org.contikios.cooja.mspmote.interfaces.MspDebugOutput + org.contikios.cooja.mspmote.interfaces.SkyTemperature + + + org.contikios.cooja.mspmote.SkyMoteType + sky3 + sink + [CONTIKI_DIR]/examples/ipv6/multicast/sink.c + make sink.sky TARGET=sky + [CONTIKI_DIR]/examples/ipv6/multicast/sink.sky + org.contikios.cooja.interfaces.Position + org.contikios.cooja.interfaces.RimeAddress + org.contikios.cooja.interfaces.IPAddress + org.contikios.cooja.interfaces.Mote2MoteRelations + org.contikios.cooja.interfaces.MoteAttributes + org.contikios.cooja.mspmote.interfaces.MspClock + org.contikios.cooja.mspmote.interfaces.MspMoteID + org.contikios.cooja.mspmote.interfaces.SkyButton + org.contikios.cooja.mspmote.interfaces.SkyFlash + org.contikios.cooja.mspmote.interfaces.SkyCoffeeFilesystem + org.contikios.cooja.mspmote.interfaces.Msp802154Radio + org.contikios.cooja.mspmote.interfaces.MspSerial + org.contikios.cooja.mspmote.interfaces.SkyLED + org.contikios.cooja.mspmote.interfaces.MspDebugOutput + org.contikios.cooja.mspmote.interfaces.SkyTemperature + + + + + org.contikios.cooja.interfaces.Position + 5.995813174969022 + 34.43129455447824 + 0.0 + + + org.contikios.cooja.mspmote.interfaces.MspMoteID + 1 + + sky1 + + + + + org.contikios.cooja.interfaces.Position + 40.70237155931961 + 16.396742420332068 + 0.0 + + + org.contikios.cooja.mspmote.interfaces.MspMoteID + 2 + + sky2 + + + + + org.contikios.cooja.interfaces.Position + 100.3720728044051 + 70.93197095432518 + 0.0 + + + org.contikios.cooja.mspmote.interfaces.MspMoteID + 3 + + sky3 + + + + + org.contikios.cooja.interfaces.Position + 81.7376718406712 + 28.854291358797 + 0.0 + + + org.contikios.cooja.mspmote.interfaces.MspMoteID + 4 + + sky3 + + + + + org.contikios.cooja.interfaces.Position + -26.161520836433183 + 8.116006415286686 + 0.0 + + + org.contikios.cooja.mspmote.interfaces.MspMoteID + 5 + + sky3 + + + + + org.contikios.cooja.interfaces.Position + -34.57705675553882 + 92.87247531485058 + 0.0 + + + org.contikios.cooja.mspmote.interfaces.MspMoteID + 6 + + sky3 + + + + + org.contikios.cooja.interfaces.Position + 39.86312587077661 + 59.603125741056246 + 0.0 + + + org.contikios.cooja.mspmote.interfaces.MspMoteID + 7 + + sky2 + + + + + org.contikios.cooja.interfaces.Position + 1.4345607604759194 + 75.2481773153879 + 0.0 + + + org.contikios.cooja.mspmote.interfaces.MspMoteID + 8 + + sky2 + + + + org.contikios.cooja.plugins.SimControl + 318 + 0 + 192 + 0 + 0 + + + org.contikios.cooja.plugins.Visualizer + + org.contikios.cooja.plugins.skins.IDVisualizerSkin + org.contikios.cooja.plugins.skins.MoteTypeVisualizerSkin + org.contikios.cooja.plugins.skins.UDGMVisualizerSkin + org.contikios.cooja.plugins.skins.AddressVisualizerSkin + 3.914959956760176 0.0 0.0 3.914959956760176 300.2075734071477 -15.682931033747009 + + 869 + 3 + 441 + 320 + 3 + + + org.contikios.cooja.plugins.LogListener + + + + + + 1281 + 2 + 213 + -1 + 714 + + + org.contikios.cooja.plugins.RadioLogger + + 117 + + false + false + + + 1280 + 1 + 268 + 0 + 445 + + + diff --git a/examples/ipv6/multicast/project-conf.h b/examples/ipv6/multicast/project-conf.h new file mode 100644 index 000000000..84686ce21 --- /dev/null +++ b/examples/ipv6/multicast/project-conf.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2010, Loughborough University - Computer Science + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + */ + +/** + * \file + * Project specific configuration defines for the RPl multicast + * example. + * + * \author + * George Oikonomou - + */ + +#ifndef PROJECT_CONF_H_ +#define PROJECT_CONF_H_ + +#include "net/ipv6/multicast/uip-mcast6-engines.h" + +/* Change this to switch engines. Engine codes in uip-mcast6-engines.h */ +#define UIP_MCAST6_CONF_ENGINE UIP_MCAST6_ENGINE_ROLL_TM + +/* For Imin: Use 16 over NullRDC, 64 over Contiki MAC */ +#define ROLL_TM_CONF_IMIN_1 64 + +#undef UIP_CONF_IPV6_RPL +#undef UIP_CONF_ND6_SEND_RA +#undef UIP_CONF_ROUTER +#define UIP_CONF_IPV6_RPL 1 +#define UIP_CONF_ND6_SEND_RA 0 +#define UIP_CONF_ROUTER 1 +#define UIP_MCAST6_ROUTE_CONF_ROUTES 1 + +#undef UIP_CONF_TCP +#define UIP_CONF_TCP 0 + +/* Code/RAM footprint savings so that things will fit on our device */ +#undef UIP_CONF_DS6_NBR_NBU +#undef UIP_CONF_DS6_ROUTE_NBU +#define UIP_CONF_DS6_NBR_NBU 10 +#define UIP_CONF_DS6_ROUTE_NBU 10 + +#endif /* PROJECT_CONF_H_ */ diff --git a/examples/ipv6/multicast/root.c b/examples/ipv6/multicast/root.c new file mode 100644 index 000000000..1c70ed388 --- /dev/null +++ b/examples/ipv6/multicast/root.c @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2010, Loughborough University - Computer Science + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + */ + +/** + * \file + * This node is part of the RPL multicast example. It is an RPL root + * and sends a multicast message periodically. For the example to work, + * we need one of those nodes. + * + * \author + * George Oikonomou - + */ + +#include "contiki.h" +#include "contiki-lib.h" +#include "contiki-net.h" +#include "net/ipv6/multicast/uip-mcast6.h" + +#include + +#define DEBUG DEBUG_PRINT +#include "net/ip/uip-debug.h" +#include "net/rpl/rpl.h" + +#define MAX_PAYLOAD_LEN 120 +#define MCAST_SINK_UDP_PORT 3001 /* Host byte order */ +#define SEND_INTERVAL CLOCK_SECOND /* clock ticks */ +#define ITERATIONS 100 /* messages */ + +/* Start sending messages START_DELAY secs after we start so that routing can + * converge */ +#define START_DELAY 60 + +static struct uip_udp_conn * mcast_conn; +static char buf[MAX_PAYLOAD_LEN]; +static uint32_t seq_id; + +#if !UIP_CONF_IPV6 || !UIP_CONF_ROUTER || !UIP_CONF_IPV6_MULTICAST || !UIP_CONF_IPV6_RPL +#error "This example can not work with the current contiki configuration" +#error "Check the values of: UIP_CONF_IPV6, UIP_CONF_ROUTER, UIP_CONF_IPV6_RPL" +#endif +/*---------------------------------------------------------------------------*/ +PROCESS(rpl_root_process, "RPL ROOT, Multicast Sender"); +AUTOSTART_PROCESSES(&rpl_root_process); +/*---------------------------------------------------------------------------*/ +static void +multicast_send(void) +{ + uint32_t id; + + id = uip_htonl(seq_id); + memset(buf, 0, MAX_PAYLOAD_LEN); + memcpy(buf, &id, sizeof(seq_id)); + + PRINTF("Send to: "); + PRINT6ADDR(&mcast_conn->ripaddr); + PRINTF(" Remote Port %u,", uip_ntohs(mcast_conn->rport)); + PRINTF(" (msg=0x%08lx)", (unsigned long)uip_ntohl(*((uint32_t *)buf))); + PRINTF(" %lu bytes\n", (unsigned long)sizeof(id)); + + seq_id++; + uip_udp_packet_send(mcast_conn, buf, sizeof(id)); +} +/*---------------------------------------------------------------------------*/ +static void +prepare_mcast(void) +{ + uip_ipaddr_t ipaddr; + + /* + * IPHC will use stateless multicast compression for this destination + * (M=1, DAC=0), with 32 inline bits (1E 89 AB CD) + */ + uip_ip6addr(&ipaddr, 0xFF1E,0,0,0,0,0,0x89,0xABCD); + mcast_conn = udp_new(&ipaddr, UIP_HTONS(MCAST_SINK_UDP_PORT), NULL); +} +/*---------------------------------------------------------------------------*/ +static void +set_own_addresses(void) +{ + int i; + uint8_t state; + rpl_dag_t *dag; + uip_ipaddr_t ipaddr; + + uip_ip6addr(&ipaddr, 0xaaaa, 0, 0, 0, 0, 0, 0, 0); + uip_ds6_set_addr_iid(&ipaddr, &uip_lladdr); + uip_ds6_addr_add(&ipaddr, 0, ADDR_AUTOCONF); + + PRINTF("Our IPv6 addresses:\n"); + for(i = 0; i < UIP_DS6_ADDR_NB; i++) { + state = uip_ds6_if.addr_list[i].state; + if(uip_ds6_if.addr_list[i].isused && (state == ADDR_TENTATIVE || state + == ADDR_PREFERRED)) { + PRINTF(" "); + PRINT6ADDR(&uip_ds6_if.addr_list[i].ipaddr); + PRINTF("\n"); + if(state == ADDR_TENTATIVE) { + uip_ds6_if.addr_list[i].state = ADDR_PREFERRED; + } + } + } + + /* Become root of a new DODAG with ID our global v6 address */ + dag = rpl_set_root(RPL_DEFAULT_INSTANCE, &ipaddr); + if(dag != NULL) { + rpl_set_prefix(dag, &ipaddr, 64); + PRINTF("Created a new RPL dag with ID: "); + PRINT6ADDR(&dag->dag_id); + PRINTF("\n"); + } +} +/*---------------------------------------------------------------------------*/ +PROCESS_THREAD(rpl_root_process, ev, data) +{ + static struct etimer et; + + PROCESS_BEGIN(); + + PRINTF("Multicast Engine: '%s'\n", UIP_MCAST6.name); + + NETSTACK_MAC.off(1); + + set_own_addresses(); + + prepare_mcast(); + + etimer_set(&et, START_DELAY * CLOCK_SECOND); + while(1) { + PROCESS_YIELD(); + if(etimer_expired(&et)) { + if(seq_id == ITERATIONS) { + etimer_stop(&et); + } else { + multicast_send(); + etimer_set(&et, SEND_INTERVAL); + } + } + } + + PROCESS_END(); +} +/*---------------------------------------------------------------------------*/ diff --git a/examples/ipv6/multicast/sink.c b/examples/ipv6/multicast/sink.c new file mode 100644 index 000000000..455e94441 --- /dev/null +++ b/examples/ipv6/multicast/sink.c @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2010, Loughborough University - Computer Science + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + */ + +/** + * \file + * This node is part of the RPL multicast example. It is a node that + * joins a multicast group and listens for messages. It also knows how + * to forward messages down the tree. + * For the example to work, we need one or more of those nodes. + * + * \author + * George Oikonomou - + */ + +#include "contiki.h" +#include "contiki-lib.h" +#include "contiki-net.h" +#include "net/ipv6/multicast/uip-mcast6.h" + +#include + +#define DEBUG DEBUG_PRINT +#include "net/ip/uip-debug.h" + +#define MCAST_SINK_UDP_PORT 3001 /* Host byte order */ + +static struct uip_udp_conn *sink_conn; +static uint16_t count; + +#define UIP_IP_BUF ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN]) + +#if !UIP_CONF_IPV6 || !UIP_CONF_ROUTER || !UIP_CONF_IPV6_MULTICAST || !UIP_CONF_IPV6_RPL +#error "This example can not work with the current contiki configuration" +#error "Check the values of: UIP_CONF_IPV6, UIP_CONF_ROUTER, UIP_CONF_IPV6_RPL" +#endif +/*---------------------------------------------------------------------------*/ +PROCESS(mcast_sink_process, "Multicast Sink"); +AUTOSTART_PROCESSES(&mcast_sink_process); +/*---------------------------------------------------------------------------*/ +static void +tcpip_handler(void) +{ + if(uip_newdata()) { + count++; + PRINTF("In: [0x%08lx], TTL %u, total %u\n", + uip_ntohl((unsigned long) *((uint32_t *)(uip_appdata))), + UIP_IP_BUF->ttl, count); + } + return; +} +/*---------------------------------------------------------------------------*/ +static uip_ds6_maddr_t * +join_mcast_group(void) +{ + uip_ipaddr_t addr; + uip_ds6_maddr_t *rv; + + /* First, set our v6 global */ + uip_ip6addr(&addr, 0xaaaa, 0, 0, 0, 0, 0, 0, 0); + uip_ds6_set_addr_iid(&addr, &uip_lladdr); + uip_ds6_addr_add(&addr, 0, ADDR_AUTOCONF); + + /* + * IPHC will use stateless multicast compression for this destination + * (M=1, DAC=0), with 32 inline bits (1E 89 AB CD) + */ + uip_ip6addr(&addr, 0xFF1E,0,0,0,0,0,0x89,0xABCD); + rv = uip_ds6_maddr_add(&addr); + + if(rv) { + PRINTF("Joined multicast group "); + PRINT6ADDR(&uip_ds6_maddr_lookup(&addr)->ipaddr); + PRINTF("\n"); + } + return rv; +} +/*---------------------------------------------------------------------------*/ +PROCESS_THREAD(mcast_sink_process, ev, data) +{ + PROCESS_BEGIN(); + + PRINTF("Multicast Engine: '%s'\n", UIP_MCAST6.name); + + if(join_mcast_group() == NULL) { + PRINTF("Failed to join multicast group\n"); + PROCESS_EXIT(); + } + + count = 0; + + sink_conn = udp_new(NULL, UIP_HTONS(0), NULL); + udp_bind(sink_conn, UIP_HTONS(MCAST_SINK_UDP_PORT)); + + PRINTF("Listening: "); + PRINT6ADDR(&sink_conn->ripaddr); + PRINTF(" local/remote port %u/%u\n", + UIP_HTONS(sink_conn->lport), UIP_HTONS(sink_conn->rport)); + + while(1) { + PROCESS_YIELD(); + if(ev == tcpip_event) { + tcpip_handler(); + } + } + + PROCESS_END(); +} +/*---------------------------------------------------------------------------*/ diff --git a/regression-tests/01-compile-base/Makefile b/regression-tests/01-compile-base/Makefile index 1252097b5..093dcfa2f 100644 --- a/regression-tests/01-compile-base/Makefile +++ b/regression-tests/01-compile-base/Makefile @@ -34,6 +34,7 @@ webserver-ipv6/eval-adf7xxxmb4z \ wget/minimal-net \ z1/z1 \ settings-example/avr-raven \ +ipv6/multicast/sky \ TOOLS= diff --git a/regression-tests/11-ipv6/17-cooja-multicast-11-hops.csc b/regression-tests/11-ipv6/17-cooja-multicast-11-hops.csc new file mode 100644 index 000000000..da90cb72b --- /dev/null +++ b/regression-tests/11-ipv6/17-cooja-multicast-11-hops.csc @@ -0,0 +1,367 @@ + + + [APPS_DIR]/mrm + [APPS_DIR]/mspsim + [APPS_DIR]/avrora + [APPS_DIR]/serial_socket + [APPS_DIR]/collect-view + [APPS_DIR]/powertracker + + Multicast regression test + 123456 + 1000000 + + org.contikios.cooja.radiomediums.UDGM + 15.0 + 0.0 + 1.0 + 1.0 + + + 40000 + + + org.contikios.cooja.contikimote.ContikiMoteType + mtype612 + Root/sender + [CONTIKI_DIR]/examples/ipv6/multicast/root.c + make root.cooja TARGET=cooja + org.contikios.cooja.interfaces.Position + org.contikios.cooja.interfaces.Battery + org.contikios.cooja.contikimote.interfaces.ContikiVib + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + org.contikios.cooja.contikimote.interfaces.ContikiRS232 + org.contikios.cooja.contikimote.interfaces.ContikiBeeper + org.contikios.cooja.interfaces.RimeAddress + org.contikios.cooja.contikimote.interfaces.ContikiIPAddress + org.contikios.cooja.contikimote.interfaces.ContikiRadio + org.contikios.cooja.contikimote.interfaces.ContikiButton + org.contikios.cooja.contikimote.interfaces.ContikiPIR + org.contikios.cooja.contikimote.interfaces.ContikiClock + org.contikios.cooja.contikimote.interfaces.ContikiLED + org.contikios.cooja.contikimote.interfaces.ContikiCFS + org.contikios.cooja.interfaces.Mote2MoteRelations + org.contikios.cooja.interfaces.MoteAttributes + false + + + org.contikios.cooja.contikimote.ContikiMoteType + mtype890 + Intermediate + [CONTIKI_DIR]/examples/ipv6/multicast/intermediate.c + make intermediate.cooja TARGET=cooja + org.contikios.cooja.interfaces.Position + org.contikios.cooja.interfaces.Battery + org.contikios.cooja.contikimote.interfaces.ContikiVib + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + org.contikios.cooja.contikimote.interfaces.ContikiRS232 + org.contikios.cooja.contikimote.interfaces.ContikiBeeper + org.contikios.cooja.interfaces.RimeAddress + org.contikios.cooja.contikimote.interfaces.ContikiIPAddress + org.contikios.cooja.contikimote.interfaces.ContikiRadio + org.contikios.cooja.contikimote.interfaces.ContikiButton + org.contikios.cooja.contikimote.interfaces.ContikiPIR + org.contikios.cooja.contikimote.interfaces.ContikiClock + org.contikios.cooja.contikimote.interfaces.ContikiLED + org.contikios.cooja.contikimote.interfaces.ContikiCFS + org.contikios.cooja.interfaces.Mote2MoteRelations + org.contikios.cooja.interfaces.MoteAttributes + false + + + org.contikios.cooja.contikimote.ContikiMoteType + mtype956 + Receiver + [CONTIKI_DIR]/examples/ipv6/multicast/sink.c + make sink.cooja TARGET=cooja + org.contikios.cooja.interfaces.Position + org.contikios.cooja.interfaces.Battery + org.contikios.cooja.contikimote.interfaces.ContikiVib + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + org.contikios.cooja.contikimote.interfaces.ContikiRS232 + org.contikios.cooja.contikimote.interfaces.ContikiBeeper + org.contikios.cooja.interfaces.RimeAddress + org.contikios.cooja.contikimote.interfaces.ContikiIPAddress + org.contikios.cooja.contikimote.interfaces.ContikiRadio + org.contikios.cooja.contikimote.interfaces.ContikiButton + org.contikios.cooja.contikimote.interfaces.ContikiPIR + org.contikios.cooja.contikimote.interfaces.ContikiClock + org.contikios.cooja.contikimote.interfaces.ContikiLED + org.contikios.cooja.contikimote.interfaces.ContikiCFS + org.contikios.cooja.interfaces.Mote2MoteRelations + org.contikios.cooja.interfaces.MoteAttributes + false + + + + org.contikios.cooja.interfaces.Position + -7.983976888750106 + 0.37523218201044733 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 1 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + mtype612 + + + + org.contikios.cooja.interfaces.Position + 0.0 + 0.0 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 2 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + mtype890 + + + + org.contikios.cooja.interfaces.Position + 10.0 + 0.0 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 3 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + mtype890 + + + + org.contikios.cooja.interfaces.Position + 20.0 + 0.0 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 4 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + mtype890 + + + + org.contikios.cooja.interfaces.Position + 30.0 + 0.0 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 5 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + mtype890 + + + + org.contikios.cooja.interfaces.Position + 40.0 + 0.0 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 6 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + mtype890 + + + + org.contikios.cooja.interfaces.Position + 50.0 + 0.0 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 7 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + mtype890 + + + + org.contikios.cooja.interfaces.Position + 60.0 + 0.0 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 8 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + mtype890 + + + + org.contikios.cooja.interfaces.Position + 70.0 + 0.0 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 9 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + mtype890 + + + + org.contikios.cooja.interfaces.Position + 79.93950307524713 + -0.043451055913349 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 10 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + mtype890 + + + + org.contikios.cooja.interfaces.Position + 90.0 + 0.0 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 11 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + mtype890 + + + + org.contikios.cooja.interfaces.Position + 99.61761525766555 + 0.37523218201044733 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 12 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + mtype956 + + + + org.contikios.cooja.plugins.SimControl + 280 + 1 + 160 + 400 + 0 + + + org.contikios.cooja.plugins.Visualizer + + true + org.contikios.cooja.plugins.skins.IDVisualizerSkin + org.contikios.cooja.plugins.skins.GridVisualizerSkin + org.contikios.cooja.plugins.skins.TrafficVisualizerSkin + org.contikios.cooja.plugins.skins.UDGMVisualizerSkin + org.contikios.cooja.plugins.skins.MoteTypeVisualizerSkin + 2.388440494916608 0.0 0.0 2.388440494916608 109.06925371156906 149.10378026149033 + + 400 + 3 + 400 + 1 + 1 + + + org.contikios.cooja.plugins.LogListener + + + + + + 1200 + 2 + 240 + 400 + 160 + + + org.contikios.cooja.plugins.Notes + + Enter notes here + true + + 920 + 4 + 160 + 680 + 0 + + + org.contikios.cooja.plugins.ScriptRunner + + + true + + 600 + 0 + 700 + 843 + 77 + + + diff --git a/regression-tests/11-ipv6/18-cooja-multicast-31-hops.csc b/regression-tests/11-ipv6/18-cooja-multicast-31-hops.csc new file mode 100644 index 000000000..c1aea4df0 --- /dev/null +++ b/regression-tests/11-ipv6/18-cooja-multicast-31-hops.csc @@ -0,0 +1,707 @@ + + + [APPS_DIR]/mrm + [APPS_DIR]/mspsim + [APPS_DIR]/avrora + [APPS_DIR]/serial_socket + [APPS_DIR]/collect-view + [APPS_DIR]/powertracker + + Multicast regression test + 123456 + 1000000 + + org.contikios.cooja.radiomediums.UDGM + 15.0 + 0.0 + 1.0 + 1.0 + + + 40000 + + + org.contikios.cooja.contikimote.ContikiMoteType + mtype816 + Root/sender + [CONTIKI_DIR]/examples/ipv6/multicast/root.c + make root.cooja TARGET=cooja + org.contikios.cooja.interfaces.Position + org.contikios.cooja.interfaces.Battery + org.contikios.cooja.contikimote.interfaces.ContikiVib + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + org.contikios.cooja.contikimote.interfaces.ContikiRS232 + org.contikios.cooja.contikimote.interfaces.ContikiBeeper + org.contikios.cooja.interfaces.RimeAddress + org.contikios.cooja.contikimote.interfaces.ContikiIPAddress + org.contikios.cooja.contikimote.interfaces.ContikiRadio + org.contikios.cooja.contikimote.interfaces.ContikiButton + org.contikios.cooja.contikimote.interfaces.ContikiPIR + org.contikios.cooja.contikimote.interfaces.ContikiClock + org.contikios.cooja.contikimote.interfaces.ContikiLED + org.contikios.cooja.contikimote.interfaces.ContikiCFS + org.contikios.cooja.interfaces.Mote2MoteRelations + org.contikios.cooja.interfaces.MoteAttributes + false + + + org.contikios.cooja.contikimote.ContikiMoteType + mtype53 + Intermediate + [CONTIKI_DIR]/examples/ipv6/multicast/intermediate.c + make intermediate.cooja TARGET=cooja + org.contikios.cooja.interfaces.Position + org.contikios.cooja.interfaces.Battery + org.contikios.cooja.contikimote.interfaces.ContikiVib + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + org.contikios.cooja.contikimote.interfaces.ContikiRS232 + org.contikios.cooja.contikimote.interfaces.ContikiBeeper + org.contikios.cooja.interfaces.RimeAddress + org.contikios.cooja.contikimote.interfaces.ContikiIPAddress + org.contikios.cooja.contikimote.interfaces.ContikiRadio + org.contikios.cooja.contikimote.interfaces.ContikiButton + org.contikios.cooja.contikimote.interfaces.ContikiPIR + org.contikios.cooja.contikimote.interfaces.ContikiClock + org.contikios.cooja.contikimote.interfaces.ContikiLED + org.contikios.cooja.contikimote.interfaces.ContikiCFS + org.contikios.cooja.interfaces.Mote2MoteRelations + org.contikios.cooja.interfaces.MoteAttributes + false + + + org.contikios.cooja.contikimote.ContikiMoteType + mtype191 + Receiver + [CONTIKI_DIR]/examples/ipv6/multicast/sink.c + make sink.cooja TARGET=cooja + org.contikios.cooja.interfaces.Position + org.contikios.cooja.interfaces.Battery + org.contikios.cooja.contikimote.interfaces.ContikiVib + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + org.contikios.cooja.contikimote.interfaces.ContikiRS232 + org.contikios.cooja.contikimote.interfaces.ContikiBeeper + org.contikios.cooja.interfaces.RimeAddress + org.contikios.cooja.contikimote.interfaces.ContikiIPAddress + org.contikios.cooja.contikimote.interfaces.ContikiRadio + org.contikios.cooja.contikimote.interfaces.ContikiButton + org.contikios.cooja.contikimote.interfaces.ContikiPIR + org.contikios.cooja.contikimote.interfaces.ContikiClock + org.contikios.cooja.contikimote.interfaces.ContikiLED + org.contikios.cooja.contikimote.interfaces.ContikiCFS + org.contikios.cooja.interfaces.Mote2MoteRelations + org.contikios.cooja.interfaces.MoteAttributes + false + + + + org.contikios.cooja.interfaces.Position + -7.983976888750106 + 0.37523218201044733 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 1 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + mtype816 + + + + org.contikios.cooja.interfaces.Position + 0.0 + 0.0 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 2 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + mtype53 + + + + org.contikios.cooja.interfaces.Position + 10.0 + 0.0 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 3 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + mtype53 + + + + org.contikios.cooja.interfaces.Position + 20.0 + 0.0 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 4 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + mtype53 + + + + org.contikios.cooja.interfaces.Position + 30.0 + 0.0 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 5 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + mtype53 + + + + org.contikios.cooja.interfaces.Position + 40.0 + 0.0 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 6 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + mtype53 + + + + org.contikios.cooja.interfaces.Position + 50.0 + 0.0 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 7 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + mtype53 + + + + org.contikios.cooja.interfaces.Position + 60.0 + 0.0 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 8 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + mtype53 + + + + org.contikios.cooja.interfaces.Position + 70.0 + 0.0 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 9 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + mtype53 + + + + org.contikios.cooja.interfaces.Position + 79.93950307524713 + -0.043451055913349 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 10 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + mtype53 + + + + org.contikios.cooja.interfaces.Position + 90.0 + 0.0 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 11 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + mtype53 + + + + org.contikios.cooja.interfaces.Position + 299.830399237567 + 0.21169609213234786 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 12 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + mtype191 + + + + org.contikios.cooja.interfaces.Position + 100.0 + 0.0 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 13 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + mtype53 + + + + org.contikios.cooja.interfaces.Position + 110.0 + 0.0 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 14 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + mtype53 + + + + org.contikios.cooja.interfaces.Position + 120.0 + 0.0 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 15 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + mtype53 + + + + org.contikios.cooja.interfaces.Position + 130.0 + 0.0 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 16 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + mtype53 + + + + org.contikios.cooja.interfaces.Position + 140.0 + 0.0 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 17 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + mtype53 + + + + org.contikios.cooja.interfaces.Position + 150.0 + 0.0 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 18 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + mtype53 + + + + org.contikios.cooja.interfaces.Position + 160.0 + 0.0 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 19 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + mtype53 + + + + org.contikios.cooja.interfaces.Position + 170.0 + 0.0 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 20 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + mtype53 + + + + org.contikios.cooja.interfaces.Position + 180.0 + 0.0 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 21 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + mtype53 + + + + org.contikios.cooja.interfaces.Position + 190.0 + 0.0 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 22 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + mtype53 + + + + org.contikios.cooja.interfaces.Position + 200.0 + 0.0 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 23 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + mtype53 + + + + org.contikios.cooja.interfaces.Position + 210.0 + 0.0 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 24 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + mtype53 + + + + org.contikios.cooja.interfaces.Position + 220.0 + 0.0 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 25 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + mtype53 + + + + org.contikios.cooja.interfaces.Position + 230.0 + 0.0 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 26 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + mtype53 + + + + org.contikios.cooja.interfaces.Position + 240.0 + 0.0 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 27 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + mtype53 + + + + org.contikios.cooja.interfaces.Position + 250.0 + 0.0 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 28 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + mtype53 + + + + org.contikios.cooja.interfaces.Position + 260.0 + 0.0 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 29 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + mtype53 + + + + org.contikios.cooja.interfaces.Position + 270.0 + 0.0 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 30 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + mtype53 + + + + org.contikios.cooja.interfaces.Position + 280.0 + 0.0 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 31 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + mtype53 + + + + org.contikios.cooja.interfaces.Position + 290.0 + 0.0 + 0.0 + + + org.contikios.cooja.contikimote.interfaces.ContikiMoteID + 32 + + + org.contikios.cooja.contikimote.interfaces.ContikiRadio + 250.0 + + mtype53 + + + + org.contikios.cooja.plugins.SimControl + 280 + 1 + 160 + 400 + 0 + + + org.contikios.cooja.plugins.Visualizer + + true + org.contikios.cooja.plugins.skins.IDVisualizerSkin + org.contikios.cooja.plugins.skins.GridVisualizerSkin + org.contikios.cooja.plugins.skins.TrafficVisualizerSkin + org.contikios.cooja.plugins.skins.UDGMVisualizerSkin + org.contikios.cooja.plugins.skins.MoteTypeVisualizerSkin + 1.1837122130192945 0.0 0.0 1.1837122130192945 27.087094588040927 150.74941275029448 + + 400 + 2 + 400 + 1 + 1 + + + org.contikios.cooja.plugins.LogListener + + + + + + 1200 + 3 + 240 + 400 + 160 + + + org.contikios.cooja.plugins.Notes + + Enter notes here + true + + 920 + 4 + 160 + 680 + 0 + + + org.contikios.cooja.plugins.ScriptRunner + + + true + + 600 + 0 + 700 + 843 + 77 + + + diff --git a/regression-tests/14-compile-8051-ports/Makefile b/regression-tests/14-compile-8051-ports/Makefile index 004c37d52..974e74df2 100644 --- a/regression-tests/14-compile-8051-ports/Makefile +++ b/regression-tests/14-compile-8051-ports/Makefile @@ -7,6 +7,7 @@ cc2530dk/cc2530dk \ cc2530dk/border-router/cc2530dk \ cc2530dk/udp-ipv6/cc2530dk \ cc2530dk/sniffer/cc2530dk \ +ipv6/multicast/cc2530dk \ TOOLS= diff --git a/regression-tests/15-compile-arm-ports/Makefile b/regression-tests/15-compile-arm-ports/Makefile index 4115ab780..572489d8a 100644 --- a/regression-tests/15-compile-arm-ports/Makefile +++ b/regression-tests/15-compile-arm-ports/Makefile @@ -14,6 +14,8 @@ webserver-ipv6/cc2538dk \ cc2538dk/cc2538dk \ cc2538dk/udp-ipv6-echo-server/cc2538dk \ cc2538dk/sniffer/cc2538dk \ +ipv6/multicast/econotag \ +ipv6/multicast/cc2538dk \ TOOLS=