diff --git a/examples/osd/native-border-router/Makefile b/examples/osd/native-border-router/Makefile new file mode 100644 index 000000000..69412170d --- /dev/null +++ b/examples/osd/native-border-router/Makefile @@ -0,0 +1,41 @@ +CONTIKI_PROJECT=border-router +all: $(CONTIKI_PROJECT) +APPS = slip-cmd + +CONTIKI=../../.. + +WITH_UIP6=1 +UIP_CONF_IPV6=1 +CFLAGS+= -DUIP_CONF_IPV6_RPL + +WITH_COAP=7 + +ifeq ($(WITH_COAP), 7) +${info INFO: compiling with CoAP-08} +CFLAGS += -DWITH_COAP=7 +CFLAGS += -DREST=coap_rest_implementation +#CFLAGS += -DUIP_CONF_TCP=0 +APPS += er-coap-07 +APPS+=erbium +endif + +#linker optimizations +SMALL=1 + +CFLAGS += -DPROJECT_CONF_H=\"project-conf.h\" +PROJECT_SOURCEFILES += border-router-cmds.c tun-bridge.c border-router-rdc.c \ +slip-config.c slip-dev.c + +WITH_WEBSERVER=0 +ifeq ($(WITH_WEBSERVER),1) +CFLAGS += -DWEBSERVER=1 +PROJECT_SOURCEFILES += httpd-simple.c +else ifneq ($(WITH_WEBSERVER), 0) +APPS += $(WITH_WEBSERVER) +CFLAGS += -DWEBSERVER=2 +endif + +include $(CONTIKI)/Makefile.include + +connect-router: border-router.native + sudo ./border-router.native aaaa::1/64 diff --git a/examples/osd/native-border-router/border-router-cmds.c b/examples/osd/native-border-router/border-router-cmds.c new file mode 100644 index 000000000..eec4646ab --- /dev/null +++ b/examples/osd/native-border-router/border-router-cmds.c @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2011, 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. + */ + +/** + * \file + * Sets up some commands for the border router + * \author + * Niclas Finne + * Joakim Eriksson + */ + +#include "contiki.h" +#include "cmd.h" +#include "border-router.h" +#include "border-router-cmds.h" +#include "dev/serial-line.h" +#include "net/rpl/rpl.h" +#include "net/uiplib.h" +#include + +#define DEBUG DEBUG_NONE +#include "net/uip-debug.h" + + +uint8_t command_context; + +void packet_sent(uint8_t sessionid, uint8_t status, uint8_t tx); +void nbr_print_stat(void); + +/*---------------------------------------------------------------------------*/ +PROCESS(border_router_cmd_process, "Border router cmd process"); +/*---------------------------------------------------------------------------*/ +/* TODO: the below code needs some way of identifying from where the command */ +/* comes. In this case it can be from stdin or from SLIP. */ +/*---------------------------------------------------------------------------*/ +int +border_router_cmd_handler(const uint8_t *data, int len) +{ + /* handle global repair, etc here */ + if(data[0] == '!') { + PRINTF("Got configuration message of type %c\n", data[1]); + if(data[1] == 'G' && command_context == CMD_CONTEXT_STDIO) { + /* This is supposed to be from stdin */ + printf("Performing Global Repair...\n"); + rpl_repair_root(RPL_DEFAULT_INSTANCE); + return 1; + } else if(data[1] == 'M' && command_context == CMD_CONTEXT_RADIO) { + /* We need to know that this is from the slip-radio here. */ + PRINTF("Setting MAC address\n"); + border_router_set_mac(&data[2]); + return 1; + } else if(data[1] == 'C' && command_context == CMD_CONTEXT_RADIO) { + /* We need to know that this is from the slip-radio here. */ + printf("Channel is:%d\n", data[2]); + return 1; + } else if(data[1] == 'R' && command_context == CMD_CONTEXT_RADIO) { + /* We need to know that this is from the slip-radio here. */ + PRINTF("Packet data report for sid:%d st:%d tx:%d\n", + data[2], data[3], data[4]); + packet_sent(data[2], data[3], data[4]); + return 1; + } else if(data[1] == 'D' && command_context == CMD_CONTEXT_RADIO) { + /* We need to know that this is from the slip-radio here... */ + PRINTF("Sensor data received\n"); + border_router_set_sensors((const char *)&data[2], len - 2); + return 1; + } + } else if(data[0] == '?') { + PRINTF("Got request message of type %c\n", data[1]); + if(data[1] == 'M' && command_context == CMD_CONTEXT_STDIO) { + uint8_t buf[20]; + char* hexchar = "0123456789abcdef"; + int j; + /* this is just a test so far... just to see if it works */ + buf[0] = '!'; + buf[1] = 'M'; + for(j = 0; j < 8; j++) { + buf[2 + j * 2] = hexchar[uip_lladdr.addr[j] >> 4]; + buf[3 + j * 2] = hexchar[uip_lladdr.addr[j] & 15]; + } + cmd_send(buf, 18); + return 1; + } else if(data[1] == 'C' && command_context == CMD_CONTEXT_STDIO) { + /* send on! */ + write_to_slip(data, len); + return 1; + } else if(data[1] == 'S') { + border_router_print_stat(); + return 1; + } + } + return 0; +} +/*---------------------------------------------------------------------------*/ +void +border_router_cmd_output(const uint8_t *data, int data_len) +{ + int i; + printf("CMD output: "); + for(i = 0; i < data_len; i++) { + printf("%c", data[i]); + } + printf("\n"); +} +/*---------------------------------------------------------------------------*/ +PROCESS_THREAD(border_router_cmd_process, ev, data) +{ + PROCESS_BEGIN(); + PRINTF("Started br-cmd process\n"); + while(1) { + PROCESS_YIELD(); + if(ev == serial_line_event_message && data != NULL) { + PRINTF("Got serial data!!! %s of len: %d\n", + (char *)data, strlen((char *)data)); + command_context = CMD_CONTEXT_STDIO; + cmd_input(data, strlen((char *)data)); + } + } + PROCESS_END(); +} +/*---------------------------------------------------------------------------*/ diff --git a/examples/osd/native-border-router/border-router-cmds.h b/examples/osd/native-border-router/border-router-cmds.h new file mode 100644 index 000000000..38fc92111 --- /dev/null +++ b/examples/osd/native-border-router/border-router-cmds.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2011, 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. + */ + +/** + * \file + * Sets up some commands for the border router + * \author + * Niclas Finne + * Joakim Eriksson + */ + +#ifndef __BORDER_ROUTER_CMDS_H__ +#define __BORDER_ROUTER_CMDS_H__ + +#define CMD_CONTEXT_RADIO 0 +#define CMD_CONTEXT_STDIO 1 + +extern uint8_t command_context; + +PROCESS_NAME(border_router_cmd_process); + +#endif /* __BORDER_ROUTER_CMDS_H__ */ diff --git a/examples/osd/native-border-router/border-router-rdc.c b/examples/osd/native-border-router/border-router-rdc.c new file mode 100644 index 000000000..78699122f --- /dev/null +++ b/examples/osd/native-border-router/border-router-rdc.c @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2011, 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. + */ + +/** + * \file + * A null RDC implementation that uses framer for headers and sends + * the packets over slip instead of radio. + * \author + * Adam Dunkels + * Joakim Eriksson + * Niclas Finne + */ + +#include "net/packetbuf.h" +#include "net/queuebuf.h" +#include "net/netstack.h" +#include "packetutils.h" +#include "border-router.h" +#include + +#define DEBUG 0 +#if DEBUG +#include +#define PRINTF(...) printf(__VA_ARGS__) +#else +#define PRINTF(...) +#endif + +#define MAX_CALLBACKS 16 +static int callback_pos; + +/* a structure for calling back when packet data is coming back + from radio... */ +struct tx_callback { + mac_callback_t cback; + void *ptr; + struct packetbuf_attr attrs[PACKETBUF_NUM_ATTRS]; + struct packetbuf_addr addrs[PACKETBUF_NUM_ADDRS]; +}; + +static struct tx_callback callbacks[MAX_CALLBACKS]; +/*---------------------------------------------------------------------------*/ +void packet_sent(uint8_t sessionid, uint8_t status, uint8_t tx) +{ + if(sessionid < MAX_CALLBACKS) { + struct tx_callback *callback; + callback = &callbacks[sessionid]; + packetbuf_clear(); + packetbuf_attr_copyfrom(callback->attrs, callback->addrs); + mac_call_sent_callback(callback->cback, callback->ptr, status, tx); + } else { + PRINTF("*** ERROR: too high session id %d\n", sessionid); + } +} +/*---------------------------------------------------------------------------*/ +static int +setup_callback(mac_callback_t sent, void *ptr) +{ + struct tx_callback *callback; + int tmp = callback_pos; + callback = &callbacks[callback_pos]; + callback->cback = sent; + callback->ptr = ptr; + packetbuf_attr_copyto(callback->attrs, callback->addrs); + + callback_pos++; + if(callback_pos >= MAX_CALLBACKS) { + callback_pos = 0; + } + + return tmp; +} +/*---------------------------------------------------------------------------*/ +static void +send_packet(mac_callback_t sent, void *ptr) +{ + int size; + /* 3 bytes per packet attribute is required for serialization */ + uint8_t buf[PACKETBUF_NUM_ATTRS * 3 + PACKETBUF_SIZE + 3]; + uint8_t sid; + + packetbuf_set_addr(PACKETBUF_ADDR_SENDER, &rimeaddr_node_addr); + + /* ack or not ? */ + packetbuf_set_attr(PACKETBUF_ATTR_MAC_ACK, 1); + + if(NETSTACK_FRAMER.create() < 0) { + /* Failed to allocate space for headers */ + PRINTF("br-rdc: send failed, too large header\n"); + mac_call_sent_callback(sent, ptr, MAC_TX_ERR_FATAL, 1); + + } else { + /* here we send the data over SLIP to the radio-chip */ + size = 0; +#if SERIALIZE_ATTRIBUTES + size = packetutils_serialize_atts(&buf[3], sizeof(buf) - 3); +#endif + if(size < 0 || size + packetbuf_totlen() + 3 > sizeof(buf)) { + PRINTF("br-rdc: send failed, too large header\n"); + mac_call_sent_callback(sent, ptr, MAC_TX_ERR_FATAL, 1); + } else { + sid = setup_callback(sent, ptr); + + buf[0] = '!'; + buf[1] = 'S'; + buf[2] = sid; /* sequence or session number for this packet */ + + /* Copy packet data */ + memcpy(&buf[3 + size], packetbuf_hdrptr(), packetbuf_totlen()); + + write_to_slip(buf, packetbuf_totlen() + size + 3); + } + } +} +/*---------------------------------------------------------------------------*/ +static void +send_list(mac_callback_t sent, void *ptr, struct rdc_buf_list *buf_list) +{ + if(buf_list != NULL) { + queuebuf_to_packetbuf(buf_list->buf); + send_packet(sent, ptr); + } +} +/*---------------------------------------------------------------------------*/ +static void +packet_input(void) +{ + if(NETSTACK_FRAMER.parse() < 0) { + PRINTF("br-rdc: failed to parse %u\n", packetbuf_datalen()); + } else { + NETSTACK_MAC.input(); + } +} +/*---------------------------------------------------------------------------*/ +static int +on(void) +{ + return 1; +} +/*---------------------------------------------------------------------------*/ +static int +off(int keep_radio_on) +{ + return 1; +} +/*---------------------------------------------------------------------------*/ +static unsigned short +channel_check_interval(void) +{ + return 0; +} +/*---------------------------------------------------------------------------*/ +static void +init(void) +{ + callback_pos = 0; +} +/*---------------------------------------------------------------------------*/ +const struct rdc_driver border_router_rdc_driver = { + "br-rdc", + init, + send_packet, + send_list, + packet_input, + on, + off, + channel_check_interval, +}; +/*---------------------------------------------------------------------------*/ diff --git a/examples/osd/native-border-router/border-router.c b/examples/osd/native-border-router/border-router.c new file mode 100644 index 000000000..281b2e27d --- /dev/null +++ b/examples/osd/native-border-router/border-router.c @@ -0,0 +1,483 @@ +/* + * Copyright (c) 2011, 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. + * + */ +/** + * \file + * border-router + * \author + * Niclas Finne + * Joakim Eriksson + * Nicolas Tsiftes + * Andreas Reder + */ + +#include "contiki.h" +#include "contiki-lib.h" +#include "contiki-net.h" +#include "net/uip.h" +#include "net/uip-ds6.h" +#include "net/rpl/rpl.h" +#include "net/mac/framer-802154.h" + +#include "net/netstack.h" +#include "dev/slip.h" +#include "cmd.h" +#include "border-router.h" +#include "border-router-cmds.h" + +#include +#include +#include +#include + +#define DEBUG DEBUG_FULL +#include "net/uip-debug.h" + +#include "erbium.h" +/* For CoAP-specific example: not required for normal RESTful Web service. */ +#if WITH_COAP == 3 +#include "er-coap-03.h" +#elif WITH_COAP == 7 +#include "er-coap-07.h" +#else +#warning "Erbium example without CoAP-specifc functionality" +#endif /* CoAP-specific example */ + + + +#define MAX_SENSORS 4 + +#define IPV6_ADDR_LEN 40 +#define RPL_TABLE_SIZE 25000 +char rpl_table[RPL_TABLE_SIZE]; +int rpl_table_len; + + + +uint16_t dag_id[] = {0x1111, 0x1100, 0, 0, 0, 0, 0, 0x0011}; + +extern uip_ds6_nbr_t uip_ds6_nbr_cache[]; +extern uip_ds6_route_t uip_ds6_routing_table[]; + +extern long slip_sent; +extern long slip_received; + +static uip_ipaddr_t prefix; +static uint8_t prefix_set; +static uint8_t mac_set; + +static uint8_t sensor_count = 0; + +/* allocate MAX_SENSORS char[32]'s */ +static char sensors[MAX_SENSORS][32]; + +extern int contiki_argc; +extern char **contiki_argv; +extern const char *slip_config_ipaddr; + +CMD_HANDLERS(border_router_cmd_handler); + +PROCESS(border_router_process, "Border router process"); +PROCESS(rest_server, "Erbium Coap Server"); + +AUTOSTART_PROCESSES(&border_router_process,&border_router_cmd_process, &rest_server); + + +static int create_ipv6_addr_str(const uip_ipaddr_t *addr, char *ptr){ + int len = 0; + int i, f; + uint16_t a; + + uip_debug_ipaddr_print(addr); + for(i = 0, f = 0; i < sizeof(uip_ipaddr_t); i += 2) { + a = (addr->u8[i] << 8) + addr->u8[i + 1]; + if(a == 0 && f >= 0) { + if(f++ == 0){ + ptr[len++] = ':'; + ptr[len++] = ':'; + } + } else { + if(f > 0) { + f = -1; + } else if(i > 0) { + ptr[len++] = ':'; + } + len += snprintf(&ptr[len], IPV6_ADDR_LEN - len, "%x", a); + } + } + return len; +} + +/*---------------------------------------------------------------------------*/ +//create JSON RPL Table +static void +generate_rpl_table(){ + char a[IPV6_ADDR_LEN]; + int addresses; + static uip_ds6_route_t *r; + int i; + + rpl_table_len = 0; + // Start JSON + rpl_table_len += snprintf(&rpl_table[rpl_table_len], RPL_TABLE_SIZE - rpl_table_len, "{\n"); + + // add title + rpl_table_len += snprintf(&rpl_table[rpl_table_len], RPL_TABLE_SIZE - rpl_table_len, "\"title\": \"RPL Table\",\n"); + + rpl_table_len += snprintf(&rpl_table[rpl_table_len], RPL_TABLE_SIZE - rpl_table_len, "\"Neighbors\": [ "); + + addresses = 0; + for(i = 0; i < UIP_DS6_NBR_NB; i++) { + if(uip_ds6_nbr_cache[i].isused) { + addresses += 1; + create_ipv6_addr_str(&uip_ds6_nbr_cache[i].ipaddr, a); + rpl_table_len += snprintf(&rpl_table[rpl_table_len], RPL_TABLE_SIZE - rpl_table_len, "\"%s\", ", a); + } + } + if(addresses > 0){ + //delete last coma + rpl_table_len -= 2; + } + rpl_table_len += snprintf(&rpl_table[rpl_table_len], RPL_TABLE_SIZE - rpl_table_len, "],\n"); + + rpl_table_len += snprintf(&rpl_table[rpl_table_len], RPL_TABLE_SIZE - rpl_table_len, "\"Routes\": [ "); + + addresses = 0; + for(r = uip_ds6_route_list_head(); r != NULL; r = list_item_next(r)) { + addresses += 1; + create_ipv6_addr_str(&r->ipaddr, a); + rpl_table_len += snprintf(&rpl_table[rpl_table_len], RPL_TABLE_SIZE - rpl_table_len, "\"%s via ", a); + create_ipv6_addr_str(&r->nexthop, a); + rpl_table_len += snprintf(&rpl_table[rpl_table_len], RPL_TABLE_SIZE - rpl_table_len, "%s\", ", a); + } + if(addresses > 0){ + //delete last coma + rpl_table_len -= 2; + } + rpl_table_len += snprintf(&rpl_table[rpl_table_len], RPL_TABLE_SIZE - rpl_table_len, "]\n"); + + // End JSON + rpl_table_len += snprintf(&rpl_table[rpl_table_len], RPL_TABLE_SIZE - rpl_table_len, "}\n"); +} + +/*---------------------------------------------------------------------------*/ +static void +print_local_addresses(void) +{ + int i; + uint8_t state; + + PRINTA("Server 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)) { + PRINTA(" %p: =>", &uip_ds6_if.addr_list[i]); + uip_debug_ipaddr_print(&(uip_ds6_if.addr_list[i]).ipaddr); + PRINTA("\n"); + } + } +} +/*---------------------------------------------------------------------------*/ +static void +request_mac(void) +{ + write_to_slip((uint8_t *)"?M", 2); +} +/*---------------------------------------------------------------------------*/ +void +border_router_set_mac(const uint8_t *data) +{ + memcpy(uip_lladdr.addr, data, sizeof(uip_lladdr.addr)); + rimeaddr_set_node_addr((rimeaddr_t *)uip_lladdr.addr); + + /* is this ok - should instead remove all addresses and + add them back again - a bit messy... ?*/ + uip_ds6_init(); + rpl_init(); + + mac_set = 1; +} +/*---------------------------------------------------------------------------*/ +void +border_router_print_stat() +{ + printf("bytes received over SLIP: %ld\n", slip_received); + printf("bytes sent over SLIP: %ld\n", slip_sent); +} + +/*---------------------------------------------------------------------------*/ +/* Format: ;;...;*/ +/* this function just cut at ; and store in the sensor array */ +void +border_router_set_sensors(const char *data, int len) +{ + int i; + int last_pos = 0; + int sc = 0; + for(i = 0;i < len; i++) { + if(data[i] == ';') { + sensors[sc][i - last_pos] = 0; + memcpy(sensors[sc++], &data[last_pos], i - last_pos); + last_pos = i + 1; /* skip the ';' */ + } + if(sc == MAX_SENSORS) { + sensor_count = sc; + return; + } + } + sensors[sc][len - last_pos] = 0; + memcpy(sensors[sc++], &data[last_pos], len - last_pos); + sensor_count = sc; +} +/*---------------------------------------------------------------------------*/ +static void +set_prefix_64(const uip_ipaddr_t *prefix_64) +{ + uip_ipaddr_t ipaddr; + memcpy(&prefix, prefix_64, 16); + memcpy(&ipaddr, prefix_64, 16); + + prefix_set = 1; + uip_ds6_set_addr_iid(&ipaddr, &uip_lladdr); + uip_ds6_addr_add(&ipaddr, 0, ADDR_AUTOCONF); +} +/*---------------------------------------------------------------------------*/ +PROCESS_THREAD(border_router_process, ev, data) +{ + static struct etimer et; + rpl_dag_t *dag; + + PROCESS_BEGIN(); + prefix_set = 0; + + PROCESS_PAUSE(); + + PRINTF("RPL-Border router started\n"); + + slip_config_handle_arguments(contiki_argc, contiki_argv); + + /* tun init is also responsible for setting up the SLIP connection */ + tun_init(); + + while(!mac_set) { + etimer_set(&et, CLOCK_SECOND); + request_mac(); + PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et)); + } + + if(slip_config_ipaddr != NULL) { + uip_ipaddr_t prefix; + + if(uiplib_ipaddrconv((const char *)slip_config_ipaddr, &prefix)) { + PRINTF("Setting prefix "); + PRINT6ADDR(&prefix); + PRINTF("\n"); + set_prefix_64(&prefix); + } else { + PRINTF("Parse error: %s\n", slip_config_ipaddr); + exit(0); + } + } + + dag = rpl_set_root(RPL_DEFAULT_INSTANCE,(uip_ip6addr_t *)dag_id); + if(dag != NULL) { + rpl_set_prefix(dag, &prefix, 64); + PRINTF("created a new RPL dag\n"); + } + +#if DEBUG + print_local_addresses(); +#endif + + /* The border router runs with a 100% duty cycle in order to ensure high + packet reception rates. */ + NETSTACK_MAC.off(1); + + while(1) { + // etimer_set(&et, CLOCK_SECOND * 2); + // PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et)); + PROCESS_YIELD(); + /* do anything here??? */ + } + + PROCESS_END(); +} +/*---------------------------------------------------------------------------*/ + +/* +* Resources are defined by the RESOURCE macro. +* Signature: resource name, the RESTful methods it handles, and its URI path (omitting the leading slash). +*/ +RESOURCE(rpl, METHOD_GET, "rpl", "title=\"rpl routing\";rt=\"Text\""); + +/* +* A handler function named [resource name]_handler must be implemented for each RESOURCE. +* A buffer for the response payload is provided through the buffer pointer. Simple resources can ignore +* preferred_size and offset, but must respect the REST_MAX_CHUNK_SIZE limit for the buffer. +* If a smaller block size is requested for CoAP, the REST framework automatically splits the data. +*/ + +void +rpl_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + int32_t strpos = 0; + int i; + + if(*offset == 0){ + generate_rpl_table(); + } + + /* Check the offset for boundaries of the resource data. */ + if (*offset>=rpl_table_len) + { + REST.set_response_status(response, REST.status.BAD_OPTION); + /* A block error message should not exceed the minimum block size (16). */ + + const char *error_msg = "BlockOutOfScope"; + REST.set_response_payload(response, error_msg, strlen(error_msg)); + return; + } + + /* Generate data until reaching CHUNKS_TOTAL. */ + while (strpos preferred_size) + { + strpos = preferred_size; + } + + /* Truncate if above CHUNKS_TOTAL bytes. */ + if (*offset+(int32_t)strpos > rpl_table_len) + { + strpos = rpl_table_len - *offset; + } + + REST.set_response_payload(response, buffer, strpos); + + /* IMPORTANT for chunk-wise resources: Signal chunk awareness to REST engine. */ + *offset += strpos; + + /* Signal end of resource representation. */ + if (*offset>=rpl_table_len) + { + *offset = -1; + } +} + +RESOURCE(osd_net_conf, METHOD_GET | METHOD_POST, "osd-net-conf", "title=\"osd configs\""); +void +osd_net_conf_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + char message[100]; + uint8_t buf[10]; + int index = 0; + int length = 0; /* |<-------->| */ + const char* strg; + uint16_t panid; + + if((length = REST.get_post_variable(request, "panid", &strg))){ + // parse panid + panid = (uint16_t)atoi(strg); + // set framer panid + framer_802154_set_panid(panid); + //set radio panid + buf[0] = '?'; + buf[1] = 'P'; + buf[2] = panid >> 8; + buf[3] = panid; + write_to_slip(buf, 4); + + }else if((length = REST.get_post_variable(request, "channel", &strg))){ + REST.set_response_status(response, REST.status.BAD_REQUEST); + return; + } + + index += sprintf(message + index, "{\n"); + index += sprintf(message + index, "\"panid\": \"%u\",\n", framer_802154_get_panid()); + //index += sprintf(message + index, "\"channel\": \"%u\",\n", //params_get_channel()); + index += sprintf(message + index, "}\n"); + + length = strlen(message); + memcpy(buffer, message,length ); + + REST.set_header_content_type(response, REST.type.APPLICATION_JSON); + REST.set_response_payload(response, buffer, length); +} + + +/*---------------------------------------------------------------------------*/ + +PROCESS_THREAD(rest_server, ev, data) +{ + + PROCESS_BEGIN(); + + + + PRINTF("Starting Erbium Coap Server\n"); + +#ifdef RF_CHANNEL + PRINTF("RF channel: %u\n", RF_CHANNEL); +#endif +#ifdef IEEE802154_PANID + PRINTF("PAN ID: 0x%04X\n", IEEE802154_PANID); +#endif + + PRINTF("uIP buffer: %u\n", UIP_BUFSIZE); + PRINTF("LL header: %u\n", UIP_LLH_LEN); + PRINTF("IP+UDP header: %u\n", UIP_IPUDPH_LEN); + PRINTF("REST max chunk: %u\n", REST_MAX_CHUNK_SIZE); + + /* Initialize the REST engine. */ + rest_init_engine(); + + /* Activate the application-specific resources. */ + rest_activate_resource(&resource_rpl); + rest_activate_resource(&resource_osd_net_conf); + + while(1) { + PROCESS_YIELD(); + } + + + PROCESS_END(); +} + + + diff --git a/examples/osd/native-border-router/border-router.h b/examples/osd/native-border-router/border-router.h new file mode 100644 index 000000000..b6a2f2ab2 --- /dev/null +++ b/examples/osd/native-border-router/border-router.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2011, 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. + */ + +/** + * \file + * Border router header file + * \author + * Joakim Eriksson + */ + +#ifndef __BORDER_ROUTER_H__ +#define __BORDER_ROUTER_H__ + +#include "contiki.h" +#include "net/uip.h" +#include + +int border_router_cmd_handler(const uint8_t *data, int len); +int slip_config_handle_arguments(int argc, char **argv); +void write_to_slip(const uint8_t *buf, int len); + +void border_router_set_prefix_64(const uip_ipaddr_t *prefix_64); +void border_router_set_mac(const uint8_t *data); +void border_router_set_sensors(const char *data, int len); +void border_router_print_stat(void); + +void tun_init(void); + +int slip_init(void); +int slip_set_fd(int maxfd, fd_set *rset, fd_set *wset); +void slip_handle_fd(fd_set *rset, fd_set *wset); + +#endif /* __BORDER_ROUTER_H__ */ diff --git a/examples/osd/native-border-router/project-conf.h b/examples/osd/native-border-router/project-conf.h new file mode 100644 index 000000000..494264b58 --- /dev/null +++ b/examples/osd/native-border-router/project-conf.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2011, 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. + */ + +#ifndef __PROJECT_ROUTER_CONF_H__ +#define __PROJECT_ROUTER_CONF_H__ + +#undef UIP_FALLBACK_INTERFACE +#define UIP_FALLBACK_INTERFACE rpl_interface + +#undef QUEUEBUF_CONF_NUM +#define QUEUEBUF_CONF_NUM 4 + +#undef UIP_CONF_BUFFER_SIZE +#define UIP_CONF_BUFFER_SIZE 1280 + +#undef UIP_CONF_RECEIVE_WINDOW +#define UIP_CONF_RECEIVE_WINDOW 60 + +#define SLIP_DEV_CONF_SEND_DELAY (CLOCK_SECOND / 32) + +#undef WEBSERVER_CONF_CFS_CONNS +#define WEBSERVER_CONF_CFS_CONNS 2 + +#define SERIALIZE_ATTRIBUTES 1 + +#define CMD_CONF_OUTPUT border_router_cmd_output + +#undef NETSTACK_CONF_RDC +#define NETSTACK_CONF_RDC border_router_rdc_driver + +/* used by wpcap (see /cpu/native/net/wpcap-drv.c) */ +#define SELECT_CALLBACK 1 + +#endif /* __PROJECT_ROUTER_CONF_H__ */ diff --git a/examples/osd/native-border-router/slip-config.c b/examples/osd/native-border-router/slip-config.c new file mode 100644 index 000000000..84d256127 --- /dev/null +++ b/examples/osd/native-border-router/slip-config.c @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2011, 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. + */ + +/** + * \file + * Slip configuration + * \author + * Niclas Finne + * Joakim Eriksson + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "contiki.h" + +int slip_config_verbose = 0; +const char *slip_config_ipaddr; +int slip_config_flowcontrol = 0; +int slip_config_timestamp = 0; +const char *slip_config_siodev = NULL; +const char *slip_config_host = NULL; +const char *slip_config_port = NULL; +char slip_config_tundev[32] = { "" }; +uint16_t slip_config_basedelay = 0; + +#ifndef BAUDRATE +#define BAUDRATE B115200 +#endif +speed_t slip_config_b_rate = BAUDRATE; + +/*---------------------------------------------------------------------------*/ +int +slip_config_handle_arguments(int argc, char **argv) +{ + const char *prog; + char c; + int baudrate = 115200; + + slip_config_verbose = 0; + + prog = argv[0]; + while((c = getopt(argc, argv, "B:H:D:Lhs:t:v::d::a:p:T")) != -1) { + switch(c) { + case 'B': + baudrate = atoi(optarg); + break; + + case 'H': + slip_config_flowcontrol = 1; + break; + + case 'L': + slip_config_timestamp = 1; + break; + + case 's': + if(strncmp("/dev/", optarg, 5) == 0) { + slip_config_siodev = optarg + 5; + } else { + slip_config_siodev = optarg; + } + break; + + case 't': + if(strncmp("/dev/", optarg, 5) == 0) { + strncpy(slip_config_tundev, optarg + 5, sizeof(slip_config_tundev)); + } else { + strncpy(slip_config_tundev, optarg, sizeof(slip_config_tundev)); + } + break; + + case 'a': + slip_config_host = optarg; + break; + + case 'p': + slip_config_port = optarg; + break; + + case 'd': + slip_config_basedelay = 10; + if(optarg) slip_config_basedelay = atoi(optarg); + break; + + case 'v': + slip_config_verbose = 2; + if(optarg) slip_config_verbose = atoi(optarg); + break; + + case '?': + case 'h': + default: +fprintf(stderr,"usage: %s [options] ipaddress\n", prog); +fprintf(stderr,"example: border-router.native -L -v2 -s ttyUSB1 aaaa::1/64\n"); +fprintf(stderr,"Options are:\n"); +#ifdef linux +fprintf(stderr," -B baudrate 9600,19200,38400,57600,115200,921600 (default 115200)\n"); +#else +fprintf(stderr," -B baudrate 9600,19200,38400,57600,115200 (default 115200)\n"); +#endif +fprintf(stderr," -H Hardware CTS/RTS flow control (default disabled)\n"); +fprintf(stderr," -L Log output format (adds time stamps)\n"); +fprintf(stderr," -s siodev Serial device (default /dev/ttyUSB0)\n"); +fprintf(stderr," -a host Connect via TCP to server at \n"); +fprintf(stderr," -p port Connect via TCP to server at :\n"); +fprintf(stderr," -t tundev Name of interface (default tun0)\n"); +fprintf(stderr," -v[level] Verbosity level\n"); +fprintf(stderr," -v0 No messages\n"); +fprintf(stderr," -v1 Encapsulated SLIP debug messages (default)\n"); +fprintf(stderr," -v2 Printable strings after they are received\n"); +fprintf(stderr," -v3 Printable strings and SLIP packet notifications\n"); +fprintf(stderr," -v4 All printable characters as they are received\n"); +fprintf(stderr," -v5 All SLIP packets in hex\n"); +fprintf(stderr," -v Equivalent to -v3\n"); +fprintf(stderr," -d[basedelay] Minimum delay between outgoing SLIP packets.\n"); +fprintf(stderr," Actual delay is basedelay*(#6LowPAN fragments) milliseconds.\n"); +fprintf(stderr," -d is equivalent to -d10.\n"); +exit(1); + break; + } + } + argc -= optind - 1; + argv += optind - 1; + + if(argc != 2 && argc != 3) { + err(1, "usage: %s [-B baudrate] [-H] [-L] [-s siodev] [-t tundev] [-T] [-v verbosity] [-d delay] [-a serveraddress] [-p serverport] ipaddress", prog); + } + slip_config_ipaddr = argv[1]; + + switch(baudrate) { + case -2: + break; /* Use default. */ + case 9600: + slip_config_b_rate = B9600; + break; + case 19200: + slip_config_b_rate = B19200; + break; + case 38400: + slip_config_b_rate = B38400; + break; + case 57600: + slip_config_b_rate = B57600; + break; + case 115200: + slip_config_b_rate = B115200; + break; +#ifdef linux + case 921600: + slip_config_b_rate = B921600; + break; +#endif + default: + err(1, "unknown baudrate %d", baudrate); + break; + } + + if(*slip_config_tundev == '\0') { + /* Use default. */ + strcpy(slip_config_tundev, "tun0"); + } + return 1; +} +/*---------------------------------------------------------------------------*/ diff --git a/examples/osd/native-border-router/slip-dev.c b/examples/osd/native-border-router/slip-dev.c new file mode 100644 index 000000000..a38c6a0c3 --- /dev/null +++ b/examples/osd/native-border-router/slip-dev.c @@ -0,0 +1,546 @@ +/* + * Copyright (c) 2001, Adam Dunkels. + * Copyright (c) 2009, 2010 Joakim Eriksson, Niclas Finne, Dogan Yazar. + * 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. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + */ + + /* Below define allows importing saved output into Wireshark as "Raw IP" packet type */ +#define WIRESHARK_IMPORT_FORMAT 1 +#include "contiki.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "net/netstack.h" +#include "net/packetbuf.h" +#include "cmd.h" +#include "border-router-cmds.h" + +extern int slip_config_verbose; +extern int slip_config_flowcontrol; +extern const char *slip_config_siodev; +extern const char *slip_config_host; +extern const char *slip_config_port; +extern uint16_t slip_config_basedelay; +extern speed_t slip_config_b_rate; + +#ifdef SLIP_DEV_CONF_SEND_DELAY +#define SEND_DELAY SLIP_DEV_CONF_SEND_DELAY +#else +#define SEND_DELAY 0 +#endif + +int devopen(const char *dev, int flags); + +static FILE *inslip; + +/* for statistics */ +long slip_sent = 0; +long slip_received = 0; + +int slipfd = 0; + +//#define PROGRESS(s) fprintf(stderr, s) +#define PROGRESS(s) do { } while(0) + +#define SLIP_END 0300 +#define SLIP_ESC 0333 +#define SLIP_ESC_END 0334 +#define SLIP_ESC_ESC 0335 + +/*---------------------------------------------------------------------------*/ +static void * +get_in_addr(struct sockaddr *sa) +{ + if(sa->sa_family == AF_INET) { + return &(((struct sockaddr_in*)sa)->sin_addr); + } + return &(((struct sockaddr_in6*)sa)->sin6_addr); +} +/*---------------------------------------------------------------------------*/ +static int +connect_to_server(const char *host, const char *port) +{ + /* Setup TCP connection */ + struct addrinfo hints, *servinfo, *p; + char s[INET6_ADDRSTRLEN]; + int rv, fd; + + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + + if((rv = getaddrinfo(host, port, &hints, &servinfo)) != 0) { + err(1, "getaddrinfo: %s", gai_strerror(rv)); + return -1; + } + + /* loop through all the results and connect to the first we can */ + for(p = servinfo; p != NULL; p = p->ai_next) { + if((fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) { + perror("client: socket"); + continue; + } + + if(connect(fd, p->ai_addr, p->ai_addrlen) == -1) { + close(fd); + perror("client: connect"); + continue; + } + break; + } + + if(p == NULL) { + err(1, "can't connect to ``%s:%s''", host, port); + return -1; + } + + fcntl(fd, F_SETFL, O_NONBLOCK); + + inet_ntop(p->ai_family, get_in_addr((struct sockaddr *)p->ai_addr), + s, sizeof(s)); + + /* all done with this structure */ + freeaddrinfo(servinfo); + return fd; +} +/*---------------------------------------------------------------------------*/ +int +is_sensible_string(const unsigned char *s, int len) +{ + int i; + for(i = 1; i < len; i++) { + if(s[i] == 0 || s[i] == '\r' || s[i] == '\n' || s[i] == '\t') { + continue; + } else if(s[i] < ' ' || '~' < s[i]) { + return 0; + } + } + return 1; +} +/*---------------------------------------------------------------------------*/ +void +slip_packet_input(unsigned char *data, int len) +{ + packetbuf_copyfrom(data, len); + if(slip_config_verbose > 0) { + printf("Packet input over SLIP: %d\n", len); + } + NETSTACK_RDC.input(); +} +/*---------------------------------------------------------------------------*/ +/* + * Read from serial, when we have a packet call slip_packet_input. No output + * buffering, input buffered by stdio. + */ +void +serial_input(FILE *inslip) +{ + unsigned char inbuf[2048]; + static int inbufptr = 0; + int ret,i; + unsigned char c; + +#ifdef linux + ret = fread(&c, 1, 1, inslip); + if(ret == -1 || ret == 0) err(1, "serial_input: read"); + goto after_fread; +#endif + + read_more: + if(inbufptr >= sizeof(inbuf)) { + fprintf(stderr, "*** dropping large %d byte packet\n", inbufptr); + inbufptr = 0; + } + ret = fread(&c, 1, 1, inslip); +#ifdef linux + after_fread: +#endif + if(ret == -1) { + err(1, "serial_input: read"); + } + if(ret == 0) { + clearerr(inslip); + return; + } + slip_received++; + switch(c) { + case SLIP_END: + if(inbufptr > 0) { + if(inbuf[0] == '!') { + command_context = CMD_CONTEXT_RADIO; + cmd_input(inbuf, inbufptr); + } else if(inbuf[0] == '?') { +#define DEBUG_LINE_MARKER '\r' + } else if(inbuf[0] == DEBUG_LINE_MARKER) { + fwrite(inbuf + 1, inbufptr - 1, 1, stdout); + } else if(is_sensible_string(inbuf, inbufptr)) { + if(slip_config_verbose == 1) { /* strings already echoed below for verbose>1 */ + fwrite(inbuf, inbufptr, 1, stdout); + } + } else { + if(slip_config_verbose > 2) { + printf("Packet from SLIP of length %d - write TUN\n", inbufptr); + if(slip_config_verbose > 4) { +#if WIRESHARK_IMPORT_FORMAT + printf("0000"); + for(i = 0; i < inbufptr; i++) printf(" %02x", inbuf[i]); +#else + printf(" "); + for(i = 0; i < inbufptr; i++) { + printf("%02x", inbuf[i]); + if((i & 3) == 3) printf(" "); + if((i & 15) == 15) printf("\n "); + } +#endif + printf("\n"); + } + } + slip_packet_input(inbuf, inbufptr); + } + inbufptr = 0; + } + break; + + case SLIP_ESC: + if(fread(&c, 1, 1, inslip) != 1) { + clearerr(inslip); + /* Put ESC back and give up! */ + ungetc(SLIP_ESC, inslip); + return; + } + + switch(c) { + case SLIP_ESC_END: + c = SLIP_END; + break; + case SLIP_ESC_ESC: + c = SLIP_ESC; + break; + } + /* FALLTHROUGH */ + default: + inbuf[inbufptr++] = c; + + /* Echo lines as they are received for verbose=2,3,5+ */ + /* Echo all printable characters for verbose==4 */ + if(slip_config_verbose == 4) { + if(c == 0 || c == '\r' || c == '\n' || c == '\t' || (c >= ' ' && c <= '~')) { + fwrite(&c, 1, 1, stdout); + } + } else if(slip_config_verbose >= 2) { + if(c == '\n' && is_sensible_string(inbuf, inbufptr)) { + fwrite(inbuf, inbufptr, 1, stdout); + inbufptr = 0; + } + } + break; + } + + goto read_more; +} + +unsigned char slip_buf[2048]; +int slip_end, slip_begin, slip_packet_end, slip_packet_count; +static struct timer send_delay_timer; +/* delay between slip packets */ +static clock_time_t send_delay = SEND_DELAY; +/*---------------------------------------------------------------------------*/ +static void +slip_send(int fd, unsigned char c) +{ + if(slip_end >= sizeof(slip_buf)) { + err(1, "slip_send overflow"); + } + slip_buf[slip_end] = c; + slip_end++; + slip_sent++; + if(c == SLIP_END) { + /* Full packet received. */ + slip_packet_count++; + if(slip_packet_end == 0) { + slip_packet_end = slip_end; + } + } +} +/*---------------------------------------------------------------------------*/ +int +slip_empty() +{ + return slip_packet_end == 0; +} +/*---------------------------------------------------------------------------*/ +void +slip_flushbuf(int fd) +{ + int n; + + if(slip_empty()) { + return; + } + + n = write(fd, slip_buf + slip_begin, slip_packet_end - slip_begin); + + if(n == -1 && errno != EAGAIN) { + err(1, "slip_flushbuf write failed"); + } else if(n == -1) { + PROGRESS("Q"); /* Outqueue is full! */ + } else { + slip_begin += n; + if(slip_begin == slip_packet_end) { + slip_packet_count--; + if(slip_end > slip_packet_end) { + memcpy(slip_buf, slip_buf + slip_packet_end, + slip_end - slip_packet_end); + } + slip_end -= slip_packet_end; + slip_begin = slip_packet_end = 0; + if(slip_end > 0) { + /* Find end of next slip packet */ + for(n = 1; n < slip_end; n++) { + if(slip_buf[n] == SLIP_END) { + slip_packet_end = n + 1; + break; + } + } + /* a delay between slip packets to avoid losing data */ + if(send_delay > 0) { + timer_set(&send_delay_timer, send_delay); + } + } + } + } +} +/*---------------------------------------------------------------------------*/ +static void +write_to_serial(int outfd, const uint8_t *inbuf, int len) +{ + const uint8_t *p = inbuf; + int i; + + if(slip_config_verbose > 2) { +#ifdef __CYGWIN__ + printf("Packet from WPCAP of length %d - write SLIP\n", len); +#else + printf("Packet from TUN of length %d - write SLIP\n", len); +#endif + if(slip_config_verbose > 4) { +#if WIRESHARK_IMPORT_FORMAT + printf("0000"); + for(i = 0; i < len; i++) printf(" %02x", p[i]); +#else + printf(" "); + for(i = 0; i < len; i++) { + printf("%02x", p[i]); + if((i & 3) == 3) printf(" "); + if((i & 15) == 15) printf("\n "); + } +#endif + printf("\n"); + } + } + + /* It would be ``nice'' to send a SLIP_END here but it's not + * really necessary. + */ + /* slip_send(outfd, SLIP_END); */ + + for(i = 0; i < len; i++) { + switch(p[i]) { + case SLIP_END: + slip_send(outfd, SLIP_ESC); + slip_send(outfd, SLIP_ESC_END); + break; + case SLIP_ESC: + slip_send(outfd, SLIP_ESC); + slip_send(outfd, SLIP_ESC_ESC); + break; + default: + slip_send(outfd, p[i]); + break; + } + } + slip_send(outfd, SLIP_END); + PROGRESS("t"); +} +/*---------------------------------------------------------------------------*/ +/* writes an 802.15.4 packet to slip-radio */ +void +write_to_slip(const uint8_t *buf, int len) +{ + if(slipfd > 0) { + write_to_serial(slipfd, buf, len); + } +} +/*---------------------------------------------------------------------------*/ +static void +stty_telos(int fd) +{ + struct termios tty; + speed_t speed = slip_config_b_rate; + int i; + + if(tcflush(fd, TCIOFLUSH) == -1) err(1, "tcflush"); + + if(tcgetattr(fd, &tty) == -1) err(1, "tcgetattr"); + + cfmakeraw(&tty); + + /* Nonblocking read. */ + tty.c_cc[VTIME] = 0; + tty.c_cc[VMIN] = 0; + if(slip_config_flowcontrol) { + tty.c_cflag |= CRTSCTS; + } else { + tty.c_cflag &= ~CRTSCTS; + } + tty.c_cflag &= ~HUPCL; + tty.c_cflag &= ~CLOCAL; + + cfsetispeed(&tty, speed); + cfsetospeed(&tty, speed); + + if(tcsetattr(fd, TCSAFLUSH, &tty) == -1) err(1, "tcsetattr"); + +#if 1 + /* Nonblocking read and write. */ + /* if(fcntl(fd, F_SETFL, O_NONBLOCK) == -1) err(1, "fcntl"); */ + + tty.c_cflag |= CLOCAL; + if(tcsetattr(fd, TCSAFLUSH, &tty) == -1) err(1, "tcsetattr"); + + i = TIOCM_DTR; + if(ioctl(fd, TIOCMBIS, &i) == -1) err(1, "ioctl"); +#endif + + usleep(10*1000); /* Wait for hardware 10ms. */ + + /* Flush input and output buffers. */ + if(tcflush(fd, TCIOFLUSH) == -1) err(1, "tcflush"); +} +/*---------------------------------------------------------------------------*/ +static int +set_fd(fd_set *rset, fd_set *wset) +{ + /* Anything to flush? */ + if(!slip_empty() && (send_delay == 0 || timer_expired(&send_delay_timer))) { + FD_SET(slipfd, wset); + } + + FD_SET(slipfd, rset); /* Read from slip ASAP! */ + return 1; +} +/*---------------------------------------------------------------------------*/ +static void +handle_fd(fd_set *rset, fd_set *wset) +{ + if(FD_ISSET(slipfd, rset)) { + serial_input(inslip); + } + + if(FD_ISSET(slipfd, wset)) { + slip_flushbuf(slipfd); + } +} +/*---------------------------------------------------------------------------*/ +static const struct select_callback slip_callback = { set_fd, handle_fd }; +/*---------------------------------------------------------------------------*/ +void +slip_init(void) +{ + setvbuf(stdout, NULL, _IOLBF, 0); /* Line buffered output. */ + + if(slip_config_host != NULL) { + if(slip_config_port == NULL) { + slip_config_port = "60001"; + } + slipfd = connect_to_server(slip_config_host, slip_config_port); + if(slipfd == -1) { + err(1, "can't connect to ``%s:%s''", slip_config_host, slip_config_port); + } + + } else if(slip_config_siodev != NULL) { + if(strcmp(slip_config_siodev, "null") == 0) { + /* Disable slip */ + return; + } + slipfd = devopen(slip_config_siodev, O_RDWR | O_NONBLOCK); + if(slipfd == -1) { + err(1, "can't open siodev ``/dev/%s''", slip_config_siodev); + } + + } else { + static const char *siodevs[] = { + "ttyUSB0", "cuaU0", "ucom0" /* linux, fbsd6, fbsd5 */ + }; + int i; + for(i = 0; i < 3; i++) { + slip_config_siodev = siodevs[i]; + slipfd = devopen(slip_config_siodev, O_RDWR | O_NONBLOCK); + if(slipfd != -1) { + break; + } + } + if(slipfd == -1) { + err(1, "can't open siodev"); + } + } + + select_set_callback(slipfd, &slip_callback); + + if(slip_config_host != NULL) { + fprintf(stderr, "********SLIP opened to ``%s:%s''\n", slip_config_host, + slip_config_port); + } else { + fprintf(stderr, "********SLIP started on ``/dev/%s''\n", slip_config_siodev); + stty_telos(slipfd); + } + + timer_set(&send_delay_timer, 0); + slip_send(slipfd, SLIP_END); + inslip = fdopen(slipfd, "r"); + if(inslip == NULL) { + err(1, "main: fdopen"); + } +} +/*---------------------------------------------------------------------------*/ diff --git a/examples/osd/native-border-router/tun-bridge.c b/examples/osd/native-border-router/tun-bridge.c new file mode 100644 index 000000000..970b4cc79 --- /dev/null +++ b/examples/osd/native-border-router/tun-bridge.c @@ -0,0 +1,311 @@ +/* + * Copyright (c) 2011, 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. + */ + +/** + * \author + * Niclas Finne + * Joakim Eriksson + */ + +#include "net/uip.h" +#include "net/uip-ds6.h" +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + +#define DEBUG DEBUG_NONE +#include "net/uip-debug.h" + +#ifdef linux +#include +#include +#endif + +#include +#include "net/netstack.h" +#include "net/packetbuf.h" +#include "cmd.h" +#include "border-router.h" + +extern const char *slip_config_ipaddr; +extern char slip_config_tundev[32]; +extern uint16_t slip_config_basedelay; + +#ifndef __CYGWIN__ +static int tunfd; + +static int set_fd(fd_set *rset, fd_set *wset); +static void handle_fd(fd_set *rset, fd_set *wset); +static const struct select_callback tun_select_callback = { + set_fd, + handle_fd +}; +#endif /* __CYGWIN__ */ + +int ssystem(const char *fmt, ...) + __attribute__((__format__ (__printf__, 1, 2))); +int +ssystem(const char *fmt, ...) __attribute__((__format__ (__printf__, 1, 2))); + +int +ssystem(const char *fmt, ...) +{ + char cmd[128]; + va_list ap; + va_start(ap, fmt); + vsnprintf(cmd, sizeof(cmd), fmt, ap); + va_end(ap); + printf("%s\n", cmd); + fflush(stdout); + return system(cmd); +} + +/*---------------------------------------------------------------------------*/ +void +cleanup(void) +{ + ssystem("ifconfig %s down", slip_config_tundev); +#ifndef linux + ssystem("sysctl -w net.ipv6.conf.all.forwarding=1"); +#endif + ssystem("netstat -nr" + " | awk '{ if ($2 == \"%s\") print \"route delete -net \"$1; }'" + " | sh", + slip_config_tundev); +} + +/*---------------------------------------------------------------------------*/ +void +sigcleanup(int signo) +{ + fprintf(stderr, "signal %d\n", signo); + exit(0); /* exit(0) will call cleanup() */ +} + +/*---------------------------------------------------------------------------*/ +void +ifconf(const char *tundev, const char *ipaddr) +{ +#ifdef linux + ssystem("ifconfig %s inet `hostname` up", tundev); + ssystem("ifconfig %s add %s", tundev, ipaddr); +#elif defined(__APPLE__) + ssystem("ifconfig %s inet6 %s up", tundev, ipaddr); + ssystem("sysctl -w net.inet.ip.forwarding=1"); +#else + ssystem("ifconfig %s inet `hostname` %s up", tundev, ipaddr); + ssystem("sysctl -w net.inet.ip.forwarding=1"); +#endif /* !linux */ + + /* Print the configuration to the console. */ + ssystem("ifconfig %s\n", tundev); +} +/*---------------------------------------------------------------------------*/ +int +devopen(const char *dev, int flags) +{ + char t[32]; + strcpy(t, "/dev/"); + strncat(t, dev, sizeof(t) - 5); + return open(t, flags); +} +/*---------------------------------------------------------------------------*/ +#ifdef linux +int +tun_alloc(char *dev) +{ + struct ifreq ifr; + int fd, err; + + if( (fd = open("/dev/net/tun", O_RDWR)) < 0 ) { + return -1; + } + + memset(&ifr, 0, sizeof(ifr)); + + /* Flags: IFF_TUN - TUN device (no Ethernet headers) + * IFF_NO_PI - Do not provide packet information + */ + ifr.ifr_flags = IFF_TUN | IFF_NO_PI; + if(*dev != 0) + strncpy(ifr.ifr_name, dev, IFNAMSIZ); + + if((err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0 ) { + close(fd); + return err; + } + strcpy(dev, ifr.ifr_name); + return fd; +} +#else +int +tun_alloc(char *dev) +{ + return devopen(dev, O_RDWR); +} +#endif + +#ifdef __CYGWIN__ +/*wpcap process is used to connect to host interface */ +void +tun_init() +{ + setvbuf(stdout, NULL, _IOLBF, 0); /* Line buffered output. */ + + slip_init(); +} + +#else + +static uint16_t delaymsec=0; +static uint32_t delaystartsec,delaystartmsec; + +/*---------------------------------------------------------------------------*/ +void +tun_init() +{ + setvbuf(stdout, NULL, _IOLBF, 0); /* Line buffered output. */ + + slip_init(); + + tunfd = tun_alloc(slip_config_tundev); + if(tunfd == -1) err(1, "main: open"); + + select_set_callback(tunfd, &tun_select_callback); + + fprintf(stderr, "opened %s device ``/dev/%s''\n", + "tun", slip_config_tundev); + + atexit(cleanup); + signal(SIGHUP, sigcleanup); + signal(SIGTERM, sigcleanup); + signal(SIGINT, sigcleanup); + ifconf(slip_config_tundev, slip_config_ipaddr); +} + +/*---------------------------------------------------------------------------*/ +void +tun_output(uint8_t *data, int len) +{ + /* fprintf(stderr, "*** Writing to tun...%d\n", len); */ + if(write(tunfd, data, len) != len) { + err(1, "serial_to_tun: write"); + } +} +/*---------------------------------------------------------------------------*/ +int +tun_input(unsigned char *data, int maxlen) +{ + int size; + if((size = read(tunfd, data, maxlen)) == -1) + err(1, "tun_input: read"); + return size; +} + +/*---------------------------------------------------------------------------*/ +static void +init(void) +{ +} +/*---------------------------------------------------------------------------*/ +static void +output(void) +{ + PRINTF("SUT: %u\n", uip_len); + if(uip_len > 0) { + tun_output(&uip_buf[UIP_LLH_LEN], uip_len); + } +} + + +const struct uip_fallback_interface rpl_interface = { + init, output +}; + +/*---------------------------------------------------------------------------*/ +/* tun and slip select callback */ +/*---------------------------------------------------------------------------*/ +static int +set_fd(fd_set *rset, fd_set *wset) +{ + FD_SET(tunfd, rset); + return 1; +} + +/*---------------------------------------------------------------------------*/ + +static void +handle_fd(fd_set *rset, fd_set *wset) +{ + /* Optional delay between outgoing packets */ + /* Base delay times number of 6lowpan fragments to be sent */ + /* delaymsec = 10; */ + if(delaymsec) { + struct timeval tv; + int dmsec; + gettimeofday(&tv, NULL); + dmsec=(tv.tv_sec-delaystartsec)*1000+tv.tv_usec/1000-delaystartmsec; + if(dmsec<0) delaymsec=0; + if(dmsec>delaymsec) delaymsec=0; + } + + if(delaymsec==0) { + int size; + + if(FD_ISSET(tunfd, rset)) { + size = tun_input(&uip_buf[UIP_LLH_LEN], sizeof(uip_buf)); + /* printf("TUN data incoming read:%d\n", size); */ + uip_len = size; + tcpip_input(); + + if(slip_config_basedelay) { + struct timeval tv; + gettimeofday(&tv, NULL) ; + delaymsec=slip_config_basedelay; + delaystartsec =tv.tv_sec; + delaystartmsec=tv.tv_usec/1000; + } + } + } +} +#endif /* __CYGWIN_ */ + +/*---------------------------------------------------------------------------*/