diff --git a/Makefile.include b/Makefile.include index 4ad1afc7b..631a927fd 100644 --- a/Makefile.include +++ b/Makefile.include @@ -60,7 +60,8 @@ ifdef UIP_CONF_IPV6 CFLAGS += -DUIP_CONF_IPV6 UIP = uip6.c tcpip.c psock.c uip-udp-packet.c uip-split.c \ resolv.c tcpdump.c uiplib.c - NET += $(UIP) uip-icmp6.c uip-nd6.c uip-nd6-io.c uip-netif.c sicslowpan.c + NET += $(UIP) uip-icmp6.c uip-nd6.c uip-nd6-io.c uip-netif.c \ + sicslowpan.c neighbor-attr.c neighbor-info.c else # UIP_CONF_IPV6 UIP = uip.c uiplib.c resolv.c tcpip.c psock.c hc.c uip-split.c uip-fw.c \ uip-fw-drv.c uip_arp.c tcpdump.c uip-neighbor.c uip-udp-packet.c \ diff --git a/core/net/neighbor-attr.c b/core/net/neighbor-attr.c new file mode 100644 index 000000000..e27b2f397 --- /dev/null +++ b/core/net/neighbor-attr.c @@ -0,0 +1,233 @@ +/* + * Copyright (c) 2010, Vrije Universiteit Brussel + * 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. + * + * + * Author: Joris Borms + * + */ + +#include "contiki.h" + +#include "lib/memb.h" +#include "lib/list.h" + +#include "neighbor-attr.h" + +#define DEBUG 0 + +#if DEBUG +#define PRINTF(...) printf(__VA_ARGS__) +#else +#define PRINTF(...) +#endif + +static uint16_t timeout = 0; + +MEMB(neighbor_addr_mem, struct neighbor_addr, MAX_NEIGHBORS); + +LIST(neighbor_addrs); +LIST(neighbor_attrs); +/*---------------------------------------------------------------------------*/ +static struct neighbor_addr * +neighbor_addr_get(const rimeaddr_t *addr) +{ + /* check if addr is derived from table, inside memb */ + if(memb_inmemb(&neighbor_addr_mem, addr)) { + return (struct neighbor_addr *) + (((void *)addr) - offsetof(struct neighbor_addr, addr)); + } + struct neighbor_addr *item = list_head(neighbor_addrs); + + while(item != NULL) { + if(rimeaddr_cmp(addr, &item->addr)) { + return item; + } + item = item->next; + } + return NULL; +} +/*---------------------------------------------------------------------------*/ +struct neighbor_addr * +neighbor_attr_list_neighbors(void) +{ + return list_head(neighbor_addrs); +} +/*---------------------------------------------------------------------------*/ +int +neighbor_attr_register(struct neighbor_attr *def) +{ + list_push(neighbor_attrs, def); + /* set default values for already existing neighbors */ + struct neighbor_addr *addr = list_head(neighbor_addrs); + + while(addr != NULL) { + if(def->default_value != NULL) { + memcpy(def->data + addr->index * def->size, def->default_value, + def->size); + } else { + /* fill with zeroes */ + memset(def->data + addr->index * def->size, 0, def->size); + } + addr = addr->next; + } + return 1; +} +/*---------------------------------------------------------------------------*/ +int +neighbor_attr_has_neighbor(const rimeaddr_t *addr) +{ + return neighbor_addr_get(addr) != NULL; +} +/*---------------------------------------------------------------------------*/ +int +neighbor_attr_add_neighbor(const rimeaddr_t *addr) +{ + if(neighbor_attr_has_neighbor(addr)) { + return 0; + } + + struct neighbor_addr *item = memb_alloc(&neighbor_addr_mem); + + if(item == NULL) { + return -1; + } + + list_push(neighbor_addrs, item); + + item->time = 0; + rimeaddr_copy(&item->addr, addr); + + /* look up index and set default values */ + uint16_t i; + struct neighbor_addr *ptr = neighbor_addr_mem.mem; + + for(i = 0; i < neighbor_addr_mem.num; ++i) { + if(&ptr[i] == item) { + break; + } + } + + item->index = i; + + struct neighbor_attr *def = list_head(neighbor_attrs); + + while(def != NULL) { + if(def->default_value != NULL) { + memcpy(def->data + i * def->size, def->default_value, def->size); + } else { + /* fill with zeroes */ + memset(def->data + i * def->size, 0, def->size); + } + def = def->next; + } + + return 1; +} +/*---------------------------------------------------------------------------*/ +void * +neighbor_attr_get_data(struct neighbor_attr *def, const rimeaddr_t *addr) +{ + struct neighbor_addr *attr = neighbor_addr_get(addr); + + if(attr != NULL) { + return (void *)(def->data + attr->index * def->size); + } + return NULL; +} +/*---------------------------------------------------------------------------*/ +int +neighbor_attr_set_data(struct neighbor_attr *def, const rimeaddr_t *addr, + void *data) +{ + struct neighbor_addr *attr = neighbor_addr_get(addr); + + if(attr == NULL) { + if(neighbor_attr_add_neighbor(addr)) { + attr = neighbor_addr_get(addr); + } + } + if(attr != NULL) { + attr->time = 0; + memcpy((void *)(def->data + attr->index * def->size), data, def->size); + return 1; + } + return 0; +} +/*---------------------------------------------------------------------------*/ +void +neighbor_attr_tick(const rimeaddr_t * addr) +{ + struct neighbor_addr *attr = neighbor_addr_get(addr); + + if(attr != NULL) { + attr->time = 0; + } +} +/*---------------------------------------------------------------------------*/ +uint16_t +neighbor_attr_get_timeout(void) +{ + return timeout; +} +/*---------------------------------------------------------------------------*/ +static struct ctimer ct; + +#define TIMEOUT_SECONDS 5 +static void +timeout_check(void *ptr) +{ + if(timeout > 0) { + struct neighbor_addr *item = neighbor_attr_list_neighbors(); + + while(item != NULL) { + item->time += TIMEOUT_SECONDS; + if(item->time >= timeout) { + struct neighbor_addr *next_item = item->next; + + memb_free(&neighbor_addr_mem, item); + list_remove(neighbor_addrs, item); + item = next_item; + } else { + item = item->next; + } + } + ctimer_set(&ct, TIMEOUT_SECONDS * CLOCK_SECOND, timeout_check, ptr); + } +} +/*---------------------------------------------------------------------------*/ +void +neighbor_attr_set_timeout(uint16_t time) +{ + if(timeout == 0 && time > 0) { + ctimer_set(&ct, TIMEOUT_SECONDS * CLOCK_SECOND, timeout_check, NULL); + } else if(timeout > 0 && time == 0) { + ctimer_stop(&ct); + } + timeout = time; +} +/*---------------------------------------------------------------------------*/ diff --git a/core/net/neighbor-attr.h b/core/net/neighbor-attr.h new file mode 100644 index 000000000..79f660048 --- /dev/null +++ b/core/net/neighbor-attr.h @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2010, Vrije Universiteit Brussel + * 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. + * + * + * Author: Joris Borms + * + */ +#ifndef NEIGHBORATTR_H_ +#define NEIGHBORATTR_H_ + +#include "rime.h" + +/** + * define how many neighbors you can store + */ +#ifdef NEIGHBOR_CONF_MAX_NEIGHBORS +#define MAX_NEIGHBORS NEIGHBOR_CONF_MAX_NEIGHBORS +#else /* NEIGHBOR_CONF_MAX_NEIGHBORS */ +#define MAX_NEIGHBORS 12 +#endif /* NEIGHBOR_CONF_MAX_NEIGHBORS */ + +/** + * \brief properties of a single neighbor + */ +struct neighbor_addr { + struct neighbor_addr *next; + rimeaddr_t addr; + uint16_t time; + uint16_t index; +}; + +/** + * \brief properties that define a neighbor attribute + */ +struct neighbor_attr { + struct neighbor_attr *next; + uint16_t size; + void *default_value; + void *data; +}; + +/** + * \brief Define space for additional parameters in neighbor table entries. + * \param type The type of the attribute. + * \param name The name of the attribute. + * \param def A ptr to the default value for this attribute. If NULL, attribute will + * be filled with zeroes by default. + * + * The attribute 'name' should be registered with 'neighbor_attr_register' + * during initialization. + */ +#define NEIGHBOR_ATTRIBUTE(type, name, default_value_ptr) \ + static type _##name##_mem[MAX_NEIGHBORS]; \ + static struct neighbor_attr name = \ + {NULL, sizeof(type), default_value_ptr, (void*)_##name##_mem} ; \ + +/** Same as NEIGHBOR_ATTRIBUTE, only the attr is not declared static + * this way you can say extern struct neighbor_attr name in header to declare + * a global neighbor attribute + */ +#define NEIGHBOR_ATTRIBUTE_NONSTATIC(type, name, default_value_ptr) \ + static type _##name##_mem[MAX_NEIGHBORS]; \ + struct neighbor_attr name = \ + {NULL, sizeof(type), default_value_ptr, (void*)_##name##_mem} ; \ + +/** + * \brief register a neighbor attribute + * \retval non-zero if successful, zero if not + */ +int neighbor_attr_register(struct neighbor_attr *); + +/** + * \retval head of neighbor list, useful for iterating over all neighbors + */ +struct neighbor_addr *neighbor_attr_list_neighbors(void); + +/** + * \brief Check if a neighbor is already added to the neighbor table + * \retval non-zero if present, zero if not + */ +int neighbor_attr_has_neighbor(const rimeaddr_t * addr); + +/** + * \brief Add a neighbor entry to neighbor table + * \retval -1 if unsuccessful, 0 if the neighbor was already + * in the table, and 1 if successful + */ +int neighbor_attr_add_neighbor(const rimeaddr_t * addr); + +/** + * \brief Get pointer to neighbor table data specified by id + * \param requested attribute + * \param addr requested neighbor + * \retval pointer to data, NULL if neighbor was not found + * + * Searches neighbor table for addr and returns pointer to data section + * specified by attribute type and addr. + * This pointer should not be saved, as it may point to data from another + * neighbor in the future if neighbors get removed/added over time. + */ +void *neighbor_attr_get_data(struct neighbor_attr *, const rimeaddr_t * addr); + +/** + * \brief Copy data to neighbor table + * \retval non-zero if successful, zero if not + * + * Copies data to specific part of the neighbor table, specified by + * neighbor and attribute type, and resets timeout for that neighbor. + * If neighbor was not found, this will add a new neighbor to the table. + */ +int neighbor_attr_set_data(struct neighbor_attr *, const rimeaddr_t * addr, + void *data); + +/** + * \brief Set global lifetime of neighbor entries. + * \param Lifetime in seconds. If 0, entries will not time out + */ +void neighbor_attr_set_timeout(uint16_t); + +/** + * \brief get global lifetime of neighbor entries. If 0, entries will not time out + */ +uint16_t neighbor_attr_get_timeout(void); + +/** + * \brief reset timeout of a neighbor to prevent it from being removed + */ +void neighbor_attr_tick(const rimeaddr_t *); + +#endif /* NEIGHBORATTR_H_ */ diff --git a/core/net/neighbor-info.c b/core/net/neighbor-info.c new file mode 100644 index 000000000..1015c8060 --- /dev/null +++ b/core/net/neighbor-info.c @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2010, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + * + * $Id: neighbor-info.c,v 1.1 2010/03/12 13:19:45 nvt-se Exp $ + */ +/** + * \file + * A generic module for management of neighbor information. + * + * \author Nicolas Tsiftes + */ + +#include "neighbor-info.h" +#include "neighbor-attr.h" + +#define DEBUG 0 +#if DEBUG +#include +#define PRINTF(...) printf(__VA_ARGS__) +#else +#define PRINTF(...) +#endif /* DEBUG */ + +#define ETX_SCALE 100 +#define ETX_ALPHA 60 +#define ETX_FIRST_GUESS 1 +#define ETX_COLLISION_PENALTY 5 +#define ETX_NO_ACK_PENALTY 5 +/*---------------------------------------------------------------------------*/ +NEIGHBOR_ATTRIBUTE(uint8_t, etx, NULL); + +static neighbor_info_subscriber_t subscriber_callback; +/*---------------------------------------------------------------------------*/ +static void +update_etx(const rimeaddr_t *dest, int packet_etx) +{ + uint8_t *etxp; + uint8_t recorded_etx, new_etx; + + etxp = (uint8_t *)neighbor_attr_get_data(&etx, dest); + if(etxp == NULL || *etxp == 0) { + recorded_etx = ETX_FIRST_GUESS; + } else { + recorded_etx = *etxp; + } + + new_etx = (ETX_SCALE / 2 + ETX_ALPHA * recorded_etx + + (ETX_SCALE - ETX_ALPHA) * packet_etx) / ETX_SCALE; + PRINTF("neighbor-info: ETX changed from %d to %d (packet ETX = %d)\n", + recorded_etx, new_etx, packet_etx); + + neighbor_attr_set_data(&etx, dest, &new_etx); + + if(new_etx != recorded_etx && subscriber_callback != NULL) { + subscriber_callback(dest, 1, recorded_etx); + } +} +/*---------------------------------------------------------------------------*/ +static void +add_neighbor(const rimeaddr_t *addr) +{ + switch(neighbor_attr_add_neighbor(addr)) { + case -1: + PRINTF("neighbor-info: failed to add a node.\n"); + break; + case 0: + PRINTF("neighbor-info: The neighbor is already known\n"); + break; + default: + if(subscriber_callback != NULL) { + subscriber_callback(addr, 1, ETX_FIRST_GUESS); + } + break; + } +} +/*---------------------------------------------------------------------------*/ +void +neighbor_info_packet_sent(int status, int numtx) +{ + const rimeaddr_t *dest; + uint8_t packet_etx; + + dest = packetbuf_addr(PACKETBUF_ADDR_RECEIVER); + if(rimeaddr_cmp(dest, &rimeaddr_null)) { + return; + } + + add_neighbor(dest); + + PRINTF("neighbor-info: packet sent to %d.%d, status=%d, numtx=%d\n", + dest->u8[sizeof(*dest) - 2], dest->u8[sizeof(*dest) - 1], + status, numtx); + + packet_etx = numtx; + switch(status) { + case MAC_TX_OK: + break; + case MAC_TX_COLLISION: + packet_etx += ETX_COLLISION_PENALTY; + break; + case MAC_TX_NOACK: + packet_etx += ETX_NO_ACK_PENALTY; + break; + default: + break; + } + + update_etx(dest, packet_etx); +} +/*---------------------------------------------------------------------------*/ +void +neighbor_info_packet_received(void) +{ + const rimeaddr_t *src; + + src = packetbuf_addr(PACKETBUF_ADDR_SENDER); + if(rimeaddr_cmp(src, &rimeaddr_null)) { + return; + } + + PRINTF("neighbor-info: packet received from %d.%d\n", + src->u8[sizeof(*src) - 2], src->u8[sizeof(*src) - 1]); + + add_neighbor(src); +} +/*---------------------------------------------------------------------------*/ +int +neighbor_info_subscribe(neighbor_info_subscriber_t s) +{ + if(subscriber_callback == NULL) { + subscriber_callback = s; + return 1; + } + + return 0; +} +/*---------------------------------------------------------------------------*/ diff --git a/core/net/neighbor-info.h b/core/net/neighbor-info.h new file mode 100644 index 000000000..b799d0da8 --- /dev/null +++ b/core/net/neighbor-info.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2010, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + * + * $Id: neighbor-info.h,v 1.1 2010/03/12 13:19:45 nvt-se Exp $ + */ +/** + * \file + * Declarations for the neighbor information module. + * + * \author Nicolas Tsiftes + */ + +#ifndef NEIGHBOR_INFO_H +#define NEIGHBOR_INFO_H + +#include "net/rime.h" + +typedef void (*neighbor_info_subscriber_t)(const rimeaddr_t *, int known, int etx); + +void neighbor_info_packet_sent(int status, int numtx); + +void neighbor_info_packet_received(void); + +int neighbor_info_subscribe(neighbor_info_subscriber_t); + +#endif /* NEIGHBOR_INFO_H */