From e770aed5c7145eaa958d4dd9fc9b460f0e69d254 Mon Sep 17 00:00:00 2001 From: mharvan Date: Wed, 5 Dec 2007 22:58:41 +0000 Subject: [PATCH] 6lowpan import --- apps/6lowpancli/CliAppC.nc | 86 + apps/6lowpancli/CliC.nc | 256 ++ apps/6lowpancli/Makefile | 12 + apps/6lowpancli/README | 42 + support/sdk/c/6lowpan/serial_tun/6lowpan.h | 378 +++ support/sdk/c/6lowpan/serial_tun/Makefile | 18 + support/sdk/c/6lowpan/serial_tun/README | 14 + support/sdk/c/6lowpan/serial_tun/serial_tun.c | 1249 ++++++++++ support/sdk/c/6lowpan/serial_tun/tun_dev.c | 129 + support/sdk/c/6lowpan/serial_tun/tun_dev.h | 40 + tos/lib/net/6lowpan/IP.h | 39 + tos/lib/net/6lowpan/IP.nc | 78 + tos/lib/net/6lowpan/IPC.nc | 82 + tos/lib/net/6lowpan/IPP.nc | 2192 +++++++++++++++++ tos/lib/net/6lowpan/IP_internal.h | 401 +++ tos/lib/net/6lowpan/README | 72 + tos/lib/net/6lowpan/UDPClient.nc | 115 + 17 files changed, 5203 insertions(+) create mode 100644 apps/6lowpancli/CliAppC.nc create mode 100644 apps/6lowpancli/CliC.nc create mode 100644 apps/6lowpancli/Makefile create mode 100644 apps/6lowpancli/README create mode 100644 support/sdk/c/6lowpan/serial_tun/6lowpan.h create mode 100644 support/sdk/c/6lowpan/serial_tun/Makefile create mode 100644 support/sdk/c/6lowpan/serial_tun/README create mode 100644 support/sdk/c/6lowpan/serial_tun/serial_tun.c create mode 100644 support/sdk/c/6lowpan/serial_tun/tun_dev.c create mode 100644 support/sdk/c/6lowpan/serial_tun/tun_dev.h create mode 100644 tos/lib/net/6lowpan/IP.h create mode 100644 tos/lib/net/6lowpan/IP.nc create mode 100644 tos/lib/net/6lowpan/IPC.nc create mode 100644 tos/lib/net/6lowpan/IPP.nc create mode 100644 tos/lib/net/6lowpan/IP_internal.h create mode 100644 tos/lib/net/6lowpan/README create mode 100644 tos/lib/net/6lowpan/UDPClient.nc diff --git a/apps/6lowpancli/CliAppC.nc b/apps/6lowpancli/CliAppC.nc new file mode 100644 index 00000000..5c6fd648 --- /dev/null +++ b/apps/6lowpancli/CliAppC.nc @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2007 Matus Harvan + * All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * 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 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 + * OWNER 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. + */ +#include "printf.h" + +#if defined(ENABLE_MICAZ_TEMP_SENSOR) || defined(ENABLE_TELOSB_TEMP_SENSOR) +#define ENABLE_TEMP_SENSOR +#endif /* ENABLE_MICAZ_TEMP_SENSOR || ENABLE_TELOSB_TEMP_SENSOR */ + +#if defined(ENABLE_MICAZ_LIGHT_SENSOR) || defined(ENABLE_TELOSB_LIGHT_SENSOR) +#define ENABLE_LIGHT_SENSOR +#endif /* ENABLE_MICAZ_LIGHT_SENSOR || ENABLE_TELOSB_LIGHT_SENSOR */ + +enum { + AM_IP_MSG = 0x41, +}; + +configuration CliAppC {} +implementation { + components CliC as App, LedsC, MainC; + components IPC; + + App.Boot -> MainC.Boot; + App.Leds -> LedsC; + App.IPControl -> IPC.IPControl; + App.IP -> IPC.IP; + App.UDPClient -> IPC.UDPClient[unique("UDPClient")]; + +#ifdef ENABLE_SOUNDER + components SounderC; + App.Sounder -> SounderC; +#endif /* ENABLE_SOUNDER */ + +#ifdef ENABLE_MICAZ_TEMP_SENSOR + components new TempC(); // telosb temp/humidity sensor + App.TempSensorC -> TempC; +#endif /* ENABLE_MICAZ_TEMP_SENSOR */ + +#ifdef ENABLE_TELOSB_TEMP_SENSOR + components new SensirionSht11C(); // telosb temp/humidity sensor + App.TempSensorC -> SensirionSht11C.Temperature; +#endif /* ENABLE_TELOSB_TEMP_SENSOR */ + +#ifdef ENABLE_MICAZ_LIGHT_SENSOR + components new PhotoC();// telosb visible light sensor + App.LightSensorC -> PhotoC; +#endif /* ENABLE_MICAZ_TEMP_SENSOR */ + +#ifdef ENABLE_TELOSB_LIGHT_SENSOR + // total solar radiation sensor + //new HamamatsuS10871TsrC() as Sensor, // telosb (IR) light sensor + // photosynthetically-active radiation sensor + components new HamamatsuS1087ParC();// telosb visible light sensor + App.LightSensorC -> HamamatsuS1087ParC; +#endif /* ENABLE_TELOSB_TEMP_SENSOR */ +} + + + diff --git a/apps/6lowpancli/CliC.nc b/apps/6lowpancli/CliC.nc new file mode 100644 index 00000000..89225cd9 --- /dev/null +++ b/apps/6lowpancli/CliC.nc @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2007 Matus Harvan + * All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * 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 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 + * OWNER 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. + */ + +#include "Timer.h" + +#define min(a,b) ( (a>b) ? b : a ) +#define max(a,b) ( (a>b) ? a : b ) + +module CliC { + uses { + interface Leds; + interface Boot; + interface IP; + interface UDPClient; + interface SplitControl as IPControl; +#ifdef ENABLE_SOUNDER + interface Mts300Sounder as Sounder; +#endif /* ENABLE_SOUNDER */ +#ifdef ENABLE_TEMP_SENSOR + interface Read as TempSensorC; +#endif /* ENABLE_TEMP_SENSOR */ +#ifdef ENABLE_LIGHT_SENSOR + interface Read as LightSensorC; +#endif /* ENABLE_LIGHT_SENSOR */ + } +} +implementation { +#ifndef MINIMIZE_MEMORY + char *help_buf = "6lowpan cli supported commands:\n" + "\tset led {0,1,2} {on,off} -- toggle leds\n" +#ifdef ENABLE_SOUNDER + "\tsounder time_in_ms\n" +#endif /* ENABLE_SOUNDER */ +#ifdef ENABLE_TEMP_SENSOR + "\tget temp\n" +#endif /* ENABLE_TEMP_SENSOR */ +#ifdef ENABLE_LIGHT_SENSOR + "\tget light\n" +#endif /* ENABLE_LIGHT_SENSOR */ + "\tsend small udp\n" + "\tsend large udp\n" + "\thelp\n"; + char *small_udp_buf = "\n"; + char *large_udp_buf = "\n"; + /* + char *small_udp_buf = "----- SMALL UDP DATA BUFFER -----\n"; + char *large_udp_buf = + "This is a large testing string. It should undergo " \ + "6lowpan fragmentation\n" \ + "0............................................................\n" \ + "1............................................................\n" \ + "2............................................................\n" \ + "3............................................................\n" \ + "4............................................................\n" \ + "5............................................................\n" \ + "6............................................................\n" \ + "7............................................................\n" \ + "8............................................................\n" \ + "9............................................................\n" \ + "A............................................................\n" \ + "B............................................................\n" \ + "C............................................................\n" \ + "D............................................................\n" \ + "E............................................................\n" \ + "10...........................................................\n" \ + "11...........................................................\n" \ + "12...........................................................\n" \ + "13(shorter)\n" \ + "---- END OF THE LARGE UDP DATA ----\n"; + */ +#if defined(ENABLE_TEMP_SENSOR) || defined(ENABLE_LIGHT_SENSOR) + char sensor_buf[15]; + bool sensor_buf_busy = FALSE; + ip6_addr_t sensor_addr; + uint16_t sensor_port; +#endif /* ENABLE_TEMP_SENSOR | ENABLE_LIGHT_SENSOR */ +#endif /* MINIMIZE_MEMORY */ + + event void Boot.booted() { + /* set an IP address */ + ip6_addr_t addr = {{0x20, 0x01, + 0x06, 0x38, + 0x07, 0x09, + 0x12, 0x34, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00 + }}; + //call IP.setAddress(&addr); + call IP.setAddressAutoconf(&addr); + + call IPControl.start(); + } + + event void IPControl.startDone(error_t err) { + + call UDPClient.listen(1234); + } + event void IPControl.stopDone(error_t err) {} + + event void UDPClient.receive(const ip6_addr_t *addr, const uint16_t port, + uint8_t *buf, uint16_t len ) + { +#ifndef MINIMIZE_MEMORY + if ( strncmp(buf, "set ", min(len, 4)) == 0 && len>0) { + buf += 4; + len -= 4; + if ( strncmp(buf, "led ", min(len, 4)) == 0 && len>0) { + buf += 4; + len -= 4; + + if ( strncmp(buf, "0 ", min(len, 2)) == 0 && len>0) { + buf += 2; + len -= 2; + if ( strncmp(buf, "on", min(len, 2)) == 0 && len>0) { + call Leds.led0On(); + } else if (strncmp(buf, "off", min(len, 3)) == 0 && len>0){ + call Leds.led0Off(); + } + } else if ( strncmp(buf, "1 ", min(len, 2)) == 0 && len>0) { + buf += 2; + len -= 2; + if ( strncmp(buf, "on", min(len, 2)) == 0 && len>0) { + call Leds.led1On(); + } else if (strncmp(buf, "off", min(len, 3)) == 0 && len>0){ + call Leds.led1Off(); + } + } else if ( strncmp(buf, "2 ", min(len, 2)) == 0 && len>0) { + buf += 2; + len -= 2; + if ( strncmp(buf, "on", min(len, 2)) == 0 && len>0) { + call Leds.led2On(); + } else if (strncmp(buf, "off", min(len, 3)) == 0 && len>0){ + call Leds.led2Off(); + } + } + } +#ifdef ENABLE_SOUNDER + } else if ( strncmp(buf, "sounder ", min(len, 8)) == 0 + && len>0) { + buf += 8; + len -= 8; + call Sounder.beep(atoi(buf)); +#endif /* ENABLE_SOUNDER */ + +#ifdef ENABLE_TEMP_SENSOR + } else if ( strncmp(buf, "get temp", min(len, 8)) == 0 + && len>0) { + memcpy(&sensor_addr, addr, sizeof(*addr)); + sensor_port = port; + //call UDPClient.sendTo(addr, port, "reading temp...\n", 16); + call TempSensorC.read(); +#endif /* ENABLE_TEMP_SENSOR */ + +#ifdef ENABLE_LIGHT_SENSOR + } else if ( strncmp(buf, "get light", min(len, 8)) == 0 + && len>0) { + memcpy(&sensor_addr, addr, sizeof(*addr)); + sensor_port = port; + //call UDPClient.sendTo(addr, port, "reading light...\n", 17); + call LightSensorC.read(); +#endif /* ENABLE_LIGHT_SENSOR */ + + } else if (strncmp(buf, "send large udp", min(len, 14)) == 0 + && len>0) { + call UDPClient.sendTo(addr, port, + large_udp_buf, strlen(large_udp_buf)); + } else if (strncmp(buf, "send small udp", min(len, 14)) == 0 + && len>0) { + call UDPClient.sendTo(addr, port, + small_udp_buf, strlen(small_udp_buf)); + } else if (strncmp(buf, "help", min(len, 14)) == 0 + && len>0) { + call UDPClient.sendTo(addr, port, + help_buf, strlen(help_buf)); + } else { + call UDPClient.sendTo(addr, port, + help_buf, strlen(help_buf)); + } +#endif /* MINIMIZE_MEMORY */ + } + + event void UDPClient.sendDone(error_t result, void* buf) + { +#if defined(ENABLE_TEMP_SENSOR) || defined(ENABLE_LIGHT_SENSOR) + if (buf == sensor_buf) { + sensor_buf_busy = FALSE; + } +#endif /* ENABLE_TEMP_SENSOR | ENABLE_LIGHT_SENSOR */ + } + +#ifdef ENABLE_TEMP_SENSOR + event void TempSensorC.readDone(error_t result, uint16_t data) { + if (sensor_buf_busy == FALSE) { + sensor_buf_busy = TRUE; + if (result == SUCCESS) { + snprintf(sensor_buf, sizeof(sensor_buf), "temp: %d\n", data); + } else { + snprintf(sensor_buf, sizeof(sensor_buf), "temp: -\n"); + } + call UDPClient.sendTo(&sensor_addr, sensor_port, + sensor_buf, strlen(sensor_buf)); + } else { + call UDPClient.sendTo(&sensor_addr, sensor_port, + "busy\n", 5); + } + } +#endif /* ENABLE_TEMP_SENSOR */ + +#ifdef ENABLE_LIGHT_SENSOR + event void LightSensorC.readDone(error_t result, uint16_t data) { + if (sensor_buf_busy == FALSE) { + sensor_buf_busy = TRUE; + if (result == SUCCESS) { + snprintf(sensor_buf, sizeof(sensor_buf), "light: %d\n", data); + } else { + snprintf(sensor_buf, sizeof(sensor_buf), "light: -\n"); + } + call UDPClient.sendTo(&sensor_addr, sensor_port, + sensor_buf, strlen(sensor_buf)); + } else { + call UDPClient.sendTo(&sensor_addr, sensor_port, + "busy\n", 5); + } + } +#endif /* ENABLE_LIGHT_SENSOR */ +} diff --git a/apps/6lowpancli/Makefile b/apps/6lowpancli/Makefile new file mode 100644 index 00000000..a4c380e4 --- /dev/null +++ b/apps/6lowpancli/Makefile @@ -0,0 +1,12 @@ +COMPONENT=CliAppC + +CFLAGS += -I$(TOSDIR)/lib/printf -I$(TOSDIR)/lib/net/6lowpan -D'TOSH_DATA_LENGTH=102' + +# TelosB +# CFLAGS + = "-D'ENABLE_TELOSB_LIGHT_SENSOR=1' -D'ENABLE_TELOSB_TEMP_SENSOR=1'" + +# MicaZ with the mts300 sensorboard +# CFLAGS += "-D'ENABLE_MICAZ_LIGHT_SENSOR=1' -D'ENABLE_MICAZ_TEMP_SENSOR=1' -D'ENABLE_SOUNDER=1'" + + +include $(MAKERULES) diff --git a/apps/6lowpancli/README b/apps/6lowpancli/README new file mode 100644 index 00000000..0ccacf1d --- /dev/null +++ b/apps/6lowpancli/README @@ -0,0 +1,42 @@ +6lowpan cli is a sample application using the 6lowpan stack. It +implements a cli listening on UDP port 1234 for commands and replying +with answers. + +Besides that, the mote answers to pings. + +The IPv6 addresses + * a global address with prefix 2001:0638:0709:1234::/64 + * a link-local address +are assigned using an interface identifier computed from the Active +Message address of the mote. This is almost like the stateless +autoconfiguration, but Duplicate Address Detection or Router +Solicitations are not implemented. + + +Note that you also need a BaseStation application and the serial_tun +daemon running. See tos/lib/net/6lowpan/REAME for more details. + + BUILDING +Debugging output with printf over USB can be enabled with + CFLAGS="-D'ENABLE_PRINTF_DEBUG=1' + +To minimize memory usage, i.e. disable everything (at the moment only +the UDP cli) to determine minimum RAM/ROM requirements, use + CFLAGS="-D'MINIMIZE_MEMORY=1' + + + TESTING +Assuming active message address (mote id) 20 (0x14): + +Small unfragmented ping + sudo ping6 -s 50 2001:638:709:1234::fffe:14 + +Large fragmented ping + sudo ping6 -s 1230 -i 3 2001:638:709:1234::fffe:14 + +Link-local all-nodes ping + sudo ping6 -s 20 ff02::01 + +UDP cli + nc6 -u 2001:638:709:1234::fffe:14 1234 + diff --git a/support/sdk/c/6lowpan/serial_tun/6lowpan.h b/support/sdk/c/6lowpan/serial_tun/6lowpan.h new file mode 100644 index 00000000..64bb5e8d --- /dev/null +++ b/support/sdk/c/6lowpan/serial_tun/6lowpan.h @@ -0,0 +1,378 @@ +/* + * Copyright (c) 2007 Matus Harvan + * All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * 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 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 + * OWNER 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. + */ +/* + * The structures are based on the ones from FreeBSD header files + * in /usr/include/netinet6/, which are distributed unred the following + * copyright: + * + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * 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 project 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 PROJECT 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 PROJECT 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. + * + * Copyright (c) 1982, 1986, 1990, 1993 + * The Regents of the University of California. 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. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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 __6LOWPAN_H__ +#define __6LOWPAN_H__ + +#include + +typedef uint8_t u_int8_t; +typedef uint16_t u_int16_t; +typedef uint32_t u_int32_t; + +#define LOWPAN_MTU 1280 +#define LOWPAN_OVERHEAD 17 +// 16 bytes opt. headers and 1 byte dispatch +#define LINK_DATA_MTU 100 +// 802.15.4 space left after the 802.15.4 header: 128 - xx = 102 bytes max + +/* Active Message */ +typedef struct __attribute__ ((__packed__))_AMPacket_t { + uint8_t pkt_type; + uint16_t dst; + uint16_t src; + uint8_t length; + uint8_t group; + uint8_t type; + uint8_t data[LINK_DATA_MTU]; +} am_packet_t; + +/* 802.15.4 address */ +enum { + HW_ADDR_SHORT, + HW_ADDR_LONG +}; + +typedef struct hw_addr { + uint8_t type; // HW_ADDR_SHORT | HW_ADDR_LONG + union { + uint8_t addr_short[2]; + uint8_t addr_long[8]; + }; +} hw_addr_t; + +/* IPv6 address */ +typedef struct __attribute__ ((__packed__)) _ip_6_addr_t { + uint8_t addr[16]; +} ip6_addr_t; + + +#define FRAG_BUFS 1 +#define FRAG_BUF_SIZE 1280 +#define FRAG_TIMEOUT 60 +// 60 seconds +#define FRAG_FREE -1 + +#define LOWPAN_APP_DATA_LEN 1517 +//#define LOWPAN_HEADER_LEN 49 +#define LOWPAN_HEADER_LEN 102 + +#define DISPATCH_UNCOMPRESSED_IPV6 0x41 +#define DISPATCH_COMPRESSED_IPV6 0x42 + +#define DISPATCH_FIRST_FRAG 0xC0 +#define DISPATCH_SUBSEQ_FRAG 0xE0 +#define DISPATCH_FRAG_MASK 0xF8 + +#define DISPATCH_BC0 0x50 + +#define DISPATCH_MESH 0x80 +#define DISPATCH_MESH_MASK 0xC0 +#define DISPATCH_MESH_O_FLAG 0x20 +#define DISPATCH_MESH_F_FLAG 0x10 +#define DISPATCH_MESH_HOPSLEFT_MASK 0x0F + +enum { + HC1_SRC_PREFIX_MASK = 0x80, + HC1_SRC_PREFIX_LINKLOCAL = 0x80, + HC1_SRC_PREFIX_INLINE = 0, + HC1_SRC_IFACEID_MASK = 0x40, + HC1_SRC_IFACEID_COMRP = 0x40, + HC1_SRC_IFACEID_INLINE = 0, + + HC1_DST_PREFIX_MASK = 0x20, + HC1_DST_PREFIX_LINKLOCAL = 0x20, + HC1_DST_PREFIX_INLINE = 0, + HC1_DST_IFACEID_MASK = 0x10, + HC1_DST_IFACEID_COMRP = 0x10, + HC1_DST_IFACEID_INLINE = 0, + + HC1_TCFL_MASK = 0x08, + HC1_TCFL_ZERO = 0x08, + HC1_TCFL_INLINE = 0, + + HC1_NEXTHDR_MASK = 0x06, + HC1_NEXTHDR_INLINE = 0, + HC1_NEXTHDR_UDP = 0x02, + HC1_NEXTHDR_ICMP = 0x04, + HC1_NEXTHDR_TCP = 0x06, + + HC1_HC2_MASK = 0x01, + HC1_HC2_PRESENT = 0x01, + HC1_HC2_NONE = 0, + + HC2_UDP_P_VALUE = 0x61616, + + HC2_UDP_SRC_PORT_MASK = 0x80, + HC2_UDP_SRC_PORT_COMPR = 0x80, + HC2_UDP_SRC_PORT_INLINE = 0, + + HC2_UDP_DST_PORT_MASK = 0x40, + HC2_UDP_DST_PORT_COMPR = 0x40, + HC2_UDP_DST_PORT_INLINE = 0, + + HC2_UDP_LEN_MASK = 0x20, + HC2_UDP_LEN_COMPR = 0x20, + HC2_UDP_LEN_INLINE = 0 +}; + +typedef struct _frag_info_t { + uint8_t offset; + uint8_t len; + struct _frag_info_t *next; +} frag_info_t; + +/* + * sending - application provides app_data and clears app_data_dealloc + * - a pointer to app_data is returned in sendDone to do deallocation + * receiving and fragment reassembly + * - IP_M provides app_data and sets app_data_dealloc + * - header_begin/end is set to point into app_data + * and the received packet is put into app_data + * - header_len should probably be set to a sane value (0) + * and header to NULL or leave as is? + * receiving without fragment reassembly + * - the complete 802.15.4 frame is put into header + * (802.15.4 header is left out) + */ +typedef struct _lowpan_pkt_t { + /* buffers */ + uint8_t buf[LOWPAN_MTU + LOWPAN_OVERHEAD]; + uint8_t *buf_begin; // start of data in the buffer + uint16_t len; // length of data in the buffer + /* fragmentation */ + uint8_t frag_state; + uint16_t dgram_tag; // network byte order + uint16_t dgram_size; // host byte order + time_t frag_timeout; // fragment reassembly times out at tv_sec */ + union { + uint8_t frag_offset; // sending - offset where next fragment starts + frag_info_t *frag_list; // sorted by offset in decreasing order + }; + /* IP addresses */ + ip6_addr_t ip_src_addr; /* needed for ND and usefull elsewhere */ + ip6_addr_t ip_dst_addr; /* both IP addresses filled in by ipv6*_input */ + /* 802.15.4 addresses */ + hw_addr_t hw_src_addr; + hw_addr_t hw_dst_addr; /* 802.15.4 MAC addresses + * needed for fragment identification + * possibly needed for 6lowpan IPv6 header + * decompression + * contains mesh header entries if available + */ + uint8_t nd_state; + struct _lowpan_pkt_t *next; +} lowpan_pkt_t; + +/* /\* fragment reassembly buffer *\/ */ +/* struct frag_buf { */ +/* hw_addr_t hw_src_addr; */ +/* hw_addr_t hw_dst_addr; */ +/* time_t frag_timeout; */ +/* uint8_t buf[FRAG_BUF_SIZE]; */ +/* lowpan_pkt_t pkt; */ +/* }; */ + +enum { + FRAG_NONE = 0, + FRAG_6LOWPAN = 1, + FRAG_IPV6 = 2, + + ND_DONE = 0, + ND_TODO = 1, + ND_SENT = 2, + + APP_DATA_DEALLOC_FALSE = 0, + APP_DATA_DEALLOC_TRUE = 1 +}; + +struct __attribute__ ((__packed__)) lowpan_mesh_hdr { + uint8_t dispatch; // dispatch, flags and hops left + // address length depends on flags in dispatch +}; + +struct __attribute__ ((__packed__)) lowpan_broadcast_hdr { + uint8_t dispatch; + uint8_t seq_no; // sequence number +}; + +struct __attribute__ ((__packed__)) lowpan_frag_hdr { + union __attribute__ ((__packed__)) { + uint8_t dispatch; + uint16_t dgram_size; + uint8_t dgram_size8[2]; + }; + uint16_t dgram_tag; +}; + +/* + * Definition for internet protocol version 6. + * RFC 2460 + */ + +struct __attribute__ ((__packed__)) ip6_hdr { + union { + uint8_t vtc; /* 4 bits version, top 4 bits class label*/ + uint32_t flow; /* 20 bits flow label at the end */ + }; + uint16_t plen; /* payload length */ + uint8_t nxt_hdr; /* next header */ + uint8_t hlim; /* hop limit */ + ip6_addr_t src_addr; /* source address */ + ip6_addr_t dst_addr; /* destination address */ +}; + +#define IPV6_VERSION 0x60 +#define IPV6_VERSION_MASK 0xf0 + +/* + * Extension Headers + */ + +struct ip6_ext { + uint8_t ip6e_nxt; + uint8_t ip6e_len; +}; + + +struct icmp6_hdr { + uint8_t type; /* type field */ + uint8_t code; /* code field */ + uint16_t cksum; /* checksum field */ + union { + uint32_t icmp6_un_data32[1]; /* type-specific field */ + uint16_t icmp6_un_data16[2]; /* type-specific field */ + uint8_t icmp6_un_data8[4]; /* type-specific field */ + } icmp6_dataun; +}; + +enum { + ICMP_TYPE_ECHO_DEST_UNREACH = 1, + ICMP_TYPE_ECHO_PKT_TOO_BIG = 129, + ICMP_TYPE_ECHO_TIME_EXCEEDED = 129, + ICMP_TYPE_ECHO_PARAM_PROBLEM = 129, + ICMP_TYPE_ECHO_REQUEST = 128, + ICMP_TYPE_ECHO_REPLY = 129 +}; + +/* + * UDP protocol header. + * Per RFC 768, September, 1981. + */ +struct __attribute__ ((__packed__)) udp_hdr { + uint16_t src_port; /* source port */ + uint16_t dst_port; /* destination port */ + uint16_t len; /* udp length */ + uint16_t chksum; /* udp checksum */ +}; + +enum { + //NEXT_HEADER_ICMP = 1, + NEXT_HEADER_TCP = 6, + NEXT_HEADER_UDP = 17, + NEXT_HEADER_ICMP6 = 58 +}; + + +// from uip-1.0/uip/uip-neighbor.c +#define NEIGHBOR_MAX_TIME 128 + +#ifndef NEIGHBOR_ENTRIES +#define NEIGHBOR_ENTRIES 8 +#endif + +struct neighbor_entry { + ip6_addr_t ip_addr; + struct hw_addr hw_addr; + uint8_t time; +}; +struct neighbor_entry neighbor_entries[NEIGHBOR_ENTRIES]; + +#endif /* __6LOWPAN_H__ */ diff --git a/support/sdk/c/6lowpan/serial_tun/Makefile b/support/sdk/c/6lowpan/serial_tun/Makefile new file mode 100644 index 00000000..37161562 --- /dev/null +++ b/support/sdk/c/6lowpan/serial_tun/Makefile @@ -0,0 +1,18 @@ +#CPPFLAGS = +#LDFLAGS = +FLAGS= +FLAGS+=-Wall +FLAGS+=-g +FLAGS+=-I${TOSROOT}/support/sdk/c + +all: serial_tun + +serial_tun: serial_tun.c tun_dev.c 6lowpan.h + gcc $(FLAGS) -o serial_tun serial_tun.c tun_dev.c ${TOSROOT}/support/sdk/c/libmote.a + +clean: + rm -f serial_tun TAGS + +TAGS: + rm -f TAGS + etags *.c *.h diff --git a/support/sdk/c/6lowpan/serial_tun/README b/support/sdk/c/6lowpan/serial_tun/README new file mode 100644 index 00000000..0f09e4c0 --- /dev/null +++ b/support/sdk/c/6lowpan/serial_tun/README @@ -0,0 +1,14 @@ +A daemon reading 6lowpan packets from the mote running the BaseStation +application via a USB interface, translating them to Ipv6 packets, +writing them to a tun interface and the other way round, i.e., reading +IPv6 packets from a tun interface, encapsulating them as 6lowpan +packets and sedning them to the mote. + +To build the daemon you also need to build the libmote.a library in +$TOSROOT/support/sdk/c/. + +Usage with a TelosB mote: + sudo ./serial_tun /dev/ttyUSB0 115200 + +The Active Message address 12 and the corresponding IPv6 addresses are +are hardcoded in the source code. diff --git a/support/sdk/c/6lowpan/serial_tun/serial_tun.c b/support/sdk/c/6lowpan/serial_tun/serial_tun.c new file mode 100644 index 00000000..798ff55c --- /dev/null +++ b/support/sdk/c/6lowpan/serial_tun/serial_tun.c @@ -0,0 +1,1249 @@ +/* + * Copyright (c) 2007 Matus Harvan + * All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * 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 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 + * OWNER 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "tun_dev.h" +#include "serialsource.h" +#include "serialpacket.h" +#include "6lowpan.h" + +#define min(a,b) ( (a>b) ? b : a ) +#define max(a,b) ( (a>b) ? a : b ) + +static char *msgs[] = { + "unknown_packet_type", + "ack_timeout" , + "sync" , + "too_long" , + "too_short" , + "bad_sync" , + "bad_crc" , + "closed" , + "no_memory" , + "unix_error" +}; + +/* global variables */ +lowpan_pkt_t *fragments = NULL; /* fragment reassembly of received frames */ +//lowpan_pkt_t *send_queue = NULL; +int g_send_pending = 0; + +hw_addr_t hw_addr; + +serial_source ser_src; +int tun_fd = 0; /* tunnel device */ +//int ser_fd = 0; /* serial device */ + +uint16_t g_dgram_tag = 0; /* datagram_tag for sending fragmented packets */ + +/* ------------------------------------------------------------------------- */ +/* function pre-declarations */ +int serial_output_am_payload(uint8_t *buf, int len, + const hw_addr_t *hw_src_addr, + const hw_addr_t *hw_dst_addr); + +int serial_input_layer3(uint8_t *buf, int len, + const hw_addr_t *hw_src_addr, + const hw_addr_t *hw_dst_addr); + +int serial_input_ipv6_uncompressed(uint8_t *buf, int len, + const hw_addr_t *hw_src_addr, + const hw_addr_t *hw_dst_addr); + +int serial_input_ipv6_compressed(uint8_t *buf, int len, + const hw_addr_t *hw_src_addr, + const hw_addr_t *hw_dst_addr); + +/* ------------------------------------------------------------------------- */ +/* utility functions */ +int get_ser_fd() +{ + return serial_source_fd(ser_src); +} + +void increment_g_dgram_tag() +{ + uint16_t tmp = ntohs(g_dgram_tag); + if (tmp == 0xFFFF) { + tmp = 0; + } else { + tmp++; + } + g_dgram_tag = htons(tmp); +} + +void stderr_msg(serial_source_msg problem) +{ + fprintf(stderr, "Note: %s\n", msgs[problem]); +} + +int +debug(const char *fmt, ...) +{ + int result; + va_list ap; + va_start(ap, fmt); + result = vfprintf(stderr, fmt, ap); + va_end(ap); + return result; +} + +/* from contiki-2.x/tools/tunslip.c */ +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); +} + +/* print char* in hex format */ +void dump_serial_packet(const unsigned char *packet, const int len) { + int i; + printf("len: %d\n", len); + if (!packet) + return; + for (i = 0; i < len; i++) { + printf("%02x ", packet[i]); + //printf("%02x(%c) ", packet[i], packet[i]); + //printf("%c", packet[i]); + } + putchar('\n'); +/* printf("---\n"); */ +/* for (i = 0; i < len; i++) { */ +/* printf("%c", packet[i]); */ +/* } */ +/* putchar('\n'); */ +/* printf("---\n"); */ +} + +/* ------------------------------------------------------------------------- */ +/* ip6_addr_t and hw_addr_t utility functions */ +int ipv6_addr_is_zero(const ip6_addr_t *addr) +{ + int i; + for (i=0;i<16;i++) { + if (addr->addr[i]) { + return 0; + } + } + return 1; +} + +int ipv6_addr_is_linklocal_unicast(const ip6_addr_t *addr) +{ + if ( addr->addr[0] == 0xFE + && addr->addr[1] == 0x80 + && addr->addr[2] == 0 + && addr->addr[3] == 0 + && addr->addr[4] == 0 + && addr->addr[5] == 0 + && addr->addr[6] == 0 + && addr->addr[7] == 0 + ) + return 1; + else + return 0; +} + +int cmp_ipv6_addr(const ip6_addr_t *addr1, const ip6_addr_t *addr2) +{ + return memcmp(addr1, addr2, sizeof(ip6_addr_t)); +} + +int cmp_hw_addr(const hw_addr_t *addr1, const hw_addr_t *addr2) +{ + // for short addresses compare only the first two bytes + if (addr1->type == HW_ADDR_SHORT && addr2->type == HW_ADDR_SHORT) { + return memcmp(addr1->addr_short, addr2->addr_short, + sizeof(addr1->addr_short)); + } else { + return memcmp(addr1, addr2, sizeof(hw_addr_t)); + } +} + +int hw_addr_is_broadcat(const hw_addr_t *hw_addr) +{ + if (hw_addr->type == HW_ADDR_SHORT + && hw_addr->addr_short[0] == 0xFF && hw_addr->addr_short[1] == 0xFF) + return 1; + // TODO: long address + else return 0; +} + +/* ------------------------------------------------------------------------- */ +/* more utility functions */ +void clear_pkt(lowpan_pkt_t *pkt) +{ + memset(pkt, 0, sizeof(*pkt)); + pkt->buf_begin = pkt->buf + LOWPAN_OVERHEAD; +} + +void free_frag_list(frag_info_t *p) +{ + frag_info_t *q; + while (p) { + q = p->next; + free(p); + p = q; + } +} + +void free_lowpan_pkt(lowpan_pkt_t *pkt) +{ + lowpan_pkt_t *p; + lowpan_pkt_t **q; + + if (!fragments) return; + for(q=&fragments; *q; q=&(*q)->next) { + if (*q == pkt) { + p = *q; + *q = p->next; + free_frag_list(p->frag_list); + free(p); + return; + } + } +} + +lowpan_pkt_t * find_fragment(hw_addr_t *hw_src_addr, hw_addr_t *hw_dst_addr, + uint16_t dgram_size, uint16_t dgram_tag) +{ + lowpan_pkt_t *p; + for(p=fragments; p; p=p->next) { + if ((p->dgram_tag == dgram_tag) + && (p->dgram_size == dgram_size) + && cmp_hw_addr(&p->hw_src_addr, hw_src_addr) == 0 + && cmp_hw_addr(&p->hw_dst_addr, hw_dst_addr) == 0 + ) { + return p; + } + } + return NULL; +} +/* ------------------------------------------------------------------------- */ +/* HC1 and HC2 compression and decompresstion functions */ + +/* the caller has to free() new_buf */ +int lowpan_decompress(uint8_t *buf, int len, + const hw_addr_t *hw_src_addr, + const hw_addr_t *hw_dst_addr, + uint8_t **new_buf, int *new_len) +{ + uint8_t hc1_enc; + uint8_t hc2_enc; + struct ip6_hdr *ip_hdr = NULL; + struct udp_hdr *udp_hdr = NULL; + + *new_buf = malloc(len + sizeof(*ip_hdr) + sizeof(*udp_hdr)); + if (!*new_buf) { + fprintf(stderr, "%s: out of memory\n", __func__); + *new_len = 0; + return 1; + } + hc1_enc = *buf; + buf += sizeof(hc1_enc); + len -= sizeof(hc1_enc); + + /* HC2 encoding follows HC1 encoding */ + if ((hc1_enc & HC1_HC2_MASK) == HC1_HC2_PRESENT) { + hc2_enc = *buf; + buf += sizeof(hc2_enc); + len -= sizeof(hc2_enc); + } + + /* IP header fields */ + ip_hdr = (struct ip6_hdr *) *new_buf; + memset(ip_hdr, 0, sizeof(struct ip6_hdr)); + + ip_hdr->vtc |= IPV6_VERSION; + + ip_hdr->hlim = *buf; + buf += sizeof(ip_hdr->hlim); + len -= sizeof(ip_hdr->hlim); + + /* source IP address */ + if ((hc1_enc & HC1_SRC_PREFIX_MASK) == HC1_SRC_PREFIX_INLINE) { + memcpy(&ip_hdr->src_addr, buf, sizeof(ip_hdr->src_addr)/2); + buf += sizeof(ip_hdr->src_addr)/2; + len -= sizeof(ip_hdr->src_addr)/2; + } else { + ip_hdr->src_addr.addr[0] = 0xFE; + ip_hdr->src_addr.addr[1] = 0x80; + } + + if ((hc1_enc & HC1_SRC_IFACEID_MASK) == HC1_SRC_IFACEID_INLINE) { + memcpy(((void*)&ip_hdr->src_addr) + sizeof(ip_hdr->src_addr)/2, + buf, sizeof(ip_hdr->src_addr)/2); + buf += sizeof(ip_hdr->src_addr)/2; + len -= sizeof(ip_hdr->src_addr)/2; + } + + /* destination IP address */ + if ((hc1_enc & HC1_DST_PREFIX_MASK) == HC1_DST_PREFIX_INLINE) { + memcpy(&ip_hdr->dst_addr, buf, sizeof(ip_hdr->dst_addr)/2); + buf += sizeof(ip_hdr->dst_addr)/2; + len -= sizeof(ip_hdr->dst_addr)/2; + } else { + ip_hdr->dst_addr.addr[0] = 0xFE; + ip_hdr->dst_addr.addr[1] = 0x80; + } + + if ((hc1_enc & HC1_DST_IFACEID_MASK) == HC1_DST_IFACEID_INLINE) { + memcpy(((void*)&ip_hdr->dst_addr) + sizeof(ip_hdr->dst_addr)/2, + buf, sizeof(ip_hdr->dst_addr)/2); + buf += sizeof(ip_hdr->dst_addr)/2; + len -= sizeof(ip_hdr->dst_addr)/2; + } + + /* Traffic Class and Flow Label */ + if ((hc1_enc & HC1_TCFL_MASK) == HC1_TCFL_INLINE) { + //TODO + } + + /* Next Header */ + switch (hc1_enc & HC1_NEXTHDR_MASK) { + case HC1_NEXTHDR_INLINE: + ip_hdr->nxt_hdr = *buf; + buf += sizeof(ip_hdr->nxt_hdr); + len -= sizeof(ip_hdr->nxt_hdr); + break; + case HC1_NEXTHDR_UDP: + ip_hdr->nxt_hdr = NEXT_HEADER_UDP; + break; + case HC1_NEXTHDR_ICMP: + ip_hdr->nxt_hdr = NEXT_HEADER_ICMP6; + break; + case HC1_NEXTHDR_TCP: + ip_hdr->nxt_hdr = NEXT_HEADER_TCP; + break; + default: + fprintf(stderr, "unknown next header HC1 encoding\n"); + break; + } + + /* HC_UDP compression */ + if ((hc1_enc & HC1_HC2_MASK) == HC1_HC2_PRESENT + && (hc1_enc & HC1_NEXTHDR_MASK) == HC1_NEXTHDR_UDP) { + + udp_hdr = (struct udp_hdr *) ((*new_buf) + sizeof(struct ip6_hdr)); + //udp_hdr = (struct udp_hdr *) (ip_hdr + 1); + memset(udp_hdr, 0, sizeof(struct udp_hdr)); + + /* UDP Source Port */ + if ((hc2_enc & HC2_UDP_SRC_PORT_MASK) == HC2_UDP_SRC_PORT_INLINE) { + memcpy(&udp_hdr->src_port, buf, sizeof(udp_hdr->src_port)); + buf += sizeof(udp_hdr->src_port); + len -= sizeof(udp_hdr->src_port); + } else { + //TODO + } + + /* UDP Destination Port */ + if ((hc2_enc & HC2_UDP_DST_PORT_MASK) == HC2_UDP_DST_PORT_INLINE) { + memcpy(&udp_hdr->dst_port, buf, sizeof(udp_hdr->dst_port)); + buf += sizeof(udp_hdr->dst_port); + len -= sizeof(udp_hdr->dst_port); + } else { + //TODO + } + + /* UDP Length */ + if ((hc2_enc & HC2_UDP_LEN_MASK) == HC2_UDP_LEN_INLINE) { + memcpy(&udp_hdr->len, buf, sizeof(udp_hdr->len)); + buf += sizeof(udp_hdr->len); + len -= sizeof(udp_hdr->len); + } else { + udp_hdr->len = len - sizeof(udp_hdr->chksum) + + sizeof(struct udp_hdr); + } + + /* Checksum */ + memcpy(&udp_hdr->chksum, buf, sizeof(udp_hdr->chksum)); + buf += sizeof(udp_hdr->chksum); + len -= sizeof(udp_hdr->chksum); + + /* IPv6 Payload Length */ + ip_hdr->plen = htons(len + sizeof(struct udp_hdr)); + + memcpy((*new_buf) + sizeof(struct ip6_hdr) + sizeof(struct udp_hdr), + buf, len); + *new_len = len + sizeof(struct ip6_hdr) + sizeof(struct udp_hdr); + } else { + /* IPv6 Payload Length */ + ip_hdr->plen = htons(len); + + memcpy((*new_buf) + sizeof(struct ip6_hdr), buf, len); + *new_len = len + sizeof(struct ip6_hdr); + } + + return 0; +} + +/* assuming there is space available in from of buf_begin */ +int lowpan_compress(uint8_t **buf_begin, int *len, + const hw_addr_t *hw_src_addr, + const hw_addr_t *hw_dst_addr) +{ + uint8_t *hc1_enc; + uint8_t *hc2_enc; + struct ip6_hdr *ip_hdr = NULL; + struct udp_hdr *udp_hdr = NULL; + + uint8_t new_buf[sizeof(struct ip6_hdr) + sizeof(struct udp_hdr) + 5]; + uint8_t *new_buf_p = new_buf; + int new_len = 0; + + debug("%s\n", __func__); + + ip_hdr = (struct ip6_hdr *) *buf_begin; + udp_hdr = (struct udp_hdr *) ((*buf_begin) + sizeof(struct ip6_hdr)); + + /* check if this is an IPv6 packet */ + if ((ip_hdr->vtc & IPV6_VERSION_MASK) != IPV6_VERSION) { + debug("IP version check failed - not an IPv6 packet\n"); + return 0; + } + + /* set 6lowpan dispatch value */ + *new_buf_p = DISPATCH_COMPRESSED_IPV6; + new_buf_p += sizeof(uint8_t); + new_len += sizeof(uint8_t); + + /* HC1 encoding field */ + hc1_enc = new_buf_p; + new_buf_p += sizeof(uint8_t); + new_len += sizeof(uint8_t); + *hc1_enc = 0; + + /* does HC2 follow after HC1? */ + if (ip_hdr->nxt_hdr == NEXT_HEADER_UDP) { + *hc1_enc |= HC1_HC2_PRESENT; + + /* HC2 encoding field */ + hc2_enc = new_buf_p; + new_buf_p += sizeof(uint8_t); + new_len += sizeof(uint8_t); + *hc2_enc = 0; + } else { + *hc1_enc |= HC1_HC2_NONE; + } + + /* Hop Limit */ + *new_buf_p = ip_hdr->hlim; + new_buf_p += sizeof(uint8_t); + new_len += sizeof(uint8_t); + + /* source address prefix */ + //TODO: fails checksum on the mote !!! + if (ipv6_addr_is_linklocal_unicast(&ip_hdr->src_addr)) { + *hc1_enc |= HC1_SRC_PREFIX_LINKLOCAL; + } else { + *hc1_enc |= HC1_SRC_PREFIX_INLINE; + + memcpy(new_buf_p, &(ip_hdr->src_addr), 8); + new_buf_p += 8; + new_len += 8; + } + + /* source address interface identifier */ + *hc1_enc |= HC1_SRC_IFACEID_INLINE; + + memcpy(new_buf_p, ((void*)&(ip_hdr->src_addr)) + 8, 8); + new_buf_p += 8; + new_len += 8; + + /* destination address prefix */ + if (ipv6_addr_is_linklocal_unicast(&ip_hdr->dst_addr)) { + *hc1_enc |= HC1_DST_PREFIX_LINKLOCAL; + } else { + *hc1_enc |= HC1_DST_PREFIX_INLINE; + + memcpy(new_buf_p, &(ip_hdr->dst_addr), 8); + new_buf_p += 8; + new_len += 8; + } + + /* destination address interface identifier */ + *hc1_enc |= HC1_DST_IFACEID_INLINE; + + memcpy(new_buf_p, ((void*)&(ip_hdr->dst_addr)) + 8, 8); + new_buf_p += 8; + new_len += 8; + + /* we're always sending packets with TC anf FL zero */ + *hc1_enc |= HC1_TCFL_ZERO; + + /* next header */ + switch (ip_hdr->nxt_hdr) { + case NEXT_HEADER_UDP: + *hc1_enc |= HC1_NEXTHDR_UDP; + break; + case NEXT_HEADER_ICMP6: + *hc1_enc |= HC1_NEXTHDR_ICMP; + break; + case NEXT_HEADER_TCP: + *hc1_enc |= HC1_NEXTHDR_TCP; + break; + default: + *hc1_enc |= HC1_NEXTHDR_INLINE; + + *new_buf_p = ip_hdr->nxt_hdr; + new_buf_p += sizeof(ip_hdr->nxt_hdr); + new_len += sizeof(ip_hdr->nxt_hdr); + break; + } + + /* HC_UDP encoding */ + if ((*hc1_enc & HC1_HC2_MASK) == HC1_HC2_PRESENT + && (*hc1_enc & HC1_NEXTHDR_MASK) == HC1_NEXTHDR_UDP) { + + /* Source Port */ + *hc2_enc |= HC2_UDP_SRC_PORT_INLINE; + memcpy(new_buf_p, &udp_hdr->src_port, sizeof(udp_hdr->src_port)); + new_buf_p += sizeof(udp_hdr->src_port); + new_len += sizeof(udp_hdr->src_port); + + /* Destination Port */ + *hc2_enc |= HC2_UDP_DST_PORT_INLINE; + memcpy(new_buf_p, &udp_hdr->dst_port, sizeof(udp_hdr->dst_port)); + new_buf_p += sizeof(udp_hdr->dst_port); + new_len += sizeof(udp_hdr->dst_port); + + /* Length */ + //*hc2_enc |= HC2_UDP_LEN_COMPR; + *hc2_enc |= HC2_UDP_LEN_INLINE; + memcpy(new_buf_p, &udp_hdr->len, sizeof(udp_hdr->len)); + new_buf_p += sizeof(udp_hdr->len); + new_len += sizeof(udp_hdr->len); + + /* Checksum */ + memcpy(new_buf_p, &udp_hdr->chksum, sizeof(udp_hdr->chksum)); + new_buf_p += sizeof(udp_hdr->chksum); + new_len += sizeof(udp_hdr->chksum); + + /* replace the IP and UDP headers with the compressed ones */ + *len += new_len; + *len -= sizeof(struct ip6_hdr); + *len -= sizeof(struct udp_hdr); + *buf_begin += sizeof(struct ip6_hdr); + *buf_begin += sizeof(struct udp_hdr); + *buf_begin -= new_len; + memcpy(*buf_begin, new_buf, new_len); + } else { + /* replace the IP header with the compressed one */ + *len += new_len; + *len -= sizeof(struct ip6_hdr); + *buf_begin += sizeof(struct ip6_hdr); + *buf_begin -= new_len; + memcpy(*buf_begin, new_buf, new_len); + } + + return 0; +} + +/* ------------------------------------------------------------------------- */ +/* handling of data arriving on the tun interface */ + +/* + * encapsulate buf as an Active Message payload + * fragments packets if needed + */ +int serial_output_am_payload(uint8_t *buf, int len, + const hw_addr_t *hw_src_addr, + const hw_addr_t *hw_dst_addr) +{ + am_packet_t AMpacket; + int result; + + //debug("%s: dumping buf (len: %d)...\n", __func__, len); + //dump_serial_packet(buf, len); + + if (len > LINK_DATA_MTU) { + fprintf(stderr, "%s: requested to send more than LINK_DATA_MTU"\ + "(%d bytes)\n", __func__, len); + // TODO: maybe we should send the fisr LINK_DATA_MTU bytes + // and only print a warning + return -1; + } + memset(&AMpacket, 0, sizeof(AMpacket)); + AMpacket.pkt_type = 0; + // TODO: make the dst addr handling more general + //AMpacket.dst = htons(0x14); + AMpacket.dst = htons(0xFFFF); + //AMpacket.src = htons(0x12); + // TODO: make the src addr handling more general + memcpy(&AMpacket.src, hw_addr.addr_short, 2); + AMpacket.group = 0; + AMpacket.type = 0x41; + AMpacket.length = min(len,LINK_DATA_MTU); + //AMpacket.data = buf; + memcpy(AMpacket.data, buf, AMpacket.length); + + len = AMpacket.length + 8; // data + header + + debug("sending to serial port...\n"); + dump_serial_packet((unsigned char *)&AMpacket, len); + + result = write_serial_packet(ser_src, &AMpacket, len); + /* + * Returns: 0 if packet successfully written, 1 if successfully + * written but not acknowledged, -1 otherwise + */ + debug("write_serial_packet returned %d\n", result); + + if (result < 0) { + perror ("sendto"); + return -1; + } + return len; +} + +/* + * read data from the tun device and send it to the serial port + * does also fragmentation + */ +int tun_input() +{ + uint8_t buf[LOWPAN_MTU + LOWPAN_OVERHEAD]; + uint8_t *buf_begin = buf + LOWPAN_OVERHEAD; + int len; + int result; + + struct lowpan_frag_hdr *frag_hdr; + uint8_t dgram_offset = 0; + uint16_t dgram_size; + hw_addr_t hw_dst_addr; + uint8_t frag_len; /* length of the fragment just being sent */ + + uint8_t *frame_begin; /* begin of the frame payload */ + uint8_t frame_len; /* length of the frame payload */ + + len = tun_read (tun_fd, (char*) buf_begin, LOWPAN_MTU); + if (len <= 0) { + perror ("read"); + return 0; + } + printf("data on tun interface\n"); + + /* set 802.15.4 destination address */ + hw_dst_addr.type = HW_ADDR_SHORT; + hw_dst_addr.addr_short[0] =0xFF; + hw_dst_addr.addr_short[1] =0xFF; + + /* HC compression */ + lowpan_compress(&buf_begin, &len, + &hw_addr, &hw_dst_addr); + + /* prepend dispatch */ +/* buf_begin--; */ +/* *buf_begin = DISPATCH_UNCOMPRESSED_IPV6; */ +/* len++; */ + + /* determine if fragmentation is needed */ + if (len > LINK_DATA_MTU) { + /* fragmentation needed */ + increment_g_dgram_tag(); + dgram_size = htons(len); + + /* first fragment */ + debug("first fragment... (len: %d, offset: %d)\n", + len, dgram_offset); + /* fragment heder */ + frame_begin = buf_begin - sizeof(struct lowpan_frag_hdr); + frag_hdr = (struct lowpan_frag_hdr *) frame_begin; + frag_hdr->dgram_size = dgram_size; + frag_hdr->dispatch |= DISPATCH_FIRST_FRAG; + frag_hdr->dgram_tag = g_dgram_tag; + /* align fragment length at an 8-byte multiple */ + frag_len = LINK_DATA_MTU - sizeof(struct lowpan_frag_hdr); + frag_len -= frag_len%8; + frame_len = frag_len + sizeof(struct lowpan_frag_hdr); + result = serial_output_am_payload(frame_begin, frame_len, + &hw_addr, &hw_dst_addr); + if (result < 0) { + perror("serial_output_am_payload() failed\n"); + return -1; + } + buf_begin += frag_len; + len -= frag_len; + dgram_offset += frag_len/8; /* in 8-byte multiples */ + + /* subseq fragment */ + while (len > 0) { + usleep(10000); /* workaround to prevent loosing fragments */ + debug("subsequent fragment... (len: %d, offset: %d)\n", + len, dgram_offset); + /* dgram_offset */ + frame_begin = buf_begin - sizeof(uint8_t); + *(frame_begin) = dgram_offset; + /* fragment heder */ + frame_begin -= sizeof(struct lowpan_frag_hdr); + frag_hdr = (struct lowpan_frag_hdr *) frame_begin; + frag_hdr->dgram_size = dgram_size; + frag_hdr->dispatch |= DISPATCH_SUBSEQ_FRAG; + frag_hdr->dgram_tag = g_dgram_tag; + if (len <= LINK_DATA_MTU - sizeof(struct lowpan_frag_hdr) + - sizeof(uint8_t)) { + /* + * last fragment does not have to be aligned + * at an 8-byte multiple + */ + frag_len = len; + } else { + /* align fragment length at an 8-byte multiple */ + frag_len = LINK_DATA_MTU - sizeof(struct lowpan_frag_hdr) + - sizeof(uint8_t); + frag_len -= frag_len%8; + } + frame_len = frag_len + sizeof(struct lowpan_frag_hdr) + + sizeof(uint8_t); + result = serial_output_am_payload(frame_begin, frame_len, + &hw_addr, &hw_dst_addr); + if (result < 0) { + perror("serial_output_am_payload() failed\n"); + //return -1; + } + buf_begin += frag_len; + len -= frag_len; + dgram_offset += frag_len/8; /* in 8-byte multiples */ + } + return 1; + + } else { + /* no need for fragmentation */ + serial_output_am_payload(buf_begin, len, + &hw_addr, &hw_dst_addr); + return 1; + } + +} + +/* ------------------------------------------------------------------------- */ +/* handling of data arriving on the serial port */ + +/* + * read data on serial port and send it to the tun interface + * does fragment reassembly + */ +int serial_input() +{ + int result = 0; + + void *ser_data; /* data read from serial port */ + int ser_len; /* length of data read from serial port */ + uint8_t *buf; + int len; + + am_packet_t *AMpacket; + struct hw_addr hw_src_addr; + struct hw_addr hw_dst_addr; + uint8_t *dispatch; + struct lowpan_broadcast_hdr *bc_hdr; + struct lowpan_frag_hdr *frag_hdr; + + uint16_t dgram_tag; + uint16_t dgram_size; + uint8_t dgram_offset; + struct timeval tv; + frag_info_t *p; + frag_info_t **q; + int last_frag; + lowpan_pkt_t *pkt; + + printf("serial_input()\n"); + /* read data from serial port */ + ser_data = read_serial_packet(ser_src, &ser_len); + + /* process the packet we have received */ + if (ser_len && ser_data) { + printf("dumping data on serial port...\n"); + dump_serial_packet(ser_data, ser_len); + AMpacket = ser_data; + + /* copy 802.15.4 addresses */ + // TODO: check if I got the byte ordering right + hw_src_addr.type = HW_ADDR_SHORT; + memcpy(hw_src_addr.addr_short, &AMpacket->src, + sizeof(hw_src_addr.addr_short)); + hw_dst_addr.type = HW_ADDR_SHORT; + memcpy(hw_dst_addr.addr_short, &AMpacket->dst, + sizeof(hw_dst_addr.addr_short)); + + /* --- 6lowpan optional headers --- */ + buf = AMpacket->data; + len = AMpacket->length; + if (len != ser_len - 8) { + fprintf(stderr, + "warning: mismatch between AMpacket->length(%d)"\ + " and ser_len - 8(%d)", AMpacket->length, ser_len - 8); + } + // TODO: check if length has a sensible value + dispatch = AMpacket->data; + /* Mesh Addressing header */ + if ( (*dispatch & DISPATCH_MESH_MASK) == DISPATCH_MESH) { + /* move over the dispatch field */ + buf += sizeof(*dispatch); + len -= sizeof(*dispatch); + + /* Hops Left */ + if ((*dispatch & 0x0F) == 0) { + goto discard_packet; + } + + /* Final Destination Address */ + if (*dispatch & DISPATCH_MESH_F_FLAG) { + hw_dst_addr.type = HW_ADDR_LONG; + memcpy(&hw_dst_addr.addr_long, buf, + sizeof(hw_dst_addr.addr_long)); + buf += sizeof(hw_dst_addr.addr_long); + len -= sizeof(hw_dst_addr.addr_long); + } else { + hw_dst_addr.type = HW_ADDR_SHORT; + memcpy(&hw_dst_addr.addr_short, buf, + sizeof(hw_dst_addr.addr_short)); + buf += sizeof(hw_dst_addr.addr_short); + len -= sizeof(hw_dst_addr.addr_short); + } + + /* check if we're the recipient */ + if (cmp_hw_addr(&hw_dst_addr, &hw_addr) != 0 + && !hw_addr_is_broadcat(&hw_dst_addr)) { + // TODO: if mesh forwarding enabled, then forward + goto discard_packet; + } + + /* Originator Address */ + if (*dispatch & DISPATCH_MESH_O_FLAG) { + hw_src_addr.type = HW_ADDR_LONG; + memcpy(&hw_src_addr.addr_long, buf, + sizeof(hw_src_addr.addr_long)); + buf += sizeof(hw_src_addr.addr_long); + len -= sizeof(hw_src_addr.addr_long); + } else { + hw_src_addr.type = HW_ADDR_SHORT; + memcpy(&hw_src_addr.addr_short, buf, + sizeof(hw_src_addr.addr_short)); + buf += sizeof(hw_src_addr.addr_short); + len -= sizeof(hw_src_addr.addr_short); + } + + dispatch = buf; + } + /* Broadcast header */ + if (*dispatch == DISPATCH_BC0) { + bc_hdr = (struct lowpan_broadcast_hdr *) buf; + // do something usefull with bc_hdr->seq_no... + + buf += (sizeof(struct lowpan_broadcast_hdr)); + len -= (sizeof(struct lowpan_broadcast_hdr)); + dispatch = buf; + } + + /* fragment header */ + if ((*dispatch & DISPATCH_FRAG_MASK) + == DISPATCH_FIRST_FRAG + || (*dispatch & DISPATCH_FRAG_MASK) + == DISPATCH_SUBSEQ_FRAG + ) { + frag_hdr = (struct lowpan_frag_hdr *) buf; + buf += sizeof(struct lowpan_frag_hdr); + len -= sizeof(struct lowpan_frag_hdr); + + /* collect information about the fragment */ + dgram_tag = frag_hdr->dgram_tag; + dgram_size = frag_hdr->dgram_size & htons(0x07FF); + //dgram_size = frag_hdr->dgram_size8[1]; + //dgram_size += ((uint16_t) (frag_hdr->dgram_size8[0] & 0x07)) << 8; + if ((*dispatch & DISPATCH_FRAG_MASK) == DISPATCH_SUBSEQ_FRAG) { + dgram_offset = *buf; + buf += 1; + len -= 1; + } else { + dgram_offset = 0; + } + + debug("fragment reassembly: tag: 0x%04X, size: %d, offset: %d"\ + "(*8=%d)\n", + ntohs(dgram_tag), ntohs(dgram_size), + dgram_offset, dgram_offset*8); + + pkt = find_fragment(&hw_src_addr, &hw_dst_addr, + dgram_size, dgram_tag); + if (pkt) { + debug("found an existing reassembly buffer\n"); + /* fragment reassembly buffer found */ + /* check for overlap */ + for (p = pkt->frag_list; p; p=p->next) { + if (dgram_offset == p->offset && len == p->len) { + /* duplicate - discard it */ + result = 0; + goto discard_packet; + } else if ((dgram_offset == p->offset && len < p->len) || + (dgram_offset > p->offset + && dgram_offset < p->offset + p->len/8) + ) { + goto frag_overlap; + } + } + /* no overlap found */ + goto frag_reassemble; + } else { + debug("starting a new reassembly buffer\n"); + /* fragment reassembly buffer not found - set up a new one */ + pkt = malloc(sizeof(lowpan_pkt_t)); + if (!pkt) { + // no free slot for reassembling fragments + fprintf(stderr, "out of memory - dropping a fragment\n"); + result = -1; + goto discard_packet; + } + pkt->next = fragments; + fragments = pkt; + clear_pkt(pkt); + memcpy(&pkt->hw_src_addr, &hw_src_addr, sizeof(hw_src_addr)); + memcpy(&pkt->hw_dst_addr, &hw_dst_addr, sizeof(hw_dst_addr)); + pkt->dgram_tag = dgram_tag; + pkt->dgram_size = dgram_size; + gettimeofday(&tv, NULL); + pkt->frag_timeout = tv.tv_sec + FRAG_TIMEOUT; + goto frag_reassemble; + } + + frag_overlap: + /* overlap - discard previous frags + * and restart freagment reassembly + */ + free_frag_list(pkt->frag_list); + pkt->frag_list = NULL; + /* not sure if we want to clear the whole buf */ + //memset(&pkt->buf, 0, sizeof(pkt->buf)); + gettimeofday(&tv, NULL); + pkt->frag_timeout = tv.tv_sec + FRAG_TIMEOUT; + goto frag_reassemble; + + frag_reassemble: + /* copy buf data */ + debug("dgram_offset: %d\n", dgram_offset); + memcpy(pkt->buf_begin + dgram_offset*8, buf, len); + //TODO: make sure a large len does not cause a buffer overflow + + /* update frag_info */ + p = malloc(sizeof(frag_info_t)); + if (!p) { + fprintf(stderr, "out of memory - fragment "\ + "reassembly failing\n"); + } else { + p->offset = dgram_offset; + p->len = len; + + /* insert frag_info into the orderer list */ + if (pkt->frag_list) { + for(q = &(pkt->frag_list); (*q)->next; q=&((*q)->next)) { + if (p->offset > (*q)->offset) { + break; + } + } + if ((*q)) { + debug("inserting frag_info before offset %d\n", + (*q)->offset); + } else { + debug("inserting frag_info at the beginning/end\n"); + } + + p->next = *q; + *q = p; + } else { + debug("inserting frag_info to the beginning " + "of the list\n"); + p->next = pkt->frag_list; + pkt->frag_list = p; + } + } + + /* check if this is not the last fragment */ + if (!dgram_offset) { + /* the first fragment cannot be the last one */ + last_frag = 0; + } else { + debug("checking last_frag...\n"); + last_frag=1; + dgram_offset = ntohs(dgram_size)/8; + for(p=pkt->frag_list; p && dgram_offset; p=p->next) { + debug("dgram_offset: %d, p->offset: %d, p->len: %d\n", + dgram_offset, p->offset, p->len); + if (p->offset + p->len/8 != dgram_offset) { + debug("offset mismatch - not the last fragment\n"); + last_frag = 0; + break; + } + dgram_offset = p->offset; + } + } + + if (last_frag) { + debug("last fragment, reassembly done\n"); + pkt->len = ntohs(dgram_size); + + debug("dumping reassembled datagram...\n"); + dump_serial_packet(pkt->buf_begin, pkt->len); + + /* pass up the complete packet */ + result = serial_input_layer3(pkt->buf_begin, pkt->len, + &hw_src_addr, &hw_dst_addr); + /* deallocate pkt and all fragment info */ + free_lowpan_pkt(pkt); + } else { + result = 0; + } + } else { /* no fragment header present */ + result = serial_input_layer3(buf, len, + &hw_src_addr, &hw_dst_addr); + } + + } else { + //printf("no data on serial port, but FD trigerred select\n"); + } + discard_packet: + if (ser_data) { + free(ser_data); + } + if (ser_data && ser_len > 0) { + return 1; + } else { + return 0; + } + //return result; +} + +int serial_input_layer3(uint8_t *buf, int len, + const hw_addr_t *hw_src_addr, + const hw_addr_t *hw_dst_addr) +{ + uint8_t *dispatch = buf; + //debug("%s()\n", __func__); + //dump_serial_packet(buf, len); + + if (len <= 0) return 1; + + /* uncompressed IPv6 */ + if (*dispatch == 0x41) { + return serial_input_ipv6_uncompressed(buf+1, len-1, + hw_src_addr, hw_dst_addr); + + } + /* LOWPAN_HC1 compressed IPv6 */ + else if (*dispatch == 0x42) { + return serial_input_ipv6_compressed(buf+1, len-1, + hw_src_addr, hw_dst_addr); + } + /* unknown dispatch value if we got here */ + else { + debug("unknown dispatch value: %X\n", *dispatch); + return tun_write(tun_fd, (char*) buf+1, len-1); + } +} + +int serial_input_ipv6_uncompressed(uint8_t *buf, int len, + const hw_addr_t *hw_src_addr, + const hw_addr_t *hw_dst_addr) +{ + debug("%s()\n", __func__); + //dump_serial_packet(buf, len); + // TODO: update neighbor table + return tun_write(tun_fd, (char*) buf, len); +} + +int serial_input_ipv6_compressed(uint8_t *buf, int len, + const hw_addr_t *hw_src_addr, + const hw_addr_t *hw_dst_addr) +{ + int ret=0; + int new_len; + uint8_t *new_buf; + + debug("%s()\n", __func__); + if (0 == lowpan_decompress(buf, len, + hw_src_addr, hw_dst_addr, + &new_buf, &new_len) + ) { + // TODO: update neighbor table + buf = new_buf; + len = new_len; + ret = tun_write(tun_fd, (char*) buf, len); + + if (new_buf && new_len) { + free(new_buf); + } + } + + return ret; +} + +/* ------------------------------------------------------------------------- */ + +void timer_fired() +{ + struct timeval tv; + lowpan_pkt_t *p; + lowpan_pkt_t **q; + + /* time out old fragments */ + (void) gettimeofday(&tv, NULL); + for(q = &fragments; *q; ) { + if ((*q)->frag_timeout > tv.tv_sec) { + p = (*q)->next; + free(*q); + *q = p; + } else { + q = &((*q)->next); + } + } + // TODO: ND retransmission + // TODO: neighbor table timeouts +} + +/* shifts data between the serial port and the tun interface */ +int serial_tunnel(serial_source ser_src, int tun_fd) { + //int result; + fd_set fs; + + while (1) { + FD_ZERO (&fs); + FD_SET (tun_fd, &fs); + FD_SET (serial_source_fd(ser_src), &fs); + + select (tun_fd>serial_source_fd(ser_src)? + tun_fd+1 : serial_source_fd(ser_src)+1, + &fs, NULL, NULL, NULL); + + debug("--- select() fired ---\n"); + + /* data available on tunnel device */ + if (FD_ISSET (tun_fd, &fs)) { + //result = tun_input(); + while( tun_input() ); + } + + /* data available on serial port */ + if (FD_ISSET (serial_source_fd(ser_src), &fs)) { + /* more packets may be queued so process them all */ + while (serial_input()); + /* using serial_source_empty() seems to make select() + * fire way too often, so the above solution is better */ + //while(! serial_source_empty(ser_src)) { + //result = serial_input(); + //} + } + /* end of data available */ + } + /* end of while(1) */ + + return 0; +} + +int main(int argc, char **argv) { + char dev[16]; + + if (argc != 3) + { + fprintf(stderr, "Usage: %s \n", argv[0]); + exit(2); + } + + hw_addr.type = HW_ADDR_SHORT; + hw_addr.addr_short[0] = 0x00; // network byte order + hw_addr.addr_short[1] = 0x12; + + /* create the tunnel device */ + dev[0] = 0; + tun_fd = tun_open(dev); + if (tun_fd < 1) { + printf("Could not create tunnel device. Fatal.\n"); + return 1; + } + else { + printf("Created tunnel device: %s\n", dev); + } + + /* open the serial port */ + ser_src = open_serial_source(argv[1], platform_baud_rate(argv[2]), + 1, stderr_msg); + /* 0 - blocking reads + * 1 - non-blocking reads + */ + + if (!ser_src) { + debug("Couldn't open serial port at %s:%s\n", + argv[1], argv[2]); + exit(1); + } + + /* set up the tun interface */ + printf("\n"); + ssystem("ifconfig tun0 up"); + ssystem("ifconfig tun0 mtu 1280"); + ssystem("ifconfig tun0 inet6 add 2001:0638:0709:1234::fffe:12/64"); + ssystem("ifconfig tun0 inet6 add fe80::fffe:12/64"); + printf("\n"); + + printf("try:\n\tsudo ping6 -s 0 2001:0638:0709:1234::fffe:14\n" + "\tnc6 -u 2001:0638:0709:1234::fffe:14 1234\n\n"); + + /* start tunneling */ + serial_tunnel(ser_src, tun_fd); + + /* clean up */ + close_serial_source(ser_src); + //close(ser_fd); + tun_close(tun_fd, dev); + return 0; +} diff --git a/support/sdk/c/6lowpan/serial_tun/tun_dev.c b/support/sdk/c/6lowpan/serial_tun/tun_dev.c new file mode 100644 index 00000000..e5d92bbb --- /dev/null +++ b/support/sdk/c/6lowpan/serial_tun/tun_dev.c @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2007 Matus Harvan + * All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * 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 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 + * OWNER 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. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "tun_dev.h" + + +int tun_open(char *dev) +{ + struct ifreq ifr; + int fd; + + if ((fd = open("/dev/net/tun", O_RDWR | O_NONBLOCK)) < 0) + return -1; + + memset(&ifr, 0, sizeof(ifr)); + /* By default packets are tagged as IPv4. To tag them as IPv6, + * thy need to be prefixed by struct tun_pi. + */ + //ifr.ifr_flags = IFF_TUN | IFF_NO_PI; + ifr.ifr_flags = IFF_TUN; + if (*dev) + strncpy(ifr.ifr_name, dev, IFNAMSIZ); + + if (ioctl(fd, TUNSETIFF, (void *) &ifr) < 0) + goto failed; + + strcpy(dev, ifr.ifr_name); + return fd; + +failed: + close(fd); + return -1; +} + +int tun_close(int fd, char *dev) +{ + return close(fd); +} + +/* Read/write frames from TUN device */ +/* +int tun_write(int fd, char *buf, int len) +{ + return write(fd, buf, len); +} + +int tun_read(int fd, char *buf, int len) +{ + return read(fd, buf, len); +} +*/ +int tun_write(int fd, char *buf, int len) +{ + int out; + struct tun_pi pi = {0, htons(ETH_P_IPV6)}; + char *nbuf = malloc(len+sizeof(struct tun_pi)); + if (!nbuf) { + fprintf(stderr, "tun_write: out of memory!"); + return -1; + } + memcpy(nbuf, &pi, sizeof(struct tun_pi)); + memcpy(nbuf+sizeof(struct tun_pi), buf, len); + out = write(fd, nbuf, len+sizeof(struct tun_pi)); + free(nbuf); + return out; +} + +int tun_read(int fd, char *buf, int len) +{ + int out; + char *nbuf = malloc(len+sizeof(struct tun_pi)); + if (!nbuf) { + fprintf(stderr, "tun_read: out of memory!"); + return -1; + } + out=read(fd, nbuf, len+sizeof(struct tun_pi)); + if (out > 0 && out >= sizeof(struct tun_pi)) { + out-=sizeof(struct tun_pi); + memcpy(buf, nbuf+sizeof(struct tun_pi), out); + free(nbuf); + return out; + } else { + free(nbuf); + return -1; + } +} diff --git a/support/sdk/c/6lowpan/serial_tun/tun_dev.h b/support/sdk/c/6lowpan/serial_tun/tun_dev.h new file mode 100644 index 00000000..0de31dec --- /dev/null +++ b/support/sdk/c/6lowpan/serial_tun/tun_dev.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2007 Matus Harvan + * All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * 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 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 + * OWNER 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 _TUN_DEV_H +#define _TUN_DEV_H + +int tun_open(char *dev); +int tun_close(int fd, char *dev); +int tun_write(int fd, char *buf, int len); +int tun_read(int fd, char *buf, int len); + +#endif diff --git a/tos/lib/net/6lowpan/IP.h b/tos/lib/net/6lowpan/IP.h new file mode 100644 index 00000000..0adbf497 --- /dev/null +++ b/tos/lib/net/6lowpan/IP.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2007 Matus Harvan + * All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * 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 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 + * OWNER 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 __IP_H__ +#define __IP_H__ + +typedef struct { + uint8_t addr[16]; +} ip6_addr_t; + +#endif // __IP_H__ diff --git a/tos/lib/net/6lowpan/IP.nc b/tos/lib/net/6lowpan/IP.nc new file mode 100644 index 00000000..65427031 --- /dev/null +++ b/tos/lib/net/6lowpan/IP.nc @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2007 Matus Harvan + * All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * 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 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 + * OWNER 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 interface design was inspired Andrew Christian's port + * of Adam Dunkel's uIP to TinyOS 1.x. The original interface file + * is distributed under the following copyrights: + * + * Copyright (c) 2005 Hewlett-Packard Company + * All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of the Hewlett-Packard Company 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 + * OWNER 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. + * + +/* + * IP address interface. + * + */ + +#include "IP.h" + +interface IP { + command void getAddress(ip6_addr_t *addr); + command void setAddress(const ip6_addr_t *addr); + command void setAddressAutoconf(const ip6_addr_t *addr); +} diff --git a/tos/lib/net/6lowpan/IPC.nc b/tos/lib/net/6lowpan/IPC.nc new file mode 100644 index 00000000..7f2be6ca --- /dev/null +++ b/tos/lib/net/6lowpan/IPC.nc @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2007 Matus Harvan + * All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * 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 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 + * OWNER 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. + */ + +#include "IP.h" +#include "IP_internal.h" +#include "message.h" + +#ifdef ENABLE_PRINTF_DEBUG +#include "printf.h" +#endif /* ENABLE_PRINTF_DEBUG */ + +configuration IPC { + provides { + interface SplitControl as IPControl; + interface IP; + interface UDPClient[uint8_t i]; + } +} + +implementation { + components IPP; + components ActiveMessageC as AM; + //TODO: need at least 2 pkts for ND + components new PoolC(lowpan_pkt_t, SEND_PKTS) as SendPktPool; + components new PoolC(app_data_t, FRAG_BUFS) as AppDataPool; + components new PoolC(frag_info_t, FRAG_BUFS*FRAGS_PER_DATAGRAM) + as FragInfoPool; + components new TimerMilliC() as Timer; + components LedsC; + + IPControl = IPP; + UDPClient = IPP.UDPClient; + IP = IPP.IP; + + IPP.MessageControl -> AM; + IPP.Receive -> AM.Receive[AM_IP_MSG]; + IPP.AMSend -> AM.AMSend[AM_IP_MSG]; + IPP.Packet -> AM; + IPP.AMPacket -> AM; + + IPP.SendPktPool -> SendPktPool; + IPP.AppDataPool -> AppDataPool; + IPP.FragInfoPool -> FragInfoPool; + + IPP.Leds -> LedsC; + IPP.Timer -> Timer; + +#ifdef ENABLE_PRINTF_DEBUG + components PrintfC; + IPP.PrintfControl -> PrintfC; + IPP.PrintfFlush -> PrintfC; +#endif /* ENABLE_PRINTF_DEBUG */ +} + diff --git a/tos/lib/net/6lowpan/IPP.nc b/tos/lib/net/6lowpan/IPP.nc new file mode 100644 index 00000000..61a8fc70 --- /dev/null +++ b/tos/lib/net/6lowpan/IPP.nc @@ -0,0 +1,2192 @@ +/* + * Copyright (c) 2007 Matus Harvan + * All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * 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 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 + * OWNER 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. + */ + +/* + * Parts of the 6lowpan implementation design were inspired Andrew + * Christian's port of Adam Dunkel's uIP to TinyOS 1.x. This work is + * distributed under the following copyrights: + * + * Copyright (c) 2001-2003, Adam Dunkels. + * 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. + * + * Copyright (c) 2005, Hewlett-Packard Company + * All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of the Hewlett-Packard Company 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 + * OWNER 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. + */ + +/* + * The actual implementaion of the 6lowpan/IPv6 stack lives in this file. + */ + +#include "IP.h" +#include "IP_internal.h" +#include "message.h" +#ifdef ENABLE_PRINTF_DEBUG +#include "printf.h" +#endif /* ENABLE_PRINTF_DEBUG */ + +module IPP { + provides { + interface SplitControl as IPControl; + interface IP; + interface UDPClient[uint8_t i]; + } + uses { + interface Timer as Timer; + interface Pool as SendPktPool; + interface Pool as AppDataPool; + interface Pool as FragInfoPool; + + interface SplitControl as MessageControl; + interface Receive; + interface AMSend; + interface Packet; + interface AMPacket; + +#ifdef ENABLE_PRINTF_DEBUG + interface PrintfFlush; + interface SplitControl as PrintfControl; +#endif /* ENABLE_PRINTF_DEBUG */ + + interface Leds; + } +} + +implementation { + /* global variables */ + enum { + COUNT_UDP_CLIENT = uniqueCount("UDPClient"), + COUNT_UDP_CONNS = COUNT_UDP_CLIENT + }; + + ip6_addr_t global_addr; + ip6_addr_t linklocal_addr; + + uint16_t g_dgram_tag = 0; + uint16_t uip_len, uip_slen; + uint8_t uip_flags; /* The uip_flags variable is used for + communication between the TCP/IP stack + and the application program. */ + + message_t g_msg; // AM for sending + lowpan_pkt_t rx_pkt; // packet used for receiving + //struct lowpan_pkt send_pkt[SEND_PKTS]; // packets to be sent + lowpan_pkt_t *send_queue; // packets to be sent - queue + + frag_buf_t frag_bufs[FRAG_BUFS]; // fragment reassembly buffers + + struct udp_conn udp_conns[COUNT_UDP_CONNS]; + static uint16_t lastport; /* Keeps track of the last port used for + a new connection. */ + static int g_send_pending = 0; + + // Pre-declare + // clear all fields, set app_data = NULL + void lowpan_pkt_clear(lowpan_pkt_t *pkt); + int ip6_addr_cmp(const ip6_addr_t *a, const ip6_addr_t *b); + + static void dump_serial_packet(const unsigned char *packet, const int len); +/*---------------------------------------------------------------------------*/ +/* from http://www.nabble.com/memcpy-assumes-16-bit-alignment--t712619.html */ +void * +my_memcpy(void *dst0, const void *src0, size_t len) +{ + char *dst = (char *)dst0; + const char *src = (const char *)src0; + void *ret = dst0; + + for (; len > 0; len--) + *dst++ = *src++; + + return ret; +} + +/* + * Use this function for copying/setting/memset() 16-bit values + * on the MSP430 !!! + * + * The mspgcc compiler geenrates broken code when doing memset with 16 + * bit values, i.e. things go wrong if they are not aligned at 16-bit + * boundaries. See + * http://www.nabble.com/msp430-gcc-generating-unaligned-access.-t2261862.html + * and page 25 in http://www.eecs.harvard.edu/~konrad/projects/motetrack/mspgcc-manual-20031127.pdf for details. + */ +/* use when DST may be UNALIGNED */ +inline void set_16t(void *dst, uint16_t val) +{ + *((uint8_t*)dst) = *((uint8_t*)&val); + *(((uint8_t*)dst)+1) = *(((uint8_t*)&val)+1); + //memcpy((uint8_t*)dst, (uint8_t*)&val, sizeof(uint8_t)); + //memcpy(((uint8_t*)dst)+1, ((uint8_t*)&val)+1, sizeof(uint8_t)); +} + +/* use when SRC may be UNALIGNED */ +inline uint16_t get_16t(void *val) +{ + uint16_t tmp; + *((uint8_t*)&tmp) = *((uint8_t*)val); + *(((uint8_t*)&tmp)+1) = *(((uint8_t*)val)+1); + //memcpy((uint8_t*)&tmp, (uint8_t*)val, sizeof(uint8_t)); + //memcpy(((uint8_t*)&tmp)+1, ((uint8_t*)val)+1, sizeof(uint8_t)); + return tmp; +} + + inline uint16_t htons( uint16_t val ) + { + // The MSB is little-endian; network order is big + return ((val & 0xff) << 8) | ((val & 0xff00) >> 8); + } + + inline uint16_t ntohs( uint16_t val ) + { + // The MSB is little-endian; network order is big + return ((val & 0xff) << 8) | ((val & 0xff00) >> 8); + } + + inline void htonl( uint32_t val, uint8_t *dest ) + { + dest[0] = (val & 0xff000000) >> 24; + dest[1] = (val & 0x00ff0000) >> 16; + dest[2] = (val & 0x0000ff00) >> 8; + dest[3] = (val & 0x000000ff); + } + + inline uint32_t ntohl( uint8_t *src ) + { + return (((uint32_t) src[0]) << 24) | (((uint32_t) src[1]) << 16) | + (((uint32_t) src[2]) << 8) | (((uint32_t) src[3])); + } + + /* + inline void uip_pack_ipaddr( ip6_addr_t *addr, uint8_t *new_addr) + { + memcpy(addr, new_addr, sizeof(addr)); + } + + // Unpack the IP address into an array of octet + inline void uip_unpack_ipaddr( uint8_t *in, uint8_t *out ) + { + memcpy(out, in, sizeof(ip6_addr_t)); + } + */ +/*---------------------------------------------------------------------------*/ + + /* This should be optimized for aligned and unaligned case */ + static uint16_t ip_chksum(const uint8_t *buf, uint16_t len, + uint16_t acc) + { + uint16_t v; + + for (; len > 1; len -= 2) { + v = (((uint16_t) buf[1]) << 8) | ((uint16_t) buf[0]); + + if ( (acc += v) < v ) acc++; + buf += 2; + } + + // add an odd byte (note we pad with 0) + if (len) { + v = (uint16_t) buf[0]; + if ( (acc += v) < v ) acc++; + } + + return acc; + } + + /* + * IPv6 checksum of the pseudo-header (RFC 2460, Sec 8.1) + * src_addr and dst_addr are in nerwork byte order + * len is in host byte order (will internally be converted) + */ + static uint16_t ipv6_chksum(const ip6_addr_t* src_addr, + const ip6_addr_t* dst_addr, + const uint8_t next_header, + const uint16_t upper_layer_len, + uint16_t acc) + { + uint16_t tmp; + + /* source address */ + acc = ip_chksum((const uint8_t *) src_addr, sizeof(*src_addr), acc); + + /* destination address */ + acc = ip_chksum((const uint8_t *) dst_addr, sizeof(*dst_addr), acc); + + /* upper-layer packet length */ + tmp = htons(upper_layer_len); + acc = ip_chksum((const uint8_t *) &tmp, sizeof(tmp), acc); + + /* next header */ + tmp = htons(next_header); + acc = ip_chksum((const uint8_t *) &tmp, sizeof(tmp), acc); + + return acc; + } + + /* same as above, but including the uppel-layer buffer */ + static uint16_t ipv6_chksum_data(const ip6_addr_t* src_addr, + const ip6_addr_t* dst_addr, + const uint8_t next_header, + const uint8_t *data, uint16_t data_len, + uint16_t acc) + { + /* upper-layer payload */ + acc = ip_chksum(data, data_len, acc); + + return ipv6_chksum(src_addr, dst_addr, next_header, data_len, acc); + } +/*---------------------------------------------------------------------------*/ + bool ipv6_addr_is_zero(const ip6_addr_t *addr) + { + int i; + for (i=0;i<16;i++) { + if (addr->addr[i]) { + return FALSE; + } + } + return TRUE; + } + + bool ipv6_addr_is_linklocal_unicast(const ip6_addr_t *addr) + { + if ( addr->addr[0] == 0xFE + && addr->addr[1] == 0x80 + && addr->addr[2] == 0 + && addr->addr[3] == 0 + && addr->addr[4] == 0 + && addr->addr[5] == 0 + && addr->addr[6] == 0 + && addr->addr[7] == 0 + ) + return TRUE; + else + return FALSE; + } + +//TODO: prepend pan_id once we have a proper 802.15.4 stack +void ipv6_iface_id_from_am_addr(am_addr_t am_addr, uint8_t *host_part) +{ + memset(host_part, 0, 6); + host_part[4] = 0xFF; + host_part[5] = 0xFE; + host_part += 6; + set_16t(host_part, htons(am_addr)); +} + +void ipv6_iface_id_from_hw_addr(hw_addr_t *hw_addr, uint8_t *host_part) +{ + if (hw_addr->type == HW_ADDR_SHORT) { + memset(host_part, 0, 6); + host_part[4] = 0xFF; + host_part[5] = 0xFE; + host_part[7] = hw_addr->addr_short[0]; + host_part[8] = hw_addr->addr_short[1]; + //ipv6_iface_id_from_am_addr(hw_addr->addr_short, host_part); + } else { + //TODO + } +} + +bool ipv6_addr_is_linklocal_multicast(const ip6_addr_t *addr) +{ + if (addr->addr[0] == 0xFF + && addr->addr[1] == 0x02) + return TRUE; + else + return FALSE; +} + +bool ipv6_addr_is_linklocal(const ip6_addr_t *addr) +{ + return (ipv6_addr_is_linklocal_unicast(addr) + || ipv6_addr_is_linklocal_multicast(addr)); +} + +bool ipv6_addr_is_linklocal_allnodes(const ip6_addr_t *addr) +{ + //TODO: interface-local addr FF01::1 + if ( addr->addr[0] == 0xFF + && addr->addr[1] == 0x02 + && addr->addr[2] == 0 + && addr->addr[3] == 0 + && addr->addr[4] == 0 + && addr->addr[5] == 0 + && addr->addr[6] == 0 + && addr->addr[7] == 0 + && addr->addr[8] == 0 + && addr->addr[9] == 0 + && addr->addr[10] == 0 + && addr->addr[11] == 0 + && addr->addr[12] == 0 + && addr->addr[13] == 0 + && addr->addr[14] == 0 + && addr->addr[15] == 0x01 + ) + return TRUE; + else + return FALSE; +} + +bool ipv6_addr_is_solicited_node_multicast_prefix(const ip6_addr_t *addr) +{ +// Solicited-Node Address: FF02:0:0:0:0:1:FFXX:XXXX + +// Solicited-Node multicast address are computed as a function of a +// node's unicast and anycast addresses. A Solicited-Node multicast +// address is formed by taking the low-order 24 bits of an address +// (unicast or anycast) and appending those bits to the prefix +// FF02:0:0:0:0:1:FF00::/104 resulting in a multicast address in the +// range + +// FF02:0:0:0:0:1:FF00:0000 + +// to + +// FF02:0:0:0:0:1:FFFF:FFFF + + if ( addr->addr[0] == 0xFF + && addr->addr[1] == 0x02 + && addr->addr[2] == 0 + && addr->addr[3] == 0 + && addr->addr[4] == 0 + && addr->addr[5] == 0 + && addr->addr[6] == 0 + && addr->addr[7] == 0 + && addr->addr[8] == 0 + && addr->addr[9] == 0 + && addr->addr[10] == 0 + && addr->addr[11] == 0x01 + && addr->addr[12] == 0xFF + ) + return TRUE; + else + return FALSE; +} + +uint8_t cmp_ipv6_addr(const ip6_addr_t *addr1, const ip6_addr_t *addr2) +{ + return memcmp(addr1, addr2, sizeof(ip6_addr_t)); +} + +uint8_t ipv6_addr_is_for_me(const ip6_addr_t *addr) +{ + //TODO: loopback addr (::1) + //TODO: interface-local addr FF01::1 + if (cmp_ipv6_addr(addr, &global_addr) == 0 || + cmp_ipv6_addr(addr, &linklocal_addr) == 0 || + ipv6_addr_is_linklocal_allnodes(addr) || + (ipv6_addr_is_solicited_node_multicast_prefix(addr) + && (((addr->addr[13] == global_addr.addr[13]) + && (addr->addr[14] == global_addr.addr[14]) + && (addr->addr[15] == global_addr.addr[15]) + ) || + ((addr->addr[13] == linklocal_addr.addr[13]) + && (addr->addr[14] == linklocal_addr.addr[14]) + && (addr->addr[15] == linklocal_addr.addr[15]) + ) + ) + ) + ) + return 1; + else + return 0; +} + +/* determine the right src_addr given a dst_addr */ +ip6_addr_t * determine_src_ipv6_addr(const ip6_addr_t *dst_addr) +{ + if (ipv6_addr_is_linklocal(dst_addr)) { + return &linklocal_addr; + } else { + return &global_addr; + } +} + +uint8_t cmp_hw_addr(const hw_addr_t *addr1, const hw_addr_t *addr2) +{ + // for short addresses compare only the first two bytes + if (addr1->type == HW_ADDR_SHORT && addr2->type == HW_ADDR_SHORT) { + return memcmp(addr1->addr_short, addr2->addr_short, 2); + } else { + return memcmp(addr1, addr2, sizeof(hw_addr_t)); + } +} + +uint8_t hw_addr_is_broadcat(const hw_addr_t *hw_addr) +{ + if (hw_addr->type == HW_ADDR_SHORT + && hw_addr->addr_short[0] == 0xFF + && hw_addr->addr_short[1] == 0xFF) + return 1; + // TODO: long address + else return 0; +} + +uint8_t hw_addr_is_for_me(const hw_addr_t *addr) +{ + am_addr_t am_addr = call AMPacket.address(); + if (hw_addr_is_broadcat(addr) || + (addr->addr_short[0] == (uint8_t) am_addr + && addr->addr_short[1] == (uint8_t) (am_addr >> 8)) + ) + return 1; + else + return 0; +} +/*---------------------------------------------------------------------------*/ + +void increment_g_dgram_tag() +{ + uint16_t tmp = ntohs(g_dgram_tag); + if (tmp == 0xFFFF) + tmp = 0; + else + tmp++; + g_dgram_tag = htons(tmp); +} + +void lowpan_pkt_clear(lowpan_pkt_t *pkt) +{ + memset(pkt, 0, sizeof(*pkt)); + pkt->header_begin = pkt->header + sizeof(pkt->header); +} + +/* +void frag_buf_clear(frag_buf_t *frag_buf) +{ + memset(frag_buf, 0, sizeof(*frag_buf)); + frag_buf->buf_begin = frag_buf->buf; +} +*/ + +frag_buf_t * find_fragment(hw_addr_t *hw_src_addr, hw_addr_t *hw_dst_addr, + uint16_t dgram_size, uint16_t dgram_tag) +{ + int i; + for (i = 0; i< FRAG_BUFS; i++) { + //printf("find_frag\n"); + if (frag_bufs[i].frag_timeout != FRAG_FREE) { + //printf("find: [%d] %d\n", i, frag_bufs[i].frag_timeout); + /* + printf("find: tag: 0x%04X, size: %d\n", + get_16t(&frag_bufs[i].dgram_tag), + ntohs(get_16t(&frag_bufs[i].dgram_size))); + */ + if ( get_16t(&(frag_bufs[i].dgram_tag)) == dgram_tag + && get_16t(&(frag_bufs[i].dgram_size)) == dgram_size + && cmp_hw_addr(&frag_bufs[i].hw_src_addr, hw_src_addr) == 0 + && cmp_hw_addr(&frag_bufs[i].hw_dst_addr, hw_dst_addr) == 0 + ) { + return &(frag_bufs[i]); + } + } else { + //printf("find: [%d] FREE\n", i); + } + } + return NULL; +} + +void free_frag_list(frag_info_t *p) +{ + frag_info_t *q; + while (p) { + q = p->next; + call FragInfoPool.put(p); + p = q; + } +} +/*---------------------------------------------------------------------------*/ + + void ip_init() + { + //int i; + lastport = 1024; + memset(udp_conns, 0, sizeof(udp_conns)); + //memset(&global_addr, 0, sizeof(global_addr)); + memset(&linklocal_addr, 0, sizeof(linklocal_addr)); + memset(frag_bufs, 0, sizeof(frag_bufs)); + /* + for(i=0;i= 32000) { + lastport = 4096; + } + + for (c = 0; c < COUNT_UDP_CONNS; ++c) { + if (udp_conns[c].lport == lastport) { + goto again; + } + } + + return lastport; + } + +/* ========================= IPv6 - output ================================= */ +task void sendTask() +{ + lowpan_pkt_t *pkt = send_queue; + struct lowpan_frag_hdr *frag_hdr; + uint8_t *payload; + uint8_t frame_len; + uint8_t len; /* length of the fragment just being sent + * excluding the 6lowpan optional headers */ + uint8_t remaining_len; /* how much more data can we fit + * into this fragment */ + + uint8_t *tmp_cpy_buf; /* simplifies memcpy */ + uint8_t tmp_cpy_len; /* simplifies memcpy */ + + if (!pkt || g_send_pending) { + return; + } + + //len = pkt->header_len + pkt->app_data_len - pkt->dgram_offset*8; + if (pkt->header_len + pkt->app_data_len <= LINK_DATA_MTU) { + /* fragmentation not needed */ + frame_len = pkt->header_len + pkt->app_data_len; + /* prepare the AM */ + call Packet.clear(&g_msg); + call Packet.setPayloadLength(&g_msg, frame_len); + payload = call Packet.getPayload(&g_msg, frame_len); + // memset(payload, 0 , payload_len); + // should check payload_len here + + /* copy header */ + if (pkt->header_begin && pkt->header_len) + memcpy(payload, pkt->header_begin, pkt->header_len); + payload += pkt->header_len; + + /* copy app_data */ + if (pkt->app_data_begin && pkt->app_data_len) + memcpy(payload, pkt->app_data_begin, pkt->app_data_len); + + } else { + /* do fragmentation */ + if (pkt->dgram_offset == 0) { + /* first fragment */ + increment_g_dgram_tag(); + set_16t(&pkt->dgram_size, + htons(pkt->header_len + pkt->app_data_len)); + + /* align fragment length at an 8-byte multiple */ + len = LINK_DATA_MTU - sizeof(struct lowpan_frag_hdr); + len -= len%8; + frame_len = len + sizeof(struct lowpan_frag_hdr); + } else { + /* subsequent fragment */ + if (pkt->header_len + pkt->app_data_len - pkt->dgram_offset*8 + <= LINK_DATA_MTU - sizeof(struct lowpan_frag_hdr) + - sizeof(uint8_t)) { + /* last fragment -- does not have to be aligned + * at an 8-byte multiple */ + len = pkt->header_len + pkt->app_data_len + - pkt->dgram_offset*8; + } else { + /* align fragment length at an 8-byte multiple */ + len = LINK_DATA_MTU - sizeof(struct lowpan_frag_hdr) + - sizeof(uint8_t); + len -= len%8; + } + frame_len = len + sizeof(struct lowpan_frag_hdr) + + sizeof(uint8_t); + } + + /* prepare the AM */ + call Packet.clear(&g_msg); + call Packet.setPayloadLength(&g_msg,frame_len); + payload = call Packet.getPayload(&g_msg, frame_len); + remaining_len = frame_len; + if (remaining_len != frame_len) { + //TODO: report an error +#ifdef ENABLE_PRINTF_DEBUG + printf("payload length does not match requested length\n"); + call PrintfFlush.flush(); +#endif /* ENABLE_PRINTF_DEBUG */ + return; + } + + /* fill in the fragment header */ + frag_hdr = (struct lowpan_frag_hdr *) payload; + set_16t(&frag_hdr->dgram_size, pkt->dgram_size); + set_16t(&frag_hdr->dgram_tag, g_dgram_tag); + payload += sizeof(struct lowpan_frag_hdr); + remaining_len -= sizeof(struct lowpan_frag_hdr); + + if (pkt->dgram_offset == 0) { + /* first fragment */ + frag_hdr->dispatch |= DISPATCH_FIRST_FRAG; + } else { + /* subsequent fragment */ + frag_hdr->dispatch |= DISPATCH_SUBSEQ_FRAG; + *payload = pkt->dgram_offset; + payload += sizeof(uint8_t); + } + + /* copy header */ + if (pkt->header_begin + && pkt->header_len + && pkt->header_len > pkt->dgram_offset*8 + /* don't copy the header if offset is beyond it*/ + ) { + /* determine what has to be copied */ + tmp_cpy_buf = pkt->header_begin + pkt->dgram_offset*8; + tmp_cpy_len = min(pkt->header_len - pkt->dgram_offset*8, + remaining_len); + /* copy it */ + memcpy(payload, tmp_cpy_buf, tmp_cpy_len); + payload += tmp_cpy_len; + remaining_len -= tmp_cpy_len; + } + + /* copy app_data */ + if (remaining_len + && pkt->app_data_begin + && pkt->app_data_len + ) { + /* determine what has to be copied */ + if (pkt->dgram_offset*8 > pkt->header_len) { + tmp_cpy_buf = pkt->app_data_begin + + pkt->dgram_offset*8 - pkt->header_len; + } else { + /* header has been copied only now, offset not yet updated */ + tmp_cpy_buf = pkt->app_data_begin; + } + tmp_cpy_len = min(remaining_len, + pkt->app_data_len + - (pkt->dgram_offset*8 - pkt->header_len)); + /* copy it */ + memcpy(payload, tmp_cpy_buf, tmp_cpy_len); + payload += tmp_cpy_len; + remaining_len -= tmp_cpy_len; + } + + /* update the offset - in 8-byte multiples */ + pkt->dgram_offset += len/8; + if (len%8) { + /* last fragment with a special length */ + pkt->dgram_offset++; + } + } + + /* send the AM */ + g_send_pending = 1; + call AMSend.send(AM_BROADCAST_ADDR, &g_msg, frame_len); + //call AMSend.send(0x12, &g_msg, frame_len); +} + +event void AMSend.sendDone(message_t* msg, error_t error) +{ + uint16_t len; + lowpan_pkt_t *pkt = send_queue; + + g_send_pending = 0; + + if (!send_queue) { + // somethign really went wrong... + return; + } + + len = pkt->header_len + pkt->app_data_len; + if (len <= LINK_DATA_MTU || pkt->dgram_offset*8 >= len){ + /* packet has been completely sent, we can move on to the next one */ + + /* UDPClient.sendDone notification */ + if (send_queue->notify_num != LOWPAN_PKT_NO_NOTIFY) { + signal UDPClient.sendDone[send_queue->notify_num - 1] + (SUCCESS, send_queue->app_data); + } + + /* deallocation of app_data (fragment reassembly buffer) */ + if (send_queue->app_data_dealloc == APP_DATA_DEALLOC_TRUE + && send_queue->app_data) { + call AppDataPool.put((app_data_t*) send_queue->app_data); + send_queue->app_data = NULL; + } + + pkt = send_queue->next; + call SendPktPool.put(send_queue); + send_queue = pkt; + } + if (send_queue) { + post sendTask(); + } +} + +void ipv6_output_uncompressed(lowpan_pkt_t *pkt, const uint8_t next_header) +{ + struct ip6_hdr *hdr; + lowpan_pkt_t *p; + + pkt->header_begin -= sizeof(struct ip6_hdr); + pkt->header_len += sizeof(struct ip6_hdr); + hdr = (struct ip6_hdr *) pkt->header_begin; + + /* fill in the IPv6 header */ + hdr->vtc = IPV6_VERSION; /* IPv6 version */ + /* payload length */ + set_16t(&hdr->plen, htons(pkt->header_len + pkt->app_data_len + - sizeof(struct ip6_hdr))); + + hdr->nxt_hdr = next_header; + hdr->hlim = IP_HOP_LIMIT; /* hop limit */ + + memcpy(&hdr->src_addr, &pkt->ip_src_addr, sizeof(hdr->src_addr)); + memcpy(&hdr->dst_addr, &pkt->ip_dst_addr, sizeof(hdr->dst_addr)); + + /* set 6lowpan dispatch value */ + pkt->header_begin -= sizeof(uint8_t); + pkt->header_len += sizeof(uint8_t); + *(pkt->header_begin) = DISPATCH_UNCOMPRESSED_IPV6; + + //TODO: check if neighbor is information available + // if yes + // fill in hw_addr + // append to send_queue + // else + // append to neighbor_queue + // request ND, add an entry into the neighbor table + + /* append pkt to send queue */ + if(!send_queue) { + send_queue = pkt; + } else { + for(p=send_queue; p->next; p=p->next); + p->next = pkt; + } + + /* schedule sendTask */ + post sendTask(); +} + +/* determines length of the inline carried fields for the HC1 encoding + * the return value is the number of bits, bot bytes !!! + */ +int get_hc1_length(uint8_t hc1_enc) +{ + int len = 0; + /* Hop Limit always carried inline */ + len += 8; + + /* source IP address */ + if ((hc1_enc & HC1_SRC_PREFIX_MASK) == HC1_SRC_PREFIX_INLINE) + len += 64; + + if ((hc1_enc & HC1_SRC_IFACEID_MASK) == HC1_SRC_IFACEID_INLINE) + len += 64; + + /* destination IP address */ + if ((hc1_enc & HC1_DST_PREFIX_MASK) == HC1_DST_PREFIX_INLINE) + len += 64; + + if ((hc1_enc & HC1_DST_IFACEID_MASK) == HC1_DST_IFACEID_INLINE) + len += 64; + + /* Traffic Class and Flow Label */ + if ((hc1_enc & HC1_TCFL_MASK) == HC1_TCFL_INLINE) + len += 24; + + /* Next Header */ + if ((hc1_enc & HC1_NEXTHDR_MASK) == HC1_NEXTHDR_INLINE) + len += 8; + + return len; +} + +void ipv6_compressed_output(lowpan_pkt_t *pkt, const uint8_t next_header, + uint8_t hc2_enc, bool hc2_present) +{ + lowpan_pkt_t *p; + uint8_t hc1_enc = 0; + + /* HC2 compression */ + if (hc2_present) { + hc1_enc |= HC1_HC2_PRESENT; + } else { + hc1_enc |= HC1_HC2_NONE; + } + + /* next header */ + switch (next_header) { + case NEXT_HEADER_UDP: + hc1_enc |= HC1_NEXTHDR_UDP; + break; + case NEXT_HEADER_ICMP6: + hc1_enc |= HC1_NEXTHDR_ICMP; + break; + case NEXT_HEADER_TCP: + hc1_enc |= HC1_NEXTHDR_TCP; + break; + default: + hc1_enc |= HC1_NEXTHDR_INLINE; + + pkt->header_begin -= sizeof(next_header); + pkt->header_len += sizeof(next_header); + *(pkt->header_begin) = next_header; + break; + } + + /* we're always sending packets with TC anf FL zero */ + hc1_enc |= HC1_TCFL_ZERO; + + /* destination address interface identifier */ + hc1_enc |= HC1_DST_IFACEID_INLINE; + + pkt->header_begin -= 8; + pkt->header_len += 8; + memcpy(pkt->header_begin, ((void*)&(pkt->ip_dst_addr)) + 8, 8); + + /* destination address prefix */ + if (ipv6_addr_is_linklocal_unicast(&pkt->ip_dst_addr)) { + hc1_enc |= HC1_DST_PREFIX_LINKLOCAL; + } else { + hc1_enc |= HC1_DST_PREFIX_INLINE; + + pkt->header_begin -= 8; + pkt->header_len += 8; + memcpy(pkt->header_begin, &(pkt->ip_dst_addr), 8); + } + + /* source address interface identifier */ + hc1_enc |= HC1_SRC_IFACEID_INLINE; + + pkt->header_begin -= 8; + pkt->header_len += 8; + memcpy(pkt->header_begin, ((void*)&(pkt->ip_src_addr)) + 8, 8); + + /* source address prefix */ + if (ipv6_addr_is_linklocal_unicast(&pkt->ip_src_addr)) { + hc1_enc |= HC1_SRC_PREFIX_LINKLOCAL; + } else { + hc1_enc |= HC1_SRC_PREFIX_INLINE; + + pkt->header_begin -= 8; + pkt->header_len += 8; + memcpy(pkt->header_begin, &(pkt->ip_src_addr), 8); + } + + /* Hop Limit */ + pkt->header_begin -= sizeof(uint8_t); + pkt->header_len += sizeof(uint8_t); + *pkt->header_begin = IP_HOP_LIMIT; + + /* HC2 encoding field */ + if (hc2_present) { + pkt->header_begin -= sizeof(uint8_t); + pkt->header_len += sizeof(uint8_t); + *(pkt->header_begin) = hc2_enc; + } + + /* HC1 encoding field */ + pkt->header_begin -= sizeof(uint8_t); + pkt->header_len += sizeof(uint8_t); + *(pkt->header_begin) = hc1_enc; + + /* set 6lowpan dispatch value */ + pkt->header_begin -= sizeof(uint8_t); + pkt->header_len += sizeof(uint8_t); + *(pkt->header_begin) = DISPATCH_COMPRESSED_IPV6; + + /* append pkt to send queue */ + if(!send_queue) { + send_queue = pkt; + } else { + for(p=send_queue; p->next; p=p->next); + p->next = pkt; + } + + /* schedule sendTask */ + post sendTask(); +} + +void icmpv6_output(lowpan_pkt_t *pkt, + uint8_t type, uint8_t code) +{ + struct icmp6_hdr *hdr; + uint16_t cksum = 0; + /* fill in the source address if not set */ + if (ipv6_addr_is_zero(&pkt->ip_src_addr)) { + memcpy(&pkt->ip_src_addr, + determine_src_ipv6_addr(&pkt->ip_dst_addr), + sizeof(pkt->ip_src_addr)); + } + + /* fill in the ICMPv6 header */ + pkt->header_begin -= sizeof(struct icmp6_hdr); + pkt->header_len += sizeof(struct icmp6_hdr); + hdr = (struct icmp6_hdr *) pkt->header_begin; + + hdr->type = type; + hdr->code = code; + + /* calculate the checksum */ + set_16t(&hdr->cksum, 0); + cksum = ipv6_chksum(&pkt->ip_src_addr, &pkt->ip_dst_addr, + NEXT_HEADER_ICMP6, + pkt->header_len + pkt->app_data_len, cksum); + cksum = ip_chksum((void*)hdr, sizeof(struct icmp6_hdr), cksum); + cksum = ip_chksum(pkt->app_data_begin, pkt->app_data_len, + cksum); + cksum = ~cksum; + set_16t(&hdr->cksum, cksum); + + ipv6_compressed_output(pkt, NEXT_HEADER_ICMP6, 0, FALSE); +} + +error_t udp_uncompressed_output(void* buf, uint16_t len, + const ip6_addr_t *src_addr, + const ip6_addr_t *dst_addr, + uint16_t src_port, + uint16_t dst_port, + uint8_t udp_client_num) +{ + struct udp_hdr *hdr; + lowpan_pkt_t *pkt; + uint16_t cksum = 0; + + if (!dst_addr) return FAIL; + + pkt = call SendPktPool.get(); + if (!pkt) return FAIL; + + lowpan_pkt_clear(pkt); + + /* set the UDPCliemt number to allow for signalling sendDone */ + pkt->notify_num = udp_client_num; + + /* set application data */ + pkt->app_data = buf; + pkt->app_data_begin = buf; + pkt->app_data_len = len; + + /* set IP addresses */ + memcpy(&pkt->ip_dst_addr, dst_addr, sizeof(pkt->ip_dst_addr)); + if (src_addr) { + memcpy(&pkt->ip_src_addr, src_addr, sizeof(pkt->ip_src_addr)); + } else { + memcpy(&pkt->ip_src_addr, + determine_src_ipv6_addr(dst_addr), + sizeof(pkt->ip_src_addr)); + } + + /* fill in the UDP header */ + pkt->header_begin -= sizeof(struct udp_hdr); + pkt->header_len += sizeof(struct udp_hdr); + hdr = (struct udp_hdr *) pkt->header_begin; + /* src port */ + set_16t(&hdr->srcport, src_port); + /* dst port */ + set_16t(&hdr->dstport, dst_port); + /* length */ + set_16t(&hdr->len,htons(len + sizeof(struct udp_hdr))); + /* checksum */ + set_16t(&hdr->chksum, 0); + cksum = ip_chksum((uint8_t*) hdr, sizeof(struct udp_hdr), cksum); + cksum = ipv6_chksum(&pkt->ip_dst_addr, + &pkt->ip_src_addr, + NEXT_HEADER_UDP, + sizeof(struct udp_hdr) + len, cksum); + cksum = ip_chksum(buf, len, cksum); + if (cksum != 0xFFFF) { + cksum = ~cksum; + } + set_16t(&hdr->chksum, cksum); + + ipv6_compressed_output(pkt, NEXT_HEADER_UDP, 0, FALSE); + + return SUCCESS; +} + +error_t udp_compressed_output(void* buf, uint16_t len, + const ip6_addr_t *src_addr, + const ip6_addr_t *dst_addr, + uint16_t src_port, + uint16_t dst_port, + uint8_t udp_client_num) +{ + lowpan_pkt_t *pkt; + uint16_t cksum = 0; + uint16_t hc2_enc = 0; + uint16_t udp_len = htons(len + sizeof(struct udp_hdr)); + + if (!dst_addr) return FAIL; + + pkt = call SendPktPool.get(); + if (!pkt) return FAIL; + + lowpan_pkt_clear(pkt); + + /* set the UDPCliemt number to allow for signalling sendDone */ + pkt->notify_num = udp_client_num; + + /* set application data */ + pkt->app_data = buf; + pkt->app_data_begin = buf; + pkt->app_data_len = len; + + /* set IP addresses */ + memcpy(&pkt->ip_dst_addr, dst_addr, sizeof(pkt->ip_dst_addr)); + if (src_addr) { + memcpy(&pkt->ip_src_addr, src_addr, sizeof(pkt->ip_src_addr)); + } else { + memcpy(&pkt->ip_src_addr, + determine_src_ipv6_addr(dst_addr), + sizeof(pkt->ip_src_addr)); + } + + /* Checksum */ + cksum = 0; + cksum = ip_chksum((void*) &src_port, sizeof(src_port), cksum); + cksum = ip_chksum((void*) &dst_port, sizeof(src_port), cksum); + cksum = ip_chksum((void*) &udp_len, sizeof(udp_len), cksum); + cksum = ipv6_chksum(&pkt->ip_dst_addr, + &pkt->ip_src_addr, + NEXT_HEADER_UDP, + sizeof(struct udp_hdr) + len, cksum); + cksum = ip_chksum(buf, len, cksum); + if (cksum != 0xFFFF) { + cksum = ~cksum; + } + + /* HC_UDP encoding */ + /* Checksum */ + pkt->header_begin -= sizeof(cksum); + pkt->header_len += sizeof(cksum); + set_16t(pkt->header_begin, cksum); + + /* Length */ + //hc2_enc |= HC2_UDP_LEN_COMPR; + hc2_enc |= HC2_UDP_LEN_INLINE; + pkt->header_begin -= sizeof(udp_len); + pkt->header_len += sizeof(udp_len); + set_16t(pkt->header_begin, udp_len); + + /* Destination Port */ + hc2_enc |= HC2_UDP_DST_PORT_INLINE; + pkt->header_begin -= sizeof(dst_port); + pkt->header_len += sizeof(dst_port); + set_16t(pkt->header_begin, dst_port); + + /* Source Port */ + hc2_enc |= HC2_UDP_SRC_PORT_INLINE; + pkt->header_begin -= sizeof(src_port); + pkt->header_len += sizeof(src_port); + set_16t(pkt->header_begin, src_port); + + ipv6_compressed_output(pkt, NEXT_HEADER_UDP, hc2_enc, TRUE); + + return SUCCESS; +} +/* ========================== IPv6 - input ================================= */ +void icmpv6_input(uint8_t* buf, uint16_t len) +{ + lowpan_pkt_t *pkt; + struct icmp6_hdr *hdr = (struct icmp6_hdr *)buf; + + /* Compute and check the IP header checksum. */ + if (ipv6_chksum_data(&rx_pkt.ip_src_addr, &rx_pkt.ip_dst_addr, + NEXT_HEADER_ICMP6, buf, len, 0) + != 0xffff) { +#ifdef ENABLE_PRINTF_DEBUG + printf("icmpv6_input(): checksum failed\n"); + call PrintfFlush.flush(); +#endif /* ENABLE_PRINTF_DEBUG */ + call Leds.led0Toggle(); + return; + } + + buf += sizeof(struct icmp6_hdr); + len -= sizeof(struct icmp6_hdr); + + switch (hdr->type) { + case ICMP_TYPE_ECHO_REQUEST: + /* ICMP code has to be 0 */ + if (hdr->code != 0) { + return; + } + + call Leds.led2Toggle(); + /* send back an ICMP ECHO REPLY */ + + /* allocate a packet for the reply */ + pkt = call SendPktPool.get(); + if (!pkt) { +#ifdef ENABLE_PRINTF_DEBUG + printf("icmpv6_input() - failed to alloc pkt\n"); + call PrintfFlush.flush(); +#endif /* ENABLE_PRINTF_DEBUG */ + return; + } + lowpan_pkt_clear(pkt); + + /* copy/set ICMP data */ + if (rx_pkt.app_data) { + /* fragment reassembly took place - ICMP data is in app_data buf */ + pkt->app_data = rx_pkt.app_data; + pkt->app_data_begin = buf; + pkt->app_data_len = len; + pkt->app_data_dealloc = rx_pkt.app_data_dealloc; + + rx_pkt.app_data_dealloc = APP_DATA_DEALLOC_FALSE; + rx_pkt.app_data = NULL; + } else { + /* there is no app_data buf, everything fits into the header buf */ + pkt->header_begin -= len; + my_memcpy(pkt->header_begin, buf, len); + pkt->app_data_begin = pkt->header_begin; + pkt->app_data_len = len; + } + + /* set destination address */ + memcpy(&pkt->ip_dst_addr, &rx_pkt.ip_src_addr, + sizeof(pkt->ip_dst_addr)); + // source address determined automatically + + icmpv6_output(pkt, ICMP_TYPE_ECHO_REPLY, 0); + break; + case ICMP_TYPE_ECHO_REPLY: + break; + + } +} + +/* UDP input processing. */ +void udp_input(uint8_t* buf, uint16_t len) +{ + struct udp_conn *conn; + int c; + struct udp_hdr *hdr = (struct udp_hdr *)buf; + + /* Compute and check the IP header checksum. */ + if (ipv6_chksum_data(&rx_pkt.ip_src_addr, &rx_pkt.ip_dst_addr, + NEXT_HEADER_UDP, buf, len, 0) + != 0xffff) { +#ifdef ENABLE_PRINTF_DEBUG + printf("udp_input(): checksum failed\n"); + call PrintfFlush.flush(); +#endif /* ENABLE_PRINTF_DEBUG */ + call Leds.led0Toggle(); + return; + } + + if (htons(len) != hdr->len) { +#ifdef ENABLE_PRINTF_DEBUG + printf("length check failed\n"); + printf("reported length: %d\n", len); + printf("UDP header len: %d\n", ntohs(hdr->len)); + call PrintfFlush.flush(); +#endif /* ENABLE_PRINTF_DEBUG */ + return; + } + /* Scan the list of UDP sockets and look for one that is accepting + this port */ + for (c = 0, conn = udp_conns; c < COUNT_UDP_CONNS; c++, conn++) { + /* + printf("lport: 0x%X\n", conn->lport); + printf("rport: 0x%X\n", conn->rport); + printf("conn->ripaddr: "); + dump_serial_packet(&(conn->ripaddr), sizeof(ip6_addr_t)); + printf("src_addr: "); + dump_serial_packet(src_addr, sizeof(ip6_addr_t)); + */ + if ( (conn->lport != 0 && conn->lport == hdr->dstport) && + (conn->rport == 0 || conn->rport == hdr->srcport) && + (ipv6_addr_is_zero(&(conn->ripaddr)) || + (cmp_ipv6_addr(&conn->ripaddr, &rx_pkt.ip_src_addr) == 0)) + ) + goto udp_match_found; + } +#ifdef ENABLE_PRINTF_DEBUG + printf("udp_input(): no connection matched - dropping UDP packet\n"); + call PrintfFlush.flush(); +#endif /* ENABLE_PRINTF_DEBUG */ + return; + + udp_match_found: + len -= sizeof(struct udp_hdr); + if (len > 0) { + signal UDPClient.receive[c](&rx_pkt.ip_src_addr, ntohs(hdr->srcport), + buf+sizeof(struct udp_hdr), len); + } +} + +void udp_input_compressed(uint8_t* buf, uint16_t len, uint8_t hc2_enc) +{ + struct udp_conn *conn; + int c; + uint16_t src_port; + uint16_t dst_port; + uint16_t chksum; + uint16_t tmp_chksum; + uint16_t tmp_len; + + /* UDP Source Port */ + if ((hc2_enc & HC2_UDP_SRC_PORT_MASK) == HC2_UDP_SRC_PORT_INLINE) { + src_port = get_16t(buf); + buf += sizeof(src_port); + len -= sizeof(src_port); + } else { + //TODO + return; + } + + /* UDP Destination Port */ + if ((hc2_enc & HC2_UDP_DST_PORT_MASK) == HC2_UDP_DST_PORT_INLINE) { + dst_port = get_16t(buf); + buf += sizeof(dst_port); + len -= sizeof(dst_port); + } else { + //TODO + return; + } + + /* UDP Length */ + if ((hc2_enc & HC2_UDP_LEN_MASK) == HC2_UDP_LEN_INLINE) { + /* check the length */ + if (ntohs(get_16t(buf)) != len + sizeof(uint16_t)*2) { +#ifdef ENABLE_PRINTF_DEBUG + printf("length check failed\n"); + printf("reported length: %d\n", len + sizeof(uint16_t)*2); + printf("UDP header len: %d\n", ntohs(get_16t(buf))); + call PrintfFlush.flush(); +#endif /* ENABLE_PRINTF_DEBUG */ + return; + } + buf += sizeof(uint16_t); + len -= sizeof(uint16_t); + } + + /* Checksum */ + chksum = get_16t(buf); + buf += sizeof(chksum); + len -= sizeof(chksum); + + /* --- end of decompression --- */ + + /* Compute and check the IP header checksum. */ + tmp_chksum = 0; + /* IPv6 pseaudo header */ + tmp_chksum = ipv6_chksum(&rx_pkt.ip_src_addr, &rx_pkt.ip_dst_addr, + NEXT_HEADER_UDP, + /* len is only app data, so add UDP header + * length to get the length for chksum */ + len + sizeof(struct udp_hdr), + tmp_chksum); + /* UDP header */ + tmp_len = htons(len + sizeof(struct udp_hdr)); + tmp_chksum = ip_chksum((void*) &src_port, sizeof(src_port), tmp_chksum); + tmp_chksum = ip_chksum((void*) &dst_port, sizeof(src_port), tmp_chksum); + tmp_chksum = ip_chksum((void*) &chksum, sizeof(chksum), tmp_chksum); + tmp_chksum = ip_chksum((void*) &tmp_len, sizeof(len), tmp_chksum); + /* UDP payload - application data */ + tmp_chksum = ip_chksum(buf, len, tmp_chksum); + + if (tmp_chksum != 0xffff) { +#ifdef ENABLE_PRINTF_DEBUG + printf("udp_input_compressed(): checksum failed\n"); + call PrintfFlush.flush(); +#endif /* ENABLE_PRINTF_DEBUG */ + call Leds.led0Toggle(); + return; + } + +// printf("udp_input_compressed()\n"); +// printf("src_port: 0x%X\n", src_port); +// printf("dst_port: 0x%X\n", dst_port); +// printf("len (app_data): %d\n", len); +// call PrintfFlush.flush(); + + /* Scan the list of UDP sockets and look for one that is accepting + this port */ + for (c = 0, conn = udp_conns; c < COUNT_UDP_CONNS; c++, conn++) { + /* + printf("lport: 0x%X\n", conn->lport); + printf("rport: 0x%X\n", conn->rport); + printf("conn->ripaddr: "); + dump_serial_packet(&(conn->ripaddr), sizeof(ip6_addr_t)); + printf("src_addr: "); + dump_serial_packet(&rx_pkt.ip_src_addr, sizeof(ip6_addr_t)); + */ + if ( (conn->lport != 0 && conn->lport == dst_port) && + (conn->rport == 0 || conn->rport == src_port) && + (ipv6_addr_is_zero(&(conn->ripaddr)) || + (cmp_ipv6_addr(&conn->ripaddr, &rx_pkt.ip_src_addr) == 0)) + ) + goto udp_match_found; + } +#ifdef ENABLE_PRINTF_DEBUG + printf("udp_input_compressed(): "\ + "no connection matched - dropping UDP packet\n"); + call PrintfFlush.flush(); +#endif /* ENABLE_PRINTF_DEBUG */ + return; + + udp_match_found: + if (len > 0) { + signal UDPClient.receive[c](&rx_pkt.ip_src_addr, ntohs(src_port), + buf, len); + } +} + +/* processed the IPv6 header (uncompressed) */ +void ipv6_input_uncompressed(uint8_t* buf, uint16_t len) +{ + struct ip6_hdr *hdr = (struct ip6_hdr *) buf; + + /* check the version */ + if ((hdr->vtc & IPV6_VERSION_MASK) != 0x60) { +#ifdef ENABLE_PRINTF_DEBUG + printf("IP version check failed (%X)\n", + hdr->vtc & IPV6_VERSION_MASK); + call PrintfFlush.flush(); +#endif /* ENABLE_PRINTF_DEBUG */ + return; + } + + /* Hop Limit */ + if (! hdr->hlim) { + /* Hop Limit reached zero */ +#ifdef ENABLE_PRINTF_DEBUG + printf("Hop Limit reached zero\n"); + call PrintfFlush.flush(); +#endif /* ENABLE_PRINTF_DEBUG */ + return; + } + + /* check dst IP address */ + if (! ipv6_addr_is_for_me(&hdr->dst_addr)) { + return; + } + + /* Check the size of the packet. If the size reported to us in + * uip_len doesn't match the size reported in the IP header, there + * has been a transmission error and we drop the packet. + */ + if ( hdr->plen != htons(len - sizeof(struct ip6_hdr))) { +#ifdef ENABLE_PRINTF_DEBUG + printf("length check failed\n"); + printf("l2 reported length: %d\n", len - sizeof(struct ip6_hdr)); + printf("IPv6 header plen: %d (network byte order: 0x%X\n", + ntohs(hdr->plen), hdr->plen); + //((hdr->plen & 0xff00) >> 8) & ((hdr->plen & 0xff) << 8)); + call PrintfFlush.flush(); +#endif /* ENABLE_PRINTF_DEBUG */ + return; + } + + /* copy IP addresses to rx_pkt */ + memcpy(&rx_pkt.ip_src_addr, &(hdr->src_addr), sizeof(rx_pkt.ip_src_addr)); + memcpy(&rx_pkt.ip_dst_addr, &(hdr->dst_addr), sizeof(rx_pkt.ip_dst_addr)); + + /* multipex on next header */ + switch (hdr->nxt_hdr) { + case NEXT_HEADER_ICMP6: + icmpv6_input(buf + sizeof(struct ip6_hdr), + len - sizeof(struct ip6_hdr)); + break; + case NEXT_HEADER_UDP: + udp_input(buf + sizeof(struct ip6_hdr), + len - sizeof(struct ip6_hdr)); + break; + /* + case NEXT_HEADER_TCP: + break; + */ + default: +#ifdef ENABLE_PRINTF_DEBUG + printf("unknown IPv6 next header: 0x%X\n", hdr->nxt_hdr); + call PrintfFlush.flush(); +#endif /* ENABLE_PRINTF_DEBUG */ + break; + } +} + +/* processed the IPv6 header (uncompressed) */ +void ipv6_input_compressed(uint8_t* buf, uint16_t len) +{ + struct ip6_hdr *ip_hdr = (struct ip6_hdr *) buf; + + uint8_t hc1_enc; + uint8_t hc2_enc = 0; + uint8_t next_header; + + /* + printf("nxt_hdr: 0x%X\n", hdr->nxt_hdr); + dump_serial_packet(buf, len); + call PrintfFlush.flush(); + */ + + hc1_enc = *buf; + buf += sizeof(hc1_enc); + len -= sizeof(hc1_enc); + + /* HC2 encoding follows HC1 encoding */ + if ((hc1_enc & HC1_HC2_MASK) == HC1_HC2_PRESENT) { + hc2_enc = *buf; + buf += sizeof(hc2_enc); + len -= sizeof(hc2_enc); + } + + /* Hop Limit */ + if (*buf) { + buf += sizeof(ip_hdr->hlim); + len -= sizeof(ip_hdr->hlim); + } else { + /* Hop Limit reached zero */ + return; + } + + /* source IP address */ + if ((hc1_enc & HC1_SRC_PREFIX_MASK) == HC1_SRC_PREFIX_INLINE) { + memcpy(&rx_pkt.ip_src_addr, buf, sizeof(rx_pkt.ip_src_addr)/2); + buf += sizeof(rx_pkt.ip_src_addr)/2; + len -= sizeof(rx_pkt.ip_src_addr)/2; + } else { + /* linl-local prefix */ + memset(&rx_pkt.ip_src_addr, 0, sizeof(rx_pkt.ip_src_addr)/2); + rx_pkt.ip_src_addr.addr[0] = 0xFE; + rx_pkt.ip_src_addr.addr[1] = 0x80; + } + + if ((hc1_enc & HC1_SRC_IFACEID_MASK) == HC1_SRC_IFACEID_INLINE) { + memcpy(((void*)&rx_pkt.ip_src_addr) + sizeof(rx_pkt.ip_src_addr)/2, + buf, sizeof(rx_pkt.ip_src_addr)/2); + buf += sizeof(rx_pkt.ip_src_addr)/2; + len -= sizeof(rx_pkt.ip_src_addr)/2; + } + + /* destination IP address */ + if ((hc1_enc & HC1_DST_PREFIX_MASK) == HC1_DST_PREFIX_INLINE) { + memcpy(&rx_pkt.ip_dst_addr, buf, sizeof(rx_pkt.ip_dst_addr)/2); + buf += sizeof(rx_pkt.ip_dst_addr)/2; + len -= sizeof(rx_pkt.ip_dst_addr)/2; + } else { + /* linl-local prefix */ + memset(&rx_pkt.ip_dst_addr, 0, sizeof(rx_pkt.ip_dst_addr)/2); + rx_pkt.ip_dst_addr.addr[0] = 0xFE; + rx_pkt.ip_dst_addr.addr[1] = 0x80; + } + + if ((hc1_enc & HC1_DST_IFACEID_MASK) == HC1_DST_IFACEID_INLINE) { + memcpy(((void*)&rx_pkt.ip_dst_addr) + sizeof(rx_pkt.ip_dst_addr)/2, + buf, sizeof(rx_pkt.ip_dst_addr)/2); + buf += sizeof(rx_pkt.ip_dst_addr)/2; + len -= sizeof(rx_pkt.ip_dst_addr)/2; + } + + /* check dst IP address */ + if (! ipv6_addr_is_for_me(&rx_pkt.ip_dst_addr)) { + /* + printf("IP address check failed\n"); + dump_serial_packet(hdr->dst_addr.addr, sizeof(hdr->dst_addr.addr)); + call PrintfFlush.flush(); + */ + return; + } + + /* Traffic Class and Flow Label */ + if ((hc1_enc & HC1_TCFL_MASK) == HC1_TCFL_INLINE) { + //TODO + return; + } + + /* Next Header */ + switch (hc1_enc & HC1_NEXTHDR_MASK) { + case HC1_NEXTHDR_INLINE: + next_header = *buf; + buf += sizeof(uint8_t); + len -= sizeof(uint8_t); + break; + case HC1_NEXTHDR_UDP: + next_header = NEXT_HEADER_UDP; + break; + case HC1_NEXTHDR_ICMP: + next_header = NEXT_HEADER_ICMP6; + break; + case HC1_NEXTHDR_TCP: + next_header = NEXT_HEADER_TCP; + break; + default: +#ifdef ENABLE_PRINTF_DEBUG + printf("unknown next header HC1 encoding\n"); + call PrintfFlush.flush(); +#endif /* ENABLE_PRINTF_DEBUG */ + return; + } + + /* multipex on the next header */ + switch (next_header) { + case NEXT_HEADER_ICMP6: + icmpv6_input(buf, len); + break; + case NEXT_HEADER_UDP: + /* HC_UDP compression */ + if ((hc1_enc & HC1_HC2_MASK) == HC1_HC2_PRESENT + && (hc1_enc & HC1_NEXTHDR_MASK) == HC1_NEXTHDR_UDP) { + udp_input_compressed(buf, len, hc2_enc); + break; + } else { + udp_input(buf, len); + break; + } + /* + case NEXT_HEADER_TCP: + break; + */ + default: +#ifdef ENABLE_PRINTF_DEBUG + printf("unknown IPv6 next header: 0x%X\n", next_header); + call PrintfFlush.flush(); +#endif /* ENABLE_PRINTF_DEBUG */ + break; + } +} + +/* call the right fct for processing the IPv6 header */ +void layer3_input(uint8_t *buf, uint16_t len) +{ + uint8_t *dispatch = buf; + buf++; + len--; + + /* uncompressed IPv6 */ + if (*dispatch == DISPATCH_UNCOMPRESSED_IPV6) { + ipv6_input_uncompressed(buf, len); + } + /* LOWPAN_HC1 compressed IPv6 */ + else if (*dispatch == DISPATCH_COMPRESSED_IPV6) { + //call Leds.led1Toggle(); + return ipv6_input_compressed(buf, len); + } + /* unknown dispatch value if we got here */ + else { + //TODO: report an error + } +} + +/* process the optional 6lowpan headers */ +void lowpan_input(uint8_t* buf, uint8_t len ) +{ + uint8_t *dispatch; + struct lowpan_broadcast_hdr *bc_hdr; + struct lowpan_frag_hdr *frag_hdr; + int i; + + frag_buf_t *frag; + uint16_t dgram_tag; + uint16_t dgram_size; + uint8_t dgram_offset; + frag_info_t *p; + frag_info_t **q; + uint8_t last_frag; + + dispatch = buf; + /* --- 6lowpan optional headers --- */ + /* Mesh Addressing header */ + if ( (*dispatch & DISPATCH_MESH_MASK) == DISPATCH_MESH) { + // check if we're the final recipient in the mesh addressing header + buf++; + len--; + + /* Hops Left */ + if ((*dispatch & 0x0F) == 0) { + goto discard_packet; + } + + /* Final Destination Address */ + if (*dispatch & DISPATCH_MESH_F_FLAG) { + rx_pkt.hw_dst_addr.type = HW_ADDR_LONG; + memcpy(&rx_pkt.hw_dst_addr.addr_long, buf, + sizeof(rx_pkt.hw_dst_addr.addr_long)); + buf += sizeof(rx_pkt.hw_dst_addr.addr_long); + len -= sizeof(rx_pkt.hw_dst_addr.addr_long); + } else { + rx_pkt.hw_dst_addr.type = HW_ADDR_SHORT; + memcpy(&rx_pkt.hw_dst_addr.addr_short, buf, + sizeof(rx_pkt.hw_dst_addr.addr_short)); + buf += sizeof(rx_pkt.hw_dst_addr.addr_short); + len -= sizeof(rx_pkt.hw_dst_addr.addr_short); + } + + /* check if we're the recipient */ + if (! hw_addr_is_for_me(&rx_pkt.hw_dst_addr)) { + // TODO: if mesh forwarding enabled, then forward + goto discard_packet; + } + + /* Originator Address */ + if (*dispatch & DISPATCH_MESH_O_FLAG) { + rx_pkt.hw_src_addr.type = HW_ADDR_LONG; + memcpy(&rx_pkt.hw_src_addr.addr_long, buf, + sizeof(rx_pkt.hw_src_addr.addr_long)); + buf += sizeof(rx_pkt.hw_src_addr.addr_long); + len -= sizeof(rx_pkt.hw_src_addr.addr_long); + } else { + rx_pkt.hw_src_addr.type = HW_ADDR_SHORT; + memcpy(rx_pkt.hw_src_addr.addr_short, buf, + sizeof(rx_pkt.hw_src_addr.addr_short)); + buf += sizeof(rx_pkt.hw_src_addr.addr_short); + len -= sizeof(rx_pkt.hw_src_addr.addr_short); + } + + dispatch = buf; + } + if (*dispatch == DISPATCH_BC0) { /* Broadcast header */ + bc_hdr = (struct lowpan_broadcast_hdr *) buf; + // do something usefull with bc_hdr->seq_no... + + buf += (sizeof(struct lowpan_broadcast_hdr)); + len -= (sizeof(struct lowpan_broadcast_hdr)); + dispatch = buf; + } + + /* fragment header */ + if ((*dispatch & DISPATCH_FRAG_MASK) + == DISPATCH_FIRST_FRAG + || (*dispatch & DISPATCH_FRAG_MASK) + == DISPATCH_SUBSEQ_FRAG + ) { + frag_hdr = (struct lowpan_frag_hdr *) buf; + buf += sizeof(struct lowpan_frag_hdr); + len -= sizeof(struct lowpan_frag_hdr); + + /* collect information about the fragment */ + dgram_tag = get_16t(&frag_hdr->dgram_tag); + //dgram_size = get_16t(&frag_hdr->dgram_size); + //dgram_size &= htons(0x07FF); + dgram_size = frag_hdr->dgram_size8[1]; + dgram_size += (frag_hdr->dgram_size8[0] & 0x07) << 8; + dgram_size = htons(dgram_size); + if ((*dispatch & DISPATCH_FRAG_MASK) == DISPATCH_SUBSEQ_FRAG) { + dgram_offset = *buf; + buf += 1; + len -= 1; + } else { + dgram_offset = 0; + } + +#ifdef ENABLE_PRINTF_DEBUG + printf("off: %d\n", dgram_offset); +#endif /* ENABLE_PRINTF_DEBUG */ + /* + printf("off: %d, f_b[%d] %d\n", + dgram_offset, 0, frag_bufs[0].frag_timeout); + */ + frag = find_fragment(&rx_pkt.hw_src_addr, &rx_pkt.hw_dst_addr, + dgram_size, dgram_tag); + /* + if (frag) { + printf("frag found\n"); + } else { + printf("frag NOT found\n"); + } + */ + if (frag) { + /* fragment reassembly buffer found */ + /* check for overlap */ + //TODO: ENABLE THIS PART !!! +// for (p = frag->frag_list; p; p=p->next) { +// if (dgram_offset == p->offset){ +// if (len == p->len) { +// /* same offset, same len => discard this duplicate */ +// goto discard_packet; +// } else { +// /* same offset, but different len */ +// goto frag_overlap; +// } +// } else if (dgram_offset > p->offset +// && dgram_offset < p->offset + p->len/8 +// ) { +// /* offset inside another frag*/ +// goto frag_overlap; +// } +// } + /* no overlap found */ + //printf("frag found: %d\n", frag->frag_timeout); + goto frag_reassemble; + } else { + /* fragment reassembly buffer not found - set up a new one */ + // no match found -- need a new frag_buf_t + for (i = 0; i< FRAG_BUFS; i++) { + if (frag_bufs[i].frag_timeout == FRAG_FREE + && call AppDataPool.empty() == FALSE) { + frag = &frag_bufs[i]; + set_16t(&frag->dgram_tag, get_16t(&frag_hdr->dgram_tag)); + set_16t(&frag->dgram_size, dgram_size); + memcpy(&frag->hw_src_addr, &rx_pkt.hw_src_addr, + sizeof(frag->hw_src_addr)); + memcpy(&frag->hw_dst_addr, &rx_pkt.hw_dst_addr, + sizeof(frag->hw_dst_addr)); + frag->frag_timeout = FRAG_TIMEOUT; + frag->buf = (uint8_t *) call AppDataPool.get(); + frag->frag_list = NULL; + /* + printf("new frag_buf[%d] %d\n", i, + frag_bufs[i].frag_timeout); + printf("frag pool size: %d\n", call FragInfoPool.size()); + call PrintfFlush.flush(); + */ + goto frag_reassemble; + } + } + // no free slot for reassembling fragments +#ifdef ENABLE_PRINTF_DEBUG + printf("no free slot - discarding frag\n"); + call PrintfFlush.flush(); +#endif /* ENABLE_PRINTF_DEBUG */ + goto discard_packet; + } + + frag_overlap: + /* overlap - discard previous frags + * and restart fragment reassembly + */ + free_frag_list(frag->frag_list); + frag->frag_list = NULL; + frag->frag_timeout = FRAG_TIMEOUT; + goto frag_reassemble; + + frag_reassemble: + /* + printf("tag: 0x%04X, size: %d, off: %d, t: %d\n", + get_16t(&frag->dgram_tag), + ntohs(get_16t(&frag->dgram_size)), + dgram_offset, + frag->frag_timeout); + //printf("f_b[%d] %d\n", 0, frag_bufs[0].frag_timeout); + if (dgram_offset > 0) { + call PrintfFlush.flush(); + } + */ + /* copy buf data */ + //if (dgram_offset*8 + len <= sizeof(frag->buf)) { + if (dgram_offset*8 + len <= FRAG_BUF_SIZE) { + memcpy(frag->buf + (dgram_offset*8), buf, len); + } else { + call Leds.led0Toggle(); + } + + /* update frag_info */ + p = call FragInfoPool.get(); + if (!p) { + //out of memory - fragment reassembly failing + //TODO + call Leds.led0Toggle(); +#ifdef ENABLE_PRINTF_DEBUG + printf("FAILED to alloc frag_info_t\n"); + call PrintfFlush.flush(); +#endif /* ENABLE_PRINTF_DEBUG */ + } else { + p->offset = dgram_offset; + p->len = len; + + /* insert frag_info into the orderer list */ + if (frag->frag_list) { + for(q = &(frag->frag_list); (*q)->next; q=&((*q)->next)) { + if (p->offset > (*q)->offset) { + break; + } + } + p->next = *q; + *q = p; + } else { + p->next = frag->frag_list; + frag->frag_list = p; + } + } + +#ifdef ENABLE_PRINTF_DEBUG + if (dgram_offset > 20) { + printf("frag_list:\n"); + //ntohs(get_16t(&frag->dgram_tag)), + //ntohs(get_16t(&frag->dgram_size))); + for (p=frag->frag_list;p;p=p->next) { + printf("off: %d, len: %d\n", p->offset, p->len); + } + call PrintfFlush.flush(); + } +#endif /* ENABLE_PRINTF_DEBUG */ + + /* check if this is not the last fragment */ + if (!dgram_offset) { + /* the first fragment cannot be the last one */ + last_frag = 0; + } else { + last_frag=1; + dgram_offset = ntohs(dgram_size)/8; + for(p=frag->frag_list; p && dgram_offset; p=p->next) { + //debug("dgram_offset: %d, p->offset: %d, p->len: %d\n", + // dgram_offset, p->offset, p->len); + if (p->offset + p->len/8 != dgram_offset) { + //debug("offset mismatch - not the last fragment\n"); + last_frag = 0; + break; + } + dgram_offset = p->offset; + } + } + + if (last_frag) { + call Leds.led1Toggle(); + /* prepare the complete packet to be passed up*/ + lowpan_pkt_clear(&rx_pkt); + rx_pkt.app_data = frag->buf; + rx_pkt.app_data_dealloc = APP_DATA_DEALLOC_TRUE; + rx_pkt.header_begin = frag->buf; + rx_pkt.header_len = ntohs(dgram_size); + + //debug("dumping reassembled datagram...\n"); + //dump_serial_packet(pkt->buf_begin, pkt->len); + + /* pass up the packet */ + layer3_input(rx_pkt.header_begin, rx_pkt.header_len); + + /* deallocate all fragment info */ + free_frag_list(frag->frag_list); + frag->frag_list = NULL; + frag->frag_timeout = FRAG_FREE; + if (rx_pkt.app_data_dealloc == APP_DATA_DEALLOC_TRUE + && rx_pkt.app_data) { + /* deallocate the frag_buf */ + call AppDataPool.put((app_data_t *) rx_pkt.app_data); + } + } else { + /* packet not yet complete */ + return; + } + dispatch = buf; + } else { + /* no fragmentation */ + + /* pass up the complete packet */ + lowpan_pkt_clear(&rx_pkt); + rx_pkt.header_begin = buf; + rx_pkt.header_len = len; + layer3_input(buf, len); + } + + + discard_packet: + // deallocate pkt + // update stats +} + +/* Receive an AM from the lower layer */ +event message_t* Receive.receive(message_t* msg, void* payload, uint8_t len) +{ + am_addr_t am_addr; + + //call Leds.led0Toggle(); + + /* 802.15.4 source address */ + rx_pkt.hw_src_addr.type = HW_ADDR_SHORT; + am_addr = call AMPacket.source(msg); + memcpy(&rx_pkt.hw_src_addr.addr_short, &am_addr, sizeof(am_addr_t)); + + /* 802.15.4 destination address */ + rx_pkt.hw_dst_addr.type = HW_ADDR_SHORT; + am_addr = call AMPacket.destination(msg); + memcpy(&rx_pkt.hw_dst_addr.addr_short, &am_addr, sizeof(am_addr_t)); + + lowpan_input(payload, len); + return msg; +} + +/****************************************** + * Interface StdControl + ******************************************/ + +command error_t IPControl.start() +{ +#ifdef ENABLE_PRINTF_DEBUG + call PrintfControl.start(); +#endif /* ENABLE_PRINTF_DEBUG */ + ip_init(); + linklocal_addr.addr[0] = 0xfe; + linklocal_addr.addr[1] = 0x80; + ipv6_iface_id_from_am_addr(call AMPacket.address(), + &(linklocal_addr.addr[8])); + //set_16t((uint16_t *)&(linklocal_addr.addr[14]), am_addr); + call MessageControl.start(); + return SUCCESS; +} + +event void MessageControl.startDone(error_t err) { + if (err == SUCCESS) { + signal IPControl.startDone(err); + call Timer.startPeriodic(1024); /* fire every second */ + } + else { + call MessageControl.start(); + } +} + +command error_t IPControl.stop() +{ + call MessageControl.stop(); + call Timer.stop(); +#ifdef ENABLE_PRINTF_DEBUG + call PrintfControl.stop(); +#endif /* ENABLE_PRINTF_DEBUG */ + return SUCCESS; +} + +event void MessageControl.stopDone(error_t err) { + signal IPControl.stopDone(err); +} + +/****************************************** + * IP Interface + ******************************************/ +command void IP.getAddress(ip6_addr_t *addr) +{ + addr = &global_addr; + //uip_unpack_ipaddr( uip_global_addr, addr->addr ); +} + +command void IP.setAddress(const ip6_addr_t *addr) +{ + memcpy(&global_addr, addr, sizeof(*addr)); + //uip_pack_ipaddr(uip_global_addr,octet1,octet2,octet3,octet4); +} + +command void IP.setAddressAutoconf(const ip6_addr_t *addr) +{ + memcpy(&global_addr, addr, sizeof(*addr)); + ipv6_iface_id_from_am_addr(call AMPacket.address(), + &(global_addr.addr[8])); + //set_16t((uint16_t *)&(global_addr.addr[14]), am_addr); +} + +/***************************** + * UDP functions + *****************************/ +command error_t UDPClient.listen[uint8_t num](uint16_t port) +{ + if (port) { + memset(&udp_conns[num].ripaddr, 0, + sizeof(udp_conns[num].ripaddr)); + set_16t(&udp_conns[num].lport, htons(port)); + } else { + set_16t(&udp_conns[num].lport, 0); + } + return SUCCESS; +} + +command error_t +UDPClient.connect[uint8_t num](const ip6_addr_t *addr, const uint16_t port) +{ + struct udp_conn *conn = &udp_conns[num]; + + if (addr && port) { + memcpy(&conn->ripaddr, addr, sizeof(conn->ripaddr)); + set_16t(&conn->rport, htons(port)); + } + else { + memset(&conn->ripaddr, 0 , sizeof(conn->ripaddr)); + set_16t(&conn->rport, 0); + } + + return SUCCESS; +} + +command error_t +UDPClient.sendTo[uint8_t num](const ip6_addr_t *addr, uint16_t port, + const uint8_t *buf, uint16_t len) +{ + if (udp_conns[num].lport == 0) { + set_16t(&udp_conns[num].lport, htons(udp_assign_port())); + } + return udp_compressed_output(buf, len, + NULL, addr, + udp_conns[num].lport, htons(port), num+1); +} + +command error_t UDPClient.send[uint8_t num]( const uint8_t *buf, uint16_t len ) +{ + if (udp_conns[num].rport == 0 + || ipv6_addr_is_zero(&udp_conns[num].ripaddr)) + return FAIL; + return call UDPClient.sendTo[num](&(udp_conns[num].ripaddr), + udp_conns[num].rport, + buf, len); +} + +default event void +UDPClient.sendDone[uint8_t num](error_t result, void* buf) +{ +} + +default event void +UDPClient.receive[uint8_t num](const ip6_addr_t *addr, uint16_t port, + uint8_t *buf, uint16_t len) +{ +} + +/****************************************** + * Printf Timer + ******************************************/ +#ifdef ENABLE_PRINTF_DEBUG +event void PrintfFlush.flushDone(error_t error) {} +event void PrintfControl.startDone(error_t error) {} +event void PrintfControl.stopDone(error_t error) {} +static void dump_serial_packet(const unsigned char *packet, const int len) +{ + int i; + printf("len: %d\n", len); + //call PrintfFlush.flush(); + if (!packet) { + printf("packet is NULL"); + } else { + for (i = 0; i < len; i++) + printf("%02x ", packet[i]); + } + printf("\n"); + //call PrintfFlush.flush(); +} +#endif /* ENABLE_PRINTF_DEBUG */ +#ifndef ENABLE_PRINTF_DEBUG +static void dump_serial_packet(const unsigned char *packet, const int len) +{} +#endif /* ENABLE_PRINTF_DEBUG */ + +/****************************************** + * Interface Timer + ******************************************/ + +event void Timer.fired() { + int i=0; + + /* heartbeat led */ + //call Leds.led0Toggle(); + + /* discard timed-out and not yet assembled fragmented packet */ + for (i=0;i 0) { + frag_bufs[i].frag_timeout--; + } else { + /* fragment reassembly timed out */ + frag_bufs[i].frag_timeout = FRAG_FREE; + free_frag_list(frag_bufs[i].frag_list); + if (frag_bufs[i].buf) { + call AppDataPool.put((app_data_t *) frag_bufs[i].buf); + } + //call Leds.led0Toggle(); + } + } + } + + //TODO: check for timed-out ND request and resend/give up and mark as such + //TODO: check outgoing pkts queue and schedule ND or sending + /* + counter++; + if (locked) { + return; + } + else { + //Packet.clear(&test_packet); + uint8_t* data=(uint8_t*) call Packet.getPayload(&test_packet,NULL); + if (call Packet.maxPayloadLength() < 1) { + return; + } + + data[0] = counter; + call AMPacket.setSource(&test_packet, 0x14); + if (call AMSend.send(3, &test_packet, 1) == SUCCESS) { + // if (call AMSend.send(AM_BROADCAST_ADDR, &test_packet, sizeof(test_serial_msg_t)) == SUCCESS) { + locked = TRUE; + } + } + */ +} + +} diff --git a/tos/lib/net/6lowpan/IP_internal.h b/tos/lib/net/6lowpan/IP_internal.h new file mode 100644 index 00000000..d2015585 --- /dev/null +++ b/tos/lib/net/6lowpan/IP_internal.h @@ -0,0 +1,401 @@ +/* + * Copyright (c) 2007 Matus Harvan + * All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * 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 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 + * OWNER 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. + */ +/* + * The structures are based on the ones from FreeBSD header files + * in /usr/include/netinet6/, which are distributed unred the following + * copyright: + * + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * 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 project 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 PROJECT 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 PROJECT 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. + * + * Copyright (c) 1982, 1986, 1990, 1993 + * The Regents of the University of California. 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. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + */ + +/* + * Header file for the 6lowpan/IPv6 stack. + */ + +#ifndef __IP_INTERNAL_H__ +#define __IP_INTERNAL_H__ + +enum { + HW_ADDR_SHORT, + HW_ADDR_LONG +}; + +typedef struct hw_addr { + uint8_t type; // HW_ADDR_SHORT | HW_ADDR_LONG + union { + uint8_t addr_short[2]; + uint8_t addr_long[8]; + }; +} hw_addr_t; + +/* number of packets in SendPktPool */ +#define SEND_PKTS 1 + +/* number of fragment reassembly buffers */ +#define FRAG_BUFS 1 + +/* timeout for discarding a fragment reassembly buffer + * 60 seconds max in 6lowpan draft */ +#define FRAG_TIMEOUT 10 + +/* number of fragments per reassembled datagram */ +#define FRAGS_PER_DATAGRAM 15 + +/* fragment reassembmly buffer size */ +#define FRAG_BUF_SIZE 1280 + +/* default IPv6 Hop Limit for outgoing packets (except Neighbor Discovery) */ +#define IP_HOP_LIMIT 64 + +#define LOWPAN_MTU 1280 +#define LOWPAN_OVERHEAD 17 +// 16 bytes opt. headers and 1 byte dispatch +#define LINK_DATA_MTU 100 +// 802.15.4 space left after the 802.15.4 header: 128 - xx = 102 bytes max + + +/* size of app_data buffer */ +#define LOWPAN_APP_DATA_LEN FRAG_BUF_SIZE +/* maximum length of 6lowpan headers */ +//#define LOWPAN_HEADER_LEN 49 +#define LOWPAN_HEADER_LEN 102 + +/* flag marking an unused fragment reassembly buffer/structure */ +#define FRAG_FREE 0xFF + +/* 6lowpan dispatch values */ +#define DISPATCH_UNCOMPRESSED_IPV6 0x41 +#define DISPATCH_COMPRESSED_IPV6 0x42 + +#define DISPATCH_FIRST_FRAG 0xC0 +#define DISPATCH_SUBSEQ_FRAG 0xE0 +#define DISPATCH_FRAG_MASK 0xF8 + +#define DISPATCH_BC0 0x50 + +#define DISPATCH_MESH 0x80 +#define DISPATCH_MESH_MASK 0xC0 +#define DISPATCH_MESH_O_FLAG 0x20 +#define DISPATCH_MESH_F_FLAG 0x10 +#define DISPATCH_MESH_HOPSLEFT_MASK 0x0F + +enum { + /* lowpan_pkt_t.app_data_dealloc */ + APP_DATA_DEALLOC_FALSE=0, + APP_DATA_DEALLOC_TRUE=1, + + /* lowpan_pkt_t.notify_num */ + LOWPAN_PKT_NO_NOTIFY = 0, + + /* HC1 encoding */ + HC1_SRC_PREFIX_MASK = 0x80, + HC1_SRC_PREFIX_LINKLOCAL = 0x80, + HC1_SRC_PREFIX_INLINE = 0, + HC1_SRC_IFACEID_MASK = 0x40, + HC1_SRC_IFACEID_COMRP = 0x40, + HC1_SRC_IFACEID_INLINE = 0, + + HC1_DST_PREFIX_MASK = 0x20, + HC1_DST_PREFIX_LINKLOCAL = 0x20, + HC1_DST_PREFIX_INLINE = 0, + HC1_DST_IFACEID_MASK = 0x10, + HC1_DST_IFACEID_COMRP = 0x10, + HC1_DST_IFACEID_INLINE = 0, + + HC1_TCFL_MASK = 0x08, + HC1_TCFL_ZERO = 0x08, + HC1_TCFL_INLINE = 0, + + HC1_NEXTHDR_MASK = 0x06, + HC1_NEXTHDR_INLINE = 0, + HC1_NEXTHDR_UDP = 0x02, + HC1_NEXTHDR_ICMP = 0x04, + HC1_NEXTHDR_TCP = 0x06, + + HC1_HC2_MASK = 0x01, + HC1_HC2_PRESENT = 0x01, + HC1_HC2_NONE = 0, + + HC2_UDP_P_VALUE = 0x61616, + + HC2_UDP_SRC_PORT_MASK = 0x80, + HC2_UDP_SRC_PORT_COMPR = 0x80, + HC2_UDP_SRC_PORT_INLINE = 0, + + HC2_UDP_DST_PORT_MASK = 0x40, + HC2_UDP_DST_PORT_COMPR = 0x40, + HC2_UDP_DST_PORT_INLINE = 0, + + HC2_UDP_LEN_MASK = 0x20, + HC2_UDP_LEN_COMPR = 0x20, + HC2_UDP_LEN_INLINE = 0 +}; + +/* used for fragment reassembly */ +typedef struct _frag_info_t { + uint8_t offset; + uint8_t len; + struct _frag_info_t *next; +} frag_info_t; + +/* used for fragment reassembly */ +typedef struct _app_data_t { + uint8_t buf[LOWPAN_MTU]; +} app_data_t; + +/* used for fragment reassembly */ +typedef struct _frag_buf_t { + uint8_t *buf; /* usually a pointer to app_data_t */ + hw_addr_t hw_src_addr; + hw_addr_t hw_dst_addr; + uint16_t dgram_tag; /* network byte order */ + uint16_t dgram_size; /* host byte order */ + uint8_t frag_timeout; /* discarded when zero is reached + * FRAG_FREE means not used at the moment */ + + frag_info_t *frag_list; /* sorted by offset in decreasing order */ +} frag_buf_t; + +/* + * sending - application provides app_data and clears app_data_dealloc + * - a pointer to app_data is returned in sendDone to do deallocation + * receiving with fragment reassembly + * - IPP provides app_data and sets app_data_dealloc + * - header_begin is set to point into app_data + * and the received packet is put into app_data + * receiving without fragment reassembly + * - the complete 802.15.4 frame is put into header + * (802.15.4 header is left out) and heade_begin points into header + */ +typedef struct _lowpan_pkt_t { + /* buffers */ + uint8_t *app_data; /* buffer for application data */ + uint16_t app_data_len; /* how much data is in the buffer */ + uint8_t *app_data_begin; /* start of the data in the buffer */ + uint8_t app_data_dealloc; /* shall IPC deallocate the app_data buffer? + /* APP_DATA_DEALLOC_FALSE | APP_DATA_DEALLOC_TRUE */ + + uint8_t header[LINK_DATA_MTU]; /* buffer for the header (tx) + * or unfragmented 802.15.4 frame (rx) */ + uint16_t header_len; /* how much data is in the buffer */ + uint8_t *header_begin; /* start of the data in the buffer */ + + /* fragmentation */ + uint16_t dgram_tag; /* network byte order */ + uint16_t dgram_size; /* host byte order */ + uint8_t dgram_offset; /* offset where next fragment starts (tx) + * (in multiples of 8 bytes) */ + /* IP addresses */ + ip6_addr_t ip_src_addr; /* needed for ND and usefull elsewhere */ + ip6_addr_t ip_dst_addr; /* both IP addresses filled in by ipv6*_input */ + /* 802.15.4 addresses */ + hw_addr_t hw_src_addr; + hw_addr_t hw_dst_addr; /* 802.15.4 MAC addresses + * needed for fragment identification + * needed for 6lowpan IPv6 header decompression + * contains mesh header entries if applicable + */ + /* to notify app with sendDone */ + uint8_t notify_num; /* num of UDPClient + 1, 0 means o not notify */ + + struct _lowpan_pkt_t *next; +} lowpan_pkt_t; + +enum { + FRAG_NONE = 0, + FRAG_6LOWPAN = 1, + FRAG_IPV6 = 2, + + ND_DONE = 0, + ND_TODO = 1, + ND_SENT = 2, + }; + +struct lowpan_mesh_hdr { + uint8_t dispatch; // dispatch and flags + // address length depends on flags in dispatch +}; + +struct lowpan_broadcast_hdr { + uint8_t dispatch; + uint8_t seq_no; // sequence number +}; + +struct lowpan_frag_hdr { + union { + uint8_t dispatch; + uint16_t dgram_size; + uint8_t dgram_size8[2]; + }; + uint16_t dgram_tag; +}; + +/* + * Definition for internet protocol version 6. + * RFC 2460 + */ + +struct ip6_hdr { + union { + uint8_t vtc; /* 4 bits version, 8 bits class label*/ + uint32_t flow; /* 20 bits flow label at the end */ + }; + uint16_t plen; /* payload length */ + uint8_t nxt_hdr; /* next header */ + uint8_t hlim; /* hop limit */ + ip6_addr_t src_addr; /* source address */ + ip6_addr_t dst_addr; /* destination address */ +} /* __attribute__((packed))*/; + +#define IPV6_VERSION 0x60 +#define IPV6_VERSION_MASK 0xf0 + +/* + * Extension Headers + */ + +struct ip6_ext { + uint8_t ip6e_nxt; + uint8_t ip6e_len; +}; + + +struct icmp6_hdr { + uint8_t type; /* type field */ + uint8_t code; /* code field */ + uint16_t cksum; /* checksum field */ +}; + +enum { + ICMP_TYPE_ECHO_DEST_UNREACH = 1, + ICMP_TYPE_ECHO_PKT_TOO_BIG = 129, + ICMP_TYPE_ECHO_TIME_EXCEEDED = 129, + ICMP_TYPE_ECHO_PARAM_PROBLEM = 129, + ICMP_TYPE_ECHO_REQUEST = 128, + ICMP_TYPE_ECHO_REPLY = 129, + ICMP_TYPE_NEIGHBOR_SOL = 135, + ICMP_TYPE_NEIGHBOR_ADV = 136, + ICMP_NEIGHBOR_HOPLIMIT = 255 +}; + +/* + * Udp protocol header. + * Per RFC 768, September, 1981. + */ +struct udp_hdr { + uint16_t srcport; /* source port */ + uint16_t dstport; /* destination port */ + uint16_t len; /* udp length */ + uint16_t chksum; /* udp checksum */ +}; + +enum { + //NEXT_HEADER_ICMP = 1, + NEXT_HEADER_TCP = 6, + NEXT_HEADER_UDP = 17, + NEXT_HEADER_ICMP6 = 58 +}; + + +struct udp_conn { + ip6_addr_t ripaddr; /* IP address of the remote peer. */ + uint16_t lport; /* local port number (network byte order) */ + uint16_t rport; /* remote port number (network byte order) */ +}; + + +/* // from uip-1.0/uip/uip-neighbor.c */ +/* #define NEIGHBOR_MAX_TIME 128 */ + +/* #ifndef NEIGHBOR_ENTRIES */ +/* #define NEIGHBOR_ENTRIES 8 */ +/* #endif */ + +/* struct neighbor_entry { */ +/* ip6_addr_t ip_addr; */ +/* struct hw_addr hw_addr; */ +/* uint8_t time; */ +/* }; */ +/* struct neighbor_entry neighbor_entries[NEIGHBOR_ENTRIES]; */ + +#endif /* __IP_INTERNAL_H__ */ diff --git a/tos/lib/net/6lowpan/README b/tos/lib/net/6lowpan/README new file mode 100644 index 00000000..4933f0ed --- /dev/null +++ b/tos/lib/net/6lowpan/README @@ -0,0 +1,72 @@ + A 6lowpan implementation for TinyOS 2.x + +This is a 6lowpan implementation for TinyOS 2.x. Mesh Addressing and +Broadcast headers are parsed, but no mesh-networking/multi-hopping is +implemented. 6lowpan fragmentation and fragment reassembly is fully +supported. The 6lowpan-specified HC1 compression of the IPv6 header +and the HC_UDP compression of the UDP header are supported as well as +handling of the uncompressed headers. The implementation can respond +to ICMP echo requests and handles communication over the UDP +protocol. It has been tested on the TelosB and MicaZ hardware +platforms. In addition a 6lowpan-translating daemon has been +implemented to allow a linux PC to use a mote as an 802.15.4 +interface. + +Shortcomings and missing features: + * 6lowpan payload is sent as Active Message payload. This means that + the 802.15.4 payload is prefixed with the 1-byte AM Type field. + * non-zero Traffic Class and Flow Label are not supported by the + current HC1 implementation + * UDP port numbers compression is not supported and port numbers are + always sent in full by the current HC_UDP compression + * Neighbor Discovery has not been implemented and link local + broadcasts are used instead. + * Not all fragments of a datagram seem to be always received by the + mote. A workaround is to add a usleep(10000) before sending subsequent + fragments in the serial_tun daemon on the PC. + +More details can be found in + http://www.inf.ethz.ch/personal/mharvan/docs/msc-thesis.pdf +or by reading the source code. + + +USAGE - MOTE +The 6lowpan/IPv6 stack is implemented in the IPP module. Applications +should use the IPC component which takes care of wiring the necessary +components. The stack offers the UDPClient interface to application +wishing to exchange UDP datagrams. Replying to ICMP echo requests is +done by the 6lowpan stack. + +The stack support two IPv6 addresses: + * a global address + * a link-local address + +The link-local address is assigned using an interface identifier +computed from the Active Message address of the mote. This is almost +like the stateless autoconfiguration, but Duplicate Address Detection +or Router Solicitations are not implemented. + +The global address can be set manually with +IPC.setAddress(). Alternatively, only the prefix of the global address +can be set with IPC.setAddressAutoconf() and the suffix will be +generated from the Active Message address of the mote. + +A sample application using the 6lowpan stack is in apps/6lowpancli. + +USAGE - PC +To interact with a 6lowpan mote from a PC, a mote flashed with the +BaseStation application (apps/BaseStation) has to be attached to the +PC. Note that the application has to be built with + CFLAGS += -D'TOSH_DATA_LENGTH=102'. + +Furthermore, the serial_tun daemon (support/sdk/c/6lowpan/serial_tun/) +has to run on the PC. + +Afterwards, ping6 and nc6 should work for talking to the motes. + +Debugging output with printf over USB can be enabled with + CFLAGS="-D'ENABLE_PRINTF_DEBUG=1' + +To minimize memory usage, i.e. disable everything (at the moment only +the UDP cli) to determine minimum RAM/ROM requirements, use + CFLAGS="-D'MINIMIZE_MEMORY=1' \ No newline at end of file diff --git a/tos/lib/net/6lowpan/UDPClient.nc b/tos/lib/net/6lowpan/UDPClient.nc new file mode 100644 index 00000000..d2b727fc --- /dev/null +++ b/tos/lib/net/6lowpan/UDPClient.nc @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2007 Matus Harvan + * All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * 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 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 + * OWNER 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 based on Andrew Christian's UDPClient interface from + * the uIP port to TinyOS 1.x, which is distributed under the + * following licence: + * + * Copyright (c) 2005 Hewlett-Packard Company + * All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of the Hewlett-Packard Company 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 + * OWNER 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. + */ + +/* + * Parameterized interface for creating a UDP client or server + */ + +#include "IP.h" + +interface UDPClient { + /** + * 'Listening' to a socket binds the local port to a fixed number and allows + * the socket to receive packets. If you call send or sendto on an unbound + * socket, a dynamic local port is assigned. Pass 0 to unbind the port. + */ + + command error_t listen( uint16_t port ); // Start listening to a port + + /** + * 'Connecting' a UDP socket fixes the remote address and port. Once fixed, + * you can send datagrams with the 'send' command. You can un-fix the socket + * by passing NULL as the argument. + */ + + command error_t connect(const ip6_addr_t *addr, const uint16_t port); + + /** + * Send a datagram to a remote host. Call 'connect' on a socket before + * calling 'send'. If a local port has not yet been assigned, a dynamic + * one will be assigned by these commands. Both commands are asynchronous + * and will generate the 'sendDone' event once the datagram has been sent. + */ + + command error_t sendTo(const ip6_addr_t *addr, uint16_t port, + const uint8_t *buf, uint16_t len ); + command error_t send(const uint8_t *buf, uint16_t len ); + + /** + * The previous send or sendTo command has completed. + */ + + event void sendDone(error_t result, void* buf); + + /** + * A datagram has been received. Datagrams are only received on sockets + * that have had 'listen' called to assign a local port, or have used + * the 'send' or 'sendTo' command. + */ + + event void receive(const ip6_addr_t *addr, uint16_t port, + uint8_t *buf, uint16_t len ); +} -- 2.39.2