]> oss.titaniummirror.com Git - tinyos-2.x.git/commitdiff
6lowpan import
authormharvan <mharvan>
Wed, 5 Dec 2007 22:58:41 +0000 (22:58 +0000)
committermharvan <mharvan>
Wed, 5 Dec 2007 22:58:41 +0000 (22:58 +0000)
17 files changed:
apps/6lowpancli/CliAppC.nc [new file with mode: 0644]
apps/6lowpancli/CliC.nc [new file with mode: 0644]
apps/6lowpancli/Makefile [new file with mode: 0644]
apps/6lowpancli/README [new file with mode: 0644]
support/sdk/c/6lowpan/serial_tun/6lowpan.h [new file with mode: 0644]
support/sdk/c/6lowpan/serial_tun/Makefile [new file with mode: 0644]
support/sdk/c/6lowpan/serial_tun/README [new file with mode: 0644]
support/sdk/c/6lowpan/serial_tun/serial_tun.c [new file with mode: 0644]
support/sdk/c/6lowpan/serial_tun/tun_dev.c [new file with mode: 0644]
support/sdk/c/6lowpan/serial_tun/tun_dev.h [new file with mode: 0644]
tos/lib/net/6lowpan/IP.h [new file with mode: 0644]
tos/lib/net/6lowpan/IP.nc [new file with mode: 0644]
tos/lib/net/6lowpan/IPC.nc [new file with mode: 0644]
tos/lib/net/6lowpan/IPP.nc [new file with mode: 0644]
tos/lib/net/6lowpan/IP_internal.h [new file with mode: 0644]
tos/lib/net/6lowpan/README [new file with mode: 0644]
tos/lib/net/6lowpan/UDPClient.nc [new file with mode: 0644]

diff --git a/apps/6lowpancli/CliAppC.nc b/apps/6lowpancli/CliAppC.nc
new file mode 100644 (file)
index 0000000..5c6fd64
--- /dev/null
@@ -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 (file)
index 0000000..89225cd
--- /dev/null
@@ -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<uint16_t> as TempSensorC;
+#endif /* ENABLE_TEMP_SENSOR */
+#ifdef ENABLE_LIGHT_SENSOR
+    interface Read<uint16_t> 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 (file)
index 0000000..a4c380e
--- /dev/null
@@ -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 (file)
index 0000000..0ccacf1
--- /dev/null
@@ -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 (file)
index 0000000..64bb5e8
--- /dev/null
@@ -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 <sys/types.h>
+
+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 (file)
index 0000000..3716156
--- /dev/null
@@ -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 (file)
index 0000000..0f09e4c
--- /dev/null
@@ -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 (file)
index 0000000..798ff55
--- /dev/null
@@ -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 <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include <stdarg.h>
+
+#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 <device> <rate>\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 (file)
index 0000000..e5d92bb
--- /dev/null
@@ -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 <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <syslog.h>
+#include <errno.h>
+
+#include <arpa/inet.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <linux/if.h>
+#include <linux/if_tun.h>
+#include <linux/if_ether.h>
+
+#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 (file)
index 0000000..0de31de
--- /dev/null
@@ -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 (file)
index 0000000..0adbf49
--- /dev/null
@@ -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 (file)
index 0000000..6542703
--- /dev/null
@@ -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 (file)
index 0000000..7f2be6c
--- /dev/null
@@ -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 (file)
index 0000000..61a8fc7
--- /dev/null
@@ -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<TMilli> as Timer;
+       interface Pool<lowpan_pkt_t> as SendPktPool;
+       interface Pool<app_data_t> as AppDataPool;
+       interface Pool<frag_info_t> 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<FAG_BUFS,i++) {
+           frag_buf_clear(frag_bufs[i]);
+       }
+       */
+    }
+
+    uint16_t udp_assign_port()
+    {
+       int c;
+       
+       /* Find an unused local port. */
+    again:
+       ++lastport;
+       
+       if (lastport >= 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<FRAG_BUFS; i++) {
+       if (frag_bufs[i].frag_timeout != FRAG_FREE) {
+           if (frag_bufs[i].frag_timeout > 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 (file)
index 0000000..d201558
--- /dev/null
@@ -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 (file)
index 0000000..4933f0e
--- /dev/null
@@ -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 (file)
index 0000000..d2b727f
--- /dev/null
@@ -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 );
+}