]> oss.titaniummirror.com Git - tinyos-2.x.git/commitdiff
commit svn HEAD of blip into core to start merge testing
authorsdhsdh <sdhsdh>
Sun, 9 Aug 2009 23:36:05 +0000 (23:36 +0000)
committersdhsdh <sdhsdh>
Sun, 9 Aug 2009 23:36:05 +0000 (23:36 +0000)
97 files changed:
apps/IPBaseStation/BaseStationC.nc
apps/IPBaseStation/BaseStationP.nc
apps/IPBaseStation/Makefile
apps/TCPEcho/HttpdP.nc [new file with mode: 0644]
apps/TCPEcho/Makefile [new file with mode: 0644]
apps/TCPEcho/TCPEchoC.nc [new file with mode: 0644]
apps/TCPEcho/TCPEchoP.nc [new file with mode: 0644]
apps/TCPEcho/UDPReport.h [new file with mode: 0644]
apps/UDPEcho/Makefile
apps/UDPEcho/Makefile.local
apps/UDPEcho/UDPEchoC.nc
apps/UDPEcho/UDPEchoP.nc
apps/UDPEcho/UDPReport.h
apps/UDPEcho/util/MySQLListener.py
apps/UDPEcho/util/UdpReport.py
support/make/blip.extra [new file with mode: 0644]
support/sdk/c/blip/Makefile
support/sdk/c/blip/driver/Makefile
support/sdk/c/blip/driver/config.c
support/sdk/c/blip/driver/config.h
support/sdk/c/blip/driver/hashtable.c
support/sdk/c/blip/driver/logging.c
support/sdk/c/blip/driver/logging.h
support/sdk/c/blip/driver/mcast.c [new file with mode: 0644]
support/sdk/c/blip/driver/mcast.h [new file with mode: 0644]
support/sdk/c/blip/driver/netlink.c [new file with mode: 0644]
support/sdk/c/blip/driver/netlink.h [new file with mode: 0644]
support/sdk/c/blip/driver/nwstate.c
support/sdk/c/blip/driver/nwstate.h
support/sdk/c/blip/driver/radvd-1.0/config.h
support/sdk/c/blip/driver/radvd-1.0/process.c
support/sdk/c/blip/driver/radvd-wrapper.c
support/sdk/c/blip/driver/routing.c
support/sdk/c/blip/driver/routing.h
support/sdk/c/blip/driver/serial_tun.c
support/sdk/c/blip/driver/tun_dev.c
support/sdk/c/blip/driver/vty/Makefile [new file with mode: 0644]
support/sdk/c/blip/driver/vty/test_srv.c [new file with mode: 0644]
support/sdk/c/blip/driver/vty/util.c [new file with mode: 0644]
support/sdk/c/blip/driver/vty/vty.c [new file with mode: 0644]
support/sdk/c/blip/driver/vty/vty.h [new file with mode: 0644]
support/sdk/c/blip/include/6lowpan.h
support/sdk/c/blip/include/TrackFlows.h [new file with mode: 0644]
support/sdk/c/blip/include/devconf.h
support/sdk/c/blip/include/ip.h
support/sdk/c/blip/include/ip_malloc.h
support/sdk/c/blip/include/lib6lowpan.h
support/sdk/c/blip/lib6lowpan/Makefile
support/sdk/c/blip/lib6lowpan/ip_malloc.c
support/sdk/c/blip/lib6lowpan/lib6lowpan.c
support/sdk/c/blip/lib6lowpan/lib6lowpanIP.c
support/sdk/c/blip/libtcp/Makefile
support/sdk/c/blip/libtcp/circ.c
support/sdk/c/blip/libtcp/circ.h
support/sdk/c/blip/libtcp/tcplib.c
support/sdk/c/blip/libtcp/tcplib.h
support/sdk/c/blip/libtcp/test_circ.c
support/sdk/c/blip/libtcp/test_server.c
support/sdk/c/blip/serial_tun.conf
tools/tinyos/misc/tos-nwprog [new file with mode: 0755]
tos/lib/net/blip/ICMP.h
tos/lib/net/blip/ICMPResponderP.nc
tos/lib/net/blip/IPAddressP.nc
tos/lib/net/blip/IPDispatch.h
tos/lib/net/blip/IPDispatchC.nc
tos/lib/net/blip/IPDispatchP.nc
tos/lib/net/blip/IPExtensionP.nc [new file with mode: 0644]
tos/lib/net/blip/IPExtensionsP.nc [new file with mode: 0644]
tos/lib/net/blip/IPRoutingP.nc
tos/lib/net/blip/Statistics.h [new file with mode: 0644]
tos/lib/net/blip/TcpP.nc
tos/lib/net/blip/TrackFlowsC.nc [new file with mode: 0644]
tos/lib/net/blip/TrackFlowsP.nc [new file with mode: 0644]
tos/lib/net/blip/UdpC.nc
tos/lib/net/blip/UdpP.nc
tos/lib/net/blip/doc/README [new file with mode: 0644]
tos/lib/net/blip/doc/README-IP [new file with mode: 0644]
tos/lib/net/blip/doc/README-MERAKI [new file with mode: 0644]
tos/lib/net/blip/doc/README-NWPROG [new file with mode: 0644]
tos/lib/net/blip/doc/README-SHELL [new file with mode: 0644]
tos/lib/net/blip/doc/README-SIM [new file with mode: 0644]
tos/lib/net/blip/doc/README-TCP [new file with mode: 0644]
tos/lib/net/blip/doc/README-UDP [new file with mode: 0644]
tos/lib/net/blip/interfaces/IP.nc
tos/lib/net/blip/interfaces/IPAddress.nc
tos/lib/net/blip/interfaces/IPExtensions.nc [new file with mode: 0644]
tos/lib/net/blip/interfaces/IPRouting.nc
tos/lib/net/blip/interfaces/InternalIPExtension.nc [new file with mode: 0644]
tos/lib/net/blip/interfaces/TLVHeader.nc [new file with mode: 0644]
tos/lib/net/blip/interfaces/Tcp.nc
tos/lib/net/blip/nwprog/Deluge.h
tos/lib/net/blip/nwprog/NWProgC.nc
tos/lib/net/blip/nwprog/NWProgP.nc
tos/lib/net/blip/shell/Shell.h
tos/lib/net/blip/shell/UDPShellP.nc
tos/lib/net/blip/table.c
tos/lib/net/blip/table.h

index 6114950d8c65d4d4e723f1abd0596f0fc592f9a7..aa36022ef6eeec6d9ea6fdad5ae693090665e5ae 100644 (file)
@@ -89,40 +89,22 @@ configuration BaseStationC {
 }
 implementation {
   components MainC, BaseStationP, LedsC;
-#ifndef SIM
-  components CC2420ActiveMessageC as Radio;
+  components Ieee154MessageC as Radio;
   components SerialDispatcherC as SerialControl, Serial802_15_4C as Serial;
-#else 
-  components ActiveMessageC as Radio;
-  components SerialActiveMessageC as Serial;
-#endif
   
   MainC.Boot <- BaseStationP;
 
   BaseStationP.RadioControl -> Radio;
-#ifndef SIM
   BaseStationP.SerialControl -> SerialControl;
   BaseStationP.UartSend -> Serial.Send;
   BaseStationP.UartReceive -> Serial.Receive;
-#else
-  BaseStationP.SerialControl -> Serial;
-  BaseStationP.UartSend -> Serial.AMSend[0];
-  BaseStationP.UartReceive -> Serial.Receive[0];
-#endif
   
 
-#ifndef SIM  
   BaseStationP.RadioSend -> Radio;
-  BaseStationP.RadioReceive -> Radio.IEEE154Receive;
-#else
-  BaseStationP.RadioSend -> Radio.AMSend[0];
-  BaseStationP.RadioReceive -> Radio.ReceiveBase[0];
-  BaseStationP.SerialAMPacket -> Serial;
-  BaseStationP.SerialPacket -> Serial;
-#endif
+  BaseStationP.RadioReceive -> Radio.Ieee154Receive;
 
-  BaseStationP.RadioPacket -> Radio.SubAMPacket;
-  BaseStationP.RadioIEEEPacket -> Radio;
+  BaseStationP.RadioPacket -> Radio.Packet;
+  BaseStationP.RadioIeeePacket -> Radio;
   
   BaseStationP.Leds -> LedsC;
 
@@ -132,7 +114,6 @@ implementation {
   components ResetC;
   BaseStationP.Reset -> ResetC;
 
-#ifndef SIM
   components SerialDevConfC as Configure;
   BaseStationP.ConfigureSend -> Configure;
   BaseStationP.ConfigureReceive -> Configure;
@@ -145,5 +126,4 @@ implementation {
 
   components CC2420ControlC;
   BaseStationP.CC2420Config -> CC2420ControlC;
-#endif
 }
index dc880a7d3c9e6c0c4a0a7da40926b0884c5a7b33..20008a991e63eecd55d880b16d0cd7a0580d8db1 100644 (file)
@@ -78,33 +78,20 @@ module BaseStationP {
     interface SplitControl as SerialControl;
     interface SplitControl as RadioControl;
 
-#ifndef SIM
     interface Send as UartSend;
-    interface IEEE154Send as RadioSend;
-#else
-    interface AMSend as UartSend;
-    interface AMSend as RadioSend;
-    interface AMPacket as SerialAMPacket;
-    interface Packet as SerialPacket;
-#endif
+    interface Ieee154Send as RadioSend;
 
     interface Receive as UartReceive;
     interface Receive as RadioReceive;
     interface Packet as RadioPacket;
 
-#ifndef SIM
     interface Send as ConfigureSend;
     interface Receive as ConfigureReceive;
     interface Timer<TMilli> as ConfigureTimer;
     interface IPAddress;
-#endif
 
 
-#ifndef SIM
-    interface IEEE154Packet as RadioIEEEPacket;
-#else
-    interface AMPacket as RadioIEEEPacket;
-#endif
+    interface Ieee154Packet as RadioIeeePacket;
 
     interface PacketLink;
     interface LowPowerListening;
@@ -123,7 +110,7 @@ implementation
     RADIO_QUEUE_LEN = 10,
   };
 
-  uint16_t radioRetries = 10;
+  uint16_t radioRetries = BLIP_L2_RETRIES;
   uint16_t radioDelay   = 30;
 
   uint16_t serial_read;
@@ -173,7 +160,7 @@ implementation
     echo_busy = TRUE;
     // delay sending the reply for a bit
     // the pc seems to usually drop the packet if we don't do this; 
-    call ConfigureTimer.startOneShot(50);
+    call ConfigureTimer.startOneShot(100);
   }
 
   event void Boot.booted() {
@@ -210,7 +197,8 @@ implementation
     if (error == SUCCESS) {
       radioFull = FALSE;
 #ifdef LPL_SLEEP_INTERVAL
-      call LowPowerListening.setLocalSleepInterval(LPL_SLEEP_INTERVAL);
+      // SDH : can actually leave the base on full time in most cases.
+      // call LowPowerListening.setLocalSleepInterval(LPL_SLEEP_INTERVAL);
 #endif
     }
   }
@@ -281,20 +269,11 @@ implementation
 
     // Since we're forwarding fully formed radio packets, we can use
     // these headers.
-#ifdef DBG_TRACK_FLOWS
-    len = call RadioPacket.payloadLength(msg) + sizeof(flow_id_t);
-#else
-    len = call RadioPacket.payloadLength(msg) - sizeof(am_header_t);
-#endif
+    len = call RadioPacket.payloadLength(msg);
 
-#ifdef SIM
-    if (call UartSend.send(call RadioIEEEPacket.source(uartQueue[uartOut]),
-                           uartQueue[uartOut], len) == SUCCESS)
-#else
-    if (call UartSend.send(uartQueue[uartOut], len) == SUCCESS)
-#endif
+    if (call UartSend.send(uartQueue[uartOut], len) == SUCCESS) {
       call Leds.led1Toggle();
-    else
+    }    else
       {
        failBlink();
        post uartSendTask();
@@ -314,6 +293,7 @@ implementation
              uartFull = FALSE;
          }
     post uartSendTask();
+
   }
 
   event message_t *UartReceive.receive(message_t *msg,
@@ -323,6 +303,9 @@ implementation
     bool reflectToken = FALSE;
     CHECK_NODE_ID msg;
     dbg("base", "uartreceive len %i of 0x%x\n", len, call SerialAMPacket.destination(msg));
+#if defined(PLATFORM_TELOS) || defined(PLATFORM_TELOSB) || defined(PLATFORM_EPIC)
+    WDTCTL = WDT_ARST_1000;
+#endif
 
     atomic
       if (!radioFull)
@@ -354,7 +337,7 @@ implementation
 
   task void radioSendTask() {
     uint8_t len;
-    hw_addr_t addr;
+    ieee154_saddr_t addr;
     message_t* msg;
     
     dbg ("base", "radioSendTask()\n");
@@ -366,24 +349,8 @@ implementation
        }
 
     msg = radioQueue[radioOut];
-#ifndef SIM
     len = call RadioPacket.payloadLength(msg);
-    addr = call RadioIEEEPacket.destination(msg);
-#else
-#ifdef DBG_TRACK_FLOWS
-    len = call SerialPacket.payloadLength(msg) - sizeof(flow_id_t);
-#else
-    len = call SerialPacket.payloadLength(msg);
-#endif
-    { 
-      hw_addr_t source;
-      addr = call SerialAMPacket.destination(msg);
-      source = TOS_NODE_ID;
-
-      call RadioPacket.clear(msg);
-      call RadioIEEEPacket.setSource(msg, source);
-    }
-#endif
+    addr = call RadioIeeePacket.destination(msg);
 
     if (addr != 0xFFFF) {
       call PacketLink.setRetries(msg, radioRetries);
@@ -431,6 +398,10 @@ implementation
                                             uint8_t len) {
     config_cmd_t *cmd;
     uint8_t error = CONFIG_ERROR_OK;
+#if defined(PLATFORM_TELOS) || defined(PLATFORM_TELOSB) || defined(PLATFORM_EPIC)
+    WDTCTL = WDT_ARST_1000;
+#endif
+
     if (len != sizeof(config_cmd_t) || msg == NULL) return msg;
     // don't parse the message if we can't reply
 
@@ -450,6 +421,8 @@ implementation
     case CONFIG_REBOOT:
       call Reset.reset();
       break;
+    case CONFIG_KEEPALIVE:
+      return msg;
     }
     if (!echo_busy) {
       reply->error = error;
index 5a8dde88b0516b43c02bcfd2a715b12b6c384238..f2135530796f4699104a58db002395d5a73c7d31 100644 (file)
@@ -5,8 +5,14 @@ COMPONENT=BaseStationC
 
 # this is necessary, otherwise we will allocate a heap by including
 # the lowpan target
-CFLAGS += -DNO_IP_MALLOC
-
+CFLAGS += -DNO_IP_MALLOC 
+
+# this aligns the 802.15.4 payload on the data field of a message_t.
+# very convenient for forwarding, and means we don't have to do a
+# memmove.  This doesn't mean that motes running blip also need this--
+# they can use IFRAMES or IEEE154FRAMES
+CFLAGS += -DIEEE154FRAMES_ENABLED
+CFLAGS += -DTOSH_DATA_LENGTH=104
 #
 # debugging
 #
@@ -20,5 +26,11 @@ CFLAGS += -DNO_IP_MALLOC
 # for simulation
 # CFLAGS += -DBASESTATION_ID=100
 
+# defs for snooping-- handy for debugging LPL, etc.
+# CFLAGS += -DCC2420_NO_UNIQUE
+# CFLAGS += -DCC2420_DEF_CHANNEL=15
+# CFLAGS += -DCC2420_NO_ACKNOWLEDGEMENTS
+# CFLAGS += -DCC2420_NO_ADDRESS_RECOGNITION
+
 include $(MAKERULES)
 
diff --git a/apps/TCPEcho/HttpdP.nc b/apps/TCPEcho/HttpdP.nc
new file mode 100644 (file)
index 0000000..26b1046
--- /dev/null
@@ -0,0 +1,152 @@
+
+module HttpdP {
+  uses {
+    interface Leds;
+    interface Boot;
+    interface Tcp;
+  }
+} implementation {
+
+  static char *http_okay = "HTTP/1.0 200 OK\r\n\r\n";
+  static int http_okay_len = 19;
+
+  enum {
+    S_IDLE,
+    S_CONNECTED,
+    S_REQUEST_PRE,
+    S_REQUEST,
+    S_HEADER,
+    S_BODY,
+  };
+
+  enum {
+    HTTP_GET,
+    HTTP_POST,
+  };
+
+  void process_request(int verb, char *request, int len) {
+    char reply[24];
+    memcpy(reply, "led0: 0 led1: 0 led2: 0\n", 24);
+
+    printfUART("request: '%s'\n", request);
+
+    if (len >= 10 &&
+        request[0] == '/' &&
+        request[1] == 'r' &&
+        request[2] == 'e' &&
+        request[3] == 'a' &&
+        request[4] == 'd' &&
+        request[5] == '/') {
+      if (request[6] == 'l' &&
+          request[7] == 'e' &&
+          request[8] == 'd' &&
+          request[9] == 's') {
+        uint8_t bitmap = call Leds.get();
+        call Tcp.send(http_okay, http_okay_len);
+        if (bitmap & 1) reply[6] = '1';
+        if (bitmap & 2) reply[14] = '1';
+        if (bitmap & 4) reply[22] = '1';
+        call Tcp.send(reply, 24);
+      }
+    }
+    call Tcp.close();
+  }
+
+  int http_state;
+  int req_verb;
+  char request_buf[150], *request;
+  char tcp_buf[100];
+
+  event void Boot.booted() {
+    http_state = S_IDLE;
+    call Tcp.bind(80);
+  }
+
+  event bool Tcp.accept(struct sockaddr_in6 *from, 
+                            void **tx_buf, int *tx_buf_len) {
+    if (http_state == S_IDLE) {
+      http_state = S_CONNECTED;
+      *tx_buf = tcp_buf;
+      *tx_buf_len = 100;
+      return TRUE;
+    }
+    printfUART("rejecting connection\n");
+    return FALSE;
+  }
+  event void Tcp.connectDone(error_t e) {
+    
+  }
+  event void Tcp.recv(void *payload, uint16_t len) {
+    static int crlf_pos;
+    char *msg = payload;
+    switch (http_state) {
+    case S_CONNECTED:
+      crlf_pos = 0;
+      request = request_buf;
+      if (len < 3) {
+        call Tcp.close();
+        return;
+      }
+      if (msg[0] == 'G') {
+        req_verb = HTTP_GET;
+        msg += 3;
+        len -= 3;
+      }
+      http_state = S_REQUEST_PRE;
+    case S_REQUEST_PRE:
+      while (len > 0 && *msg == ' ') {
+        len--; msg++;
+      }
+      if (len == 0) break;
+      http_state = S_REQUEST;
+    case S_REQUEST:
+      while (len > 0 && *msg != ' ') {
+        *request++ = *msg++;
+        len--;
+      }
+      if (len == 0) break;
+      *request++ = '\0';
+      http_state = S_HEADER;
+    case S_HEADER:
+      while (len > 0) {
+        switch (crlf_pos) {
+        case 0:
+        case 2:
+          if (*msg == '\r') crlf_pos ++;
+          else if (*msg == '\n') crlf_pos += 2;
+          else crlf_pos = 0;
+          break;
+        case 1:
+        case 3:
+          if (*msg == '\n') crlf_pos ++;
+          else crlf_pos = 0;
+          break;
+        }
+        len--; msg++;
+        // if crlf == 2, we just finished a header line.  you know.  fyi.
+        if (crlf_pos == 4) {
+          http_state = S_BODY;
+          process_request(req_verb, request_buf, request - request_buf - 1);
+          break;
+        } 
+      }
+    if (crlf_pos < 4) break;
+
+    case S_BODY:
+      // len might be zero here... just a note.
+    default:
+      call Tcp.close();
+    }
+  }
+
+  event void Tcp.closed(error_t e) {
+    call Leds.led2Toggle();
+
+    call Tcp.bind(80);
+    http_state = S_IDLE;
+  }
+
+  event void Tcp.acked() {
+
+  }
+}
diff --git a/apps/TCPEcho/Makefile b/apps/TCPEcho/Makefile
new file mode 100644 (file)
index 0000000..d9c3d0a
--- /dev/null
@@ -0,0 +1,26 @@
+COMPONENT=TCPEchoC
+
+# uncomment this for network programming support
+# BOOTLOADER=tosboot
+
+# radio opts
+CFLAGS += -DCC2420_DEF_CHANNEL=17
+# CFLAGS += -DCC2420_DEF_RFPOWER=4
+
+
+# CFLAGS += -DNO_LIB6LOWPAN_ASCII
+
+# if this is set, motes will send debugging information to the address
+# listed.
+# CFLAGS += -DREPORT_DEST=\"2001:470:1f04:56d::64\"
+
+# sim/test harness
+# CFLAGS += -I../IPBaseStation
+# CFLAGS += -DDBG_TRACK_FLOWS -DDBG_FLOWS_REPORT
+
+# printf debugs.  works only on telosb/tmote sky
+# CFLAGS += -DPRINTFUART_ENABLED
+
+
+include $(MAKERULES)
+
diff --git a/apps/TCPEcho/TCPEchoC.nc b/apps/TCPEcho/TCPEchoC.nc
new file mode 100644 (file)
index 0000000..8351bbc
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * "Copyright (c) 2008 The Regents of the University  of California.
+ * All rights reserved."
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice, the following
+ * two paragraphs and the author appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
+ *
+ */
+
+#include <6lowpan.h>
+#include "TestDriver.h"
+
+configuration TCPEchoC {
+
+} implementation {
+  components MainC, LedsC;
+  components TCPEchoP;
+
+  TCPEchoP.Boot -> MainC;
+  TCPEchoP.Leds -> LedsC;
+
+  components new TimerMilliC();
+  components IPDispatchC;
+
+  TCPEchoP.RadioControl -> IPDispatchC;
+  components new UdpSocketC() as Echo,
+    new UdpSocketC() as Status;
+  TCPEchoP.Echo -> Echo;
+
+  components new TcpSocketC() as TcpEcho;
+  TCPEchoP.TcpEcho -> TcpEcho;
+
+  components new TcpSocketC() as TcpWeb, HttpdP;
+  HttpdP.Boot -> MainC;
+  HttpdP.Leds -> LedsC;
+  HttpdP.Tcp -> TcpWeb;
+
+  TCPEchoP.Status -> Status;
+
+  TCPEchoP.StatusTimer -> TimerMilliC;
+
+  components UdpC;
+
+  TCPEchoP.IPStats -> IPDispatchC.IPStats;
+  TCPEchoP.RouteStats -> IPDispatchC.RouteStats;
+  TCPEchoP.ICMPStats -> IPDispatchC.ICMPStats;
+  TCPEchoP.UDPStats -> UdpC;
+
+  components RandomC;
+  TCPEchoP.Random -> RandomC;
+
+  components UDPShellC;
+}
diff --git a/apps/TCPEcho/TCPEchoP.nc b/apps/TCPEcho/TCPEchoP.nc
new file mode 100644 (file)
index 0000000..4386089
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ * "Copyright (c) 2008 The Regents of the University  of California.
+ * All rights reserved."
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice, the following
+ * two paragraphs and the author appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
+ *
+ */
+
+#include <IPDispatch.h>
+#include <lib6lowpan.h>
+#include <ip.h>
+#include <lib6lowpan.h>
+#include <ip.h>
+
+#include "UDPReport.h"
+#include "PrintfUART.h"
+
+#define REPORT_PERIOD 75L
+
+module TCPEchoP {
+  uses {
+    interface Boot;
+    interface SplitControl as RadioControl;
+
+    interface UDP as Echo;
+    interface UDP as Status;
+    interface Tcp as TcpEcho;
+
+    interface Leds;
+    
+    interface Timer<TMilli> as StatusTimer;
+   
+    interface Statistics<ip_statistics_t> as IPStats;
+    interface Statistics<route_statistics_t> as RouteStats;
+    interface Statistics<icmp_statistics_t> as ICMPStats;
+    interface Statistics<udp_statistics_t> as UDPStats;
+
+    interface Random;
+
+  }
+
+} implementation {
+
+  bool timerStarted;
+  nx_struct udp_report stats;
+  struct sockaddr_in6 route_dest;
+
+#ifndef SIM
+#define CHECK_NODE_ID
+#else
+#define CHECK_NODE_ID if (TOS_NODE_ID == BASESTATION_ID) return
+#endif
+
+  event void Boot.booted() {
+    CHECK_NODE_ID;
+    call RadioControl.start();
+    timerStarted = FALSE;
+
+    call IPStats.clear();
+    call RouteStats.clear();
+    call ICMPStats.clear();
+    printfUART_init();
+
+
+#ifdef REPORT_DEST
+    route_dest.sin6_port = hton16(7000);
+    inet_pton6(REPORT_DEST, &route_dest.sin6_addr);
+    call StatusTimer.startOneShot(call Random.rand16() % (1024 * REPORT_PERIOD));
+#endif
+
+    dbg("Boot", "booted: %i\n", TOS_NODE_ID);
+    call Echo.bind(7);
+    call TcpEcho.bind(7);
+    call Status.bind(7001);
+  }
+
+  event void RadioControl.startDone(error_t e) {
+
+  }
+
+  event void RadioControl.stopDone(error_t e) {
+
+  }
+
+  event void Status.recvfrom(struct sockaddr_in6 *from, void *data, 
+                             uint16_t len, struct ip_metadata *meta) {
+
+  }
+
+  event void Echo.recvfrom(struct sockaddr_in6 *from, void *data, 
+                           uint16_t len, struct ip_metadata *meta) {
+    CHECK_NODE_ID;
+    call Echo.sendto(from, data, len);
+  }
+
+  enum {
+    STATUS_SIZE = sizeof(ip_statistics_t) + 
+    sizeof(route_statistics_t) +
+    sizeof(icmp_statistics_t) + sizeof(udp_statistics_t),
+  };
+
+
+  event void StatusTimer.fired() {
+
+    if (!timerStarted) {
+      call StatusTimer.startPeriodic(1024 * REPORT_PERIOD);
+      timerStarted = TRUE;
+    }
+
+    stats.seqno++;
+    stats.sender = TOS_NODE_ID;
+
+    call IPStats.get(&stats.ip);
+    call RouteStats.get(&stats.route);
+    call ICMPStats.get(&stats.icmp);
+    call UDPStats.get(&stats.udp);
+
+    call Status.sendto(&route_dest, &stats, sizeof(stats));
+  }
+
+  /* 
+   * Example code for setting up a TCP echo socket.
+   */
+
+  bool sock_connected = FALSE;
+  char tcp_buf[150];
+
+  event bool TcpEcho.accept(struct sockaddr_in6 *from,
+                            void **tx_buf, int *tx_buf_len) {
+    *tx_buf = tcp_buf;
+    *tx_buf_len = 150;
+    return TRUE;
+  }
+  event void TcpEcho.connectDone(error_t e) {
+    
+  }
+  event void TcpEcho.recv(void *payload, uint16_t len) {
+    if (call TcpEcho.send(payload,len) != SUCCESS)
+      call Leds.led2Toggle();
+  }
+  event void TcpEcho.closed(error_t e) {
+    call Leds.led0Toggle();
+    call TcpEcho.bind(7);
+  }
+  event void TcpEcho.acked() {}
+
+}
diff --git a/apps/TCPEcho/UDPReport.h b/apps/TCPEcho/UDPReport.h
new file mode 100644 (file)
index 0000000..2efaaa0
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * "Copyright (c) 2008 The Regents of the University  of California.
+ * All rights reserved."
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice, the following
+ * two paragraphs and the author appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
+ *
+ */
+#ifndef _UDPREPORT_H
+#define _UDPREPORT_H
+
+#include <Statistics.h>
+
+nx_struct udp_report {
+  nx_uint16_t seqno;
+  nx_uint16_t sender;
+  ip_statistics_t    ip;
+  udp_statistics_t   udp;
+  icmp_statistics_t  icmp;
+  route_statistics_t route;
+} ;
+
+#endif
index f10a20721e9aef6803b2c2e4f32fde89be41b89b..f883f1bd3609a3212f357c8ccc0d6afa849b92c8 100644 (file)
@@ -3,18 +3,23 @@ COMPONENT=UDPEchoC
 # uncomment this for network programming support
 # BOOTLOADER=tosboot
 
-# radio opts
 CFLAGS += -DCC2420_DEF_CHANNEL=15
 # CFLAGS += -DCC2420_DEF_RFPOWER=4
 
+# disables support for the AM stack, which somewhat reduces code size
+# and compresses packet formats.  If you want to use other tinyos
+# protocols which are AM-based, you should not include this.
+CFLAGS += -DIEEE154FRAMES_ENABLED
+
+# lib6lowpan contains inet_ntop6 and inet_pton6 to process ascii
+# representations of IPv6 addresses.  You can remove them to save some
+# code if you don't use them
+# CFLAGS += -DNO_LIB6LOWPAN_ASCII
+
 # if this is set, motes will send debugging information to the address
 # listed.
 # CFLAGS += -DREPORT_DEST=\"2001:470:1f04:56d::64\"
 
-# sim/test harness
-# CFLAGS += -I../IPBaseStation
-# CFLAGS += -DDBG_TRACK_FLOWS -DDBG_FLOWS_REPORT
-
 # printf debugs.  works only on telosb/tmote sky
 # CFLAGS += -DPRINTFUART_ENABLED
 
index 9f5e04fb312285312b48407a34a748739b1878b7..a911f108634bef0db147ef81cff32f84e318d864 100644 (file)
@@ -28,5 +28,5 @@ clean:
        $(CC) -c -fPIC -o $@ $<
 
 msg:   
-       mig -DMIG -I$(LOWPAN_ROOT)/tos/lib/net/b6lowpan -I$(LOWPAN_ROOT)/support/sdk/c/lib6lowpan  python -python-classname=UdpReport UDPReport.h udp_report -o UdpReport.py
-       mig -DMIG -I$(LOWPAN_ROOT)/tos/lib/net/b6lowpan -I$(LOWPAN_ROOT)/support/sdk/c/lib6lowpan  python -python-classname=TestDriverMsg TestDriver.h testdriver_msg -o TestDriverMsg.py
+       mig -DMIG -I$(LOWPAN_ROOT)/tos/lib/net/blip -I$(TOSROOT)/tos/chips/cc2420 -I$(LOWPAN_ROOT)/support/sdk/c/blip/include  python -python-classname=UdpReport UDPReport.h udp_report -o util/UdpReport.py
+       mig -DMIG -I$(LOWPAN_ROOT)/tos/lib/net/blip -I$(TOSROOT)/tos/chips/cc2420 -I$(LOWPAN_ROOT)/support/sdk/c/blip/include  python -python-classname=TestDriverMsg TestDriver.h testdriver_msg -o util/TestDriverMsg.py
index 04322eb4463e3459e6f1786a8388f133eaa7af25..984f55d9ad34742ca669cfe76adb04e52645d286 100644 (file)
@@ -21,6 +21,7 @@
  */
 
 #include <6lowpan.h>
+#include "TestDriver.h"
 
 configuration UDPEchoC {
 
@@ -43,7 +44,9 @@ configuration UDPEchoC {
 
   UDPEchoP.StatusTimer -> TimerMilliC;
 
+  components UdpC;
   UDPEchoP.IPStats -> IPDispatchC.IPStats;
+  UDPEchoP.UDPStats -> UdpC;
   UDPEchoP.RouteStats -> IPDispatchC.RouteStats;
   UDPEchoP.ICMPStats -> IPDispatchC.ICMPStats;
 
@@ -58,14 +61,16 @@ configuration UDPEchoC {
 #ifdef DBG_TRACK_FLOWS
   components TestDriverP, SerialActiveMessageC as Serial;
   components ICMPResponderC, IPRoutingP;
-  components new TimerMilliC() as Mark;
   TestDriverP.Boot -> MainC;
   TestDriverP.SerialControl -> Serial;
   TestDriverP.ICMPPing -> ICMPResponderC.ICMPPing[unique("PING")];
   TestDriverP.CmdReceive -> Serial.Receive[AM_TESTDRIVER_MSG];
   TestDriverP.IPRouting -> IPRoutingP;
   TestDriverP.DoneSend -> Serial.AMSend[AM_TESTDRIVER_MSG];
+  TestDriverP.AckSend -> Serial.AMSend[AM_TESTDRIVER_ACK];
   TestDriverP.RadioControl -> IPDispatchC;
-  TestDriverP.MarkTimer -> Mark;
+#endif
+#ifdef DBG_FLOWS_REPORT
+  components TrackFlowsC;
 #endif
 }
index 055502032a4a213396aa21893210e267c2ff077a..eb10fc87c90f1361008373f1bd4cb72d06a3e29f 100644 (file)
@@ -29,7 +29,7 @@
 #include "UDPReport.h"
 #include "PrintfUART.h"
 
-#define REPORT_PERIOD 45L
+#define REPORT_PERIOD 75L
 
 module UDPEchoP {
   uses {
@@ -44,6 +44,7 @@ module UDPEchoP {
     interface Timer<TMilli> as StatusTimer;
    
     interface Statistics<ip_statistics_t> as IPStats;
+    interface Statistics<udp_statistics_t> as UDPStats;
     interface Statistics<route_statistics_t> as RouteStats;
     interface Statistics<icmp_statistics_t> as ICMPStats;
 
@@ -53,17 +54,10 @@ module UDPEchoP {
 } implementation {
 
   bool timerStarted;
-  udp_statistics_t stats;
+  nx_struct udp_report stats;
   struct sockaddr_in6 route_dest;
 
-#ifndef SIM
-#define CHECK_NODE_ID
-#else
-#define CHECK_NODE_ID if (TOS_NODE_ID == BASESTATION_ID) return
-#endif
-
   event void Boot.booted() {
-    CHECK_NODE_ID;
     call RadioControl.start();
     timerStarted = FALSE;
 
@@ -72,12 +66,9 @@ module UDPEchoP {
     call ICMPStats.clear();
     printfUART_init();
 
-    stats.total = 0;
-    stats.failed = 0;
-
 #ifdef REPORT_DEST
     route_dest.sin6_port = hton16(7000);
-    inet6_aton(REPORT_DEST, &route_dest.sin6_addr);
+    inet_pton6(REPORT_DEST, &route_dest.sin6_addr);
     call StatusTimer.startOneShot(call Random.rand16() % (1024 * REPORT_PERIOD));
 #endif
 
@@ -101,39 +92,24 @@ module UDPEchoP {
 
   event void Echo.recvfrom(struct sockaddr_in6 *from, void *data, 
                            uint16_t len, struct ip_metadata *meta) {
-    CHECK_NODE_ID;
     call Echo.sendto(from, data, len);
   }
 
-  enum {
-    STATUS_SIZE = // sizeof(ip_statistics_t) + 
-    sizeof(route_statistics_t) +
-    sizeof(icmp_statistics_t) + sizeof(udp_statistics_t),
-  };
-
-
   event void StatusTimer.fired() {
-    uint8_t status[STATUS_SIZE];
-    nx_struct udp_report *payload;
-    CHECK_NODE_ID;
 
-    stats.total++;
-    
     if (!timerStarted) {
       call StatusTimer.startPeriodic(1024 * REPORT_PERIOD);
       timerStarted = TRUE;
     }
 
-    payload = (nx_struct udp_report *)status;
-    
     stats.seqno++;
     stats.sender = TOS_NODE_ID;
 
-    // memcpy(&payload->ip,    call IPStats.get(),    sizeof(ip_statistics_t));
-    call RouteStats.get(&payload->route);
-    call ICMPStats.get(&payload->icmp);
-    memcpy(&payload->udp,   &stats,                sizeof(udp_statistics_t));
+    call IPStats.get(&stats.ip);
+    call UDPStats.get(&stats.udp);
+    call ICMPStats.get(&stats.icmp);
+    call RouteStats.get(&stats.route);
 
-    call Status.sendto(&route_dest, status, STATUS_SIZE);
+    call Status.sendto(&route_dest, &stats, sizeof(stats));
   }
 }
index e1d7dfc9c5d7105d613f1de1f3967ede5477b223..2efaaa0ec0298fbe7363a5725d994596eeb3f69c 100644 (file)
 #ifndef _UDPREPORT_H
 #define _UDPREPORT_H
 
-#include <IPDispatch.h>
+#include <Statistics.h>
 
 nx_struct udp_report {
-  // ip_statistics_t    ip;
+  nx_uint16_t seqno;
+  nx_uint16_t sender;
+  ip_statistics_t    ip;
   udp_statistics_t   udp;
   icmp_statistics_t  icmp;
   route_statistics_t route;
index 0522ca41c6dbb22722605283dbea7d232f64ce4c..4a240cf49c830f997ca8c53661bedf77679444dc 100644 (file)
@@ -9,7 +9,7 @@ port = 7000
 
 if __name__ == '__main__':
     conn = MySQLdb.connect (host = "localhost",
-                            user = "root",
+                            user = "b6lowpan",
                             db = "b6lowpan")
     cursor = conn.cursor()
     s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
index 5b75951b3f6e43a53e0f6f846e6bfb749a95d644..c42f81748aa8d22469932acdb38906215b61777b 100644 (file)
@@ -7,14 +7,14 @@
 import tinyos.message.Message
 
 # The default size of this message type in bytes.
-DEFAULT_MESSAGE_SIZE = 32
+DEFAULT_MESSAGE_SIZE = 35
 
 # The Active Message type associated with this message.
 AM_TYPE = -1
 
 class UdpReport(tinyos.message.Message.Message):
-    # Create a new UdpReport of size 32.
-    def __init__(self, data="", addr=None, gid=None, base_offset=0, data_length=32):
+    # Create a new UdpReport of size 35.
+    def __init__(self, data="", addr=None, gid=None, base_offset=0, data_length=35):
         tinyos.message.Message.Message.__init__(self, data, addr, gid, base_offset, data_length)
         self.amTypeSet(AM_TYPE)
     
@@ -31,68 +31,99 @@ class UdpReport(tinyos.message.Message.Message):
     def __str__(self):
         s = "Message <UdpReport> \n"
         try:
-            s += "  [udp.total=0x%x]\n" % (self.get_udp_total())
+            s += "  [ip.sent=0x%x]\n" % (self.get_ip_sent())
         except:
             pass
         try:
-            s += "  [udp.failed=0x%x]\n" % (self.get_udp_failed())
+            s += "  [ip.forwarded=0x%x]\n" % (self.get_ip_forwarded())
         except:
             pass
         try:
-            s += "  [udp.seqno=0x%x]\n" % (self.get_udp_seqno())
+            s += "  [ip.rx_drop=0x%x]\n" % (self.get_ip_rx_drop())
         except:
             pass
         try:
-            s += "  [udp.sender=0x%x]\n" % (self.get_udp_sender())
+            s += "  [ip.tx_drop=0x%x]\n" % (self.get_ip_tx_drop())
         except:
             pass
         try:
-            s += "  [icmp.rx=0x%x]\n" % (self.get_icmp_rx())
+            s += "  [ip.fw_drop=0x%x]\n" % (self.get_ip_fw_drop())
+        except:
+            pass
+        try:
+            s += "  [ip.rx_total=0x%x]\n" % (self.get_ip_rx_total())
+        except:
+            pass
+        try:
+            s += "  [ip.real_drop=0x%x]\n" % (self.get_ip_real_drop())
+        except:
+            pass
+        try:
+            s += "  [ip.hlim_drop=0x%x]\n" % (self.get_ip_hlim_drop())
+        except:
+            pass
+        try:
+            s += "  [ip.senddone_el=0x%x]\n" % (self.get_ip_senddone_el())
+        except:
+            pass
+        try:
+            s += "  [ip.fragpool=0x%x]\n" % (self.get_ip_fragpool())
+        except:
+            pass
+        try:
+            s += "  [ip.sendinfo=0x%x]\n" % (self.get_ip_sendinfo())
+        except:
+            pass
+        try:
+            s += "  [ip.sendentry=0x%x]\n" % (self.get_ip_sendentry())
+        except:
+            pass
+        try:
+            s += "  [ip.sndqueue=0x%x]\n" % (self.get_ip_sndqueue())
+        except:
+            pass
+        try:
+            s += "  [ip.encfail=0x%x]\n" % (self.get_ip_encfail())
         except:
             pass
         try:
-            s += "  [route.parent.flags=0x%x]\n" % (self.get_route_parent_flags())
+            s += "  [ip.heapfree=0x%x]\n" % (self.get_ip_heapfree())
         except:
             pass
         try:
-            s += "  [route.parent.hops=0x%x]\n" % (self.get_route_parent_hops())
+            s += "  [udp.total=0x%x]\n" % (self.get_udp_total())
+        except:
+            pass
+        try:
+            s += "  [udp.failed=0x%x]\n" % (self.get_udp_failed())
         except:
             pass
         try:
-            s += "  [route.parent.neighbor=0x%x]\n" % (self.get_route_parent_neighbor())
+            s += "  [udp.seqno=0x%x]\n" % (self.get_udp_seqno())
         except:
             pass
         try:
-            s += "  [route.parent.costEstimate=0x%x]\n" % (self.get_route_parent_costEstimate())
+            s += "  [udp.sender=0x%x]\n" % (self.get_udp_sender())
         except:
             pass
         try:
-            s += "  [route.parent.linkEstimate=0x%x]\n" % (self.get_route_parent_linkEstimate())
+            s += "  [icmp.rx=0x%x]\n" % (self.get_icmp_rx())
         except:
             pass
         try:
-            s += "  [route.parent.rssiEstimate=0x%x]\n" % (self.get_route_parent_rssiEstimate())
+            s += "  [route.hop_limit=0x%x]\n" % (self.get_route_hop_limit())
         except:
             pass
         try:
-            s += "  [route.parent.stats.success=";
-            for i in range(0, 2):
-                s += "0x%x " % (self.getElement_route_parent_stats_success(i) & 0xff)
-            s += "]\n";
+            s += "  [route.parent=0x%x]\n" % (self.get_route_parent())
         except:
             pass
         try:
-            s += "  [route.parent.stats.total=";
-            for i in range(0, 2):
-                s += "0x%x " % (self.getElement_route_parent_stats_total(i) & 0xff)
-            s += "]\n";
+            s += "  [route.parent_metric=0x%x]\n" % (self.get_route_parent_metric())
         except:
             pass
         try:
-            s += "  [route.parent.stats.receptions=";
-            for i in range(0, 2):
-                s += "0x%x " % (self.getElement_route_parent_stats_receptions(i) & 0xff)
-            s += "]\n";
+            s += "  [route.parent_etx=0x%x]\n" % (self.get_route_parent_etx())
         except:
             pass
         return s
@@ -100,952 +131,1322 @@ class UdpReport(tinyos.message.Message.Message):
     # Message-type-specific access methods appear below.
 
     #
-    # Accessor methods for field: udp.total
+    # Accessor methods for field: ip.sent
     #   Field type: int
     #   Offset (bits): 0
     #   Size (bits): 16
     #
 
     #
-    # Return whether the field 'udp.total' is signed (False).
+    # Return whether the field 'ip.sent' is signed (False).
     #
-    def isSigned_udp_total(self):
+    def isSigned_ip_sent(self):
         return False
     
     #
-    # Return whether the field 'udp.total' is an array (False).
+    # Return whether the field 'ip.sent' is an array (False).
     #
-    def isArray_udp_total(self):
+    def isArray_ip_sent(self):
         return False
     
     #
-    # Return the offset (in bytes) of the field 'udp.total'
+    # Return the offset (in bytes) of the field 'ip.sent'
     #
-    def offset_udp_total(self):
+    def offset_ip_sent(self):
         return (0 / 8)
     
     #
-    # Return the offset (in bits) of the field 'udp.total'
+    # Return the offset (in bits) of the field 'ip.sent'
     #
-    def offsetBits_udp_total(self):
+    def offsetBits_ip_sent(self):
         return 0
     
     #
-    # Return the value (as a int) of the field 'udp.total'
+    # Return the value (as a int) of the field 'ip.sent'
     #
-    def get_udp_total(self):
-        return self.getUIntElement(self.offsetBits_udp_total(), 16, 1)
+    def get_ip_sent(self):
+        return self.getUIntElement(self.offsetBits_ip_sent(), 16, 1)
     
     #
-    # Set the value of the field 'udp.total'
+    # Set the value of the field 'ip.sent'
     #
-    def set_udp_total(self, value):
-        self.setUIntElement(self.offsetBits_udp_total(), 16, value, 1)
+    def set_ip_sent(self, value):
+        self.setUIntElement(self.offsetBits_ip_sent(), 16, value, 1)
     
     #
-    # Return the size, in bytes, of the field 'udp.total'
+    # Return the size, in bytes, of the field 'ip.sent'
     #
-    def size_udp_total(self):
+    def size_ip_sent(self):
         return (16 / 8)
     
     #
-    # Return the size, in bits, of the field 'udp.total'
+    # Return the size, in bits, of the field 'ip.sent'
     #
-    def sizeBits_udp_total(self):
+    def sizeBits_ip_sent(self):
         return 16
     
     #
-    # Accessor methods for field: udp.failed
+    # Accessor methods for field: ip.forwarded
     #   Field type: int
     #   Offset (bits): 16
     #   Size (bits): 16
     #
 
     #
-    # Return whether the field 'udp.failed' is signed (False).
+    # Return whether the field 'ip.forwarded' is signed (False).
     #
-    def isSigned_udp_failed(self):
+    def isSigned_ip_forwarded(self):
         return False
     
     #
-    # Return whether the field 'udp.failed' is an array (False).
+    # Return whether the field 'ip.forwarded' is an array (False).
     #
-    def isArray_udp_failed(self):
+    def isArray_ip_forwarded(self):
         return False
     
     #
-    # Return the offset (in bytes) of the field 'udp.failed'
+    # Return the offset (in bytes) of the field 'ip.forwarded'
     #
-    def offset_udp_failed(self):
+    def offset_ip_forwarded(self):
         return (16 / 8)
     
     #
-    # Return the offset (in bits) of the field 'udp.failed'
+    # Return the offset (in bits) of the field 'ip.forwarded'
     #
-    def offsetBits_udp_failed(self):
+    def offsetBits_ip_forwarded(self):
         return 16
     
     #
-    # Return the value (as a int) of the field 'udp.failed'
+    # Return the value (as a int) of the field 'ip.forwarded'
     #
-    def get_udp_failed(self):
-        return self.getUIntElement(self.offsetBits_udp_failed(), 16, 1)
+    def get_ip_forwarded(self):
+        return self.getUIntElement(self.offsetBits_ip_forwarded(), 16, 1)
     
     #
-    # Set the value of the field 'udp.failed'
+    # Set the value of the field 'ip.forwarded'
     #
-    def set_udp_failed(self, value):
-        self.setUIntElement(self.offsetBits_udp_failed(), 16, value, 1)
+    def set_ip_forwarded(self, value):
+        self.setUIntElement(self.offsetBits_ip_forwarded(), 16, value, 1)
     
     #
-    # Return the size, in bytes, of the field 'udp.failed'
+    # Return the size, in bytes, of the field 'ip.forwarded'
     #
-    def size_udp_failed(self):
+    def size_ip_forwarded(self):
         return (16 / 8)
     
     #
-    # Return the size, in bits, of the field 'udp.failed'
+    # Return the size, in bits, of the field 'ip.forwarded'
     #
-    def sizeBits_udp_failed(self):
+    def sizeBits_ip_forwarded(self):
         return 16
     
     #
-    # Accessor methods for field: udp.seqno
-    #   Field type: int
+    # Accessor methods for field: ip.rx_drop
+    #   Field type: short
     #   Offset (bits): 32
-    #   Size (bits): 16
+    #   Size (bits): 8
     #
 
     #
-    # Return whether the field 'udp.seqno' is signed (False).
+    # Return whether the field 'ip.rx_drop' is signed (False).
     #
-    def isSigned_udp_seqno(self):
+    def isSigned_ip_rx_drop(self):
         return False
     
     #
-    # Return whether the field 'udp.seqno' is an array (False).
+    # Return whether the field 'ip.rx_drop' is an array (False).
     #
-    def isArray_udp_seqno(self):
+    def isArray_ip_rx_drop(self):
         return False
     
     #
-    # Return the offset (in bytes) of the field 'udp.seqno'
+    # Return the offset (in bytes) of the field 'ip.rx_drop'
     #
-    def offset_udp_seqno(self):
+    def offset_ip_rx_drop(self):
         return (32 / 8)
     
     #
-    # Return the offset (in bits) of the field 'udp.seqno'
+    # Return the offset (in bits) of the field 'ip.rx_drop'
     #
-    def offsetBits_udp_seqno(self):
+    def offsetBits_ip_rx_drop(self):
         return 32
     
     #
-    # Return the value (as a int) of the field 'udp.seqno'
+    # Return the value (as a short) of the field 'ip.rx_drop'
     #
-    def get_udp_seqno(self):
-        return self.getUIntElement(self.offsetBits_udp_seqno(), 16, 1)
+    def get_ip_rx_drop(self):
+        return self.getUIntElement(self.offsetBits_ip_rx_drop(), 8, 1)
     
     #
-    # Set the value of the field 'udp.seqno'
+    # Set the value of the field 'ip.rx_drop'
     #
-    def set_udp_seqno(self, value):
-        self.setUIntElement(self.offsetBits_udp_seqno(), 16, value, 1)
+    def set_ip_rx_drop(self, value):
+        self.setUIntElement(self.offsetBits_ip_rx_drop(), 8, value, 1)
     
     #
-    # Return the size, in bytes, of the field 'udp.seqno'
+    # Return the size, in bytes, of the field 'ip.rx_drop'
     #
-    def size_udp_seqno(self):
-        return (16 / 8)
+    def size_ip_rx_drop(self):
+        return (8 / 8)
     
     #
-    # Return the size, in bits, of the field 'udp.seqno'
+    # Return the size, in bits, of the field 'ip.rx_drop'
     #
-    def sizeBits_udp_seqno(self):
-        return 16
+    def sizeBits_ip_rx_drop(self):
+        return 8
     
     #
-    # Accessor methods for field: udp.sender
-    #   Field type: int
-    #   Offset (bits): 48
-    #   Size (bits): 16
+    # Accessor methods for field: ip.tx_drop
+    #   Field type: short
+    #   Offset (bits): 40
+    #   Size (bits): 8
     #
 
     #
-    # Return whether the field 'udp.sender' is signed (False).
+    # Return whether the field 'ip.tx_drop' is signed (False).
     #
-    def isSigned_udp_sender(self):
+    def isSigned_ip_tx_drop(self):
         return False
     
     #
-    # Return whether the field 'udp.sender' is an array (False).
+    # Return whether the field 'ip.tx_drop' is an array (False).
     #
-    def isArray_udp_sender(self):
+    def isArray_ip_tx_drop(self):
         return False
     
     #
-    # Return the offset (in bytes) of the field 'udp.sender'
+    # Return the offset (in bytes) of the field 'ip.tx_drop'
     #
-    def offset_udp_sender(self):
-        return (48 / 8)
+    def offset_ip_tx_drop(self):
+        return (40 / 8)
     
     #
-    # Return the offset (in bits) of the field 'udp.sender'
+    # Return the offset (in bits) of the field 'ip.tx_drop'
     #
-    def offsetBits_udp_sender(self):
-        return 48
+    def offsetBits_ip_tx_drop(self):
+        return 40
     
     #
-    # Return the value (as a int) of the field 'udp.sender'
+    # Return the value (as a short) of the field 'ip.tx_drop'
     #
-    def get_udp_sender(self):
-        return self.getUIntElement(self.offsetBits_udp_sender(), 16, 1)
+    def get_ip_tx_drop(self):
+        return self.getUIntElement(self.offsetBits_ip_tx_drop(), 8, 1)
     
     #
-    # Set the value of the field 'udp.sender'
+    # Set the value of the field 'ip.tx_drop'
     #
-    def set_udp_sender(self, value):
-        self.setUIntElement(self.offsetBits_udp_sender(), 16, value, 1)
+    def set_ip_tx_drop(self, value):
+        self.setUIntElement(self.offsetBits_ip_tx_drop(), 8, value, 1)
     
     #
-    # Return the size, in bytes, of the field 'udp.sender'
+    # Return the size, in bytes, of the field 'ip.tx_drop'
     #
-    def size_udp_sender(self):
-        return (16 / 8)
+    def size_ip_tx_drop(self):
+        return (8 / 8)
     
     #
-    # Return the size, in bits, of the field 'udp.sender'
+    # Return the size, in bits, of the field 'ip.tx_drop'
     #
-    def sizeBits_udp_sender(self):
-        return 16
+    def sizeBits_ip_tx_drop(self):
+        return 8
     
     #
-    # Accessor methods for field: icmp.rx
-    #   Field type: int
-    #   Offset (bits): 64
-    #   Size (bits): 16
+    # Accessor methods for field: ip.fw_drop
+    #   Field type: short
+    #   Offset (bits): 48
+    #   Size (bits): 8
     #
 
     #
-    # Return whether the field 'icmp.rx' is signed (False).
+    # Return whether the field 'ip.fw_drop' is signed (False).
     #
-    def isSigned_icmp_rx(self):
+    def isSigned_ip_fw_drop(self):
         return False
     
     #
-    # Return whether the field 'icmp.rx' is an array (False).
+    # Return whether the field 'ip.fw_drop' is an array (False).
     #
-    def isArray_icmp_rx(self):
+    def isArray_ip_fw_drop(self):
         return False
     
     #
-    # Return the offset (in bytes) of the field 'icmp.rx'
+    # Return the offset (in bytes) of the field 'ip.fw_drop'
     #
-    def offset_icmp_rx(self):
-        return (64 / 8)
+    def offset_ip_fw_drop(self):
+        return (48 / 8)
     
     #
-    # Return the offset (in bits) of the field 'icmp.rx'
+    # Return the offset (in bits) of the field 'ip.fw_drop'
     #
-    def offsetBits_icmp_rx(self):
-        return 64
+    def offsetBits_ip_fw_drop(self):
+        return 48
     
     #
-    # Return the value (as a int) of the field 'icmp.rx'
+    # Return the value (as a short) of the field 'ip.fw_drop'
     #
-    def get_icmp_rx(self):
-        return self.getUIntElement(self.offsetBits_icmp_rx(), 16, 1)
+    def get_ip_fw_drop(self):
+        return self.getUIntElement(self.offsetBits_ip_fw_drop(), 8, 1)
     
     #
-    # Set the value of the field 'icmp.rx'
+    # Set the value of the field 'ip.fw_drop'
     #
-    def set_icmp_rx(self, value):
-        self.setUIntElement(self.offsetBits_icmp_rx(), 16, value, 1)
+    def set_ip_fw_drop(self, value):
+        self.setUIntElement(self.offsetBits_ip_fw_drop(), 8, value, 1)
     
     #
-    # Return the size, in bytes, of the field 'icmp.rx'
+    # Return the size, in bytes, of the field 'ip.fw_drop'
     #
-    def size_icmp_rx(self):
-        return (16 / 8)
+    def size_ip_fw_drop(self):
+        return (8 / 8)
     
     #
-    # Return the size, in bits, of the field 'icmp.rx'
+    # Return the size, in bits, of the field 'ip.fw_drop'
     #
-    def sizeBits_icmp_rx(self):
-        return 16
+    def sizeBits_ip_fw_drop(self):
+        return 8
     
     #
-    # Accessor methods for field: route.parent.flags
+    # Accessor methods for field: ip.rx_total
     #   Field type: short
-    #   Offset (bits): 80
+    #   Offset (bits): 56
     #   Size (bits): 8
     #
 
     #
-    # Return whether the field 'route.parent.flags' is signed (False).
+    # Return whether the field 'ip.rx_total' is signed (False).
     #
-    def isSigned_route_parent_flags(self):
+    def isSigned_ip_rx_total(self):
         return False
     
     #
-    # Return whether the field 'route.parent.flags' is an array (False).
+    # Return whether the field 'ip.rx_total' is an array (False).
     #
-    def isArray_route_parent_flags(self):
+    def isArray_ip_rx_total(self):
         return False
     
     #
-    # Return the offset (in bytes) of the field 'route.parent.flags'
+    # Return the offset (in bytes) of the field 'ip.rx_total'
     #
-    def offset_route_parent_flags(self):
-        return (80 / 8)
+    def offset_ip_rx_total(self):
+        return (56 / 8)
     
     #
-    # Return the offset (in bits) of the field 'route.parent.flags'
+    # Return the offset (in bits) of the field 'ip.rx_total'
     #
-    def offsetBits_route_parent_flags(self):
-        return 80
+    def offsetBits_ip_rx_total(self):
+        return 56
     
     #
-    # Return the value (as a short) of the field 'route.parent.flags'
+    # Return the value (as a short) of the field 'ip.rx_total'
     #
-    def get_route_parent_flags(self):
-        return self.getUIntElement(self.offsetBits_route_parent_flags(), 8, 0)
+    def get_ip_rx_total(self):
+        return self.getUIntElement(self.offsetBits_ip_rx_total(), 8, 1)
     
     #
-    # Set the value of the field 'route.parent.flags'
+    # Set the value of the field 'ip.rx_total'
     #
-    def set_route_parent_flags(self, value):
-        self.setUIntElement(self.offsetBits_route_parent_flags(), 8, value, 0)
+    def set_ip_rx_total(self, value):
+        self.setUIntElement(self.offsetBits_ip_rx_total(), 8, value, 1)
     
     #
-    # Return the size, in bytes, of the field 'route.parent.flags'
+    # Return the size, in bytes, of the field 'ip.rx_total'
     #
-    def size_route_parent_flags(self):
+    def size_ip_rx_total(self):
         return (8 / 8)
     
     #
-    # Return the size, in bits, of the field 'route.parent.flags'
+    # Return the size, in bits, of the field 'ip.rx_total'
     #
-    def sizeBits_route_parent_flags(self):
+    def sizeBits_ip_rx_total(self):
         return 8
     
     #
-    # Accessor methods for field: route.parent.hops
+    # Accessor methods for field: ip.real_drop
     #   Field type: short
-    #   Offset (bits): 88
+    #   Offset (bits): 64
     #   Size (bits): 8
     #
 
     #
-    # Return whether the field 'route.parent.hops' is signed (False).
+    # Return whether the field 'ip.real_drop' is signed (False).
     #
-    def isSigned_route_parent_hops(self):
+    def isSigned_ip_real_drop(self):
         return False
     
     #
-    # Return whether the field 'route.parent.hops' is an array (False).
+    # Return whether the field 'ip.real_drop' is an array (False).
     #
-    def isArray_route_parent_hops(self):
+    def isArray_ip_real_drop(self):
         return False
     
     #
-    # Return the offset (in bytes) of the field 'route.parent.hops'
+    # Return the offset (in bytes) of the field 'ip.real_drop'
     #
-    def offset_route_parent_hops(self):
-        return (88 / 8)
+    def offset_ip_real_drop(self):
+        return (64 / 8)
     
     #
-    # Return the offset (in bits) of the field 'route.parent.hops'
+    # Return the offset (in bits) of the field 'ip.real_drop'
     #
-    def offsetBits_route_parent_hops(self):
-        return 88
+    def offsetBits_ip_real_drop(self):
+        return 64
     
     #
-    # Return the value (as a short) of the field 'route.parent.hops'
+    # Return the value (as a short) of the field 'ip.real_drop'
     #
-    def get_route_parent_hops(self):
-        return self.getUIntElement(self.offsetBits_route_parent_hops(), 8, 0)
+    def get_ip_real_drop(self):
+        return self.getUIntElement(self.offsetBits_ip_real_drop(), 8, 1)
     
     #
-    # Set the value of the field 'route.parent.hops'
+    # Set the value of the field 'ip.real_drop'
     #
-    def set_route_parent_hops(self, value):
-        self.setUIntElement(self.offsetBits_route_parent_hops(), 8, value, 0)
+    def set_ip_real_drop(self, value):
+        self.setUIntElement(self.offsetBits_ip_real_drop(), 8, value, 1)
     
     #
-    # Return the size, in bytes, of the field 'route.parent.hops'
+    # Return the size, in bytes, of the field 'ip.real_drop'
     #
-    def size_route_parent_hops(self):
+    def size_ip_real_drop(self):
         return (8 / 8)
     
     #
-    # Return the size, in bits, of the field 'route.parent.hops'
+    # Return the size, in bits, of the field 'ip.real_drop'
     #
-    def sizeBits_route_parent_hops(self):
+    def sizeBits_ip_real_drop(self):
         return 8
     
     #
-    # Accessor methods for field: route.parent.neighbor
-    #   Field type: int
-    #   Offset (bits): 96
-    #   Size (bits): 16
+    # Accessor methods for field: ip.hlim_drop
+    #   Field type: short
+    #   Offset (bits): 72
+    #   Size (bits): 8
     #
 
     #
-    # Return whether the field 'route.parent.neighbor' is signed (False).
+    # Return whether the field 'ip.hlim_drop' is signed (False).
     #
-    def isSigned_route_parent_neighbor(self):
+    def isSigned_ip_hlim_drop(self):
         return False
     
     #
-    # Return whether the field 'route.parent.neighbor' is an array (False).
+    # Return whether the field 'ip.hlim_drop' is an array (False).
     #
-    def isArray_route_parent_neighbor(self):
+    def isArray_ip_hlim_drop(self):
         return False
     
     #
-    # Return the offset (in bytes) of the field 'route.parent.neighbor'
+    # Return the offset (in bytes) of the field 'ip.hlim_drop'
     #
-    def offset_route_parent_neighbor(self):
-        return (96 / 8)
+    def offset_ip_hlim_drop(self):
+        return (72 / 8)
     
     #
-    # Return the offset (in bits) of the field 'route.parent.neighbor'
+    # Return the offset (in bits) of the field 'ip.hlim_drop'
     #
-    def offsetBits_route_parent_neighbor(self):
-        return 96
+    def offsetBits_ip_hlim_drop(self):
+        return 72
     
     #
-    # Return the value (as a int) of the field 'route.parent.neighbor'
+    # Return the value (as a short) of the field 'ip.hlim_drop'
     #
-    def get_route_parent_neighbor(self):
-        return self.getUIntElement(self.offsetBits_route_parent_neighbor(), 16, 0)
+    def get_ip_hlim_drop(self):
+        return self.getUIntElement(self.offsetBits_ip_hlim_drop(), 8, 1)
     
     #
-    # Set the value of the field 'route.parent.neighbor'
+    # Set the value of the field 'ip.hlim_drop'
     #
-    def set_route_parent_neighbor(self, value):
-        self.setUIntElement(self.offsetBits_route_parent_neighbor(), 16, value, 0)
+    def set_ip_hlim_drop(self, value):
+        self.setUIntElement(self.offsetBits_ip_hlim_drop(), 8, value, 1)
     
     #
-    # Return the size, in bytes, of the field 'route.parent.neighbor'
+    # Return the size, in bytes, of the field 'ip.hlim_drop'
     #
-    def size_route_parent_neighbor(self):
-        return (16 / 8)
+    def size_ip_hlim_drop(self):
+        return (8 / 8)
     
     #
-    # Return the size, in bits, of the field 'route.parent.neighbor'
+    # Return the size, in bits, of the field 'ip.hlim_drop'
     #
-    def sizeBits_route_parent_neighbor(self):
-        return 16
+    def sizeBits_ip_hlim_drop(self):
+        return 8
     
     #
-    # Accessor methods for field: route.parent.costEstimate
-    #   Field type: int
-    #   Offset (bits): 112
-    #   Size (bits): 16
+    # Accessor methods for field: ip.senddone_el
+    #   Field type: short
+    #   Offset (bits): 80
+    #   Size (bits): 8
     #
 
     #
-    # Return whether the field 'route.parent.costEstimate' is signed (False).
+    # Return whether the field 'ip.senddone_el' is signed (False).
     #
-    def isSigned_route_parent_costEstimate(self):
+    def isSigned_ip_senddone_el(self):
         return False
     
     #
-    # Return whether the field 'route.parent.costEstimate' is an array (False).
+    # Return whether the field 'ip.senddone_el' is an array (False).
     #
-    def isArray_route_parent_costEstimate(self):
+    def isArray_ip_senddone_el(self):
         return False
     
     #
-    # Return the offset (in bytes) of the field 'route.parent.costEstimate'
+    # Return the offset (in bytes) of the field 'ip.senddone_el'
     #
-    def offset_route_parent_costEstimate(self):
-        return (112 / 8)
+    def offset_ip_senddone_el(self):
+        return (80 / 8)
     
     #
-    # Return the offset (in bits) of the field 'route.parent.costEstimate'
+    # Return the offset (in bits) of the field 'ip.senddone_el'
     #
-    def offsetBits_route_parent_costEstimate(self):
-        return 112
+    def offsetBits_ip_senddone_el(self):
+        return 80
     
     #
-    # Return the value (as a int) of the field 'route.parent.costEstimate'
+    # Return the value (as a short) of the field 'ip.senddone_el'
     #
-    def get_route_parent_costEstimate(self):
-        return self.getUIntElement(self.offsetBits_route_parent_costEstimate(), 16, 0)
+    def get_ip_senddone_el(self):
+        return self.getUIntElement(self.offsetBits_ip_senddone_el(), 8, 1)
     
     #
-    # Set the value of the field 'route.parent.costEstimate'
+    # Set the value of the field 'ip.senddone_el'
     #
-    def set_route_parent_costEstimate(self, value):
-        self.setUIntElement(self.offsetBits_route_parent_costEstimate(), 16, value, 0)
+    def set_ip_senddone_el(self, value):
+        self.setUIntElement(self.offsetBits_ip_senddone_el(), 8, value, 1)
     
     #
-    # Return the size, in bytes, of the field 'route.parent.costEstimate'
+    # Return the size, in bytes, of the field 'ip.senddone_el'
     #
-    def size_route_parent_costEstimate(self):
-        return (16 / 8)
+    def size_ip_senddone_el(self):
+        return (8 / 8)
     
     #
-    # Return the size, in bits, of the field 'route.parent.costEstimate'
+    # Return the size, in bits, of the field 'ip.senddone_el'
     #
-    def sizeBits_route_parent_costEstimate(self):
-        return 16
+    def sizeBits_ip_senddone_el(self):
+        return 8
     
     #
-    # Accessor methods for field: route.parent.linkEstimate
-    #   Field type: int
-    #   Offset (bits): 128
-    #   Size (bits): 16
+    # Accessor methods for field: ip.fragpool
+    #   Field type: short
+    #   Offset (bits): 88
+    #   Size (bits): 8
     #
 
     #
-    # Return whether the field 'route.parent.linkEstimate' is signed (False).
+    # Return whether the field 'ip.fragpool' is signed (False).
     #
-    def isSigned_route_parent_linkEstimate(self):
+    def isSigned_ip_fragpool(self):
         return False
     
     #
-    # Return whether the field 'route.parent.linkEstimate' is an array (False).
+    # Return whether the field 'ip.fragpool' is an array (False).
     #
-    def isArray_route_parent_linkEstimate(self):
+    def isArray_ip_fragpool(self):
         return False
     
     #
-    # Return the offset (in bytes) of the field 'route.parent.linkEstimate'
+    # Return the offset (in bytes) of the field 'ip.fragpool'
     #
-    def offset_route_parent_linkEstimate(self):
-        return (128 / 8)
+    def offset_ip_fragpool(self):
+        return (88 / 8)
     
     #
-    # Return the offset (in bits) of the field 'route.parent.linkEstimate'
+    # Return the offset (in bits) of the field 'ip.fragpool'
     #
-    def offsetBits_route_parent_linkEstimate(self):
-        return 128
+    def offsetBits_ip_fragpool(self):
+        return 88
     
     #
-    # Return the value (as a int) of the field 'route.parent.linkEstimate'
+    # Return the value (as a short) of the field 'ip.fragpool'
     #
-    def get_route_parent_linkEstimate(self):
-        return self.getUIntElement(self.offsetBits_route_parent_linkEstimate(), 16, 0)
+    def get_ip_fragpool(self):
+        return self.getUIntElement(self.offsetBits_ip_fragpool(), 8, 1)
     
     #
-    # Set the value of the field 'route.parent.linkEstimate'
+    # Set the value of the field 'ip.fragpool'
     #
-    def set_route_parent_linkEstimate(self, value):
-        self.setUIntElement(self.offsetBits_route_parent_linkEstimate(), 16, value, 0)
+    def set_ip_fragpool(self, value):
+        self.setUIntElement(self.offsetBits_ip_fragpool(), 8, value, 1)
     
     #
-    # Return the size, in bytes, of the field 'route.parent.linkEstimate'
+    # Return the size, in bytes, of the field 'ip.fragpool'
     #
-    def size_route_parent_linkEstimate(self):
-        return (16 / 8)
+    def size_ip_fragpool(self):
+        return (8 / 8)
     
     #
-    # Return the size, in bits, of the field 'route.parent.linkEstimate'
+    # Return the size, in bits, of the field 'ip.fragpool'
     #
-    def sizeBits_route_parent_linkEstimate(self):
-        return 16
+    def sizeBits_ip_fragpool(self):
+        return 8
     
     #
-    # Accessor methods for field: route.parent.rssiEstimate
-    #   Field type: int
-    #   Offset (bits): 144
-    #   Size (bits): 16
+    # Accessor methods for field: ip.sendinfo
+    #   Field type: short
+    #   Offset (bits): 96
+    #   Size (bits): 8
     #
 
     #
-    # Return whether the field 'route.parent.rssiEstimate' is signed (False).
+    # Return whether the field 'ip.sendinfo' is signed (False).
     #
-    def isSigned_route_parent_rssiEstimate(self):
+    def isSigned_ip_sendinfo(self):
         return False
     
     #
-    # Return whether the field 'route.parent.rssiEstimate' is an array (False).
+    # Return whether the field 'ip.sendinfo' is an array (False).
     #
-    def isArray_route_parent_rssiEstimate(self):
+    def isArray_ip_sendinfo(self):
         return False
     
     #
-    # Return the offset (in bytes) of the field 'route.parent.rssiEstimate'
+    # Return the offset (in bytes) of the field 'ip.sendinfo'
     #
-    def offset_route_parent_rssiEstimate(self):
-        return (144 / 8)
+    def offset_ip_sendinfo(self):
+        return (96 / 8)
     
     #
-    # Return the offset (in bits) of the field 'route.parent.rssiEstimate'
+    # Return the offset (in bits) of the field 'ip.sendinfo'
     #
-    def offsetBits_route_parent_rssiEstimate(self):
-        return 144
+    def offsetBits_ip_sendinfo(self):
+        return 96
     
     #
-    # Return the value (as a int) of the field 'route.parent.rssiEstimate'
+    # Return the value (as a short) of the field 'ip.sendinfo'
     #
-    def get_route_parent_rssiEstimate(self):
-        return self.getUIntElement(self.offsetBits_route_parent_rssiEstimate(), 16, 0)
+    def get_ip_sendinfo(self):
+        return self.getUIntElement(self.offsetBits_ip_sendinfo(), 8, 1)
     
     #
-    # Set the value of the field 'route.parent.rssiEstimate'
+    # Set the value of the field 'ip.sendinfo'
     #
-    def set_route_parent_rssiEstimate(self, value):
-        self.setUIntElement(self.offsetBits_route_parent_rssiEstimate(), 16, value, 0)
+    def set_ip_sendinfo(self, value):
+        self.setUIntElement(self.offsetBits_ip_sendinfo(), 8, value, 1)
     
     #
-    # Return the size, in bytes, of the field 'route.parent.rssiEstimate'
+    # Return the size, in bytes, of the field 'ip.sendinfo'
     #
-    def size_route_parent_rssiEstimate(self):
-        return (16 / 8)
+    def size_ip_sendinfo(self):
+        return (8 / 8)
     
     #
-    # Return the size, in bits, of the field 'route.parent.rssiEstimate'
+    # Return the size, in bits, of the field 'ip.sendinfo'
     #
-    def sizeBits_route_parent_rssiEstimate(self):
-        return 16
+    def sizeBits_ip_sendinfo(self):
+        return 8
     
     #
-    # Accessor methods for field: route.parent.stats.success
-    #   Field type: int[]
-    #   Offset (bits): 0
-    #   Size of each element (bits): 16
+    # Accessor methods for field: ip.sendentry
+    #   Field type: short
+    #   Offset (bits): 104
+    #   Size (bits): 8
     #
 
     #
-    # Return whether the field 'route.parent.stats.success' is signed (False).
+    # Return whether the field 'ip.sendentry' is signed (False).
     #
-    def isSigned_route_parent_stats_success(self):
+    def isSigned_ip_sendentry(self):
         return False
     
     #
-    # Return whether the field 'route.parent.stats.success' is an array (True).
+    # Return whether the field 'ip.sendentry' is an array (False).
     #
-    def isArray_route_parent_stats_success(self):
-        return True
+    def isArray_ip_sendentry(self):
+        return False
     
     #
-    # Return the offset (in bytes) of the field 'route.parent.stats.success'
+    # Return the offset (in bytes) of the field 'ip.sendentry'
     #
-    def offset_route_parent_stats_success(self, index1):
-        offset = 0
-        if index1 < 0 or index1 >= 2:
-            raise IndexError
-        offset += 160 + index1 * 48
-        return (offset / 8)
+    def offset_ip_sendentry(self):
+        return (104 / 8)
     
     #
-    # Return the offset (in bits) of the field 'route.parent.stats.success'
+    # Return the offset (in bits) of the field 'ip.sendentry'
     #
-    def offsetBits_route_parent_stats_success(self, index1):
-        offset = 0
-        if index1 < 0 or index1 >= 2:
-            raise IndexError
-        offset += 160 + index1 * 48
-        return offset
+    def offsetBits_ip_sendentry(self):
+        return 104
     
     #
-    # Return the entire array 'route.parent.stats.success' as a int[]
+    # Return the value (as a short) of the field 'ip.sendentry'
     #
-    def get_route_parent_stats_success(self):
-        tmp = [None]*2
-        for index0 in range (0, self.numElements_route_parent_stats_success(0)):
-                tmp[index0] = self.getElement_route_parent_stats_success(index0)
-        return tmp
+    def get_ip_sendentry(self):
+        return self.getUIntElement(self.offsetBits_ip_sendentry(), 8, 1)
     
     #
-    # Set the contents of the array 'route.parent.stats.success' from the given int[]
+    # Set the value of the field 'ip.sendentry'
     #
-    def set_route_parent_stats_success(self, value):
-        for index0 in range(0, len(value)):
-            self.setElement_route_parent_stats_success(index0, value[index0])
-
+    def set_ip_sendentry(self, value):
+        self.setUIntElement(self.offsetBits_ip_sendentry(), 8, value, 1)
+    
     #
-    # Return an element (as a int) of the array 'route.parent.stats.success'
+    # Return the size, in bytes, of the field 'ip.sendentry'
     #
-    def getElement_route_parent_stats_success(self, index1):
-        return self.getUIntElement(self.offsetBits_route_parent_stats_success(index1), 16, 0)
+    def size_ip_sendentry(self):
+        return (8 / 8)
     
     #
-    # Set an element of the array 'route.parent.stats.success'
+    # Return the size, in bits, of the field 'ip.sendentry'
     #
-    def setElement_route_parent_stats_success(self, index1, value):
-        self.setUIntElement(self.offsetBits_route_parent_stats_success(index1), 16, value, 0)
+    def sizeBits_ip_sendentry(self):
+        return 8
     
     #
-    # Return the total size, in bytes, of the array 'route.parent.stats.success'
+    # Accessor methods for field: ip.sndqueue
+    #   Field type: short
+    #   Offset (bits): 112
+    #   Size (bits): 8
     #
-    def totalSize_route_parent_stats_success(self):
-        return (96 / 8)
-    
+
     #
-    # Return the total size, in bits, of the array 'route.parent.stats.success'
+    # Return whether the field 'ip.sndqueue' is signed (False).
     #
-    def totalSizeBits_route_parent_stats_success(self):
-        return 96
+    def isSigned_ip_sndqueue(self):
+        return False
     
     #
-    # Return the size, in bytes, of each element of the array 'route.parent.stats.success'
+    # Return whether the field 'ip.sndqueue' is an array (False).
     #
-    def elementSize_route_parent_stats_success(self):
-        return (16 / 8)
+    def isArray_ip_sndqueue(self):
+        return False
     
     #
-    # Return the size, in bits, of each element of the array 'route.parent.stats.success'
+    # Return the offset (in bytes) of the field 'ip.sndqueue'
     #
-    def elementSizeBits_route_parent_stats_success(self):
-        return 16
+    def offset_ip_sndqueue(self):
+        return (112 / 8)
     
     #
-    # Return the number of dimensions in the array 'route.parent.stats.success'
+    # Return the offset (in bits) of the field 'ip.sndqueue'
     #
-    def numDimensions_route_parent_stats_success(self):
-        return 1
+    def offsetBits_ip_sndqueue(self):
+        return 112
     
     #
-    # Return the number of elements in the array 'route.parent.stats.success'
+    # Return the value (as a short) of the field 'ip.sndqueue'
     #
-    def numElements_route_parent_stats_success():
-        return 2
+    def get_ip_sndqueue(self):
+        return self.getUIntElement(self.offsetBits_ip_sndqueue(), 8, 1)
     
     #
-    # Return the number of elements in the array 'route.parent.stats.success'
-    # for the given dimension.
+    # Set the value of the field 'ip.sndqueue'
     #
-    def numElements_route_parent_stats_success(self, dimension):
-        array_dims = [ 2,  ]
-        if dimension < 0 or dimension >= 1:
-            raise IndexException
-        if array_dims[dimension] == 0:
-            raise IndexError
-        return array_dims[dimension]
+    def set_ip_sndqueue(self, value):
+        self.setUIntElement(self.offsetBits_ip_sndqueue(), 8, value, 1)
     
     #
-    # Accessor methods for field: route.parent.stats.total
-    #   Field type: int[]
-    #   Offset (bits): 16
-    #   Size of each element (bits): 16
+    # Return the size, in bytes, of the field 'ip.sndqueue'
     #
-
+    def size_ip_sndqueue(self):
+        return (8 / 8)
+    
     #
-    # Return whether the field 'route.parent.stats.total' is signed (False).
+    # Return the size, in bits, of the field 'ip.sndqueue'
     #
-    def isSigned_route_parent_stats_total(self):
-        return False
+    def sizeBits_ip_sndqueue(self):
+        return 8
+    
+    #
+    # Accessor methods for field: ip.encfail
+    #   Field type: short
+    #   Offset (bits): 120
+    #   Size (bits): 8
+    #
+
+    #
+    # Return whether the field 'ip.encfail' is signed (False).
+    #
+    def isSigned_ip_encfail(self):
+        return False
+    
+    #
+    # Return whether the field 'ip.encfail' is an array (False).
+    #
+    def isArray_ip_encfail(self):
+        return False
+    
+    #
+    # Return the offset (in bytes) of the field 'ip.encfail'
+    #
+    def offset_ip_encfail(self):
+        return (120 / 8)
     
     #
-    # Return whether the field 'route.parent.stats.total' is an array (True).
+    # Return the offset (in bits) of the field 'ip.encfail'
     #
-    def isArray_route_parent_stats_total(self):
-        return True
+    def offsetBits_ip_encfail(self):
+        return 120
     
     #
-    # Return the offset (in bytes) of the field 'route.parent.stats.total'
+    # Return the value (as a short) of the field 'ip.encfail'
     #
-    def offset_route_parent_stats_total(self, index1):
-        offset = 16
-        if index1 < 0 or index1 >= 2:
-            raise IndexError
-        offset += 160 + index1 * 48
-        return (offset / 8)
+    def get_ip_encfail(self):
+        return self.getUIntElement(self.offsetBits_ip_encfail(), 8, 1)
     
     #
-    # Return the offset (in bits) of the field 'route.parent.stats.total'
+    # Set the value of the field 'ip.encfail'
     #
-    def offsetBits_route_parent_stats_total(self, index1):
-        offset = 16
-        if index1 < 0 or index1 >= 2:
-            raise IndexError
-        offset += 160 + index1 * 48
-        return offset
+    def set_ip_encfail(self, value):
+        self.setUIntElement(self.offsetBits_ip_encfail(), 8, value, 1)
     
     #
-    # Return the entire array 'route.parent.stats.total' as a int[]
+    # Return the size, in bytes, of the field 'ip.encfail'
     #
-    def get_route_parent_stats_total(self):
-        tmp = [None]*2
-        for index0 in range (0, self.numElements_route_parent_stats_total(0)):
-                tmp[index0] = self.getElement_route_parent_stats_total(index0)
-        return tmp
+    def size_ip_encfail(self):
+        return (8 / 8)
     
     #
-    # Set the contents of the array 'route.parent.stats.total' from the given int[]
+    # Return the size, in bits, of the field 'ip.encfail'
+    #
+    def sizeBits_ip_encfail(self):
+        return 8
+    
+    #
+    # Accessor methods for field: ip.heapfree
+    #   Field type: int
+    #   Offset (bits): 128
+    #   Size (bits): 16
     #
-    def set_route_parent_stats_total(self, value):
-        for index0 in range(0, len(value)):
-            self.setElement_route_parent_stats_total(index0, value[index0])
 
     #
-    # Return an element (as a int) of the array 'route.parent.stats.total'
+    # Return whether the field 'ip.heapfree' is signed (False).
     #
-    def getElement_route_parent_stats_total(self, index1):
-        return self.getUIntElement(self.offsetBits_route_parent_stats_total(index1), 16, 0)
+    def isSigned_ip_heapfree(self):
+        return False
     
     #
-    # Set an element of the array 'route.parent.stats.total'
+    # Return whether the field 'ip.heapfree' is an array (False).
     #
-    def setElement_route_parent_stats_total(self, index1, value):
-        self.setUIntElement(self.offsetBits_route_parent_stats_total(index1), 16, value, 0)
+    def isArray_ip_heapfree(self):
+        return False
     
     #
-    # Return the total size, in bytes, of the array 'route.parent.stats.total'
+    # Return the offset (in bytes) of the field 'ip.heapfree'
     #
-    def totalSize_route_parent_stats_total(self):
-        return (96 / 8)
+    def offset_ip_heapfree(self):
+        return (128 / 8)
     
     #
-    # Return the total size, in bits, of the array 'route.parent.stats.total'
+    # Return the offset (in bits) of the field 'ip.heapfree'
     #
-    def totalSizeBits_route_parent_stats_total(self):
-        return 96
+    def offsetBits_ip_heapfree(self):
+        return 128
+    
+    #
+    # Return the value (as a int) of the field 'ip.heapfree'
+    #
+    def get_ip_heapfree(self):
+        return self.getUIntElement(self.offsetBits_ip_heapfree(), 16, 1)
     
     #
-    # Return the size, in bytes, of each element of the array 'route.parent.stats.total'
+    # Set the value of the field 'ip.heapfree'
+    #
+    def set_ip_heapfree(self, value):
+        self.setUIntElement(self.offsetBits_ip_heapfree(), 16, value, 1)
+    
     #
-    def elementSize_route_parent_stats_total(self):
+    # Return the size, in bytes, of the field 'ip.heapfree'
+    #
+    def size_ip_heapfree(self):
         return (16 / 8)
     
     #
-    # Return the size, in bits, of each element of the array 'route.parent.stats.total'
+    # Return the size, in bits, of the field 'ip.heapfree'
     #
-    def elementSizeBits_route_parent_stats_total(self):
+    def sizeBits_ip_heapfree(self):
         return 16
     
     #
-    # Return the number of dimensions in the array 'route.parent.stats.total'
+    # Accessor methods for field: udp.total
+    #   Field type: int
+    #   Offset (bits): 144
+    #   Size (bits): 16
+    #
+
+    #
+    # Return whether the field 'udp.total' is signed (False).
+    #
+    def isSigned_udp_total(self):
+        return False
+    
+    #
+    # Return whether the field 'udp.total' is an array (False).
+    #
+    def isArray_udp_total(self):
+        return False
+    
+    #
+    # Return the offset (in bytes) of the field 'udp.total'
     #
-    def numDimensions_route_parent_stats_total(self):
-        return 1
+    def offset_udp_total(self):
+        return (144 / 8)
     
     #
-    # Return the number of elements in the array 'route.parent.stats.total'
+    # Return the offset (in bits) of the field 'udp.total'
     #
-    def numElements_route_parent_stats_total():
-        return 2
+    def offsetBits_udp_total(self):
+        return 144
     
     #
-    # Return the number of elements in the array 'route.parent.stats.total'
-    # for the given dimension.
+    # Return the value (as a int) of the field 'udp.total'
     #
-    def numElements_route_parent_stats_total(self, dimension):
-        array_dims = [ 2,  ]
-        if dimension < 0 or dimension >= 1:
-            raise IndexException
-        if array_dims[dimension] == 0:
-            raise IndexError
-        return array_dims[dimension]
+    def get_udp_total(self):
+        return self.getUIntElement(self.offsetBits_udp_total(), 16, 1)
     
     #
-    # Accessor methods for field: route.parent.stats.receptions
-    #   Field type: int[]
-    #   Offset (bits): 32
-    #   Size of each element (bits): 16
+    # Set the value of the field 'udp.total'
+    #
+    def set_udp_total(self, value):
+        self.setUIntElement(self.offsetBits_udp_total(), 16, value, 1)
+    
+    #
+    # Return the size, in bytes, of the field 'udp.total'
+    #
+    def size_udp_total(self):
+        return (16 / 8)
+    
+    #
+    # Return the size, in bits, of the field 'udp.total'
+    #
+    def sizeBits_udp_total(self):
+        return 16
+    
+    #
+    # Accessor methods for field: udp.failed
+    #   Field type: int
+    #   Offset (bits): 160
+    #   Size (bits): 16
     #
 
     #
-    # Return whether the field 'route.parent.stats.receptions' is signed (False).
+    # Return whether the field 'udp.failed' is signed (False).
+    #
+    def isSigned_udp_failed(self):
+        return False
+    
+    #
+    # Return whether the field 'udp.failed' is an array (False).
     #
-    def isSigned_route_parent_stats_receptions(self):
+    def isArray_udp_failed(self):
         return False
     
     #
-    # Return whether the field 'route.parent.stats.receptions' is an array (True).
+    # Return the offset (in bytes) of the field 'udp.failed'
+    #
+    def offset_udp_failed(self):
+        return (160 / 8)
+    
+    #
+    # Return the offset (in bits) of the field 'udp.failed'
     #
-    def isArray_route_parent_stats_receptions(self):
-        return True
+    def offsetBits_udp_failed(self):
+        return 160
     
     #
-    # Return the offset (in bytes) of the field 'route.parent.stats.receptions'
+    # Return the value (as a int) of the field 'udp.failed'
     #
-    def offset_route_parent_stats_receptions(self, index1):
-        offset = 32
-        if index1 < 0 or index1 >= 2:
-            raise IndexError
-        offset += 160 + index1 * 48
-        return (offset / 8)
+    def get_udp_failed(self):
+        return self.getUIntElement(self.offsetBits_udp_failed(), 16, 1)
     
     #
-    # Return the offset (in bits) of the field 'route.parent.stats.receptions'
+    # Set the value of the field 'udp.failed'
     #
-    def offsetBits_route_parent_stats_receptions(self, index1):
-        offset = 32
-        if index1 < 0 or index1 >= 2:
-            raise IndexError
-        offset += 160 + index1 * 48
-        return offset
+    def set_udp_failed(self, value):
+        self.setUIntElement(self.offsetBits_udp_failed(), 16, value, 1)
     
     #
-    # Return the entire array 'route.parent.stats.receptions' as a int[]
+    # Return the size, in bytes, of the field 'udp.failed'
     #
-    def get_route_parent_stats_receptions(self):
-        tmp = [None]*2
-        for index0 in range (0, self.numElements_route_parent_stats_receptions(0)):
-                tmp[index0] = self.getElement_route_parent_stats_receptions(index0)
-        return tmp
+    def size_udp_failed(self):
+        return (16 / 8)
     
     #
-    # Set the contents of the array 'route.parent.stats.receptions' from the given int[]
+    # Return the size, in bits, of the field 'udp.failed'
+    #
+    def sizeBits_udp_failed(self):
+        return 16
+    
+    #
+    # Accessor methods for field: udp.seqno
+    #   Field type: int
+    #   Offset (bits): 176
+    #   Size (bits): 16
     #
-    def set_route_parent_stats_receptions(self, value):
-        for index0 in range(0, len(value)):
-            self.setElement_route_parent_stats_receptions(index0, value[index0])
 
     #
-    # Return an element (as a int) of the array 'route.parent.stats.receptions'
+    # Return whether the field 'udp.seqno' is signed (False).
     #
-    def getElement_route_parent_stats_receptions(self, index1):
-        return self.getUIntElement(self.offsetBits_route_parent_stats_receptions(index1), 16, 0)
+    def isSigned_udp_seqno(self):
+        return False
     
     #
-    # Set an element of the array 'route.parent.stats.receptions'
+    # Return whether the field 'udp.seqno' is an array (False).
     #
-    def setElement_route_parent_stats_receptions(self, index1, value):
-        self.setUIntElement(self.offsetBits_route_parent_stats_receptions(index1), 16, value, 0)
+    def isArray_udp_seqno(self):
+        return False
     
     #
-    # Return the total size, in bytes, of the array 'route.parent.stats.receptions'
+    # Return the offset (in bytes) of the field 'udp.seqno'
     #
-    def totalSize_route_parent_stats_receptions(self):
-        return (96 / 8)
+    def offset_udp_seqno(self):
+        return (176 / 8)
     
     #
-    # Return the total size, in bits, of the array 'route.parent.stats.receptions'
+    # Return the offset (in bits) of the field 'udp.seqno'
     #
-    def totalSizeBits_route_parent_stats_receptions(self):
-        return 96
+    def offsetBits_udp_seqno(self):
+        return 176
+    
+    #
+    # Return the value (as a int) of the field 'udp.seqno'
+    #
+    def get_udp_seqno(self):
+        return self.getUIntElement(self.offsetBits_udp_seqno(), 16, 1)
+    
+    #
+    # Set the value of the field 'udp.seqno'
+    #
+    def set_udp_seqno(self, value):
+        self.setUIntElement(self.offsetBits_udp_seqno(), 16, value, 1)
     
     #
-    # Return the size, in bytes, of each element of the array 'route.parent.stats.receptions'
+    # Return the size, in bytes, of the field 'udp.seqno'
     #
-    def elementSize_route_parent_stats_receptions(self):
+    def size_udp_seqno(self):
         return (16 / 8)
     
     #
-    # Return the size, in bits, of each element of the array 'route.parent.stats.receptions'
+    # Return the size, in bits, of the field 'udp.seqno'
     #
-    def elementSizeBits_route_parent_stats_receptions(self):
+    def sizeBits_udp_seqno(self):
         return 16
     
     #
-    # Return the number of dimensions in the array 'route.parent.stats.receptions'
+    # Accessor methods for field: udp.sender
+    #   Field type: int
+    #   Offset (bits): 192
+    #   Size (bits): 16
+    #
+
+    #
+    # Return whether the field 'udp.sender' is signed (False).
     #
-    def numDimensions_route_parent_stats_receptions(self):
-        return 1
+    def isSigned_udp_sender(self):
+        return False
     
     #
-    # Return the number of elements in the array 'route.parent.stats.receptions'
+    # Return whether the field 'udp.sender' is an array (False).
     #
-    def numElements_route_parent_stats_receptions():
-        return 2
+    def isArray_udp_sender(self):
+        return False
     
     #
-    # Return the number of elements in the array 'route.parent.stats.receptions'
-    # for the given dimension.
+    # Return the offset (in bytes) of the field 'udp.sender'
+    #
+    def offset_udp_sender(self):
+        return (192 / 8)
+    
     #
-    def numElements_route_parent_stats_receptions(self, dimension):
-        array_dims = [ 2,  ]
-        if dimension < 0 or dimension >= 1:
-            raise IndexException
-        if array_dims[dimension] == 0:
-            raise IndexError
-        return array_dims[dimension]
+    # Return the offset (in bits) of the field 'udp.sender'
+    #
+    def offsetBits_udp_sender(self):
+        return 192
+    
+    #
+    # Return the value (as a int) of the field 'udp.sender'
+    #
+    def get_udp_sender(self):
+        return self.getUIntElement(self.offsetBits_udp_sender(), 16, 1)
+    
+    #
+    # Set the value of the field 'udp.sender'
+    #
+    def set_udp_sender(self, value):
+        self.setUIntElement(self.offsetBits_udp_sender(), 16, value, 1)
+    
+    #
+    # Return the size, in bytes, of the field 'udp.sender'
+    #
+    def size_udp_sender(self):
+        return (16 / 8)
+    
+    #
+    # Return the size, in bits, of the field 'udp.sender'
+    #
+    def sizeBits_udp_sender(self):
+        return 16
+    
+    #
+    # Accessor methods for field: icmp.rx
+    #   Field type: int
+    #   Offset (bits): 208
+    #   Size (bits): 16
+    #
+
+    #
+    # Return whether the field 'icmp.rx' is signed (False).
+    #
+    def isSigned_icmp_rx(self):
+        return False
+    
+    #
+    # Return whether the field 'icmp.rx' is an array (False).
+    #
+    def isArray_icmp_rx(self):
+        return False
+    
+    #
+    # Return the offset (in bytes) of the field 'icmp.rx'
+    #
+    def offset_icmp_rx(self):
+        return (208 / 8)
+    
+    #
+    # Return the offset (in bits) of the field 'icmp.rx'
+    #
+    def offsetBits_icmp_rx(self):
+        return 208
+    
+    #
+    # Return the value (as a int) of the field 'icmp.rx'
+    #
+    def get_icmp_rx(self):
+        return self.getUIntElement(self.offsetBits_icmp_rx(), 16, 1)
+    
+    #
+    # Set the value of the field 'icmp.rx'
+    #
+    def set_icmp_rx(self, value):
+        self.setUIntElement(self.offsetBits_icmp_rx(), 16, value, 1)
+    
+    #
+    # Return the size, in bytes, of the field 'icmp.rx'
+    #
+    def size_icmp_rx(self):
+        return (16 / 8)
+    
+    #
+    # Return the size, in bits, of the field 'icmp.rx'
+    #
+    def sizeBits_icmp_rx(self):
+        return 16
+    
+    #
+    # Accessor methods for field: route.hop_limit
+    #   Field type: short
+    #   Offset (bits): 224
+    #   Size (bits): 8
+    #
+
+    #
+    # Return whether the field 'route.hop_limit' is signed (False).
+    #
+    def isSigned_route_hop_limit(self):
+        return False
+    
+    #
+    # Return whether the field 'route.hop_limit' is an array (False).
+    #
+    def isArray_route_hop_limit(self):
+        return False
+    
+    #
+    # Return the offset (in bytes) of the field 'route.hop_limit'
+    #
+    def offset_route_hop_limit(self):
+        return (224 / 8)
+    
+    #
+    # Return the offset (in bits) of the field 'route.hop_limit'
+    #
+    def offsetBits_route_hop_limit(self):
+        return 224
+    
+    #
+    # Return the value (as a short) of the field 'route.hop_limit'
+    #
+    def get_route_hop_limit(self):
+        return self.getUIntElement(self.offsetBits_route_hop_limit(), 8, 1)
+    
+    #
+    # Set the value of the field 'route.hop_limit'
+    #
+    def set_route_hop_limit(self, value):
+        self.setUIntElement(self.offsetBits_route_hop_limit(), 8, value, 1)
+    
+    #
+    # Return the size, in bytes, of the field 'route.hop_limit'
+    #
+    def size_route_hop_limit(self):
+        return (8 / 8)
+    
+    #
+    # Return the size, in bits, of the field 'route.hop_limit'
+    #
+    def sizeBits_route_hop_limit(self):
+        return 8
+    
+    #
+    # Accessor methods for field: route.parent
+    #   Field type: int
+    #   Offset (bits): 232
+    #   Size (bits): 16
+    #
+
+    #
+    # Return whether the field 'route.parent' is signed (False).
+    #
+    def isSigned_route_parent(self):
+        return False
+    
+    #
+    # Return whether the field 'route.parent' is an array (False).
+    #
+    def isArray_route_parent(self):
+        return False
+    
+    #
+    # Return the offset (in bytes) of the field 'route.parent'
+    #
+    def offset_route_parent(self):
+        return (232 / 8)
+    
+    #
+    # Return the offset (in bits) of the field 'route.parent'
+    #
+    def offsetBits_route_parent(self):
+        return 232
+    
+    #
+    # Return the value (as a int) of the field 'route.parent'
+    #
+    def get_route_parent(self):
+        return self.getUIntElement(self.offsetBits_route_parent(), 16, 1)
+    
+    #
+    # Set the value of the field 'route.parent'
+    #
+    def set_route_parent(self, value):
+        self.setUIntElement(self.offsetBits_route_parent(), 16, value, 1)
+    
+    #
+    # Return the size, in bytes, of the field 'route.parent'
+    #
+    def size_route_parent(self):
+        return (16 / 8)
+    
+    #
+    # Return the size, in bits, of the field 'route.parent'
+    #
+    def sizeBits_route_parent(self):
+        return 16
+    
+    #
+    # Accessor methods for field: route.parent_metric
+    #   Field type: int
+    #   Offset (bits): 248
+    #   Size (bits): 16
+    #
+
+    #
+    # Return whether the field 'route.parent_metric' is signed (False).
+    #
+    def isSigned_route_parent_metric(self):
+        return False
+    
+    #
+    # Return whether the field 'route.parent_metric' is an array (False).
+    #
+    def isArray_route_parent_metric(self):
+        return False
+    
+    #
+    # Return the offset (in bytes) of the field 'route.parent_metric'
+    #
+    def offset_route_parent_metric(self):
+        return (248 / 8)
+    
+    #
+    # Return the offset (in bits) of the field 'route.parent_metric'
+    #
+    def offsetBits_route_parent_metric(self):
+        return 248
+    
+    #
+    # Return the value (as a int) of the field 'route.parent_metric'
+    #
+    def get_route_parent_metric(self):
+        return self.getUIntElement(self.offsetBits_route_parent_metric(), 16, 1)
+    
+    #
+    # Set the value of the field 'route.parent_metric'
+    #
+    def set_route_parent_metric(self, value):
+        self.setUIntElement(self.offsetBits_route_parent_metric(), 16, value, 1)
+    
+    #
+    # Return the size, in bytes, of the field 'route.parent_metric'
+    #
+    def size_route_parent_metric(self):
+        return (16 / 8)
+    
+    #
+    # Return the size, in bits, of the field 'route.parent_metric'
+    #
+    def sizeBits_route_parent_metric(self):
+        return 16
+    
+    #
+    # Accessor methods for field: route.parent_etx
+    #   Field type: int
+    #   Offset (bits): 264
+    #   Size (bits): 16
+    #
+
+    #
+    # Return whether the field 'route.parent_etx' is signed (False).
+    #
+    def isSigned_route_parent_etx(self):
+        return False
+    
+    #
+    # Return whether the field 'route.parent_etx' is an array (False).
+    #
+    def isArray_route_parent_etx(self):
+        return False
+    
+    #
+    # Return the offset (in bytes) of the field 'route.parent_etx'
+    #
+    def offset_route_parent_etx(self):
+        return (264 / 8)
+    
+    #
+    # Return the offset (in bits) of the field 'route.parent_etx'
+    #
+    def offsetBits_route_parent_etx(self):
+        return 264
+    
+    #
+    # Return the value (as a int) of the field 'route.parent_etx'
+    #
+    def get_route_parent_etx(self):
+        return self.getUIntElement(self.offsetBits_route_parent_etx(), 16, 1)
+    
+    #
+    # Set the value of the field 'route.parent_etx'
+    #
+    def set_route_parent_etx(self, value):
+        self.setUIntElement(self.offsetBits_route_parent_etx(), 16, value, 1)
+    
+    #
+    # Return the size, in bytes, of the field 'route.parent_etx'
+    #
+    def size_route_parent_etx(self):
+        return (16 / 8)
+    
+    #
+    # Return the size, in bits, of the field 'route.parent_etx'
+    #
+    def sizeBits_route_parent_etx(self):
+        return 16
     
diff --git a/support/make/blip.extra b/support/make/blip.extra
new file mode 100644 (file)
index 0000000..06c0c7f
--- /dev/null
@@ -0,0 +1,26 @@
+# -*- makefile -*-
+
+PFLAGS +=-DPACKET_LINK -DDEF_MEMCPY
+# PFLAGS += -DCC2420_HW_ACKNOWLEDGEMENTS
+PFLAGS += -DTOSH_DATA_LENGTH=102
+
+ifndef LOWPAN_ROOT
+  LOWPAN_ROOT=$(TOSROOT)
+endif
+
+PFLAGS+=-DENABLE_SPI0_DMA
+
+PFLAGS+=-I$(LOWPAN_ROOT)/support/sdk/c/blip/include/
+PFLAGS+=-I$(LOWPAN_ROOT)/support/sdk/c/blip/libtcp/
+PFLAGS+=-I$(LOWPAN_ROOT)/tos/lib/net/blip/
+PFLAGS+=-I$(LOWPAN_ROOT)/tos/lib/net/blip/interfaces/ 
+PFLAGS+=-I$(LOWPAN_ROOT)/tos/lib/net/blip/nwprog/
+PFLAGS+=-I$(LOWPAN_ROOT)/tos/lib/net/blip/shell/
+PFLAGS+=-I$(LOWPAN_ROOT)/tos/lib/net/blip/serial/
+
+PFLAGS+=$(LOWPAN_ROOT)/support/sdk/c/blip/lib6lowpan/lib6lowpan.c 
+PFLAGS+=$(LOWPAN_ROOT)/support/sdk/c/blip/lib6lowpan/lib6lowpanIP.c
+PFLAGS+=$(LOWPAN_ROOT)/support/sdk/c/blip/lib6lowpan/lib6lowpanFrag.c
+PFLAGS+=$(LOWPAN_ROOT)/support/sdk/c/blip/lib6lowpan/in_cksum.c
+PFLAGS+=$(LOWPAN_ROOT)/support/sdk/c/blip/lib6lowpan/ip_malloc.c
+
index 38caf5670a244d563f0ccd3bfe0456fd748c17e4..10cb1b93e8a957960f5a0f0c121722b6698ebae2 100644 (file)
@@ -1,12 +1,16 @@
 
+ifneq ($(filter lpl,$(MAKECMDGOALS)),)
+       EXTRATARGETS+=lpl
+endif
+
+lpl: all
+
 all:
        cd lib6lowpan && make
        cp lib6lowpan/lib6lowpan.a .
-
-       cd driver && make
-       cp driver/ip-driver .
+       cd driver && make $(EXTRATARGETS)
 
 clean:
        cd lib6lowpan && make clean
        cd driver && make clean
-       rm lib6lowpan.a ip-driver
+       rm -f lib6lowpan.a ip-driver
index 1b0e3cafb084a8b66f1d633c3349c0d965483697..b72b6bbf4604c0b9287cfb11dd6b79fb600840ab 100644 (file)
@@ -1,15 +1,15 @@
 
 SOURCES=serial_tun.c tun_dev.c hashtable.c routing.c nwstate.c \
-       logging.c config.c radvd-wrapper.c
+       logging.c config.c radvd-wrapper.c vty/util.c vty/vty.c \
+       netlink.c mcast.c
 
-RADVD=./radvd-1.0
-COMMON_SRC = $(RADVD)/log.c $(RADVD)/socket.c $(RADVD)/recv.c $(RADVD)/util.c $(RADVD)/radvd.h \
-       $(RADVD)/defaults.h $(RADVD)/pathnames.h \
-        $(RADVD)/includes.h
-radvd_SOURCES = $(COMMON_SRC) $(RADVD)/timer.c $(RADVD)/send.c $(RADVD)/process.c $(RADVD)/interface.c \
-        $(RADVD)/device.c $(RADVD)/device-common.c $(RADVD)/gram.h 
+COMMON_SRC = radvd/log.c radvd/socket.c radvd/recv.c radvd/util.c radvd/radvd.h \
+       radvd/defaults.h radvd/pathnames.h \
+        radvd/includes.h
+radvd_SOURCES = $(COMMON_SRC) radvd/timer.c radvd/send.c radvd/process.c radvd/interface.c \
+        radvd/device.c radvd/device-common.c radvd/gram.h 
 
-LIBS=../lib6lowpan.a ${TOSROOT}/support/sdk/c/sf/libmote.a 
+LIBS=../lib6lowpan.a ${TOSROOT}/support/sdk/c/sf/libmote.a
 TARGET=ip-driver
 INCLUDE=../include/
 
@@ -17,16 +17,28 @@ ifndef GCC
 GCC=gcc
 endif
 
-TFLAGS=-Wall -g -DPC
-TFLAGS+=-I${TOSROOT}/support/sdk/c/sf -I$(INCLUDE) -I$(RADVD)/
+TFLAGS=-Wall -DPC -D_GNU_SOURCE  -g
+TFLAGS+=-I${TOSROOT}/support/sdk/c/sf -I$(INCLUDE) -Iradvd/ -Ivty/
 
+# CFLAGS+= -DCENTRALIZED_ROUTING
+# CFLAGS+=-DFULL_PATH_INSTALL
 
 ifneq ($(filter sim-null,$(MAKECMDGOALS)),)
   TFLAGS+=-DSIM
 endif
 
-# CFLAGS+=-DFULL_PATH_INSTALL
+ifneq ($(filter lpl,$(MAKECMDGOALS)),)
+       TFLAGS+=-DBLIP_L2_RETRIES=1
+endif
+
+ifneq ($(filter sf,$(MAKECMDGOALS)),)
+       TFLAGS+=-DSF_SRC
+endif
+
+sf: all
+lpl: all
 all: $(TARGET)
+       ln -sf `pwd`/$(TARGET) ..
 
 sim: lib
        make $(TARGET) sim-null
@@ -38,5 +50,5 @@ $(TARGET): $(SOURCES) $(LIBS)
        $(GCC) $(TFLAGS) $(CFLAGS) -o $(TARGET) $(SOURCES) $(radvd_SOURCES) $(LIBS) -lm
 
 clean:
-       rm $(TARGET)
+       rm -f $(TARGET)
 
index 4cbb4f8fd64451cd138e6cb6f3fd56e2cfca39a4..48e53a12709a3ac3017be576b48b9a1eafeb4b77 100644 (file)
@@ -1,3 +1,27 @@
+/*
+ * "Copyright (c) 2008 The Regents of the University  of California.
+ * All rights reserved."
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice, the following
+ * two paragraphs and the author appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
+ *
+ */
+/*
+ * @author Stephen Dawson-Haggerty <stevedh@eecs.berkeley.edu>
+ */
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -9,8 +33,10 @@
 #include "ip.h"
 #include "config.h"
 #include "logging.h"
+#include "vty.h"
 
 #define BUF_LEN 200
+struct config *lastconfig;
 
 void rm_comment (char *buf) {
   while (*buf != '#' && *buf != '\0')
@@ -29,6 +55,9 @@ int config_parse(const char *file, struct config *c) {
   int gotargs = 0;
   if (fp == NULL) return 1;
 
+  // defaults
+  c->retries = BLIP_L2_RETRIES;
+
   while (fgets(real_buf, BUF_LEN, fp) != NULL) {
     buf = real_buf;
     rm_comment(buf);
@@ -53,6 +82,10 @@ int config_parse(const char *file, struct config *c) {
           break;
         }
       }
+    } else if (sscanf(buf, "retry %i\n", &c->retries) > 0) {
+      if (c->retries <= 0 || c->retries > 25) {
+        warn("retry value set to %i: outside of the recommended range (0,25]\n", c->retries);
+      }
     } else if (*buf != '\0') {
       // anything else indicates that there's invalid input.
       return 1;
@@ -62,18 +95,25 @@ int config_parse(const char *file, struct config *c) {
 
   if (gotargs != 3) return 1;
 
-  info("Read config from '%s'\n", file);
-  info("\tProxying neighbor advertisements to %s\n", c->proxy_dev);
-  info("\tUsing channel %i\n", c->channel);
+  info("Read config from '%s'\r\n", file);
+  info("Proxying neighbor advertisements to %s\r\n", c->proxy_dev);
+  info("Using channel %i\r\n", c->channel);
+  info("Retries: %i\r\n", c->retries);
+  lastconfig = c;
   return 0;
 }
 
-int config_print(struct config *c) {
+#define STR(X) #X
+
+void config_print(int fd, int argc, char **argv) { //struct config *c) {
+  VTY_HEAD;
   char buf[64];
-  printf ("configuration:\n");
-  inet_ntop(AF_INET6, &c->router_addr, buf, 64);
-  printf ("  router address: %s\n", buf);
-  printf("  proxy dev: %s\n", c->proxy_dev);
-  printf("  channel: %i\n", c->channel);
-  return 0;
+  VTY_printf ("configuration:\r\n");
+  inet_ntop(AF_INET6, &lastconfig->router_addr, buf, 64);
+  VTY_printf ("  router address: %s\r\n", buf);
+  VTY_printf("  proxy dev: %s\r\n", lastconfig->proxy_dev);
+  VTY_printf("  channel: %i\r\n", lastconfig->channel);
+  VTY_printf("  version: %s\r\n", STR($Id$));
+  VTY_printf("  retries: %i\r\n", lastconfig->retries);
+  VTY_flush();
 }
index 0a79dd3619162e0e7d7bb2ce1a1d90df195b316c..241771e955b887bdf81ec6807ec0e1b65f175fa8 100644 (file)
@@ -1,3 +1,28 @@
+/*
+ * "Copyright (c) 2008 The Regents of the University  of California.
+ * All rights reserved."
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice, the following
+ * two paragraphs and the author appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
+ *
+ */
+/*
+ * @author Stephen Dawson-Haggerty <stevedh@eecs.berkeley.edu>
+ */
+
 #ifndef _CONFIG_H
 #define _CONFIG_H
 
@@ -7,10 +32,11 @@ struct config {
   struct in6_addr router_addr;
   char proxy_dev[IFNAMSIZ];
   int channel;
+  int retries;
 };
 
 
 int config_parse(const char *file, struct config *c);
-int config_print(struct config *c);
+void config_print(int fd, int argc, char **argv);
 
 #endif
index 763357edce54955114b5c0e1dc14de17ad3f7757..64f11f86527f871f9937372da0422846dd4d53e5 100644 (file)
@@ -7,6 +7,8 @@
 #include <string.h>
 #include <math.h>
 
+#define iceil(X)  ((unsigned int)((X) + 1))
+
 /*
 Credit for primes table: Aaron Krowne
  http://br.endernet.org/~akrowne/
@@ -48,7 +50,7 @@ create_hashtable(unsigned int minsize,
     h->entrycount   = 0;
     h->hashfn       = hashf;
     h->eqfn         = eqf;
-    h->loadlimit    = (unsigned int) ceil(size * max_load_factor);
+    h->loadlimit    = (unsigned int) iceil(size * max_load_factor);
     return h;
 }
 
@@ -121,7 +123,7 @@ hashtable_expand(struct hashtable *h)
         }
     }
     h->tablelength = newsize;
-    h->loadlimit   = (unsigned int) ceil(newsize * max_load_factor);
+    h->loadlimit   = (unsigned int) iceil(newsize * max_load_factor);
     return -1;
 }
 
index 4df083db782e35d8ac918233a36c0725ce946299..610055cee8cfc687d0f35d46e4a9dc2209caa32e 100644 (file)
@@ -20,6 +20,8 @@
  *
  */
 #include <stdio.h>
+#include <errno.h>
+#include <string.h>
 #include <time.h>
 #include <sys/time.h>
 #include <stdarg.h>
@@ -30,20 +32,20 @@ loglevel_t log_level;
 FILE *log_dest;
 
 
-char *log_names[5] = {"DEBUG",
-                      "INFO",
-                      "WARN",
-                      "ERROR",
-                      "FATAL"};
+const char *log_names[5] = {"DEBUG",
+                            "INFO",
+                            "WARN",
+                            "ERROR",
+                            "FATAL"};
 
 static void timestamp(){
   struct timeval tv;
-  struct timezone tz;
   struct tm *ltime;
-  gettimeofday(&tv, &tz);
+  gettimeofday(&tv, NULL);
+  // automatically calls tzset()
   ltime = localtime(&tv.tv_sec);
-  fprintf(log_dest, "%02d:%02d:%02d.%03d: ", 
-          ltime->tm_hour, ltime->tm_min, ltime->tm_sec, (int)tv.tv_usec);
+  fprintf(log_dest, ISO8601_FMT(ltime, &tv));
+  fprintf(log_dest, ": ");
 }
 
 loglevel_t log_setlevel(loglevel_t l) {
@@ -71,6 +73,15 @@ void log_log  (loglevel_t level, const char *fmt, ...) {
     va_end(ap);
 }
 
+void log_fatal_perror(const char *msg) {
+  int in_errno = errno;
+  if (in_errno < 0) return;
+  timestamp();
+  fprintf(log_dest, "%s: ", log_names[LOGLVL_FATAL]);
+  if (msg != NULL) fprintf(log_dest, "%s: ", msg);
+  fprintf(log_dest, "%s\n", strerror(in_errno));
+}
+
 void log_clear (loglevel_t level, const char *fmt, ...) {
   if (log_level > level) return;
   va_list ap;
index c0f983763295b7cc91bbdccb26b4f6064d46b9d2..9a33426db431d83b9a883452b295613aa6ff5cc2 100644 (file)
@@ -34,7 +34,7 @@ typedef enum {
   LOGLVL_FATAL = 4,
 } loglevel_t;
 
-extern char *log_names[5];
+extern const char *log_names[5];
 extern loglevel_t log_level;
 extern FILE *log_dest;
 
@@ -44,6 +44,7 @@ loglevel_t log_setlevel(loglevel_t l);
 loglevel_t log_getlevel();
 
 void log_log  (loglevel_t level, const char *fmt, ...);
+void log_fatal_perror(const char *msg);
 void log_clear (loglevel_t level, const char *fmt, ...);
 
 #define debug(fmt, args...) \
@@ -59,6 +60,12 @@ void log_clear (loglevel_t level, const char *fmt, ...);
 
 #define log_fprintf(X, FMT, ...) ;
 
+
+#define ISO8601_FMT(ltime, tv) "%04d-%02d-%02dT%02d:%02d:%02d.%03d%s",   \
+    (ltime)->tm_year+1900, (ltime)->tm_mon+1, (ltime)->tm_mday,               \
+    (ltime)->tm_hour, (ltime)->tm_min, (ltime)->tm_sec, (int)(tv)->tv_usec/ 1000, \
+    tzname[0]
+
 void log_dump_serial_packet(unsigned char *packet, const int len);
 
 #endif
diff --git a/support/sdk/c/blip/driver/mcast.c b/support/sdk/c/blip/driver/mcast.c
new file mode 100644 (file)
index 0000000..4cd011b
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+ * "Copyright (c) 2008, 2009 The Regents of the University  of California.
+ * All rights reserved."
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice, the following
+ * two paragraphs and the author appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <net/if.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <arpa/inet.h>
+
+#include "mcast.h"
+#include "logging.h"
+
+int __mcast_sock;
+struct sockaddr_in6 __mcast_addr;
+char __mcast_dev[IFNAMSIZ];
+
+static int open_loopback(struct sockaddr_in6 *laddr) {
+
+  /* we need to send to the loopback address, not the group  */
+  memcpy(&__mcast_addr.sin6_addr, &in6addr_loopback, sizeof(struct in6_addr));
+  memcpy(&laddr->sin6_addr, &in6addr_loopback, sizeof(struct in6_addr));
+
+  /* bind to the local address (we're already BINDTODEVICE, so this
+     might be redundant)  */
+  if (bind(__mcast_sock, (struct sockaddr *)laddr, sizeof(struct sockaddr_in6)) < 0) {
+    log_fatal_perror("binding multicast socket failed");
+    goto fail;
+  }
+
+  return __mcast_sock;
+ fail:
+  close(__mcast_sock);
+  return -1;
+}
+
+int mcast_start(char *dev) {
+  struct ipv6_mreq join;
+  struct ifreq ifr;
+  int opt;
+  int ifindex = if_nametoindex(dev);
+
+  __mcast_addr.sin6_family = AF_INET6;
+  inet_pton(AF_INET6, "ff12::cafe:babe", &__mcast_addr.sin6_addr);
+  __mcast_addr.sin6_port = htons(10023);
+  __mcast_addr.sin6_scope_id = ifindex;
+
+  strncpy(__mcast_dev, dev, IFNAMSIZ);
+
+  struct sockaddr_in6 laddr = {
+    .sin6_family = AF_INET6,
+    .sin6_port = __mcast_addr.sin6_port,
+    .sin6_addr = IN6ADDR_ANY_INIT,
+    .sin6_scope_id = ifindex,
+  };
+
+
+  /* get the socket */
+  if ((__mcast_sock = socket(PF_INET6, SOCK_DGRAM, 0)) < 0) {
+    log_fatal_perror("error opening socket");
+    return -1;
+  }
+
+  /* bind it to the device we're going to join the link-local
+     multicast group on */
+  memset(&ifr, 0, sizeof(struct ifreq));
+  strncpy(ifr.ifr_name, dev, IFNAMSIZ);
+  if (setsockopt(__mcast_sock, SOL_SOCKET, SO_BINDTODEVICE,
+                 (char *)&ifr, sizeof(struct ifreq)) < 0) {
+    log_fatal_perror("could not BINDTODEVICE");
+    goto fail;
+  }
+
+  /* the loopback on linux doesn't support multicast. that's okay,
+     though, since we can just attach to it and use it to feed routing
+     reports back into us.  */
+  if (strncmp(dev, "lo", 2) == 0) {
+    return open_loopback(&laddr);
+  }
+
+  /* receive messages we send */
+  opt = 1;
+  if (setsockopt(__mcast_sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &opt, sizeof(opt)) < 0) {
+    log_fatal_perror("setting loop failed");
+    goto fail;
+  }
+
+  opt = 1;
+  if (setsockopt(__mcast_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
+    log_fatal_perror("setting reuse failed");
+    goto fail;
+  }
+
+  /* bind to the local address (we're already BINDTODEVICE, so this
+     might be redundant)  */
+  if (bind(__mcast_sock, (struct sockaddr *)&laddr, sizeof(struct sockaddr_in6)) < 0) {
+    log_fatal_perror("binding multicast socket failed");
+    goto fail;
+  }
+
+  memset(&join, 0, sizeof(struct ipv6_mreq));
+  memcpy(&join.ipv6mr_multiaddr, &__mcast_addr.sin6_addr, sizeof(struct in6_addr));
+  join.ipv6mr_interface = ifindex;
+
+  if (setsockopt(__mcast_sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &join, sizeof(join)) < 0) {
+    log_fatal_perror("error joining group");
+    goto fail;
+  }
+
+  return __mcast_sock;
+ fail:
+  close(__mcast_sock);
+  return -1;
+}
+
+
+
+int mcast_recvfrom(struct sockaddr_in6 *from, void *buf, int len) {
+  int rc;
+  socklen_t fromlen = sizeof(struct sockaddr_in6);
+
+  if ((rc = recvfrom(__mcast_sock, buf, len, 0, (struct sockaddr *)from, &fromlen)) < 0) { 
+    log_fatal_perror("multicast receive");
+    return -1;
+  }
+  return rc;
+}
+
+int mcast_send(void *data, int len) {
+  int rc;
+
+  if ((rc = sendto(__mcast_sock, data, len, 0, (struct sockaddr *)&__mcast_addr, sizeof(struct sockaddr_in6))) < 0) {
+    log_fatal_perror("send failed");
+    return -1;
+  }
+  return 0;
+}
+
+#if 0
+int main(int argc, char **argv) {
+
+  char *dev = argv[1];
+  int fd;
+  struct sockaddr_in6 grp = {
+    .sin6_port = htons(10620),
+  };
+
+  if (argc < 2) {
+    printf("\n\t%s <iface>\n\n", argv[0]);
+    exit(1);
+  }
+
+  inet_pton(AF_INET6, "ff12::1abc", &grp.sin6_addr);
+
+  fd = mcast_start(&grp, dev);
+  printf("mcast start done: %i\n", fd);
+
+  struct sockaddr_in6 from;
+  char rxbuf[1024];
+  int len;
+
+  if (argc == 3 && strcmp(argv[2], "listen") == 0) {
+
+    printf("listening\n");
+
+    while (1) {
+      len = mcast_recvfrom(&from, rxbuf, 1024);
+      if (len > 0) {
+        rxbuf[len] = '\0';
+        puts(rxbuf);
+      }
+    }
+  } else {
+    char *msg = "hello, mcast world!";
+    while (1) {
+      mcast_send(msg, strlen(msg)+1);
+      sleep(1);
+      len = mcast_recvfrom(&from, rxbuf, 1024);
+      if (len > 0) {
+        rxbuf[len] = '\0';
+        puts(rxbuf);
+      }
+      
+    }
+  }
+}
+#endif
diff --git a/support/sdk/c/blip/driver/mcast.h b/support/sdk/c/blip/driver/mcast.h
new file mode 100644 (file)
index 0000000..a0b9b1c
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * "Copyright (c) 2008, 2009 The Regents of the University  of California.
+ * All rights reserved."
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice, the following
+ * two paragraphs and the author appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
+ *
+ */
+#ifndef _MCAST_H
+#define _MCAST_H
+
+int mcast_start(char *dev);
+int mcast_recvfrom(struct sockaddr_in6 *from, void *buf, int len);
+int mcast_send(void *data, int len);
+
+#endif
+
diff --git a/support/sdk/c/blip/driver/netlink.c b/support/sdk/c/blip/driver/netlink.c
new file mode 100644 (file)
index 0000000..1ee1231
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ * "Copyright (c) 2008, 2009 The Regents of the University  of California.
+ * All rights reserved."
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice, the following
+ * two paragraphs and the author appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <net/if.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <arpa/inet.h>
+
+#include "logging.h"
+
+static int __nl_sock;
+static int __if_index;
+
+/* 
+ * Start a netlink session.
+ *
+ */
+int nl_init() {
+  struct sockaddr_nl nladdr;
+
+  /* with any luck, we've constructed the message, can send it to the
+     kernel, and have a beer. */
+  if ((__nl_sock = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0) {
+    log_fatal_perror("PACKETLINK socket");
+    return -1;
+  }
+
+  memset(&nladdr, 0, sizeof(nladdr));
+  nladdr.nl_family = AF_NETLINK;
+  nladdr.nl_groups = 0;
+  if (bind(__nl_sock, (struct sockaddr*)&nladdr, sizeof(nladdr)) < 0) {
+    close(__nl_sock);
+    log_fatal_perror("Cannot bind netlink socket");
+    return -1;
+  }
+  return 0;
+}
+
+int nl_shutdown() {
+  close(__nl_sock);
+  __nl_sock = __if_index = -1;
+  return 0;
+}
+
+/*
+ * Start proxying addr on device 'dev'
+ */
+static int nl_cmd(int type, int flags, struct in6_addr *addr, char *dev) {
+  static int seq;
+  struct {
+    struct nlmsghdr    n;
+    struct ndmsg               ndm;
+    char                       buf[256];
+  } req;
+  struct rtattr *rta;
+  struct sockaddr_nl nladdr;
+
+  memset(&req, 0, sizeof(req));
+  
+  /* set up our request packet with one request */
+  req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg));
+  req.n.nlmsg_flags = NLM_F_REQUEST | flags; 
+  req.n.nlmsg_type = type;
+  req.ndm.ndm_family = AF_INET6;
+  req.ndm.ndm_state = NUD_PERMANENT;
+  req.ndm.ndm_ifindex = if_nametoindex(dev);
+
+  /* add the actual address to the tail of the message  */
+  int nl_len = RTA_LENGTH(sizeof(struct in6_addr));
+  if (NLMSG_ALIGN(req.n.nlmsg_len) + RTA_ALIGN(nl_len) > sizeof(req)) {
+    fprintf(stderr, "message too long\n");
+    return -1;
+  }
+
+  rta = ((struct rtattr *) (((void *) (&req.n)) + NLMSG_ALIGN((req.n.nlmsg_len))));
+  rta->rta_type = NDA_DST;
+  rta->rta_len = nl_len;
+  memcpy(RTA_DATA(rta), addr, sizeof(struct in6_addr));
+  req.n.nlmsg_len = NLMSG_ALIGN(req.n.nlmsg_len) + RTA_ALIGN(nl_len);
+
+  struct iovec iov = {
+    .iov_base = (void*) &req.n,
+    .iov_len = req.n.nlmsg_len
+  };
+  struct msghdr msg = {
+    .msg_name = &nladdr,
+    .msg_namelen = sizeof(nladdr),
+    .msg_iov = &iov,
+    .msg_iovlen = 1,
+  };
+
+  memset(&nladdr, 0, sizeof(nladdr));
+  nladdr.nl_family = AF_NETLINK;
+  req.n.nlmsg_seq = seq++;
+  
+  if (sendmsg(__nl_sock, &msg, 0) < 0) {
+    log_fatal_perror("RTNETLINK");
+    return -1;
+  }
+  /* TODO : nonblocking receive to check for error? */
+
+
+  return 0;
+
+  ///
+
+  char buf[16384];
+
+       iov.iov_base = buf;
+       while (1) {
+               int status;
+               struct nlmsghdr *h;
+
+               iov.iov_len = sizeof(buf);
+               status = recvmsg(__nl_sock, &msg, 0);
+
+               if (status < 0) {
+                       if (errno == EINTR)
+                               continue;
+                       log_fatal_perror("OVERRUN");
+                       continue;
+               }
+
+               if (status == 0) {
+                       fprintf(stderr, "EOF on netlink\n");
+                       return -1;
+               }
+
+               h = (struct nlmsghdr*)buf;
+               while (NLMSG_OK(h, status)) {
+                       int err;
+
+                       if (nladdr.nl_pid != 0 ||
+                           h->nlmsg_pid != 0 ||
+                           h->nlmsg_seq != seq) {
+                                       if (err < 0)
+                                               return err;
+
+                               goto skip_it;
+                       }
+
+                       if (h->nlmsg_type == NLMSG_DONE)
+                               return 0;
+                       if (h->nlmsg_type == NLMSG_ERROR) {
+                               struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
+                               if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) {
+                                       fprintf(stderr, "ERROR truncated\n");
+                               } else {
+                                       errno = -err->error;
+                                       log_fatal_perror("RTNETLINK answers");
+                               }
+                               return -1;
+                       }
+skip_it:
+                       h = NLMSG_NEXT(h, status);
+               }
+               if (msg.msg_flags & MSG_TRUNC) {
+                       fprintf(stderr, "Message truncated\n");
+                       continue;
+               }
+               if (status) {
+                       fprintf(stderr, "!!!Remnant of size %d\n", status);
+                       exit(1);
+               }
+       }
+  return 0;
+}
+
+int nl_nd_add_neigh(struct in6_addr *addr, char *dev) {
+  return nl_cmd(RTM_NEWNEIGH, NLM_F_CREATE|NLM_F_REPLACE, addr, dev);
+}
+int nl_nd_del_neigh(struct in6_addr *addr, char *dev) {
+  return nl_cmd(RTM_DELNEIGH, 0, addr, dev);
+}
+int nl_nd_add_proxy(struct in6_addr *addr, char *dev) {
+  // SDH : shit, the netlink proxy doesn't work (the add neighbor
+  // did).  I WILL fix it... later.
+  char buf [100], cmd[256];
+  inet_ntop(AF_INET6, addr, buf, 100);
+  snprintf(cmd, sizeof(cmd), "ip neigh add proxy %s dev %s\n", buf, dev);
+  system(cmd);
+  return 0;
+
+  // return nl_cmd(RTM_NEWNEIGH, NLM_F_CREATE|NLM_F_EXCL|NTF_PROXY, addr, dev);
+}
diff --git a/support/sdk/c/blip/driver/netlink.h b/support/sdk/c/blip/driver/netlink.h
new file mode 100644 (file)
index 0000000..b6f03de
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * "Copyright (c) 2008, 2009 The Regents of the University  of California.
+ * All rights reserved."
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice, the following
+ * two paragraphs and the author appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
+ *
+ */
+#ifndef _NETLINK_H
+#define _NETLINK_H
+
+/* 
+ * The netlink interface to the kernel is not the most concise one
+ * imaginable, but seems like the only way to manipulate the ND state
+ * from userland, at least as of 2.6.22.  
+ */
+
+int nl_init();
+int nl_shutdown();
+
+int nl_nd_add_neigh(struct in6_addr *addr, char *dev);
+int nl_nd_del_neigh(struct in6_addr *addr, char *dev);
+int nl_nd_add_proxy(struct in6_addr *addr, char *dev);
+
+
+#endif
+
index 965754013b8ddbecf22e78bbaf3ea370099d0735..0ef8ed6b10f9a5dd8a63af2bef23992d1e4926de 100644 (file)
 #include <stdio.h>
 #include <stdlib.h>
 #include <float.h>
+#include <time.h>
+#include <sys/time.h>
 #include "nwstate.h"
 #include "hashtable.h"
 #include "logging.h"
 #include "lib6lowpan.h"
 #include "routing.h"
+#include "vty.h"
 
 struct hashtable *links;
 struct hashtable *routers;
@@ -100,44 +103,112 @@ int nw_print_dotfile(char *filename) {
 }
 
 
-void nw_print_routes() {
+void nw_print_routes(int fd, int argc, char **argv) {
+  VTY_HEAD;
   router_t *r,*s;
   for (r = router_list; r != NULL; r = r->next) {
-    log_clear(LOGLVL_INFO, "  0x%x: ", r->id);
+    VTY_printf("  0x%x: ", r->id);
     for (s = r->sp.prev; s != NULL; s = s->sp.prev) {
-      log_clear(LOGLVL_INFO, "0x%x ", s->id);
+      VTY_printf("0x%x", s->id);
+      if (r->isController) VTY_printf("[C] ");
+      else VTY_printf(" ");
     }
-    log_clear(LOGLVL_INFO, "\n");
+    VTY_printf("\r\n");
+    VTY_flush();
   }
 }
 
-void nw_test_routes() {
+void nw_test_routes(int fd, int argc, char **argv) {
   node_id_t dest = ntohs(__my_address.s6_addr16[7]);
   debug("nwstate: computing new routes (root: 0x%x)\n", ntohs(__my_address.s6_addr16[7]));
   compute_routes(dest);
 }
 
-void nw_print_links() {
+void nw_print_links(int fd, int argc, char **argv) {
+  VTY_HEAD;
+  struct tm *ltime;
+  int target = -1;
   router_t *r;
   link_t *l;
+
+  if (argc == 2)
+    target = atoi(argv[1]);
+
   for (r = router_list; r != NULL; r = r->next) {
-    log_clear(LOGLVL_INFO, " 0x%x: dist: %.1f\n", r->id, r->sp.dist);
+    char flags[16]; int pos = 0;
+    if (target >= 0 && r->id != target) continue;
+
+    flags[0] = '\0';
+    if (r->isProxying || r->isController) {
+      flags[pos++] = '['; 
+      if (r->isController) flags[pos++] = 'C';
+      if (r->isProxying) flags[pos++] = 'P';
+      flags[pos++] = ']';
+      flags[pos++] = '\0';
+    }
+
+    VTY_printf(" 0x%x%s: dist: ", r->id, flags);
+    if (r->sp.dist == FLT_MAX)
+      VTY_printf("Inf");
+    else
+      VTY_printf("%.1f", r->sp.dist);
+    if (!r->isController) {
+      ltime = localtime(&r->lastReport.tv_sec);
+      VTY_printf(" reported: " ISO8601_FMT(ltime, &r->lastReport));
+    }
+
+    VTY_printf("\r\n");
     for (l = r->links; l != NULL; l = (r == l->n1) ? l->next1 : l->next2) {
       if (r == l->n1) {
-        log_clear(LOGLVL_INFO, "  --> 0x%x [%.1f]\n", l->n2->id, l->qual);
+        VTY_printf("  --> 0x%x [%.1f]\r\n", l->n2->id, l->qual);
       }
     }
-    log_clear(LOGLVL_INFO, "\n");
+    VTY_printf("\r\n");
+    VTY_flush();
+  }
+}
+
+void nw_add_sticky_edge(int fd, int argc, char **argv) {
+  VTY_HEAD;
+  int v1, v2;
+  if (argc == 3) {
+    link_t *l;
+    struct topology_entry te;
+    v1 = atoi(argv[1]);
+    v2 = atoi(argv[2]);
+    VTY_printf("adding sticky edge between %i and %i\r\n", v1, v2);
+    te.etx = 10;
+    te.conf = 255;
+    te.hwaddr = htons(v2);
+    l = nw_add_incr_edge(v1, &te);
+    l->marked = L_STICKY;
+  } else {
+    VTY_printf("add a link: 'a <n1> <n2>'\r\n");
   }
+  VTY_flush();
 }
 
+void nw_inval_node_sh(int fd, int argc, char **argv) {
+  VTY_HEAD;
+  int int_arg;
+  if (argc == 2) {
+    int_arg = atoi(argv[1]);
+    VTY_printf("invalidating node 0x%x\n", int_arg);
+    nw_inval_node(int_arg);
+  }
+  VTY_flush();
+}
 //
 // helpers
 // 
 
+router_t *nw_get_router(node_id_t rid) {
+  return hashtable_search(routers, &rid);
+}
+
 router_t *get_insert_router(node_id_t rid) {
   router_key_t *key;
-  router_t *ret = hashtable_search(routers, &rid);
+  router_t *ret = nw_get_router(rid);
   if (ret == NULL) {
     key = (router_key_t *)malloc(sizeof(router_key_t));
     ret = (router_t *)malloc(sizeof(router_t));
@@ -147,6 +218,10 @@ router_t *get_insert_router(node_id_t rid) {
     ret->next = router_list;
 
     ret->reports = 0;
+    ret->lastSeqno = -1;
+
+    ret->isProxying = FALSE;
+    ret->isController = FALSE;
 
     ret->sp.dist = FLT_MAX;
     ret->sp.prev = NULL;
@@ -155,7 +230,6 @@ router_t *get_insert_router(node_id_t rid) {
 
     *key = rid;
     hashtable_insert(routers, key, ret);
-    routing_add_table_entry(rid);
   }
   return ret;
 }
@@ -166,8 +240,11 @@ router_t *get_insert_router(node_id_t rid) {
 //
 
 int nw_init() {
+  router_t *r;
   links   = create_hashtable(16, hash_link,   link_equal);
   routers = create_hashtable(16, hash_router, router_equal);
+  r = get_insert_router(ntohs(__my_address.s6_addr16[7]));
+  r->isController = TRUE;
   return 0;
 }
 
@@ -175,7 +252,7 @@ int nw_init() {
  * Adds an observation of the link (v1, v2) to the database.  This
  * implicitly adds the reverse edge for now, as well.
  */
-int nw_add_incr_edge(node_id_t v1, struct topology_entry *te) {
+link_t *nw_add_incr_edge(node_id_t v1, struct topology_entry *te) {
   link_key_t key;
   link_t *link_str;
   node_id_t v2 = ntoh16(te->hwaddr);
@@ -212,7 +289,7 @@ int nw_add_incr_edge(node_id_t v1, struct topology_entry *te) {
 
   } 
 
-  link_str->marked = 1;
+  link_str->marked = L_REPORTED;
   link_str->qual = ((float)(te->etx)) / 10.0;
   link_str->conf = te->conf;
   debug("nw_add_incr_edge [%i -> %i]: qual: %f conf: %i\n", 
@@ -220,7 +297,7 @@ int nw_add_incr_edge(node_id_t v1, struct topology_entry *te) {
   (v1 == link_str->n1->id) ? link_str->n1_reportcount++ :
     link_str->n2_reportcount++;
 
-  return 0;
+  return link_str;
 }
 
 /*
@@ -343,6 +420,8 @@ path_t *nw_get_route(node_id_t v1, node_id_t v2) {
     debug("nw_get_route: computing new routes\n");
     compute_routes(v1);
   }
+  if (to->sp.prev == NULL) return NULL;
+
   // now the routes should be valid;
   for (r = to; r != NULL; r = r->sp.prev) {
     // this both constructs the return value and reverses the path,
@@ -355,6 +434,7 @@ path_t *nw_get_route(node_id_t v1, node_id_t v2) {
       new->node = r->id;
       new->next = ret;
       new->length = (ret == NULL) ? 1 : ret->length + 1;
+      new->isController = r->isController;
       ret = new;
     }
   }
@@ -384,6 +464,25 @@ void remove_link(router_t *r, link_t *link) {
   warn("link_remove: link not removed (inconsistent state)?\n");
 }
 
+void nw_remove_link(node_id_t n1, node_id_t n2) {
+  router_t *r1 = nw_get_router(n1);
+  router_t *r2 = nw_get_router(n2);
+  link_t *link;
+  link_key_t key;
+
+  key.r1 = n1;
+  key.r2 = n2;
+  link = hashtable_search(links, &key);
+  if (link != NULL) {
+    routes_out_of_date = 1;
+
+    remove_link(r1, link);
+    remove_link(r2, link);
+    hashtable_remove(links, &key);
+    free(link);
+  }
+}
+
 void nw_inval_node(node_id_t v) {
   router_t *cur;
   link_t *l, *next;
@@ -432,7 +531,7 @@ void nw_unmark_links(node_id_t v) {
   if (cur == NULL) return;
 
   for (l = cur->links; l != NULL; l = (cur == l->n1) ? l->next1 : l->next2) {
-    l->marked = 0;
+    if (l->marked == L_REPORTED) l->marked = L_UNREPORTED;
   }
 
 }
@@ -463,7 +562,7 @@ void nw_clear_unmarked(node_id_t v) {
   if (cur == NULL) return;
 
   for (l = cur->links; l != NULL; l = (cur == l->n1) ? l->next1 : l->next2) {
-    if (l->marked == 0) {
+    if (l->marked == L_UNREPORTED) {
       // it's not marked, so it wasn't contained in the topology report
       if (((cur == l->n1) ? l->n2_reportcount : l->n1_reportcount) == 0) {
         // it has never been reported by the router on the other end, so we
@@ -479,7 +578,7 @@ void nw_clear_unmarked(node_id_t v) {
         // observation count to zero.
         if (cur == l->n1)  l->n1_reportcount = 0 ;
         else l->n2_reportcount = 0;
-        l->marked = 1;
+        l->marked = L_REPORTED;
         // router_t *otherguy = (cur == l->n1) ? l->n2 : l->n1;
         //debug("unseting obs count on 0x%x -> 0x%x\n", cur->id, otherguy->id);
       }
@@ -501,3 +600,23 @@ void nw_clear_unmarked(node_id_t v) {
 
   age_routers();
 }
+
+
+void nw_add_controller(node_id_t node) {
+  router_t *r, *thisController;
+
+  struct topology_entry te;
+  te.etx = 1;
+  te.conf = 255;
+
+  thisController = nw_get_router(node);
+  if (!thisController) return;
+
+  thisController->isController = TRUE;
+  for (r = router_list; r != NULL; r = r->next) {
+    if (r->isController && r != thisController) {
+      te.hwaddr = htons(r->id);
+      nw_add_incr_edge(node, &te);
+    }
+  }
+}
index 7374047d56996036f6fe56991ce6c3ad3664079f..c888e6a608aabb2b8071cd62fe9bbdf4d5ab16e3 100644 (file)
  *
  */
 
+enum {
+  L_UNREPORTED,
+  L_REPORTED,
+  L_STICKY,
+};
+
 typedef uint16_t node_id_t;
 
 struct route_path {
   uint16_t len;
-  hw_addr_t path[0];
+  ieee154_saddr_t path[0];
 };
 
 typedef struct {
@@ -72,7 +78,15 @@ typedef struct router {
   node_id_t id;
   link_t *links;
   struct router *next;
+
   int reports;
+  int lastSeqno;
+  struct timeval lastReport;
+
+  bool_t isProxying;
+  bool_t isController;
+
+  
 
   // fields for shortest path
   // computation
@@ -91,22 +105,29 @@ typedef struct router {
 typedef struct path {
   node_id_t node;
   int length;
+  bool_t isController;
   struct path *next;
 } path_t;
 
 int nw_init();
-int nw_add_incr_edge(node_id_t v1, struct topology_entry *v2);
+link_t *nw_add_incr_edge(node_id_t v1, struct topology_entry *v2);
 void nw_report_node(node_id_t v);
 path_t *nw_get_route(node_id_t v1, node_id_t v2);
 void nw_free_path(path_t *path);
 void nw_inval_node(node_id_t v);
+router_t *nw_get_router(node_id_t rid);
+router_t *get_insert_router(node_id_t rid);
+void nw_add_controller(node_id_t node);
+void nw_remove_link(node_id_t n1, node_id_t n2);
 
 void nw_unmark_links(node_id_t v);
 void nw_clear_unmarked(node_id_t v);
 
 int  nw_print_dotfile(char *filename);
-void nw_print_routes();
-void nw_print_links();
-void nw_test_routes();
+void nw_print_routes(int fd, int argc, char **argv);
+void nw_print_links(int fd, int argc, char **argv);
+void nw_test_routes(int fd, int argc, char **argv);
+void nw_add_sticky_edge(int fd, int argc, char **argv);
+void nw_inval_node_sh(int fd, int argc, char **argv);
 
 #endif
index b1c13a599913355637f2ddb2ee51525e6ec87a52..efd4219b7843da45a6148c2f78dbfbf3e5bd19ca 100644 (file)
@@ -1,3 +1,24 @@
+/*
+ * "Copyright (c) 2008, 2009 The Regents of the University  of California.
+ * All rights reserved."
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice, the following
+ * two paragraphs and the author appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
+ *
+ */
 /* config.h.  Generated automatically by configure.  */
 /* config.h.in.  Generated automatically from configure.in by autoheader.  */
 
index bcd9589cb8deb2cb0f1edae4f41fe0f3f1e8a39d..2bf38e9c8b904446cb004dfa68cc0babd071a718 100644 (file)
@@ -230,19 +230,19 @@ process_ra(struct Interface *iface, unsigned char *msg, int len,
        if ((radvert->nd_ra_curhoplimit && iface->AdvCurHopLimit) && 
           (radvert->nd_ra_curhoplimit != iface->AdvCurHopLimit))
        {
-               flog(LOG_WARNING, "our AdvCurHopLimit on %s doesn't agree with %s",
+               dlog(LOG_WARNING, LOG_INFO, "our AdvCurHopLimit on %s doesn't agree with %s",
                        iface->Name, addr_str);
        }
 
        if ((radvert->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED) && !iface->AdvManagedFlag)
        {
-               flog(LOG_WARNING, "our AdvManagedFlag on %s doesn't agree with %s",
+               dlog(LOG_WARNING, LOG_INFO, "our AdvManagedFlag on %s doesn't agree with %s",
                        iface->Name, addr_str);
        }
        
        if ((radvert->nd_ra_flags_reserved & ND_RA_FLAG_OTHER) && !iface->AdvOtherConfigFlag)
        {
-               flog(LOG_WARNING, "our AdvOtherConfigFlag on %s doesn't agree with %s",
+               dlog(LOG_WARNING, LOG_INFO, "our AdvOtherConfigFlag on %s doesn't agree with %s",
                        iface->Name, addr_str);
        }
 
@@ -251,14 +251,14 @@ process_ra(struct Interface *iface, unsigned char *msg, int len,
        if ((radvert->nd_ra_reachable && iface->AdvReachableTime) &&
           (ntohl(radvert->nd_ra_reachable) != iface->AdvReachableTime))
        {
-               flog(LOG_WARNING, "our AdvReachableTime on %s doesn't agree with %s",
+               dlog(LOG_WARNING, LOG_INFO, "our AdvReachableTime on %s doesn't agree with %s",
                        iface->Name, addr_str);
        }
        
        if ((radvert->nd_ra_retransmit && iface->AdvRetransTimer) &&
           (ntohl(radvert->nd_ra_retransmit) != iface->AdvRetransTimer))
        {
-               flog(LOG_WARNING, "our AdvRetransTimer on %s doesn't agree with %s",
+               dlog(LOG_WARNING, LOG_INFO, "our AdvRetransTimer on %s doesn't agree with %s",
                        iface->Name, addr_str);
        }
 
@@ -332,7 +332,7 @@ process_ra(struct Interface *iface, unsigned char *msg, int len,
 
                                        if (valid != prefix->AdvValidLifetime)
                                        {
-                                               flog(LOG_WARNING, "our AdvValidLifetime on"
+                                          dlog(LOG_WARNING, LOG_INFO, "our AdvValidLifetime on"
                                                 " %s for %s doesn't agree with %s",
                                                 iface->Name,
                                                 prefix_str,
@@ -341,7 +341,7 @@ process_ra(struct Interface *iface, unsigned char *msg, int len,
                                        }
                                        if (preferred != prefix->AdvPreferredLifetime)
                                        {
-                                               flog(LOG_WARNING, "our AdvPreferredLifetime on"
+                                          dlog(LOG_WARNING, LOG_INFO, "our AdvPreferredLifetime on"
                                                 " %s for %s doesn't agree with %s",
                                                 iface->Name,
                                                 prefix_str,
index b5562aa2b7c4f9f8837fa4b15d658f378704ad22..73e605961904aabffbd56eb813343e10f5df1e68 100644 (file)
@@ -1,3 +1,24 @@
+/*
+ * "Copyright (c) 2008, 2009 The Regents of the University  of California.
+ * All rights reserved."
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice, the following
+ * two paragraphs and the author appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
+ *
+ */
 /* 
  * radvd-wrapper.c
  * author: Stephen Dawson-Haggerty <stevedh@eecs.berkeley.edu>
@@ -158,5 +179,7 @@ int radvd_init(char *ifname, struct config *c) {
   // config_interface();
   radvd_kickoff_adverts();
 
+  set_debuglevel(0);
+
   return sock;
 }
index f883f32c7d28a7c1bcd7975ac85fec3b2db7f9cd..11059e14f597a4c55d34022d434a1cd2d9f2f5ec 100644 (file)
 #include <stdio.h>
 #include <stdlib.h>
 #include <net/if.h>
+#include <arpa/inet.h>
+#include <sys/select.h>
+#include <net/route.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
 
 #include <6lowpan.h>
 #include <lib6lowpan.h>
 #include "nwstate.h"
 #include "logging.h"
 #include "config.h"
+#include "mcast.h"
+#include "netlink.h"
 
-static hw_addr_t my_short_addr;
+static ieee154_saddr_t my_short_addr;
 extern struct in6_addr  __my_address;
 
 char proxy_dev[IFNAMSIZ], tun_dev[IFNAMSIZ];
+int mcast_sock;
+
+char report_buf[ROUTMSGSIZ];
 
 /*
  * Call to setup routing tables.
  *
  */
-uint8_t routing_init(struct config *c, char *tun_name) {
-  nw_init();
+int routing_init(struct config *c, char *tun_name) {
+  FILE *fd;
+  char buf[256];
   my_short_addr = ntohs(__my_address.s6_addr16[7]);
   strncpy(proxy_dev, c->proxy_dev, IFNAMSIZ);
   strncpy(tun_dev, tun_name, IFNAMSIZ);
-/*   nl_fd = socket(AF_NETLINK, SOCK_RAW, protocol); */
-/*   if (nl_fd < 0)  */
-/*     return -1; */
 
+  // set up the network state data structures
+  nw_init();
+
+  // start a netlink session to the kernel
+  nl_init();
+
+  mcast_sock = mcast_start(proxy_dev);;
+
+  if ((fd = fopen("/proc/sys/net/ipv6/conf/all/forwarding", "w")) == NULL) {
+    log_fatal_perror("enable forwarding");
+    return -1;
+  }
+  fprintf(fd, "1");
+  fclose(fd);
+
+  snprintf(buf, sizeof(buf), "/proc/sys/net/ipv6/conf/%s/proxy_ndp", proxy_dev);
+  if ((fd = fopen(buf, "w")) == NULL) {
+    warn("unable to enable IPv6 ND proxy on %s\n", proxy_dev);
+  } else {
+    fprintf(fd, "1");
+    fclose(fd);
+  }
+
+  return (mcast_sock >= 0) ? 0 : -1;
+}
+
+int routing_add_fds(fd_set *fds) {
+  if (mcast_sock >=0) {
+    FD_SET(mcast_sock, fds);
+  }
+  return mcast_sock;
+}
+
+int route_cmd(int cmd, struct in6_addr *dest, char *dev) {
+  struct in6_rtmsg rt;
+  memset((char *) &rt, 0, sizeof(struct in6_rtmsg));
+  memcpy(&rt.rtmsg_dst, dest, sizeof(struct in6_addr));
+
+  rt.rtmsg_flags = RTF_UP | RTF_HOST;
+  rt.rtmsg_metric = 1;
+  rt.rtmsg_dst_len = 128;
+  rt.rtmsg_ifindex = if_nametoindex(dev);
+
+  return ioctl(mcast_sock, cmd, &rt);
+}        
+
+
+int routing_process(fd_set *fds) {
+  struct sockaddr_in6 from;
+  char buf[ROUTMSGSIZ], *cur, printbuf[100];
+  struct routing_message *rmsg;
+  struct topology_header_package *th;
+  int len;
+  struct in6_addr addr;
+
+  if (mcast_sock < 0 || !FD_ISSET(mcast_sock, fds)) return 0;
+
+  len = mcast_recvfrom(&from, buf, sizeof(buf));
+  rmsg = (struct routing_message *)buf;
+
+  inet_ntop(AF_INET6, &from.sin6_addr, printbuf, sizeof(printbuf));
+  debug("processing routing message from %s type %i\n", printbuf, rmsg->type);
+
+  memset(&addr, 0, sizeof(struct in6_addr));
+  memcpy(addr.s6_addr, __my_address.s6_addr, 8);
+
+  switch (rmsg->type) {
+  case RMSG_TOPOLOGY:
+    cur = rmsg->data;
+    len -= sizeof(struct routing_message);
+    while (len > 0) {
+      router_t *router;
+      int header_len, i;
+      node_id_t reporter;
+
+      th = (struct topology_header_package *)cur;
+      header_len = ntohs(th->len);
+      reporter = ntohs(th->reporter);
+
+      nw_unmark_links(reporter);
+      for (i = 0; i < (header_len - sizeof(struct topology_header_package))/sizeof(struct topology_entry); i++) {
+
+        nw_add_incr_edge(reporter, &th->topo[i]);
+
+        router = nw_get_router(reporter);
+        gettimeofday(&router->lastReport, NULL);
+        
+        if (router == NULL) continue;
+        addr.s6_addr16[7] = htons(reporter);
+
+        if (rmsg->source == __my_address.s6_addr16[7] && !router->isProxying) {
+          // if I sent this report, make sure we are proxying for him
+          info("Starting to proxy for 0x%x\n", reporter);
+
+          if (route_cmd(SIOCADDRT, &addr, tun_dev) < 0) {
+            log_fatal_perror("route_add");
+          }
+
+          nl_nd_add_proxy(&addr, proxy_dev);
+          router->isProxying = TRUE;
+        }
+        if (rmsg->source != __my_address.s6_addr16[7] && router->isProxying) {
+          info("Was proxying 0x%x, but he has moved\n", reporter);
+          if (route_cmd(SIOCDELRT, &addr, tun_dev) < 0) {
+            log_fatal_perror("route_del");
+          }
+
+          nl_nd_del_neigh(&addr, proxy_dev);
+          router->isProxying = FALSE;
+        }
+      }
+      nw_clear_unmarked(reporter);
+
+      router = nw_get_router(ntohs(rmsg->source));
+      if (router != NULL && !router->isController) {
+        nw_add_controller(ntohs(rmsg->source));
+      }
+      
+      cur += header_len;
+      len -= header_len;
+    }
+    break;
+  }
   return 0;
 }
 
+int routing_add_report(node_id_t reporter, struct tlv_hdr *tlv) {
+  struct topology_header *th = (struct topology_header *)(tlv + 1);
+  struct routing_message *rmsg;
+  struct topology_header_package *pack;
+
+  rmsg = (struct routing_message *)report_buf;
+  pack = (struct topology_header_package *)&rmsg->data[0];
+
+  memset(report_buf, 0, sizeof(report_buf));
+
+  debug("routing_add_report: report from 0x%x seq: %i\n", reporter, th->seqno);
+
+  rmsg->type = RMSG_TOPOLOGY;
+  rmsg->source = __my_address.s6_addr16[7];
+  pack->reporter = htons(reporter);
+  pack->seqno = th->seqno;
+  pack->len      = htons(tlv->len - 
+                         sizeof(struct tlv_hdr) -
+                         sizeof(struct topology_header) + 
+                         sizeof(struct topology_header_package));
+
+  memcpy(pack->topo, th->topo, tlv->len - sizeof(struct tlv_hdr) -
+         sizeof(struct topology_header));
+  
+  mcast_send(report_buf, ntohs(pack->len) + sizeof(struct routing_message));
+
+  return 0;
+}
+
+
 /*
  * @returns: truth value indicating if the destination of the packet
  * is a single hop, and requires no source route.
  */
-uint8_t routing_is_onehop(struct split_ip_msg *msg) {
+int routing_is_onehop(struct split_ip_msg *msg) {
   path_t *path;
-  uint8_t ret = ROUTE_NO_ROUTE;
+  int ret = ROUTE_NO_ROUTE;
 
   if (cmpPfx(msg->hdr.ip6_dst.s6_addr, multicast_prefix))
     return ROUTE_ONEHOP;
 
+
+#if 0
   if (msg->hdr.nxt_hdr == NXTHDR_SOURCE) {
     debug("routing_is_onehop: Source header\n");
     return ROUTE_SOURCE;
   }
+#endif
 
   path = nw_get_route(my_short_addr, ntohs(msg->hdr.ip6_dst.s6_addr16[7]));
   
   if (path != NULL) {
-    if (path->length == 1)
+    if (path->isController) {
+      ret = ROUTE_WORMHOLE;
+    } else if (path->length == 1) {
       ret = ROUTE_ONEHOP;
-    else
+    } else {
       ret = ROUTE_MHOP;
+    }
   }
   debug("routing_is_onehop: 0x%x\n", ret);
   nw_free_path(path);
@@ -137,31 +304,32 @@ uint8_t routing_is_onehop(struct split_ip_msg *msg) {
 */
 
 /*
- * Copys the IP message at orig to the empty one at ret, inserting
- * necessary routing information.
  */
 uint8_t routing_insert_route(struct split_ip_msg *orig) {
   int offset = 0;
   path_t *path = nw_get_route(my_short_addr, ntohs(orig->hdr.ip6_dst.s6_addr16[7]));
   path_t *i;
   struct generic_header *g_hdr = (struct generic_header *)malloc(sizeof(struct generic_header));
-  struct source_header *sh;
+  struct ip6_route *sh;
 
   if (g_hdr == NULL || path == NULL) {
     if (g_hdr) free(g_hdr);
     if (path) nw_free_path(path);
     return 1;
   }
+#if 0
   if (path->length == 1) {
     free(g_hdr);
     nw_free_path(path);
     return 1;
   }
+#endif
+
   debug("routing_insert_route len: 0x%x\n", path->length);
 
   // if the packet with the source route is longer then the buffer
   // we're putting it into, drop it.
-  if (ntoh16(orig->hdr.plen) + sizeof(struct source_header) + 
+  if (ntoh16(orig->hdr.plen) + sizeof(struct ip6_route) + 
       (path->length * sizeof(uint16_t)) + sizeof(struct ip6_hdr) > INET_MTU) {
     warn("packet plus source header too long\n");
     free(g_hdr);
@@ -169,7 +337,7 @@ uint8_t routing_insert_route(struct split_ip_msg *orig) {
     return 1;
   }
   
-  sh = (struct source_header *)malloc(sizeof(struct source_header) + path->length * sizeof(uint16_t));
+  sh = (struct ip6_route *)malloc(sizeof(struct ip6_route) + path->length * sizeof(uint16_t));
   if (sh == NULL) {
     free (g_hdr);
     nw_free_path(path);
@@ -177,11 +345,11 @@ uint8_t routing_insert_route(struct split_ip_msg *orig) {
   }
 
   sh->nxt_hdr = orig->hdr.nxt_hdr;
-  sh->len = sizeof(struct source_header) + (path->length * sizeof(uint16_t));
-  sh->dispatch = IP_EXT_SOURCE_DISPATCH | IP_EXT_SOURCE_CONTROLLER;
-  sh->current = 0;
+  sh->len = sizeof(struct ip6_route) + (path->length * sizeof(uint16_t));
+  sh->type = IP6ROUTE_FLAG_CONTROLLER | IP6ROUTE_TYPE_SOURCE;
+  sh->segs_remain = path->length;
   
-  orig->hdr.nxt_hdr = NXTHDR_SOURCE;
+  orig->hdr.nxt_hdr = IPV6_ROUTING;
 
   log_clear(LOGLVL_DEBUG, "to 0x%x [%i]: ", ntohs(orig->hdr.ip6_dst.s6_addr16[7]), path->length);
   for (i = path; i != NULL; i = i->next) {
@@ -207,17 +375,19 @@ uint8_t routing_insert_route(struct split_ip_msg *orig) {
 /*
  * Returns the address of the next router this packet should be send to.
  */
-hw_addr_t routing_get_nexthop(struct split_ip_msg *msg) {
-  hw_addr_t ret = 0xffff;;
+ieee154_saddr_t routing_get_nexthop(struct split_ip_msg *msg) {
+  ieee154_saddr_t ret = 0xffff;;
   path_t * path;
   if (cmpPfx(msg->hdr.ip6_dst.s6_addr, multicast_prefix))
     return ret;
 
   // If it's source routed, just grab the next hop out of the header 
+#if 0
   if (msg->hdr.nxt_hdr == NXTHDR_SOURCE) {
     debug("routing_get_nexthop: src header\n"); 
     return ntoh16((msg->headers->hdr.sh->hops[msg->headers->hdr.sh->current]));
   }
+#endif
 
   path = nw_get_route(my_short_addr, ntohs(msg->hdr.ip6_dst.s6_addr16[7]));
 
@@ -228,45 +398,3 @@ hw_addr_t routing_get_nexthop(struct split_ip_msg *msg) {
 
   return ret;
 }
-
-void routing_proc_msg(struct split_ip_msg *msg) {
-  struct generic_header *g_hdr, **prev_hdr;
-  uint8_t *prev_next, nxt_hdr = msg->hdr.nxt_hdr;
-  int i;
-  node_id_t reporter = ntohs(msg->hdr.ip6_src.s6_addr16[7]);
-
-  prev_next = &msg->hdr.nxt_hdr;
-  prev_hdr = &msg->headers;
-
-  nw_report_node(reporter);
-  for (g_hdr = msg->headers; g_hdr != NULL; g_hdr = g_hdr->next) {
-    if (nxt_hdr == NXTHDR_TOPO) {
-      // add the topology reports to the database 
-      nw_unmark_links(reporter);
-      for (i = 0; i < (g_hdr->len - sizeof(struct topology_header))/sizeof(struct topology_entry); i++) {
-        //debug("topo neigh: 0x%x hop: %i qual: 0x%x\n", g_hdr->hdr.th->topo[i].hwaddr,
-             // g_hdr->hdr.th->topo[i].hops, g_hdr->hdr.th->topo[i].link);
-        nw_add_incr_edge(reporter, &g_hdr->hdr.th->topo[i]);
-      }
-      nw_clear_unmarked(reporter);
-      // remove the topology header
-      *prev_next = g_hdr->hdr.ext->nxt_hdr;
-      *prev_hdr = g_hdr->next;
-      if (g_hdr->payload_malloced) free(g_hdr->hdr.data);
-      msg->hdr.plen = hton16(ntoh16(msg->hdr.plen) - g_hdr->len);
-      free(g_hdr);
-      return;
-    } else {
-      nxt_hdr = g_hdr->hdr.ext->nxt_hdr;
-      prev_next = &g_hdr->hdr.ext->nxt_hdr;
-      prev_hdr = &g_hdr->next;
-    }
-  }
-}
-
-
-void routing_add_table_entry(node_id_t id) {
-  /* static const char* route_add_fmt = "ip -6 route add %x%02x:%x%02x:%x%02x:%x%02x:%x%02x:%x%02x:%x%02x:%x%02x/128 dev %s"; */
-  /* static const char* route_proxy_fmt = "ip -6 neigh add proxy %x%02x:%x%02x:%x%02x:%x%02x:%x%02x:%x%02x:%x%02x:%x%02x dev %s"; */
-}
index cfb3193419378eb02f88c6bee3d501a47eb54e97..c9c3eb453cb9d2c80d1ddfc32be56b230afc3a63 100644 (file)
@@ -32,16 +32,36 @@ enum {
   ROUTE_ONEHOP,
   ROUTE_MHOP,
   ROUTE_SOURCE,
+  ROUTE_WORMHOLE,
 };
 
+// the maximum size of a set of topology entries we send out over the network
+#define ROUTMSGSIZ 1400
+
+enum {
+  RMSG_TOPOLOGY = 1,
+};
+
+struct routing_message {
+  uint16_t type;
+  uint16_t source;
+  char    data[0];
+};
+
+int routing_init(struct config *c, char *tun_dev);
+
+/* 
+ * handles for  the blocking loop
+ */
+int routing_add_fds(fd_set *fds);
+int routing_process(fd_set *fds);
 
-uint8_t routing_init(struct config *c, char *tun_dev);
 
 /*
  * @returns: truth value indicating if the destination of the packet
  * is a single hop, and requires no source route.
  */
-uint8_t routing_is_onehop(struct split_ip_msg  *msg);
+int routing_is_onehop(struct split_ip_msg  *msg);
 
 
 /*
@@ -53,19 +73,14 @@ uint8_t routing_insert_route(struct split_ip_msg *orig);
 /*
  * Returns the address of the next router this packet should be send to.
  */
-hw_addr_t routing_get_nexthop(struct split_ip_msg *msg);
+ieee154_saddr_t routing_get_nexthop(struct split_ip_msg *msg);
 
 
 /*
  * Called for all reconstructed packets off serial.
  * allows the router to inpect and remove any extra headers in the message.
  */
-void routing_proc_msg(struct split_ip_msg *msg);
-
-/*
- * Update kernel routing state to reflect a new node
- */
-void routing_add_table_entry(node_id_t id);
+int routing_add_report(node_id_t reporter, struct tlv_hdr *tlv);
 
 
 #endif 
index 0462f35ab54e25818a4ca756617b5c93d907fee1..53381e1591d4570040f844636858a7c635124103 100644 (file)
 #include <termios.h>
 #include <errno.h>
 #include <signal.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "TrackFlows.h"
 
 #include "tun_dev.h"
 #include "serialsource.h"
 #include "logging.h"
 #include "config.h"
 #include "nwstate.h"
+#include "vty.h"
 
 #define min(a,b) ( (a>b) ? b : a )
 #define max(a,b) ( (a>b) ? a : b )
 
-int tun_fd, radvd_fd = -1;
+int tun_fd, radvd_fd = -1, fifo_fd = -1, keepalive_needed = 1;
+int opt_listenonly = 0, opt_trackflows = 0;
+
 int radvd_init(char *ifname, struct config *c);
 void radvd_process();
 
-#ifndef SIM
+#ifndef SF_SRC
 serial_source ser_src;
 #define write_pan_packet(DATA, LEN) write_serial_packet(ser_src, DATA, LEN)
 #define read_pan_packet(LENP) read_serial_packet(ser_src, LENP)
+#define close_pan()   close_serial_source(ser_src);
 #else
 int sf_fd;
 #define write_pan_packet(DATA, LEN) write_sf_packet(sf_fd, DATA, LEN)
 #define read_pan_packet(LENP) read_sf_packet(sf_fd, LENP)
+#define close_pan()           close(sf_fd)
 #endif
 
+sig_atomic_t do_shutdown = 0;
+
+void driver_shutdown() {
+  do_shutdown = 1;
+}
+
+
 enum {
   N_RECONSTRUCTIONS = 10,
 };
 
 /*
- * This is not the right way to detect we're on that platform, but I
- * can't find a better macro.
  */ 
 #ifdef __TARGET_mips__
-char *def_configfile = "/etc/lowpan/serial_tun.conf";
+const char *def_configfile = "/etc/lowpan/serial_tun.conf";
 #else
-char *def_configfile = "serial_tun.conf";
+const char *def_configfile = "serial_tun.conf";
 #endif
 
-#ifdef DBG_TRACK_FLOWS
-FILE *dbg_file;
-#endif
 
 
 extern struct in6_addr __my_address;
@@ -133,6 +144,11 @@ struct {
   unsigned long fw_pkts;
 } stats = {0, 0, 0, 0, 0, 0, 0, 0};
 
+#ifdef CENTRALIZED_ROUTING
+void install_route(struct split_ip_msg *amsg, uint8_t flags);
+void uninstall_route(uint16_t n1, uint16_t n2);
+#endif
+
 
 /* ------------------------------------------------------------------------- */
 
@@ -177,6 +193,77 @@ void print_ip_packet(struct split_ip_msg *msg) {
   printf("\n");
 }
 
+
+const char *fifo_name = "/var/run/ip-driver/flows";
+void fifo_open() {
+  struct stat stat_buf;
+
+  if (opt_trackflows) {
+    if (stat(fifo_name, &stat_buf) < 0) {
+      error("fifo does not exist -- track flows will be diabled\n");
+      return;
+    }
+    fifo_fd = open(fifo_name, O_WRONLY | O_NONBLOCK );
+    if (fifo_fd < 0) {
+      error("unable to open fifo %i %s: is a reader connected?\n", fifo_fd, fifo_name);
+      fifo_fd = -1;
+      return;
+    }
+  }
+}
+void fifo_close() {
+  if (fifo_fd >= 0) {
+    close(fifo_fd);
+  }
+}
+
+enum { N_OUTGOING_CACHE = 10, }; int outgoing_cache_idx = 0;
+struct flow_id_msg outgoing_cache[N_OUTGOING_CACHE];
+
+void fifo_report(struct split_ip_msg *msg, uint16_t dest, int nxt_hdr) {
+  if (fifo_fd >= 0) {
+    outgoing_cache_idx = (outgoing_cache_idx + 1) % N_OUTGOING_CACHE;
+    outgoing_cache[outgoing_cache_idx].flow = msg->flow_id;
+    outgoing_cache[outgoing_cache_idx].src  = ntohs(msg->hdr.ip6_src.s6_addr16[7]);
+    outgoing_cache[outgoing_cache_idx].dst  = ntohs(msg->hdr.ip6_dst.s6_addr16[7]);
+    outgoing_cache[outgoing_cache_idx].local_address = ntohs(__my_address.s6_addr16[7]);
+    outgoing_cache[outgoing_cache_idx].nxt_hdr = nxt_hdr;
+    outgoing_cache[outgoing_cache_idx].n_attempts = 1;
+    outgoing_cache[outgoing_cache_idx].attempts[0].next_hop = (dest);
+    debug("adding cache entry: %i %i\n",  outgoing_cache[outgoing_cache_idx].src,
+          outgoing_cache[outgoing_cache_idx].flow);
+  }
+}
+
+void flow_insert_label(struct split_ip_msg *msg) {
+  uint8_t *buf;
+  struct generic_header *g_hdr;
+
+
+  if (opt_trackflows) {
+    buf = malloc(sizeof(struct ip6_ext) + sizeof(struct tlv_hdr) + sizeof(struct flow_id));
+    g_hdr = (struct generic_header *)malloc(sizeof(struct generic_header));
+    struct ip6_ext *ext = (struct ip6_ext *)buf;
+    struct tlv_hdr *tlv = (struct tlv_hdr *)(ext + 1);
+    struct flow_id *id  = (struct flow_id *)(tlv + 1);
+
+    ext->nxt_hdr = msg->hdr.nxt_hdr;
+    msg->hdr.nxt_hdr = IPV6_HOP;
+    ext->len = sizeof(struct ip6_ext) + sizeof(struct tlv_hdr) + sizeof(struct flow_id);
+    tlv->type = TLV_TYPE_FLOW;
+    tlv->len = ext->len - sizeof(struct ip6_ext);
+    id->id = msg->flow_id;
+  
+    g_hdr->payload_malloced = 1;
+    g_hdr->hdr.ext = ext;
+    g_hdr->len = ext->len;
+    g_hdr->next = msg->headers;
+    msg->headers = g_hdr;
+    
+    msg->hdr.plen = htons(ntohs(msg->hdr.plen) + ext->len);
+  }
+}
+
 /*
  * frees the linked list structs, and their payloads if we have
  * malloc'ed them at some other point.
@@ -217,15 +304,15 @@ void configure_reboot() {
   alarm(5);
 }
 
-void configure_setparms(struct config *c) {
+void configure_setparms(struct config *c, int cmdno) {
   uint8_t buf[sizeof(config_cmd_t) + 1];
   config_cmd_t *cmd = (config_cmd_t *)(&buf[1]);
   memset(buf, 0, sizeof(config_cmd_t) + 1);
   buf[0] = TOS_SERIAL_DEVCONF;
-  cmd->cmd = CONFIG_SET_PARM;
+  cmd->cmd = cmdno;
   cmd->rf.addr = c->router_addr.s6_addr16[7]; // is network byte-order
   cmd->rf.channel = c->channel;
-  cmd->retx.retries = htons(10);
+  cmd->retx.retries = htons(c->retries);
   cmd->retx.delay = htons(30);
 
   write_pan_packet(buf, CONFIGURE_MSG_SIZE + 1);
@@ -246,7 +333,7 @@ void handle_other_pkt(uint8_t *data, int len) {
     debug("interface configured (0x%x) addr: 0x%x\n", rep->error, ntohs(rep->addr));
     switch (rep->error) {
     case CONFIG_ERROR_BOOTED:
-      configure_setparms(&driver_config);
+      configure_setparms(&driver_config, CONFIG_SET_PARM);
       break;
     default:
       info("interface device successfully initialized\n");
@@ -254,10 +341,10 @@ void handle_other_pkt(uint8_t *data, int len) {
 
       /* put this here because we already use SIGALRM for the
          configure timeout, and radvd needs it for its own timer. */
-      if ((radvd_fd = radvd_init(dev, &driver_config)) < 0) {
+      if (radvd_fd < 0 && (radvd_fd = radvd_init(dev, &driver_config)) < 0) {
         fatal("radvd init failed!\n");
         exit(1);
-      }
+      } 
     }
     break;
   default:
@@ -269,15 +356,10 @@ void handle_other_pkt(uint8_t *data, int len) {
 
 /* ------------------------------------------------------------------------- */
 /* handling of data arriving on the tun interface */
-void write_radio_header(uint8_t *serial, hw_addr_t dest, uint16_t payload_len) {
-#ifndef SIM
+void write_radio_header(uint8_t *serial, ieee154_saddr_t dest, uint16_t payload_len) {
   IEEE154_header_t *radioPacket = (IEEE154_header_t *)(serial + 1);
-  radioPacket->length = payload_len + MAC_HEADER_SIZE + MAC_FOOTER_SIZE 
-#ifdef DBG_TRACK_FLOWS
-    + sizeof(struct flow_id);
-#else
-  ;
-#endif
+  radioPacket->length = payload_len + MAC_HEADER_SIZE + MAC_FOOTER_SIZE;
+
   // don't include the length byte
   radioPacket->fcf = htons(0x4188);
   // dsn will get set on mote
@@ -286,62 +368,25 @@ void write_radio_header(uint8_t *serial, hw_addr_t dest, uint16_t payload_len) {
   // src will get set on mote 
   
   serial[0] = SERIAL_TOS_SERIAL_802_15_4_ID;
-#else
-  serial_header_t *serialHeader = (serial_header_t *)(serial + 1);
-  serialHeader->length = payload_len
-#ifdef DBG_TRACK_FLOWS
-    + sizeof(struct flow_id);
-#else
-  ;
-#endif
-  serialHeader->dest = htons(dest);
-  serialHeader->type = 0;
-
-  serial[0] = 0;
-#endif
 }
 
-void send_fragments (struct split_ip_msg *msg, hw_addr_t dest) {
+void send_fragments (struct split_ip_msg *msg, ieee154_saddr_t dest) {
   int result;
   uint16_t frag_len;
   fragment_t progress;
   uint8_t serial[LOWPAN_LINK_MTU + 1];
-#ifndef SIM
   IEEE154_header_t *radioPacket = (IEEE154_header_t *)(serial + 1);
 #define PKTLEN(X) ((X)->length + 2)
-#else
-  serial_header_t *radioPacket = (serial_header_t *)(serial + 1);
-#define PKTLEN(X) ((X)->length + sizeof(serial_header_t) + 1)
-#endif
 
   uint8_t *lowpan = (uint8_t *)(radioPacket + 1);
 
-#ifdef DBG_TRACK_FLOWS
-#define LOWPAN_PAYLOAD_LENGTH (LOWPAN_LINK_MTU - MAC_HEADER_SIZE \
-                              - MAC_FOOTER_SIZE - sizeof(struct flow_id))
-  lowpan += sizeof(struct flow_id);
-#else 
 #define LOWPAN_PAYLOAD_LENGTH (LOWPAN_LINK_MTU - MAC_HEADER_SIZE \
                               - MAC_FOOTER_SIZE)
-#endif
 
   progress.offset = 0;
 
   // and IEEE 802.15.4 header
   // write_radio_header(serial, dest, frag_len);
-#ifdef DBG_TRACK_FLOWS
-#ifndef SIM
-  ip_memcpy(serial + 1 + sizeof(IEEE154_header_t), &msg->id, sizeof(struct flow_id));
-#else
-  ip_memcpy(serial + 1 + sizeof(serial_header_t), &msg->id, sizeof(struct flow_id));
-#endif
-  if (dest != 0xffff) {
-    fprintf(dbg_file, "DEBUG (%i): %i\t%i\t%i\t%i\t%i\t%i\t%i\n",
-            100, msg->id.src, msg->id.dst, msg->id.id, msg->id.seq,
-            msg->id.nxt_hdr, 100, dest);
-    fflush(dbg_file);
-  }
-#endif
 
   while ((frag_len = getNextFrag(msg, &progress, lowpan, 
                                  LOWPAN_PAYLOAD_LENGTH)) > 0) {
@@ -372,6 +417,7 @@ void send_fragments (struct split_ip_msg *msg, hw_addr_t dest) {
     stats.tx_frags++;
     stats.tx_bytes += PKTLEN(radioPacket);
   }
+  keepalive_needed = 0;
   stats.tx_pkts++;
 }
 
@@ -386,27 +432,36 @@ void icmp_unreachable(struct split_ip_msg *msg) {
  *
  */ 
 uint8_t ip_to_pan(struct split_ip_msg *msg) {
+  int nxt_hdr = msg->hdr.nxt_hdr;
   uint16_t dest;
 
   debug("ip_to_pan\n");
   print_ip_packet(msg);
-
   // if this packet has a source route (rinstall header, or prexisting
   // source header, we don't want to mess with it
   switch (routing_is_onehop(msg)) {
   case ROUTE_MHOP:
-    debug("Multihop packet");
+    debug("Multihop packet\n");
     if (routing_insert_route(msg)) goto fail;
     break;
     
+  case ROUTE_WORMHOLE:
+    debug("Wormhole packet\n");
+
+    // fall through
   case ROUTE_NO_ROUTE:
-    info("destination unreachable: 0x%x: dropping\n", ntohs(msg->hdr.ip6_dst.s6_addr16[7]));
+    tun_write(tun_fd, msg);
+    // info("destination unreachable: 0x%x: dropping\n", ntohs(msg->hdr.ip6_dst.s6_addr16[7]));
     return 0;
   }
 
-
   dest = routing_get_nexthop(msg);
   debug("next hop: 0x%x\n", dest);
+  flow_insert_label(msg);
+  print_ip_packet(msg);
+
+  fifo_report(msg, dest, nxt_hdr);
+
   send_fragments(msg, dest);
   return 0;
  fail:
@@ -414,15 +469,138 @@ uint8_t ip_to_pan(struct split_ip_msg *msg) {
   return 1;
 }
 
-void upd_source_route(struct source_header *sh, hw_addr_t addr) {
-  if (sh->current < SH_NENTRIES(sh)) {
-    sh->hops[sh->current] = leton16(addr);
-    sh->current++;
+void upd_source_route(struct ip6_route *sh, ieee154_saddr_t addr) {
+  if (sh->segs_remain > 0) {
+    sh->hops[ROUTE_NENTRIES(sh) - sh->segs_remain] = leton16(addr);
+    sh->segs_remain--;
   }
 }
 
+int process_dest_tlv(struct ip6_hdr *iph, struct ip6_ext *hdr, int len) {
+  struct tlv_hdr *tlv = (struct tlv_hdr *)(hdr + 1);
+  node_id_t reporter = ntohs(iph->ip6_src.s6_addr16[7]);
+
+  if (len != hdr-> len) return 1;
+  len -= sizeof(struct ip6_ext);
+
+  while (tlv != NULL && len > 0) {
+    if (tlv->len == 0) return 1;
+
+    switch(tlv->type) {
+    case TLV_TYPE_TOPOLOGY:
+      routing_add_report(reporter, tlv);
+      break;
+    }
+    
+    len -= tlv->len;
+    tlv = (struct tlv_hdr *)(((uint8_t *)tlv) + tlv->len);
+  }
+  return 0;
+}
+
+int process_hop_tlv(struct split_ip_msg *msg, struct ip6_ext *hdr, int len) {
+  struct tlv_hdr *tlv = (struct tlv_hdr *)(hdr + 1);
+  uint16_t *fl;
+
+  if (len != hdr-> len) return 1;
+  len -= sizeof(struct ip6_ext);
+
+  while (tlv != NULL && len > 0) {
+    if (tlv->len == 0) return 1;
+
+    switch(tlv->type) {
+    case TLV_TYPE_FLOW:
+      fl = (uint16_t *)(tlv + 1);
+      msg->flow_id = *fl;
+      debug("process_hop_tlv: flow 0x%x\n", msg->flow_id);
+      break;
+    }
+
+    len -= tlv->len;
+    tlv = (struct tlv_hdr *)(((uint8_t *)tlv) + tlv->len);
+  }
+  return 0;
+}
+
+int process_extensions(struct split_ip_msg *msg) {
+  struct generic_header *prev = NULL, *cur = msg->headers;
+  struct ip6_route *route;
+  uint8_t nxt_hdr = msg->hdr.nxt_hdr;
+  int lendelta = 0;
+
+  while (cur != NULL && EXTENSION_HEADER(nxt_hdr)) {
+    debug("dropping header type 0x%x, len %i\n", nxt_hdr, cur->len);
+    msg->headers = cur->next;
+    msg->hdr.nxt_hdr = cur->hdr.ext->nxt_hdr;
+    lendelta += cur->len;
+
+    switch (nxt_hdr) {
+    case IPV6_DEST:
+      if (process_dest_tlv(&msg->hdr, cur->hdr.ext, cur->len)) 
+        return 1;
+      break;
+    case IPV6_HOP:
+      if (process_hop_tlv(msg, cur->hdr.ext, cur->len)) {
+        warn("dropping packet due to hop tlv\n");
+        return 1;
+      }
+      break;
+    case IPV6_ROUTING:
+
+      route = cur->hdr.sh;
+
+      if ((route->type & ~IP6ROUTE_FLAG_MASK) == IP6ROUTE_TYPE_INVAL || route->segs_remain == 0) {
+/*         if (route->type == IP6ROUTE_TYPE_INVAL) { */
+/*           if (route->hops[0] == __my_address.s6_addr16[7]) { */
+/*             warn("dropping packet since it has an invalid source route and I sent it\n"); */
+/*             return 1; */
+/*           } */
+/*         } */
+      } else {
+        uint16_t target_hop = ntohs(route->hops[ROUTE_NENTRIES(route) - route->segs_remain]);
+        // if this is actually a valid source route, maybe update it
+        // (even though we're going to delete it shortly)
+        if (target_hop != __my_address.s6_addr16[7]) {
+          if (ROUTE_NENTRIES(route) >= 2) {
+            route->hops[0] = htons(msg->prev_hop);
+            route->hops[1] = htons(target_hop);
+          }
+          route->type = (route->type & IP6ROUTE_FLAG_MASK) | IP6ROUTE_TYPE_INVAL;
+        } else {
+          route->hops[ROUTE_NENTRIES(route) - route->segs_remain] = htons(msg->prev_hop);
+          route->segs_remain--;
+        }
+      }
+      
+      if ((route->type & ~IP6ROUTE_FLAG_MASK) == IP6ROUTE_TYPE_INVAL && ROUTE_NENTRIES(route) >= 2) {
+        node_id_t n1 = ntohs(route->hops[0]);
+        node_id_t n2 = ntohs(route->hops[1]);
+        warn ("broken link was %i -> %i\n", n1, n2);
+        nw_remove_link(n1, n2);
+        if (route->type & IP6ROUTE_FLAG_CONTROLLER) {
+          warn("dropping packet since it has an invalid source route and I sent it\n");
+          return 1;
+        } else {
+          warn("received broken source route based on installed route-- uninstalling\n");
+/*           uninstall_route(ntohs(msg->hdr.ip6_src.s6_addr16[7]), */
+/*                           ntohs(msg->hdr.ip6_dst.s6_addr16[7])); */
+        }
+      }
+    }
+
+    nxt_hdr = cur->hdr.ext->nxt_hdr;
+    prev = cur;
+    cur = cur->next;
+    free(prev);
+  }
+
+  msg->hdr.plen = htons(ntohs(msg->hdr.plen) - lendelta);
+  return 0;
+}
+
+#if 0
 int remove_sourceroute(struct split_ip_msg *msg) {
-  struct source_header *sh;
+  struct source_header *s;
   struct rinstall_header *rih;
   struct generic_header *g_hdr;
   uint8_t removeSource = 1;
@@ -470,12 +648,12 @@ int remove_sourceroute(struct split_ip_msg *msg) {
   }
   return 0;
 }
-
+#endif
 
 void handle_serial_packet(struct split_ip_msg *msg) {
   path_t* tPath;
   path_t* i;
-#ifdef DBG_TRACK_FLOWS
+#ifdef CENTRALIZED_ROUTING
   uint8_t flags = 0x00;
 #endif
   if (ntohs(msg->hdr.plen) > INET_MTU - sizeof(struct ip6_hdr)) {
@@ -484,34 +662,29 @@ void handle_serial_packet(struct split_ip_msg *msg) {
   }
 
   // print_ip_packet(msg);
-  // if this packet has a source route that we inserted, we need to
-  // drop it to prevent loops.
-  if (remove_sourceroute(msg))
+  print_ip_packet(msg);
+  if (process_extensions(msg))
     return;
-  routing_proc_msg(msg);
-  remove_sourceroute(msg);
 
   if (cmpPfx(msg->hdr.ip6_dst.s6_addr, __my_address.s6_addr) && 
       msg->hdr.ip6_dst.s6_addr16[7] != __my_address.s6_addr16[7]) {
-/*       ((msg->hdr.ip6_dst.s6_addr[14] != __my_address[14] || */
-/*         msg->hdr.ip6_dst.s6_addr[15] != __my_address[15]))) { */
-      info("Received packet destined to 0x%x\n", msg->hdr.ip6_dst.s6_addr[15]);
-     
+      debug("Received packet destined to 0x%x\n", msg->hdr.ip6_dst.s6_addr[15]); 
+      stats.fw_pkts++;
+    
      // If this packet is not source routed, check to see if we're on the best path before
      //  issuing a route install
-     if (msg->hdr.nxt_hdr != NXTHDR_SOURCE) { 
        tPath = nw_get_route(ntohs(msg->hdr.ip6_src.s6_addr16[7]), ntohs(msg->hdr.ip6_dst.s6_addr16[7]));
         for (i = tPath; i != NULL; i = i->next) {
           if (i->node == ntohs(__my_address.s6_addr16[7])) {
-           info("Not installing route for packet from 0x%x to 0x%x (on best path)\n", 
-                 ntohs(msg->hdr.ip6_src.s6_addr16[7]), ntohs(msg->hdr.ip6_dst.s6_addr16[7]));
+            debug("Not installing route for packet from 0x%x to 0x%x (on best path)\n", 
+                  ntohs(msg->hdr.ip6_src.s6_addr16[7]), ntohs(msg->hdr.ip6_dst.s6_addr16[7]));
             nw_free_path(tPath);
             ip_to_pan(msg);
             return;
           }
         }
         nw_free_path(tPath);
-      }
+        // }
       
       // We send the route installation packet before forwarding the actual
       //  packet, with the thinking being that the route can be set up, in
@@ -521,13 +694,20 @@ void handle_serial_packet(struct split_ip_msg *msg) {
      
       //  At this point, if it's not source routed, then this packet
       //  shouldn't be coming through us so we install a route
-      if (msg->hdr.nxt_hdr != NXTHDR_SOURCE) {
-        info("installing route for packet from 0x%x to 0x%x\n", 
-             ntohs(msg->hdr.ip6_src.s6_addr16[7]), ntohs(msg->hdr.ip6_dst.s6_addr16[7]));
-      } else {
-        info("Packet had a source header so no route install\n"); 
-      }
-      stats.fw_pkts++;
+        // if (msg->hdr.nxt_hdr != NXTHDR_SOURCE) {
+        debug("installing route for packet from 0x%x to 0x%x\n", 
+              ntohs(msg->hdr.ip6_src.s6_addr16[7]), ntohs(msg->hdr.ip6_dst.s6_addr16[7]));
+#ifdef CENTRALIZED_ROUTING
+#ifndef FULL_PATH_INSTALL
+        flags = HYDRO_METHOD_SOURCE | HYDRO_INSTALL_REVERSE;
+#else
+        flags = HYDRO_METHOD_HOP | HYDRO_INSTALL_REVERSE;
+#endif
+        //        install_route(msg, flags);
+#endif
+        // } else {
+        // info("Packet had a source header so no route install\n"); 
+        // }
       ip_to_pan(msg);
       // do routing
   } else {
@@ -544,11 +724,11 @@ void add_header_list(struct split_ip_msg *msg) {
   struct generic_header *g_hdr, **g_list;
   struct ip6_ext *ext = (struct ip6_ext *)msg->next;
   uint16_t hdr_len = 0;
-  debug("add_header_list for message destined to 0x%x\n", ntohs(msg->hdr.ip6_dst.s6_addr16[7]));
+  // debug("add_header_list for message destined to 0x%x\n", ntohs(msg->hdr.ip6_dst.s6_addr16[7]));
   nxt_hdr = msg->hdr.nxt_hdr;
   msg->headers = NULL;
   g_list = &(msg->headers);
-  while (KNOWN_HEADER(nxt_hdr)) {
+  while (EXTENSION_HEADER(nxt_hdr)) {
     g_hdr = (struct generic_header *)malloc(sizeof(struct generic_header));
     g_hdr->payload_malloced = 0;
     g_hdr->hdr.ext = ext;
@@ -556,35 +736,166 @@ void add_header_list(struct split_ip_msg *msg) {
     *g_list = g_hdr;
     g_list = &g_hdr->next;
 
-    switch(nxt_hdr) {
-    case IANA_UDP:
-      // a UDP header terminates a chain of headers we can compress...
-      g_hdr->len = sizeof(struct udp_hdr);
-      ext = (struct ip6_ext *)(((uint8_t *)ext) + sizeof(struct udp_hdr));
-      nxt_hdr = NXTHDR_UNKNOWN;
-      break;
-      // XXX : SDH : these are all "ip extension" headers and so can be treated genericlly.
-    case NXTHDR_INSTALL:
-      info("inserted NXTHDR_INSTALL\n");
-    case NXTHDR_TOPO:
-    case NXTHDR_SOURCE:
-      g_hdr->len = ext->len;
-      
-      nxt_hdr = ext->nxt_hdr;
-      ext = (struct ip6_ext *)(((uint8_t *)ext) + ext->len);
-      break;
-    default:
-      // TODO : SDH : discard the packet here since we can get in a
-      // bad place with invalid header types.  this isn't all that
-      // likely, but you never know.
-      break;
-    }
+    g_hdr->len = ext->len;
+    
+    nxt_hdr = ext->nxt_hdr;
+    ext = (struct ip6_ext *)(((uint8_t *)ext) + ext->len);
+    
     hdr_len += g_hdr->len;
   }
+  if (COMPRESSIBLE_TRANSPORT(nxt_hdr)) {
+      int transport_len;
+      switch (nxt_hdr) {
+      case IANA_UDP:
+        transport_len = sizeof(struct udp_hdr); break;
+      }
+
+      g_hdr = (struct generic_header *)malloc(sizeof(struct generic_header));
+      g_hdr->payload_malloced = 0;
+      g_hdr->hdr.ext = ext;
+      g_hdr->next = NULL;
+      *g_list = g_hdr;
+      g_list = &g_hdr->next;
+
+      g_hdr->len = transport_len;
+      ext = (struct ip6_ext *)(((uint8_t *)ext) + transport_len);
+      hdr_len += transport_len;
+  }
+
   msg->data = (uint8_t *)ext;
   msg->data_len = ntohs(msg->hdr.plen) - hdr_len;
 }
 
+#ifdef CENTRALIZED_ROUTING
+/*
+ * Given a source and destination, send a source-routed route install message
+ * that will install the correct routes.
+ *
+ * NOTE: Make sure that this is the correct way to create a new packet
+ */
+time_t last_install;
+void install_route(struct split_ip_msg *amsg, uint8_t flags) {
+  uint8_t buf[sizeof(struct split_ip_msg) + INET_MTU];
+  struct split_ip_msg *msg = (struct split_ip_msg *)buf;
+  int offset = 0;
+
+
+  struct ip6_ext *ext = (struct ip6_ext *)(msg->next);
+  struct tlv_hdr *tlv = (struct tlv_hdr *)(ext + 1);
+  struct rinstall_header *rih = (struct rinstall_header *)(tlv + 1);
+
+  path_t* path = nw_get_route(ntohs(amsg->hdr.ip6_src.s6_addr16[7]), ntohs(amsg->hdr.ip6_dst.s6_addr16[7]));
+  path_t* i;
+  time_t current_time;
+
+#if 0
+  time(&current_time);
+
+  if (current_time < last_install + 2) {
+    debug("Not sending install\n");
+    return;
+  }
+  time(&last_install);
+#endif 
+
+
+  if (path == NULL || path->isController) return;
+  fprintf(stderr, "install_route for src: 0x%x, dest: 0x%x, flags: %x\n", 
+          ntohs(amsg->hdr.ip6_src.s6_addr16[7]), ntohs(amsg->hdr.ip6_dst.s6_addr16[7]), path->length);
+  if (path->length > 10) return;
+
+  memset((uint8_t *)&msg->hdr, 0, sizeof(struct ip6_hdr));
+
+  // Set IP Header options
+  msg->hdr.hlim = 0x64; // CHECK THIS
+  msg->hdr.nxt_hdr = IPV6_DEST;
+  msg->hdr.vlfc[0] = IPV6_VERSION << 4;
+  msg->flow_id = local_seqno++;
+
+  memcpy(&msg->hdr.ip6_src, &__my_address, sizeof(struct in6_addr));
+  memcpy(&msg->hdr.ip6_dst, &amsg->hdr.ip6_src, sizeof(struct in6_addr));
+  msg->headers = NULL;
+
+  ext->nxt_hdr = IPV6_NONEXT;
+  ext->len = sizeof(struct ip6_ext) + sizeof(struct tlv_hdr) + sizeof(struct rinstall_header)
+    + (path->length * sizeof(uint16_t));
+
+  tlv->len = ext->len - sizeof(struct ip6_ext);
+  tlv->type = TLV_TYPE_INSTALL;
+
+  // Setup rinstall_header
+ // Size is longer because we put the src in there
+  rih->flags = flags;
+  rih->match.src = htons(T_INVAL_NEIGH);
+  rih->match.dest = amsg->hdr.ip6_dst.s6_addr16[7]; 
+  rih->path_len = path->length;
+
+  // Convert to host so add_headers_list works
+  msg->hdr.plen = htons(ext->len); 
+
+  info("install_route len: 0x%x\n", rih->path_len);
+
+  fprintf(stderr, "from 0x%x to 0x%x [%i]: ", 
+          ntohs(amsg->hdr.ip6_src.s6_addr16[7]), ntohs(amsg->hdr.ip6_dst.s6_addr16[7]), path->length);
+  // rih->path[0] = amsg->hdr.ip6_src.s6_addr16[7]; //htons(l2fromIP(amsg->hdr.ip6_src.s6_addr));
+  for (i = path; i != NULL; i = i->next) {
+    fprintf(stderr, "0x%x ", i->node);
+    rih->path[offset++] = htons(i->node);
+  }
+
+  nw_free_path(path);
+
+  add_header_list(msg);
+  print_ip_packet(msg);
+  loglevel_t old_lvl = log_setlevel(LOGLVL_DEBUG);
+  ip_to_pan(msg);
+  log_setlevel(old_lvl);
+  free_split_msg(msg);
+}
+
+void uninstall_route(uint16_t n1, uint16_t n2) {
+  uint8_t buf[sizeof(struct split_ip_msg) + INET_MTU];
+  struct split_ip_msg *msg = (struct split_ip_msg *)buf;
+  struct ip6_ext *ext = (struct ip6_ext *)(msg->next);
+  struct tlv_hdr *tlv = (struct tlv_hdr *)(ext + 1);
+  struct rinstall_header *rih = (struct rinstall_header *)(tlv + 1);
+
+  // Set IP Header options
+  msg->hdr.hlim = 0x64; // CHECK THIS
+  msg->hdr.nxt_hdr = IPV6_DEST;
+  msg->hdr.vlfc[0] = IPV6_VERSION << 4;
+  msg->flow_id = local_seqno++;
+
+  memcpy(&msg->hdr.ip6_src, &__my_address, sizeof(struct in6_addr));
+  memcpy(&msg->hdr.ip6_dst, &__my_address, sizeof(struct in6_addr));
+  msg->hdr.ip6_dst.s6_addr16[7] = htons(n1);
+  msg->headers = NULL;
+
+  ext->nxt_hdr = IPV6_NONEXT;
+  ext->len = sizeof(struct ip6_ext) + sizeof(struct tlv_hdr) + sizeof(struct rinstall_header);
+
+  tlv->len = ext->len - sizeof(struct ip6_ext);
+  tlv->type = TLV_TYPE_INSTALL;
+
+  // Convert to host so add_headers_list works
+  msg->hdr.plen = htons(ext->len); 
+
+  rih->flags = HYDRO_INSTALL_UNINSTALL_MASK | HYDRO_METHOD_SOURCE;
+  rih->match.src = htons(n1);
+  rih->match.dest = htons(n2);
+  rih->path_len = 0;
+    
+
+  add_header_list(msg);
+  print_ip_packet(msg);
+  loglevel_t old_lvl = log_setlevel(LOGLVL_DEBUG);
+  ip_to_pan(msg);
+  log_setlevel(old_lvl);
+  free_split_msg(msg);
+}
+
+#endif
+
 /*
  * read data from the tun device and send it to the serial port
  * does also fragmentation
@@ -616,13 +927,7 @@ int tun_input()
   }
   
   add_header_list(msg);
-#ifdef DBG_TRACK_FLOWS
-  msg->id.src = 100;
-  msg->id.dst = ntohs(msg->hdr.ip6_dst.s6_addr16[7]); //l2fromIP(msg->hdr.dst_addr);
-  msg->id.id = local_seqno++;
-  msg->id.seq = 0;
-  msg->id.nxt_hdr = msg->hdr.nxt_hdr;
-#endif
+  msg->flow_id = local_seqno++;
 
   ip_to_pan(msg);
 
@@ -697,73 +1002,40 @@ int serial_input() {
     packed_lowmsg_t pkt;
     reconstruct_t *recon;
     struct split_ip_msg *msg;
-#ifndef SIM
     IEEE154_header_t *mac_hdr;
-#else
-    serial_header_t *mac_hdr;
-#endif
     
     uint8_t *ser_data = NULL;          /* data read from serial port */
     int ser_len = 0;                    /* length of data read from serial port */
     uint8_t shortMsg[INET_MTU];
     uint8_t *payload;
-#ifdef DBG_TRACK_FLOWS
-    struct flow_id *fl_id;
-#endif
 
+#ifdef SF_SRC
+    int rv = 0;
+#else
     int rv = 1;
+#endif
 
     /* read data from serial port */
     ser_data = (uint8_t *)read_pan_packet(&ser_len);
 
     /* process the packet we have received */
     if (ser_len && ser_data) {
-#ifndef SIM
       if (ser_data[0] != TOS_SERIAL_802_15_4_ID) {
         handle_other_pkt(ser_data, ser_len);
         goto discard_packet;
       }
       mac_hdr = (IEEE154_header_t *)(ser_data + 1);
 
-#ifdef DBG_TRACK_FLOWS
-      fl_id = (struct flow_id *)(ser_data + 1 + sizeof(IEEE154_header_t));
-
-      // size is  one for the length byte, minus two for the checksum
-      pkt.len = mac_hdr->length - MAC_HEADER_SIZE - MAC_FOOTER_SIZE - sizeof(struct flow_id);
-      // add one for the dispatch byte.
-      pkt.data = ser_data + 1 + sizeof(IEEE154_header_t) + sizeof(struct flow_id);
-#else 
       // size is  one for the length byte, minus two for the checksum
       pkt.len = mac_hdr->length - MAC_HEADER_SIZE - MAC_FOOTER_SIZE;
       // add one for the dispatch byte.
       pkt.data = ser_data + 1 + sizeof(IEEE154_header_t);
-#endif // DBG_TRACK_FLOWS
 
       // for some reason these are little endian so we don't do any conversion.
       pkt.src = mac_hdr->src;
       pkt.dst = mac_hdr->dest;
-#else
-      mac_hdr = (serial_header_t *)(ser_data + 1);
 
-      if (mac_hdr->type != 0) {
-        goto discard_packet;
-      }
-
-#ifdef DBG_TRACK_FLOWS
-      fl_id = (struct flow_id *)(ser_data + 1 + sizeof(serial_header_t));
-      pkt.len = mac_hdr->length - sizeof(struct flow_id);
-      pkt.data = ser_data + 1 + sizeof(serial_header_t) + sizeof(struct flow_id);
-#else
-      pkt.len = mac_hdr->length;;
-      pkt.data = ser_data + 1 + sizeof(serial_header_t);
-#endif // DBG_TRACK_FLOWS
-
-      // except in serial packets, they __are__ little endian...
-      pkt.src = ntohs(mac_hdr->src);
-      pkt.dst = ntohs(mac_hdr->dest);
-#endif
-
-      debug("serial_input: read 0x%x bytes\n", ser_len);
+      log_dump_serial_packet(ser_data, ser_len);
 
       pkt.headers = getHeaderBitmap(&pkt);
       if (pkt.headers == LOWPAN_NALP_PATTERN) goto discard_packet;
@@ -777,11 +1049,14 @@ int serial_input() {
         recon = getReassembly(&pkt);
         if (recon == NULL || recon->buf == NULL) goto discard_packet;
         msg = (struct split_ip_msg *)recon->buf;
+        msg->prev_hop = pkt.src;
 
         if (hasFrag1Header(&pkt)) {
           if (unpackHeaders(&pkt, &u_info,
                             (uint8_t *)&msg->hdr, recon->size) == NULL) goto discard_packet;
           amount_here = pkt.len - (u_info.payload_start - pkt.data);
+          // adjustPlen(&msg->hdr, &u_info);
+
           ip_memcpy(u_info.header_end, u_info.payload_start, amount_here);
           recon->bytes_rcvd = sizeof(struct ip6_hdr) + u_info.payload_offset + amount_here;
         } else {
@@ -813,21 +1088,21 @@ int serial_input() {
 
       } else {
         unpack_info_t u_info;
-        u_info.rih = NULL;
+        // u_info.rih = NULL;
         msg = (struct split_ip_msg *)shortMsg;
+        msg->prev_hop = pkt.src;
+
         if (unpackHeaders(&pkt, &u_info,
                           (uint8_t *)&msg->hdr, INET_MTU) == NULL) goto discard_packet;
         if (ntohs(msg->hdr.plen) > INET_MTU - sizeof(struct ip6_hdr)) goto discard_packet;
+        // adjustPlen(&msg->hdr, &u_info);
 
         msg->metadata.sender = pkt.src;
-        if (u_info.rih != NULL)
-          info("Has a rinstall_header for src 0x%x with match: 0x%x\n", 
-               pkt.src, ntohs(u_info.rih->match.dest));;
+/*         if (u_info.rih != NULL) */
+/*           info("Has a rinstall_header for src 0x%x with match: 0x%x\n",  */
+/*                pkt.src, ntohs(u_info.rih->match.dest));; */
 
         ip_memcpy(u_info.header_end, u_info.payload_start, ntohs(msg->hdr.plen));
-#ifdef DBG_TRACK_FLOWS
-        ip_memcpy(&msg->id, fl_id, sizeof(struct flow_id));
-#endif
 
         add_header_list(msg);
         
@@ -844,157 +1119,238 @@ int serial_input() {
     return rv;
 }
 
-void print_stats() {
-  printf("Up since %s", ctime(&stats.boot_time));
-  printf("  receive  packets: %lu fragments: %lu bytes: %lu\n",
-         stats.tx_pkts, stats.tx_frags, stats.tx_bytes);
-  printf("  transmit packets: %lu fragments: %lu bytes: %lu\n",
-         stats.rx_pkts, stats.rx_frags, stats.rx_bytes);
-  printf("  forward  packets: %lu\n", stats.fw_pkts);
+void print_stats(int fd, int argc, char **argv) {
+  VTY_HEAD;
+  
+  VTY_printf("Up since %s", ctime(&stats.boot_time));
+  VTY_printf("  receive  packets: %lu fragments: %lu bytes: %lu\n",
+             stats.rx_pkts, stats.rx_frags, stats.rx_bytes);
+  VTY_printf("  transmit packets: %lu fragments: %lu bytes: %lu\n",
+             stats.tx_pkts, stats.tx_frags, stats.tx_bytes);
+  VTY_printf("  forward  packets: %lu\n", stats.fw_pkts);
+  VTY_flush();
 }
 
-int eval_cmd(char *cmd) {
-  char arg[1024];
-  int int_arg;
-  switch (cmd[0]) {
-  case 'c':
-    config_print(&driver_config);
-    return 0;
-  case 'd':
-    if (sscanf(cmd, "d %s\n", arg) == 1) {
-      nw_print_dotfile(arg);
-    } else {
-      printf("error: include a filename!\n");
-    }
-    return 0;
-  case 'i':
-    if (sscanf(cmd, "i %i\n", &int_arg) == 1) {
-      info("invalidating node 0x%x\n", int_arg);
-      nw_inval_node(int_arg);
+void print_help(int fd, int argc, char **argv) {
+  VTY_HEAD;
+  VTY_printf("ip-driver console\r\n");
+  VTY_printf("  conf      : print configuration info\r\n");
+  VTY_printf("  stats     : print statistics\r\n");
+  VTY_printf("  shutdown  : shutdown the driver\r\n");
+  VTY_printf("  chan <c>  : switch to channel 'c'\r\n");
+  VTY_printf("  dot <dotfile>: print dot-file of topology\r\n");
+  VTY_printf("  log {DEBUG INFO WARN ERROR FATAL}: set loglevel\r\n");
+  
+  VTY_printf("\r\n Routing commands:\r\n");
+  VTY_printf("  inval <nodeid> : invalidate a router\r\n");
+  VTY_printf("  add <n1> <n2>  : add a persistent link between n1 and n2\r\n");
+  VTY_printf("  links          : print link detail\r\n");
+  VTY_printf("  routes         : print routes\r\n");
+  VTY_printf("  newroutes      : recalculate routes\r\n");
+  VTY_printf("  controller <n> : add a new controller\r\n");
+#ifdef CENTRALIZED_ROUTING
+  VTY_printf("  install <HOP | SRC> <n1> <n2> [reverse]: install a route between n1 and n2\r\n");
+  VTY_printf("  uninstall <n1> <n2>: uninstall a route between n1 and n2\r\n");
+#endif
+  
+  VTY_printf("\r\n");
+  VTY_printf("  help: print this help\r\n");
+  VTY_flush();
+}
+
+void sh_loglevel(int fd, int argc, char **argv) {
+  VTY_HEAD;
+  int i;
+
+  if (argc != 2) return;
+  for (i = 0; i < 5; i++) {
+    if (strcmp(log_names[i], argv[1]) == 0) {
+      VTY_printf("setting verbosity to %s\r\n", log_names[i]);
+      log_setlevel(i);
     }
-    return 0;
-  case 'l':
-    nw_print_links();
-    return 0;
-  case 'p':
-    nw_print_routes();
-    return 0;
-  case 's':
-    print_stats();
-    return 0;
-  case 't':
-    nw_test_routes();
-    return 0;
-  case 'v':
-    if (sscanf(cmd, "v %s\n", arg) == 1) {
-      int i;
-      for (i = 0; i < 5; i++) {
-        if (strcmp(log_names[i], arg) == 0) {
-          printf("setting verbosity to %s\n", log_names[i]);
-          log_setlevel(i);
-        }
-      }
+  }
+  VTY_flush();
+}
+
+void sh_dotfile(int fd, int argc, char **argv) {
+  VTY_HEAD;
+  if (argc == 2) {
+    VTY_printf("writing topology to %s\r\n", argv[1]);
+    nw_print_dotfile(argv[1]);
+  } else {
+    VTY_printf("error: include a filename!\r\n");
+  }
+  VTY_flush();
+}
+
+void sh_chan(int fd, int argc, char **argv) {
+  VTY_HEAD;
+  if (argc != 2) {
+    VTY_printf("%s <channel>\r\n", argv[0]);
+  } else {
+    int channel = atoi(argv[1]);
+    if (channel < 11 || channel > 26) {
+      VTY_printf("channel must be in [11:26]\r\n");
+    } else {
+      driver_config.channel = channel;
+      VTY_printf("setting channel to %i\r\n", channel);
+      configure_setparms(&driver_config, CONFIG_SET_PARM);
     }
-    return 0;
-  case 'h':
-  default:
-    printf("ip-driver console\n");
-    printf("  c: print configuration info\n");
-    printf("  d <dotfile>: print dot-file of topology\n");
-    printf("  i <nodeid>: invalidate a router\n");
-    printf("  l: print link detail\n");
-    printf("  p: print routes\n");
-    printf("  t: recalculate routes\n");
-    printf("  v {DEBUG INFO WARN ERROR FATAL}: set verbosity\n");
-    printf("  s: print statistics\n");
-    printf("\n");
-    printf("  h: print this help\n");           
   }
+  VTY_flush();
+}
 
-  return 0;
+#ifdef CENTRALIZED_ROUTING
+void sh_install(int fd, int argc, char **argv) {
+  VTY_HEAD;
+  int flags = 0;
+  struct split_ip_msg msg;
+  if (argc < 4) {
+    goto usage;
+  } 
+  if (strcmp("HOP", argv[1]) == 0) 
+    flags |= HYDRO_METHOD_HOP;
+  else if (strcmp("SRC", argv[1]) == 0) {
+    flags |= HYDRO_METHOD_SOURCE;
+  } else goto usage;
+
+  argc -= 4;
+  while (argc > 0) {
+    if (argv[argc+3][0] == 'R') {
+      flags |= HYDRO_INSTALL_REVERSE;
+    } else goto usage;
+    argc--;
+  }
+  memset(&msg, 0, sizeof(struct split_ip_msg));
+  memcpy(msg.hdr.ip6_src.s6_addr, __my_address.s6_addr, 8);
+  memcpy(msg.hdr.ip6_dst.s6_addr, __my_address.s6_addr, 8);
+  msg.hdr.ip6_src.s6_addr16[7] = htons(atoi(argv[2]));
+  msg.hdr.ip6_dst.s6_addr16[7] = htons(atoi(argv[3]));
+
+  VTY_printf("installing route between 0x%x and 0x%x\r\n", atoi(argv[2]), atoi(argv[3]));
+  install_route(&msg, flags);
+
+  VTY_flush();
+  return;
+ usage:
+  VTY_printf("%s <HOP | SRC> <n1> <n2> [REV]\r\n", argv[0]);
+  VTY_flush();
+}
+
+void sh_uninstall(int fd, int argc, char **argv) {
+  VTY_HEAD;
+  if (argc != 3) {
+    VTY_printf("%s <n1> <n2>\r\n", argv[0]);
+    VTY_flush();
+    return;
+  }
+  int n1 = atoi(argv[1]);
+  int n2 = atoi(argv[2]);
+  VTY_printf("uninstalling route from 0x%x to 0x%x\r\n", n1, n2);
+  uninstall_route(n1, n2);
+  VTY_flush();
+}
+#endif
+
+void sh_controller(int fd, int argc, char **argv) {
+  VTY_HEAD;
+  if (argc != 2) {
+    VTY_printf("%s <cid>\r\n", argv[0]);
+  } else {
+    int n = atoi(argv[1]);
+    get_insert_router(n);
+    nw_add_controller(n);
+  }
+  VTY_flush();
 }
 
+struct vty_cmd vty_cmd_list[] = {{"help", print_help},
+                                 {"stats",  print_stats},
+                                 {"links", nw_print_links},
+                                 {"route", nw_print_routes},
+                                 {"newroutes", nw_test_routes},
+                                 {"add", nw_add_sticky_edge},
+                                 {"inval", nw_inval_node_sh},
+                                 {"conf", config_print},
+                                 {"log", sh_loglevel},
+                                 {"dot", sh_dotfile},
+                                 {"chan", sh_chan},
+#ifdef CENTRALIZED_ROUTING
+                                 {"install", sh_install},
+                                 {"uninstall", sh_uninstall},
+#endif
+                                 {"controller", sh_controller},
+                                 {"shutdown", (void(*)(int,int,char**))driver_shutdown}};
+
 /* shifts data between the serial port and the tun interface */
 int serial_tunnel(int tun_fd) {
-  char cmd_buf[2][1024], *cmd_cur;
-  int cur_buf = 0;
   fd_set fs;
-  int maxfd = 0;
+  int maxfd = -1;
+  int usecs_remain = KEEPALIVE_INTERVAL;
   time_t last_aging, current_time;
   time(&last_aging);
-#ifndef SIM
-  int pan_fd = serial_source_fd(ser_src);
+#ifndef SF_SRC
+  int pan_fd = opt_listenonly ? -1 : serial_source_fd(ser_src);
 #else
-  int pan_fd = sf_fd;
+  int pan_fd = opt_listenonly ? -1 : sf_fd;
 #endif
-  cmd_cur = cmd_buf[0];
-
-  /* disable input buffering on stdin since we're going to accumulate
-     the input outselves, and don't want to block */
-  if (isatty(fileno(stdin))) {
-    struct termios tio;
-    /* disable it on the fd */
-    if (tcgetattr(fileno(stdin), &tio))
-      return -1;
-    tio.c_lflag &= ~ICANON;
-    if (tcsetattr(fileno(stdin), TCSANOW, &tio))
-      return -1;
-    /* and also in libc */
-    setbuf(stdin, NULL);
-  }
 
   while (1) {
+    int n_fds;
+    struct timeval tv;
+    if (do_shutdown) return 0;
+
     FD_ZERO(&fs);
-    FD_SET(tun_fd, &fs);
-    FD_SET(pan_fd, &fs);
 
-    maxfd = max(tun_fd, pan_fd);
-    if (isatty(fileno(stdin))) {
-      FD_SET(fileno(stdin), &fs);
-      maxfd = max(fileno(stdin), maxfd);
+    if (opt_listenonly) {
+      maxfd = -1;
+    } else {
+      FD_SET(tun_fd, &fs);
+      FD_SET(pan_fd, &fs);
+
+      maxfd = max(tun_fd, pan_fd);
     }
+
     if (radvd_fd >= 0) {
       FD_SET(radvd_fd, &fs);
       maxfd = max(radvd_fd, maxfd);
     }
 
-    if (select(maxfd + 1, &fs, NULL, NULL, NULL) < 0)
-      continue;
+    maxfd = max(vty_add_fds(&fs), maxfd);
+    maxfd = max(routing_add_fds(&fs), maxfd);
 
-    
-    /* data available on tunnel device */
-    if (FD_ISSET(tun_fd, &fs))
-      while(tun_input());
+    // having a timeout also means that we poll for new packets every
+    // so often, which is apparently A Good Thing
+    tv.tv_sec  = 0;
+    tv.tv_usec = KEEPALIVE_TIMEOUT;
+    if ((n_fds = select(maxfd + 1, &fs, NULL, NULL, &tv)) < 0) {
+      continue;
+    }
+    usecs_remain -= (KEEPALIVE_TIMEOUT - tv.tv_usec);
+    if (usecs_remain <= 0) {
+      if (keepalive_needed) {
+        configure_setparms(&driver_config, CONFIG_KEEPALIVE);
+      } else keepalive_needed = 1;
 
-    if (FD_ISSET(pan_fd, &fs))
-      while(serial_input());
-    
-    if (FD_ISSET(fileno(stdin), &fs)) {
-      *cmd_cur++ = getc(stdin);
-      if (*(cmd_cur - 1) == '\n' || 
-          cmd_cur - cmd_buf[cur_buf] == 1024) {
-        *cmd_cur = '\0';
-        if (cmd_cur == cmd_buf[cur_buf] + 1) {
-          eval_cmd(cmd_buf[(cur_buf + 1) % 2]);
-        } else {
-          eval_cmd(cmd_buf[cur_buf]);
-          cur_buf = (cur_buf + 1) % 2;
-        }
-        cmd_cur = cmd_buf[cur_buf];
-      }
+      usecs_remain = KEEPALIVE_INTERVAL;
     }
     
+    if (!opt_listenonly) {
+      int more_data;
+      /* check for data */
+      do {
+        more_data = tun_input();
+        more_data = serial_input() || more_data ;
+      } while (more_data);
+    }
+
+    vty_process(&fs);
+    routing_process(&fs);
+
     if (radvd_fd >= 0 && FD_ISSET(radvd_fd, &fs)) {
       radvd_process();
     }
 
-#ifndef SIM
-/*     if (tcdrain(pan_fd) < 0) { */
-/*       fatal("tcdrain error: %i\n", errno); */
-/*       exit(3); */
-/*     } */
-#endif
-
     /* end of data available */
     time(&current_time);
     if (current_time > last_aging + (FRAG_EXPIRE_TIME / 1024)) {
@@ -1003,26 +1359,26 @@ int serial_tunnel(int tun_fd) {
     }
   }
 
-  return 0;
 }
 
-#ifdef DBG_TRACK_FLOWS
-void truncate_dbg() {
-  ftruncate(fileno(dbg_file), 0);
-}
-#endif
-
 int main(int argc, char **argv) {
   int i, c;
 
   time(&stats.boot_time);
 
   log_init();
-  while ((c = getopt(argc, argv, "c:")) != -1) {
+  while ((c = getopt(argc, argv, "c:lt")) != -1) {
     switch (c) {
     case 'c':
       def_configfile = optarg;
       break;
+    case 'l':
+      opt_listenonly = 1;
+      break;
+    case 't':
+      info("TrackFlows: will insert flow id on outgoing packets\n");
+      opt_trackflows = 1;
+      break;
     default:
       fatal("Invalid command line argument.\n");
       exit(1);
@@ -1030,22 +1386,16 @@ int main(int argc, char **argv) {
   }
 
   if (argc - optind != 2) {
-#ifndef SIM
-    fatal("usage: %s [-c config] <device> <rate>\n", argv[0]);
+#ifndef SF_SRC
+    fatal("usage: %s [-c config] [-n] <device> <rate>\n", argv[0]);
 #else
     fatal("usage: %s [-c config] <host> <port>\n", argv[0]);
 #endif
     exit(2);
   }
     
-#ifdef DBG_TRACK_FLOWS
-  dbg_file = fopen("dbg.txt", "w");
-  if (dbg_file == NULL) {
-    perror("main: opening dbg file:");
-    exit(1);
-  }
-  signal(SIGUSR2, truncate_dbg);
-#endif
+  fifo_open();
+  signal(SIGINT,  driver_shutdown);
 
   if (config_parse(def_configfile, &driver_config) != 0) {
     fatal ("config parse of %s failed!\n", def_configfile);
@@ -1053,56 +1403,83 @@ int main(int argc, char **argv) {
   }
   globalPrefix = 1;
   memcpy(&__my_address, &driver_config.router_addr, sizeof(struct in6_addr));
-  
-  /* create the tunnel device */
-  dev[0] = 0;
-  tun_fd = tun_open(dev);
-  if (tun_fd < 1) {
-    fatal("Could not create tunnel device. Fatal.\n");
-    return 1;
+
+
+  struct vty_cmd_table t;
+  short vty_port = 6106;
+  t.n = sizeof(vty_cmd_list) / sizeof(struct vty_cmd);
+  t.table = vty_cmd_list;
+  if (vty_init(&t, vty_port) < 0) {
+    error("could not start debug console server\n");
+    error("the console will be available only on stdin\n");
   } else {
-    info("created tun device: %s\n", dev);
-  }
-  if (tun_setup(dev, &__my_address) < 0) {
-    fatal("configuring the tun failed; aborting\n");
-    perror("tun_setup");
-    return 1;
+    info("telnet console server running on port %i\n", vty_port);
   }
 
 
-  for (i = 0; i < N_RECONSTRUCTIONS; i++) {
-    reconstructions[i].timeout = T_UNUSED;
-  }
+  dev[0] = 0;
+  if (opt_listenonly) {
+    tun_fd = -1;
+#ifndef SF_SRC
+    ser_src = NULL;
+#endif
+  } else {
+    /* create the tunnel device */
+    tun_fd = tun_open(dev);
+    if (tun_fd < 1) {
+      fatal("Could not create tunnel device. Fatal.\n");
+      return 1;
+    } else {
+      info("created tun device: %s\n", dev);
+    }
+    if (tun_setup(dev, &__my_address) < 0) {
+      fatal("configuring the tun failed; aborting\n");
+      perror("tun_setup");
+      return 1;
+    }
+    
+    
+    for (i = 0; i < N_RECONSTRUCTIONS; i++) {
+      reconstructions[i].timeout = T_UNUSED;
+    }
 
-  /* open the serial port */
-#ifndef SIM
-  ser_src = open_serial_source(argv[optind], platform_baud_rate(argv[optind + 1]),
-                               1, stderr_msg);
-  if (!ser_src) {
-    fatal("Couldn't open serial port at %s:%s\n", argv[optind], argv[optind + 1]);
-    exit(1);
-  }
+    /* open the serial port */
+#ifndef SF_SRC
+    ser_src = open_serial_source(argv[optind], platform_baud_rate(argv[optind + 1]),
+                                 1, stderr_msg);
+    if (!ser_src) {
+      fatal("Couldn't open serial port at %s:%s\n", argv[optind], argv[optind + 1]);
+      exit(1);
+    }
 #else
-  sf_fd = open_sf_source(argv[optind], atoi(argv[optind + 1]));
-  if (sf_fd < 0) {
-    fatal("Couldn't connect to serial forwarder sf@%s:%s\n", argv[optind], argv[optind + 1]);
-    exit(1);
-  }
+    sf_fd = open_sf_source(argv[optind], atoi(argv[optind + 1]));
+    if (sf_fd < 0) {
+      fatal("Couldn't connect to serial forwarder sf@%s:%s\n", argv[optind], argv[optind + 1]);
+      exit(1);
+    }
 #endif
 
-  info("Press 'h' for help\n");
-
-  routing_init(&driver_config, dev);
 #ifndef SIM
   configure_reboot();
 #endif
 
+  }
+
+  if (routing_init(&driver_config, dev) < 0) {
+    fatal("could not start routing engine!\n");
+    exit(1);
+  }
+
   /* start tunneling */
   serial_tunnel(tun_fd);
 
   /* clean up */
-  // close_serial_source(ser_src);
-  // close(ser_fd);
-  tun_close(tun_fd, dev);
+  info("driver shutting down\n");
+  vty_shutdown();
+  if (!opt_listenonly)  {
+    tun_close(tun_fd, dev);
+    close_pan();
+  }
+  fifo_close();
   return 0;
 }
index 684efb94a3bf6b8d6a598aff91f5e13524a759f0..3caf41f8ec200fe613f57f2639787722c4e81c15 100644 (file)
@@ -67,6 +67,7 @@
 
 #include "lib6lowpan.h"
 #include "tun_dev.h"
+#include "logging.h"
 
 
 /*
@@ -104,7 +105,7 @@ int tun_open(char *dev)
     return fd;
 
   failed:
-    perror("tun_open");
+    log_fatal_perror("tun_open");
     close(fd);
     return -1;
 }
@@ -122,19 +123,19 @@ int tun_setup(char *dev, struct in6_addr *addr) {
 
   /* set the interface up */
   if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
-    perror("SIOCGIFFLAGS");
+    log_fatal_perror("SIOCGIFFLAGS");
     return -1;
   }
   ifr.ifr_flags |= IFF_UP;
   if (ioctl(fd, SIOCSIFFLAGS, &ifr) < 0) {
-    perror("SIOCSIFFLAGS");
+    log_fatal_perror("SIOCSIFFLAGS");
     return -1;
   }
 
   /* MTU */
   ifr.ifr_mtu = 1280;
   if (ioctl(fd, SIOCSIFMTU, &ifr) < 0) {
-    perror("SIOCSIFMTU");
+    log_fatal_perror("SIOCSIFMTU");
     return -1;
   }
 
@@ -142,14 +143,14 @@ int tun_setup(char *dev, struct in6_addr *addr) {
   memset(&ifr6, 0, sizeof(struct in6_ifreq));
   memcpy(&ifr6.ifr6_addr, addr, 16);
   if (ioctl(fd, SIOGIFINDEX, &ifr) < 0) {
-    perror("SIOGIFINDEX");
+    log_fatal_perror("SIOGIFINDEX");
     return -1;
   }
 
   ifr6.ifr6_ifindex = ifr.ifr_ifindex;
-  ifr6.ifr6_prefixlen = 64;
+  ifr6.ifr6_prefixlen = 128;
   if (ioctl(fd, SIOCSIFADDR, &ifr6) < 0) {
-    perror("SIOCSIFADDR (global)");
+    log_fatal_perror("SIOCSIFADDR (global)");
     return -1;
   }
 
@@ -158,7 +159,7 @@ int tun_setup(char *dev, struct in6_addr *addr) {
   ifr6.ifr6_addr.s6_addr16[7] = addr->s6_addr16[7];
   
   if (ioctl(fd, SIOCSIFADDR, &ifr6) < 0) {
-    perror("SIOCSIFADDR (local)");
+    log_fatal_perror("SIOCSIFADDR (local)");
     return -1;
   }
 
diff --git a/support/sdk/c/blip/driver/vty/Makefile b/support/sdk/c/blip/driver/vty/Makefile
new file mode 100644 (file)
index 0000000..69bf9a7
--- /dev/null
@@ -0,0 +1,6 @@
+
+test_SOURCE=test_srv.c vty.c util.c ../logging.c
+CFLAGS=-I.. -g
+
+test: $(test_SOURCE)
+       gcc $(test_SOURCE) -o $@ $(CFLAGS)
\ No newline at end of file
diff --git a/support/sdk/c/blip/driver/vty/test_srv.c b/support/sdk/c/blip/driver/vty/test_srv.c
new file mode 100644 (file)
index 0000000..a3c8f03
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * "Copyright (c) 2008, 2009 The Regents of the University  of California.
+ * All rights reserved."
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice, the following
+ * two paragraphs and the author appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
+ *
+ */
+
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+#include "logging.h"
+#include "vty.h"
+
+
+void do_echo(int fd, int argc, char ** argv) {
+  VTY_HEAD;
+  if (argc > 1) {
+    VTY_printf("%s\r\n", argv[1]);
+    VTY_flush();
+  }
+}
+
+struct vty_cmd echo = {"echo", do_echo};
+
+void shutdown() {
+  vty_shutdown();
+  exit(0);
+}
+
+int main(int argc, char **argv) {
+  int maxfd;
+  fd_set fds;
+  struct vty_cmd_table t;
+  log_init();
+  log_setlevel(LOGLVL_DEBUG);
+  
+  signal(SIGINT, shutdown);
+
+  t.n = 1;
+  t.table = &echo;
+
+
+  vty_init(&t, atoi(argv[1]));
+  while (1) {
+    FD_ZERO(&fds);
+    maxfd = vty_add_fds(&fds);
+
+    select(maxfd+1, &fds, NULL, NULL, NULL);
+
+    vty_process(&fds);
+  }
+  info("Done, exiting\n");
+
+}
diff --git a/support/sdk/c/blip/driver/vty/util.c b/support/sdk/c/blip/driver/vty/util.c
new file mode 100644 (file)
index 0000000..583e41d
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * "Copyright (c) 2008, 2009 The Regents of the University  of California.
+ * All rights reserved."
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice, the following
+ * two paragraphs and the author appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
+ *
+ */
+
+#include "vty.h"
+
+void init_argv(char *cmd, int len, char **argv, int *argc) {
+  int inArg = 0;
+  *argc = 0;
+  while (len > 0 && *argc < N_ARGS) {
+    if (*cmd == ' ' || *cmd == '\n' || 
+        *cmd == '\t' || *cmd == '\0' || 
+        *cmd == '\r' || *cmd == '\4' ||
+        len == 1){
+      if (inArg) {
+        *argc = *argc + 1;
+        inArg = 0;
+        *cmd = '\0';
+      }
+    } else if (!inArg) {
+      argv[*argc] = cmd;
+        inArg = 1;
+    }
+    cmd ++;
+    len --;
+  }
+}
diff --git a/support/sdk/c/blip/driver/vty/vty.c b/support/sdk/c/blip/driver/vty/vty.c
new file mode 100644 (file)
index 0000000..b5611c4
--- /dev/null
@@ -0,0 +1,318 @@
+/*
+ * "Copyright (c) 2008 The Regents of the University  of California.
+ * All rights reserved."
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice, the following
+ * two paragraphs and the author appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
+ *
+ */
+/*
+ * @author Stephen Dawson-Haggerty <stevedh@eecs.berkeley.edu>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <signal.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include "vty.h"
+#include "../logging.h"
+
+#define max(X,Y)  (((X) > (Y)) ?  (X) : (Y))
+
+typedef enum {
+  FALSE = 0,
+  TRUE  = 1,
+} bool;
+
+enum {
+  VTY_REMOVE_PENDING = 0x1,
+};
+
+struct vty_client {
+  int                 flags;
+  int                 readfd;
+  int                 writefd;
+  struct sockaddr_in  ep;
+  struct vty_client  *next;
+  
+  int                 buf_off;
+  unsigned char       buf[1024];
+};
+
+static int sock = -1;
+static struct vty_client *conns = NULL;
+static struct vty_cmd_table *cmd_tab;
+static char prompt_str[40];
+
+int vty_init(struct vty_cmd_table * cmds, short port) {
+  struct sockaddr_in si_me;
+  struct vty_client *tty_client;
+  int len, yes = 1;
+
+  conns = NULL;
+  cmd_tab = cmds;
+
+  strncpy(prompt_str, "blip:", 5);
+  gethostname(prompt_str+5, sizeof(prompt_str)- 5);
+  len=strlen(prompt_str+5);
+  prompt_str[len+5]='>';
+  prompt_str[len+6]=' ';
+  prompt_str[len+7]='\0';
+
+  if (isatty(fileno(stdin))) {
+    setbuf(stdin, NULL);
+    tty_client = (struct vty_client *)malloc(sizeof(struct vty_client));
+    memset(tty_client, 0, sizeof(struct vty_client));
+    tty_client->flags = 0;
+    tty_client->readfd = fileno(stdin);
+    tty_client->writefd = fileno(stdout);
+    tty_client->next = NULL;
+    conns = tty_client;
+  }
+
+  sock = socket(PF_INET, SOCK_STREAM, 0);
+  if (sock < 0) {
+    log_fatal_perror("vty: socket");
+    return -1;
+  }
+
+  if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) {
+    log_fatal_perror("vty: setsockopt");
+    goto abort;
+  }
+
+  si_me.sin_family = AF_INET;
+  si_me.sin_port = htons(port);
+  si_me.sin_addr.s_addr = htonl(INADDR_ANY);
+  if (bind(sock, (struct sockaddr *)&si_me, sizeof(si_me)) < 0) {
+    log_fatal_perror("vty: bind");
+    goto abort;
+  }
+
+  if (listen(sock, 2) < 0) {
+    log_fatal_perror("vty: listen");
+    goto abort;
+  }
+
+  return 0;
+ abort:
+  close(sock);
+  sock = -1;
+  return -1;
+}
+
+int vty_add_fds(fd_set *fds) {
+  int maxfd;
+  struct vty_client *cur;
+  if (sock >= 0) FD_SET(sock, fds);
+  maxfd = sock;
+
+  for (cur = conns; cur != NULL; cur = cur->next) {
+    if (cur->flags & VTY_REMOVE_PENDING) continue;
+    FD_SET(cur->readfd, fds);
+    maxfd = max(maxfd, cur->readfd);
+  }
+  return maxfd;
+}
+
+static void vty_print_string(struct vty_client *c, const char *fmt, ...) {
+  char buf[1024];
+  int len;
+  va_list ap;
+  va_start(ap, fmt);
+  len = vsnprintf(buf, 1024, fmt, ap);
+  write(c->writefd, buf, len);
+}
+
+static void prompt(struct vty_client *c) {
+  vty_print_string(c, prompt_str);
+}
+
+static void vty_new_connection() {
+  struct vty_client * c = malloc(sizeof(struct vty_client));
+  socklen_t len;
+  if (c == NULL) return;
+
+  len = sizeof(struct sockaddr_in);
+  c->readfd = c->writefd = accept(sock, (struct sockaddr *)&c->ep, &len);
+  if (c->readfd < 0) {
+    error("Accept failed!\n");
+    log_fatal_perror(0);
+    free(c);
+    return;
+  }
+  c->buf_off = 0;
+
+  info("VTY: new connection accepted from %s\n", inet_ntoa(c->ep.sin_addr));
+  vty_print_string(c, "Welcome to the blip console!\r\n");
+  vty_print_string(c, " type 'help' to print the command options\r\n");
+  prompt(c);
+  c->flags = 0;
+  c->next = conns;
+  conns = c;
+}
+
+void vty_close_connection(struct vty_client *c) {
+  close(c->readfd);
+  if (c->readfd != c->writefd) close(c->writefd);
+  c->flags |= VTY_REMOVE_PENDING;
+}
+
+
+void vty_dispatch_command(struct vty_client *c) {
+  int   argc, i;
+  char *argv[N_ARGS];
+  init_argv((char *)c->buf, c->buf_off, argv, &argc);
+
+  if (argc > 0) {
+    for (i = 0; i < cmd_tab->n; i++) {
+      if (strncmp(argv[0], cmd_tab->table[i].name, 
+                  strlen(cmd_tab->table[i].name)) == 0) {
+        cmd_tab->table[i].fn(c->writefd, argc, argv);
+        break;
+      }
+      
+      if (strncmp(argv[0], "quit", 4) == 0) {
+        vty_close_connection(c);
+        return;
+      }
+    }
+  }
+  prompt(c);
+}
+
+void vty_handle_data(struct vty_client *c) {
+  int len, i;
+  bool prompt_pending = FALSE;
+  len = read(c->readfd, c->buf + c->buf_off, sizeof(c->buf) - c->buf_off);
+  if (len <= 0) {
+    warn("Invalid read on connection from %s: closing\n", 
+         inet_ntoa(c->ep.sin_addr));
+    vty_close_connection(c);
+  }
+  c->buf_off += len;
+  // try to scan the whole line we're building up and remove/process
+  // any telnet escapes in there
+  for (i = 0; i < c->buf_off; i++) {
+    int escape_len;
+
+    if (c->buf[i] == 255) {
+      escape_len = 2;
+      // process and remove a command;
+      // the command code is in buf[i+1]
+      switch (c->buf[i+1]) {
+      case TELNET_INTERRUPT:
+        // ignore the command buffer we've accumulated
+        memmove(&c->buf[0], &c->buf[i+2], c->buf_off - i - 2);
+        c->buf_off -= i + 2;
+        i = -1;
+        prompt_pending = TRUE;
+        continue;
+      }
+      if (c->buf[i+1] >= 250) {
+        unsigned char response[3];
+        // we don't do __anything__
+        response[0] = 255;
+        response[1] = TELNET_WONT;
+        response[2] = c->buf[i+2];
+        write(c->writefd, response, 3);
+        escape_len++;
+      }
+
+      // this isn't like the most efficient parser ever, but since we
+      // don't ask for anything and reply to everyone with DONT it seems okay.
+      memmove(&c->buf[i], &c->buf[i+escape_len], 
+              c->buf_off - (i + escape_len));
+      c->buf_off -= escape_len;
+      // restart processing at the same place
+      i--;
+    } else if (c->buf[i] == 4) {
+      // EOT : make C-d work
+      vty_close_connection(c);
+    }
+    // technically, clients are supposed to send \r\n as a newline.
+    // however, the client in busybox (an important one) doesn't
+    // escape the terminal input and so only sends \n.
+    if (/* i > 0 && c->buf[i-1] == '\r' && */ c->buf[i] == '\n') {
+      c->buf[i] = '\0';
+      prompt_pending = FALSE;
+      vty_dispatch_command(c);
+
+      // start a new command at the head of the buffer
+      memmove(&c->buf[0], &c->buf[i+1], c->buf_off - i - 1);
+      c->buf_off -= i + 1;
+      i = -1;
+    }
+  }
+  
+  if (prompt_pending) {
+    vty_print_string(c, "\r\n");
+    prompt(c);
+    prompt_pending = FALSE;
+  }
+}
+
+int vty_process(fd_set *fds) {
+  struct vty_client *prev, *cur, *next;
+  if (sock >= 0 && FD_ISSET(sock, fds)) {
+    vty_new_connection();
+  }
+  for (cur = conns; cur != NULL; cur = cur->next) {
+    if (FD_ISSET(cur->readfd, fds)) {
+      vty_handle_data(cur);
+    }
+  }
+
+  prev = NULL;
+  cur = conns;
+  while (cur != NULL) {
+    next = cur->next;
+    if (cur->flags & VTY_REMOVE_PENDING) {
+      info("VTY: removing connection with endpoint %s\n", 
+           inet_ntoa(cur->ep.sin_addr));
+      free(cur);
+      if (cur == conns) conns = next;
+      if (prev != NULL) prev->next = next;
+    } else {
+      prev = cur;
+    }
+    cur = next;
+  }
+
+  return 0;
+}
+
+void vty_shutdown() {
+  struct vty_client *cur = conns, *next;
+  if (sock >= 0) close(sock);
+
+  while (cur != NULL) {
+    next = cur->next;
+    if (!(cur->flags & VTY_REMOVE_PENDING)) {
+      close(cur->readfd);
+      if (cur->readfd != cur->writefd) close(cur->writefd);
+    }
+    free(cur);
+    cur = next;
+  }
+}
diff --git a/support/sdk/c/blip/driver/vty/vty.h b/support/sdk/c/blip/driver/vty/vty.h
new file mode 100644 (file)
index 0000000..37bcca3
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * "Copyright (c) 2008 The Regents of the University  of California.
+ * All rights reserved."
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice, the following
+ * two paragraphs and the author appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
+ *
+ */
+/*
+ * @author Stephen Dawson-Haggerty <stevedh@eecs.berkeley.edu>
+ *
+ * This is a very simple set of functions to allow a program using a
+ * single blocking select() loop to include a telnet server.  Most of
+ * the telnet RFC854 protocol is not implemented; this just gives you
+ * an easy way to add a simple shell that doesn't do much.
+ *
+ * Readline-like editing would be nice; unfortunatly readline itself
+ * is GPL, so it's not an option.
+ */
+
+#ifndef _VTY_H_
+#define _VTY_H_
+
+#include <unistd.h>
+#include <sys/select.h>
+
+// helpful macros since you can't do straight printf() on a socket
+#define VTY_HEAD                  char __vty_buf[4096]; int __vty_len = 0
+#define VTY_printf(fmt, args...)  __vty_len += snprintf(__vty_buf + __vty_len, 4096 - __vty_len, \
+                                                        fmt, ## args)
+#define VTY_flush()               write(fd, __vty_buf, __vty_len); __vty_len = 0
+
+#define VTYNAMSIZ 16
+
+// set these up and pass it to vty_init().  the only builtin is 'quit'.
+struct vty_cmd {
+  char name[VTYNAMSIZ];
+  void (*fn)(int fd, int argc, char **argv);
+};
+
+struct vty_cmd_table {
+  int              n;
+  struct vty_cmd * table;
+};
+
+int  vty_init(struct vty_cmd_table *cmd_tab, short port);
+int  vty_add_fds(fd_set *fds);
+int  vty_process(fd_set *fds);
+void vty_shutdown();
+
+// defined in util.c  N_ARGS is the maximum number length of argv.
+#define N_ARGS  30
+void init_argv(char *cmd, int len, char **argv, int *argc);
+
+
+// values from telnet rfc854.  We don't implement very much at all of
+// the telnet protocol
+#define TELNET_INTERRUPT 244
+#define TELNET_WONT      252
+
+#endif
index 76ddd7586abc6836e295857cafda3bfa8a1fd418..65c26717421889563ba06f2da2cf35cdd98b3f73 100644 (file)
@@ -38,7 +38,7 @@
 typedef uint8_t ip6_addr_t [16];
 typedef uint16_t cmpr_ip6_addr_t;
 #ifdef PC
-typedef uint16_t hw_addr_t;
+typedef uint16_t ieee154_saddr_t;
 typedef uint16_t hw_pan_t;
 enum {
   HW_BROADCAST_ADDR = 0xffff,
@@ -72,8 +72,8 @@ typedef struct packed_lowmsg {
   uint8_t headers;
   uint8_t len;
   // we preprocess the headers bitmap for easy processing.
-  hw_addr_t src;
-  hw_addr_t dst;
+  ieee154_saddr_t src;
+  ieee154_saddr_t dst;
   uint8_t *data;
 } packed_lowmsg_t;
 
@@ -126,22 +126,6 @@ enum {
   LOWPAN_MESH_HOPS_MASK = 0x0f,
 };
 
-/*
- * IP protocol numbers
- */
-enum {
-  IANA_ICMP = 58,
-  IANA_UDP = 17,
-  IANA_TCP = 6,
-
-  NXTHDR_SOURCE = 0,
-  NXTHDR_INSTALL   = 253, // Use for experimentation and testing(IANA.org)
-  NXTHDR_TOPO      = 252,
-  NXTHDR_UNKNOWN = 0xff,
-};
-
-#define KNOWN_HEADER(X)  ((X) == NXTHDR_SOURCE || (X) == IANA_UDP || (X) == NXTHDR_INSTALL || (X) == NXTHDR_TOPO)
-
 /*
  * constants to unpack HC-packed headers
  */
@@ -181,55 +165,22 @@ enum {
 };
 
 
-/*
- * nonstandard source routing header fields
- */
-enum {
-  IP_EXT_SOURCE_DISPATCH    = 0x40,
-  IP_EXT_SOURCE_MASK        = 0xc0,
-
-  // dispatch values
-  IP_EXT_SOURCE_RECORD      = 0x01,
-  IP_EXT_SOURCE_RECORD_MASK = 0x01,
-  IP_EXT_SOURCE_INVAL       = 0x02,
-  IP_EXT_SOURCE_INVAL_MASK  = 0x02,
-  IP_EXT_SOURCE_CONTROLLER  = 0x04,
-
-  // dispatch values for route installation if this flag is set, the
-  // source_header must be immediately followed by a
-  // source_install_opt struct.
-  IP_EXT_SOURCE_INSTALL     = 0x10,
-  IP_EXT_SOURCE_INSTALL_MASK= 0x10,
-
-  // indicates weather the forward and reverse paths should be
-  // installed.  Are these needed?  the only case when we don't want
-  // to install the reverse path is when the destination is a
-  // multicast?
-  IP_EXT_SOURCE_INST_SRC    = 0x20,
-  IP_EXT_SOURCE_INST_DST    = 0x40,
-};
-
-#define SH_NENTRIES(SH)   ((sh->len - (sizeof(struct source_header))) / (sizeof(uint16_t)))
-
-struct source_header {
-  uint8_t nxt_hdr;
-  uint8_t len;
-  // the equalivent of the "routing type" field
-  uint8_t dispatch;
-  uint8_t current;
-  uint16_t hops[0];
-};
 
 // AT: These are really 16 bit values, but after a certain point the numbers
 //  beyond 255 aren't important to us, or rather no different than 255
 struct topology_entry {
   uint8_t etx;
   uint8_t conf;
-  hw_addr_t hwaddr;
+  ieee154_saddr_t hwaddr;
 };
 struct topology_header {
-  uint8_t nxt_hdr;
-  uint8_t len;
+  uint16_t seqno;
+  struct topology_entry topo[0];
+};
+struct topology_header_package {
+  uint16_t reporter;
+  uint16_t len;
+  uint16_t seqno;
   struct topology_entry topo[0];
 };
 
@@ -237,4 +188,8 @@ enum {
   IP_NUMBER_FRAGMENTS = 12,
 };
 
+#ifndef BLIP_L2_RETRIES
+#define BLIP_L2_RETRIES 10
+#endif
+
 #endif
diff --git a/support/sdk/c/blip/include/TrackFlows.h b/support/sdk/c/blip/include/TrackFlows.h
new file mode 100644 (file)
index 0000000..0e90c51
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * "Copyright (c) 2008, 2009 The Regents of the University  of California.
+ * All rights reserved."
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice, the following
+ * two paragraphs and the author appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
+ *
+ */
+#ifndef TRACKFLOWS_H_
+#define TRACKFLOWS_H_
+
+#ifndef PC
+enum {
+  AM_FLOW_ID_MSG = 248,
+};
+
+nx_struct flow_id {
+  nxle_uint16_t id;
+};
+
+nx_struct flow_id_msg {
+  nx_struct flow_id flow;
+  nxle_uint16_t src;
+  nxle_uint16_t dst;
+  nxle_uint16_t local_address;
+  nxle_uint8_t nxt_hdr;
+  nxle_uint8_t n_attempts;
+  nx_struct {
+    nxle_uint16_t next_hop;
+    nxle_uint16_t tx;
+  } attempts[3];
+};
+#else
+
+#include <stdint.h>
+struct flow_id {
+  uint16_t id;
+};
+
+
+struct flow_id_msg {
+  uint16_t flow;
+  uint16_t src;
+  uint16_t dst;
+  uint16_t local_address;
+  uint8_t nxt_hdr;
+  uint8_t n_attempts;
+  struct {
+    uint16_t next_hop;
+    uint16_t tx;
+  } attempts[3];
+};
+#endif
+
+#endif
index 3a56d1b96f770b3fb676632262b2d32e2c6e8b50..8d8a34cb153b8ecb67d6c51e6c1dfc579801e018 100644 (file)
@@ -28,6 +28,7 @@ enum {
   CONFIG_ECHO = 0,       // ping the device for status information
   CONFIG_SET_PARM = 1,   // instruct the device to set its hardware addr
   CONFIG_REBOOT = 2,
+  CONFIG_KEEPALIVE = 3,
 };
 
 enum {
@@ -36,6 +37,11 @@ enum {
   CONFIG_ERROR_BOOTED,
 };
 
+enum {
+  KEEPALIVE_INTERVAL = 500000,
+  KEEPALIVE_TIMEOUT = 5000,
+};
+                                  
 #ifndef PC
 
 
@@ -73,7 +79,7 @@ typedef struct config_cmd {
     uint16_t delay;
   } retx;
   struct {
-    hw_addr_t addr;
+    ieee154_saddr_t addr;
     uint8_t channel;
   } rf;
 } __attribute__((packed)) config_cmd_t;
@@ -82,7 +88,7 @@ typedef struct config_cmd {
 
 typedef struct {
   uint8_t error;
-  hw_addr_t addr;
+  ieee154_saddr_t addr;
   uint16_t serial_read;
   uint16_t radio_read;
   uint16_t serial_fail;
index e48163f8386d0679880869fd7bffb50a37753044..666cc1f26ba12826b23f71d5e984c0acc96ac3ca 100644 (file)
@@ -92,6 +92,78 @@ struct ip6_ext {
   uint8_t data[0];
 };
 
+struct tlv_hdr {
+  uint8_t type;
+  uint8_t len;
+};
+/*
+ * IP protocol numbers
+ */
+enum {
+  IANA_ICMP = 58,
+  IANA_UDP = 17,
+  IANA_TCP = 6,
+
+  // IPV6 defined extention header types.  All other next header
+  // values are supposed to be transport protocols, with TLVs used
+  IPV6_HOP = 0,
+  IPV6_DEST = 60,
+  IPV6_ROUTING = 43,
+  IPV6_FRAG = 44,
+  IPV6_AUTH = 51,
+  IPV6_SEC = 50,
+  IPV6_MOBILITY = 135,
+  IPV6_NONEXT = 59,
+};
+#define EXTENSION_HEADER(X) ((X) == IPV6_HOP || (X) == IPV6_ROUTING || (X) == IPV6_DEST)
+#define COMPRESSIBLE_TRANSPORT(X) ((X) == IANA_UDP)
+
+/*
+ * nonstandard source routing header fields
+ */
+enum {
+  IP6ROUTE_TYPE_SOURCE  = 0,
+  IP6ROUTE_TYPE_INVAL   = 1,
+  IP6ROUTE_FLAG_CONTROLLER = 0x8,
+  IP6ROUTE_FLAG_MASK = IP6ROUTE_FLAG_CONTROLLER,
+
+  IP_EXT_SOURCE_DISPATCH    = 0x40,
+  IP_EXT_SOURCE_MASK        = 0xc0,
+
+  // dispatch values
+  IP_EXT_SOURCE_CONTROLLER  = 0x40,
+
+  // dispatch values for route installation if this flag is set, the
+  // source_header must be immediately followed by a
+  // source_install_opt struct.
+  IP_EXT_SOURCE_INSTALL     = 0x10,
+  IP_EXT_SOURCE_INSTALL_MASK= 0x10,
+
+  // indicates weather the forward and reverse paths should be
+  // installed.  Are these needed?  the only case when we don't want
+  // to install the reverse path is when the destination is a
+  // multicast?
+  IP_EXT_SOURCE_INST_SRC    = 0x20,
+  IP_EXT_SOURCE_INST_DST    = 0x40,
+
+  // a topology TLV inside a destination option
+  TLV_TYPE_TOPOLOGY = 0x0a,
+  // a route install message, inside a hop-by-hop or destination
+  // option message.
+  TLV_TYPE_INSTALL  = 0x0b,
+  TLV_TYPE_FLOW     = 0x0c,
+};
+
+struct ip6_route {
+  uint8_t nxt_hdr;
+  uint8_t len;
+  uint8_t type;
+  uint8_t segs_remain;
+  uint16_t hops[0];
+};
+#define ROUTE_NENTRIES(SH)   (((SH)->len - (sizeof(struct ip6_route))) / (sizeof(uint16_t)))
+
+
 /*
  * icmp
  */
@@ -158,7 +230,7 @@ struct tcp_hdr {
  * IP metadata and routing structures
  */
 struct ip_metadata {
-  hw_addr_t sender;
+  ieee154_saddr_t sender;
   uint8_t   lqi;
   uint8_t   padding[1];
 };
@@ -166,51 +238,34 @@ struct ip_metadata {
 struct flow_match {
   cmpr_ip6_addr_t src;
   cmpr_ip6_addr_t dest; // Need to make this more extensible at some point
-  cmpr_ip6_addr_t prev_hop;
 };
 
 struct rinstall_header {
-  struct ip6_ext ext;
-  uint16_t flags;
   struct flow_match match;
+  uint8_t flags;
   uint8_t path_len;
-  uint8_t current;
   cmpr_ip6_addr_t path[0];
 };
 
 enum {
-  R_SRC_FULL_PATH_INSTALL_MASK = 0x01,
-  R_DEST_FULL_PATH_INSTALL_MASK = 0x02,
-  R_HOP_BY_HOP_PATH_INSTALL_MASK = 0x04,
-  R_REVERSE_PATH_INSTALL_MASK = 0x08,
-  R_SRC_FULL_PATH_UNINSTALL_MASK = 0x10,
-  R_DEST_FULL_PATH_UNINSTALL_MASK = 0x20,
-  R_HOP_BY_HOP_PATH_UNINSTALL_MASK = 0x40,
-  R_REVERSE_PATH_UNINSTALL_MASK = 0x80,
-};
+  // is this a hop-by-hop or source install command
+  HYDRO_INSTALL_METHOD_MASK    = 0x03,
+  HYDRO_METHOD_HOP             = 0x01,
+  HYDRO_METHOD_SOURCE          = 0x02,
 
-#define IS_FULL_SRC_INSTALL(r) (((r)->flags & R_SRC_FULL_PATH_INSTALL_MASK) == R_SRC_FULL_PATH_INSTALL_MASK)
-#define IS_FULL_DST_INSTALL(r) (((r)->flags & R_DEST_FULL_PATH_INSTALL_MASK) == R_DEST_FULL_PATH_INSTALL_MASK)
-#define IS_HOP_INSTALL(r) (((r)->flags & R_HOP_BY_HOP_PATH_INSTALL_MASK) == R_HOP_BY_HOP_PATH_INSTALL_MASK)
-#define IS_REV_INSTALL(r) (((r)->flags & R_REVERSE_PATH_INSTALL_MASK) == R_REVERSE_PATH_INSTALL_MASK)
-#define IS_FULL_SRC_UNINSTALL(r) (((r)->flags & R_SRC_FULL_PATH_UNINSTALL_MASK) == R_SRC_FULL_PATH_UNINSTALL_MASK)
-#define IS_FULL_DST_UNINSTALL(r) (((r)->flags & R_DEST_FULL_PATH_UNINSTALL_MASK) == R_DEST_FULL_PATH_UNINSTALL_MASK)
-#define IS_HOP_UNINSTALL(r) (((r)->flags & R_HOP_BY_HOP_PATH_UNINSTALL_MASK) == R_HOP_BY_HOP_PATH_UNINSTALL_MASK)
-#define IS_REV_UNINSTALL(r) (((r)->flags & R_REVERSE_PATH_UNINSTALL_MASK) == R_REVERSE_PATH_UNINSTALL_MASK)
+  // should we also apply the action to the reverse path?
+  HYDRO_INSTALL_REVERSE        = 0x04,
+
+  // is this an uninstallation?
+  HYDRO_INSTALL_UNINSTALL_MASK = 0x08,
+
+};
 
 enum {
   T_INVAL_NEIGH =  0xef,
   T_SET_NEIGH = 0xee,
 };
 
-struct flow_id {
-  uint16_t src;
-  uint16_t dst;
-  uint16_t id;
-  uint16_t seq;
-  uint16_t nxt_hdr;
-};
-
 
 /*
  * These are data structures to hold IP messages.  We used a linked
@@ -235,25 +290,26 @@ struct generic_header {
   union {
     // this could be an eumeration of all the valid headers we can have here.
     struct ip6_ext *ext;
-    struct source_header *sh;
+    struct ip6_route *sh;
     struct udp_hdr *udp;
-    struct tcp_hdr *tcp;
-    struct rinstall_header *rih;
-    struct topology_header *th;
     uint8_t *data;
   } hdr;
   struct generic_header *next;
 };
 
+enum {
+  IP_NOHEADERS = 1,
+};
+
 struct split_ip_msg {
   struct generic_header *headers;
   uint16_t data_len;
   uint8_t *data;
 #ifdef PC
+  uint16_t foo;
+  uint16_t flow_id;
+  uint16_t prev_hop;
   struct ip_metadata metadata;
-#ifdef DBG_TRACK_FLOWS
-  struct flow_id id;
-#endif
   // this must be last so we can read() straight into the end of the buffer.
   struct tun_pi pi;
 #endif
@@ -261,9 +317,12 @@ struct split_ip_msg {
   uint8_t next[0];
 };
 
+#ifndef NO_LIB6LOWPAN_ASCII
 /*
  * parse a string representation of an IPv6 address
  */ 
 void inet_pton6(char *addr, struct in6_addr *dest);
+int  inet_ntop6(struct in6_addr *addr, char *buf, int cnt);
+#endif
 
 #endif
index dbd0db59117c3e280b35ad249ab2159e187dfc3d..02e3e2e450c2e11fa792fdc076f51b84155c553a 100644 (file)
@@ -1,3 +1,24 @@
+/*
+ * "Copyright (c) 2008, 2009 The Regents of the University  of California.
+ * All rights reserved."
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice, the following
+ * two paragraphs and the author appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
+ *
+ */
 #ifndef NO_IP_MALLOC
 #ifndef IP_MALLOC_H_
 #define IP_MALLOC_H_
index 8723c29292ae2071579e077d7c10f332d3958344..4596ac960abde51afc1184f856a9f0b94dd640b2 100644 (file)
  */
 #ifndef _LIB6LOWPAN_H_
 #define _LIB6LOWPAN_H_
-
 #include <stdint.h>
 #include <stddef.h>
 
 #include "6lowpan.h"
 #include "ip.h"
 
-#ifdef __TARGET_mips__
-// #warning "Using big endian byte order"
-#define ntoh16(X)   (X)
-#define hton16(X)   (X)
-#define ntoh32(X)   (X)
-#define hton32(X)   (X)
+#if defined(PC) || defined(__TARGET_mips__)
+// use library versions if on linux
+#include <netinet/in.h>
+#define ntoh16(X)   ntohs(X)
+#define hton16(X)   htons(X)
+#define ntoh32(X)   ntohl(X)
+#define hton32(X)   htonl(X)
+
+#if defined(PC)
+#define leton16(X)  hton16(X)
+#ifndef htole16
+#define htole16(X)  (X)
+#endif
+#else
 #define leton16(X)  (((((uint16_t)(X)) << 8) | ((uint16_t)(X) >> 8)) & 0xffff)
 #define htole16(X)  leton16(X)
-#else
-// #warning "Using little endian byte order"
-#define ntoh16(X)   (((((uint16_t)(X)) >> 8) | ((uint16_t)(X) << 8)) & 0xffff)
-#define hton16(X)   (((((uint16_t)(X)) << 8) | ((uint16_t)(X) >> 8)) & 0xffff)
+#endif
+
+#else 
+// otherwise have to provide our own 
+
 #define leton16(X)  hton16(X)
+#ifndef htole16
 #define htole16(X)  (X)
-#define ntoh32(X)   ((((uint32_t)(X) >> 24) & 0x000000ff)| \
-                     ((((uint32_t)(X) >> 8)) & 0x0000ff00) | \
-                     ((((uint32_t)(X) << 8)) & 0x00ff0000) | \
-                     ((((uint32_t)(X) << 24)) & 0xff000000))
-
-#define hton32(X)   ((((uint32_t)(X) << 24) & 0xff000000)| \
-                     ((((uint32_t)(X) << 8)) & 0x00ff0000) | \
-                     ((((uint32_t)(X) >> 8)) & 0x0000ff00) | \
-                     ((((uint32_t)(X) >> 24)) & 0x000000ff))
 #endif
 
+#define ntoh16(X)   (((((uint16_t)(X)) >> 8) | ((uint16_t)(X) << 8)) & 0xffff)
+#define hton16(X)   (((((uint16_t)(X)) << 8) | ((uint16_t)(X) >> 8)) & 0xffff)
+
+/* this is much more efficient since gcc can insert swpb now.  */
+static uint32_t __attribute__((unused))  ntoh32(uint32_t i) {
+  uint16_t lo = (uint16_t)i;
+  uint16_t hi = (uint16_t)(i >> 16);
+  lo = (lo << 8) | (lo >> 8);
+  hi = (hi << 8) | (hi >> 8);
+  return (((uint32_t)lo) << 16) | ((uint32_t)hi);
+}                                                                                                                      
+#define hton32(X) ntoh32(X)
 
 #define ntohs(X) ntoh16(X)
 #define htons(X) hton16(X)
-
 #define ntohl(X) ntoh32(X)
 #define htonl(X) hton32(X)
 
+#endif
+
 
 #ifdef DEF_MEMCPY
 #define memcpy(X,Y,Z) ip_memcpy(X,Y,Z)
@@ -106,10 +119,10 @@ uint8_t setupHeaders(packed_lowmsg_t *packed, uint16_t headers);
 /*
  * Test if various protocol features are enabled
  */
-uint8_t hasMeshHeader(packed_lowmsg_t *msg);
-uint8_t hasBcastHeader(packed_lowmsg_t *msg);
-uint8_t hasFrag1Header(packed_lowmsg_t *msg);
-uint8_t hasFragNHeader(packed_lowmsg_t *msg);
+inline uint8_t hasMeshHeader(packed_lowmsg_t *msg);
+inline uint8_t hasBcastHeader(packed_lowmsg_t *msg);
+inline uint8_t hasFrag1Header(packed_lowmsg_t *msg);
+inline uint8_t hasFragNHeader(packed_lowmsg_t *msg);
 
 /*
  * Mesh header fields
@@ -117,12 +130,12 @@ uint8_t hasFragNHeader(packed_lowmsg_t *msg);
  *  return FAIL if the message doesn't have a mesh header
  */
 uint8_t getMeshHopsLeft(packed_lowmsg_t *msg, uint8_t *hops);
-uint8_t getMeshOriginAddr(packed_lowmsg_t *msg, hw_addr_t *origin);
-uint8_t getMeshFinalAddr(packed_lowmsg_t *msg, hw_addr_t *final);
+uint8_t getMeshOriginAddr(packed_lowmsg_t *msg, ieee154_saddr_t *origin);
+uint8_t getMeshFinalAddr(packed_lowmsg_t *msg, ieee154_saddr_t *final);
 
 uint8_t setMeshHopsLeft(packed_lowmsg_t *msg, uint8_t hops);
-uint8_t setMeshOriginAddr(packed_lowmsg_t *msg, hw_addr_t origin);
-uint8_t setMeshFinalAddr(packed_lowmsg_t *msg, hw_addr_t final);
+uint8_t setMeshOriginAddr(packed_lowmsg_t *msg, ieee154_saddr_t origin);
+uint8_t setMeshFinalAddr(packed_lowmsg_t *msg, ieee154_saddr_t final);
 
 /*
  * Broadcast header fields
@@ -134,19 +147,20 @@ uint8_t setBcastSeqno(packed_lowmsg_t *msg, uint8_t seqno);
 /*
  * Fragmentation header fields
  */
-uint8_t getFragDgramSize(packed_lowmsg_t *msg, uint16_t *size);
-uint8_t getFragDgramTag(packed_lowmsg_t *msg, uint16_t *tag);
-uint8_t getFragDgramOffset(packed_lowmsg_t *msg, uint8_t *size);
+inline uint8_t getFragDgramSize(packed_lowmsg_t *msg, uint16_t *size);
+inline uint8_t getFragDgramTag(packed_lowmsg_t *msg, uint16_t *tag);
+inline uint8_t getFragDgramOffset(packed_lowmsg_t *msg, uint8_t *size);
 
-uint8_t setFragDgramSize(packed_lowmsg_t *msg, uint16_t size);
-uint8_t setFragDgramTag(packed_lowmsg_t *msg, uint16_t tag);
-uint8_t setFragDgramOffset(packed_lowmsg_t *msg, uint8_t size);
+inline uint8_t setFragDgramSize(packed_lowmsg_t *msg, uint16_t size);
+inline uint8_t setFragDgramTag(packed_lowmsg_t *msg, uint16_t tag);
+inline uint8_t setFragDgramOffset(packed_lowmsg_t *msg, uint8_t size);
 
 /*
  * IP header compression functions
  *
  */
-int getCompressedLen(packed_lowmsg_t *pkt);
+
+// int getCompressedLen(packed_lowmsg_t *pkt);
 
 /*
  * Pack the header fields of msg into buffer 'buf'.
@@ -183,13 +197,16 @@ typedef struct {
   //  if it was not, it is the same as header_end
   uint8_t *transport_ptr;
   // points to the source header within the packed fields, IF it contains one.
-  struct source_header *sh;
-  struct rinstall_header *rih;
+  struct ip6_ext   *hdr_hop;
+  struct ip6_route *hdr_route;
+  struct ip6_ext   *hdr_dest;
 } unpack_info_t;
 
 uint8_t *unpackHeaders(packed_lowmsg_t *pkt, unpack_info_t *u_info,
                        uint8_t *dest, uint16_t len);
 
+void adjustPlen(struct ip6_hdr *ip, unpack_info_t *u_info);
+
 /*
  * Fragmentation routines.
  */
@@ -203,6 +220,7 @@ typedef struct {
   uint16_t bytes_rcvd;     /* how many bytes from the packet we have
                               received so far */
   uint8_t timeout;
+  uint8_t nxt_hdr;
   uint8_t *transport_hdr;
   struct ip_metadata metadata;
 } reconstruct_t;
index fb34df22f60ab588a9de5e0e6209a4dcad5bf384..41faf0323cab230c9b43f744db98bee21d68d065 100644 (file)
@@ -1,6 +1,7 @@
 
 SOURCES=lib6lowpan.c lib6lowpanIP.c  lib6lowpanFrag.c
 INCLUDE=../include/
+IP_HDRS=$(INCLUDE)/6lowpan.h $(INCLUDE)/ip.h $(INCLUDE)/lib6lowpan.h
 
 ###############
 ##
@@ -12,7 +13,7 @@ ifndef AR
 AR=ar
 endif
 
-CFLAGS=-DPC -g -I$(INCLUDE)
+CFLAGS=-DPC -g -I$(INCLUDE) 
 TEST=testhc.c
 
 ###############
@@ -32,14 +33,12 @@ $(LIB): $(OBJS)
 test: $(SOURCES) $(TEST) $(LIB)
        $(GCC) -o $@ $(TEST) $(CFLAGS) $(LIB) printpacket.c
 
-%.o: %.c
+%.o:  %.c
        $(GCC) -o $@ $< $(CFLAGS) -c
 
 clean:
        rm -f test $(OBJS) $(LIB)
 
-lib6lowpan.o: lib6lowpan.c ip-hdrs
-lib6lowpanIP.o: lib6lowpanIP.c ip-hdrs
-lib6lowpanFrag.o: lib6lowpanFrag.c ip-hdrs
-
-ip-hdrs: $(INCLUDE)/6lowpan.h $(INCLUDE)/ip.h $(INCLUDE)/lib6lowpan.h
\ No newline at end of file
+lib6lowpan.o: lib6lowpan.c $(IP_HDRS)
+lib6lowpanIP.o: lib6lowpanIP.c $(IP_HDRS)
+lib6lowpanFrag.o: lib6lowpanFrag.c $(IP_HDRS)
index 0ace8e7a9c31371fcdd4c0a4c092a5635a684888..9149efd3d00e2a6dfb70107426fc09620b75b501 100644 (file)
@@ -1,3 +1,24 @@
+/*
+ * "Copyright (c) 2008, 2009 The Regents of the University  of California.
+ * All rights reserved."
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice, the following
+ * two paragraphs and the author appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
+ *
+ */
 #ifndef NO_IP_MALLOC
 #include <stdint.h>
 #include <stdio.h>
index 3ebe2f675dcaba1cdd8e2890235b031ee442b568..b7b676cc7541c02b90e979c1e1798ca0b8cbb997 100644 (file)
@@ -50,7 +50,7 @@
  * Return the length (in bytes) of the buffer required to pack lowmsg
  * into a buffer.
  */
-uint8_t *getLowpanPayload(packed_lowmsg_t *lowmsg) {
+inline uint8_t *getLowpanPayload(packed_lowmsg_t *lowmsg) {
   uint8_t len = 0;
 #if LIB6LOWPAN_FULL
   if (lowmsg->headers & LOWMSG_MESH_HDR)
@@ -70,7 +70,7 @@ uint8_t *getLowpanPayload(packed_lowmsg_t *lowmsg) {
  *  present in the message pointed to by lowmsg.
  *
  */
-uint16_t getHeaderBitmap(packed_lowmsg_t *lowmsg) {
+inline uint16_t getHeaderBitmap(packed_lowmsg_t *lowmsg) {
   uint16_t headers = 0;
   uint8_t *buf = lowmsg->data;
   uint16_t len = lowmsg->len;
@@ -114,7 +114,7 @@ uint16_t getHeaderBitmap(packed_lowmsg_t *lowmsg) {
 /*
  * Fill in dispatch values
  */
-uint8_t setupHeaders(packed_lowmsg_t *packed, uint16_t headers) {
+inline uint8_t setupHeaders(packed_lowmsg_t *packed, uint16_t headers) {
   uint8_t *buf = packed->data;
   uint16_t len = packed->len;
   if (packed == NULL) return 1;
@@ -181,7 +181,7 @@ inline uint8_t getMeshHopsLeft(packed_lowmsg_t *msg, uint8_t *hops) {
   *hops = (*buf) & LOWPAN_MESH_HOPS_MASK;
   return 0;
 }
-inline uint8_t getMeshOriginAddr(packed_lowmsg_t *msg, hw_addr_t *origin) {
+inline uint8_t getMeshOriginAddr(packed_lowmsg_t *msg, ieee154_saddr_t *origin) {
   uint8_t *buf = msg->data;
   if (!hasMeshHeader(msg) || msg->data == NULL || origin == NULL) return 1;
   // skip 64-bit addresses
@@ -190,7 +190,7 @@ inline uint8_t getMeshOriginAddr(packed_lowmsg_t *msg, hw_addr_t *origin) {
   *origin = ntoh16(*((uint16_t *)buf));
   return 0;
 }
-inline uint8_t getMeshFinalAddr(packed_lowmsg_t *msg, hw_addr_t *final) {
+inline uint8_t getMeshFinalAddr(packed_lowmsg_t *msg, ieee154_saddr_t *final) {
   uint8_t *buf = msg->data;
   if (!hasMeshHeader(msg) || msg->data == NULL || final == NULL) return 1;
   // skip 64-bit addresses
@@ -209,7 +209,7 @@ inline uint8_t setMeshHopsLeft(packed_lowmsg_t *msg, uint8_t hops) {
   *buf |= hops & LOWPAN_MESH_HOPS_MASK;
   return 0;
 }
-inline uint8_t setMeshOriginAddr(packed_lowmsg_t *msg, hw_addr_t origin) {
+inline uint8_t setMeshOriginAddr(packed_lowmsg_t *msg, ieee154_saddr_t origin) {
   uint8_t *buf = msg->data;
   if (!hasMeshHeader(msg) || msg->data == NULL) return 1;
   // skip 64-bit addresses
@@ -218,7 +218,7 @@ inline uint8_t setMeshOriginAddr(packed_lowmsg_t *msg, hw_addr_t origin) {
   *((uint16_t *)buf) = hton16(origin);
   return 0;
 }
-inline uint8_t setMeshFinalAddr(packed_lowmsg_t *msg, hw_addr_t final) {
+inline uint8_t setMeshFinalAddr(packed_lowmsg_t *msg, ieee154_saddr_t final) {
   uint8_t *buf = msg->data;
   if (!hasMeshHeader(msg) || msg->data == NULL) return 1;
   // skip 64-bit addresses
index 16b77d206c74c3fc2509681ec3ccc3bc7de39307..9fb8cea3aeff883114e0a570a04b73514f89236c 100644 (file)
@@ -1,4 +1,4 @@
-/*l
+/*
  * "Copyright (c) 2008 The Regents of the University  of California.
  * All rights reserved."
  *
@@ -41,7 +41,9 @@ uint8_t *getLinkLocalPrefix() {
 }
 
 uint8_t cmpPfx(ip6_addr_t a, uint8_t *pfx) {
-  return (a[0] == pfx[0] &&
+  return (memcmp(a, pfx, 8) == 0);
+#if 0
+    (a[0] == pfx[0] &&
           a[1] == pfx[1] &&
           a[2] == pfx[2] &&
           a[3] == pfx[3] &&
@@ -49,9 +51,10 @@ uint8_t cmpPfx(ip6_addr_t a, uint8_t *pfx) {
           a[5] == pfx[5] &&
           a[6] == pfx[6] &&
           a[7] == pfx[7]);
+#endif
 }
 
-int ipv6_addr_suffix_is_long(const ip6_addr_t addr) {
+static inline int ipv6_addr_suffix_is_long(const ip6_addr_t addr) {
   return (!(addr[8] == 0 &&
             addr[9] == 0 &&
             addr[10] == 0 &&
@@ -60,6 +63,7 @@ int ipv6_addr_suffix_is_long(const ip6_addr_t addr) {
             addr[13] == 0));
 }
 
+#if LIB6LOWPAN_FULL
 /*
  * return the length of the compressed fields in buf
  */
@@ -114,8 +118,9 @@ int getCompressedLen(packed_lowmsg_t *pkt) {
   len += (buf - pkt->data);
   return len;
 }
+#endif
 
-int decompressShortAddress(uint8_t dispatch, uint8_t *s_addr, uint8_t *dest) {
+static inline int decompressShortAddress(uint8_t dispatch, uint8_t *s_addr, uint8_t *dest) {
   if ((*s_addr & LOWPAN_IPHC_SHORT_MASK) == 0) {
     // simplest case, just use the appropriate prefix.
     if (dispatch == LOWPAN_HC_LOCAL_PATTERN)
@@ -151,8 +156,8 @@ int decompressShortAddress(uint8_t dispatch, uint8_t *s_addr, uint8_t *dest) {
   return 0;
 }
 
-int decompressAddress(uint8_t dispatch, uint16_t src, uint8_t addr_flags, 
-                       uint8_t **buf, uint8_t *dest) {
+static inline int decompressAddress(uint8_t dispatch, uint16_t src, uint8_t addr_flags, 
+                                    uint8_t **buf, uint8_t *dest) {
   uint8_t *prefix;
   uint16_t tmp;
   int rc = 0;
@@ -185,6 +190,17 @@ int decompressAddress(uint8_t dispatch, uint16_t src, uint8_t addr_flags,
   return rc;
 }
 
+void adjustPlen(struct ip6_hdr *ip, unpack_info_t *u_info) {
+  uint16_t adjust_amt = u_info->payload_offset;
+  /*
+  switch (u_info->nxt_hdr) {
+  case IANA_UDP:
+    adjust_amt -= sizeof(struct udp_hdr); break;
+  }
+  */
+  ip->plen = htons(ntohs(ip->plen) - adjust_amt);
+}
+
 /*
  * Unpacks all headers, including any compressed transport headers if
  * there is a compression scheme defined for them.
@@ -204,10 +220,7 @@ uint8_t *unpackHeaders(packed_lowmsg_t *pkt, unpack_info_t *u_info,
   // pointers to fields  we may come back to fill in later
   uint8_t *plen, *prot_len, *nxt_hdr;
 
-  u_info->payload_offset = 0;
-  u_info->rih = NULL;
-  u_info->sh = NULL;
-  u_info->transport_ptr = NULL;
+  ip_memclr((void *)u_info, sizeof(unpack_info_t));
 
   // a buffer we can write addresses prefixes and suffexes into.
   // now we don't need to check sizes until we get to next headers
@@ -321,7 +334,7 @@ uint8_t *unpackHeaders(packed_lowmsg_t *pkt, unpack_info_t *u_info,
       dest += sizeof(struct udp_hdr);
 
       u_info->nxt_hdr = IANA_UDP;
-      u_info->payload_offset += sizeof(struct udp_hdr);
+      // u_info->payload_offset += sizeof(struct udp_hdr);
       u_info->transport_ptr = (uint8_t *)udp;
 
     } else {
@@ -338,30 +351,28 @@ uint8_t *unpackHeaders(packed_lowmsg_t *pkt, unpack_info_t *u_info,
     uint8_t nhdr_len = 0;
     struct ip6_ext *hdr;
     u_info->nxt_hdr = nhdr;
-    while (KNOWN_HEADER(nhdr)) {
+
+    // copy any IPv6 extension headers out of the packet.
+    // the rule is that the extension headers must fit in the first
+    // fragment so we can route on them after only one fragment.
+    while (EXTENSION_HEADER(nhdr)) {
       hdr = (struct ip6_ext *)buf;
-      u_info->nxt_hdr = nhdr;
+
       switch (nhdr) {
-      case IANA_UDP:
-        nhdr = NXTHDR_UNKNOWN;
-        nhdr_len = sizeof(struct udp_hdr);
-        u_info->transport_ptr = dest;
+      case IPV6_HOP:
+        u_info->hdr_hop = (struct ip6_ext *)buf;
+        break;
+      case IPV6_ROUTING:
+        u_info->hdr_route = (struct ip6_route *)buf;
         break;
-      case NXTHDR_SOURCE:
-        u_info->sh = (struct source_header *)buf;
-        nhdr = hdr->nxt_hdr; 
-        nhdr_len = hdr->len;
-        u_info->nxt_hdr = nhdr;
+      case IPV6_DEST:
+        u_info->hdr_dest = (struct ip6_ext *)buf;
         break;
-      case NXTHDR_INSTALL:
-        // this is how to handle all ipv6 options headers: should we
-        // use "default" here?
-        u_info->rih = (struct rinstall_header *)buf;
-      default:
-        nhdr = hdr->nxt_hdr;
-        nhdr_len = hdr->len;
-        u_info->nxt_hdr = nhdr;
       }
+      nhdr = hdr->nxt_hdr;
+      nhdr_len = hdr->len;
+      u_info->nxt_hdr = nhdr;
+
       if (len < nhdr_len) return NULL;
       ip_memcpy(dest, buf, nhdr_len);
       dest += nhdr_len;
@@ -370,6 +381,8 @@ uint8_t *unpackHeaders(packed_lowmsg_t *pkt, unpack_info_t *u_info,
       u_info->payload_offset += nhdr_len;
       extra_header_length += nhdr_len;
     }
+
+    u_info->transport_ptr = dest;
   }
 
   u_info->payload_start = buf;
@@ -407,7 +420,7 @@ uint8_t *unpackHeaders(packed_lowmsg_t *pkt, unpack_info_t *u_info,
  * that was needed.
  * @returns the bit flags indicating which length was used
  */
-uint8_t packAddress(uint8_t dispatch, uint8_t **buf, ip6_addr_t addr) {
+static uint8_t packAddress(uint8_t dispatch, uint8_t **buf, ip6_addr_t addr) {
 
   if ((dispatch == LOWPAN_HC_CRP_PATTERN && globalPrefix &&
       cmpPfx(addr, __my_address.s6_addr)) ||
@@ -581,6 +594,10 @@ uint8_t packHeaders(struct split_ip_msg *msg,
 /* } */
 
 
+
+#ifndef NO_LIB6LOWPAN_ASCII
+
+#define TO_CHAR(X) (((X) < 10) ? ('0' + (X)) : ('a' + ((X) - 10)))
 #define CHAR_VAL(X)  (((X) >= '0' && (X) <= '9') ? ((X) - '0') : \
                       (((X) >= 'A' && (X) <= 'F') ? ((X) - 'A' + 10) : ((X) - 'a' + 10)))
 
@@ -626,3 +643,33 @@ void inet_pton6(char *addr, struct in6_addr *dest) {
     if (*(p + 1) == ':' && *p == ':') break;
   }
 }
+
+
+
+int inet_ntop6(struct in6_addr *addr, char *buf, int cnt) {
+  uint16_t block;
+  char *end = buf + cnt;
+  int i, j, compressed = 0;
+
+  for (j = 0; j < 8; j++) {
+    if (buf > end - 7) return -1;
+
+    block = ntohs(addr->s6_addr16[j]);
+    for (i = 4; i <= 16; i+=4) {
+      if (block > (0xffff >> i) || (compressed == 2 && i == 16)) {
+        *buf++ = TO_CHAR((block >> (16 - i)) & 0xf);
+      }
+    }
+    if (addr->s6_addr16[j] == 0 && compressed == 0) {
+      *buf++ = ':';
+      compressed++;
+    }
+    if (addr->s6_addr16[j] != 0 && compressed == 1) compressed++;
+
+    if (j < 7 && compressed != 1) *buf++ = ':';
+  }
+  *buf++ = '\0';
+  return buf - (end - cnt);
+}
+
+#endif
index d62787369ef2e63c8a8bbc3860a31fc54f3946f8..6c5a45dee360a6b8d371cb49198b7571e25d73aa 100644 (file)
@@ -1,18 +1,20 @@
 
 GCC=gcc
-CFLAGS=-I../include -I../driver/ -DPC -g
+CFLAGS=-I../include -I../driver/ -DPC -g -Wall
 
 
 all: test_client test_server
 
-test_circ: test_circ.c circ.c
-       $(GCC) -o $@ $^
+test_circ: test_circ.c circ.c circ.h
+       $(GCC) -o $@ $^ $(CFLAGS)
 
-test_client: test_client.c  tcplib.h tcplib.c circ.c
-       $(GCC) -o $@ $< tcplib.c circ.c ../driver/tun_dev.c ../lib6lowpan/ip_malloc.c ../lib6lowpan/in_cksum.c $(CFLAGS)
+test_client: test_client.c  # tcplib.h tcplib.c circ.c
+       $(GCC) -o $@ $< $(CFLAGS)
+#      $(GCC) -o $@ $< tcplib.c circ.c ../driver/tun_dev.c ../lib6lowpan/ip_malloc.c ../lib6lowpan/in_cksum.c $(CFLAGS)
 
 test_server: test_server.c  tcplib.h tcplib.c circ.c
        $(GCC) -o $@ $< tcplib.c circ.c ../driver/tun_dev.c ../lib6lowpan/ip_malloc.c ../lib6lowpan/in_cksum.c $(CFLAGS)
 
 clean:
-       rm -rf test_server test_circ
\ No newline at end of file
+       rm -rf test_server test_circ
+
index de8bff1fcc412379b9fde43302af13ef352edde6..cd91d8e4b648b10569924bfca26d8cad3f9b504b 100644 (file)
+/*
+ * "Copyright (c) 2008, 2009 The Regents of the University  of California.
+ * All rights reserved."
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice, the following
+ * two paragraphs and the author appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
+ *
+ */
 
 #include <stdio.h>
 #include <stdint.h>
-// #include <assert.h>
 #include <string.h>
 
 #include "tcplib.h"
 
 struct circ_buf {
-  uint8_t  *map;
-  uint16_t  map_len;
   uint8_t  *data_start;
   uint8_t  *data_head;
   uint16_t  data_len;
   uint32_t  head_seqno;
 };
 
-int circ_buf_init(void *data, int len, uint32_t seqno, int incl_map) {
+int circ_buf_init(void *data, int len, uint32_t seqno) {
   struct circ_buf *b = (struct circ_buf *)data;
-  int bitmap_len = ((len - sizeof(struct circ_buf)) / 9);
-  // int data_len   = bitmap_len * 8;
-
-  // printf("circ_buf_init: len: %i data_len: %i bitmap_len: %i\n", len, data_len, bitmap_len);
-  // assert(bitmap_len + data_len + sizeof(struct circ_buf) <= len);
 
   if (len < sizeof(struct circ_buf))
     return -1;
 
-  if (incl_map) {
-    b->map     = (uint8_t *)(b + 1);
-    b->map_len = bitmap_len;
-    b->data_start  = b->map + bitmap_len;
-    b->data_len= bitmap_len * 8;
-    memset(b->map, 0, bitmap_len * 9);
-  } else {
-    b->map = NULL;
-    b->map_len = 0;
-    b->data_start = (uint8_t *)(b + 1);
-    b->data_len = len - sizeof(struct circ_buf);
-    memset(b->data_start, 0, b->data_len);
-  }
-  b->data_head   = b->data_start;
+  b->data_head = b->data_start = (uint8_t *)(b + 1);
+  b->data_len = len - sizeof(struct circ_buf);
   b->head_seqno = seqno;
-
-  // printf("circ_buf_init: buf: %p data_start: %p data_head: %p data_len: %i\n",
-  // b, b->data_start, b->data_head, b->data_len);
-
   return 0;
 }
 
-#define BIT_SET(off,map)       map[(off)/8] |= (1 << (7 - ((off) % 8)))
-#define BIT_UNSET(off,map)     map[(off)/8] &= ~(1 << (7 - ((off) % 8)))
-#define BIT_ISSET(off, map)    map[(off)/8] & 1 << (7 - (off) % 8)
-
-static void bitmap_mark(struct circ_buf *b, uint8_t *data, int len) {
-  int offset = data - b->data_start;
-  if (b->map_len == 0) return;
-  while (len-- > 0) {
-    BIT_SET(offset, b->map);
-    offset = (offset + 1) % b->data_len;
-  }
-}
-
-/* return the sequence number of the first byte of data in the buffer;
-   this is what the stack can ACK. */
 uint32_t circ_get_seqno(void *buf) {
   struct circ_buf *b = (struct circ_buf *)buf;
   return b->head_seqno;
 }
 
-void circ_set_seqno(void *buf, uint32_t seqno) {
-  struct circ_buf *b = (struct circ_buf *)buf;
-  b->head_seqno = seqno;
-}
-
-uint16_t circ_get_window(void *buf) {
-  struct circ_buf *b = (struct circ_buf *)buf;
-  return b->data_len;
-}
-
-/* read as many contiguous bytes from the head of the buffer as
- *   possible, and update the internal data structures to shorten the
- *  buffer 
- * 
- * buf:  the circular buffer
- * data: a pointer which will be updated with the location of the data
- * return: the number of bytes available
- */
-int circ_buf_read_head(void *buf, char **data) {
-  struct circ_buf *b = (struct circ_buf *)buf;
-  int off = b->data_head - b->data_start;
-  int rlen = 0;
-  *data = b->data_head;
-  while (BIT_ISSET(off, b->map) && off < b->data_len) {
-    BIT_UNSET(off, b->map);
-    rlen++;
-    b->head_seqno++;
-    b->data_head ++;
-    if (b->data_head == b->data_start + b->data_len)
-      b->data_head = b->data_start;
-    off++;
-  }
-  return rlen;
-}
-
-
 static void get_ptr_off_1(struct circ_buf *b, uint32_t sseqno, int len,
                           uint8_t **writeptr, int *w_len) {
   uint8_t *endptr =  b->data_start + b->data_len;
   int offset;
 
   *writeptr = NULL;
-  *w_len = 0;
+  *w_len = len;
 
   /* write up to either the end of the buffer */
   offset = sseqno - b->head_seqno;
   if (b->data_head + offset < endptr) {
-    *w_len = len;
     *writeptr = b->data_head + offset;
-    if (*writeptr + *w_len > endptr) {
-      *w_len = endptr - *writeptr;
-    }
+  } else {
+    offset -= (endptr - b->data_head);
+    *writeptr = b->data_start + offset;
+  }
+  if (*writeptr + *w_len > endptr) {
+    *w_len = endptr - *writeptr;
   }
 }
 
@@ -128,8 +76,8 @@ int circ_shorten_head(void *buf, uint32_t seqno) {
   int offset = seqno - b->head_seqno;
 
   b->head_seqno = seqno;
-
   b->data_head += offset;
+
   while (b->data_head > b->data_start + b->data_len)
     b->data_head -= b->data_len;
 
@@ -156,64 +104,44 @@ int circ_buf_read(void *buf, uint32_t sseqno,
   return rc;
 }
 
-int circ_buf_write(void *buf, uint32_t sseqno,
+int circ_buf_write(char *buf, uint32_t sseqno,
                    uint8_t *data, int len) {
   struct circ_buf *b = (struct circ_buf *)buf;
   uint8_t *writeptr;
   int w_len;
-  
   /* we can't write any bytes since we're trying to write too far
      ahead  */
-  // printf("circ_buf_write: sseqno: %i head_seqno: %i len: %i\n",
-  // sseqno, b->head_seqno, len);
-
   if (sseqno > b->head_seqno + b->data_len)
     return -1;
-
-  if (sseqno < b->head_seqno) {
-    /* old data, but already received */
-    if (sseqno < b->head_seqno - len) return -1;
-    /* a segment which overlaps with data we've already received */
-    data += (b->head_seqno - sseqno);
-    len  -= (b->head_seqno - sseqno);
-    sseqno = b->head_seqno;
-  }
   if (len == 0) return 0;
 
-  // printf("circ_buf_write: buf: %p data_start: %p data_head: %p data_len: %i\n",
-  // b, b->data_start, b->data_head, b->data_len);
   get_ptr_off_1(b, sseqno, len, &writeptr, &w_len);
+
   memcpy(writeptr, data, w_len);
   data += w_len;
-  bitmap_mark(b, writeptr, w_len);
 
   if (w_len != len) {
     writeptr = b->data_start;
     w_len = min(len - w_len, b->data_head - b->data_start);
     memcpy(writeptr, data, w_len);
-    bitmap_mark(b, writeptr, w_len);
-    // printf("circ_buf_write (2): write: %p len: %i\n", writeptr, w_len);
   }
+
   return 0;
 }
 
 #ifdef PC             
 void circ_buf_dump(void *buf) {
   struct circ_buf *b = (struct circ_buf *)buf;
+  uint8_t *d;
   int i;
 /*   printf("circ buf: %p\n\tmap: %p\n\tmap_len: %i\n\tdata_start: %p\n\t" */
 /*          "data_head: %p\n\tdata_len: %i\n\thead_seqno: %i\n",  */
 /*          b, b->map, */
 /*          b->map_len, b->data_start, b->data_head, b->data_len, b->head_seqno); */
-
-  for (i = 1; i <= b->data_len; i++) {
-    if (BIT_ISSET(i-1, b->map))
-      putc('x',stdout);
-    else
-      putc('_',stdout);
-    if (i % 80 == 0 || i == b->data_len) {
-      putc('\n',stdout);
-    }
+  for (d = b->data_start; d < b->data_start + b->data_len; d++) {
+    if (d == b->data_head) putc('|', stdout);
+    printf("%2.x ", *d);
   }
+  putc('\n', stdout);
 }
 #endif
index d937b06d6a3e098621cbe39d1fdfba8df9e6c139..d71f3a0f01e27bac7ee814011e281987965677ea 100644 (file)
@@ -1,12 +1,33 @@
+/*
+ * "Copyright (c) 2008, 2009 The Regents of the University  of California.
+ * All rights reserved."
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice, the following
+ * two paragraphs and the author appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
+ *
+ */
 #ifndef __CIRC_H_
 #define __CIRC_H_
 
 #include <stdint.h>
 
-int circ_buf_init(void *data, int len, uint32_t seqno, int inc_map);
+int circ_buf_init(void *data, int len, uint32_t seqno);
 
 
-int circ_buf_write(void *buf, uint32_t sseqno,
+int circ_buf_write(char *buf, uint32_t sseqno,
                    uint8_t *data, int len);
 
 
@@ -17,10 +38,11 @@ int circ_buf_read(void *buf, uint32_t sseqno,
 int circ_shorten_head(void *buf, uint32_t seqno);
 
 /* read from the head of the buffer, moving the data pointer forward */
-int circ_buf_read_head(void *buf, char **data);
+// int circ_buf_read_head(char *buf, char **data);
 
 void circ_buf_dump(void *buf);
 
+uint32_t circ_get_seqno(void *buf);
 void circ_set_seqno(void *buf, uint32_t seqno);
 
 #endif
index 21b8c4d2ebf760c85da51aa5900000a46f290f3f..140ca7ced41efa5efe813c2b7bcb0f9ae481ac92 100644 (file)
@@ -1,3 +1,24 @@
+/*
+ * "Copyright (c) 2008, 2009 The Regents of the University  of California.
+ * All rights reserved."
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice, the following
+ * two paragraphs and the author appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
+ *
+ */
 
 /* A nonblocking library-based implementation of TCP
  *
@@ -43,11 +64,36 @@ static int isInaddrAny(struct in6_addr *addr) {
   return 1;
 }
 
+#ifdef PC
+#include <arpa/inet.h>
+
+void print_conn(struct tcplib_sock *sock) {
+  char addr_buf[32];
+  printf("tcplib socket state: %i:\n", sock->state);
+  inet_ntop(AF_INET6, sock->l_ep.sin6_addr.s6_addr, addr_buf, 32);
+  printf(" local ep: %s port: %u\n", addr_buf, ntohs(sock->l_ep.sin6_port));
+  inet_ntop(AF_INET6, sock->r_ep.sin6_addr.s6_addr, addr_buf, 32);
+  printf(" remote ep: %s port: %u\n", addr_buf, ntohs(sock->r_ep.sin6_port));
+  printf(" tx buf length: %i\n", sock->tx_buf_len);
+}
+void print_headers(struct ip6_hdr *iph, struct tcp_hdr *tcph) {
+  char addr_buf[32];
+  printf("headers ip length: %i:\n", ntohs(iph->plen));
+  inet_ntop(AF_INET6, iph->ip6_src.s6_addr, addr_buf, 32);
+  printf(" source: %s port: %u\n", addr_buf, ntohs(tcph->srcport));
+  inet_ntop(AF_INET6, iph->ip6_dst.s6_addr, addr_buf, 32);
+  printf(" remote ep: %s port: %u\n", addr_buf, ntohs(tcph->dstport));
+  printf(" tcp seqno: %u ackno: %u\n", ntohl(tcph->seqno), ntohl(tcph->ackno));
+}
+#endif
+
 static struct tcplib_sock *conn_lookup(struct ip6_hdr *iph, 
                                        struct tcp_hdr *tcph) {
   struct tcplib_sock *iter;
-  printfUART("looking up conns...\n");
+  //printf("looking up conns: %p %p\n", iph, tcph);
+  // print_headers(iph, tcph);
   for (iter = conns; iter != NULL; iter = iter->next) {
+    // print_conn(iter);
     printf("conn lport: %i\n", ntohs(iter->l_ep.sin6_port));
     if (((memcmp(iph->ip6_dst.s6_addr, iter->l_ep.sin6_addr.s6_addr, 16) == 0) ||
          isInaddrAny(&iter->l_ep.sin6_addr)) &&
@@ -75,6 +121,7 @@ struct tcp_hdr *find_tcp_hdr(struct split_ip_msg *msg) {
     return (struct tcp_hdr *)((msg->headers == NULL) ? msg->data :
                               msg->headers->hdr.data);
   }
+  return NULL;
 }
 
 static struct split_ip_msg *get_ipmsg(int plen) {
@@ -95,16 +142,16 @@ static struct split_ip_msg *get_ipmsg(int plen) {
 static void __tcplib_send(struct tcplib_sock *sock,
                           struct split_ip_msg *msg) {
   struct tcp_hdr *tcph = find_tcp_hdr(msg);
+  if (tcph == NULL) return;
   memcpy(&msg->hdr.ip6_dst, &sock->r_ep.sin6_addr, 16);
 
   sock->flags &= ~TCP_ACKPENDING;
-
   // sock->ackno = ntohl(tcph->ackno);
 
   tcph->srcport = sock->l_ep.sin6_port;
   tcph->dstport = sock->r_ep.sin6_port;
   tcph->offset = sizeof(struct tcp_hdr) * 4;
-  tcph->window = htons(circ_get_window(sock->rx_buf));
+  tcph->window = htons(sock->my_wind);
   tcph->chksum = 0;
   tcph->urgent = 0;
 
@@ -118,11 +165,15 @@ static void tcplib_send_ack(struct tcplib_sock *sock, int fin_seqno, uint8_t fla
     struct tcp_hdr *tcp_rep = (struct tcp_hdr *)(msg + 1);
     tcp_rep->flags = flags;
 
+
     tcp_rep->seqno = htonl(sock->seqno);
-    tcp_rep->ackno = htonl(circ_get_seqno(sock->rx_buf) + 
+    tcp_rep->ackno = htonl(sock->ackno +
                            (fin_seqno ? 1 : 0));
+    // printf("sending ACK seqno: %u ackno: %u\n", ntohl(tcp_rep->seqno), ntohl(tcp_rep->ackno));
     __tcplib_send(sock, msg);
     ip_free(msg);
+  } else {
+    printf("Could not send ack-- no memory!\n");
   }
 }
 
@@ -134,9 +185,9 @@ static void tcplib_send_rst(struct ip6_hdr *iph, struct tcp_hdr *tcph) {
 
     memcpy(&msg->hdr.ip6_dst, &iph->ip6_src, 16);
 
-    tcp_rep->flags = TCP_FLAG_RST;
+    tcp_rep->flags = TCP_FLAG_RST | TCP_FLAG_ACK;
 
-    tcp_rep->ackno = tcph->seqno + 1;
+    tcp_rep->ackno = htonl(ntohl(tcph->seqno) + 1);
     tcp_rep->seqno = tcph->ackno;;
 
     tcp_rep->srcport = tcph->dstport;
@@ -159,6 +210,7 @@ static int tcplib_output(struct tcplib_sock *sock, uint32_t sseqno) {
   // conjestion window.  of course, if we have less data we send even
   // less.
   int seg_size = min(sock->seqno - sseqno, sock->r_wind);
+  printf("r_wind: %i\n", sock->r_wind);
   seg_size = min(seg_size, sock->cwnd);
   while (seg_size > 0 && sock->seqno > sseqno) {
     // printf("sending seg_size: %i\n", seg_size);
@@ -171,9 +223,15 @@ static int tcplib_output(struct tcplib_sock *sock, uint32_t sseqno) {
 
     tcph->flags = TCP_FLAG_ACK;
     tcph->seqno = htonl(sseqno);
-    tcph->ackno = htonl(circ_get_seqno(sock->rx_buf));
+    tcph->ackno = htonl(sock->ackno);
 
-    circ_buf_read(sock->tx_buf, sseqno, data, seg_size);
+    printf("tcplib_output: seqno: %u ackno: %u len: %i headno: %u\n",
+           ntohl(tcph->seqno), ntohl(tcph->ackno), seg_size,
+           circ_get_seqno(sock->tx_buf));
+
+    if (seg_size != circ_buf_read(sock->tx_buf, sseqno, data, seg_size)) {
+      printf("WARN: circ could not read!\n");
+    }
     __tcplib_send(sock, msg);
     ip_free(msg);
 
@@ -185,7 +243,8 @@ static int tcplib_output(struct tcplib_sock *sock, uint32_t sseqno) {
 
 int tcplib_init_sock(struct tcplib_sock *sock) {
   memset(sock, 0, sizeof(struct tcplib_sock) - sizeof(struct tcplib_sock *));
-  sock->mss = 100;
+  sock->mss = 200;
+  sock->my_wind = 200;
   sock->cwnd = ONE_SEGMENT(sock);
   sock->ssthresh = 0xffff;
   conn_add_once(sock);
@@ -196,20 +255,16 @@ int tcplib_init_sock(struct tcplib_sock *sock) {
 /* deliver as much data to the app as possible, and update the ack
  * number of the socket to reflect how much was delivered 
  */
-static void add_data(struct tcplib_sock *sock, struct tcp_hdr *tcph, int len) {
-  char *ptr;
+static void receive_data(struct tcplib_sock *sock, struct tcp_hdr *tcph, int len) {
+  uint8_t *ptr;
   int payload_len;
+
   ptr = ((uint8_t *)tcph) + (tcph->offset / 4);
   payload_len = len - (tcph->offset / 4);
-  // TODO : SDH : optimize out the extra copy for in-sequence data
-  circ_buf_write(sock->rx_buf, ntohl(tcph->seqno),
-                 ptr, payload_len);
-  // now try to deliver any data ahead of the ack pointer that's in
-  // the buffer
-
-  /* if we wrapped around the buffer, we'll actually recieve twice.  */
-  while ((payload_len = circ_buf_read_head(sock->rx_buf, &ptr)) > 0) {
-    sock->ops.recvfrom(sock, ptr, payload_len);
+  sock->ackno = ntohl(tcph->seqno) + payload_len;
+
+  if (payload_len > 0) {
+    tcplib_extern_recv(sock, ptr, payload_len);
   }
 }
 
@@ -225,30 +280,27 @@ int tcplib_process(struct ip6_hdr *iph, void *payload) {
   struct tcp_hdr *tcph;
   struct tcplib_sock *this_conn;
   //   uint8_t *ptr;
+  int len = ntohs(iph->plen) + sizeof(struct ip6_hdr);
   int payload_len;
-  int len = ntohs(iph->plen) + sizeof(struct ip6_hdr);;
-  tcph = (struct tcp_hdr *)payload;
-
-  // printf("tcplib_process\n");
+  uint32_t hdr_seqno, hdr_ackno;
 
-  /* malformed ip packet?  could happen I supppose... */
-/*   if (len < sizeof(struct ip6_hdr) || */
-/*       len != ntohs(iph->plen) + sizeof(struct ip6_hdr)) { */
-/*     fprintf(stderr, "tcplib_process: warn: length mismatch\n"); */
-/*     return -1; */
-/*   } */
+  tcph = (struct tcp_hdr *)payload;
+  payload_len = len - sizeof(struct ip6_hdr) - (tcph->offset / 4);
 
   /* if there's no local */
   this_conn = conn_lookup(iph, tcph);
+  // printf("conn: %p\n", this_conn);
   if (this_conn != NULL) {
+    hdr_seqno = ntohl(tcph->seqno);
+    hdr_ackno = ntohl(tcph->ackno);
+
     if (tcph->flags & TCP_FLAG_RST) {
       /* Really hose this connection if we get a RST packet.
        * still TODO: RST generation for unbound ports */
       printf("connection reset by peer\n");
           
-      if (this_conn->ops.closed)
-        this_conn->ops.close_done(this_conn);
-      tcplib_init_sock(this_conn);
+      tcplib_extern_closedone(this_conn);
+      // tcplib_init_sock(this_conn);
       return 0;
     }
     // always get window updates from new segments
@@ -259,27 +311,47 @@ int tcplib_process(struct ip6_hdr *iph, void *payload) {
     switch (this_conn->state) {
     case TCP_LAST_ACK:
       if (tcph->flags & TCP_FLAG_ACK && 
-          ntohl(tcph->ackno) == this_conn->seqno + 1) {
-        // printf("closing connection\n");
+          hdr_ackno == this_conn->seqno + 1) {
+
         this_conn->state = TCP_CLOSED;
-        this_conn->ops.close_done(this_conn);
+        tcplib_extern_closedone(this_conn);
         break;
       }
+    case TCP_FIN_WAIT_1:
+      if (tcph->flags & TCP_FLAG_ACK && 
+          hdr_ackno == this_conn->seqno + 1) {
+        if (tcph->flags & TCP_FLAG_FIN) {
+          this_conn->seqno++;
+          this_conn->state = TCP_TIME_WAIT;
+          
+          // the TIME_WAIT state is problematic, since it holds up the
+          // resources while we're in it...
+          this_conn->timer.retx = TCPLIB_TIMEWAIT_LEN;
+        } else {
+          this_conn->state = TCP_FIN_WAIT_2;
+        }
+        // this generate the ACK we need here
+        goto ESTABLISHED;
+      }
+    case TCP_FIN_WAIT_2:
+
+      break;
 
     case TCP_SYN_SENT:
       if (tcph->flags & (TCP_FLAG_SYN | TCP_FLAG_ACK)) {
         // got a syn-ack
-        // send the ACK 
+        // send the ACK this_conn
         this_conn->state = TCP_ESTABLISHED;
-        circ_set_seqno(this_conn->rx_buf, ntohl(tcph->seqno) + 1);
+        this_conn->ackno = hdr_seqno + 1;
         // skip the LISTEN processing
         // this will also generate an ACK
         goto ESTABLISHED;
       } else if (this_conn->flags & TCP_FLAG_SYN) {
-      // otherwise the state machine says we're in a simultaneous open, so continue doen
+        // otherwise the state machine says we're in a simultaneous open, so continue doen
         this_conn->state = TCP_SYN_RCVD;
       } else {
         printf("sending RST on bad data in state SYN_SENT\n");
+        // we'll just let the timeout eventually close the socket, though
         tcplib_send_rst(iph, tcph);
         break;
       }
@@ -309,10 +381,9 @@ int tcplib_process(struct ip6_hdr *iph, void *payload) {
           memcpy(&new_sock->l_ep.sin6_addr, &iph->ip6_dst, 16);
           new_sock->l_ep.sin6_port = tcph->dstport;
 
-          circ_buf_init(new_sock->rx_buf, new_sock->rx_buf_len, 
-                        ntohl(tcph->seqno) + 1, 1);
+          new_sock->ackno = hdr_seqno + 1;
           circ_buf_init(new_sock->tx_buf, new_sock->tx_buf_len,
-                        0xcafebabe + 1, 0);
+                        0xcafebabe + 1);
         } else {
           /* recieved a SYN retransmission. */
           new_sock = this_conn;
@@ -327,36 +398,36 @@ int tcplib_process(struct ip6_hdr *iph, void *payload) {
           memset(&this_conn->r_ep, 0, sizeof(struct sockaddr_in6));
         }
       } else if (this_conn->state == TCP_LISTEN) {
-        printf("sending RST on out-of-sequence data\n");
         tcplib_send_rst(iph, tcph);
         break;
       }
       /* this is SYN_RECVd */
       if (tcph->flags & TCP_FLAG_ACK) {
-        // printf("recv ack, in state TCP_SYN_RCVD\n");
         this_conn->state = TCP_ESTABLISHED;
       } 
       /* fall through to handle any data. */
       
+
     case TCP_CLOSE_WAIT:
     case TCP_ESTABLISHED:
     ESTABLISHED:
-      // ptr = ((uint8_t *)(iph + 1)) + (tcph->offset / 4);
-      payload_len = len - sizeof(struct ip6_hdr) - (tcph->offset / 4);
-      // printf("recv data len: %i\n", payload_len);
 
       /* ack any data in this packet */
-      if (this_conn->state == TCP_ESTABLISHED) {
-        if (payload_len > 0)
+      if (this_conn->state == TCP_ESTABLISHED || this_conn->state == TCP_FIN_WAIT_1) {
+        if (payload_len > 0) {
+          if ((this_conn->flags & TCP_ACKPENDING) == TCP_ACKPENDING) {
+            // printf("Incr would overflow\n");
+          }
           this_conn->flags ++;
+        }
 
 
         // receive side sequence check and add data
-        // printf("seqno: %i ackno: %i\n", ntohl(tcph->seqno), ntohl(tcph->ackno));
+        printf("seqno: %u ackno: %u\n", hdr_seqno, hdr_ackno);
 
 
         // send side recieve sequence check and congestion window updates.
-        if (ntohl(tcph->ackno) > circ_get_seqno(this_conn->tx_buf)) {
+        if (hdr_ackno > circ_get_seqno(this_conn->tx_buf)) {
           // new data is being ACKed
           // or we haven't sent anything new
           if (this_conn->cwnd <= this_conn->ssthresh) {
@@ -372,8 +443,12 @@ int tcplib_process(struct ip6_hdr *iph, void *payload) {
           // reset the duplicate ack counter
           UNSET_ACK_COUNT(this_conn->flags);
           // truncates the ack buffer 
-          circ_shorten_head(this_conn->tx_buf, ntohl(tcph->ackno));
+          circ_shorten_head(this_conn->tx_buf, hdr_ackno);
           // printf("ack_count: %i\n", GET_ACK_COUNT(this_conn->flags));
+
+          if (this_conn->seqno == hdr_ackno) {
+            tcplib_extern_acked(this_conn);
+          }
         } else if (this_conn->seqno > circ_get_seqno(this_conn->tx_buf)) {
           // this is a duplicate ACK
           //  - increase the counter of the number of duplicate ACKs
@@ -397,31 +472,41 @@ int tcplib_process(struct ip6_hdr *iph, void *payload) {
             this_conn->timer.retx = 6;
             
           }
-        } else if (ntohl(tcph->seqno) != circ_get_seqno(this_conn->rx_buf)) {
-          printf("==> received out-of-sequence data!\n");
-          tcplib_send_ack(this_conn, 0, TCP_FLAG_ACK);
         }
-        add_data(this_conn, tcph, len - sizeof(struct ip6_hdr));
-
 
-        // printf("tx seqno: %i ackno: %i\n", circ_get_seqno(this_conn->tx_buf),
-        // ntohl(tcph->ackno));
+        if (hdr_seqno != this_conn->ackno) {
+          printf("==> received forward segment\n");
+          if ((hdr_seqno > this_conn->ackno + this_conn->my_wind) ||
+              (hdr_seqno < this_conn->ackno - this_conn->my_wind)) {
+            // send a RST on really wild data 
+            tcplib_send_rst(iph, tcph);
+          } else {
+            tcplib_send_ack(this_conn, 0, TCP_FLAG_ACK);
+            this_conn->flags |= TCP_ACKSENT;
+          }
+        } else { // (hdr_seqno == this_conn->ackno) {
+          receive_data(this_conn, tcph, len - sizeof(struct ip6_hdr));
 
+          if (this_conn->flags & TCP_ACKSENT) {
+            this_conn->flags &= ~TCP_ACKSENT;
+            tcplib_send_ack(this_conn, 0, TCP_FLAG_ACK);
+          }
+        }          
 
         // reset the retransmission timer
         if (this_conn->timer.retx == 0)
           this_conn->timer.retx = 6;
       }
-      if ((payload_len > 0 && (this_conn->flags & TCP_ACKPENDING) >= 2) 
+    case TCP_TIME_WAIT:
+      if ((payload_len > 0 && (this_conn->flags & TCP_ACKPENDING) >= 1) 
           || tcph->flags & TCP_FLAG_FIN) {
-        ///|| ntohl(tcph->seqno) != circ_get_seqno(this_conn->rx_buf)) {
         tcplib_send_ack(this_conn, (payload_len == 0 && tcph->flags & TCP_FLAG_FIN), TCP_FLAG_ACK);
         /* only close the connection if we've gotten all the data */
         if (this_conn->state == TCP_ESTABLISHED 
             && tcph->flags & TCP_FLAG_FIN
-            && ntohl(tcph->seqno)  == circ_get_seqno(this_conn->rx_buf)) {
+            && hdr_seqno  == this_conn->ackno) {
           this_conn->state = TCP_CLOSE_WAIT;
-          this_conn->ops.closed(this_conn);
+          tcplib_extern_closed(this_conn);
         }
       }
       break;
@@ -433,7 +518,10 @@ int tcplib_process(struct ip6_hdr *iph, void *payload) {
     }
   } else {
     /* this_conn was NULL */
-    /* TODO : SDH : send ICMP error */
+    /* interestingly, TCP sends a RST on this condition, not an ICMP error.  go figure. */
+    printf("sending rst on missing connection\n");
+    tcplib_send_rst(iph, tcph);
+
   }
   return rc;
 }
@@ -450,12 +538,13 @@ int tcplib_bind(struct tcplib_sock *sock,
   memcpy(&sock->l_ep, addr, sizeof(struct sockaddr_in6));
   /* passive open */
   sock->state = TCP_LISTEN;
+  return 0;
 }
 
 /* connect the socket to a remote endpoint */
 int tcplib_connect(struct tcplib_sock *sock,
                    struct sockaddr_in6 *serv_addr) {
-  if (sock->rx_buf == NULL || sock->tx_buf == NULL)
+  if (sock->tx_buf == NULL)
     return -1;
 
   switch (sock->state) {
@@ -470,16 +559,17 @@ int tcplib_connect(struct tcplib_sock *sock,
   default:
     return -1;
   }
-  circ_buf_init(sock->rx_buf, sock->rx_buf_len, 
-                0, 1);
   circ_buf_init(sock->tx_buf, sock->tx_buf_len,
-                0xcafebabe + 1, 0);
+                0xcafebabe + 1);
 
+  sock->ackno = 0;
   sock->seqno = 0xcafebabe;
   memcpy(&sock->r_ep, serv_addr, sizeof(struct sockaddr_in6));
   tcplib_send_ack(sock, 0, TCP_FLAG_SYN);
   sock->state = TCP_SYN_SENT;
   sock->seqno++;
+  sock->timer.retx = 6;
+
   return 0;
 }
 
@@ -488,10 +578,10 @@ int tcplib_send(struct tcplib_sock *sock, void *data, int len) {
   /* have enough tx buffer left? */
   if (sock->state != TCP_ESTABLISHED)
     return -1;
-  if (sock->seqno - circ_get_seqno(sock->tx_buf) + len > circ_get_window(sock->tx_buf))
+  if (sock->seqno - circ_get_seqno(sock->tx_buf) + len > sock->tx_buf_len) // circ_get_window(sock->tx_buf))
+    return -1;
+  if (circ_buf_write(sock->tx_buf, sock->seqno, data, len) < 0)
     return -1;
-
-  circ_buf_write(sock->tx_buf, sock->seqno, data, len);
 
   sock->seqno += len;
   // printf("tcplib_output from send\n");
@@ -506,25 +596,72 @@ int tcplib_send(struct tcplib_sock *sock, void *data, int len) {
 
 void tcplib_retx_expire(struct tcplib_sock *sock) {
   // printf("retransmission timer expired!\n");
-  if (sock->state == TCP_ESTABLISHED &&
-      circ_get_seqno(sock->tx_buf) != sock->seqno) {
-    printf("retransmitting [%u, %u]\n", circ_get_seqno(sock->tx_buf),
-           sock->seqno);
-    reset_ssthresh(sock);
-    // restart slow start
-    sock->cwnd = ONE_SEGMENT(sock);
-    // printf("tcplib_output from timer\n");
-    tcplib_output(sock, circ_get_seqno(sock->tx_buf));
+  sock->retxcnt++;
+  switch (sock->state) {
+  case TCP_ESTABLISHED:
+    if (circ_get_seqno(sock->tx_buf) != sock->seqno) {
+      printf("retransmitting [%u, %u]\n", circ_get_seqno(sock->tx_buf),
+             sock->seqno);
+      reset_ssthresh(sock);
+      // restart slow start
+      sock->cwnd = ONE_SEGMENT(sock);
+      // printf("tcplib_output from timer\n");
+      tcplib_output(sock, circ_get_seqno(sock->tx_buf));
+      sock->timer.retx = 6;
+    } else {
+      sock->retxcnt--;
+    }
+    break;
+  case TCP_SYN_SENT:
+    tcplib_send_ack(sock, 0, TCP_FLAG_SYN);
     sock->timer.retx = 6;
-  } else if (sock->state == TCP_LAST_ACK) {
-    //     printf("resending FIN\n");
+    break;
+  case TCP_LAST_ACK:
+  case TCP_FIN_WAIT_1:
     tcplib_send_ack(sock, 1, TCP_FLAG_ACK | TCP_FLAG_FIN);
     sock->timer.retx = 6;
+    break;
+  case TCP_TIME_WAIT:
+    sock->state = TCP_CLOSED;
+    // exit TIME_WAIT
+    tcplib_extern_closedone(sock);
+    break;
+  default:
+    break;
   }
+
+  /* if we've hit this timer a lot, give up
+   *
+   * do this by going into
+   * TIME_WAIT, which will generate a FIN if anyone sends to us but
+   * otherwise just do nothing.
+   *
+   * we don't do something like try to close it here, since we might
+   * have gotten here from doing that.
+   */
+  if (sock->retxcnt > TCPLIB_GIVEUP) {
+    sock->state = TCP_TIME_WAIT;
+    sock->timer.retx = TCPLIB_TIMEWAIT_LEN;
+   }
+}
+
+int tcplib_abort(struct tcplib_sock *sock) {
+  switch (sock->state) {
+    // nothing to abort
+  case TCP_CLOSED:
+  case TCP_LISTEN:
+    break;
+  default:
+    tcplib_send_ack(sock, 0, TCP_FLAG_RST);
+    memset(&sock->l_ep, 0, sizeof(struct sockaddr_in6));
+    memset(&sock->r_ep, 0, sizeof(struct sockaddr_in6));
+    sock->state = TCP_CLOSED;
+  }
+  return 0;
 }
 
 int tcplib_close(struct tcplib_sock *sock) {
-  int rc = -1;
+  int rc = 0;
 
   switch (sock->state) {
     /* passive close */
@@ -536,7 +673,9 @@ int tcplib_close(struct tcplib_sock *sock) {
     /* active close */
   case TCP_ESTABLISHED:
     // kick off the close
-    
+    tcplib_send_ack(sock, 0, TCP_FLAG_ACK | TCP_FLAG_FIN);
+    sock->timer.retx = 6;
+    sock->state = TCP_FIN_WAIT_1;
     break;
   case TCP_SYN_SENT:
     sock->state = TCP_CLOSED;
@@ -553,8 +692,7 @@ int tcplib_timer_process() {
   for (iter = conns; iter != NULL; iter = iter->next) {
     if (iter->timer.retx > 0 && (--iter->timer.retx) == 0)
       tcplib_retx_expire(iter);
-    if (iter->flags & TCP_ACKPENDING) {
-      // printf("sending delayed ACK\n");
+    if ((iter->flags & TCP_ACKPENDING) >= 2) {
       tcplib_send_ack(iter, 0, TCP_FLAG_ACK);
     }
   }
index 6b25d1fb8871d7ffcc4767223e74897c52ac31b8..40323af14fa950d0442b9bc9653497cea33bae28 100644 (file)
@@ -1,6 +1,34 @@
+/*
+ * "Copyright (c) 2008, 2009 The Regents of the University  of California.
+ * All rights reserved."
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice, the following
+ * two paragraphs and the author appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
+ *
+ */
 #ifndef TCPLIB_H_
 #define TCPLIB_H_
 
+/* 
+ * tcplib: a simple tcp implemented in a library
+ * @author Stephen Dawson-Haggerty <stevedh@eecs.berkeley.edu>
+ *
+ *
+ */
+
 // #include <netinet/in.h>
 #include "ip.h"
 
@@ -28,12 +56,19 @@ enum {
   TCP_ACKPENDING  = 0x3,
   TCP_DUPACKS     = 0x3c,
   TCP_DUPACKS_OFF = 2,
+  TCP_ACKSENT     = 0x80,
+};
+
+enum {
+  /* how many timer tics to stay in TIME_WAIT */
+  TCPLIB_TIMEWAIT_LEN = 12,
+  /* how many un-acked retransmissions before we give up the connection */
+  TCPLIB_GIVEUP = 6,
 };
 
 #define GET_ACK_COUNT(X)    (((X) & TCP_DUPACKS) >> TCP_DUPACKS_OFF)
 #define UNSET_ACK_COUNT(X)  ((X) &= ~TCP_DUPACKS)
 #define INCR_ACK_COUNT(X)   ((X) += 1 << TCP_DUPACKS_OFF)
-#define ACK_COUNT_IS_3(X)   (((X) & TCP_DUPACKS) == TCP_DUPACKS)
 
 struct tcplib_sock {
   uint8_t flags;
@@ -45,10 +80,6 @@ struct tcplib_sock {
   /* current connection state */
   tcplib_sock_state_t state;
 
-  /* a buffer allocated for data on this connection */
-  void    *rx_buf;
-  uint16_t rx_buf_len;
-
   void    *tx_buf;
   uint16_t tx_buf_len;
 
@@ -56,6 +87,8 @@ struct tcplib_sock {
      we didn't bother to pull it out
      of the options field */
   uint16_t mss;
+
+  uint16_t my_wind;
   /* the window the other end is
      reporting */
   uint16_t r_wind;
@@ -63,28 +96,31 @@ struct tcplib_sock {
   uint16_t ssthresh;
 
   // the current next sequence number for ourgoing data.
-  // the ack number is stored in the receive buffer.
   uint32_t seqno;
-  // uint32_t ackno;
+  // and the index of the last byte we've ACKed
+  uint32_t ackno;
 
   struct {
     int8_t retx;
   } timer;
 
+  /* retransmission counter */
+  uint16_t retxcnt;
+
   /* callbacks for this connection */
-  struct {
-    /* a previous connection request has finished */
-    void (*connect_done)(struct tcplib_sock *sock, int error);
+/*   struct { */
+/*     /\* a previous connection request has finished *\/ */
+/*     void (*connect_done)(struct tcplib_sock *sock, int error); */
 
-    /* a callback to signal new data is ready */
-    void (*recvfrom)(struct tcplib_sock *sock, void *data, int len);
+/*     /\* a callback to signal new data is ready *\/ */
+/*     void (*recvfrom)(struct tcplib_sock *sock, void *data, int len); */
 
-    /* the connection was closed by the other party */
-    void (*closed)(struct tcplib_sock *sock);
+/*     /\* the connection was closed by the other party *\/ */
+/*     void (*closed)(struct tcplib_sock *sock); */
 
-    /* you called close(); we've finished closing the socket. */
-    void (*close_done)(struct tcplib_sock *sock);
-  } ops;
+/*     /\* you called close(); we've finished closing the socket. *\/ */
+/*     void (*close_done)(struct tcplib_sock *sock); */
+/*   } ops; */
 
   /* this needs to be at the end so
      we can call init() on a socket
@@ -158,5 +194,12 @@ int tcplib_send(struct tcplib_sock *sock,
 
 int tcplib_close(struct tcplib_sock *sock);
 
-
+/* abort a connection 
+ *
+ * This will send a RST segment if the connection has been opened and
+ * immediately return the socket to the CLOSED, uninitialized state,
+ * although buffer pointers are maintained.
+ *
+ */
+int tcplib_abort(struct tcplib_sock *sock);
 #endif
index b6ae8fc167d45b6f06078a3e7e6291ba50ee59c8..a8a6edd7eadcb5be7de1dbcd0e1d00d0edea81c8 100644 (file)
@@ -1,16 +1,38 @@
+/*
+ * "Copyright (c) 2008, 2009 The Regents of the University  of California.
+ * All rights reserved."
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice, the following
+ * two paragraphs and the author appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
+ *
+ */
 
 #include <stdio.h>
+#include <string.h>
 #include "circ.h"
 
-void do_head_read(void *buf) {
-  char *read_data;
-  int i, data_len;
-  data_len = circ_buf_read_head(buf, (void **)&read_data);
-  printf("buf_read_head: %i\n", data_len);
-  for (i = 0; i < data_len; i++)
-    putc(((char *)read_data)[i], stdout);
-  putc('\n', stdout);
-}
+/* void do_head_read(void *buf) { */
+/*   char *read_data; */
+/*   int i, data_len; */
+/*   data_len = circ_buf_read_head(buf, (void **)&read_data); */
+/*   printf("buf_read_head: %i\n", data_len); */
+/*   for (i = 0; i < data_len; i++) */
+/*     putc(((char *)read_data)[i], stdout); */
+/*   putc('\n', stdout); */
+/* } */
 
 void do_read(void *buf, uint32_t sseqno) {
   char data[20];
@@ -29,7 +51,9 @@ int main(int argc, char **argv) {
   char data[20], readbuf[30];
   int i = 20, data_len;
   char *read_data;
-  if (circ_buf_init(buf, 200, 0, 1) < 0)
+  memset(buf, 0, sizeof(buf));
+
+  if (circ_buf_init(buf, 200, 0) < 0)
     printf("cir_buf_init: error\n");
 
   for (i=0;i<20;i++)
@@ -38,29 +62,51 @@ int main(int argc, char **argv) {
   if (circ_buf_write(buf, 0, data, 20) < 0)
     printf("circ_buf_write: error\n");
 
+  circ_buf_dump(buf);
+
   if (circ_buf_write(buf, 10, data, 20) < 0)
     printf("circ_buf_write: error\n");
 
+  circ_buf_dump(buf);
+
 
   if (circ_buf_write(buf, 50, data, 20) < 0)
     printf("circ_buf_write: error\n");
 
-  circ_buf_dump(buf);
+  // circ_buf_dump(buf);
 
-  do_head_read(buf);
-  circ_buf_dump(buf);
+  // do_head_read(buf);
+  // circ_buf_dump(buf);
 
   if (circ_buf_write(buf, 30, data, 20) < 0)
     printf("circ_buf_write: error\n");
 
-  circ_buf_dump(buf);
+  // circ_buf_dump(buf);
 
   if (circ_buf_write(buf, 70, data, 20) < 0)
     printf("circ_buf_write: error\n");
 
   circ_buf_dump(buf);
 
-  do_read(buf, 50);
+  circ_shorten_head(buf, 10);
+  circ_buf_dump(buf);
+
+  memset(buf, 0, sizeof(buf));
+
+  if (circ_buf_init(buf, 200, 0) < 0)
+    printf("cir_buf_init: error\n");
+
+  printf("\n\nRESTART\n\n");
+  
+  for (i = 0; i < 25; i++) {
+    circ_buf_write(buf, i * 20, data, 20);
+    do_read(buf, i * 20);
+    circ_shorten_head(buf, (i > 0) ? (i - 1) * 20 : 0 * 10);
+    circ_buf_dump(buf);
+  }
+
+  // do_read(buf, 50);
+
 /*   do_head_read(buf); */
 /*   circ_buf_dump(buf); */
 
index 4f39e57021ccdff1c90cbae80b43188e1eb6b00f..418d164752a521774f61b9fb13c00771ecae633f 100644 (file)
@@ -1,3 +1,24 @@
+/*
+ * "Copyright (c) 2008, 2009 The Regents of the University  of California.
+ * All rights reserved."
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice, the following
+ * two paragraphs and the author appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
+ *
+ */
 
 #include <stdlib.h>
 #include <unistd.h>
@@ -9,6 +30,7 @@
 #include <linux/if.h>
 #include <signal.h>
 #include <string.h>
+#include <limits.h>
 
 
 #include "ip.h"
 #include "ip_malloc.h"
 
 
-#define BUFSZ 1024
-#define LOSS_RATE_RECPR 100
+#define BUFSZ 1000
+#define LOSS_RATE_RECPR 200
+#define LOSS_RATE_TRANS 200
 
 int sock = 0;
-uint8_t iface_addr[16] = {0x20, 0x01, 0x00, 0x00, 0xde, 0xad, 0xbe, 0xef,
-                          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01};
-
+struct in6_addr iface_addr[16] = {{{0x20, 0x05, 0x00, 0x00, 0x00, 0x0, 0x00, 0x00,
+                                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}}};
 struct sockaddr_in6 laddr;
 
 
@@ -40,28 +62,32 @@ void printBuf(uint8_t *buf, uint16_t len) {
 void print_split_msg(struct split_ip_msg *msg) {
   int i;
   printf("src_addr: ");
-  for (i = 0; i < 16; i++) printf("0x%x ", msg->hdr.src_addr[i]);
+  for (i = 0; i < 16; i++) printf("0x%x ", msg->hdr.ip6_src.s6_addr[i]);
   printf("\ndst_addr: ");
-  for (i = 0; i < 16; i++) printf("0x%x ", msg->hdr.dst_addr[i]);
+  for (i = 0; i < 16; i++) printf("0x%x ", msg->hdr.ip6_dst.s6_addr[i]);
   printf("\nplen: %i hlim: %i\n", ntohs(msg->hdr.plen), msg->hdr.hlim);
 
   printBuf(msg->data, msg->data_len);
 }
 
-void rx(struct tcplib_sock *sock, void *data, int len) {
+void tcplib_extern_recv(struct tcplib_sock *sock, void *data, int len) {
   // printBuf(data, len);
   if (tcplib_send(sock, data, len) < 0)
     printf("tcplib_send: fail\n");
+
+  if (strncmp((char *)data, "close", 5) == 0) {
+    printf("Server closing sock\n");
+    tcplib_close(sock);
+  }
 }
 
-void cl(struct tcplib_sock *sock) {
+void tcplib_extern_closed(struct tcplib_sock *sock) {
   printf("remote conn closed\n");
   tcplib_close(sock);
 }
 
-void cd(struct tcplib_sock *sock) {
-  printf("local close done\n");
-  free(sock->rx_buf);
+void tcplib_extern_closedone(struct tcplib_sock *sock) {
+  printf("close done\n");
   free(sock->tx_buf);
   tcplib_init_sock(sock);
 /*   printf("rebinding...\n"); */
@@ -76,36 +102,40 @@ void cd(struct tcplib_sock *sock) {
 struct tcplib_sock *tcplib_accept(struct tcplib_sock *conn,
                                   struct sockaddr_in6 *from) {
   printf("tcplib_accept\n");
-  conn->rx_buf = malloc(BUFSZ);
-  conn->rx_buf_len = BUFSZ;
   
   conn->tx_buf = malloc(BUFSZ);
   conn->tx_buf_len = BUFSZ;
 
-  conn->ops.recvfrom = rx;
-  conn->ops.closed = cl;
-  conn->ops.close_done = cd;
 
   return conn;
 }
 
 void tcplib_send_out(struct split_ip_msg *msg, struct tcp_hdr *tcph) {
   uint8_t buf[8192];
+  struct timespec tv;
   if (sock <= 0) return;
 
-  memcpy(msg->hdr.src_addr, iface_addr, 16);
-  msg->hdr.src_addr[15] = 2;
+  // printf("sending message\n");
+
+  memcpy(msg->hdr.ip6_src.s6_addr, iface_addr, 16);
+  msg->hdr.ip6_src.s6_addr[15] = 2;
   msg->hdr.hlim = 64;
 
   memset(msg->hdr.vlfc, 0, 4);
   msg->hdr.vlfc[0] = 6 << 4;
 
-  tcph->chksum = msg_cksum(msg, IANA_TCP);
+  tcph->chksum = htons(msg_cksum(msg, IANA_TCP));
   
+  tv.tv_sec = 0;
+  // sleep for a ms to give up the cpu...
+  tv.tv_nsec = 1000000;
+  nanosleep(&tv);
+
   // print_split_msg(msg);
-  if (rand() % LOSS_RATE_RECPR == 0) {
+  if (rand() % LOSS_RATE_TRANS == 0) {
     printf("dropping packet on write\n");
   } else {
+    printf("tun_write\n");
     tun_write(sock, msg);
   }
 }
@@ -143,6 +173,7 @@ int main(int argg, char **argv) {
   struct timeval timeout;
   FD_ZERO(&fds);
   FD_SET(sock, &fds);
+  FD_SET(fileno(stdin), &fds);
 
   timeout.tv_sec = 0;
   timeout.tv_usec = 500000;
@@ -150,15 +181,33 @@ int main(int argg, char **argv) {
   while (select(sock + 1, &fds, NULL, NULL, &timeout) >= 0) {
     if (FD_ISSET(sock, &fds)) {
       if ((len = read(sock, buf, 8192)) <= 0) break;
+      // printf("read %i bytes\n", len);
       struct ip6_hdr *iph = (struct ip6_hdr *)payload;
       if (iph->nxt_hdr == IANA_TCP) {
         if (rand() % LOSS_RATE_RECPR == 0) {
           printf("dropping packet on rx\n");
         } else {
-          if (tcplib_process(payload, len - sizeof(struct tun_pi)))
+          void *p = buf + sizeof(struct tun_pi) + sizeof(struct ip6_hdr);
+          // printBuf(p, len - sizeof(struct tun_pi) - sizeof(struct tcp_hdr));
+          if (tcplib_process(iph, p)) // len - sizeof(struct tun_pi)))
             printf("TCPLIB_PROCESS: ERROR!\n");
         }
       }
+    } else if (FD_ISSET(fileno(stdin), &fds)) {
+      char c = getchar();
+      switch (c) {
+      case 'a':
+        printf("ABORTING CONNETION\n");
+        tcplib_abort(&srv_sock);
+        break;
+      case 'c':
+        printf("CLOSING CONNETION\n");
+        tcplib_close(&srv_sock);
+        break;
+      case 's':
+        printf("connection state: %i\n", srv_sock.state);
+        break;
+      }
     } else {
       timeout.tv_sec = 0;
       timeout.tv_usec = 500000;
@@ -170,6 +219,7 @@ int main(int argg, char **argv) {
 
     FD_ZERO(&fds);
     FD_SET(sock, &fds);
+    FD_SET(fileno(stdin), &fds);
   }
   tun_close(sock, dev);
 }
index 1949d88a66ee0723806b3c15bd4af9577adfe304..db5cc17f481b5fab42e9866595b8bd87f53765d1 100644 (file)
 
 # set the address of the router's 802.15.4 interface.  The interface
 # ID must be a 16-bit short identifier.
-addr 2001:470:1f04:56d::64
+addr fec0::64
 
 # the router can proxy neighbor IPv6 neighbor discovery on another
 # interface so that other machines on the subnet can discover hosts
 # routing through this router.  This specifies which interface to proxy
 # the NDP on.
-proxy eth1
+proxy lo #eth1
 
 # which 802.15.4 channel to operate on.  valid choices are 11-26.
 channel 15
diff --git a/tools/tinyos/misc/tos-nwprog b/tools/tinyos/misc/tos-nwprog
new file mode 100755 (executable)
index 0000000..d8c78a3
--- /dev/null
@@ -0,0 +1,308 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2007 Johns Hopkins University.
+# All rights reserved.
+#
+# Permission to use, copy, modify, and distribute this software and its
+# documentation for any purpose, without fee, and without written
+# agreement is hereby granted, provided that the above copyright
+# notice, the (updated) modification history and the author appear in
+# all copies of this source code.
+#
+# 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 HOLDERS OR CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, LOSS OF USE, DATA,
+# OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+# THE POSSIBILITY OF SUCH DAMAGE.
+
+# @author Razvan Musaloiu-E. <razvanm@cs.jhu.edu>
+# @author Chieh-Jan Mike Liang <cliang4@cs.jhu.edu>
+
+# b6lowpan/nwprog port:
+# @author Stephen Dawson-Haggerty <stevedh@cs.berkeley.edu>
+
+import sys, stat, struct, subprocess, time, os.path, socket, getopt, re
+try:
+    import tos
+except ImportError:
+    import posix
+    sys.path = [os.path.join(posix.environ['TOSROOT'], 'support', 'sdk', 'python')] + sys.path
+    import tos
+from datetime import datetime
+
+# Path to the python script that builds Deluge image from XML
+PATH_PY_BUILD_IMAGE  = os.path.join(os.path.dirname(sys.argv[0]), 'tos-build-deluge-image')
+
+# Commands for NWProg
+NWPROG_CMD_ERASE = 1
+NWPROG_CMD_WRITE = 2
+NWPROG_CMD_READ  = 3
+
+
+# Deluge parameters
+DELUGE_MAX_PAGES    = 128
+DELUGE_IDENT_OFFSET = 0
+DELUGE_IDENT_SIZE   = 128
+
+NWPROG_PORT = 5213
+NWPROG_PKT_SIZE = 64
+NWPROG_REQ_FMT = "!BBH"
+NWPROG_REPLY_FMT = "!BBBBH"
+
+ERROR_SUCCESS = 0
+nRetries = 3
+
+class CommandFailedException:
+    pass
+
+def send_command(cmd_str, retries):
+    s.sendto(cmd_str, (remote, NWPROG_PORT))
+    s.settimeout(3)
+    (real_cmd, real_imgno, real_offset) = struct.unpack(NWPROG_REQ_FMT, cmd_str[0:4])
+    try:
+        data, addr = s.recvfrom(1024)
+        # make sure this is the guy we're programming
+        if (addr[0] == remote):
+            (error, pack, cmd, imgno, offset) = struct.unpack(NWPROG_REPLY_FMT, data)
+            if error != ERROR_SUCCESS or real_offset != offset or real_imgno != imgno:
+                print "WARNING: received error while sending block; retrying"
+                raise socket.timeout
+            else: return data
+        else:
+            print "WARNING: received unexpected reply from", addr[0]
+            return False
+    except socket.timeout:
+        # socket timeout out try again
+        if retries > 0:
+            return send_command(cmd_str, retries - 1)
+        else:
+            return False
+
+def erase(imgNum, none=None):
+    e_req = struct.pack(NWPROG_REQ_FMT, NWPROG_CMD_ERASE, imgNum, 0)
+    return send_command(e_req, 1)
+
+def read(imgNum, unused=None):
+    length = 40000
+    pkt_offset = 0
+    while length > 0:
+        sreqpkt = struct.pack(NWPROG_REQ_FMT, NWPROG_CMD_READ, imgNum, pkt_offset)
+
+        data = send_command(sreqpkt, 5)
+        if data != False:
+            (error, pack, cmd, imgno, offset) = struct.unpack(NWPROG_REPLY_FMT, data[0:6])
+            if offset == pkt_offset:
+                for c in data[6:]:
+                    print >>sys.stderr, ord(c)
+            else:
+                print "ERROR: Out of sequence data: aborting"
+                sys.exit(1)
+        pkt_offset += len(data) - 6
+        length -= (len(data) - 6)
+    return True
+            
+
+def write(imgNum, data):
+    length = len(data)
+    total_length = length   # For progress bar
+    next_tick = 100         # For progress bar
+    start_time = time.time()
+
+    print "[0%        25%         50%         75%         100%]\r[",
+
+    pkt_offset = 0
+    pkt_length = 0
+
+    while length > 0:
+        if ((length * 100) / total_length) < next_tick:
+            next_tick = next_tick - 2
+            sys.stdout.write('-')
+            sys.stdout.flush()
+
+        # Calculates the payload size for the current packet
+        if length >= NWPROG_PKT_SIZE:
+            pkt_length = NWPROG_PKT_SIZE
+        else:
+            pkt_length = length
+
+        sreqpkt = struct.pack(NWPROG_REQ_FMT,
+                              NWPROG_CMD_WRITE, imgNum, pkt_offset)
+
+        for i in data[pkt_offset:pkt_offset+pkt_length]:
+            sreqpkt += chr(i)
+
+        # Sends packet to serial
+        if not send_command(sreqpkt, 5):
+            print "\nReceived error from mote while programming"
+            print "Perhaps the block size is too large, or the flash is broken?"
+            return False
+
+        length -= pkt_length
+        pkt_offset += pkt_length
+
+
+    print '\r' + ' ' * 52,
+    elasped_time = time.time() - start_time
+    print "\r%s bytes in %.2f seconds (%.4f bytes/s)" % (total_length, elasped_time, int(total_length) / (elasped_time))
+
+    return True
+
+
+# Injects an image (specified by tos_image_xml) to an image volume
+def upload(imgNum, tos_image_xml):
+    # Checks for valid file path
+    try:
+        os.stat(tos_image_xml)         # Checks whether tos_image_xml is a valid file
+    except:
+        print "ERROR: Unable to find the TOS image XML, \"%s\"" % tos_image_xml
+        return False
+    try:
+        os.stat(PATH_PY_BUILD_IMAGE)   # Checks whether PATH_PY_BUILD_IMAGE is a valid file
+    except:
+        print "ERROR: Unable to find the image building utility, \"%s\"" % PATH_PY_BUILD_IMAGE
+        return False
+
+    # Creates binary image from the TOS image XML
+    print "--------------------------------------------------"
+    cmd = [PATH_PY_BUILD_IMAGE, "-i", str(imgNum), tos_image_xml]
+    print "Create image:", ' '.join(cmd)
+    p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+    (out, err) = p.communicate(None)
+    print err,
+    print "--------------------------------------------------"
+
+    # Writes the new binary image
+    image = [struct.unpack("B", c)[0] for c in out]
+    if len(image) > 0 and erase(imgNum):
+        return write(imgNum, image)
+    else:
+        print "Could not proceed: image size is zero or erase failed"
+
+    return False
+
+
+def print_usage():
+    print
+    print "Usage: %s <(-e|-u) image_number> <-f app_xml> [options] [ip_address]" % sys.argv[0]
+    print "  -u --upload      Upload a compiled TinyOS application"
+    print "  -r --read        Read back a volume"
+    print "  -e --erase       Erase an image in the external flash"
+    print "  -f --appfile     The tos_image.xml file to upload"
+    print "  -m --motelist    A file containing a list of IPv6 addresses to upload to"
+    print "  -r --retries     The number of times to retry each operation (currently %i)" % nRetries
+    print "  -p --payload-sz  How much payload to include in every packet (currently %i)" % NWPROG_PKT_SIZE
+    print "  -d --dudfile     File to write list of motes which did not program (default: stdout)"
+    print
+
+def checkImgNum(imgNum):
+    # Checks for valid image number format
+    try:
+        imgNum = int(imgNum)
+    except:
+        print "ERROR: Image number is not valid"
+        sys.exit(-1)
+    return imgNum
+
+# ======== MAIN ======== #
+if __name__ == '__main__':
+
+    try:
+        opts, args = getopt.getopt(sys.argv[1:], "e:u:m:f:r:p:d:r:",
+                                   ["--erase", "--upload", "--motelist", "--appfile",
+                                    "--retries", "--payload", "--dudfile",
+                                    "--upload"])
+    except getopt.GetoptError, err:
+        print str(err)
+        print_usage()
+        sys.exit(1)
+
+    imgNum = None
+    uploadFile = None
+    appFile = None
+    dudFile = None
+    
+    for o, a in opts:
+        if o in ["-e", "--erase"]:
+            imgNum = checkImgNum(a)
+            cmd = "eras"
+        elif o in ["-u", "--upload"]:
+            imgNum = checkImgNum(a)
+            cmd = "upload"
+        elif o in ["-r", "--read"]:
+            imgNum = checkImgNum(a)
+            cmd = "read"
+        elif o in ["-m", "--motelist"]:
+            uploadFile = a
+        elif o in ["-f", "--appfile"]:
+            appFile = a
+        elif o in ["-r", "--retries"]:
+            nRetries = int(a)
+        elif o in ["-p", "--payload-sz"]:
+            NWPROG_PKT_SIZE = int(a)
+        elif o in ["-d", "--dudfile"]:
+            dudFile = a
+
+    if imgNum == None or (cmd != "eras" and cmd != "read" and appFile == None):
+        print_usage()
+        sys.exit(1)
+
+    upload_list = []
+    if uploadFile == None:
+        upload_list = [(ip, nRetries) for ip in args]
+    else:
+        fp = open(uploadFile, "r")
+        rexp = re.compile("^.*#")
+        for ip in fp.readlines():
+            if re.match(rexp,ip): continue
+            upload_list.append( (ip.strip().lower(), nRetries) )
+        fp.close()
+
+    if cmd == 'upload': cmd_fn = upload
+    elif cmd == 'read': cmd_fn = read
+    else: cmd_fn = erase
+
+    print "%sing %i motes" % (cmd, len(upload_list))
+    print "retries: %i payload: %i" % (nRetries, NWPROG_PKT_SIZE)
+
+    for t in range(0, nRetries):
+        for i in range(0, len(upload_list)):
+            remote, tries_left = upload_list[i]
+            if tries_left <= 0: continue
+            print "%sing %s, %i tries remaining ..." % (cmd, remote, tries_left)
+            try:
+                s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
+                if not cmd_fn(imgNum, appFile):
+                    upload_list[i] = (remote, tries_left - 1)
+                else:
+                    upload_list[i] = (remote, -1)
+                    print "Success!"
+                s.close()
+            except KeyboardInterrupt:
+                print "Interrupted; exiting"
+                sys.exit(2)
+            except Exception, e:
+                print "Received unexpected exception while programming"
+                print str(e)
+                s.close()
+                pass
+
+    printedHeading = False
+    if dudFile != None:
+        dudFp = open(dudFile, "w")
+    else: dudFp = sys.stdout
+    
+    for i in range(0, len(upload_list)):
+        remote, tries_left = upload_list[i]
+        if tries_left == 0 and not printedHeading:
+            printedHeading = True
+            print "WARNING: not all motes were succesfully %sed!" % cmd
+        if tries_left == 0:
+            print >>dudFp, remote
+
+    if dudFp != sys.stdout:
+        dudFp.close()
index d9657ece69579d15dd2f0f15edacc4c5da5a0d74..293cd8fada732898dd2c882ca6916d9ba94455e0 100644 (file)
@@ -27,6 +27,7 @@ enum {
   ICMP_EXT_TYPE_BEACON = 17,
 };
 
+#ifndef LOW_POWER_LISTENING     /* parameters for CSMA MAC */
 enum {
   // jitter start requests by 10 seconds
   TRICKLE_JITTER = 10240,
@@ -37,6 +38,18 @@ enum {
   TRICKLE_MAX = (TRICKLE_PERIOD << 5),
   
 };
+#else  /* parameters for LPL */
+enum {
+  // have a trickle timer with a period of 4
+  TRICKLE_PERIOD = 16384L, 
+  // jitter start requests by 10 seconds
+  TRICKLE_JITTER = TRICKLE_PERIOD,
+
+  // send a maximum of three trickle messages
+  TRICKLE_MAX = (TRICKLE_PERIOD << 5),
+  
+};
+#endif
 
 typedef nx_struct icmp6_echo_hdr {
   nx_uint8_t        type;     /* type field */
@@ -80,6 +93,7 @@ typedef nx_struct {
   nx_uint8_t type;
   nx_uint8_t length;
   nx_uint16_t metric;
+  nx_uint8_t pad[4];
 } rqual_t;
 
 struct icmp_stats {
index 102d077bbedf75ed3fbac02d3149c2a89ce35eb0..4ac2b31cb2c82b99854705c044ebf4107944e1a9 100644 (file)
@@ -23,6 +23,7 @@
 #include <lib6lowpan.h>
 #include <6lowpan.h>
 #include <ip_malloc.h>
+#include <Statistics.h>
 #include "in_cksum.h"
 #include "PrintfUART.h"
 #include "ICMP.h"
@@ -137,7 +138,7 @@ module ICMPResponderP {
 
     msg->hdr.nxt_hdr = IANA_ICMP;
 
-    i_hdr->cksum = call ICMP.cksum(msg, IANA_ICMP);
+    i_hdr->cksum = htons(call ICMP.cksum(msg, IANA_ICMP));
 
     call IP.send(msg);
 
@@ -153,7 +154,7 @@ module ICMPResponderP {
     if (ipmsg == NULL) return;
 
     dbg("ICMPResponder", "Solicitation\n");
-    //stats.sol_tx++;
+    //BLIP_STATS_INCR(stats.sol_tx);
 
     msg->type = ICMP_TYPE_ROUTER_SOL;
     msg->code = 0;
@@ -169,7 +170,9 @@ module ICMPResponderP {
 
 
     call IPAddress.getLLAddr(&ipmsg->hdr.ip6_src);
-    inet_pton6("ff02::2", &ipmsg->hdr.ip6_dst);
+    ip_memclr((uint8_t *)&ipmsg->hdr.ip6_dst, 16);
+    ipmsg->hdr.ip6_dst.s6_addr16[0] = htons(0xff02);
+    ipmsg->hdr.ip6_dst.s6_addr16[7] = htons(2);
 
     msg->cksum = call ICMP.cksum(ipmsg, IANA_ICMP);
 
@@ -263,17 +266,20 @@ module ICMPResponderP {
     if (globalPrefix) {
       len += sizeof(pfx_t);
       p->type = ICMP_EXT_TYPE_PREFIX;
-      p->length = 8;
+      p->length = sizeof(pfx_t) >> 3;
+      p->pfx_len = 64;
       memcpy(p->prefix, call IPAddress.getPublicAddr(), 8);
     }
 
     len += sizeof(rqual_t);
     q->type = ICMP_EXT_TYPE_BEACON;
-    q->length = 2;
+    q->length = sizeof(rqual_t) >> 3;;
     q->metric = call IPRouting.getQuality();
 
     call IPAddress.getLLAddr(&ipmsg->hdr.ip6_src);
-    inet_pton6("ff02::1", &ipmsg->hdr.ip6_dst);
+    ip_memclr((uint8_t *)&ipmsg->hdr.ip6_dst, 16);
+    ipmsg->hdr.ip6_dst.s6_addr16[0] = htons(0xff02);
+    ipmsg->hdr.ip6_dst.s6_addr16[7] = htons(1);
 
     //dbg("ICMPResponder", "My Address: [0x%x] [0x%x] [0x%x] [0x%x]\n", ipmsg->hdr.src_addr[12], ipmsg->hdr.src_addr[13], ipmsg->hdr.src_addr[14], ipmsg->hdr.src_addr[15]);
     dbg("ICMPResponder", "adv hop limit: 0x%x\n", r->hlim);
@@ -300,7 +306,7 @@ module ICMPResponderP {
                      struct ip_metadata *meta) {
     icmp_echo_hdr_t *req = (icmp_echo_hdr_t *)payload;
     uint16_t len = ntohs(iph->plen);
-    stats.rx++;
+    BLIP_STATS_INCR(stats.rx);
   
     // for checksum calculation
     printfUART ("icmp type: 0x%x code: 0x%x cksum: 0x%x ident: 0x%x seqno: 0x%x len: 0x%x\n",
@@ -309,7 +315,7 @@ module ICMPResponderP {
     switch (req->type) {
     case ICMP_TYPE_ROUTER_ADV:
         handleRouterAdv(payload, len, meta);
-        //stats.adv_rx++;
+        //BLIP_STATS_INCR(stats.adv_rx);
         break;
     case ICMP_TYPE_ROUTER_SOL:
       // only reply to solicitations if we have established a default route.
@@ -322,7 +328,7 @@ module ICMPResponderP {
         nx_uint32_t *sendTime = (nx_uint32_t *)(req + 1);
         struct icmp_stats p_stat;
         p_stat.seq = req->seqno;
-        p_stat.ttl = 0;// buf->hdr.hlim;
+        p_stat.ttl = iph->hlim;
         p_stat.rtt = (call LocalTime.get()) - (*sendTime);
         signal ICMPPing.pingReply[req->ident](&iph->ip6_src, &p_stat);
         ping_rcv++;
index b8af35202bd2e835da05f3ba4d587fb13d2bc4e4..68b10cb1084b45c8a60f8b2b1730856036057103 100644 (file)
@@ -37,11 +37,11 @@ module IPAddressP {
 } implementation {
 
 
-  command hw_addr_t IPAddress.getShortAddr() {
+  command ieee154_saddr_t IPAddress.getShortAddr() {
     return TOS_NODE_ID;
   }
 
-  command void IPAddress.setShortAddr(hw_addr_t newAddr) {
+  command void IPAddress.setShortAddr(ieee154_saddr_t newAddr) {
     TOS_NODE_ID = newAddr;
 #ifndef SIM
     call ActiveMessageAddress.setAddress(call ActiveMessageAddress.amGroup(), newAddr);
@@ -51,6 +51,7 @@ module IPAddressP {
   }
 
   command void IPAddress.getLLAddr(struct in6_addr *addr) {
+    __my_address.s6_addr16[7] = htons(TOS_NODE_ID);
     memcpy(addr->s6_addr, linklocal_prefix, 8);
     memcpy(&addr->s6_addr[8], &__my_address.s6_addr[8], 8);
   }
index ffb2641b3a684ed4424401509ebe0aaf11810fbb..b2e6caeca0801ed8e6848304c48102856bf22706 100644 (file)
@@ -24,6 +24,7 @@
 
 #include <message.h>
 #include <lib6lowpan.h>
+#include <Statistics.h>
 
 enum {
   N_PARENTS = 3,
@@ -31,12 +32,13 @@ enum {
   N_EPOCHS_COUNTED = 1,
   N_RECONSTRUCTIONS = 2,
   N_FORWARD_ENT = IP_NUMBER_FRAGMENTS,
+  N_RETRIES = 5,
 };
 
 enum {
   CONF_EVICT_THRESHOLD = 5, // Neighbor is 'mature'
   CONF_PROM_THRESHOLD = 5, // Acceptable threshold for promotion
-  MAX_CONSEC_FAILURES = 40, // Max Failures before reroute is attempted
+  MAX_CONSEC_FAILURES = 11, // Max Failures before reroute is attempted
   PATH_COST_DIFF_THRESH = 10, // Threshold for 'similar' path costs
   LQI_DIFF_THRESH = 10, // Threshold for 'similar' LQI's
   LINK_EVICT_THRESH = 50, // ETX * 10
@@ -51,10 +53,18 @@ enum {
   BELOW_THRESH = 3,
 };
 
+#ifndef LOW_POWER_LISTENING
 enum {
   TGEN_BASE_TIME = 512,
   TGEN_MAX_INTERVAL = 60L * 1024L * 5L,
 };
+#else
+enum {
+  TGEN_MAX_INTERVAL = 60L * 1024L * 5L,
+  TGEN_BASE_TIME = TGEN_MAX_INTERVAL,
+};
+#endif
+
 
 struct epoch_stats {
   uint16_t success;
@@ -98,7 +108,7 @@ enum {
 typedef struct {
   // The extra 2 is because one dest could be from source route, other
   //  from the dest being a direct neighbor
-  hw_addr_t dest[N_FLOW_CHOICES + N_PARENT_CHOICES + 2];
+  ieee154_saddr_t dest[N_FLOW_CHOICES + N_PARENT_CHOICES + 2];
   uint8_t   current:4;
   uint8_t   nchoices:4;
   uint8_t   retries;
@@ -111,6 +121,7 @@ typedef struct {
   uint8_t frags_sent;
   bool failed;
   uint8_t refcount;
+  uint8_t local_flow_label;
 } send_info_t;
 
 typedef struct {
@@ -120,7 +131,7 @@ typedef struct {
 
 typedef struct {
   uint8_t timeout;
-  hw_addr_t l2_src;
+  ieee154_saddr_t l2_src;
   uint16_t old_tag;
   uint16_t new_tag;
   send_info_t *s_info;
@@ -193,7 +204,7 @@ struct flow_entry {
 struct neigh_entry {
   uint8_t flags;
   uint8_t hops; // Put this before neighbor to remove potential padding issues
-  hw_addr_t neighbor;
+  ieee154_saddr_t neighbor;
   uint16_t costEstimate;
   uint16_t linkEstimate;
   struct epoch_stats stats[N_EPOCHS];
@@ -227,46 +238,4 @@ typedef enum {
 } send_type_t;
 
 
-typedef nx_struct {
-  nx_uint16_t sent;
-  nx_uint16_t forwarded;
-  nx_uint8_t rx_drop;
-  nx_uint8_t tx_drop;
-  nx_uint8_t fw_drop;
-  nx_uint8_t rx_total;
-  nx_uint8_t real_drop;
-  nx_uint8_t hlim_drop;
-  nx_uint8_t senddone_el;
-  nx_uint8_t fragpool;
-  nx_uint8_t sendinfo;
-  nx_uint8_t sendentry;
-  nx_uint8_t sndqueue;
-  nx_uint8_t encfail;
-  nx_uint16_t heapfree;
-} ip_statistics_t;
-
-
-typedef nx_struct {
-  nx_uint8_t hop_limit;
-  nx_uint16_t parent;
-  nx_uint16_t parent_metric;
-  nx_uint16_t parent_etx;
-} route_statistics_t;
-
-typedef nx_struct {
-/*   nx_uint8_t sol_rx; */
-/*   nx_uint8_t sol_tx; */
-/*   nx_uint8_t adv_rx; */
-/*   nx_uint8_t adv_tx; */
-/*   nx_uint8_t unk_rx; */
-  nx_uint16_t rx;
-} icmp_statistics_t;
-
-typedef nx_struct {
-  nx_uint16_t total;
-  nx_uint16_t failed;
-  nx_uint16_t seqno;
-  nx_uint16_t sender;
-} udp_statistics_t;
-
 #endif
index e74d70d2e2ba4aaa96e2a83740b151bffb93c75f..66a44c0f2c8f27308ad69fb14d8a6842f159112d 100644 (file)
@@ -39,11 +39,7 @@ configuration IPDispatchC {
   }
 } implementation {
   
-#ifndef SIM
-  components CC2420ActiveMessageC as MessageC;
-#else
-  components ActiveMessageC as MessageC;
-#endif
+  components Ieee154MessageC as MessageC;
   components MainC, IPDispatchP, IPAddressC, IPRoutingP; 
   components NoLedsC as LedsC;
   components RandomC;
@@ -54,27 +50,18 @@ configuration IPDispatchC {
 
   IPDispatchP.Boot -> MainC;
 
-#ifndef SIM
-  IPDispatchP.IEEE154Send -> MessageC;
-  IPDispatchP.IEEE154Receive -> MessageC;
-#else
-  IPDispatchP.IEEE154Send -> MessageC.AMSend[0];
-  IPDispatchP.IEEE154Receive -> MessageC.Receive[0];
-#endif
-  IPDispatchP.Packet -> MessageC.SubAMPacket;
+  IPDispatchP.Ieee154Send -> MessageC;
+  IPDispatchP.Ieee154Receive -> MessageC.Ieee154Receive;
+  IPDispatchP.Packet -> MessageC.Packet;
 #ifdef LOW_POWER_LISTENING
   IPDispatchP.LowPowerListening -> MessageC;
 #endif
 
+  components CC2420PacketC;
 
-  IPDispatchP.IEEE154Packet -> MessageC;
+  IPDispatchP.Ieee154Packet -> MessageC;
   IPDispatchP.PacketLink -> MessageC;
-  IPDispatchP.CC2420Packet -> MessageC;
-
-#ifdef DBG_TRACK_FLOWS
-  IPDispatchP.getFlowID -> MessageC;
-#endif
-
+  IPDispatchP.CC2420Packet -> CC2420PacketC;
 
   IPDispatchP.Leds -> LedsC;
 
@@ -101,13 +88,21 @@ configuration IPDispatchC {
   IPRoutingP.ICMP  -> ICMPResponderC;
   IPDispatchP.RadioControl -> MessageC;
 
+  components IPExtensionP;
+  MainC.SoftwareInit -> IPExtensionP.Init;
+  IPDispatchP.InternalIPExtension -> IPExtensionP;
+
   IPDispatchP.IPRouting -> IPRoutingP;
   IPRoutingP.Boot -> MainC;
   IPRoutingP.Leds -> LedsC;
   IPRoutingP.IPAddress -> IPAddressC;
   IPRoutingP.Random -> RandomC;
   IPRoutingP.TrafficGenTimer -> TGenTimer;
-  IPRoutingP.TGenSend -> IPDispatchP.IP[NXTHDR_UNKNOWN];
+  IPRoutingP.TGenSend -> IPDispatchP.IP[IPV6_NONEXT];
+
+  IPRoutingP.IPExtensions -> IPDispatchP;
+  IPRoutingP.DestinationExt -> IPExtensionP.DestinationExt[0];
+  
 
   IPStats    = IPDispatchP;
   RouteStats = IPRoutingP;
index 214b7cd55451f7994d1b7b70ceba5d0e6bce6a3c..a83eee85125b084c72cc9d7feb420c1d3bdd42e4 100644 (file)
@@ -76,9 +76,6 @@
 #include "IPDispatch.h"
 #include "table.h"
 #include "PrintfUART.h"
-#ifdef PRINTF_LIBRARY
-#include "printf.h"
-#endif
 
 /*
  * Provides IP layer reception to applications on motes.
@@ -91,7 +88,15 @@ module IPDispatchP {
     interface SplitControl;
     // interface for protocols not requiring special hand-holding
     interface IP[uint8_t nxt_hdr];
+
     interface Statistics<ip_statistics_t>;
+
+    // IPv6 Extension headers are very useful, but somewhat tricky to
+    // handle in a pretty way.  This is my attempt.
+
+    // for inspecting/modifying extension headers on incomming packets
+    interface IPExtensions;
+
   }
   uses {
     interface Boot;
@@ -101,13 +106,13 @@ module IPDispatchP {
     interface Packet;
 
 #ifndef SIM
-    interface IEEE154Send;
-    interface IEEE154Packet;
+    interface Ieee154Send;
+    interface Ieee154Packet;
 #else
-    interface AMSend as IEEE154Send;
-    interface AMPacket as IEEE154Packet;
+    interface AMSend as Ieee154Send;
+    interface AMPacket as Ieee154Packet;
 #endif
-    interface Receive as IEEE154Receive;
+    interface Receive as Ieee154Receive;
 
     interface PacketLink;
 
@@ -128,13 +133,17 @@ module IPDispatchP {
     
     interface IPAddress;
 
-#ifdef DBG_TRACK_FLOWS
-    command flow_id_t *getFlowID(message_t *);
-#endif
-
+    interface InternalIPExtension;
   }
 } implementation {
   
+#include "table.c"
+
+#ifdef PRINTFUART_ENABLED
+#undef dbg
+#define dbg(X, fmt, args...)  printfUART(fmt, ## args)
+#endif
+
   enum {
     S_RUNNING,
     S_STOPPED,
@@ -142,6 +151,7 @@ module IPDispatchP {
   };
   uint8_t state = S_STOPPED;
   bool radioBusy;
+  uint8_t current_local_label = 0;
   ip_statistics_t stats;
 
   // this in theory could be arbitrarily large; however, it needs to
@@ -170,16 +180,6 @@ module IPDispatchP {
   //
   ////////////////////////////////////////
 
-#ifdef DBG_TRACK_FLOWS
-  uint16_t dbg_flowid = 0;
-#endif
-
-#ifndef SIM
-#define CHECK_NODE_ID if (0) return
-#else
-#define CHECK_NODE_ID if (TOS_NODE_ID == BASESTATION_ID) return 
-#endif
-
   task void sendTask();
 
   void reconstruct_clear(void *ent) {
@@ -227,7 +227,6 @@ module IPDispatchP {
 #define SENDINFO_DECR(X) if (--((X)->refcount) == 0) call SendInfoPool.put(X)
 
   command error_t SplitControl.start() {
-    CHECK_NODE_ID FAIL;
     return call RadioControl.start();
   }
 
@@ -259,7 +258,6 @@ module IPDispatchP {
   }
 
   event void Boot.booted() {
-    CHECK_NODE_ID;
     call Statistics.clear();
 
     ip_malloc_init();
@@ -289,7 +287,8 @@ module IPDispatchP {
    */
   void signalDone(reconstruct_t *recon) {
     struct ip6_hdr *iph = (struct ip6_hdr *)recon->buf;
-    signal IP.recv[iph->nxt_hdr](iph, recon->transport_hdr, &recon->metadata);
+
+    signal IP.recv[recon->nxt_hdr](iph, recon->transport_hdr, &recon->metadata);
     ip_free(recon->buf);
     recon->timeout = T_UNUSED;
     recon->buf = NULL;
@@ -364,7 +363,6 @@ module IPDispatchP {
   }
 
   event void ExpireTimer.fired() {
-    CHECK_NODE_ID;
     table_map(&recon_cache, reconstruct_age);
     table_map(&forward_cache, forward_age);
 
@@ -381,7 +379,7 @@ module IPDispatchP {
    * allocate a structure for recording information about incomming fragments.
    */
 
-  reconstruct_t *get_reconstruct(hw_addr_t src, uint16_t tag) {
+  reconstruct_t *get_reconstruct(ieee154_saddr_t src, uint16_t tag) {
     reconstruct_t *ret = NULL;
     int i;
     for (i = 0; i < N_RECONSTRUCTIONS; i++) {
@@ -418,28 +416,32 @@ module IPDispatchP {
    *  spot, this means we are along the default path and so should invalidate this
    *  source header.
    */
-  void updateSourceRoute(hw_addr_t prev_hop, struct source_header *sh) {
+  void updateSourceRoute(ieee154_saddr_t prev_hop, struct ip6_route *sh) {
     uint16_t my_address = call IPAddress.getShortAddr();
-    if ((sh->dispatch & IP_EXT_SOURCE_INVAL) == IP_EXT_SOURCE_INVAL) return;
-    if (((sh->dispatch & IP_EXT_SOURCE_RECORD) != IP_EXT_SOURCE_RECORD) && 
-        (ntohs(sh->hops[sh->current]) != my_address)) {
-      sh->dispatch |= IP_EXT_SOURCE_INVAL;
-      dbg("IPDispatch", "Invalidating source route!\n");
-      return;
-    } 
-    if (sh->current == SH_NENTRIES(sh)) return;
-    sh->hops[sh->current] = htons(prev_hop);
-    sh->current++;
-  }
+    uint16_t target_hop = sh->hops[ROUTE_NENTRIES(sh) - sh->segs_remain];
+    if ((sh->type & ~IP6ROUTE_FLAG_MASK) == IP6ROUTE_TYPE_INVAL || sh->segs_remain == 0) return;
 
-    
+    if (target_hop != htons(my_address)) {
+      printfUART("invalidating source route\n");
 
+      if (ROUTE_NENTRIES(sh) >= 2) {
+        sh->hops[0] = htons(prev_hop);
+        sh->hops[1] = target_hop;
+      }
+      sh->type = (sh->type & IP6ROUTE_FLAG_MASK) | IP6ROUTE_TYPE_INVAL;
+    } else {
+      sh->hops[ROUTE_NENTRIES(sh) - sh->segs_remain] = htons(prev_hop);
+      sh->segs_remain--;
+      printfUART("updating source route with prev: 0x%x remaining: %i\n",
+                 prev_hop, sh->segs_remain);
+    }
+  }
 
   message_t *handle1stFrag(message_t *msg, packed_lowmsg_t *lowmsg) {
     uint8_t *unpack_buf;
     struct ip6_hdr *ip;
 
-    // uint16_t real_payload_length, real_offset = sizeof(struct ip6_hdr);
+    uint16_t real_payload_length;// , real_offset = sizeof(struct ip6_hdr);
 
     unpack_info_t u_info;
 
@@ -458,6 +460,21 @@ module IPDispatchP {
     
     ip = (struct ip6_hdr *)unpack_buf;
 
+
+    if (u_info.hdr_route != NULL) {
+      // this updates the source route in the message_t, if it
+      // exists...
+      updateSourceRoute(call Ieee154Packet.source(msg),
+                        u_info.hdr_route);
+    }
+
+    // we handle the extension headers generically now
+    signal IPExtensions.handleExtensions(current_local_label++,
+                                         ip,
+                                         u_info.hdr_hop,
+                                         u_info.hdr_dest,
+                                         u_info.hdr_route,
+                                         u_info.nxt_hdr);
     
     // first check if we forward or consume it
     if (call IPRouting.isForMe(ip)) {
@@ -468,18 +485,25 @@ module IPDispatchP {
       //   - if fragmented, wait for remaining fragments
       //   - if not, dispatch from here.
 
-      metadata.sender = call IEEE154Packet.source(msg);
+      metadata.sender = call Ieee154Packet.source(msg);
       metadata.lqi = call CC2420Packet.getLqi(msg);
 
-      ip->plen = htons(ntohs(ip->plen) - u_info.payload_offset);
-      switch (ip->nxt_hdr) {
-      case IANA_UDP:
-        ip->plen = htons(ntohs(ip->plen) + sizeof(struct udp_hdr));
-      }
+      real_payload_length = ntohs(ip->plen);
+      adjustPlen(ip, &u_info);
 
       if (!hasFrag1Header(lowmsg)) {
         uint16_t amount_here = lowmsg->len - (u_info.payload_start - lowmsg->data);
 
+#if 0
+        int i;
+        for (i = 0; i < 48; i++)
+          printfUART("0x%x ", ((uint8_t *)ip)[i]);
+        printfUART("\n");
+        for (i = 0; i < 8; i++)
+          printfUART("0x%x ", ((uint8_t *)u_info.payload_start)[i]);
+        printfUART("\n");
+#endif
+
         // we can fill in the data and deliver the packet from here.
         // this is the easy case...
         // we malloc'ed a bit extra in this case so we don't have to
@@ -487,7 +511,9 @@ module IPDispatchP {
         //  buffers.
         // if (rcv_buf == NULL) goto done;
         ip_memcpy(u_info.header_end, u_info.payload_start, amount_here);
-        signal IP.recv[ip->nxt_hdr](ip, u_info.transport_ptr, &metadata);
+
+        printfUART("IP.recv[%i] here: %i\n", amount_here);
+        signal IP.recv[u_info.nxt_hdr](ip, u_info.transport_ptr, &metadata);
       } else {
         // in this case, we need to set up a reconstruction
         // structure so when the next packets come in, they can be
@@ -507,12 +533,13 @@ module IPDispatchP {
         }
         
         // the total size of the IP packet
-        rcv_buf = ip_malloc(ntohs(ip->plen) + sizeof(struct ip6_hdr));
+        rcv_buf = ip_malloc(real_payload_length + sizeof(struct ip6_hdr));
 
         recon->metadata.sender = lowmsg->src;
         recon->tag = tag;
-        recon->size = ntohs(ip->plen) + sizeof(struct ip6_hdr);
+        recon->size = real_payload_length + sizeof(struct ip6_hdr);
         recon->buf = rcv_buf;
+        recon->nxt_hdr = u_info.nxt_hdr;
         recon->transport_hdr = ((uint8_t *)rcv_buf) + (u_info.transport_ptr - unpack_buf);
         recon->bytes_rcvd = u_info.payload_offset + amount_here + sizeof(struct ip6_hdr);
         recon->timeout = T_ACTIVE;
@@ -548,10 +575,13 @@ module IPDispatchP {
       forward_entry_t *fwd;
       message_t *msg_replacement;
       
+      // this is a pointer to the hop-limit field in the packed fragment
       *u_info.hlim = *u_info.hlim - 1;
       if (*u_info.hlim == 0) {
+#ifdef ICMP_TIME_EXCEEDED
         uint16_t amount_here = lowmsg->len - (u_info.payload_start - lowmsg->data);
         call ICMP.sendTimeExceeded(ip, &u_info, amount_here);
+#endif
         // by bailing here and not setting up an entry in the
         // forwarding cache, following fragments will be dropped like
         // they should be.  we don't strictly follow the RFC that says
@@ -572,17 +602,11 @@ module IPDispatchP {
         goto fail;
       }
 
-      if (ip->nxt_hdr == NXTHDR_SOURCE) {
-        // this updates the source route in the message_t, if it
-        // exists...
-        updateSourceRoute(call IEEE154Packet.source(msg),
-                          u_info.sh);
-      }
-
-      if (call IPRouting.getNextHop(ip, u_info.sh, lowmsg->src, &s_info->policy) != SUCCESS)
+      if (call IPRouting.getNextHop(ip, u_info.hdr_route, 
+                                    lowmsg->src, &s_info->policy) != SUCCESS)
         goto fwd_fail;
 
-      dbg("IPDispatch", "next hop is: 0x%x\n", s_info->policy.dest);
+      dbg("IPDispatch", "next hop is: 0x%x\n", s_info->policy.dest[0]);
 
       if (hasFrag1Header(lowmsg)) {
         fwd = table_search(&forward_cache, forward_unused);
@@ -591,7 +615,7 @@ module IPDispatchP {
         }
 
         fwd->timeout = T_ACTIVE;
-        fwd->l2_src = call IEEE154Packet.source(msg);
+        fwd->l2_src = call Ieee154Packet.source(msg);
         getFragDgramTag(lowmsg, &fwd->old_tag);
         fwd->new_tag = ++lib6lowpan_frag_tag;
         // forward table gets a reference
@@ -602,13 +626,16 @@ module IPDispatchP {
 
       // give a reference to the send_entry
       SENDINFO_INCR(s_info);
+      s_info->local_flow_label = current_local_label - 1;
       s_entry->msg = msg;
       s_entry->info = s_info;
 
       if (call SendQueue.enqueue(s_entry) != SUCCESS)
-        stats.encfail++;
+        BLIP_STATS_INCR(stats.encfail);
       post sendTask();
 
+      BLIP_STATS_INCR(stats.forwarded);
+
       // s_info leaves lexical scope;
       SENDINFO_DECR(s_info);
       ip_free(unpack_buf);
@@ -628,19 +655,21 @@ module IPDispatchP {
     return msg;
   }
 
-  event message_t *IEEE154Receive.receive(message_t *msg, void *msg_payload, uint8_t len) {
+  event message_t *Ieee154Receive.receive(message_t *msg, void *msg_payload, uint8_t len) {
     packed_lowmsg_t lowmsg;
-    CHECK_NODE_ID msg;
 
+    printfUART("p1: %p p2: %p\n", msg_payload, call Packet.getPayload(msg, 0));
     // set up the ip message structaddFragment
     lowmsg.data = msg_payload;
     lowmsg.len  = len;
-    lowmsg.src  = call IEEE154Packet.source(msg);
-    lowmsg.dst  = call IEEE154Packet.destination(msg);
+    lowmsg.src  = call Ieee154Packet.source(msg);
+    lowmsg.dst  = call Ieee154Packet.destination(msg);
+
+    printfUART("receive(): %i\n", len);
 
-    stats.rx_total++;
+    BLIP_STATS_INCR(stats.rx_total);
 
-    call IPRouting.reportReception(call IEEE154Packet.source(msg),
+    call IPRouting.reportReception(call Ieee154Packet.source(msg),
                                    call CC2420Packet.getLqi(msg));
 
     lowmsg.headers = getHeaderBitmap(&lowmsg);
@@ -667,7 +696,7 @@ module IPDispatchP {
       if (getFragDgramOffset(&lowmsg, &offset_cmpr)) goto fail;
 
       forward_lookup_tag = tag;
-      forward_lookup_src = call IEEE154Packet.source(msg);
+      forward_lookup_src = call Ieee154Packet.source(msg);
 
       fwd = table_search(&forward_cache, forward_lookup);
       payload = getLowpanPayload(&lowmsg);
@@ -684,6 +713,7 @@ module IPDispatchP {
         
         recon->bytes_rcvd += amount_here;
         
+        printfUART("sz: %i rcv: %i\n", recon->size, recon->bytes_rcvd);
         if (recon->size == recon->bytes_rcvd) { 
           // signal and free the recon.
           signalDone(recon);
@@ -704,7 +734,7 @@ module IPDispatchP {
           if (s_entry != NULL)
             call SendEntryPool.put(s_entry);
 
-          stats.fw_drop++;
+          BLIP_STATS_INCR(stats.fw_drop);
           fwd->timeout = T_FAILED1;
           goto fail;
         }
@@ -731,7 +761,7 @@ module IPDispatchP {
             fwd->s_info->policy.dest[s_entry->info->policy.current]);
 
         if (call SendQueue.enqueue(s_entry) != SUCCESS) {
-          stats.encfail++;
+          BLIP_STATS_INCR(stats.encfail);
           dbg("Drops", "drops: receive enqueue failed\n");
         }
         post sendTask();
@@ -743,7 +773,7 @@ module IPDispatchP {
 
   fail:
     dbg("Drops", "drops: receive()\n");;
-    stats.rx_drop++;
+    BLIP_STATS_INCR(stats.rx_drop);
   done:
     return msg;
   }
@@ -753,6 +783,8 @@ module IPDispatchP {
    * Send-side functionality
    */
 
+
+
   task void sendTask() {
     send_entry_t *s_entry;
     if (radioBusy || state != S_RUNNING) return;
@@ -761,7 +793,7 @@ module IPDispatchP {
     s_entry = call SendQueue.head();
 
 
-    call IEEE154Packet.setDestination(s_entry->msg, 
+    call Ieee154Packet.setDestination(s_entry->msg, 
                                       s_entry->info->policy.dest[s_entry->info->policy.current]);
     call PacketLink.setRetries(s_entry->msg, s_entry->info->policy.retries);
     call PacketLink.setRetryDelay(s_entry->msg, s_entry->info->policy.delay);
@@ -769,7 +801,7 @@ module IPDispatchP {
     call LowPowerListening.setRxSleepInterval(s_entry->msg, LPL_SLEEP_INTERVAL);
 #endif
 
-    dbg("IPDispatch", "sendTask dest: 0x%x len: 0x%x \n", call IEEE154Packet.destination(s_entry->msg),
+    dbg("IPDispatch", "sendTask dest: 0x%x len: 0x%x \n", call Ieee154Packet.destination(s_entry->msg),
         call Packet.payloadLength(s_entry->msg));
     
     if (s_entry->info->failed) {
@@ -777,7 +809,7 @@ module IPDispatchP {
       goto fail;
     }
           
-    if ((call IEEE154Send.send(call IEEE154Packet.destination(s_entry->msg),
+    if ((call Ieee154Send.send(call Ieee154Packet.destination(s_entry->msg),
                                s_entry->msg,
                                call Packet.payloadLength(s_entry->msg))) != SUCCESS) {
       dbg("Drops", "drops: sendTask: send failed\n");
@@ -791,7 +823,7 @@ module IPDispatchP {
     return;
   fail:
     post sendTask();
-    stats.tx_drop++;
+    BLIP_STATS_INCR(stats.tx_drop);
 
     // deallocate the memory associated with this request.
     // other fragments associated with this packet will get dropped.
@@ -818,6 +850,13 @@ module IPDispatchP {
    * layers.
    */
   command error_t IP.send[uint8_t prot](struct split_ip_msg *msg) {
+    msg->hdr.nxt_hdr = prot;
+    return call IP.bareSend[prot](msg, NULL, 0);
+  }
+
+  command error_t IP.bareSend[uint8_t prot](struct split_ip_msg *msg, 
+                              struct ip6_route *route,
+                              int flags) {
     uint16_t payload_length;
 
     if (state != S_RUNNING) {
@@ -827,14 +866,20 @@ module IPDispatchP {
     if (msg->hdr.hlim != 0xff)
       msg->hdr.hlim = call IPRouting.getHopLimit();
 
-    msg->hdr.nxt_hdr = prot;
+    printfUART("sending...\n");
+
     ip_memclr(msg->hdr.vlfc, 4);
     msg->hdr.vlfc[0] = IPV6_VERSION << 4;
 
-    call IPRouting.insertRoutingHeaders(msg);
+    current_local_label++;
+    if (!(flags & IP_NOHEADERS)) {
+      call InternalIPExtension.addHeaders(msg, prot, current_local_label);
+
+      if (route == NULL)
+        route = call IPRouting.insertRoutingHeader(msg);
+    }
                              
     payload_length = msg->data_len;
-
     {
       struct generic_header *cur = msg->headers;
       while (cur != NULL) {
@@ -844,12 +889,14 @@ module IPDispatchP {
     }
 
     msg->hdr.plen = htons(payload_length);
+    printfUART("sending: total length is: %i\n", payload_length);
     
     // okay, so we ought to have a fully setup chain of headers here,
     // so we ought to be able to compress everything into fragments.
     //
 
     {
+      error_t rc = SUCCESS;
       send_info_t  *s_info;
       send_entry_t *s_entry;
       uint8_t frag_len = 1;
@@ -859,20 +906,20 @@ module IPDispatchP {
       progress.offset = 0;
 
       s_info = getSendInfo();
-      if (s_info == NULL) return ERETRY;
+      if (s_info == NULL) {
+        rc = ERETRY;
+        goto cleanup_outer;
+      }
+      s_info->local_flow_label = current_local_label;
 
       // fill in destination information on outgoing fragments.
       sh = (msg->headers != NULL) ? (struct source_header *)msg->headers->hdr.ext : NULL;
-      if (call IPRouting.getNextHop(&msg->hdr, sh, 0x0,
+      if (call IPRouting.getNextHop(&msg->hdr, route, 0x0,
                                     &s_info->policy) != SUCCESS) {
         dbg("Drops", "drops: IP send: getNextHop failed\n");
         goto done;
       }
 
-#ifdef DBG_TRACK_FLOWS
-      dbg_flowid++;
-#endif
-
       //goto done;
       while (frag_len > 0) {
         s_entry  = call SendEntryPool.get();
@@ -890,18 +937,13 @@ module IPDispatchP {
           goto done;
         }
 
-#ifdef DBG_TRACK_FLOWS
-        (call getFlowID(outgoing))->src = TOS_NODE_ID;
-        (call getFlowID(outgoing))->dst = ((uint16_t )msg->hdr.dst_addr[14]) << 8 |
-          (uint16_t)msg->hdr.dst_addr[15];
-        (call getFlowID(outgoing))->id = dbg_flowid;
-        (call getFlowID(outgoing))->seq = 0;
-        (call getFlowID(outgoing))->nxt_hdr = prot;
-#endif
+        // printfUART("getting frag... ");
+        // ip_dump_msg(msg);
 
         frag_len = getNextFrag(msg, &progress, 
                                call Packet.getPayload(outgoing, call Packet.maxPayloadLength()),
                                call Packet.maxPayloadLength());
+        // printfUART("got frag: len: %i\n", frag_len);
         if (frag_len == 0) {
           call FragPool.put(outgoing);
           call SendEntryPool.put(s_entry);
@@ -913,26 +955,30 @@ module IPDispatchP {
         s_entry->info = s_info;
 
         if (call SendQueue.enqueue(s_entry) != SUCCESS) {
-          stats.encfail++;
+          BLIP_STATS_INCR(stats.encfail);
           dbg("Drops", "drops: IP send: enqueue failed\n");
           goto done;
         }
 
         SENDINFO_INCR(s_info);
-        printfUART("enqueue len 0x%x dest: 0x%x retries: 0x%x delay: 0x%x\n",frag_len,
-                   s_info->policy.dest, s_info->policy.retries, s_info->policy.delay);
+//        printfUART("enqueue len 0x%x dest: 0x%x retries: 0x%x delay: 0x%x\n",frag_len,
+//                   s_info->policy.dest, s_info->policy.retries, s_info->policy.delay);
       }
     done:
+      BLIP_STATS_INCR(stats.sent);
       SENDINFO_DECR(s_info);
       post sendTask();
-      return SUCCESS;
+    cleanup_outer:
+      call InternalIPExtension.free();
+
+      return rc;
       
     }
   }
 
-  event void IEEE154Send.sendDone(message_t *msg, error_t error) {
+  event void Ieee154Send.sendDone(message_t *msg, error_t error) {
+    ip_statistics_t stat;
     send_entry_t *s_entry = call SendQueue.head();
-    CHECK_NODE_ID;
 
     radioBusy = FALSE;
 
@@ -974,7 +1020,7 @@ module IPDispatchP {
 
   done:
     s_entry->info->policy.actRetries = call PacketLink.getRetries(msg);
-    call IPRouting.reportTransmission(&s_entry->info->policy);
+    signal IPExtensions.reportTransmission(s_entry->info->local_flow_label, &s_entry->info->policy);
     // kill off any pending fragments
     SENDINFO_DECR(s_entry->info);
     call FragPool.put(s_entry->msg);
@@ -982,9 +1028,20 @@ module IPDispatchP {
     call SendQueue.dequeue();
 
     post sendTask();
+    call Statistics.get(&stat);
   }
 
-
+  command struct tlv_hdr *IPExtensions.findTlv(struct ip6_ext *ext, uint8_t tlv_val) {
+    int len = ext->len - sizeof(struct ip6_ext);
+    struct tlv_hdr *tlv = (struct tlv_hdr *)(ext + 1);
+    while (len > 0) {
+      if (tlv->type == tlv_val) return tlv;
+      if (tlv->len == 0) return NULL;
+      tlv = (struct tlv_hdr *)(((uint8_t *)tlv) + tlv->len);
+      len -= tlv->len;
+    }
+    return NULL;
+  }
 
   event void ICMP.solicitationDone() {
 
@@ -994,12 +1051,21 @@ module IPDispatchP {
    * Statistics interface
    */
   command void Statistics.get(ip_statistics_t *statistics) {
+#ifdef BLIP_STATS_IP_MEM
     stats.fragpool = call FragPool.size();
     stats.sendinfo = call SendInfoPool.size();
     stats.sendentry= call SendEntryPool.size();
     stats.sndqueue = call SendQueue.size();
     stats.heapfree = ip_malloc_freespace();
+    printfUART("frag: %i sendinfo: %i sendentry: %i sendqueue: %i heap: %i\n",
+               stats.fragpool,
+               stats.sendinfo,
+               stats.sendentry,
+               stats.sndqueue,
+               stats.heapfree);
+#endif
     ip_memcpy(statistics, &stats, sizeof(ip_statistics_t));
+
   }
 
   command void Statistics.clear() {
diff --git a/tos/lib/net/blip/IPExtensionP.nc b/tos/lib/net/blip/IPExtensionP.nc
new file mode 100644 (file)
index 0000000..415e868
--- /dev/null
@@ -0,0 +1,144 @@
+
+/* 
+ * Provides various functions for dealing with IP extension header
+ * processing
+
+ *
+ */
+
+#include <ip_malloc.h>
+
+module IPExtensionP {
+  provides {
+    // for inserting destination and hop-by-hop headers on outgoing packets.
+    // routing headers are handled through the IPRouting interface
+    interface Init;
+    interface TLVHeader as HopByHopExt[uint8_t client];
+    interface TLVHeader as DestinationExt[uint8_t client];
+    interface InternalIPExtension;
+  }
+} implementation {
+
+  struct generic_header *ext_dest, *ext_hop;
+
+  command error_t Init.init() {
+    ext_hop = ext_dest = NULL;
+    return SUCCESS;
+  }
+
+  struct tlv_hdr *destopt_get(int i, int nxt_hdr, struct ip6_hdr *iph) {
+    return signal DestinationExt.getHeader[i](0, nxt_hdr, iph);
+  }
+  struct tlv_hdr *hopopt_get(struct ip6_hdr *iph, int i) { //, uint8_t nxt_hdr) {
+    // return signal HopByHopExt.getHeader[i](label, iph, nxt_hdr);
+    return NULL;
+  }
+
+  /* build up a sequence of TLV headers for hop-by-hop or
+     destination only extension headers */
+  struct generic_header *buildTLVHdr(struct split_ip_msg *msg,
+                                     int which, 
+                                     int n, int nxt_hdr) {
+    // allocate generic headers for all the possible TLV-encoded
+    // headers we might get
+    int i;
+    uint8_t *buf = ip_malloc(sizeof(struct ip6_ext) + (sizeof(struct generic_header) * (n + 1)));
+    struct ip6_ext *real_hdr;
+    struct generic_header *ghdrs;
+    if (buf == NULL) return NULL;
+    ghdrs = (struct generic_header *)buf;
+    real_hdr = (struct ip6_ext *)(ghdrs + (n + 1));
+
+
+    real_hdr->len = sizeof(struct ip6_ext);
+
+    ghdrs[0].len = sizeof(struct ip6_ext);
+    ghdrs[0].hdr.data = (uint8_t *)real_hdr;
+    ghdrs[0].next = msg->headers;
+
+    for (i = 0; i < n; i++) {
+      struct tlv_hdr *this_hdr;
+      if (which == 0) {
+        printfUART("adding destination idx %i\n", i);
+        this_hdr = signal DestinationExt.getHeader[i](0, nxt_hdr, &msg->hdr);
+      } else {
+        this_hdr = signal HopByHopExt.getHeader[i](0, nxt_hdr, &msg->hdr);
+      }
+
+      printfUART("buildTLV: got %p\n", this_hdr);
+      if (this_hdr == NULL) continue;
+
+      real_hdr->len += this_hdr->len;
+      ghdrs[i+1].len = this_hdr->len;
+      ghdrs[i+1].hdr.data = (uint8_t *)this_hdr;
+      ghdrs[i].next = &ghdrs[i+1];
+      ghdrs[i+1].next = msg->headers;
+    }
+    if (real_hdr->len == sizeof(struct ip6_ext)) {
+      ip_free(buf);
+      return NULL;
+    } else {
+      real_hdr->nxt_hdr = msg->hdr.nxt_hdr;
+      msg->headers = ghdrs;
+      return ghdrs;
+    }
+  }
+
+  command void InternalIPExtension.addHeaders(struct split_ip_msg *msg, 
+                                              uint8_t nxt_hdr,
+                                              uint16_t label) {
+
+    ext_dest = ext_hop = NULL;
+    msg->hdr.nxt_hdr = nxt_hdr;
+    ext_dest = buildTLVHdr(msg, 0, 1, nxt_hdr);
+    if (ext_dest != NULL) msg->hdr.nxt_hdr = IPV6_DEST;
+
+    ext_hop = buildTLVHdr(msg, 1, 1, msg->hdr.nxt_hdr);
+    if (ext_hop != NULL) msg->hdr.nxt_hdr = IPV6_HOP;
+  }
+
+  command void InternalIPExtension.free() {
+    if (ext_dest != NULL) ip_free(ext_dest);
+    if (ext_hop  != NULL) ip_free(ext_hop);
+    ext_dest = ext_hop = NULL;
+    // signal HopByHopExt.free[0]();
+    // signal DestinationExt.free[0]();
+  }
+
+#if 0
+  void ip_dump_msg(struct split_ip_msg *msg) {
+    struct generic_header *cur = msg->headers;
+    int i;
+    printfUART("DUMPING IP PACKET\n ");
+    for (i = 0; i < sizeof(struct ip6_hdr); i++)
+      printfUART("0x%x ", ((uint8_t *)&msg->hdr)[i]);
+    printfUART("\n");
+
+    while (cur != NULL) {
+      printfUART(" header [%i]: ", cur->len);
+      for (i = 0; i < cur->len; i++) 
+        printfUART("0x%x ", cur->hdr.data[i]);
+      printfUART("\n");
+      cur = cur->next;
+    }
+
+    printfUART("data [%i]: ", msg->data_len);
+    for (i = 0; i < msg->data_len; i++) 
+      printfUART("0x%x ", ((uint8_t *)msg->data)[i]);
+    printfUART("\n\n");
+  }
+#endif
+
+  default event struct tlv_hdr *DestinationExt.getHeader[uint8_t i](int label,int nxt_hdr,
+                                                                   struct ip6_hdr *msg) {
+    printfUART("default dest handler?\n");
+    return NULL;
+  }
+
+  default event struct tlv_hdr *HopByHopExt.getHeader[uint8_t i](int label,int nxt_hdr,
+                                                                   struct ip6_hdr *msg) {
+    return NULL;
+  }
+
+
+}
diff --git a/tos/lib/net/blip/IPExtensionsP.nc b/tos/lib/net/blip/IPExtensionsP.nc
new file mode 100644 (file)
index 0000000..d82322c
--- /dev/null
@@ -0,0 +1,33 @@
+
+module IPExtensionsP {
+  provides interface IPExtensions[uint8_t client];
+  uses interface IPExtensions;
+} implementation {
+
+
+
+
+  command struct tlv_hdr *findTlv(struct ip6_ext *ext, uint8_t tlv) {
+
+  }
+
+  event void handleExtensions(uint8_t label,
+                              struct ip6_hdr *iph,
+                              struct ip6_ext *hop,
+                              struct ip6_ext *dst,
+                              struct ip6_route *route,
+                              uint8_t nxt_hdr) {
+
+  }
+
+
+
+
+  /*
+   * will be called once for each fragment when sending or forwarding
+   */
+  event void reportTransmission(uint8_t label, send_policy_t *send) {
+
+  }
+
+}
index 83ade73006d86ad52e62012ddbd712aab1da811a..e2780fdcb8a7657ede1dc41b24ad8f489a7da899 100644 (file)
@@ -26,6 +26,9 @@
 module IPRoutingP {
   provides interface IPRouting;
   provides interface Statistics<route_statistics_t>;
+
+  uses interface IPExtensions;
+  uses interface TLVHeader as DestinationExt;
   uses interface ICMP;
   uses interface Boot;
   uses interface IPAddress;
@@ -40,6 +43,11 @@ module IPRoutingP {
 
 } implementation {
 
+#ifdef PRINTFUART_ENABLED
+/* #undef dbg */
+/* #define dbg(X, fmt, args...)  printfUART(fmt, ## args) */
+#endif
+
   enum {
     SHORT_EPOCH = 0,
     LONG_EPOCH = 1,
@@ -49,6 +57,7 @@ module IPRoutingP {
   //route_statistics_t stats;
   uint16_t last_qual;
   uint8_t last_hops;
+  uint16_t reportSeqno;
 
   uint8_t num_low_neigh;
 
@@ -62,6 +71,11 @@ module IPRoutingP {
   uint32_t traffic_interval;
   bool traffic_sent;
 
+#ifdef CENTRALIZED_ROUTING
+  // this is the routing table (k parents);
+  struct flow_path full_path_entries[N_FULL_PATH_ENTRIES];
+  struct flow_entry flow_table[N_FLOW_ENT];
+#endif
   struct neigh_entry neigh_table[N_NEIGH];
 
   void printTable();
@@ -81,12 +95,15 @@ module IPRoutingP {
   }
 
   void clearStats(struct neigh_entry *r) {
+    ip_memclr((uint8_t *)r->stats, sizeof(struct epoch_stats) * N_EPOCHS);
+#if 0
     int j;
     for (j = 0; j < N_EPOCHS; j++) {
       r->stats[j].total   = 0;
       r->stats[j].success = 0;
       r->stats[j].receptions = 0;
     }
+#endif
   }
 
   void clearEpoch(uint8_t target_epoch) {
@@ -98,12 +115,6 @@ module IPRoutingP {
     }
   }
 
-  cmpr_ip6_addr_t shortenAddr(ip6_addr_t addr) {
-    cmpr_ip6_addr_t shortAddr;
-    ip_memcpy(&shortAddr, &addr[14],2);
-    return shortAddr;
-  } 
-
   void restartTrafficGen() {
     traffic_interval = TGEN_BASE_TIME;
     // jitter the period by 10% to prevent synchronization
@@ -117,6 +128,7 @@ module IPRoutingP {
   event void TrafficGenTimer.fired() {
     struct split_ip_msg *msg;
     if (traffic_sent) goto done;
+    traffic_sent = FALSE;
     msg = (struct split_ip_msg *)ip_malloc(sizeof(struct split_ip_msg));
     if (msg == NULL) goto done;
 
@@ -154,6 +166,13 @@ module IPRoutingP {
       clearStats(&neigh_table[i]);
     }
 
+#ifdef CENTRALIZED_ROUTING
+    call IPRouting.clearFlows();
+    for (i = 0; i < N_FULL_PATH_ENTRIES; i++) {
+      full_path_entries[i].path_len = 0;
+    }
+#endif
+
     // current_epoch = 0;
     soliciting = FALSE;
     //reRouting = FALSE;
@@ -164,6 +183,8 @@ module IPRoutingP {
     last_qual = 0xffff;
     last_hops = 0xff;
     num_low_neigh = 0;
+    reportSeqno = call Random.rand16();
+
     call Statistics.clear();
     call SortTimer.startPeriodic(1024L * 60);
 
@@ -182,6 +203,82 @@ module IPRoutingP {
             || cmpPfx(multicast_prefix, hdr->ip6_dst.s6_addr));
   }
 
+#ifdef CENTRALIZED_ROUTING
+  void print_rinstall(struct rinstall_header *rih) {
+    uint8_t i;
+    dbg("Install", "rinstall header:\n");
+    dbg_clear("Install", "\tnxt_header\t0x%x\n", rih->ext.nxt_hdr);
+    dbg_clear("Install", "\tlen\t0x%x\n", rih->ext.len);
+    dbg_clear("Install", "\tflags\t0x%x\n", rih->flags);
+    dbg_clear("Install", "\tmatch_src\t0x%x\n", ntohs(rih->match.src));
+    dbg_clear("Install", "\tmatch_prev\t0x%x\n", ntohs(rih->match.prev_hop));
+    dbg_clear("Install", "\tmatch_dest\t0x%x\n", ntohs(rih->match.dest));
+    dbg_clear("Install", "\tpath_len\t0x%x\n", rih->path_len);
+    dbg_clear("Install", "\tcurrent\t0x%x\n", rih->current);
+    for(i = 0; i < rih->path_len; i++)
+      dbg_clear("Install", "\thop[%u]\t0x%x\n", i, ntohs(rih->path[i]));
+  }
+
+  struct flow_entry *getFlowEntry(cmpr_ip6_addr_t a) {
+    int i;
+    dbg("IPRouting", "getFlowEntry called for 0x%x\n", a);
+    for (i = 0; i < N_FLOW_ENT; i++) {
+      if (IS_VALID_SLOT(&flow_table[i]) && flow_table[i].match.dest == a) {
+        dbg("IPRouting", "Match found in slot [%u]\n", i);
+        return &(flow_table[i]);
+      }
+    }
+    return NULL;
+  }
+
+  //  Add this extra layer of indirection to allow us to do
+  //   more extensive 5-tuple lookups.
+  struct flow_entry *getFlowEntry_Header(struct ip6_hdr* hdr) {
+   if (hdr == NULL)
+     //return &flow_table[T_DEF_PARENT_SLOT]; 
+     return NULL;
+   return getFlowEntry(ntohs(hdr->ip6_dst.s6_addr16[7]));
+  }
+
+  struct flow_entry *getFlowEntry_Match(struct flow_match *match) {
+    dbg("IPRouting", "getFlowEntry_Match called for 0x%x\n", ntohs(match->dest));
+    return getFlowEntry(ntohs(match->dest));
+  }
+
+  struct flow_entry *getNewEntry(struct flow_match *match) {
+    uint8_t i;
+    uint8_t place = N_FLOW_ENT;
+    for (i = 0; i < N_FLOW_ENT; i++) {
+      if (!IS_VALID_SLOT(&(flow_table[i]))) {
+        flow_table[i].match.src = ntohs(match->src);
+        flow_table[i].match.dest = ntohs(match->dest);
+
+        dbg("IPRouting", "New flow entry slot provided in slot [%u]\n", i);
+        return &(flow_table[i]);
+      }
+      if (flow_table[i].count == (N_FLOW_ENT - 1))
+        place = i;
+    }
+    if (place == N_FLOW_ENT) {
+      dbg("IPRouting", "The correct value of place doesn't exist!!\n");
+      return NULL;
+    }
+
+    dbg("IPRouting", "Conflicted flow entry slot. Dest: 0x%x, slot 0x%x\n", flow_table[place].match.dest, place);
+    for (i = 0; i < N_FLOW_CHOICES; i++) {
+      if(IS_VALID_ENTRY(flow_table[place].entries[i])) {
+        SET_INVALID_ENTRY(flow_table[place].entries[i]);
+        if (IS_FULL_TYPE(flow_table[place].entries[i]))
+          freeFullPath(flow_table[place].entries[i].pathE);
+      }
+    }
+    SET_INVALID_SLOT(&(flow_table[place]));
+    updateFlowCounts(&(flow_table[place]));
+    ip_memclr((uint8_t *)(&(flow_table[place])), sizeof(struct flow_entry));
+    return &(flow_table[place]);
+  }
+#endif
 
   struct neigh_entry *getNeighEntry(cmpr_ip6_addr_t a) {
     int i;
@@ -192,7 +289,332 @@ module IPRoutingP {
     return NULL;
   }
 
+#ifdef CENTRALIZED_ROUTING
+  cmpr_ip6_addr_t nextHop_Flow(struct f_entry *fEntry) {
+    if (IS_VALID_ENTRY(*fEntry)) {
+      if (IS_HOP_TYPE(*fEntry)) return fEntry->nextHop;
+      return fEntry->pathE->path[0];
+    }
+    return T_INVAL_NEIGH;
+  }
+
+  struct flow_path *getNewFlowPath() {
+    uint8_t i;
+    for (i = 0; i < N_FULL_PATH_ENTRIES; i++) {
+      if (full_path_entries[i].path_len == 0)
+        return &(full_path_entries[i]);
+    }
+    return NULL;
+  }
+  
+  error_t freeFullPath(struct flow_path* path) {
+    path->path_len = 0;
+    return SUCCESS;
+  }
+
+  void reverseFlowMatch(struct rinstall_header *orig, 
+                        struct flow_match *reverse,
+                        struct ip6_hdr *iph) {
+
+    printfUART("reverseFlowMatch: %i %i\n", ntohs(iph->ip6_dst.s6_addr16[7]),
+               ntohs(iph->ip6_src.s6_addr16[7]));
+
+    if (orig->match.src == htons(T_INVAL_NEIGH))
+      reverse->src = htons(T_INVAL_NEIGH);
+    else
+      reverse->src = iph->ip6_src.s6_addr16[7];
+
+    if (orig->match.dest == htons(T_INVAL_NEIGH)) // Shouldn't happen
+      reverse->dest = htons(T_INVAL_NEIGH);
+    else
+      reverse->dest = iph->ip6_dst.s6_addr16[7];
+  }  
+  
+  /*
+   * Function takes the set of choices within a single flow_entry slot and arranges
+   *  them in order of addition/modification.
+   *
+   * @entry_index - The index of the entry that is being uninstalled, or moved to
+   *  the top of the stack. (Set this to N_FLOW_CHOICES to indicate that a new
+   *  entry is being installed).
+   * @install - Whether an entry is being installed or moved to the top of the stack
+   *
+   * TODO: Implement explicit flow entry removal
+   */
+  void sortFlowEntries(struct flow_entry *target, uint8_t entry_index, bool install) {
+    struct f_entry f_temp;
+    uint8_t i;
+   
+    dbg("IPRouting", "sortFlowEntries: Index: 0x%x, Install: 0x%x\n", entry_index, install);
+
+    if (install && (entry_index < N_FLOW_CHOICES)) {
+      ip_memcpy(&f_temp, &(target->entries[entry_index]), sizeof(struct f_entry));
+    }
+
+    for (i = ((entry_index < N_FLOW_CHOICES)? (entry_index):(N_FLOW_CHOICES - 1)); i > 0; i--) {
+      ip_memcpy(&(target->entries[i]), &(target->entries[i-1]), sizeof(struct f_entry));
+    }
+
+    if (install && (entry_index < N_FLOW_CHOICES))
+      ip_memcpy(&(target->entries[0]), &f_temp, sizeof(struct f_entry));
+    else
+      ip_memclr((uint8_t *)(&(target->entries[0])), sizeof(struct f_entry));
+  }
+
+  void updateFlowCounts(struct flow_entry *target) {
+    uint8_t i;
+    if (target == NULL) return;
+    dbg("IPRouting", "updateFlowCounts\n");
+    
+    // Just used or installed something
+    if (IS_VALID_SLOT(target)) {
+      for(i = 0; i < N_FLOW_ENT; i++) {
+        if (!(IS_VALID_SLOT(&(flow_table[i])))) continue;
+        if (flow_table[i].count < target->count) flow_table[i].count++;
+      }
+      target->count = 0;
+    } else {
+      for (i = 0; i < N_FLOW_ENT; i++) {
+        if (!(IS_VALID_SLOT(&(flow_table[i])))) continue;
+        if (flow_table[i].count > target->count) flow_table[i].count--;
+      }
+      target->count = N_FLOW_ENT;
+    }
+  }
+
+  // Helper Functions
+  error_t installEntry(struct ip6_hdr *iph, struct rinstall_header *rih, struct ip6_route *route) {
+    struct flow_entry *entry;
+    struct flow_match reverse_match;
+    uint16_t current, path_len, 
+      reverse = 0,
+      fullPath = (rih->flags & HYDRO_INSTALL_METHOD_MASK) == HYDRO_METHOD_SOURCE;
+    cmpr_ip6_addr_t *path;
+    uint8_t i;
+
+    // if this is a METHOD_SOURCE install, and the path is carried in
+    // the routing header we must be on the far end of the install,
+    // and so need to reverse everything.
+
+
+    if (fullPath && rih->path_len == 0) reverse = 1;
+    if (!fullPath) {
+      printfUART("not fp, route: %p  rip: %i\n", route, rih->path_len);
+      reverse = rih->flags & HYDRO_INSTALL_REVERSE;
+      if (!reverse && route && route->segs_remain == 0 && rih->path_len == 0) return SUCCESS;
+      if (reverse && rih->path_len > 0) return SUCCESS;
+    }
+
+    printfUART("install rev: %i fp: %i\n", reverse, fullPath)
+
+    if (rih->path_len == 0) {
+      if (route == NULL) return FAIL;
+      current = ROUTE_NENTRIES(route) - route->segs_remain;
+      path = route->hops;
+      path_len = ROUTE_NENTRIES(route);
+    } else {
+      current = reverse ? rih->path_len - 1 : 0;
+      path = rih->path;
+      path_len = rih->path_len;
+    }
+    
+    dbg("Install", "installEntry: flags: 0x%x\n", rih->flags);
+    
+    if (!reverse && 
+        ((entry = getFlowEntry_Match(&(rih->match))) == NULL) && 
+        ((entry = getNewEntry(&(rih->match))) == NULL)) {
+      dbg("Install", "installEntry: forward path has no match and no room in flow table\n");
+      return FAIL;
+    } else if (reverse) {
+      reverseFlowMatch(rih, &reverse_match, iph);
+      if (((entry = getFlowEntry_Match(&(reverse_match))) == NULL) && 
+          ((entry = getNewEntry(&(reverse_match))) == NULL)) {
+        dbg("Install", "installEntry: reverse path has no match and no room in flow table\n");
+        return FAIL;
+       }
+    }
+
+    //Inefficient duplicate detection
+    for (i = 0; i < N_FLOW_CHOICES; i++) {
+      printfUART("checking dup %i %i\n", nextHop_Flow(&entry->entries[i]),
+                 ntohs(path[reverse ? (current - 1) : current]));
+      if (IS_VALID_ENTRY(entry->entries[i]) && 
+          (nextHop_Flow(&entry->entries[i]) == 
+           ntohs(path[reverse ? (current - 1) : current])) && 
+          !fullPath) { 
+        dbg("Install", "This choice already exists in flow table!\n");
+        // Since order indicates order of arrival, need to move this one up higher
+        if (i != 0) {
+          sortFlowEntries(entry, i, TRUE);
+        }
+        return SUCCESS;
+      }
+      if (IS_VALID_ENTRY(entry->entries[i]) && IS_FULL_TYPE(entry->entries[i])) {
+        dbg("Install", "Removing exiting source choice\n");
+        entry->entries[0].pathE->path_len = 0;
+        SET_INVALID_ENTRY(entry->entries[0]);        
+      }
+    }
+    
+
+    if (IS_VALID_ENTRY(entry->entries[0]))
+      sortFlowEntries(entry, N_FLOW_CHOICES, TRUE);
+    if (fullPath) {
+      if ((entry->entries[0].pathE = getNewFlowPath()) == NULL) {
+        dbg("Install", "No room available for new full path entry\n");
+        return FAIL;
+      }
+      for (i = 0; i < path_len; i++) {
+        entry->entries[0].pathE->path[i] = ntohs(path[(reverse ? (path_len - i - 1): i)]);
+        dbg("Install", "Put node 0x%x as hop [%u]\n", entry->entries[0].pathE->path[i], (i));
+      }
+      entry->entries[0].pathE->path_len = path_len;
+    } else {
+      entry->entries[0].nextHop = ntohs(path[(reverse? (current - 1) : current)]);
+      dbg("Install", "Put node 0x%x as next hop\n", entry->entries[0].nextHop);
+    }
+    SET_VALID_ENTRY((entry->entries[0]));
+    SET_VALID_SLOT(entry);
+    (fullPath? (SET_FULL_TYPE(entry->entries[0])) : (SET_HOP_TYPE(entry->entries[0])));
+   
+    updateFlowCounts(entry); 
+    printTable();
+    return SUCCESS;
+  }
+
+  error_t uninstallEntry(struct rinstall_header *rih) {
+    struct flow_entry *entry;
+    //struct neigh_entry *neigh;
+    uint8_t i;
+
+    // don't support reverse install
+    if (rih->flags & HYDRO_INSTALL_REVERSE) return FAIL;
+    // only work for source installs
+    if ((rih->flags & HYDRO_INSTALL_METHOD_MASK) != HYDRO_METHOD_SOURCE) return FAIL;
+    if ((entry = getFlowEntry_Match(&(rih->match))) == NULL)
+      return FAIL;
+    
+    for (i = 0; i < N_FLOW_CHOICES; i++) {
+      if (IS_VALID_ENTRY(entry->entries[i])) {
+        SET_INVALID_ENTRY(entry->entries[i]);
+        SET_INVALID_SLOT(entry);
+        freeFullPath(entry->entries[i].pathE);
+      }
+    }
+    return SUCCESS;
+  }
+#endif
+
+
+  event void IPExtensions.handleExtensions(uint8_t label,
+                                           struct ip6_hdr *iph,
+                                           struct ip6_ext *hop,
+                                           struct ip6_ext *dst,
+                                           struct ip6_route *route,
+                                           uint8_t nxt_hdr) {
+#ifdef CENTRALIZED_ROUTING
+    struct tlv_hdr *tlv = NULL;
+    struct rinstall_header *rih;
+    uint8_t method;
+    bool forMe = call IPRouting.isForMe(iph), isHop = FALSE;
+
+    printfUART("handling extension header!\n");
+
+    if (dst != NULL) tlv = call IPExtensions.findTlv(dst, TLV_TYPE_INSTALL);
+    if (tlv == NULL && hop != NULL) { tlv = call IPExtensions.findTlv(hop, TLV_TYPE_INSTALL); isHop = TRUE; }
+    if (tlv == NULL) return;
+    rih = (struct rinstall_header *)(tlv + 1);
+    // first, install the entry if it's for me
+    method = (rih->flags & HYDRO_INSTALL_METHOD_MASK);
+
+
+    if (!forMe) {
+      if (method == HYDRO_METHOD_HOP    && !isHop) return;
+      if (method == HYDRO_METHOD_SOURCE) return;
+    }
+    if (!(rih->flags & HYDRO_INSTALL_UNINSTALL_MASK)) {
+      installEntry(iph, rih, route);
+    } else {
+      // uninstall only returns
+      uninstallEntry(rih);
+      return;
+    }
+
+    if (method == HYDRO_METHOD_HOP && (rih->flags & HYDRO_INSTALL_REVERSE)) {
+      // a little clunky, perhaps, but this is sort of how
+      // installEntry expects things to work.
+      rih->flags &= ~HYDRO_INSTALL_REVERSE;
+      installEntry(iph, rih, route);
+      rih->flags |= HYDRO_INSTALL_REVERSE;
+    }
 
+    if ( (forMe && rih->path_len > 0 && rih->path_len < 10) && 
+
+         // if it's a source install, we don't need to generate a new
+         // message unless the command is for us to also install the reverse path.
+         ((method == HYDRO_METHOD_SOURCE &&
+           rih->flags & HYDRO_INSTALL_REVERSE) ||
+          // if it's a hop-by-hop install, we always need to generate a
+          // new message to do the install.  however, only want this to
+          // happen once, and since along the path the route install will be
+          // carried as a hop-by-hop options, this check is sufficient.
+          (method == HYDRO_METHOD_HOP && !isHop))) {
+      
+      // in either case the actual route to install must be in the
+      // route install header
+      uint16_t plen = sizeof(struct ip6_route) + (sizeof(cmpr_ip6_addr_t) * rih->path_len) +
+        sizeof(struct ip6_ext) + sizeof(struct tlv_hdr) + 
+        sizeof(struct rinstall_header);
+      struct uint8_t *buf = ip_malloc(sizeof(struct split_ip_msg) + plen);
+      struct split_ip_msg *ipmsg;
+      struct ip6_ext   *newext;
+      struct tlv_hdr   *newtlv;
+      struct rinstall_header *newrih;
+      struct ip6_route *iproute;
+      printfUART("installing reverse path to 0x%x\n", rih->match.dest);
+
+      if (buf == NULL) return;
+      ip_memclr((void *)buf, sizeof(struct split_ip_msg) + plen);
+
+      ipmsg = (struct split_ip_msg *)buf;
+      newext = (struct ip6_ext *)(ipmsg + 1);
+      newtlv = (struct tlv_hdr *)(newext + 1);
+      newrih = (struct rinstall_header *)(newtlv + 1);
+      iproute = (struct ip6_route *)(newrih + 1);
+      
+      ipmsg->hdr.nxt_hdr = (method == HYDRO_METHOD_SOURCE) ? IPV6_DEST : IPV6_HOP;
+      ipmsg->hdr.plen = htons(plen);
+      ipmsg->data = (uint8_t *)(ipmsg  + 1);
+      ipmsg->data_len = plen;
+      ipmsg->headers = NULL;
+      call IPAddress.getIPAddr(&ipmsg->hdr.ip6_src);
+      call IPAddress.getIPAddr(&ipmsg->hdr.ip6_dst);
+      ipmsg->hdr.ip6_src.s6_addr16[7] = rih->match.dest;
+
+      newext->nxt_hdr = IPV6_ROUTING;
+      newext->len = sizeof(struct ip6_ext) + sizeof(struct tlv_hdr) + 
+        sizeof(struct rinstall_header);
+      newtlv->type = TLV_TYPE_INSTALL;
+      newtlv->len = sizeof(struct tlv_hdr) + sizeof(struct rinstall_header);
+
+      ip_memcpy(&newrih->match, &rih->match, sizeof(struct flow_match));
+      newrih->flags = rih->flags;
+      newrih->path_len = 0;
+
+      iproute->nxt_hdr = IPV6_NONEXT;
+      iproute->len = sizeof(struct ip6_route) + (sizeof(cmpr_ip6_addr_t) * rih->path_len);
+      iproute->type = IP6ROUTE_TYPE_SOURCE;
+      iproute->segs_remain = rih->path_len;
+      ip_memcpy(iproute->hops, rih->path, sizeof(cmpr_ip6_addr_t) * rih->path_len);
+      
+      call TGenSend.bareSend(ipmsg, iproute, IP_NOHEADERS);
+      ip_free(buf);
+      // we should be all set up now.  
+    }
+#endif
+  }
+
+  
   uint16_t getConfidence(struct neigh_entry *neigh) {
     //uint8_t i;
     uint16_t conf = 0;
@@ -257,6 +679,32 @@ module IPRoutingP {
           getLinkCost(&(neigh_table[i])), neigh_table[i].linkEstimate, 
           getMetric(&(neigh_table[i])));
     }
+#ifdef CENTRALIZED_ROUTING
+    dbg("Table", "------ Valid Flow Tables -------\n");
+    dbg("Table", "valid\ttype\tnext\n");
+    for (j = 0; j < N_FLOW_ENT; j++) {
+      if (!(IS_VALID_SLOT(&(flow_table[j])))) continue;
+      dbg("Table", "\n -- Flow Table Slot [%u] , Dest: [0x%x] , Count: [0x%x] --\n", 
+          j, flow_table[j].match.dest, flow_table[j].count);
+      for (i = 0; i < N_FLOW_CHOICES; i++) {
+        if (IS_VALID_ENTRY(flow_table[j].entries[i]) && 
+            IS_FULL_TYPE(flow_table[j].entries[i])) {
+          dbg("Table", "0x%x\t0x%x\t", 
+              IS_VALID_ENTRY(flow_table[j].entries[i]), 
+              IS_FULL_TYPE(flow_table[j].entries[i]));
+          for (k = 0; k < flow_table[j].entries[i].pathE->path_len; k++)
+            dbg("Table", "0x%x\t", 
+                flow_table[j].entries[i].pathE->path[k]);
+          dbg("Table", "\n");
+        } else {
+          dbg("Table", "0x%x\t0x%x\t0x%x\n", 
+              IS_VALID_ENTRY(flow_table[j].entries[i]), 
+              IS_FULL_TYPE(flow_table[j].entries[i]),
+              nextHop_Flow(&(flow_table[j].entries[i])));
+        }
+      }
+    }
+#endif
     dbg("Table", "----------------------------------------\n");
 #endif
   }
@@ -271,14 +719,17 @@ module IPRoutingP {
     uint8_t i;
     uint8_t numNeigh = 0;
     uint8_t chosenNeigh;
+    bool useHops = TRUE;
 
     dbg("IPRouting", "Looking for a new default route\n");
-
+  retry:
     for (i = 1; i < N_NEIGH; i++) {
       if (!(IS_NEIGH_VALID(&(neigh_table[i])))) break;
       if (&neigh_table[i] == default_route) continue;
-      if (neigh_table[i].hops < neigh_table[0].hops) 
+      if ((useHops && neigh_table[i].hops < neigh_table[0].hops) ||
+          (!useHops && neigh_table[i].costEstimate < neigh_table[0].costEstimate)) {
         numNeigh++;
+      }
     }
 
     // There exist other neighbors with respectable hop counts
@@ -286,7 +737,8 @@ module IPRoutingP {
       chosenNeigh = (call Random.rand16()) % numNeigh;
       for (i = 1; i < N_NEIGH; i++) {
         if (&neigh_table[i] == default_route) continue;
-        if (neigh_table[i].hops < neigh_table[0].hops) {
+        if ((useHops && neigh_table[i].hops < neigh_table[0].hops)
+            || (!useHops && neigh_table[i].costEstimate < neigh_table[0].costEstimate)) {
           if (chosenNeigh) {
             chosenNeigh--;
           } else {
@@ -298,32 +750,11 @@ module IPRoutingP {
       }
     }
 
-    if (!force) goto done;
-
+    if (!force || !useHops) goto done;
     numNeigh = 0;
-    for (i = 1; i < N_NEIGH; i++) {
-      if (!(IS_NEIGH_VALID(&(neigh_table[i])))) break;
-      if (&neigh_table[i] == default_route) continue;
-      if (neigh_table[i].costEstimate < neigh_table[0].costEstimate)
-        numNeigh++;
-    }
+    useHops = FALSE;
+  goto retry;
 
-    if (numNeigh) {
-      chosenNeigh = (call Random.rand16()) % numNeigh;
-      for (i = 1; i < N_NEIGH; i++) {
-        if (&neigh_table[i] == default_route) continue;
-        //if (neigh_table[i].costEstimate < getMetric(&(neigh_table[0]))) {
-        if (neigh_table[i].costEstimate < neigh_table[0].costEstimate) {
-          if (chosenNeigh) { 
-            chosenNeigh--;
-          } else {
-            default_route = &neigh_table[i];
-            default_route_failures = 0;
-            return;
-          }
-        }
-      }
-    }
   done:
     dbg("IPRouting", "No random route found\n");
     default_route = &neigh_table[0];
@@ -336,33 +767,40 @@ module IPRoutingP {
    *        all-node/all-routers local multicast group.
    *
    */
-  command error_t IPRouting.getNextHop(struct ip6_hdr *hdr, 
-                                       struct source_header *sh,
-                                       hw_addr_t prev_hop,
+  command error_t IPRouting.getNextHop(struct ip6_hdr   *hdr, 
+                                       struct ip6_route *sh,
+                                       ieee154_saddr_t prev_hop,
                                        send_policy_t *ret) {
     
     int i;
+#ifdef CENTRALIZED_ROUTING
+    struct flow_entry *r = getFlowEntry_Header(hdr);
+#endif
     prev_hop = 0;
-    ret->retries = 10;
+    ret->retries = N_RETRIES;;
     ret->delay = 30;
     ret->current = 0;
     ret->nchoices = 0;
  
+/*     printfUART("determining next hop for message bound to: 0x%x (sh: %p)\n",  */
+/*                ntohs(hdr->ip6_dst.s6_addr16[7]), sh); */
+
+    if (sh != NULL) {
+      printfUART(" type: 0x%x, next hop: 0x%x, remain: 0x%x\n",
+          sh->type, ntohs(sh->hops[ROUTE_NENTRIES(sh) - sh->segs_remain]), sh->segs_remain);
+    }
+
 
     // we only use the address in the source header if the record option is not used
     // otherwise, we use normal routing.
-    if (hdr->nxt_hdr == NXTHDR_SOURCE && 
-        (sh->dispatch & IP_EXT_SOURCE_RECORD_MASK) != IP_EXT_SOURCE_RECORD && 
-        (sh->dispatch & IP_EXT_SOURCE_INVAL) != IP_EXT_SOURCE_INVAL) {
+    if (sh != NULL && ((sh->type & ~IP6ROUTE_FLAG_MASK) == IP6ROUTE_TYPE_SOURCE)) {
       // if it's source routed, grab the next address out of the header.
 
-      // if (sh->current == sh->nentries) return FAIL;
 
-      ret->dest[0] = ntohs(sh->hops[sh->current]);
-      ret->nchoices = 1;
+      if (sh->segs_remain == 0) return FAIL;
 
-      dbg("IPRouting", "source dispatch: 0x%x, next hop: 0x%x, current: 0x%x\n", 
-                 sh->dispatch, ntohs(sh->hops[sh->current]), sh->current);
+      ret->dest[0] = ntohs(sh->hops[ROUTE_NENTRIES(sh) - sh->segs_remain]);
+      ret->nchoices = 1;
 
     } else if (hdr->ip6_dst.s6_addr16[0] == htons(0xff02)) {
       //hdr->dst_addr[0] == 0xff && (hdr->dst_addr[1] & 0xf) == 0x2) {
@@ -377,17 +815,41 @@ module IPRoutingP {
       ret->nchoices = 1;
       return SUCCESS; // Currently only want one choice for broadcast
     } 
-      //     if (getNeighEntry(ntohs(shortenAddr(hdr->dst_addr))) != NULL) {
-      //       dbg("IPRouting", "Directly adding next hop of dest: 0x%x\n", ntohs(shortenAddr(hdr->dst_addr)));
-      //       ret->dest[ret->nchoices++] = ntohs(shortenAddr(hdr->dst_addr));
-      //     }
-    
+
+    if (getNeighEntry(ntohs(hdr->ip6_dst.s6_addr16[7])) != NULL) {
+        dbg("IPRouting", "Directly adding next hop of dest: 0x%x\n", ntohs(hdr->ip6_dst.s6_addr16[7]));
+        ret->dest[ret->nchoices++] = ntohs(hdr->ip6_dst.s6_addr16[7]);
+    }
     
+#ifdef CENTRALIZED_ROUTING
+    if (r != NULL)
+      updateFlowCounts(r);
+     
+    for (i = 0; i < N_FLOW_CHOICES; i++) {
+      ieee154_saddr_t next_choice;
+      if (r == NULL || 
+          !IS_VALID_ENTRY(r->entries[i]) || 
+          (IS_FULL_TYPE(r->entries[i]) && 
+           r->entries[i].pathE->path_len > 1)) break;
+      next_choice = nextHop_Flow(&(r->entries[i]));
+      if (next_choice != prev_hop) {
+        ret->dest[ret->nchoices++] = next_choice;
+        dbg("Install", "Match: Neighbor 0x%x provided as choice 0x%x\n", 
+            ret->dest[i], ret->nchoices - 1);
+      }
+    }
+#endif
+
     //dbg("IPRouting", "flags: 0x%x neigh: 0x%x\n", r->flags, r->neighbor);
     if (IS_NEIGH_VALID(default_route) && prev_hop != default_route->neighbor) {
       ret->dest[ret->nchoices++] = default_route->neighbor;
     } else {
       dbg("IPRouting", "Invalid default route... quitting\n");
+      /*
+       * if we failed because the default route is invalid, we want to
+       * trigger a routing update whenever we manage to reattach.
+       */
+      traffic_sent = FALSE;
       return FAIL;
     }
     i = 0;
@@ -441,7 +903,7 @@ module IPRoutingP {
    *         and Link estimate is lower by at least LQI_DIFF_THRESH
    * 5) Make sure to update the receptions statistic
    */ 
-  command void IPRouting.reportAdvertisement(hw_addr_t neigh, uint8_t hops, 
+  command void IPRouting.reportAdvertisement(ieee154_saddr_t neigh, uint8_t hops, 
                                              uint8_t lqi, uint16_t cost) {
     //int i, place = N_NEIGH;
     //bool mustInsert = FALSE, exists = FALSE;
@@ -532,7 +994,7 @@ module IPRoutingP {
    *
    * Updates the link estimate, as well as the number of receptions
    */
-  command void IPRouting.reportReception(hw_addr_t neigh, uint8_t lqi) {
+  command void IPRouting.reportReception(ieee154_saddr_t neigh, uint8_t lqi) {
     struct neigh_entry *e = getNeighEntry(neigh);
     dbg("IPRouting", "Packet received from 0x%x lqi: %u\n", neigh, lqi);
     //if (e == NULL) e = addNeighEntry(neigh);
@@ -550,7 +1012,7 @@ module IPRoutingP {
 
   // Updates success (and failure) statistics
   // Also needs to reroute if the number of failures hits the threshold 
-  command void IPRouting.reportTransmission(send_policy_t *policy) {
+  event void IPExtensions.reportTransmission(uint8_t label, send_policy_t *policy) {
     int i;
     struct neigh_entry *e = NULL;
     
@@ -562,8 +1024,8 @@ module IPRoutingP {
     //   a) It has a lower path cost and higher confidence than the above entry
     //   b) It has a similar path cost and confidence above a threshold (CONF_PROM_THRESHOLD)
     //  5. If we have had too many consecutive losses (MAX_CONSEC_FAILURES) toggle ReRouting
-    if (policy->dest[0] != HW_BROADCAST_ADDR) {
-      // stats.messages++;
+    if (policy->dest[0] != IEEE154_BROADCAST_ADDR) {
+      // BLIP_STATS_INCR(stats.messages);
       dbg("IPRouting", "reportTransmission: current: 0x%x, nchoices: 0x%x, retries: 0x%x\n", 
                  policy->current, policy->nchoices, policy->actRetries); 
 
@@ -630,38 +1092,35 @@ module IPRoutingP {
     return (IS_NEIGH_VALID(&(neigh_table[0])));
   }
 
-  void insertSourceHeader(struct split_ip_msg *msg, struct flow_entry *entry) {
+  struct ip6_route *insertSourceHeader(struct split_ip_msg *msg, struct flow_entry *entry) {
     // these actually need to be static
-    static uint8_t source_buf[sizeof(struct source_header) + MAX_PATH_LENGTH * sizeof(uint16_t)];
+    static uint8_t source_buf[sizeof(struct ip6_route) + MAX_PATH_LENGTH * sizeof(uint16_t)];
     static struct generic_header g_sh;
-    struct source_header *sh = (struct source_header *)source_buf;
+    struct ip6_route *sh = (struct ip6_route *)source_buf;
     uint8_t i;
 
-    sh->len = sizeof(struct source_header) + entry->entries[0].pathE->path_len * sizeof(uint16_t);
-    sh->current = 0;
-    sh->dispatch = IP_EXT_SOURCE_DISPATCH;
     sh->nxt_hdr = msg->hdr.nxt_hdr;
-    msg->hdr.nxt_hdr = NXTHDR_SOURCE;
+    msg->hdr.nxt_hdr = IPV6_ROUTING;
+
+    sh->len = sizeof(struct ip6_route) + entry->entries[0].pathE->path_len * sizeof(uint16_t);
+    sh->type = IP6ROUTE_TYPE_SOURCE;
+    sh->segs_remain = entry->entries[0].pathE->path_len;
+
     g_sh.hdr.ext = (struct ip6_ext *)sh;
     g_sh.len = sh->len;
     g_sh.next = msg->headers;
     msg->headers = &g_sh;
 
-    dbg("Install", "Inserted source header with length 0x%x and next hop: 0x%x and dispatch 0x%x\n", 
-        entry->entries[0].pathE->path_len, entry->entries[0].pathE->path[0], sh->dispatch);
+    dbg("Install", "Inserted source header with length 0x%x and next hop: 0x%x\n", 
+        entry->entries[0].pathE->path_len, entry->entries[0].pathE->path[0]);
 
     for (i = 0; i < entry->entries[0].pathE->path_len; i++) {
       sh->hops[i] = ntohs(entry->entries[0].pathE->path[i]);
     }
+    return sh;
   }
 
-  uint8_t convertTo8(uint16_t target) {
-    if (target > 0xFF)
-      return 0xFF;
-    return target;
-  }
-
-#ifdef DBG_TRACK_FLOWS
+#ifdef CENTRALIZED_ROUTING
   command void IPRouting.clearFlows() {
     int i, j;
     for (i = 0; i < N_FLOW_ENT; i++) {
@@ -678,36 +1137,52 @@ module IPRoutingP {
   }
 #endif
 
+#define convertTo8(X)  ((X) > 0xff ? 0xff : (X))
+
   /*
    * Inserts all necessary routing headers for the packet
    * 
    * If packet is going to the root, inserts a topology information
    *  collection header
+   *  XXX : SDH : the detection of weather it's going to the root is 
+   *              very broken...
    *
-   * AT: Should move source-routing header insertion to another function
-   *  to avoid unnecessary allocation of buffer space
    */
-  command void IPRouting.insertRoutingHeaders(struct split_ip_msg *msg) {
-    // these actually need to be static
-    static uint8_t sh_buf[sizeof(struct topology_header) + 
+
+  event struct tlv_hdr *DestinationExt.getHeader(int label,int nxt_hdr,
+                                                 struct ip6_hdr *iph) {
+    static uint8_t sh_buf[sizeof(struct tlv_hdr) + 
+                          sizeof(struct topology_header) +
                           (sizeof(struct topology_entry) * N_NEIGH)];
-    static struct generic_header record_route;
-    struct topology_header *th = (struct topology_header *)sh_buf;
-    int i, j = 0;
+    struct tlv_hdr *tlv =    (struct tlv_hdr *)sh_buf;
+    struct topology_header *th = (struct topology_header *)(tlv + 1);
+
+    tlv->len = sizeof(struct tlv_hdr) + sizeof(struct topology_header);
+    tlv->type = TLV_TYPE_TOPOLOGY;
+
+    printfUART("inserting destination options header\n");
 
     // AT: We theoretically only want to attach this topology header if we're
     //  sending this message to a controller.  Isn't it easier to just check
     //  to see if the dest address matches that of the sink?
     // SDH: how do you know what the address of the sink is?  
-    if (msg->hdr.nxt_hdr == IANA_UDP || msg->hdr.nxt_hdr == NXTHDR_UNKNOWN) {
+    // some how we need to check if we're using a default route and
+    // only attach the topology information if we are.  This still isn't
+    // perfect since somebody further down the tree may have a route and the
+    // packet might not get to the controller.
+    if (iph->nxt_hdr == IANA_UDP || iph->nxt_hdr == IPV6_NONEXT) {
+      int i,j = 0;
+      if (iph->ip6_dst.s6_addr16[0] == htons(0xff02)) return NULL;
+      if (traffic_sent) return NULL;
+      
       traffic_sent = TRUE;
 
-      th->len = sizeof(struct topology_header);
       // only add topology information directly behind actual payload
       // headers.
       // SDH : TODO : check that this will not fragment the packet...
       // AT: Why do we care about the number of hops? Debugging purposes?
-      th->nxt_hdr = msg->hdr.nxt_hdr;
+      th->seqno = reportSeqno++;
+      th->seqno = htons(th->seqno);
 
       // For all these 16-bit values, we're only using 8 bit values
       for (i = 0; i < N_NEIGH; i++) {
@@ -717,21 +1192,42 @@ module IPRoutingP {
           th->topo[j].conf = convertTo8(getConfidence(&neigh_table[i]));
           th->topo[j].hwaddr = htons(neigh_table[i].neighbor);
           j++;
-          th->len += sizeof(struct topology_entry);
+          tlv->len += sizeof(struct topology_entry);
           dbg("Lqi", "link est: 0x%x hops: 0x%x\n", 
               neigh_table[i].linkEstimate, neigh_table[i].hops);
         }
       }
-       
-      record_route.hdr.ext = (struct ip6_ext *)th;
-      record_route.len = th->len;
-      record_route.next = msg->headers;
       if (j > 0) {
-        msg->hdr.nxt_hdr = NXTHDR_TOPO;
-        msg->headers = &record_route;
+        return tlv;
       }
     }
-    
+    return NULL;
+  }
+
+  event void DestinationExt.free() {
+
+  }
+
+  command struct ip6_route *IPRouting.insertRoutingHeader(struct split_ip_msg *msg) {
+    // these actually need to be static
+#ifdef CENTRALIZED_ROUTING
+    struct flow_entry *entry;
+
+    // Need to source route this packet
+    //  Put this last because theoretically we could have a source
+    //  routed packet to the root, in which case it would have a topo
+    //  header, but the source header must always be the first in the
+    //  header list
+    if (((entry = getFlowEntry_Header(&msg->hdr)) != NULL) &&
+        IS_FULL_TYPE(entry->entries[0]) &&
+        entry->entries[0].pathE->path_len > 1) {
+      dbg("IPRouting", "Inserting a source routing header for a full path!\n");
+      updateFlowCounts(entry);
+      return insertSourceHeader(msg, entry);
+    }
+
+#endif
+    return NULL;
   }
 
   /*
@@ -879,7 +1375,7 @@ module IPRoutingP {
     for (i = 0; i < N_NEIGH; i++) {
       if (IS_NEIGH_VALID(&neigh_table[i]) &&
           SHOULD_EVICT(neigh_table[i])) {
-#if 0
+// #if 0
         // SDH : because of the overflow bug, this was never being
         // triggered.  I'm not sure it's actually a good idea because
         // it seems to increase path lengths for heavily used routes.
@@ -887,7 +1383,7 @@ module IPRoutingP {
         dbg("Evictions", "performing evict: %i\n", i);
         evictNeighbor(&neigh_table[i]);
         i --;
-#endif
+// #endif
         evicted = TRUE;
       }
     }
diff --git a/tos/lib/net/blip/Statistics.h b/tos/lib/net/blip/Statistics.h
new file mode 100644 (file)
index 0000000..6f5a5fb
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * "Copyright (c) 2008, 2009 The Regents of the University  of California.
+ * All rights reserved."
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice, the following
+ * two paragraphs and the author appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
+ *
+ */
+#ifndef _BLIP_STATISTICS_H_
+#define _BLIP_STATISTICS_H_
+
+/* Different IP components provide statistics about their operation. 
+ *
+ * Structures with this information is available here.
+ */
+
+#ifdef BLIP_STATS
+// if we get rid of the increments the compiler can optimize out the
+// statistics data structures when we don't use them.
+#define BLIP_STATS_INCR(X) X++
+#else
+#define BLIP_STATS_INCR(X)
+#endif
+
+
+/* Statistics from the core 6lowpan/IPv6 fragmentation and forwarding engine */
+typedef nx_struct {
+  nx_uint16_t sent;       // total IP datagrams sent
+  nx_uint16_t forwarded;  // total IP datagrams forwarded
+  nx_uint8_t rx_drop;     // L2 frags dropped due to 6lowpan failure
+  nx_uint8_t tx_drop;     // L2 frags dropped due to link failures
+  nx_uint8_t fw_drop;     // L2 frags dropped when forwarding due to queue overflow
+  nx_uint8_t rx_total;    // L2 frags received
+  nx_uint8_t encfail;     // frags dropped due to send queue
+
+#ifdef BLIP_STATS_IP_MEM
+  // statistics about free memory
+  // mostly useful for looking for memory leaks, or looking at
+  // forwarding queue depth.
+  nx_uint8_t fragpool;    // free fragments in pool
+  nx_uint8_t sendinfo;    // free sendinfo structures
+  nx_uint8_t sendentry;   // free send entryies
+  nx_uint8_t sndqueue;    // free send queue entries
+  nx_uint16_t heapfree;   // available free space in the heap
+#endif
+} ip_statistics_t;
+
+
+typedef nx_struct {
+  nx_uint8_t hop_limit;
+  nx_uint16_t parent;
+  nx_uint16_t parent_metric;
+  nx_uint16_t parent_etx;
+} route_statistics_t;
+
+typedef nx_struct {
+  nx_uint8_t sol_rx;
+  nx_uint8_t sol_tx;
+  nx_uint8_t adv_rx;
+  nx_uint8_t adv_tx;
+  nx_uint8_t echo_rx;
+  nx_uint8_t echo_tx;
+  nx_uint8_t unk_rx;
+  nx_uint16_t rx;
+} icmp_statistics_t;
+
+/* Statistics from the UDP transport protocol  */
+typedef nx_struct {
+  nx_uint16_t sent;  // UDP datagrams sent from app
+  nx_uint16_t rcvd;  // UDP datagrams delivered to apps
+  nx_uint16_t cksum; // UDP datagrams dropped due to checksum error
+} udp_statistics_t;
+
+
+#endif
index f594914e760fc97035edac102d33ac667afad88d..02c42aff7f80b66eb8c3b0e9ed598dca14ddab38 100644 (file)
@@ -29,43 +29,40 @@ module TcpP {
     return i;
   }
 
-  void conn_d(struct tcplib_sock *sock, int error) {
+  void tcplib_extern_connectdone(struct tcplib_sock *sock, int error) {
     int cid = find_client(sock);
     if (cid < N_CLIENTS)
       signal Tcp.connectDone[cid](error == 0);
   }
 
-  void rx(struct tcplib_sock *sock, void *data, int len) {
+  void tcplib_extern_recv(struct tcplib_sock *sock, void *data, int len) {
     int cid = find_client(sock);
     if (cid < N_CLIENTS)
       signal Tcp.recv[cid](data, len);
   }
 
-  void cl(struct tcplib_sock *sock) {
+  void tcplib_extern_closed(struct tcplib_sock *sock) {
     tcplib_close(sock);
   }
 
-  void cd(struct tcplib_sock *sock) {
+  void tcplib_extern_closedone(struct tcplib_sock *sock) {
     int cid = find_client(sock);
     tcplib_init_sock(sock);
     if (cid < N_CLIENTS)
       signal Tcp.closed[cid](0);
   }
 
-  void init_ops(struct tcplib_sock *sock) {
-    sock->ops.connect_done = conn_d;
-    sock->ops.recvfrom = rx;
-    sock->ops.closed = cl;
-    sock->ops.close_done = cd;
+  void tcplib_extern_acked(struct tcplib_sock *sock) {
+    int cid = find_client(sock);
+    if (cid < N_CLIENTS)
+      signal Tcp.acked[cid]();
   }
-
-
+#include "circ.c"
+#include "tcplib.c"
 
   void setSrcAddr(struct split_ip_msg *msg) {
     if (msg->hdr.ip6_dst.s6_addr16[0] == htons(0xff02) ||
         msg->hdr.ip6_dst.s6_addr16[0] == htons(0xfe80)) {
-//         (msg->hdr.dst_addr[0] == 0xff && (msg->hdr.dst_addr[1] & 0xf) == 0x2) ||
-//         (msg->hdr.dst_addr[0] == 0xfe && msg->hdr.dst_addr[2] == 0x80)) {
       call IPAddress.getLLAddr(&msg->hdr.ip6_src);
     } else {
       call IPAddress.getIPAddr(&msg->hdr.ip6_src);
@@ -76,21 +73,13 @@ module TcpP {
 
   struct tcplib_sock *tcplib_accept(struct tcplib_sock *conn,
                                     struct sockaddr_in6 *from) {
-    void *rx_buf = NULL, *tx_buf = NULL;
-    int rx_buf_len, tx_buf_len;
     int cid = find_client(conn);
 
     printfUART("tcplib_accept: cid: %i\n", cid);
 
     if (cid == N_CLIENTS) return NULL;
-    if (signal Tcp.accept[cid](from, &rx_buf, &rx_buf_len,
-                               &tx_buf, &tx_buf_len)) {
-      if (rx_buf == NULL || tx_buf == NULL) return NULL;
-      conn->rx_buf = rx_buf;
-      conn->rx_buf_len = rx_buf_len;
-      conn->tx_buf = tx_buf;
-      conn->tx_buf_len = tx_buf_len;
-      init_ops(conn);
+    if (signal Tcp.accept[cid](from, &conn->tx_buf, &conn->tx_buf_len)) {
+      if (conn->tx_buf == NULL) return NULL;
       return conn;
     }
     return NULL;
@@ -103,9 +92,6 @@ module TcpP {
     call IP.send(msg);
   }
 
-#include "circ.c"
-#include "tcplib.c"
-
   command error_t Init.init() {
     int i;
     for (i = 0; i < uniqueCount("TCP_CLIENT"); i++) {
@@ -140,17 +126,14 @@ module TcpP {
   }
 
   command error_t Tcp.connect[uint8_t client](struct sockaddr_in6 *dest,
-                                              void *rx_buf, int rx_buf_len,
                                               void *tx_buf, int tx_buf_len) {
-    socks[client].rx_buf;
-    socks[client].rx_buf_len = rx_buf_len;
     socks[client].tx_buf = tx_buf;
     socks[client].tx_buf_len = tx_buf_len;
     tcplib_connect(&socks[client], dest);
   }
 
   command error_t Tcp.send[uint8_t client](void *payload, uint16_t len) {
-    tcplib_send(&socks[client], payload, len);
+    if (tcplib_send(&socks[client], payload, len) < 0) return FAIL;
     return SUCCESS;
   }
   
@@ -160,8 +143,12 @@ module TcpP {
     return FAIL;
   }
 
+  command error_t Tcp.abort[uint8_t client]() {
+    if (tcplib_abort(&socks[client]) < 0) return FAIL;
+    return SUCCESS;
+  }
+
   default event bool Tcp.accept[uint8_t cid](struct sockaddr_in6 *from, 
-                                             void **rx_buf, int *rx_buf_len,
                                              void **tx_buf, int *tx_buf_len) {
     return FALSE;
   }
@@ -169,9 +156,6 @@ module TcpP {
  default event void Tcp.connectDone[uint8_t cid](error_t e) {}
  default event void Tcp.recv[uint8_t cid](void *payload, uint16_t len) {  }
  default event void Tcp.closed[uint8_t cid](error_t e) { }
+ default event void Tcp.acked[uint8_t cid]() { }
  
-
-
-
-  
 }
diff --git a/tos/lib/net/blip/TrackFlowsC.nc b/tos/lib/net/blip/TrackFlowsC.nc
new file mode 100644 (file)
index 0000000..729d935
--- /dev/null
@@ -0,0 +1,16 @@
+
+configuration TrackFlowsC {
+
+} implementation {
+  
+  components MainC, TrackFlowsP, IPDispatchP;
+  components SerialActiveMessageC as Serial;
+
+  TrackFlowsP.Boot -> MainC;
+  TrackFlowsP.SerialControl -> Serial;
+  TrackFlowsP.IPExtensions -> IPDispatchP.IPExtensions;
+  TrackFlowsP.Headers -> IPDispatchP.HopByHopExt;
+
+  TrackFlowsP.FlowSend -> Serial.AMSend[AM_FLOW_ID_MSG];
+  
+}
diff --git a/tos/lib/net/blip/TrackFlowsP.nc b/tos/lib/net/blip/TrackFlowsP.nc
new file mode 100644 (file)
index 0000000..f06bcae
--- /dev/null
@@ -0,0 +1,140 @@
+
+#include "TrackFlows.h"
+
+module TrackFlowsP {
+  uses {
+    interface Boot;
+    interface SplitControl as SerialControl;
+    interface IPExtensions;
+    interface TLVHeader as Headers;
+    interface AMSend as FlowSend;
+  }
+} implementation {
+  
+
+  bool flow_send_busy = FALSE;
+  uint16_t current_flowid = 0;
+  message_t flow_send;
+
+  int send_flow_idx = -1, cur_idx = 0;
+  nx_struct {
+    nx_uint8_t flags;
+    nx_uint8_t label;
+    nx_struct flow_id_msg flow;
+  } flow_cache[N_FORWARD_ENT * 3];
+
+  int get_entry() {
+    cur_idx = (cur_idx + 1) % (N_FORWARD_ENT * 3);
+    return cur_idx;
+  }
+  int lookup_entry(uint8_t label) {
+    int i;
+    for (i = 0; i < N_FORWARD_ENT * 3; i++) {
+      if (flow_cache[i].flags == 1 && flow_cache[i].label == label)
+        return i;
+    } 
+    return -1;
+  }
+  
+  event void Boot.booted() {
+    call SerialControl.start();
+    flow_send_busy = FALSE;
+    ip_memclr((void *)flow_cache, sizeof(flow_cache));
+  }
+
+  event void FlowSend.sendDone(message_t *msg, error_t error) {
+    flow_send_busy = FALSE;
+    flow_cache[send_flow_idx].flags = 0;
+  }
+
+  void update_msg(struct ip6_hdr *iph, nx_struct flow_id *flow, uint8_t label, uint8_t nxt_hdr) {
+    nx_struct flow_id_msg *payload;
+    int i = get_entry();
+    if (i < 0) return;
+    flow_cache[i].flags = 1;
+    flow_cache[i].label = label;
+    payload = &flow_cache[i].flow;
+
+    memcpy(&payload->flow, flow, sizeof(nx_struct flow_id));
+    payload->src = ntohs(iph->ip6_src.s6_addr16[7]);
+    payload->dst = ntohs(iph->ip6_dst.s6_addr16[7]);
+    payload->local_address = TOS_NODE_ID;
+    payload->nxt_hdr = nxt_hdr;
+  }
+
+  event void IPExtensions.handleExtensions(uint8_t label,
+                                           struct ip6_hdr *iph,
+                                           struct ip6_ext *hop,
+                                           struct ip6_ext *dst,
+                                           struct ip6_route *route,
+                                           uint8_t nxt_hdr) {
+    if (hop != NULL) {
+      struct tlv_hdr *tlv = call IPExtensions.findTlv(hop, TLV_TYPE_FLOW);
+      if (tlv != NULL && tlv->len == sizeof(struct tlv_hdr) + sizeof(nx_struct flow_id)) {
+        update_msg(iph, (nx_struct flow_id *)(tlv + 1), label, nxt_hdr);
+      }
+    }
+  }
+
+  event void IPExtensions.reportTransmission(uint8_t label, send_policy_t *send) {
+    int i, flow_idx = lookup_entry(label);
+    nx_struct flow_id_msg *payload =
+      (nx_struct flow_id_msg *)call FlowSend.getPayload(&flow_send, sizeof(nx_struct flow_id_msg));
+
+    
+    if (flow_idx < 0) return;
+    memcpy(payload, &flow_cache[flow_idx].flow, sizeof(nx_struct flow_id_msg));
+
+
+    payload->n_attempts = 0;
+    for (i = 0; i < send->current && i < 3; i++) {
+      // if (send->dest[i] == IEEE154_BROADCAST_ADDR) return;
+      
+      payload->attempts[i].next_hop = send->dest[i];
+      payload->attempts[i].tx = send->retries;
+    }
+    if (i < 3) {
+      payload->attempts[i].next_hop = send->dest[i];
+      payload->attempts[i].tx = send->actRetries;
+      i++;
+    }
+    payload->n_attempts = i;
+    
+    if (!flow_send_busy) {
+      if (call FlowSend.send(0xffff, &flow_send, sizeof(nx_struct flow_id_msg)) == SUCCESS) {
+        flow_send_busy = TRUE;
+        send_flow_idx = flow_idx;
+        return;
+      } 
+      // otherwise fall through and invalidate the cache
+    }
+    flow_cache[flow_idx].flags = 0;
+  }
+
+  event struct tlv_hdr *Headers.getHeader(uint8_t label,
+                                          struct ip6_hdr *msg,
+                                          uint8_t nxt_hdr) {
+    static uint8_t buf[sizeof(struct tlv_hdr) + sizeof(nx_struct flow_id)];
+    struct tlv_hdr *tlv;
+    nx_struct flow_id *flow;
+    tlv = (struct tlv_hdr *)buf;
+    flow = (nx_struct flow_id *)(tlv + 1);
+
+    tlv->type = TLV_TYPE_FLOW;
+    tlv->len = sizeof(struct tlv_hdr) + sizeof(nx_struct flow_id);
+
+/*     if (msg->ip6_dst.s6_addr[0] != 0xff ||  */
+/*         (msg->ip6_dst.s6_addr[0] == 0xff &&  */
+/*          (msg->ip6_dst.s6_addr[1] & 0x0f) > 2)) { */
+      flow->id  = current_flowid++;
+
+      update_msg(msg, flow, label, nxt_hdr);
+      return tlv;
+/*     } */
+/*     return NULL; */
+  }
+
+  event void SerialControl.startDone(error_t e) { }
+  event void SerialControl.stopDone(error_t e) { }
+
+}
index 31cb217026749e49507e2933c18bd5b5d793f82f..eda9c236f26df32e83ed18e52a447cc9e5ee7e25 100644 (file)
@@ -1,10 +1,14 @@
 
+#include <Statistics.h>
+
 configuration UdpC {
-  provides interface UDP[uint8_t clnt];                         
+  provides interface UDP[uint8_t clnt];
+  provides interface Statistics<udp_statistics_t>;
 } implementation {
 
   components MainC, IPDispatchC, UdpP, IPAddressC;
   UDP = UdpP;
+  Statistics = UdpP;
 
   MainC -> UdpP.Init;
   UdpP.IP -> IPDispatchC.IP[IANA_UDP];
index 8cb0e5fb7351418529b24e7ab0e2a0a55ea3c331..47ecb0d53177f88c3511be9cab97cbf8c210c8c3 100644 (file)
@@ -1,18 +1,26 @@
 
 #include <ip_malloc.h>
 #include <in_cksum.h>
+#include <Statistics.h>
 
 module UdpP {
   provides interface UDP[uint8_t clnt];
   provides interface Init;
+  provides interface Statistics<udp_statistics_t>;
   uses interface IP;
   uses interface IPAddress;
 } implementation {
 
+#ifdef PRINTFUART_ENABLED
+#undef dbg
+#define dbg(X,fmt, args...) printfUART(fmt, ##args)
+#endif
+
   enum {
     N_CLIENTS = uniqueCount("UDP_CLIENT"),
   };
 
+  udp_statistics_t stats;
   uint16_t local_ports[N_CLIENTS];
 
   enum {
@@ -40,6 +48,7 @@ module UdpP {
   }
 
   command error_t Init.init() {
+    call Statistics.clear();
     ip_memclr((uint8_t *)local_ports, sizeof(uint16_t) * N_CLIENTS);
     return SUCCESS;
   }
@@ -64,7 +73,6 @@ module UdpP {
     return SUCCESS;
   }
 
-
   event void IP.recv(struct ip6_hdr *iph,
                      void *payload,
                      struct ip_metadata *meta) {
@@ -86,6 +94,34 @@ module UdpP {
     ip_memcpy(&addr.sin6_addr, &iph->ip6_src, 16);
     addr.sin6_port = udph->srcport;
 
+
+    { 
+      uint16_t rx_cksum = ntohs(udph->chksum), my_cksum;
+      vec_t cksum_vec[4];
+      uint32_t hdr[2];
+
+      udph->chksum = 0;
+
+      cksum_vec[0].ptr = (uint8_t *)(iph->ip6_src.s6_addr);
+      cksum_vec[0].len = 16;
+      cksum_vec[1].ptr = (uint8_t *)(iph->ip6_dst.s6_addr);
+      cksum_vec[1].len = 16;
+      cksum_vec[2].ptr = (uint8_t *)hdr;
+      cksum_vec[2].len = 8;
+      hdr[0] = iph->plen;
+      hdr[1] = htonl(IANA_UDP);
+      cksum_vec[3].ptr = payload;
+      cksum_vec[3].len = ntohs(iph->plen);
+
+      my_cksum = in_cksum(cksum_vec, 4);
+      printfUART("rx cksum: %x calc: %x\n", rx_cksum, my_cksum);
+      if (rx_cksum != my_cksum) {
+        BLIP_STATS_INCR(cksum);
+        return;
+      }
+    }
+
+    BLIP_STATS_INCR(rcvd);
     signal UDP.recvfrom[i](&addr, (void *)(udph + 1), ntohs(iph->plen) - sizeof(struct udp_hdr), meta);
   }
 
@@ -118,13 +154,16 @@ module UdpP {
     g_udp = (struct generic_header *)(udp + 1);
 
     // fill in all the packet fields
-    ip_memclr((uint8_t *)&msg->hdr, sizeof(struct ip6_hdr));
+    ip_memclr((uint8_t *)msg, sizeof(struct split_ip_msg));
     ip_memclr((uint8_t *)udp, sizeof(struct udp_hdr));
     
     setSrcAddr(msg);
     memcpy(&msg->hdr.ip6_dst, dest->sin6_addr.s6_addr, 16);
     
-    if (local_ports[clnt] == 0 && alloc_lport(clnt) == 0) return FAIL;
+    if (local_ports[clnt] == 0 && (local_ports[clnt] = alloc_lport(clnt)) == 0) {
+      ip_free(msg);
+      return FAIL;
+    }
     udp->srcport = local_ports[clnt];
     udp->dstport = dest->sin6_port;
     udp->len = htons(len + sizeof(struct udp_hdr));
@@ -141,12 +180,25 @@ module UdpP {
     udp->chksum = htons(msg_cksum(msg, IANA_UDP)); 
 
     rc = call IP.send(msg);
+    BLIP_STATS_INCR(sent);
 
     ip_free(msg);
     return rc;
 
   }
 
+  command void Statistics.clear() {
+#ifdef BLIP_STATS
+    ip_memclr((uint8_t *)&stats, sizeof(udp_statistics_t));
+#endif
+  }
+
+  command void Statistics.get(udp_statistics_t *buf) {
+#ifdef BLIP_STATS
+    ip_memcpy(buf, &stats, sizeof(udp_statistics_t));
+#endif
+  }
+
   default event void UDP.recvfrom[uint8_t clnt](struct sockaddr_in6 *from, void *payload,
                                                uint16_t len, struct ip_metadata *meta) {
 
diff --git a/tos/lib/net/blip/doc/README b/tos/lib/net/blip/doc/README
new file mode 100644 (file)
index 0000000..959584f
--- /dev/null
@@ -0,0 +1,104 @@
+
+ @title blip documentation
+ @author Stephen Dawson-Haggerty stevedh@eecs.berkeley.edu
+ @release public
+---------------------------------------------------------------------
+
+ 1. Installation
+
+ - This is only going to work on linux.
+
+ - The recommended version of TinyOS is a recent CVS checkout.  This
+   is necessary for appropriate radio stack support.
+
+ - Make sure the c serial tools are built in
+   $TOS_ROOT/support/sdk/c/sf.  You may need to run ./bootstrap,
+   ./configure, and make in that folder to generate libmote.a.
+
+ - Add two environment variables to your startup scripts:
+     export LOWPAN_ROOT=~/svn/code/b6lowpan/
+     export TOSMAKE_PATH="$LOWPAN_ROOT/support/make"
+   where LOWPAN_ROOT is replaced with the path to the blip top
+   level directory.
+
+ - Optionally, have a look at $TOS_ROOT/support/sdk/c/sf/serialsource.c.  
+   There is an enum which defines ACK_TIMEOUT = 1000000 (one second in
+   usecs).  This is much too long and will cause a lot of jitter when
+   (not if) serial writes fail.  Changing it to 100000 is worthwhile.
+   You will need to rebuild libmote.a by typing 'make' in that folder
+   after making this change.  (SDH : this was true up to a little past 
+   version 2.1.  It is now false.)
+
+ 2. Building
+
+ - Build a test app:
+      * cd to $LOWPAN_ROOT/apps/UDPEcho/ and try typing `make <platform> blip`
+ - Build the IEEE802.15.4 bridge to your computer
+      * cd to $LOWPAN_ROOT/apps/IPBaseStation/ and `make <platform> blip`
+ - Build the driver 
+      * cd to $LOWPAN_ROOT/support/sdk/c/blip and type `make`
+
+ 3. Running
+
+ - Install IPBaseStation on a mote.  This will be your
+       computer's interface to the world of low-power radio.
+
+ - Start the driver (once you've built it)
+      * cd $LOWPAN_ROOT/support/sdk/c/blip
+      * edit the config file $LOWPAN_ROOT/support/sdk/c/blip/serial_tun.conf
+         * set 'addr' you would like your computer's interface to use on the PAN
+         * set 'proxy' to the network device you would like to proxy
+                neighbor advertisements on
+      * sudo ./ip-driver /dev/ttyUSB0 telosb
+           (replace the device and baud with whatever you're using)
+   The config file is assumed to be in the CWD when ip-driver starts;
+       if this is not the case it may be specified using '-c <config file>'
+
+ - The driver registers itself on the 2001:470:1f04:56d::/64
+       subnet (or whatever you have specified in the config file).
+
+ - If you program a few motes with UDPEcho, their addresses are formed
+       with octets 15 and 16 of the IPv6 address comming from the
+       802.15.4 short address you programmed them with.  Octets 9-14
+       are zero, so the address formed is:
+
+       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+       |  network prefix       |     zero        | id  | 
+       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+       ICMPv6 DAD is not performed.
+
+ - For instance, if you program a mote with ID 101 (0x65), you can try
+       ping6 2001:470:1f04:56d::65
+       tracert6 2001:470:1f04:56d::65
+       nc6 -u 2001:470:1f04:56d::65 7
+       nc6 -u 2001:470:1f04:56d::65 2000
+       
+       UDPEcho runs an echo service on port 7, and a simple shell on
+       port 2000; type 'help' for a list of commands.
+
+ - The motes can also report back statistics every 15 seconds over
+       UDP.  They will send these reports to an address specified in the
+       application make file; however these reports are disabled by default.
+       You can observe these statistics using the Listener.py
+       script in $LOWPAN_ROOT/apps/UDPEcho/: `python Listener.py`.
+
+ - The driver provides a simple console when running, which allows you
+       to inspect and manipulates routes, and view statistics.  The
+       console runs as a telnet service on port 6106.
+
+ - A good way of understanding what is happening is to start wireshark
+       on tun0; you should be able to observe the neighbor discovery
+       process as motes boot.  You may also notice messages sent to
+       ff05::1; these are routing updates.  They are sent from a
+       binary exponential timer with a maximum period of 5 minutes to
+       inform the router of mote's presence; however, they are
+       suppressed by data traffic since the routing updates will be
+       piggybacked on it.
+
+ - Further reading: doc/ contains a numbers of README's related to
+       pieces of blip such as the socket interface, the shell, and
+       network programming support.  For more technical details on
+       IPv6, please see any reference on the subject.  Many of the
+       documents produced by the IETF ROLL and 6lowpan working groups
+       are relevent to this design space.  
diff --git a/tos/lib/net/blip/doc/README-IP b/tos/lib/net/blip/doc/README-IP
new file mode 100644 (file)
index 0000000..a73fbf9
--- /dev/null
@@ -0,0 +1,56 @@
+
+ @title IP data-structure documentation
+ @author Stephen Dawson-Haggerty
+ @release public
+----------------------------------------------------------------------
+
+The ip-stack provides a bare IP datagram interface to the network
+layer; this is documented in comments in the code.
+
+For the purposes of socket programming, two data structures are most
+important.  The 'struct sockaddr_in6' and the 'struct in6_addr'.  They
+are substantially shared with the linux/bsd versions, and reproduced
+below.
+
+struct in6_addr
+  {
+    union
+      {
+       uint8_t u6_addr8[16];
+       uint16_t u6_addr16[8];
+       uint32_t u6_addr32[4];
+      } in6_u;
+#define s6_addr                        in6_u.u6_addr8
+#define s6_addr16              in6_u.u6_addr16
+#define s6_addr32              in6_u.u6_addr32
+  };
+
+struct sockaddr_in6 {
+  uint16_t sin6_port;
+  struct in6_addr sin6_addr;
+};
+
+void inet_pton6(char *addr, struct in6_addr *dest);
+
+Usage
+----------------------------------------------------------------------
+
+ Example 1: Suppose we want to setup a sockaddr_in6 to point to ff02::5, port 10000:
+ {
+   struct sockaddr_in6 sa6;
+   inet_pton6("ff02::5", &sa6.sin6_addr);
+   sa6.sin6_port = htons(10000);
+ }
+
+ Example 2: Do the same thing, but without the overhead of storing and
+  parsing the string address representation.
+ {
+   struct sockaddr_in6 sa6;
+   memset(&sa6, 0, sizeof(struct sockaddr_in6));
+   sa6.sin6_addr.s6_addr16[0] = htons(0xff02);
+   sa6.sin6_addr.s6_addr[15] = 5;
+   sa6.sin6_port = htons(10000);
+ }
+
+ This code is very unix-y; the second example will work on *nix's.
+
diff --git a/tos/lib/net/blip/doc/README-MERAKI b/tos/lib/net/blip/doc/README-MERAKI
new file mode 100644 (file)
index 0000000..ab9514b
--- /dev/null
@@ -0,0 +1,53 @@
+
+ @title Meraki Documentation
+ @author Stephen Dawson-Haggerty stevedh@eecs.berkeley.edu
+ @release internal
+---------------------------------------------------------------------
+
+This README explains how to use a Meraki Mini programmed with
+OpenWRT/kamikaze as a border router.  This document and the code make
+the following assumptions:
+
+ - The Meraki has a public IP address or is in a DMZ such that the
+        6over4 tunneling protocol will work.
+ - The Meraki is the sole router for a prefix
+
+Background
+---------------------------------------------------------------------
+
+To ease configuration, the important parameters are stored in a
+database.  When the meraki waits up, it hits the database and
+downloads a few config files which it then uses.  To grab new
+configuration, you can either log in and manually restart the router
+daemon, or just reboot.  The parameters stored are:
+ prefix : the one received from the hurricane electric tunnel broker
+ short addr : the address of this device on the network
+ channel : which channel to use
+
+Install
+---------------------------------------------------------------------
+
+ 1. Install the router daemon on the meraki using either the provided
+ipkg, or your own if you've built a version.  Building the package is
+very easy but not covered here.
+   'ipkg update'
+   'ipkg install lowpan-bridge_1.2-855_mips.ipk' 
+In order for the dependancies to be automatically installed, you must
+do the update first so that the package system downloads the directory
+with the necessary packages.
+ 2. Set up the configuration parameters in the database.  The key used
+is the hostname; precisely, whatever 'uname -n' prints.  If no key is
+found in the database the meraki will just use defaults.
+ 3. Start the daemon with '/etc/init.d/lowpan-bridge start' This will
+run automatically when the meraki boots.
+
+... I think that's it.  Pretty easy!
+
+Bugs/Notes
+---------------------------------------------------------------------
+
+There seems to be an issue with the serial port on the meraki.  The
+effect is that packets are dropped when you send too quickly.  This
+mostly effects fragmentation.  As a stopgap, I've inserted a timeout
+between fragments, but this means the performance is somewhat worse
+then on a PC and a micaz.
diff --git a/tos/lib/net/blip/doc/README-NWPROG b/tos/lib/net/blip/doc/README-NWPROG
new file mode 100644 (file)
index 0000000..ef59590
--- /dev/null
@@ -0,0 +1,70 @@
+
+ @title Meraki Documentation
+ @author Stephen Dawson-Haggerty stevedh@eecs.berkeley.edu
+ @release public
+---------------------------------------------------------------------
+
+What is it?
+---------------------------------------------------------------------
+nwprog is a method of over-the-air programming.  It uses much of the
+machinery Deluge has developed, like the boot loader and flash layout,
+but substitutes a simpler transport using UDP for Deluge's
+dissemination algorithm.  This means that it is point-to-point, and
+not incredibly appropriate for reprogramming an entire network all at
+once.
+
+How do I get it?
+---------------------------------------------------------------------
+It is included with the b6lowpan stack.  It reuses much of the Deluge
+code directly from the TinyOS tree without shadowing the files.
+
+Differences from Deluge?
+---------------------------------------------------------------------
+ - no dissemination 
+ - no base station or serial port for injection
+
+ The application is very simple: flash is formatted into several
+volumes (a golden image and three application volumes), which are used
+to store application images.  Flash management, boot loading, and
+image formatting are all provided by Deluge.
+
+How to use it?
+---------------------------------------------------------------------
+Build your application with support by include a line in your
+application Makefile, and include the IPDispatchC component.
+== application makefile ==
+BOOTLOADER=tosboot
+== </snip> == 
+Also, it is necessary to include a volumes xml file for your flash
+chip; examples for the stm25p and at45db are present in apps/UDPEcho.
+
+First built the tosboot bootloader for your platform by going to
+tinyos-2.x/tos/lib/tosboot and typing `make <platform>`.
+
+Then just build and install your application like usual.  If
+networking is working, you should have no problem following the rest
+of the instructions.
+
+Interactions with the motes happen using the 'nwprog' tool in a shell.
+Connect the shell with `nc6 -u 2001:470:1f04:56d::65 2000`.
+It has three commands:
+ `nwprog list`: examine the flash and print out information on volumes
+        containing images believed to be valid
+ `nwprog reboot`: reboot into the same image
+ `nwprog boot N`: reboot, and flash the mote with the binary stored in
+        volume N
+
+In order to upload new images, use the tos-nwprog tool, located in
+$LOWPAN_ROOT/tools/tinyos/misc.  This tool provides minimal
+functionality; only erasing and uploading are supported.
+
+ `./tos-nwprog 2001:470:1f04:56d::65 -e 0`: erase image 0 from the
+        mote at the given IP address.
+ `./tos-nwprog 2001:470:1f04:56d::65 -u 0 tos_image.xml`: upload the
+        image in tos_image.xml to volume 0 on the mote at the IP
+        address.  This will erase the volume before uploading it.
+
+To integrate with your own application, there are several internal
+interfaces which can be used to examine the flash.  Looking at the
+example code in UDPShellP component is the best way of finding out
+about these.
diff --git a/tos/lib/net/blip/doc/README-SHELL b/tos/lib/net/blip/doc/README-SHELL
new file mode 100644 (file)
index 0000000..dd09536
--- /dev/null
@@ -0,0 +1,55 @@
+ @title UDPShell Documentation
+ @author Stephen Dawson-Haggerty
+ @release public
+----------------------------------------------------------------------
+
+UDPShell is a simple text-based command processor which comes with the
+ip-stack.  It is an optional, although convenient way of
+implementating debugging commands on a mote.
+
+Usage
+----------------------------------------------------------------------
+
+By default, the shell contains only a few simple commands: help, echo,
+uptime, ping, and ident.  It is designed to be very easy to extend by
+adding your own commands.
+
+To include just the basic shell, include the UDPShellC component in
+your application.  To augment the shell with a new shell command, use
+the generic component ShellCommandC.
+
+Example
+----------------------------------------------------------------------
+
+Suppose we want to implement `expr`, a simple arithmetic evaluator.
+First, bind the 'expr' command string in your application configuration.
+
+configuration App {} implementation {
+  components AppImplP;
+  components new ShellCommandC("expr") as Expr;
+  AppImplP.Expr -> Expr;
+}
+
+Within AppImplP, you must implement the ShellCommand interface.  The
+interface has only one event, 'eval' which has the same prototype as
+main() in a typical c program.
+
+event char *Expr.eval(int argc, char **argv) {
+  static char ret[10];
+  return ret;
+}
+
+If expr returns a non-null value, it is assumed to be a
+null-terminated string which will be echoed back to a connected
+client.  The buffer returned must obviously not be allocated on the
+stack.  The shell does maintain a single buffer which components can
+use to print their reply to; it can be requested with a call to
+Expr.getBuffer(uint16_t len).
+
+More running code
+----------------------------------------------------------------------
+
+Fully fleshed out examples of code using this interface are available
+within the stack; see tos/lib/net/b6lowpan/shell/FlashShell[CP].nc and
+tos/lib/net/b6lowpan/nwprog/NWProg[CP].nc
\ No newline at end of file
diff --git a/tos/lib/net/blip/doc/README-SIM b/tos/lib/net/blip/doc/README-SIM
new file mode 100644 (file)
index 0000000..5461d94
--- /dev/null
@@ -0,0 +1,43 @@
+
+ @title blip + TOSSIM documentation
+ @author Stephen Dawson-Haggerty stevedh@eecs.berkeley.edu
+ @release internal
+---------------------------------------------------------------------
+
+The state of blip + TOSSIM
+---------------------------------------------------------------------
+
+TOSSIM and blip have worked reliably together in the not-so-distant
+past.  However, blip makes several assumptions about the radio stack
+which are not (yet) reflected in TOSSIM-cvs.  It expects a PacketLink
+and Unique layer a la the cc2420 stack in order to provide reliable
+transmissions with link duplicate suppression.  Performance without
+these is very poor.  There are also several other minor changes which
+deal with the deliver of serial packets.
+
+Ported versions of those components exist and are present in the blip
+distribution.  However, they require patching an existing tinyos
+stack, so it is probably a good idea to do a sideways checkout of
+tinyos for experimenting on.
+
+Instructions for using TOSSIM with UDPEcho
+---------------------------------------------------------------------
+
+This is completely unsupported right now.  If you really want TOSSIM +
+blip, it ought to work, but there are definitly NO GUARANTEES and NO
+SUPPORT.  It's just too much of a hack at the moment.
+
+ - patch your tossim installation.  The patch is in $LOWPAN_ROOT/tos/lib/tossim.patch, so apply that using
+    * `cd $TOSDIR/tos/lib`
+    * `patch -p0 < $LOWPAN_ROOT/tos/lib/tossim.patch`
+   Then copy $LOWPAN_ROOT/tos/lib/tossim/Packet* to $TOSDIR/tos/lib/tossim
+
+ - I think you should then be able to cd to apps/UDPEcho/sim and type `make`
+    * make sure you have python2.5 and python2.5-dev installed
+ - run `./Sim.py` (or `python2.5 ./Sim.py` if 2.4 is default)
+ - build the driver in support/sdh/c/lib6lowpan/tunnel using `make
+     sim` (probably doing make clean first)
+ - you can then run the driver as usually, except using `./serial_tun
+     localhost 9001` to point it at the serialforwarder running in the simulator.
+
+
diff --git a/tos/lib/net/blip/doc/README-TCP b/tos/lib/net/blip/doc/README-TCP
new file mode 100644 (file)
index 0000000..d20e4e6
--- /dev/null
@@ -0,0 +1,101 @@
+
+ @title TCP Socket Documentation
+ @author Stephen Dawson-Haggerty
+ @release internal
+ @target 2.1.1
+----------------------------------------------------------------------
+
+TCP is the standard  Internet protocol for reliable, in-order delivery
+of data across the  network.  Although inefficient, its ubiquity makes
+it impossible to ignore; thus, blip provides a very simple TCP stack.
+TCP is considerably more complicated then UDP, and requires careful
+use in the embedded setting to prevent resource exhaustion.  It is
+essential that one understand the BSD sockets API; this brief README
+does not cover many details.
+
+For memory-constrained operation, blip's TCP does not do any
+receive-side buffering.  Instead, it will immediately dispatch
+new, in-order data to the application and otherwise drop the segment.
+Blip does provide send-buffering so that it can automatically
+retransmit missing segments; this buffer may be of any size and is
+provided by the application.  
+
+Important parameters:
+
+MSS: Maximum Segment Size: the maximum amount of data that a TCP packet
+will contain.  Since blip immediately delivers new data, this is also
+greater then or equal to the maximum amount of data which will ever be
+delivered in a recv() call.
+
+Window: TCP keeps the other side informed about how much buffer is
+available for new data.  Since blip does not have a receive buffer,
+this parameter is not adjusted by blip; only set to a reasonable
+value.  Applications using TCP may wish to dynamically control this
+value for various reasons.
+
+Notes
+----------------------------------------------------------------------
+
+The TCP interface is located in
+$LOWPAN_ROOT/tos/lib/net/blip/interfaces/Tcp.nc.  For the most part,
+it should be familier.
+
+Since the application is responsible for buffering, both accept() and
+connect() require the implementer to include a buffer for the stack's
+use.  Once passed to the stack, the buffer is reserved until a
+closed() event is signaled on that socket.
+
+A few of the most important caveats/brokeness:
+
+ - there is no listen().  calling bind() on a socket also begins to listen.
+
+ - there is no way to accept() multiple sockets like you can in Unix.
+   More precisely, all the code would support it but then there is
+   dynamic allocation since you have to allocate a new socket struct
+   on the fly.
+
+ - (sort of) as a result of these, if the socket is closed, you have
+   to call bind() if you want to continue listening.
+
+ - you'll need to carefully manage buffer and window sized by hand if
+   you want to be sure of correct operation.  Make sure you check
+   return codes from send() since it will fail if there is not enough
+   local buffer for the entire request.
+
+
+Example
+----------------------------------------------------------------------
+
+
+configuration {
+  components new TcpSocketC() as TcpEcho;
+  TCPEchoP.TcpEcho -> TcpEcho;
+}
+
+module {} implementation {
+  // allocate a send buffer
+  char tcp_buf[150];
+
+  // accept connections from anyone.  no need to save the endpoint,
+  // but this is the only time its available (add an API call?)
+  event bool TcpEcho.accept(struct sockaddr_in6 *from, 
+                            void **tx_buf, int *tx_buf_len) {
+    *tx_buf = tcp_buf;
+    *tx_buf_len = 150;
+    // indicates we are accepting the connection
+    return TRUE;
+  }
+  // potentially useful?
+  event void TcpEcho.connectDone(error_t e) {}
+
+  // just echo the data back.
+  event void TcpEcho.recv(void *payload, uint16_t len) {
+    call TcpEcho.send(payload,len);
+  }
+
+  // rebind to accept other connections.
+  event void TcpEcho.closed(error_t e) {
+    call Leds.led0Toggle();
+    call TcpEcho.bind(7);
+  }
+}
\ No newline at end of file
diff --git a/tos/lib/net/blip/doc/README-UDP b/tos/lib/net/blip/doc/README-UDP
new file mode 100644 (file)
index 0000000..e85e793
--- /dev/null
@@ -0,0 +1,70 @@
+
+ @title UDP Socket Documentation
+ @author Stephen Dawson-Haggerty
+ @release public
+----------------------------------------------------------------------
+
+ip-stack provides a UDP sockets layer as a basic application transport
+service.  The UDP interface is located in
+tos/lib/net/b6lowpan/interfaces/UDP.nc and is simple:
+
+interface UDP {
+
+  /*
+   * bind a local address.  to cut down memory requirements and handle the 
+   * common case well, you can only bind a port; all local interfaces are 
+   * implicitly bound.  the port should be passed in host byte-order (is 
+   * this confusing?
+   */
+  command error_t bind(uint16_t port);
+
+  /*
+   * send a payload to the socket address indicated
+   * once the call returns, the stack has no claim on the buffer pointed to
+   */ 
+  command error_t sendto(struct sockaddr_in6 *dest, void *payload, 
+                         uint16_t len);
+
+  /*
+   * indicate that the stack has finished writing data into the
+   * receive buffer.  if error is not SUCCESS, the payload does not
+   * contain valid data and the src pointer should not be used.
+   */
+  event void recvfrom(struct sockaddr_in6 *src, void *payload, 
+                      uint16_t len, struct ip_metadata *meta);
+
+}
+
+Usage
+----------------------------------------------------------------------
+
+Each socket must be allocated using the generic component UdpSocketC.
+
+For clients, no initialization is necessary; they may send to a
+destination without calling bind.  The stack will allocate a unique
+ephemeral port number and send out the datagram.
+
+Servers wishing to provide a service using a well-known port should
+call bind() on that port number before generating datagrams.
+
+Example
+----------------------------------------------------------------------
+
+The simplest server is an echo service running on port 7.
+
+Because of the buffer semantics, it is safe to call send directly from
+a receive event handler.
+
+  event void Boot.booted() {
+    call Echo.bind(7);
+  }
+
+  event void Echo.recvfrom(struct sockaddr_in6 *from, void *data,
+                           uint16_t len, struct ip_metadata *meta) {
+    call Echo.sendto(from, data, len);
+  }
+
+The wiring is as follows. 
+
+  components new UdpSocketC();
+  UDPEchoP.Echo -> UdpSocketC;
index 05214b7a0057199ff2d692dc1e3c61f9ab21f3ed..2b74bc9faca0403e815465ab946d6e293863b430 100644 (file)
@@ -14,6 +14,10 @@ interface IP {
    */ 
   command error_t send(struct split_ip_msg *msg);
 
+  command error_t bareSend(struct split_ip_msg *msg, 
+                           struct ip6_route *route,
+                           int flags);
+
   /*
    * indicate that the stack has finished writing data into the
    * receive buffer. 
index 38d308462107a70b67fd4942f69ed1d270071f16..b681950bab15b48968bb868dc7963dc27e8cced9 100644 (file)
@@ -22,8 +22,8 @@
 #include <6lowpan.h>
 
 interface IPAddress {
-  command hw_addr_t getShortAddr();
-  command void setShortAddr(hw_addr_t newaddr);
+  command ieee154_saddr_t getShortAddr();
+  command void setShortAddr(ieee154_saddr_t newaddr);
 
   command struct in6_addr *getPublicAddr();
   command void getLLAddr(struct in6_addr *addr);
diff --git a/tos/lib/net/blip/interfaces/IPExtensions.nc b/tos/lib/net/blip/interfaces/IPExtensions.nc
new file mode 100644 (file)
index 0000000..eb6f5c3
--- /dev/null
@@ -0,0 +1,19 @@
+
+interface IPExtensions {
+
+  command struct tlv_hdr *findTlv(struct ip6_ext *ext, uint8_t tlv);
+
+  event void handleExtensions(uint8_t label,
+                              struct ip6_hdr *iph,
+                              struct ip6_ext *hop,
+                              struct ip6_ext *dst,
+                              struct ip6_route *route,
+                              uint8_t nxt_hdr);
+
+
+  /*
+   * will be called once for each fragment when sending or forwarding
+   */
+  event void reportTransmission(uint8_t label, send_policy_t *send);
+
+}
index 8c0f4dd6f921d447b1051325de3f238cb4011c2d..873280abe7625d32d0ad73e862b8fd44ade96c86 100644 (file)
@@ -45,9 +45,9 @@ interface IPRouting {
    *     and spacing between them.
    *
    */ 
-  command error_t getNextHop(struct ip6_hdr *hdr, 
-                             struct source_header *sh,
-                             hw_addr_t prev_hop,
+  command error_t getNextHop(struct ip6_hdr   *hdr, 
+                             struct ip6_route *routing_hdr,
+                             ieee154_saddr_t prev_hop,
                              send_policy_t *ret);
 
 
@@ -63,7 +63,7 @@ interface IPRouting {
    * 
    *
    */
-  command void reportAdvertisement(hw_addr_t neigh, uint8_t hops, 
+  command void reportAdvertisement(ieee154_saddr_t neigh, uint8_t hops, 
                                              uint8_t lqi, uint16_t cost);
 
   /*
@@ -71,22 +71,17 @@ interface IPRouting {
    *  the rssi of the received packet.
    *
    */
-  command void reportReception(hw_addr_t neigh, uint8_t lqi);
-
-  /*
-   * the result of sending to a neighbor.
-   */
-  command void reportTransmission(send_policy_t *send);
+  command void reportReception(ieee154_saddr_t neigh, uint8_t lqi);
 
   /*
    * @returns TRUE if the routing engine has established a default route.
    */
   command bool hasRoute();
 
-  command void insertRoutingHeaders(struct split_ip_msg *msg);
+  command struct ip6_route *insertRoutingHeader(struct split_ip_msg *msg);
   
 #ifdef CENTRALIZED_ROUTING
-  command error_t installFlowEntry(struct rinstall_header* rih, bool isMine);
+  // command error_t installFlowEntry(struct rinstall_header* rih, bool isMine);
 
   command void clearFlows();
 #endif
diff --git a/tos/lib/net/blip/interfaces/InternalIPExtension.nc b/tos/lib/net/blip/interfaces/InternalIPExtension.nc
new file mode 100644 (file)
index 0000000..e6f6958
--- /dev/null
@@ -0,0 +1,8 @@
+
+interface InternalIPExtension {
+
+  command void addHeaders(struct split_ip_msg *msg, uint8_t nxt_hdr, uint16_t label);
+
+  command void free();
+
+}
diff --git a/tos/lib/net/blip/interfaces/TLVHeader.nc b/tos/lib/net/blip/interfaces/TLVHeader.nc
new file mode 100644 (file)
index 0000000..faeb368
--- /dev/null
@@ -0,0 +1,9 @@
+
+#include <ip.h>
+
+interface TLVHeader {
+  event struct tlv_hdr *getHeader(int label,int nxt_hdr,
+                                  struct ip6_hdr *msg);
+
+  event void free();
+}
index 25f66ecba87e5b787447247e835289d921caf271..a87bb019663e464cc67858eec34219a2f7379c31 100644 (file)
@@ -4,14 +4,16 @@ interface Tcp {
 
   /*
    * Bind the socket to a local address
+   * 
    */
   command error_t bind(uint16_t port);
 
   /*
    * Accept an incomming connection.
+   *
+   * the app should return FALSE to reject the connection attempt
    */
   event bool accept(struct sockaddr_in6 *from, 
-                    void **rx_buf, int *rx_buf_len,
                     void **tx_buf, int *tx_buf_len);
 
   /*
@@ -20,7 +22,6 @@ interface Tcp {
    * The socket should not be used until connectDone is signaled.
    */
   command error_t connect(struct sockaddr_in6 *dest,
-                          void *rx_buf, int rx_buf_len,
                           void *tx_buf, int tx_buf_len);
   event void connectDone(error_t e);
 
@@ -36,6 +37,7 @@ interface Tcp {
    * terminate a connection.
    */
   command error_t close();
+  command error_t abort();
 
   /*
    * notify the app that the socket connection has been closed or
@@ -43,4 +45,11 @@ interface Tcp {
    * local side has given up.
    */
   event void closed(error_t e);
+
+  /* 
+   * returns TRUE if all previously sent data has been ACKed
+   */
+  event void acked();
+
+
 }
index 1a0e99ef3551d6e9a3aa3a3c97feabde1a818f35..58489f2b23f79ea3899b8f15ff8502f710760068 100644 (file)
@@ -82,6 +82,16 @@ typedef struct BootArgs {
 enum {
   NWPROG_CMD_ERASE = 1,
   NWPROG_CMD_WRITE = 2,
+  NWPROG_CMD_READ  = 3,
+  NWPROG_CMD_LIST  = 4,
+  NWPROG_CMD_BOOT  = 5,
+  NWPROG_CMD_REBOOT= 6,
+  NWPROG_CMD_READDONE = 7,
+  NWPROG_CMD_IMAGEIFO = 8,
+};
+
+enum {
+  NWPROG_ERROR_OK = 0,
 };
 
 enum{
@@ -89,15 +99,27 @@ enum{
   PATCH_CMD_COPY   = 17,
 };
 
+nx_struct ShortDelugeIdent {
+  nx_uint8_t   appname[16];
+  nx_uint8_t   username[16];
+  nx_uint8_t   hostname[16];
+  nx_uint32_t  timestamp;
+};
+
 typedef nx_struct prog_req {
   nx_uint8_t cmd;
   nx_uint8_t imgno;
-  nx_uint16_t offset;
+  nx_union {
+    nx_uint16_t offset;
+    nx_uint16_t when;
+    nx_uint16_t nimages;
+  } cmd_data;
   nx_uint8_t data[0];
 } prog_req_t;
 
 typedef nx_struct prog_reply {
   nx_uint8_t error;
+  nx_uint8_t pad;
   nx_struct prog_req req;
 } prog_reply_t;
 
index 3796ec5ea488c33f1cdc5ba24413e6b3f2e0beae..960c538046cf6ebd7db5251c6026e3992a42fd51 100644 (file)
@@ -1,4 +1,5 @@
 
+#include <BinaryShell.h>
 #include "StorageVolumes.h"
 #include "Deluge.h"
 
@@ -7,7 +8,7 @@ configuration NWProgC {
 } implementation {
 
   // send and receive pages
-  components MainC, IPDispatchC;
+  components MainC, new UdpSocketC();
   components NetProgC, NWProgP;
 
   BootImage = NWProgP;
@@ -19,10 +20,15 @@ configuration NWProgC {
   components new BlockWriterC(VOLUME_DELUGE2) as BlockWriterDeluge2;
   components new BlockWriterC(VOLUME_DELUGE3) as BlockWriterDeluge3;
 
+  components new BlockReaderC(VOLUME_GOLDENIMAGE) as BlockReaderDeluge0;
+  components new BlockReaderC(VOLUME_DELUGE1) as BlockReaderDeluge1;
+  components new BlockReaderC(VOLUME_DELUGE2) as BlockReaderDeluge2;
+  components new BlockReaderC(VOLUME_DELUGE3) as BlockReaderDeluge3;
+
   NWProgP.Boot -> MainC;
   NWProgP.NetProg -> NetProgC;
   NWProgP.StorageMap -> BlockStorageManagerC;
-  NWProgP.Recv -> IPDispatchC.UDP[5213];
+  NWProgP.Recv -> UdpSocketC; // IPDispatchC.UDP[5213];
   NWProgP.Resource -> BlockStorageLockClientC;
 
   NWProgP.BlockWrite[VOLUME_GOLDENIMAGE] -> BlockWriterDeluge0;
@@ -30,8 +36,19 @@ configuration NWProgC {
   NWProgP.BlockWrite[VOLUME_DELUGE2] -> BlockWriterDeluge2;
   NWProgP.BlockWrite[VOLUME_DELUGE3] -> BlockWriterDeluge3;
 
+  NWProgP.BlockRead[VOLUME_GOLDENIMAGE] -> BlockReaderDeluge0;
+  NWProgP.BlockRead[VOLUME_DELUGE1] -> BlockReaderDeluge1;
+  NWProgP.BlockRead[VOLUME_DELUGE2] -> BlockReaderDeluge2;
+  NWProgP.BlockRead[VOLUME_DELUGE3] -> BlockReaderDeluge3;
+
+#ifdef BINARY_SHELL
+  components BinaryShellC;
+  NWProgP.ShellCommand -> BinaryShellC.BinaryCommand[BSHELL_NWPROG];
+#else
   components new ShellCommandC("nwprog");
   NWProgP.ShellCommand -> ShellCommandC;
+#endif
+
   components new TimerMilliC();
   NWProgP.RebootTimer -> TimerMilliC;
   components new DelugeMetadataClientC();
index 5974126f2045315df13d126f3a19284b3ba47440..ddeebb096468068626c76f03aef1b3130fddb95c 100644 (file)
@@ -1,9 +1,10 @@
 
 #include <Storage.h>
 #include <Shell.h>
+#include <BinaryShell.h>
 #include "imgNum2volumeId.h"
 #include "Deluge.h"
-
+#include "PrintfUART.h"
 module NWProgP {
   provides interface BootImage;
   uses {
@@ -11,12 +12,19 @@ module NWProgP {
     interface UDP as Recv;
     interface StorageMap[uint8_t imag_num];
     interface NetProg;
+    interface BlockRead[uint8_t img_num];
     interface BlockWrite[uint8_t img_num];
     interface Resource;
-    interface ShellCommand;
     interface DelugeMetadata;
     interface Timer<TMilli> as RebootTimer;
+
     event void storageReady();
+
+#ifdef BINARY_SHELL
+    interface BinaryCommand as ShellCommand;
+#else
+    interface ShellCommand;
+#endif
   }
 } implementation {
 
@@ -27,6 +35,20 @@ module NWProgP {
   uint8_t state;
   struct sockaddr_in6 endpoint;
   prog_reply_t reply;
+  prog_reply_t *read_buffer;
+
+  // SDH : if this is defined, we read back each packet after we write
+  // it and check that it matches.  It turns out that this doesn't
+  // actually guarantee you much, due to buffering.
+#undef PARANOID
+
+#ifdef PARANOID
+  bool paranoid_read;
+  uint16_t cmp_len;
+  uint8_t cmp_img;
+  uint32_t cmp_off;
+  uint8_t cmp_buf[256];
+#endif
 
   // Begin-added by Jaein Jeong
   command error_t BootImage.erase(uint8_t img_num) {
@@ -44,7 +66,11 @@ module NWProgP {
   }
 
   event void Boot.booted() {
+#ifdef PARANOID
+    paranoid_read = FALSE;
+#endif
     state = S_IDLE;
+    call Recv.bind(5213);
   }
 
   void sendDone(error_t error) {
@@ -59,6 +85,7 @@ module NWProgP {
     uint8_t imgNum = imgNum2volumeId(req->imgno);
     error_t error = FAIL;
     void *buffer;
+
     // just copy the payload out and write it into flash
     // we'll send the ack from the write done event.
     if (state != S_IDLE) return;
@@ -76,17 +103,45 @@ module NWProgP {
         break;
       case NWPROG_CMD_WRITE:
         len -= sizeof(prog_req_t);
+
+#ifdef PARANOID
+        if (len > sizeof(cmp_buf)) {
+          error = ENOMEM;
+          break;
+        }
+        memcpy(cmp_buf, req->data, len);
+        cmp_len = len;
+        cmp_off = req->cmd_data.offset;
+        cmp_img = imgNum;
+#endif
+        
         buffer = ip_malloc(len);
         if (buffer == NULL) {
           error = ENOMEM;
           break;
         }
         memcpy(buffer, req->data, len);
-        error = call BlockWrite.write[imgNum](req->offset,
+        error = call BlockWrite.write[imgNum](req->cmd_data.offset,
                                               buffer,
                                               len);
         if (error != SUCCESS) ip_free(buffer);
         break;
+      case NWPROG_CMD_READ: {
+
+        read_buffer = (prog_reply_t *)ip_malloc(64 + sizeof(prog_reply_t));
+        if (read_buffer == NULL) {
+          error = ENOMEM;
+          break;
+        }
+        memcpy(&read_buffer->req, req, sizeof(prog_req_t));
+        error = call BlockRead.read[imgNum](req->cmd_data.offset,
+                                            read_buffer->req.data,
+                                            64);
+        if (error != SUCCESS) {
+          ip_free(read_buffer);
+        }
+        break;
+      }
       default:
         error = FAIL;
       }
@@ -94,7 +149,9 @@ module NWProgP {
 
     if (error != SUCCESS) {
       sendDone(error);
-      call Resource.release();
+      if (call Resource.isOwner()) {
+        call Resource.release();
+      }
     } else {
       state = S_BUSY;
     }
@@ -102,10 +159,81 @@ module NWProgP {
 
   event void BlockWrite.writeDone[uint8_t img_num](storage_addr_t addr, void* buf, storage_len_t len, error_t error) {
     if (state != S_BUSY) return;
-    sendDone(error);
+
+#ifdef PARANOID
+    if (len != cmp_len) {
+      printfUART("WARNING: write length changed from %i to %lu!\n", cmp_len, len);
+    }
+    if (addr != cmp_off) {
+      printfUART("WARNING: write address changed from %li to %li!\n", cmp_off, addr);
+    }
+    if (img_num != cmp_img) {
+      printfUART("WARNING: write volume changed from %i to %i\n", cmp_img, img_num);
+    }
+    if (memcmp(buf, cmp_buf, cmp_len) != 0) {
+      printfUART("WARNING: write data changed during call!\n");
+    }
+    memset(buf, 0, cmp_len);
+    if (call BlockRead.read[cmp_img](cmp_off, buf, cmp_len) == SUCCESS) {
+      paranoid_read = TRUE;
+      return;
+    } 
+
+
+#else
+    ip_free(buf);
+#endif
+
+    if (error == SUCCESS) {
+      call BlockWrite.sync[img_num]();
+    } else {
+      state = S_IDLE;
+      call Resource.release();
+      sendDone(error);
+    }
+  }
+  event void BlockRead.readDone[uint8_t img_num](storage_addr_t addr, void* buf, storage_len_t len, error_t error) {
+
+#ifdef PARANOID
+    if (paranoid_read) {
+      if (len != cmp_len) {
+        printfUART("WARNING: read length changed from %u to %lu!\n", cmp_len, len);
+      }
+      if (addr != cmp_off) {
+        printfUART("WARNING: read address changed from %li to %li!\n", cmp_off, addr);
+      }
+      if (img_num != cmp_img) {
+        printfUART("WARNING: read volume changed from %i to %i\n", cmp_img, img_num);
+      }
+      if (memcmp(buf, cmp_buf, cmp_len) != 0) {
+        printfUART("WARNING: write data changed during call!\n");
+      } else {
+        printfUART("SUCCESS: write verified!\n");
+      }
+
+      paranoid_read = FALSE;
+      ip_free(buf);
+      if (error == SUCCESS) {
+        call BlockWrite.sync[img_num]();
+      } else {
+        call Resource.release();
+        state = S_IDLE;
+        sendDone(error);
+      }
+
+      return;
+    }
+#endif
+
+
+    if (state != S_BUSY || buf != read_buffer->req.data) return;
     call Resource.release();
+
+    read_buffer->error = error;
+    call Recv.sendto(&endpoint, read_buffer, sizeof(prog_reply_t) + 64);
+
+    ip_free(read_buffer);
     state = S_IDLE;
-    ip_free(buf);
   }
 
   event void BlockWrite.eraseDone[uint8_t img_num](error_t error) {
@@ -134,7 +262,6 @@ module NWProgP {
   /*
    * Shell command implementation
    */
-  char *nwprog_help_str = "nwprog [list | boot <imgno> [when] | reboot]\n";
   uint8_t nwprog_currentvol, nwprog_validvols;
   uint8_t boot_image;
 
@@ -151,21 +278,45 @@ module NWProgP {
     char *reply_buf = call ShellCommand.getBuffer(MAX_REPLY_LEN);
     if (error == SUCCESS) {
       if (ident->uidhash != DELUGE_INVALID_UID) {
+#ifdef BINARY_SHELL
+        nx_struct cmd_payload *payload = (nx_struct cmd_payload *)reply_buf;
+        prog_req_t *rep = (prog_req_t *)payload->data;
+        nx_struct ShortDelugeIdent *i = (nx_struct ShortDelugeIdent *)rep->data;
+        rep->cmd = NWPROG_CMD_IMAGEIFO;
+        rep->imgno = volumeID2imgNum(imgNum);
+        memcpy(i->appname, ident->appname, 16);
+        memcpy(i->username, ident->username, 16);
+        memcpy(i->hostname, ident->hostname, 16);
+        i->timestamp = ident->timestamp;
+        nwprog_validvols++;
+        call ShellCommand.write(payload, sizeof(nx_struct cmd_payload) + 
+                                sizeof(prog_reply_t) + sizeof(nx_struct ShortDelugeIdent));
+
+#else
         len = snprintf(reply_buf, MAX_REPLY_LEN,
                        "image: %i\n\t[size: %li]\n\t[app: %s]\n\t[user: %s]\n\t[host: %s]\n\t[arch: %s]\n\t[time: 0x%lx]\n",
                        volumeID2imgNum(imgNum), ident->size, (char *)ident->appname, (char *) ident->username,
                        (char *)ident->hostname, (char *)ident->platform, (uint32_t)ident->timestamp);
         nwprog_validvols++;
         call ShellCommand.write(reply_buf, len);
+#endif
       }
       
     }
     if (++nwprog_currentvol < DELUGE_NUM_VOLUMES) {
       call DelugeMetadata.read(imgNum2volumeId(nwprog_currentvol));
     } else {
+#ifdef BINARY_SHELL
+      nx_struct cmd_payload *payload = (nx_struct cmd_payload *)reply_buf;
+      prog_req_t *rep = (prog_req_t *)payload->data; 
+      rep->cmd = NWPROG_CMD_READDONE;
+      rep->cmd_data.nimages = nwprog_validvols;
+      call ShellCommand.write(payload, sizeof(nx_struct cmd_payload) + sizeof(prog_req_t));
+#else
       len = snprintf(reply_buf, MAX_REPLY_LEN,
                      "%i valid image(s)\n", nwprog_validvols);
       call ShellCommand.write(reply_buf, len);
+#endif
     }
   }
 
@@ -173,8 +324,34 @@ module NWProgP {
     call BootImage.boot(boot_image);
   }
 
+#ifdef BINARY_SHELL
+  event void ShellCommand.dispatch(nx_struct cmd_payload *data, int len) {
+    nx_struct prog_req *req = (nx_struct prog_req *)data->data;
+    nx_struct cmd_payload *rep;
+    prog_reply_t *rc;
+    int error = NWPROG_ERROR_OK;
+
+    switch (req->cmd) {
+    case NWPROG_CMD_LIST:
+      nwprog_currentvol = 0;
+      nwprog_validvols = 0;
+      call DelugeMetadata.read(imgNum2volumeId(nwprog_currentvol));
+      return;
+      break;
+    case NWPROG_CMD_BOOT:
+      call ShellCommand.write(data, len);
 
+      boot_image = imgNum2volumeId(req->imgno);
+      call RebootTimer.startOneShot(req->cmd_data.when);
+      break;
+    case NWPROG_CMD_REBOOT:
+      call BootImage.reboot();
+      break;
+    }
+  }
+#else
   event char *ShellCommand.eval(int argc, char **argv) {
+    char *nwprog_help_str = "nwprog [list | boot <imgno> [when] | reboot]\n";
     if (argc >= 2) {
       if (memcmp(argv[1], "list", 4) == 0) {
         nwprog_currentvol = 0;
@@ -182,6 +359,7 @@ module NWProgP {
         call DelugeMetadata.read(imgNum2volumeId(nwprog_currentvol));
         return NULL;
       } else if (memcmp(argv[1], "boot", 4) == 0 && (argc == 3 || argc == 4)) {
+
         uint32_t when = 15;
         boot_image = atoi(argv[2]),
         boot_image = imgNum2volumeId(boot_image);
@@ -198,18 +376,20 @@ module NWProgP {
         return NULL;
       } else if (memcmp(argv[1], "reboot", 6) == 0) {
         call BootImage.reboot();
-      } else if (memcmp(argv[1], "erase", 5) == 0 && argc == 3) {
-        uint8_t img = atoi(argv[2]);
-        img = imgNum2volumeId(img);
-        
         return NULL;
-      }
+      } 
     }
     return nwprog_help_str;
   }
+#endif
 
   default command error_t BlockWrite.write[uint8_t imgNum](storage_addr_t addr, void* buf, storage_len_t len) { return FAIL; }
   default command error_t BlockWrite.erase[uint8_t imgNum]() { return FAIL; }
   default command error_t BlockWrite.sync[uint8_t imgNum]() { return FAIL; }
+  
+ default command error_t BlockRead.read[uint8_t imgNum](storage_addr_t addr, void* buf, storage_len_t len) {return FAIL;}
+
+  event void BlockRead.computeCrcDone[uint8_t imgNum](storage_addr_t addr, storage_len_t len,uint16_t crc, error_t error) {}
+
 
 }
index 04e289008cc30e87c06753bc59fd671022a9991c..c9bdc25b0cb7d92fdb598a901606568aea4ecff4 100644 (file)
@@ -1,3 +1,24 @@
+/*
+ * "Copyright (c) 2008, 2009 The Regents of the University  of California.
+ * All rights reserved."
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice, the following
+ * two paragraphs and the author appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
+ *
+ */
 #ifndef _SHELL_H
 #define _SHELL_H
 
index 8de6f888dd8f3368bb7e60d9ba78c98445ccbdec..7c968aae8f2ab66dcb6dee461381076a046a941e 100644 (file)
@@ -94,10 +94,17 @@ module UDPShellP {
     call UDP.bind(2000);
   }
 
+
+#define DEREF(X)  #X
+#define QUOTE(X)  DEREF(X)
   char reply_buf[MAX_REPLY_LEN];
   char *help_str = "sdsh-0.9\tbuiltins: [help, echo, ping6, uptime, ident]\n";
-  const char *ping_fmt = "%x%02x:%x%02x:%x%02x:%x%02x:%x%02x:%x%02x:%x%02x:%x%02x: icmp_seq=%i ttl=%i time=%i ms\n";
+  const char *ping_fmt = " icmp_seq=%i ttl=%i time=%i ms\n";
   const char *ping_summary = "%i packets transmitted, %i received\n";
+  char *ident_string = "\t[app: "
+    IDENT_APPNAME "]\n\t[user: " IDENT_USERNAME "]\n\t[host: " IDENT_HOSTNAME
+    "]\n\t[time: " QUOTE(IDENT_TIMESTAMP) "]\n";
+  
 
   void action_help(int argc, char **argv) {
     int i = 0;
@@ -179,11 +186,7 @@ module UDPShellP {
   }
 
   void action_ident(int argc, char **argv) {
-    int len;
-    len = snprintf(reply_buf, MAX_REPLY_LEN, 
-                   "\t[app: %s]\n\t[user: %s]\n\t[host: %s]\n\t[time: 0x%lx]\n",
-                   IDENT_APPNAME, IDENT_USERNAME, IDENT_HOSTNAME, IDENT_TIMESTAMP);
-    call UDP.sendto(&session_endpoint, reply_buf, len);
+    call UDP.sendto(&session_endpoint, ident_string, strlen(ident_string));
   }
 
   // commands 
@@ -258,13 +261,12 @@ module UDPShellP {
 
   event void ICMPPing.pingReply(struct in6_addr *source, struct icmp_stats *stats) {
     int len;
-    len = snprintf(reply_buf, MAX_REPLY_LEN, ping_fmt,
-                   source->s6_addr[0],source->s6_addr[1],source->s6_addr[2],source->s6_addr[3],
-                   source->s6_addr[4],source->s6_addr[5],source->s6_addr[6],source->s6_addr[7],
-                   source->s6_addr[8],source->s6_addr[9],source->s6_addr[10],source->s6_addr[11],
-                   source->s6_addr[12],source->s6_addr[13],source->s6_addr[14],source->s6_addr[15],
-                   stats->seq, stats->ttl, stats->rtt);
-    call UDP.sendto(&session_endpoint, reply_buf, len);
+    len = inet_ntop6(source, reply_buf, MAX_REPLY_LEN);
+    if (len > 0) {
+      len += snprintf(reply_buf + len - 1, MAX_REPLY_LEN - len + 1, ping_fmt,
+                      stats->seq, stats->ttl, stats->rtt);
+      call UDP.sendto(&session_endpoint, reply_buf, len);
+    }
   }
 
   event void ICMPPing.pingDone(uint16_t ping_rcv, uint16_t ping_n) {
index 52e262f13480d56d5437e9ad0880debd6f53fa72..3cb912e7a851b29cfa9e436ab2dd486cb8bfd888 100644 (file)
@@ -1,3 +1,24 @@
+/*
+ * "Copyright (c) 2008, 2009 The Regents of the University  of California.
+ * All rights reserved."
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice, the following
+ * two paragraphs and the author appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
+ *
+ */
 
 #include <stdlib.h>
 #include "table.h"
index 346e940a63f0d6b5e9150f031449f7359ca37b1b..3f2914b2aaa1eb618e7b0073c62cdd2f5eaa096e 100644 (file)
@@ -1,3 +1,24 @@
+/*
+ * "Copyright (c) 2008, 2009 The Regents of the University  of California.
+ * All rights reserved."
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice, the following
+ * two paragraphs and the author appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
+ *
+ */
 #ifndef TABLE_H_
 #define TABLE_H_