--- /dev/null
+/*
+ * 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 */
+}
+
+
+
--- /dev/null
+/*
+ * 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 */
+}
--- /dev/null
+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)
--- /dev/null
+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
+
--- /dev/null
+/*
+ * 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__ */
--- /dev/null
+#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
--- /dev/null
+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.
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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__
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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 */
+}
+
--- /dev/null
+/*
+ * 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;
+ }
+ }
+ */
+}
+
+}
--- /dev/null
+/*
+ * 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__ */
--- /dev/null
+ 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
--- /dev/null
+/*
+ * 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 );
+}