From 3d5c78e867d6fd52e44894e93e4bd0c172071522 Mon Sep 17 00:00:00 2001 From: sdhsdh Date: Sun, 9 Aug 2009 23:36:05 +0000 Subject: [PATCH] commit svn HEAD of blip into core to start merge testing --- apps/IPBaseStation/BaseStationC.nc | 28 +- apps/IPBaseStation/BaseStationP.nc | 69 +- apps/IPBaseStation/Makefile | 16 +- apps/TCPEcho/HttpdP.nc | 152 ++ apps/TCPEcho/Makefile | 26 + apps/TCPEcho/TCPEchoC.nc | 66 + apps/TCPEcho/TCPEchoP.nc | 161 ++ apps/TCPEcho/UDPReport.h | 36 + apps/UDPEcho/Makefile | 15 +- apps/UDPEcho/Makefile.local | 4 +- apps/UDPEcho/UDPEchoC.nc | 9 +- apps/UDPEcho/UDPEchoP.nc | 42 +- apps/UDPEcho/UDPReport.h | 6 +- apps/UDPEcho/util/MySQLListener.py | 2 +- apps/UDPEcho/util/UdpReport.py | 1371 +++++++++++------ support/make/blip.extra | 26 + support/sdk/c/blip/Makefile | 12 +- support/sdk/c/blip/driver/Makefile | 36 +- support/sdk/c/blip/driver/config.c | 60 +- support/sdk/c/blip/driver/config.h | 28 +- support/sdk/c/blip/driver/hashtable.c | 6 +- support/sdk/c/blip/driver/logging.c | 29 +- support/sdk/c/blip/driver/logging.h | 9 +- support/sdk/c/blip/driver/mcast.c | 212 +++ support/sdk/c/blip/driver/mcast.h | 30 + support/sdk/c/blip/driver/netlink.c | 213 +++ support/sdk/c/blip/driver/netlink.h | 40 + support/sdk/c/blip/driver/nwstate.c | 153 +- support/sdk/c/blip/driver/nwstate.h | 31 +- support/sdk/c/blip/driver/radvd-1.0/config.h | 21 + support/sdk/c/blip/driver/radvd-1.0/process.c | 14 +- support/sdk/c/blip/driver/radvd-wrapper.c | 23 + support/sdk/c/blip/driver/routing.c | 254 ++- support/sdk/c/blip/driver/routing.h | 33 +- support/sdk/c/blip/driver/serial_tun.c | 1057 +++++++++---- support/sdk/c/blip/driver/tun_dev.c | 17 +- support/sdk/c/blip/driver/vty/Makefile | 6 + support/sdk/c/blip/driver/vty/test_srv.c | 69 + support/sdk/c/blip/driver/vty/util.c | 45 + support/sdk/c/blip/driver/vty/vty.c | 318 ++++ support/sdk/c/blip/driver/vty/vty.h | 74 + support/sdk/c/blip/include/6lowpan.h | 75 +- support/sdk/c/blip/include/TrackFlows.h | 68 + support/sdk/c/blip/include/devconf.h | 10 +- support/sdk/c/blip/include/ip.h | 133 +- support/sdk/c/blip/include/ip_malloc.h | 21 + support/sdk/c/blip/include/lib6lowpan.h | 94 +- support/sdk/c/blip/lib6lowpan/Makefile | 13 +- support/sdk/c/blip/lib6lowpan/ip_malloc.c | 21 + support/sdk/c/blip/lib6lowpan/lib6lowpan.c | 14 +- support/sdk/c/blip/lib6lowpan/lib6lowpanIP.c | 109 +- support/sdk/c/blip/libtcp/Makefile | 14 +- support/sdk/c/blip/libtcp/circ.c | 152 +- support/sdk/c/blip/libtcp/circ.h | 28 +- support/sdk/c/blip/libtcp/tcplib.c | 310 ++-- support/sdk/c/blip/libtcp/tcplib.h | 79 +- support/sdk/c/blip/libtcp/test_circ.c | 76 +- support/sdk/c/blip/libtcp/test_server.c | 94 +- support/sdk/c/blip/serial_tun.conf | 4 +- tools/tinyos/misc/tos-nwprog | 308 ++++ tos/lib/net/blip/ICMP.h | 14 + tos/lib/net/blip/ICMPResponderP.nc | 24 +- tos/lib/net/blip/IPAddressP.nc | 5 +- tos/lib/net/blip/IPDispatch.h | 61 +- tos/lib/net/blip/IPDispatchC.nc | 37 +- tos/lib/net/blip/IPDispatchP.nc | 266 ++-- tos/lib/net/blip/IPExtensionP.nc | 144 ++ tos/lib/net/blip/IPExtensionsP.nc | 33 + tos/lib/net/blip/IPRoutingP.nc | 680 ++++++-- tos/lib/net/blip/Statistics.h | 88 ++ tos/lib/net/blip/TcpP.nc | 54 +- tos/lib/net/blip/TrackFlowsC.nc | 16 + tos/lib/net/blip/TrackFlowsP.nc | 140 ++ tos/lib/net/blip/UdpC.nc | 6 +- tos/lib/net/blip/UdpP.nc | 58 +- tos/lib/net/blip/doc/README | 104 ++ tos/lib/net/blip/doc/README-IP | 56 + tos/lib/net/blip/doc/README-MERAKI | 53 + tos/lib/net/blip/doc/README-NWPROG | 70 + tos/lib/net/blip/doc/README-SHELL | 55 + tos/lib/net/blip/doc/README-SIM | 43 + tos/lib/net/blip/doc/README-TCP | 101 ++ tos/lib/net/blip/doc/README-UDP | 70 + tos/lib/net/blip/interfaces/IP.nc | 4 + tos/lib/net/blip/interfaces/IPAddress.nc | 4 +- tos/lib/net/blip/interfaces/IPExtensions.nc | 19 + tos/lib/net/blip/interfaces/IPRouting.nc | 19 +- .../blip/interfaces/InternalIPExtension.nc | 8 + tos/lib/net/blip/interfaces/TLVHeader.nc | 9 + tos/lib/net/blip/interfaces/Tcp.nc | 13 +- tos/lib/net/blip/nwprog/Deluge.h | 24 +- tos/lib/net/blip/nwprog/NWProgC.nc | 21 +- tos/lib/net/blip/nwprog/NWProgP.nc | 204 ++- tos/lib/net/blip/shell/Shell.h | 21 + tos/lib/net/blip/shell/UDPShellP.nc | 28 +- tos/lib/net/blip/table.c | 21 + tos/lib/net/blip/table.h | 21 + 97 files changed, 7145 insertions(+), 1891 deletions(-) create mode 100644 apps/TCPEcho/HttpdP.nc create mode 100644 apps/TCPEcho/Makefile create mode 100644 apps/TCPEcho/TCPEchoC.nc create mode 100644 apps/TCPEcho/TCPEchoP.nc create mode 100644 apps/TCPEcho/UDPReport.h create mode 100644 support/make/blip.extra create mode 100644 support/sdk/c/blip/driver/mcast.c create mode 100644 support/sdk/c/blip/driver/mcast.h create mode 100644 support/sdk/c/blip/driver/netlink.c create mode 100644 support/sdk/c/blip/driver/netlink.h create mode 100644 support/sdk/c/blip/driver/vty/Makefile create mode 100644 support/sdk/c/blip/driver/vty/test_srv.c create mode 100644 support/sdk/c/blip/driver/vty/util.c create mode 100644 support/sdk/c/blip/driver/vty/vty.c create mode 100644 support/sdk/c/blip/driver/vty/vty.h create mode 100644 support/sdk/c/blip/include/TrackFlows.h create mode 100755 tools/tinyos/misc/tos-nwprog create mode 100644 tos/lib/net/blip/IPExtensionP.nc create mode 100644 tos/lib/net/blip/IPExtensionsP.nc create mode 100644 tos/lib/net/blip/Statistics.h create mode 100644 tos/lib/net/blip/TrackFlowsC.nc create mode 100644 tos/lib/net/blip/TrackFlowsP.nc create mode 100644 tos/lib/net/blip/doc/README create mode 100644 tos/lib/net/blip/doc/README-IP create mode 100644 tos/lib/net/blip/doc/README-MERAKI create mode 100644 tos/lib/net/blip/doc/README-NWPROG create mode 100644 tos/lib/net/blip/doc/README-SHELL create mode 100644 tos/lib/net/blip/doc/README-SIM create mode 100644 tos/lib/net/blip/doc/README-TCP create mode 100644 tos/lib/net/blip/doc/README-UDP create mode 100644 tos/lib/net/blip/interfaces/IPExtensions.nc create mode 100644 tos/lib/net/blip/interfaces/InternalIPExtension.nc create mode 100644 tos/lib/net/blip/interfaces/TLVHeader.nc diff --git a/apps/IPBaseStation/BaseStationC.nc b/apps/IPBaseStation/BaseStationC.nc index 6114950d..aa36022e 100644 --- a/apps/IPBaseStation/BaseStationC.nc +++ b/apps/IPBaseStation/BaseStationC.nc @@ -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 } diff --git a/apps/IPBaseStation/BaseStationP.nc b/apps/IPBaseStation/BaseStationP.nc index dc880a7d..20008a99 100644 --- a/apps/IPBaseStation/BaseStationP.nc +++ b/apps/IPBaseStation/BaseStationP.nc @@ -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 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; diff --git a/apps/IPBaseStation/Makefile b/apps/IPBaseStation/Makefile index 5a8dde88..f2135530 100644 --- a/apps/IPBaseStation/Makefile +++ b/apps/IPBaseStation/Makefile @@ -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 index 00000000..26b1046a --- /dev/null +++ b/apps/TCPEcho/HttpdP.nc @@ -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 index 00000000..d9c3d0a4 --- /dev/null +++ b/apps/TCPEcho/Makefile @@ -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 index 00000000..8351bbca --- /dev/null +++ b/apps/TCPEcho/TCPEchoC.nc @@ -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 index 00000000..43860892 --- /dev/null +++ b/apps/TCPEcho/TCPEchoP.nc @@ -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 +#include +#include +#include +#include + +#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 as StatusTimer; + + interface Statistics as IPStats; + interface Statistics as RouteStats; + interface Statistics as ICMPStats; + interface Statistics 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 index 00000000..2efaaa0e --- /dev/null +++ b/apps/TCPEcho/UDPReport.h @@ -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 + +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 diff --git a/apps/UDPEcho/Makefile b/apps/UDPEcho/Makefile index f10a2072..f883f1bd 100644 --- a/apps/UDPEcho/Makefile +++ b/apps/UDPEcho/Makefile @@ -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 diff --git a/apps/UDPEcho/Makefile.local b/apps/UDPEcho/Makefile.local index 9f5e04fb..a911f108 100644 --- a/apps/UDPEcho/Makefile.local +++ b/apps/UDPEcho/Makefile.local @@ -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 diff --git a/apps/UDPEcho/UDPEchoC.nc b/apps/UDPEcho/UDPEchoC.nc index 04322eb4..984f55d9 100644 --- a/apps/UDPEcho/UDPEchoC.nc +++ b/apps/UDPEcho/UDPEchoC.nc @@ -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 } diff --git a/apps/UDPEcho/UDPEchoP.nc b/apps/UDPEcho/UDPEchoP.nc index 05550203..eb10fc87 100644 --- a/apps/UDPEcho/UDPEchoP.nc +++ b/apps/UDPEcho/UDPEchoP.nc @@ -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 as StatusTimer; interface Statistics as IPStats; + interface Statistics as UDPStats; interface Statistics as RouteStats; interface Statistics 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)); } } diff --git a/apps/UDPEcho/UDPReport.h b/apps/UDPEcho/UDPReport.h index e1d7dfc9..2efaaa0e 100644 --- a/apps/UDPEcho/UDPReport.h +++ b/apps/UDPEcho/UDPReport.h @@ -22,10 +22,12 @@ #ifndef _UDPREPORT_H #define _UDPREPORT_H -#include +#include 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; diff --git a/apps/UDPEcho/util/MySQLListener.py b/apps/UDPEcho/util/MySQLListener.py index 0522ca41..4a240cf4 100644 --- a/apps/UDPEcho/util/MySQLListener.py +++ b/apps/UDPEcho/util/MySQLListener.py @@ -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) diff --git a/apps/UDPEcho/util/UdpReport.py b/apps/UDPEcho/util/UdpReport.py index 5b75951b..c42f8174 100644 --- a/apps/UDPEcho/util/UdpReport.py +++ b/apps/UDPEcho/util/UdpReport.py @@ -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 \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 index 00000000..06c0c7f6 --- /dev/null +++ b/support/make/blip.extra @@ -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 + diff --git a/support/sdk/c/blip/Makefile b/support/sdk/c/blip/Makefile index 38caf567..10cb1b93 100644 --- a/support/sdk/c/blip/Makefile +++ b/support/sdk/c/blip/Makefile @@ -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 diff --git a/support/sdk/c/blip/driver/Makefile b/support/sdk/c/blip/driver/Makefile index 1b0e3caf..b72b6bbf 100644 --- a/support/sdk/c/blip/driver/Makefile +++ b/support/sdk/c/blip/driver/Makefile @@ -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) diff --git a/support/sdk/c/blip/driver/config.c b/support/sdk/c/blip/driver/config.c index 4cbb4f8f..48e53a12 100644 --- a/support/sdk/c/blip/driver/config.c +++ b/support/sdk/c/blip/driver/config.c @@ -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 + */ #include #include @@ -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(); } diff --git a/support/sdk/c/blip/driver/config.h b/support/sdk/c/blip/driver/config.h index 0a79dd36..241771e9 100644 --- a/support/sdk/c/blip/driver/config.h +++ b/support/sdk/c/blip/driver/config.h @@ -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 + */ + #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 diff --git a/support/sdk/c/blip/driver/hashtable.c b/support/sdk/c/blip/driver/hashtable.c index 763357ed..64f11f86 100644 --- a/support/sdk/c/blip/driver/hashtable.c +++ b/support/sdk/c/blip/driver/hashtable.c @@ -7,6 +7,8 @@ #include #include +#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; } diff --git a/support/sdk/c/blip/driver/logging.c b/support/sdk/c/blip/driver/logging.c index 4df083db..610055ce 100644 --- a/support/sdk/c/blip/driver/logging.c +++ b/support/sdk/c/blip/driver/logging.c @@ -20,6 +20,8 @@ * */ #include +#include +#include #include #include #include @@ -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; diff --git a/support/sdk/c/blip/driver/logging.h b/support/sdk/c/blip/driver/logging.h index c0f98376..9a33426d 100644 --- a/support/sdk/c/blip/driver/logging.h +++ b/support/sdk/c/blip/driver/logging.h @@ -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 index 00000000..4cd011b7 --- /dev/null +++ b/support/sdk/c/blip/driver/mcast.c @@ -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 +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#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 \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 index 00000000..a0b9b1c3 --- /dev/null +++ b/support/sdk/c/blip/driver/mcast.h @@ -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 index 00000000..1ee12317 --- /dev/null +++ b/support/sdk/c/blip/driver/netlink.c @@ -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 +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#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 index 00000000..b6f03dec --- /dev/null +++ b/support/sdk/c/blip/driver/netlink.h @@ -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 + diff --git a/support/sdk/c/blip/driver/nwstate.c b/support/sdk/c/blip/driver/nwstate.c index 96575401..0ef8ed6b 100644 --- a/support/sdk/c/blip/driver/nwstate.c +++ b/support/sdk/c/blip/driver/nwstate.c @@ -24,11 +24,14 @@ #include #include #include +#include +#include #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 '\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); + } + } +} diff --git a/support/sdk/c/blip/driver/nwstate.h b/support/sdk/c/blip/driver/nwstate.h index 7374047d..c888e6a6 100644 --- a/support/sdk/c/blip/driver/nwstate.h +++ b/support/sdk/c/blip/driver/nwstate.h @@ -29,11 +29,17 @@ * */ +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 diff --git a/support/sdk/c/blip/driver/radvd-1.0/config.h b/support/sdk/c/blip/driver/radvd-1.0/config.h index b1c13a59..efd4219b 100644 --- a/support/sdk/c/blip/driver/radvd-1.0/config.h +++ b/support/sdk/c/blip/driver/radvd-1.0/config.h @@ -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. */ diff --git a/support/sdk/c/blip/driver/radvd-1.0/process.c b/support/sdk/c/blip/driver/radvd-1.0/process.c index bcd9589c..2bf38e9c 100644 --- a/support/sdk/c/blip/driver/radvd-1.0/process.c +++ b/support/sdk/c/blip/driver/radvd-1.0/process.c @@ -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, diff --git a/support/sdk/c/blip/driver/radvd-wrapper.c b/support/sdk/c/blip/driver/radvd-wrapper.c index b5562aa2..73e60596 100644 --- a/support/sdk/c/blip/driver/radvd-wrapper.c +++ b/support/sdk/c/blip/driver/radvd-wrapper.c @@ -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 @@ -158,5 +179,7 @@ int radvd_init(char *ifname, struct config *c) { // config_interface(); radvd_kickoff_adverts(); + set_debuglevel(0); + return sock; } diff --git a/support/sdk/c/blip/driver/routing.c b/support/sdk/c/blip/driver/routing.c index f883f32c..11059e14 100644 --- a/support/sdk/c/blip/driver/routing.c +++ b/support/sdk/c/blip/driver/routing.c @@ -24,6 +24,11 @@ #include #include #include +#include +#include +#include +#include +#include #include <6lowpan.h> #include @@ -31,51 +36,213 @@ #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"; */ - -} diff --git a/support/sdk/c/blip/driver/routing.h b/support/sdk/c/blip/driver/routing.h index cfb31934..c9c3eb45 100644 --- a/support/sdk/c/blip/driver/routing.h +++ b/support/sdk/c/blip/driver/routing.h @@ -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 diff --git a/support/sdk/c/blip/driver/serial_tun.c b/support/sdk/c/blip/driver/serial_tun.c index 0462f35a..53381e15 100644 --- a/support/sdk/c/blip/driver/serial_tun.c +++ b/support/sdk/c/blip/driver/serial_tun.c @@ -63,6 +63,10 @@ #include #include #include +#include +#include + +#include "TrackFlows.h" #include "tun_dev.h" #include "serialsource.h" @@ -79,41 +83,48 @@ #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(¤t_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 : switch to channel 'c'\r\n"); + VTY_printf(" dot : 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 : invalidate a router\r\n"); + VTY_printf(" add : 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 : add a new controller\r\n"); +#ifdef CENTRALIZED_ROUTING + VTY_printf(" install [reverse]: install a route between n1 and n2\r\n"); + VTY_printf(" uninstall : 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 \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 : print dot-file of topology\n"); - printf(" i : 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 [REV]\r\n", argv[0]); + VTY_flush(); +} + +void sh_uninstall(int fd, int argc, char **argv) { + VTY_HEAD; + if (argc != 3) { + VTY_printf("%s \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 \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(¤t_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] \n", argv[0]); +#ifndef SF_SRC + fatal("usage: %s [-c config] [-n] \n", argv[0]); #else fatal("usage: %s [-c config] \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; } diff --git a/support/sdk/c/blip/driver/tun_dev.c b/support/sdk/c/blip/driver/tun_dev.c index 684efb94..3caf41f8 100644 --- a/support/sdk/c/blip/driver/tun_dev.c +++ b/support/sdk/c/blip/driver/tun_dev.c @@ -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 index 00000000..69bf9a7d --- /dev/null +++ b/support/sdk/c/blip/driver/vty/Makefile @@ -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 index 00000000..a3c8f03b --- /dev/null +++ b/support/sdk/c/blip/driver/vty/test_srv.c @@ -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 +#include +#include +#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 index 00000000..583e41df --- /dev/null +++ b/support/sdk/c/blip/driver/vty/util.c @@ -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 index 00000000..b5611c41 --- /dev/null +++ b/support/sdk/c/blip/driver/vty/vty.c @@ -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 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 index 00000000..37bcca38 --- /dev/null +++ b/support/sdk/c/blip/driver/vty/vty.h @@ -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 + * + * 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 +#include + +// 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 diff --git a/support/sdk/c/blip/include/6lowpan.h b/support/sdk/c/blip/include/6lowpan.h index 76ddd758..65c26717 100644 --- a/support/sdk/c/blip/include/6lowpan.h +++ b/support/sdk/c/blip/include/6lowpan.h @@ -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 index 00000000..0e90c51e --- /dev/null +++ b/support/sdk/c/blip/include/TrackFlows.h @@ -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 +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 diff --git a/support/sdk/c/blip/include/devconf.h b/support/sdk/c/blip/include/devconf.h index 3a56d1b9..8d8a34cb 100644 --- a/support/sdk/c/blip/include/devconf.h +++ b/support/sdk/c/blip/include/devconf.h @@ -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; diff --git a/support/sdk/c/blip/include/ip.h b/support/sdk/c/blip/include/ip.h index e48163f8..666cc1f2 100644 --- a/support/sdk/c/blip/include/ip.h +++ b/support/sdk/c/blip/include/ip.h @@ -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 diff --git a/support/sdk/c/blip/include/ip_malloc.h b/support/sdk/c/blip/include/ip_malloc.h index dbd0db59..02e3e2e4 100644 --- a/support/sdk/c/blip/include/ip_malloc.h +++ b/support/sdk/c/blip/include/ip_malloc.h @@ -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_ diff --git a/support/sdk/c/blip/include/lib6lowpan.h b/support/sdk/c/blip/include/lib6lowpan.h index 8723c292..4596ac96 100644 --- a/support/sdk/c/blip/include/lib6lowpan.h +++ b/support/sdk/c/blip/include/lib6lowpan.h @@ -21,45 +21,58 @@ */ #ifndef _LIB6LOWPAN_H_ #define _LIB6LOWPAN_H_ - #include #include #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 +#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; diff --git a/support/sdk/c/blip/lib6lowpan/Makefile b/support/sdk/c/blip/lib6lowpan/Makefile index fb34df22..41faf032 100644 --- a/support/sdk/c/blip/lib6lowpan/Makefile +++ b/support/sdk/c/blip/lib6lowpan/Makefile @@ -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) diff --git a/support/sdk/c/blip/lib6lowpan/ip_malloc.c b/support/sdk/c/blip/lib6lowpan/ip_malloc.c index 0ace8e7a..9149efd3 100644 --- a/support/sdk/c/blip/lib6lowpan/ip_malloc.c +++ b/support/sdk/c/blip/lib6lowpan/ip_malloc.c @@ -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 #include diff --git a/support/sdk/c/blip/lib6lowpan/lib6lowpan.c b/support/sdk/c/blip/lib6lowpan/lib6lowpan.c index 3ebe2f67..b7b676cc 100644 --- a/support/sdk/c/blip/lib6lowpan/lib6lowpan.c +++ b/support/sdk/c/blip/lib6lowpan/lib6lowpan.c @@ -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 diff --git a/support/sdk/c/blip/lib6lowpan/lib6lowpanIP.c b/support/sdk/c/blip/lib6lowpan/lib6lowpanIP.c index 16b77d20..9fb8cea3 100644 --- a/support/sdk/c/blip/lib6lowpan/lib6lowpanIP.c +++ b/support/sdk/c/blip/lib6lowpan/lib6lowpanIP.c @@ -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 diff --git a/support/sdk/c/blip/libtcp/Makefile b/support/sdk/c/blip/libtcp/Makefile index d6278736..6c5a45de 100644 --- a/support/sdk/c/blip/libtcp/Makefile +++ b/support/sdk/c/blip/libtcp/Makefile @@ -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 + diff --git a/support/sdk/c/blip/libtcp/circ.c b/support/sdk/c/blip/libtcp/circ.c index de8bff1f..cd91d8e4 100644 --- a/support/sdk/c/blip/libtcp/circ.c +++ b/support/sdk/c/blip/libtcp/circ.c @@ -1,125 +1,73 @@ +/* + * "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 #include -// #include #include #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 diff --git a/support/sdk/c/blip/libtcp/circ.h b/support/sdk/c/blip/libtcp/circ.h index d937b06d..d71f3a0f 100644 --- a/support/sdk/c/blip/libtcp/circ.h +++ b/support/sdk/c/blip/libtcp/circ.h @@ -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 -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 diff --git a/support/sdk/c/blip/libtcp/tcplib.c b/support/sdk/c/blip/libtcp/tcplib.c index 21b8c4d2..140ca7ce 100644 --- a/support/sdk/c/blip/libtcp/tcplib.c +++ b/support/sdk/c/blip/libtcp/tcplib.c @@ -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 + +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); } } diff --git a/support/sdk/c/blip/libtcp/tcplib.h b/support/sdk/c/blip/libtcp/tcplib.h index 6b25d1fb..40323af1 100644 --- a/support/sdk/c/blip/libtcp/tcplib.h +++ b/support/sdk/c/blip/libtcp/tcplib.h @@ -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 + * + * + */ + // #include #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 diff --git a/support/sdk/c/blip/libtcp/test_circ.c b/support/sdk/c/blip/libtcp/test_circ.c index b6ae8fc1..a8a6edd7 100644 --- a/support/sdk/c/blip/libtcp/test_circ.c +++ b/support/sdk/c/blip/libtcp/test_circ.c @@ -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 +#include #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); */ diff --git a/support/sdk/c/blip/libtcp/test_server.c b/support/sdk/c/blip/libtcp/test_server.c index 4f39e570..418d1647 100644 --- a/support/sdk/c/blip/libtcp/test_server.c +++ b/support/sdk/c/blip/libtcp/test_server.c @@ -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 #include @@ -9,6 +30,7 @@ #include #include #include +#include #include "ip.h" @@ -17,13 +39,13 @@ #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); } diff --git a/support/sdk/c/blip/serial_tun.conf b/support/sdk/c/blip/serial_tun.conf index 1949d88a..db5cc17f 100644 --- a/support/sdk/c/blip/serial_tun.conf +++ b/support/sdk/c/blip/serial_tun.conf @@ -10,13 +10,13 @@ # 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 index 00000000..d8c78a3f --- /dev/null +++ b/tools/tinyos/misc/tos-nwprog @@ -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. +# @author Chieh-Jan Mike Liang + +# b6lowpan/nwprog port: +# @author Stephen Dawson-Haggerty + +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() diff --git a/tos/lib/net/blip/ICMP.h b/tos/lib/net/blip/ICMP.h index d9657ece..293cd8fa 100644 --- a/tos/lib/net/blip/ICMP.h +++ b/tos/lib/net/blip/ICMP.h @@ -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 { diff --git a/tos/lib/net/blip/ICMPResponderP.nc b/tos/lib/net/blip/ICMPResponderP.nc index 102d077b..4ac2b31c 100644 --- a/tos/lib/net/blip/ICMPResponderP.nc +++ b/tos/lib/net/blip/ICMPResponderP.nc @@ -23,6 +23,7 @@ #include #include <6lowpan.h> #include +#include #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++; diff --git a/tos/lib/net/blip/IPAddressP.nc b/tos/lib/net/blip/IPAddressP.nc index b8af3520..68b10cb1 100644 --- a/tos/lib/net/blip/IPAddressP.nc +++ b/tos/lib/net/blip/IPAddressP.nc @@ -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); } diff --git a/tos/lib/net/blip/IPDispatch.h b/tos/lib/net/blip/IPDispatch.h index ffb2641b..b2e6caec 100644 --- a/tos/lib/net/blip/IPDispatch.h +++ b/tos/lib/net/blip/IPDispatch.h @@ -24,6 +24,7 @@ #include #include +#include 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 diff --git a/tos/lib/net/blip/IPDispatchC.nc b/tos/lib/net/blip/IPDispatchC.nc index e74d70d2..66a44c0f 100644 --- a/tos/lib/net/blip/IPDispatchC.nc +++ b/tos/lib/net/blip/IPDispatchC.nc @@ -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; diff --git a/tos/lib/net/blip/IPDispatchP.nc b/tos/lib/net/blip/IPDispatchP.nc index 214b7cd5..a83eee85 100644 --- a/tos/lib/net/blip/IPDispatchP.nc +++ b/tos/lib/net/blip/IPDispatchP.nc @@ -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; + + // 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 index 00000000..415e868b --- /dev/null +++ b/tos/lib/net/blip/IPExtensionP.nc @@ -0,0 +1,144 @@ + +/* + * Provides various functions for dealing with IP extension header + * processing + + * + */ + +#include + +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 index 00000000..d82322ce --- /dev/null +++ b/tos/lib/net/blip/IPExtensionsP.nc @@ -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) { + + } + +} diff --git a/tos/lib/net/blip/IPRoutingP.nc b/tos/lib/net/blip/IPRoutingP.nc index 83ade730..e2780fdc 100644 --- a/tos/lib/net/blip/IPRoutingP.nc +++ b/tos/lib/net/blip/IPRoutingP.nc @@ -26,6 +26,9 @@ module IPRoutingP { provides interface IPRouting; provides interface Statistics; + + 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 index 00000000..6f5a5fb9 --- /dev/null +++ b/tos/lib/net/blip/Statistics.h @@ -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 diff --git a/tos/lib/net/blip/TcpP.nc b/tos/lib/net/blip/TcpP.nc index f594914e..02c42aff 100644 --- a/tos/lib/net/blip/TcpP.nc +++ b/tos/lib/net/blip/TcpP.nc @@ -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 index 00000000..729d9355 --- /dev/null +++ b/tos/lib/net/blip/TrackFlowsC.nc @@ -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 index 00000000..f06bcae8 --- /dev/null +++ b/tos/lib/net/blip/TrackFlowsP.nc @@ -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) { } + +} diff --git a/tos/lib/net/blip/UdpC.nc b/tos/lib/net/blip/UdpC.nc index 31cb2170..eda9c236 100644 --- a/tos/lib/net/blip/UdpC.nc +++ b/tos/lib/net/blip/UdpC.nc @@ -1,10 +1,14 @@ +#include + configuration UdpC { - provides interface UDP[uint8_t clnt]; + provides interface UDP[uint8_t clnt]; + provides interface Statistics; } implementation { components MainC, IPDispatchC, UdpP, IPAddressC; UDP = UdpP; + Statistics = UdpP; MainC -> UdpP.Init; UdpP.IP -> IPDispatchC.IP[IANA_UDP]; diff --git a/tos/lib/net/blip/UdpP.nc b/tos/lib/net/blip/UdpP.nc index 8cb0e5fb..47ecb0d5 100644 --- a/tos/lib/net/blip/UdpP.nc +++ b/tos/lib/net/blip/UdpP.nc @@ -1,18 +1,26 @@ #include #include +#include module UdpP { provides interface UDP[uint8_t clnt]; provides interface Init; + provides interface Statistics; 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 index 00000000..959584fa --- /dev/null +++ b/tos/lib/net/blip/doc/README @@ -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 blip` + - Build the IEEE802.15.4 bridge to your computer + * cd to $LOWPAN_ROOT/apps/IPBaseStation/ and `make 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 ' + + - 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 index 00000000..a73fbf9b --- /dev/null +++ b/tos/lib/net/blip/doc/README-IP @@ -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 index 00000000..ab9514b0 --- /dev/null +++ b/tos/lib/net/blip/doc/README-MERAKI @@ -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 index 00000000..ef59590d --- /dev/null +++ b/tos/lib/net/blip/doc/README-NWPROG @@ -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 +== == +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 `. + +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 index 00000000..dd09536e --- /dev/null +++ b/tos/lib/net/blip/doc/README-SHELL @@ -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 index 00000000..5461d94f --- /dev/null +++ b/tos/lib/net/blip/doc/README-SIM @@ -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 index 00000000..d20e4e63 --- /dev/null +++ b/tos/lib/net/blip/doc/README-TCP @@ -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 index 00000000..e85e793a --- /dev/null +++ b/tos/lib/net/blip/doc/README-UDP @@ -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; diff --git a/tos/lib/net/blip/interfaces/IP.nc b/tos/lib/net/blip/interfaces/IP.nc index 05214b7a..2b74bc9f 100644 --- a/tos/lib/net/blip/interfaces/IP.nc +++ b/tos/lib/net/blip/interfaces/IP.nc @@ -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. diff --git a/tos/lib/net/blip/interfaces/IPAddress.nc b/tos/lib/net/blip/interfaces/IPAddress.nc index 38d30846..b681950b 100644 --- a/tos/lib/net/blip/interfaces/IPAddress.nc +++ b/tos/lib/net/blip/interfaces/IPAddress.nc @@ -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 index 00000000..eb6f5c35 --- /dev/null +++ b/tos/lib/net/blip/interfaces/IPExtensions.nc @@ -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); + +} diff --git a/tos/lib/net/blip/interfaces/IPRouting.nc b/tos/lib/net/blip/interfaces/IPRouting.nc index 8c0f4dd6..873280ab 100644 --- a/tos/lib/net/blip/interfaces/IPRouting.nc +++ b/tos/lib/net/blip/interfaces/IPRouting.nc @@ -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 index 00000000..e6f69588 --- /dev/null +++ b/tos/lib/net/blip/interfaces/InternalIPExtension.nc @@ -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 index 00000000..faeb368e --- /dev/null +++ b/tos/lib/net/blip/interfaces/TLVHeader.nc @@ -0,0 +1,9 @@ + +#include + +interface TLVHeader { + event struct tlv_hdr *getHeader(int label,int nxt_hdr, + struct ip6_hdr *msg); + + event void free(); +} diff --git a/tos/lib/net/blip/interfaces/Tcp.nc b/tos/lib/net/blip/interfaces/Tcp.nc index 25f66ecb..a87bb019 100644 --- a/tos/lib/net/blip/interfaces/Tcp.nc +++ b/tos/lib/net/blip/interfaces/Tcp.nc @@ -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(); + + } diff --git a/tos/lib/net/blip/nwprog/Deluge.h b/tos/lib/net/blip/nwprog/Deluge.h index 1a0e99ef..58489f2b 100644 --- a/tos/lib/net/blip/nwprog/Deluge.h +++ b/tos/lib/net/blip/nwprog/Deluge.h @@ -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; diff --git a/tos/lib/net/blip/nwprog/NWProgC.nc b/tos/lib/net/blip/nwprog/NWProgC.nc index 3796ec5e..960c5380 100644 --- a/tos/lib/net/blip/nwprog/NWProgC.nc +++ b/tos/lib/net/blip/nwprog/NWProgC.nc @@ -1,4 +1,5 @@ +#include #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(); diff --git a/tos/lib/net/blip/nwprog/NWProgP.nc b/tos/lib/net/blip/nwprog/NWProgP.nc index 5974126f..ddeebb09 100644 --- a/tos/lib/net/blip/nwprog/NWProgP.nc +++ b/tos/lib/net/blip/nwprog/NWProgP.nc @@ -1,9 +1,10 @@ #include #include +#include #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 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 [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 [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) {} + } diff --git a/tos/lib/net/blip/shell/Shell.h b/tos/lib/net/blip/shell/Shell.h index 04e28900..c9bdc25b 100644 --- a/tos/lib/net/blip/shell/Shell.h +++ b/tos/lib/net/blip/shell/Shell.h @@ -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 diff --git a/tos/lib/net/blip/shell/UDPShellP.nc b/tos/lib/net/blip/shell/UDPShellP.nc index 8de6f888..7c968aae 100644 --- a/tos/lib/net/blip/shell/UDPShellP.nc +++ b/tos/lib/net/blip/shell/UDPShellP.nc @@ -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) { diff --git a/tos/lib/net/blip/table.c b/tos/lib/net/blip/table.c index 52e262f1..3cb912e7 100644 --- a/tos/lib/net/blip/table.c +++ b/tos/lib/net/blip/table.c @@ -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 #include "table.h" diff --git a/tos/lib/net/blip/table.h b/tos/lib/net/blip/table.h index 346e940a..3f2914b2 100644 --- a/tos/lib/net/blip/table.h +++ b/tos/lib/net/blip/table.h @@ -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_ -- 2.39.2