}
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;
components ResetC;
BaseStationP.Reset -> ResetC;
-#ifndef SIM
components SerialDevConfC as Configure;
BaseStationP.ConfigureSend -> Configure;
BaseStationP.ConfigureReceive -> Configure;
components CC2420ControlC;
BaseStationP.CC2420Config -> CC2420ControlC;
-#endif
}
interface SplitControl as SerialControl;
interface SplitControl as RadioControl;
-#ifndef SIM
interface Send as UartSend;
- interface IEEE154Send as RadioSend;
-#else
- interface AMSend as UartSend;
- interface AMSend as RadioSend;
- interface AMPacket as SerialAMPacket;
- interface Packet as SerialPacket;
-#endif
+ interface Ieee154Send as RadioSend;
interface Receive as UartReceive;
interface Receive as RadioReceive;
interface Packet as RadioPacket;
-#ifndef SIM
interface Send as ConfigureSend;
interface Receive as ConfigureReceive;
interface Timer<TMilli> as ConfigureTimer;
interface IPAddress;
-#endif
-#ifndef SIM
- interface IEEE154Packet as RadioIEEEPacket;
-#else
- interface AMPacket as RadioIEEEPacket;
-#endif
+ interface Ieee154Packet as RadioIeeePacket;
interface PacketLink;
interface LowPowerListening;
RADIO_QUEUE_LEN = 10,
};
- uint16_t radioRetries = 10;
+ uint16_t radioRetries = BLIP_L2_RETRIES;
uint16_t radioDelay = 30;
uint16_t serial_read;
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() {
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
}
}
// 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();
uartFull = FALSE;
}
post uartSendTask();
+
}
event message_t *UartReceive.receive(message_t *msg,
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)
task void radioSendTask() {
uint8_t len;
- hw_addr_t addr;
+ ieee154_saddr_t addr;
message_t* msg;
dbg ("base", "radioSendTask()\n");
}
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);
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
case CONFIG_REBOOT:
call Reset.reset();
break;
+ case CONFIG_KEEPALIVE:
+ return msg;
}
if (!echo_busy) {
reply->error = error;
# 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
#
# 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)
--- /dev/null
+
+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() {
+
+ }
+}
--- /dev/null
+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)
+
--- /dev/null
+/*
+ * "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;
+}
--- /dev/null
+/*
+ * "Copyright (c) 2008 The Regents of the University of California.
+ * All rights reserved."
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice, the following
+ * two paragraphs and the author appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
+ *
+ */
+
+#include <IPDispatch.h>
+#include <lib6lowpan.h>
+#include <ip.h>
+#include <lib6lowpan.h>
+#include <ip.h>
+
+#include "UDPReport.h"
+#include "PrintfUART.h"
+
+#define REPORT_PERIOD 75L
+
+module TCPEchoP {
+ uses {
+ interface Boot;
+ interface SplitControl as RadioControl;
+
+ interface UDP as Echo;
+ interface UDP as Status;
+ interface Tcp as TcpEcho;
+
+ interface Leds;
+
+ interface Timer<TMilli> as StatusTimer;
+
+ interface Statistics<ip_statistics_t> as IPStats;
+ interface Statistics<route_statistics_t> as RouteStats;
+ interface Statistics<icmp_statistics_t> as ICMPStats;
+ interface Statistics<udp_statistics_t> as UDPStats;
+
+ interface Random;
+
+ }
+
+} implementation {
+
+ bool timerStarted;
+ nx_struct udp_report stats;
+ struct sockaddr_in6 route_dest;
+
+#ifndef SIM
+#define CHECK_NODE_ID
+#else
+#define CHECK_NODE_ID if (TOS_NODE_ID == BASESTATION_ID) return
+#endif
+
+ event void Boot.booted() {
+ CHECK_NODE_ID;
+ call RadioControl.start();
+ timerStarted = FALSE;
+
+ call IPStats.clear();
+ call RouteStats.clear();
+ call ICMPStats.clear();
+ printfUART_init();
+
+
+#ifdef REPORT_DEST
+ route_dest.sin6_port = hton16(7000);
+ inet_pton6(REPORT_DEST, &route_dest.sin6_addr);
+ call StatusTimer.startOneShot(call Random.rand16() % (1024 * REPORT_PERIOD));
+#endif
+
+ dbg("Boot", "booted: %i\n", TOS_NODE_ID);
+ call Echo.bind(7);
+ call TcpEcho.bind(7);
+ call Status.bind(7001);
+ }
+
+ event void RadioControl.startDone(error_t e) {
+
+ }
+
+ event void RadioControl.stopDone(error_t e) {
+
+ }
+
+ event void Status.recvfrom(struct sockaddr_in6 *from, void *data,
+ uint16_t len, struct ip_metadata *meta) {
+
+ }
+
+ event void Echo.recvfrom(struct sockaddr_in6 *from, void *data,
+ uint16_t len, struct ip_metadata *meta) {
+ CHECK_NODE_ID;
+ call Echo.sendto(from, data, len);
+ }
+
+ enum {
+ STATUS_SIZE = sizeof(ip_statistics_t) +
+ sizeof(route_statistics_t) +
+ sizeof(icmp_statistics_t) + sizeof(udp_statistics_t),
+ };
+
+
+ event void StatusTimer.fired() {
+
+ if (!timerStarted) {
+ call StatusTimer.startPeriodic(1024 * REPORT_PERIOD);
+ timerStarted = TRUE;
+ }
+
+ stats.seqno++;
+ stats.sender = TOS_NODE_ID;
+
+ call IPStats.get(&stats.ip);
+ call RouteStats.get(&stats.route);
+ call ICMPStats.get(&stats.icmp);
+ call UDPStats.get(&stats.udp);
+
+ call Status.sendto(&route_dest, &stats, sizeof(stats));
+ }
+
+ /*
+ * Example code for setting up a TCP echo socket.
+ */
+
+ bool sock_connected = FALSE;
+ char tcp_buf[150];
+
+ event bool TcpEcho.accept(struct sockaddr_in6 *from,
+ void **tx_buf, int *tx_buf_len) {
+ *tx_buf = tcp_buf;
+ *tx_buf_len = 150;
+ return TRUE;
+ }
+ event void TcpEcho.connectDone(error_t e) {
+
+ }
+ event void TcpEcho.recv(void *payload, uint16_t len) {
+ if (call TcpEcho.send(payload,len) != SUCCESS)
+ call Leds.led2Toggle();
+ }
+ event void TcpEcho.closed(error_t e) {
+ call Leds.led0Toggle();
+ call TcpEcho.bind(7);
+ }
+ event void TcpEcho.acked() {}
+
+}
--- /dev/null
+/*
+ * "Copyright (c) 2008 The Regents of the University of California.
+ * All rights reserved."
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice, the following
+ * two paragraphs and the author appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
+ *
+ */
+#ifndef _UDPREPORT_H
+#define _UDPREPORT_H
+
+#include <Statistics.h>
+
+nx_struct udp_report {
+ nx_uint16_t seqno;
+ nx_uint16_t sender;
+ ip_statistics_t ip;
+ udp_statistics_t udp;
+ icmp_statistics_t icmp;
+ route_statistics_t route;
+} ;
+
+#endif
# 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
$(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
*/
#include <6lowpan.h>
+#include "TestDriver.h"
configuration UDPEchoC {
UDPEchoP.StatusTimer -> TimerMilliC;
+ components UdpC;
UDPEchoP.IPStats -> IPDispatchC.IPStats;
+ UDPEchoP.UDPStats -> UdpC;
UDPEchoP.RouteStats -> IPDispatchC.RouteStats;
UDPEchoP.ICMPStats -> IPDispatchC.ICMPStats;
#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
}
#include "UDPReport.h"
#include "PrintfUART.h"
-#define REPORT_PERIOD 45L
+#define REPORT_PERIOD 75L
module UDPEchoP {
uses {
interface Timer<TMilli> as StatusTimer;
interface Statistics<ip_statistics_t> as IPStats;
+ interface Statistics<udp_statistics_t> as UDPStats;
interface Statistics<route_statistics_t> as RouteStats;
interface Statistics<icmp_statistics_t> as ICMPStats;
} 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;
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
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));
}
}
#ifndef _UDPREPORT_H
#define _UDPREPORT_H
-#include <IPDispatch.h>
+#include <Statistics.h>
nx_struct udp_report {
- // ip_statistics_t ip;
+ nx_uint16_t seqno;
+ nx_uint16_t sender;
+ ip_statistics_t ip;
udp_statistics_t udp;
icmp_statistics_t icmp;
route_statistics_t route;
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)
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)
def __str__(self):
s = "Message <UdpReport> \n"
try:
- s += " [udp.total=0x%x]\n" % (self.get_udp_total())
+ s += " [ip.sent=0x%x]\n" % (self.get_ip_sent())
except:
pass
try:
- s += " [udp.failed=0x%x]\n" % (self.get_udp_failed())
+ s += " [ip.forwarded=0x%x]\n" % (self.get_ip_forwarded())
except:
pass
try:
- s += " [udp.seqno=0x%x]\n" % (self.get_udp_seqno())
+ s += " [ip.rx_drop=0x%x]\n" % (self.get_ip_rx_drop())
except:
pass
try:
- s += " [udp.sender=0x%x]\n" % (self.get_udp_sender())
+ s += " [ip.tx_drop=0x%x]\n" % (self.get_ip_tx_drop())
except:
pass
try:
- s += " [icmp.rx=0x%x]\n" % (self.get_icmp_rx())
+ s += " [ip.fw_drop=0x%x]\n" % (self.get_ip_fw_drop())
+ except:
+ pass
+ try:
+ s += " [ip.rx_total=0x%x]\n" % (self.get_ip_rx_total())
+ except:
+ pass
+ try:
+ s += " [ip.real_drop=0x%x]\n" % (self.get_ip_real_drop())
+ except:
+ pass
+ try:
+ s += " [ip.hlim_drop=0x%x]\n" % (self.get_ip_hlim_drop())
+ except:
+ pass
+ try:
+ s += " [ip.senddone_el=0x%x]\n" % (self.get_ip_senddone_el())
+ except:
+ pass
+ try:
+ s += " [ip.fragpool=0x%x]\n" % (self.get_ip_fragpool())
+ except:
+ pass
+ try:
+ s += " [ip.sendinfo=0x%x]\n" % (self.get_ip_sendinfo())
+ except:
+ pass
+ try:
+ s += " [ip.sendentry=0x%x]\n" % (self.get_ip_sendentry())
+ except:
+ pass
+ try:
+ s += " [ip.sndqueue=0x%x]\n" % (self.get_ip_sndqueue())
+ except:
+ pass
+ try:
+ s += " [ip.encfail=0x%x]\n" % (self.get_ip_encfail())
except:
pass
try:
- s += " [route.parent.flags=0x%x]\n" % (self.get_route_parent_flags())
+ s += " [ip.heapfree=0x%x]\n" % (self.get_ip_heapfree())
except:
pass
try:
- s += " [route.parent.hops=0x%x]\n" % (self.get_route_parent_hops())
+ s += " [udp.total=0x%x]\n" % (self.get_udp_total())
+ except:
+ pass
+ try:
+ s += " [udp.failed=0x%x]\n" % (self.get_udp_failed())
except:
pass
try:
- s += " [route.parent.neighbor=0x%x]\n" % (self.get_route_parent_neighbor())
+ s += " [udp.seqno=0x%x]\n" % (self.get_udp_seqno())
except:
pass
try:
- s += " [route.parent.costEstimate=0x%x]\n" % (self.get_route_parent_costEstimate())
+ s += " [udp.sender=0x%x]\n" % (self.get_udp_sender())
except:
pass
try:
- s += " [route.parent.linkEstimate=0x%x]\n" % (self.get_route_parent_linkEstimate())
+ s += " [icmp.rx=0x%x]\n" % (self.get_icmp_rx())
except:
pass
try:
- s += " [route.parent.rssiEstimate=0x%x]\n" % (self.get_route_parent_rssiEstimate())
+ s += " [route.hop_limit=0x%x]\n" % (self.get_route_hop_limit())
except:
pass
try:
- s += " [route.parent.stats.success=";
- for i in range(0, 2):
- s += "0x%x " % (self.getElement_route_parent_stats_success(i) & 0xff)
- s += "]\n";
+ s += " [route.parent=0x%x]\n" % (self.get_route_parent())
except:
pass
try:
- s += " [route.parent.stats.total=";
- for i in range(0, 2):
- s += "0x%x " % (self.getElement_route_parent_stats_total(i) & 0xff)
- s += "]\n";
+ s += " [route.parent_metric=0x%x]\n" % (self.get_route_parent_metric())
except:
pass
try:
- s += " [route.parent.stats.receptions=";
- for i in range(0, 2):
- s += "0x%x " % (self.getElement_route_parent_stats_receptions(i) & 0xff)
- s += "]\n";
+ s += " [route.parent_etx=0x%x]\n" % (self.get_route_parent_etx())
except:
pass
return s
# 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
--- /dev/null
+# -*- 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
+
+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
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/
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
$(GCC) $(TFLAGS) $(CFLAGS) -o $(TARGET) $(SOURCES) $(radvd_SOURCES) $(LIBS) -lm
clean:
- rm $(TARGET)
+ rm -f $(TARGET)
+/*
+ * "Copyright (c) 2008 The Regents of the University of California.
+ * All rights reserved."
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice, the following
+ * two paragraphs and the author appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
+ *
+ */
+/*
+ * @author Stephen Dawson-Haggerty <stevedh@eecs.berkeley.edu>
+ */
#include <stdio.h>
#include <stdlib.h>
#include "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')
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);
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;
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();
}
+/*
+ * "Copyright (c) 2008 The Regents of the University of California.
+ * All rights reserved."
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice, the following
+ * two paragraphs and the author appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
+ *
+ */
+/*
+ * @author Stephen Dawson-Haggerty <stevedh@eecs.berkeley.edu>
+ */
+
#ifndef _CONFIG_H
#define _CONFIG_H
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
#include <string.h>
#include <math.h>
+#define iceil(X) ((unsigned int)((X) + 1))
+
/*
Credit for primes table: Aaron Krowne
http://br.endernet.org/~akrowne/
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;
}
}
}
h->tablelength = newsize;
- h->loadlimit = (unsigned int) ceil(newsize * max_load_factor);
+ h->loadlimit = (unsigned int) iceil(newsize * max_load_factor);
return -1;
}
*
*/
#include <stdio.h>
+#include <errno.h>
+#include <string.h>
#include <time.h>
#include <sys/time.h>
#include <stdarg.h>
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) {
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;
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;
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...) \
#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
--- /dev/null
+/*
+ * "Copyright (c) 2008, 2009 The Regents of the University of California.
+ * All rights reserved."
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice, the following
+ * two paragraphs and the author appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <net/if.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <arpa/inet.h>
+
+#include "mcast.h"
+#include "logging.h"
+
+int __mcast_sock;
+struct sockaddr_in6 __mcast_addr;
+char __mcast_dev[IFNAMSIZ];
+
+static int open_loopback(struct sockaddr_in6 *laddr) {
+
+ /* we need to send to the loopback address, not the group */
+ memcpy(&__mcast_addr.sin6_addr, &in6addr_loopback, sizeof(struct in6_addr));
+ memcpy(&laddr->sin6_addr, &in6addr_loopback, sizeof(struct in6_addr));
+
+ /* bind to the local address (we're already BINDTODEVICE, so this
+ might be redundant) */
+ if (bind(__mcast_sock, (struct sockaddr *)laddr, sizeof(struct sockaddr_in6)) < 0) {
+ log_fatal_perror("binding multicast socket failed");
+ goto fail;
+ }
+
+ return __mcast_sock;
+ fail:
+ close(__mcast_sock);
+ return -1;
+}
+
+int mcast_start(char *dev) {
+ struct ipv6_mreq join;
+ struct ifreq ifr;
+ int opt;
+ int ifindex = if_nametoindex(dev);
+
+ __mcast_addr.sin6_family = AF_INET6;
+ inet_pton(AF_INET6, "ff12::cafe:babe", &__mcast_addr.sin6_addr);
+ __mcast_addr.sin6_port = htons(10023);
+ __mcast_addr.sin6_scope_id = ifindex;
+
+ strncpy(__mcast_dev, dev, IFNAMSIZ);
+
+ struct sockaddr_in6 laddr = {
+ .sin6_family = AF_INET6,
+ .sin6_port = __mcast_addr.sin6_port,
+ .sin6_addr = IN6ADDR_ANY_INIT,
+ .sin6_scope_id = ifindex,
+ };
+
+
+ /* get the socket */
+ if ((__mcast_sock = socket(PF_INET6, SOCK_DGRAM, 0)) < 0) {
+ log_fatal_perror("error opening socket");
+ return -1;
+ }
+
+ /* bind it to the device we're going to join the link-local
+ multicast group on */
+ memset(&ifr, 0, sizeof(struct ifreq));
+ strncpy(ifr.ifr_name, dev, IFNAMSIZ);
+ if (setsockopt(__mcast_sock, SOL_SOCKET, SO_BINDTODEVICE,
+ (char *)&ifr, sizeof(struct ifreq)) < 0) {
+ log_fatal_perror("could not BINDTODEVICE");
+ goto fail;
+ }
+
+ /* the loopback on linux doesn't support multicast. that's okay,
+ though, since we can just attach to it and use it to feed routing
+ reports back into us. */
+ if (strncmp(dev, "lo", 2) == 0) {
+ return open_loopback(&laddr);
+ }
+
+ /* receive messages we send */
+ opt = 1;
+ if (setsockopt(__mcast_sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &opt, sizeof(opt)) < 0) {
+ log_fatal_perror("setting loop failed");
+ goto fail;
+ }
+
+ opt = 1;
+ if (setsockopt(__mcast_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
+ log_fatal_perror("setting reuse failed");
+ goto fail;
+ }
+
+ /* bind to the local address (we're already BINDTODEVICE, so this
+ might be redundant) */
+ if (bind(__mcast_sock, (struct sockaddr *)&laddr, sizeof(struct sockaddr_in6)) < 0) {
+ log_fatal_perror("binding multicast socket failed");
+ goto fail;
+ }
+
+ memset(&join, 0, sizeof(struct ipv6_mreq));
+ memcpy(&join.ipv6mr_multiaddr, &__mcast_addr.sin6_addr, sizeof(struct in6_addr));
+ join.ipv6mr_interface = ifindex;
+
+ if (setsockopt(__mcast_sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &join, sizeof(join)) < 0) {
+ log_fatal_perror("error joining group");
+ goto fail;
+ }
+
+ return __mcast_sock;
+ fail:
+ close(__mcast_sock);
+ return -1;
+}
+
+
+
+int mcast_recvfrom(struct sockaddr_in6 *from, void *buf, int len) {
+ int rc;
+ socklen_t fromlen = sizeof(struct sockaddr_in6);
+
+ if ((rc = recvfrom(__mcast_sock, buf, len, 0, (struct sockaddr *)from, &fromlen)) < 0) {
+ log_fatal_perror("multicast receive");
+ return -1;
+ }
+ return rc;
+}
+
+int mcast_send(void *data, int len) {
+ int rc;
+
+ if ((rc = sendto(__mcast_sock, data, len, 0, (struct sockaddr *)&__mcast_addr, sizeof(struct sockaddr_in6))) < 0) {
+ log_fatal_perror("send failed");
+ return -1;
+ }
+ return 0;
+}
+
+#if 0
+int main(int argc, char **argv) {
+
+ char *dev = argv[1];
+ int fd;
+ struct sockaddr_in6 grp = {
+ .sin6_port = htons(10620),
+ };
+
+ if (argc < 2) {
+ printf("\n\t%s <iface>\n\n", argv[0]);
+ exit(1);
+ }
+
+ inet_pton(AF_INET6, "ff12::1abc", &grp.sin6_addr);
+
+ fd = mcast_start(&grp, dev);
+ printf("mcast start done: %i\n", fd);
+
+ struct sockaddr_in6 from;
+ char rxbuf[1024];
+ int len;
+
+ if (argc == 3 && strcmp(argv[2], "listen") == 0) {
+
+ printf("listening\n");
+
+ while (1) {
+ len = mcast_recvfrom(&from, rxbuf, 1024);
+ if (len > 0) {
+ rxbuf[len] = '\0';
+ puts(rxbuf);
+ }
+ }
+ } else {
+ char *msg = "hello, mcast world!";
+ while (1) {
+ mcast_send(msg, strlen(msg)+1);
+ sleep(1);
+ len = mcast_recvfrom(&from, rxbuf, 1024);
+ if (len > 0) {
+ rxbuf[len] = '\0';
+ puts(rxbuf);
+ }
+
+ }
+ }
+}
+#endif
--- /dev/null
+/*
+ * "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
+
--- /dev/null
+/*
+ * "Copyright (c) 2008, 2009 The Regents of the University of California.
+ * All rights reserved."
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice, the following
+ * two paragraphs and the author appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <net/if.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <arpa/inet.h>
+
+#include "logging.h"
+
+static int __nl_sock;
+static int __if_index;
+
+/*
+ * Start a netlink session.
+ *
+ */
+int nl_init() {
+ struct sockaddr_nl nladdr;
+
+ /* with any luck, we've constructed the message, can send it to the
+ kernel, and have a beer. */
+ if ((__nl_sock = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0) {
+ log_fatal_perror("PACKETLINK socket");
+ return -1;
+ }
+
+ memset(&nladdr, 0, sizeof(nladdr));
+ nladdr.nl_family = AF_NETLINK;
+ nladdr.nl_groups = 0;
+ if (bind(__nl_sock, (struct sockaddr*)&nladdr, sizeof(nladdr)) < 0) {
+ close(__nl_sock);
+ log_fatal_perror("Cannot bind netlink socket");
+ return -1;
+ }
+ return 0;
+}
+
+int nl_shutdown() {
+ close(__nl_sock);
+ __nl_sock = __if_index = -1;
+ return 0;
+}
+
+/*
+ * Start proxying addr on device 'dev'
+ */
+static int nl_cmd(int type, int flags, struct in6_addr *addr, char *dev) {
+ static int seq;
+ struct {
+ struct nlmsghdr n;
+ struct ndmsg ndm;
+ char buf[256];
+ } req;
+ struct rtattr *rta;
+ struct sockaddr_nl nladdr;
+
+ memset(&req, 0, sizeof(req));
+
+ /* set up our request packet with one request */
+ req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg));
+ req.n.nlmsg_flags = NLM_F_REQUEST | flags;
+ req.n.nlmsg_type = type;
+ req.ndm.ndm_family = AF_INET6;
+ req.ndm.ndm_state = NUD_PERMANENT;
+ req.ndm.ndm_ifindex = if_nametoindex(dev);
+
+ /* add the actual address to the tail of the message */
+ int nl_len = RTA_LENGTH(sizeof(struct in6_addr));
+ if (NLMSG_ALIGN(req.n.nlmsg_len) + RTA_ALIGN(nl_len) > sizeof(req)) {
+ fprintf(stderr, "message too long\n");
+ return -1;
+ }
+
+ rta = ((struct rtattr *) (((void *) (&req.n)) + NLMSG_ALIGN((req.n.nlmsg_len))));
+ rta->rta_type = NDA_DST;
+ rta->rta_len = nl_len;
+ memcpy(RTA_DATA(rta), addr, sizeof(struct in6_addr));
+ req.n.nlmsg_len = NLMSG_ALIGN(req.n.nlmsg_len) + RTA_ALIGN(nl_len);
+
+ struct iovec iov = {
+ .iov_base = (void*) &req.n,
+ .iov_len = req.n.nlmsg_len
+ };
+ struct msghdr msg = {
+ .msg_name = &nladdr,
+ .msg_namelen = sizeof(nladdr),
+ .msg_iov = &iov,
+ .msg_iovlen = 1,
+ };
+
+ memset(&nladdr, 0, sizeof(nladdr));
+ nladdr.nl_family = AF_NETLINK;
+ req.n.nlmsg_seq = seq++;
+
+ if (sendmsg(__nl_sock, &msg, 0) < 0) {
+ log_fatal_perror("RTNETLINK");
+ return -1;
+ }
+ /* TODO : nonblocking receive to check for error? */
+
+
+ return 0;
+
+ ///
+
+ char buf[16384];
+
+ iov.iov_base = buf;
+ while (1) {
+ int status;
+ struct nlmsghdr *h;
+
+ iov.iov_len = sizeof(buf);
+ status = recvmsg(__nl_sock, &msg, 0);
+
+ if (status < 0) {
+ if (errno == EINTR)
+ continue;
+ log_fatal_perror("OVERRUN");
+ continue;
+ }
+
+ if (status == 0) {
+ fprintf(stderr, "EOF on netlink\n");
+ return -1;
+ }
+
+ h = (struct nlmsghdr*)buf;
+ while (NLMSG_OK(h, status)) {
+ int err;
+
+ if (nladdr.nl_pid != 0 ||
+ h->nlmsg_pid != 0 ||
+ h->nlmsg_seq != seq) {
+ if (err < 0)
+ return err;
+
+ goto skip_it;
+ }
+
+ if (h->nlmsg_type == NLMSG_DONE)
+ return 0;
+ if (h->nlmsg_type == NLMSG_ERROR) {
+ struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
+ if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) {
+ fprintf(stderr, "ERROR truncated\n");
+ } else {
+ errno = -err->error;
+ log_fatal_perror("RTNETLINK answers");
+ }
+ return -1;
+ }
+skip_it:
+ h = NLMSG_NEXT(h, status);
+ }
+ if (msg.msg_flags & MSG_TRUNC) {
+ fprintf(stderr, "Message truncated\n");
+ continue;
+ }
+ if (status) {
+ fprintf(stderr, "!!!Remnant of size %d\n", status);
+ exit(1);
+ }
+ }
+ return 0;
+}
+
+int nl_nd_add_neigh(struct in6_addr *addr, char *dev) {
+ return nl_cmd(RTM_NEWNEIGH, NLM_F_CREATE|NLM_F_REPLACE, addr, dev);
+}
+int nl_nd_del_neigh(struct in6_addr *addr, char *dev) {
+ return nl_cmd(RTM_DELNEIGH, 0, addr, dev);
+}
+int nl_nd_add_proxy(struct in6_addr *addr, char *dev) {
+ // SDH : shit, the netlink proxy doesn't work (the add neighbor
+ // did). I WILL fix it... later.
+ char buf [100], cmd[256];
+ inet_ntop(AF_INET6, addr, buf, 100);
+ snprintf(cmd, sizeof(cmd), "ip neigh add proxy %s dev %s\n", buf, dev);
+ system(cmd);
+ return 0;
+
+ // return nl_cmd(RTM_NEWNEIGH, NLM_F_CREATE|NLM_F_EXCL|NTF_PROXY, addr, dev);
+}
--- /dev/null
+/*
+ * "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
+
#include <stdio.h>
#include <stdlib.h>
#include <float.h>
+#include <time.h>
+#include <sys/time.h>
#include "nwstate.h"
#include "hashtable.h"
#include "logging.h"
#include "lib6lowpan.h"
#include "routing.h"
+#include "vty.h"
struct hashtable *links;
struct hashtable *routers;
}
-void nw_print_routes() {
+void nw_print_routes(int fd, int argc, char **argv) {
+ VTY_HEAD;
router_t *r,*s;
for (r = router_list; r != NULL; r = r->next) {
- log_clear(LOGLVL_INFO, " 0x%x: ", r->id);
+ VTY_printf(" 0x%x: ", r->id);
for (s = r->sp.prev; s != NULL; s = s->sp.prev) {
- log_clear(LOGLVL_INFO, "0x%x ", s->id);
+ VTY_printf("0x%x", s->id);
+ if (r->isController) VTY_printf("[C] ");
+ else VTY_printf(" ");
}
- log_clear(LOGLVL_INFO, "\n");
+ VTY_printf("\r\n");
+ VTY_flush();
}
}
-void nw_test_routes() {
+void nw_test_routes(int fd, int argc, char **argv) {
node_id_t dest = ntohs(__my_address.s6_addr16[7]);
debug("nwstate: computing new routes (root: 0x%x)\n", ntohs(__my_address.s6_addr16[7]));
compute_routes(dest);
}
-void nw_print_links() {
+void nw_print_links(int fd, int argc, char **argv) {
+ VTY_HEAD;
+ struct tm *ltime;
+ int target = -1;
router_t *r;
link_t *l;
+
+ if (argc == 2)
+ target = atoi(argv[1]);
+
for (r = router_list; r != NULL; r = r->next) {
- log_clear(LOGLVL_INFO, " 0x%x: dist: %.1f\n", r->id, r->sp.dist);
+ char flags[16]; int pos = 0;
+ if (target >= 0 && r->id != target) continue;
+
+ flags[0] = '\0';
+ if (r->isProxying || r->isController) {
+ flags[pos++] = '[';
+ if (r->isController) flags[pos++] = 'C';
+ if (r->isProxying) flags[pos++] = 'P';
+ flags[pos++] = ']';
+ flags[pos++] = '\0';
+ }
+
+ VTY_printf(" 0x%x%s: dist: ", r->id, flags);
+ if (r->sp.dist == FLT_MAX)
+ VTY_printf("Inf");
+ else
+ VTY_printf("%.1f", r->sp.dist);
+ if (!r->isController) {
+ ltime = localtime(&r->lastReport.tv_sec);
+ VTY_printf(" reported: " ISO8601_FMT(ltime, &r->lastReport));
+ }
+
+ VTY_printf("\r\n");
for (l = r->links; l != NULL; l = (r == l->n1) ? l->next1 : l->next2) {
if (r == l->n1) {
- log_clear(LOGLVL_INFO, " --> 0x%x [%.1f]\n", l->n2->id, l->qual);
+ VTY_printf(" --> 0x%x [%.1f]\r\n", l->n2->id, l->qual);
}
}
- log_clear(LOGLVL_INFO, "\n");
+ VTY_printf("\r\n");
+ VTY_flush();
+ }
+}
+
+void nw_add_sticky_edge(int fd, int argc, char **argv) {
+ VTY_HEAD;
+ int v1, v2;
+ if (argc == 3) {
+ link_t *l;
+ struct topology_entry te;
+ v1 = atoi(argv[1]);
+ v2 = atoi(argv[2]);
+ VTY_printf("adding sticky edge between %i and %i\r\n", v1, v2);
+ te.etx = 10;
+ te.conf = 255;
+ te.hwaddr = htons(v2);
+ l = nw_add_incr_edge(v1, &te);
+ l->marked = L_STICKY;
+ } else {
+ VTY_printf("add a link: 'a <n1> <n2>'\r\n");
}
+ VTY_flush();
}
+void nw_inval_node_sh(int fd, int argc, char **argv) {
+ VTY_HEAD;
+ int int_arg;
+ if (argc == 2) {
+ int_arg = atoi(argv[1]);
+ VTY_printf("invalidating node 0x%x\n", int_arg);
+ nw_inval_node(int_arg);
+ }
+ VTY_flush();
+}
//
// helpers
//
+router_t *nw_get_router(node_id_t rid) {
+ return hashtable_search(routers, &rid);
+}
+
router_t *get_insert_router(node_id_t rid) {
router_key_t *key;
- router_t *ret = hashtable_search(routers, &rid);
+ router_t *ret = nw_get_router(rid);
if (ret == NULL) {
key = (router_key_t *)malloc(sizeof(router_key_t));
ret = (router_t *)malloc(sizeof(router_t));
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;
*key = rid;
hashtable_insert(routers, key, ret);
- routing_add_table_entry(rid);
}
return ret;
}
//
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;
}
* 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);
}
- 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",
(v1 == link_str->n1->id) ? link_str->n1_reportcount++ :
link_str->n2_reportcount++;
- return 0;
+ return link_str;
}
/*
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,
new->node = r->id;
new->next = ret;
new->length = (ret == NULL) ? 1 : ret->length + 1;
+ new->isController = r->isController;
ret = new;
}
}
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;
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;
}
}
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
// 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);
}
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);
+ }
+ }
+}
*
*/
+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 {
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
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
+/*
+ * "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. */
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);
}
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);
}
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,
}
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,
+/*
+ * "Copyright (c) 2008, 2009 The Regents of the University of California.
+ * All rights reserved."
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice, the following
+ * two paragraphs and the author appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
+ *
+ */
/*
* radvd-wrapper.c
* author: Stephen Dawson-Haggerty <stevedh@eecs.berkeley.edu>
// config_interface();
radvd_kickoff_adverts();
+ set_debuglevel(0);
+
return sock;
}
#include <stdio.h>
#include <stdlib.h>
#include <net/if.h>
+#include <arpa/inet.h>
+#include <sys/select.h>
+#include <net/route.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
#include <6lowpan.h>
#include <lib6lowpan.h>
#include "nwstate.h"
#include "logging.h"
#include "config.h"
+#include "mcast.h"
+#include "netlink.h"
-static hw_addr_t my_short_addr;
+static ieee154_saddr_t my_short_addr;
extern struct in6_addr __my_address;
char proxy_dev[IFNAMSIZ], tun_dev[IFNAMSIZ];
+int mcast_sock;
+
+char report_buf[ROUTMSGSIZ];
/*
* Call to setup routing tables.
*
*/
-uint8_t routing_init(struct config *c, char *tun_name) {
- nw_init();
+int routing_init(struct config *c, char *tun_name) {
+ FILE *fd;
+ char buf[256];
my_short_addr = ntohs(__my_address.s6_addr16[7]);
strncpy(proxy_dev, c->proxy_dev, IFNAMSIZ);
strncpy(tun_dev, tun_name, IFNAMSIZ);
-/* nl_fd = socket(AF_NETLINK, SOCK_RAW, protocol); */
-/* if (nl_fd < 0) */
-/* return -1; */
+ // set up the network state data structures
+ nw_init();
+
+ // start a netlink session to the kernel
+ nl_init();
+
+ mcast_sock = mcast_start(proxy_dev);;
+
+ if ((fd = fopen("/proc/sys/net/ipv6/conf/all/forwarding", "w")) == NULL) {
+ log_fatal_perror("enable forwarding");
+ return -1;
+ }
+ fprintf(fd, "1");
+ fclose(fd);
+
+ snprintf(buf, sizeof(buf), "/proc/sys/net/ipv6/conf/%s/proxy_ndp", proxy_dev);
+ if ((fd = fopen(buf, "w")) == NULL) {
+ warn("unable to enable IPv6 ND proxy on %s\n", proxy_dev);
+ } else {
+ fprintf(fd, "1");
+ fclose(fd);
+ }
+
+ return (mcast_sock >= 0) ? 0 : -1;
+}
+
+int routing_add_fds(fd_set *fds) {
+ if (mcast_sock >=0) {
+ FD_SET(mcast_sock, fds);
+ }
+ return mcast_sock;
+}
+
+int route_cmd(int cmd, struct in6_addr *dest, char *dev) {
+ struct in6_rtmsg rt;
+ memset((char *) &rt, 0, sizeof(struct in6_rtmsg));
+ memcpy(&rt.rtmsg_dst, dest, sizeof(struct in6_addr));
+
+ rt.rtmsg_flags = RTF_UP | RTF_HOST;
+ rt.rtmsg_metric = 1;
+ rt.rtmsg_dst_len = 128;
+ rt.rtmsg_ifindex = if_nametoindex(dev);
+
+ return ioctl(mcast_sock, cmd, &rt);
+}
+
+
+int routing_process(fd_set *fds) {
+ struct sockaddr_in6 from;
+ char buf[ROUTMSGSIZ], *cur, printbuf[100];
+ struct routing_message *rmsg;
+ struct topology_header_package *th;
+ int len;
+ struct in6_addr addr;
+
+ if (mcast_sock < 0 || !FD_ISSET(mcast_sock, fds)) return 0;
+
+ len = mcast_recvfrom(&from, buf, sizeof(buf));
+ rmsg = (struct routing_message *)buf;
+
+ inet_ntop(AF_INET6, &from.sin6_addr, printbuf, sizeof(printbuf));
+ debug("processing routing message from %s type %i\n", printbuf, rmsg->type);
+
+ memset(&addr, 0, sizeof(struct in6_addr));
+ memcpy(addr.s6_addr, __my_address.s6_addr, 8);
+
+ switch (rmsg->type) {
+ case RMSG_TOPOLOGY:
+ cur = rmsg->data;
+ len -= sizeof(struct routing_message);
+ while (len > 0) {
+ router_t *router;
+ int header_len, i;
+ node_id_t reporter;
+
+ th = (struct topology_header_package *)cur;
+ header_len = ntohs(th->len);
+ reporter = ntohs(th->reporter);
+
+ nw_unmark_links(reporter);
+ for (i = 0; i < (header_len - sizeof(struct topology_header_package))/sizeof(struct topology_entry); i++) {
+
+ nw_add_incr_edge(reporter, &th->topo[i]);
+
+ router = nw_get_router(reporter);
+ gettimeofday(&router->lastReport, NULL);
+
+ if (router == NULL) continue;
+ addr.s6_addr16[7] = htons(reporter);
+
+ if (rmsg->source == __my_address.s6_addr16[7] && !router->isProxying) {
+ // if I sent this report, make sure we are proxying for him
+ info("Starting to proxy for 0x%x\n", reporter);
+
+ if (route_cmd(SIOCADDRT, &addr, tun_dev) < 0) {
+ log_fatal_perror("route_add");
+ }
+
+ nl_nd_add_proxy(&addr, proxy_dev);
+ router->isProxying = TRUE;
+ }
+ if (rmsg->source != __my_address.s6_addr16[7] && router->isProxying) {
+ info("Was proxying 0x%x, but he has moved\n", reporter);
+ if (route_cmd(SIOCDELRT, &addr, tun_dev) < 0) {
+ log_fatal_perror("route_del");
+ }
+
+ nl_nd_del_neigh(&addr, proxy_dev);
+ router->isProxying = FALSE;
+ }
+ }
+ nw_clear_unmarked(reporter);
+
+ router = nw_get_router(ntohs(rmsg->source));
+ if (router != NULL && !router->isController) {
+ nw_add_controller(ntohs(rmsg->source));
+ }
+
+ cur += header_len;
+ len -= header_len;
+ }
+ break;
+ }
return 0;
}
+int routing_add_report(node_id_t reporter, struct tlv_hdr *tlv) {
+ struct topology_header *th = (struct topology_header *)(tlv + 1);
+ struct routing_message *rmsg;
+ struct topology_header_package *pack;
+
+ rmsg = (struct routing_message *)report_buf;
+ pack = (struct topology_header_package *)&rmsg->data[0];
+
+ memset(report_buf, 0, sizeof(report_buf));
+
+ debug("routing_add_report: report from 0x%x seq: %i\n", reporter, th->seqno);
+
+ rmsg->type = RMSG_TOPOLOGY;
+ rmsg->source = __my_address.s6_addr16[7];
+ pack->reporter = htons(reporter);
+ pack->seqno = th->seqno;
+ pack->len = htons(tlv->len -
+ sizeof(struct tlv_hdr) -
+ sizeof(struct topology_header) +
+ sizeof(struct topology_header_package));
+
+ memcpy(pack->topo, th->topo, tlv->len - sizeof(struct tlv_hdr) -
+ sizeof(struct topology_header));
+
+ mcast_send(report_buf, ntohs(pack->len) + sizeof(struct routing_message));
+
+ return 0;
+}
+
+
/*
* @returns: truth value indicating if the destination of the packet
* is a single hop, and requires no source route.
*/
-uint8_t routing_is_onehop(struct split_ip_msg *msg) {
+int routing_is_onehop(struct split_ip_msg *msg) {
path_t *path;
- uint8_t ret = ROUTE_NO_ROUTE;
+ int ret = ROUTE_NO_ROUTE;
if (cmpPfx(msg->hdr.ip6_dst.s6_addr, multicast_prefix))
return ROUTE_ONEHOP;
+
+#if 0
if (msg->hdr.nxt_hdr == NXTHDR_SOURCE) {
debug("routing_is_onehop: Source header\n");
return ROUTE_SOURCE;
}
+#endif
path = nw_get_route(my_short_addr, ntohs(msg->hdr.ip6_dst.s6_addr16[7]));
if (path != NULL) {
- if (path->length == 1)
+ if (path->isController) {
+ ret = ROUTE_WORMHOLE;
+ } else if (path->length == 1) {
ret = ROUTE_ONEHOP;
- else
+ } else {
ret = ROUTE_MHOP;
+ }
}
debug("routing_is_onehop: 0x%x\n", ret);
nw_free_path(path);
*/
/*
- * 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);
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);
}
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) {
/*
* 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]));
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"; */
-
-}
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);
/*
/*
* 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
#include <termios.h>
#include <errno.h>
#include <signal.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "TrackFlows.h"
#include "tun_dev.h"
#include "serialsource.h"
#include "logging.h"
#include "config.h"
#include "nwstate.h"
+#include "vty.h"
#define min(a,b) ( (a>b) ? b : a )
#define max(a,b) ( (a>b) ? a : b )
-int tun_fd, radvd_fd = -1;
+int tun_fd, radvd_fd = -1, fifo_fd = -1, keepalive_needed = 1;
+int opt_listenonly = 0, opt_trackflows = 0;
+
int radvd_init(char *ifname, struct config *c);
void radvd_process();
-#ifndef SIM
+#ifndef SF_SRC
serial_source ser_src;
#define write_pan_packet(DATA, LEN) write_serial_packet(ser_src, DATA, LEN)
#define read_pan_packet(LENP) read_serial_packet(ser_src, LENP)
+#define close_pan() close_serial_source(ser_src);
#else
int sf_fd;
#define write_pan_packet(DATA, LEN) write_sf_packet(sf_fd, DATA, LEN)
#define read_pan_packet(LENP) read_sf_packet(sf_fd, LENP)
+#define close_pan() close(sf_fd)
#endif
+sig_atomic_t do_shutdown = 0;
+
+void driver_shutdown() {
+ do_shutdown = 1;
+}
+
+
enum {
N_RECONSTRUCTIONS = 10,
};
/*
- * This is not the right way to detect we're on that platform, but I
- * can't find a better macro.
*/
#ifdef __TARGET_mips__
-char *def_configfile = "/etc/lowpan/serial_tun.conf";
+const char *def_configfile = "/etc/lowpan/serial_tun.conf";
#else
-char *def_configfile = "serial_tun.conf";
+const char *def_configfile = "serial_tun.conf";
#endif
-#ifdef DBG_TRACK_FLOWS
-FILE *dbg_file;
-#endif
extern struct in6_addr __my_address;
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
+
/* ------------------------------------------------------------------------- */
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.
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);
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");
/* 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:
/* ------------------------------------------------------------------------- */
/* 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
// 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) {
stats.tx_frags++;
stats.tx_bytes += PKTLEN(radioPacket);
}
+ keepalive_needed = 0;
stats.tx_pkts++;
}
*
*/
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:
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;
}
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)) {
}
// 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
// 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 {
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;
*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
}
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);
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;
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 {
} 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);
return rv;
}
-void print_stats() {
- printf("Up since %s", ctime(&stats.boot_time));
- printf(" receive packets: %lu fragments: %lu bytes: %lu\n",
- stats.tx_pkts, stats.tx_frags, stats.tx_bytes);
- printf(" transmit packets: %lu fragments: %lu bytes: %lu\n",
- stats.rx_pkts, stats.rx_frags, stats.rx_bytes);
- printf(" forward packets: %lu\n", stats.fw_pkts);
+void print_stats(int fd, int argc, char **argv) {
+ VTY_HEAD;
+
+ VTY_printf("Up since %s", ctime(&stats.boot_time));
+ VTY_printf(" receive packets: %lu fragments: %lu bytes: %lu\n",
+ stats.rx_pkts, stats.rx_frags, stats.rx_bytes);
+ VTY_printf(" transmit packets: %lu fragments: %lu bytes: %lu\n",
+ stats.tx_pkts, stats.tx_frags, stats.tx_bytes);
+ VTY_printf(" forward packets: %lu\n", stats.fw_pkts);
+ VTY_flush();
}
-int eval_cmd(char *cmd) {
- char arg[1024];
- int int_arg;
- switch (cmd[0]) {
- case 'c':
- config_print(&driver_config);
- return 0;
- case 'd':
- if (sscanf(cmd, "d %s\n", arg) == 1) {
- nw_print_dotfile(arg);
- } else {
- printf("error: include a filename!\n");
- }
- return 0;
- case 'i':
- if (sscanf(cmd, "i %i\n", &int_arg) == 1) {
- info("invalidating node 0x%x\n", int_arg);
- nw_inval_node(int_arg);
+void print_help(int fd, int argc, char **argv) {
+ VTY_HEAD;
+ VTY_printf("ip-driver console\r\n");
+ VTY_printf(" conf : print configuration info\r\n");
+ VTY_printf(" stats : print statistics\r\n");
+ VTY_printf(" shutdown : shutdown the driver\r\n");
+ VTY_printf(" chan <c> : switch to channel 'c'\r\n");
+ VTY_printf(" dot <dotfile>: print dot-file of topology\r\n");
+ VTY_printf(" log {DEBUG INFO WARN ERROR FATAL}: set loglevel\r\n");
+
+ VTY_printf("\r\n Routing commands:\r\n");
+ VTY_printf(" inval <nodeid> : invalidate a router\r\n");
+ VTY_printf(" add <n1> <n2> : add a persistent link between n1 and n2\r\n");
+ VTY_printf(" links : print link detail\r\n");
+ VTY_printf(" routes : print routes\r\n");
+ VTY_printf(" newroutes : recalculate routes\r\n");
+ VTY_printf(" controller <n> : add a new controller\r\n");
+#ifdef CENTRALIZED_ROUTING
+ VTY_printf(" install <HOP | SRC> <n1> <n2> [reverse]: install a route between n1 and n2\r\n");
+ VTY_printf(" uninstall <n1> <n2>: uninstall a route between n1 and n2\r\n");
+#endif
+
+ VTY_printf("\r\n");
+ VTY_printf(" help: print this help\r\n");
+ VTY_flush();
+}
+
+void sh_loglevel(int fd, int argc, char **argv) {
+ VTY_HEAD;
+ int i;
+
+ if (argc != 2) return;
+ for (i = 0; i < 5; i++) {
+ if (strcmp(log_names[i], argv[1]) == 0) {
+ VTY_printf("setting verbosity to %s\r\n", log_names[i]);
+ log_setlevel(i);
}
- return 0;
- case 'l':
- nw_print_links();
- return 0;
- case 'p':
- nw_print_routes();
- return 0;
- case 's':
- print_stats();
- return 0;
- case 't':
- nw_test_routes();
- return 0;
- case 'v':
- if (sscanf(cmd, "v %s\n", arg) == 1) {
- int i;
- for (i = 0; i < 5; i++) {
- if (strcmp(log_names[i], arg) == 0) {
- printf("setting verbosity to %s\n", log_names[i]);
- log_setlevel(i);
- }
- }
+ }
+ VTY_flush();
+}
+
+void sh_dotfile(int fd, int argc, char **argv) {
+ VTY_HEAD;
+ if (argc == 2) {
+ VTY_printf("writing topology to %s\r\n", argv[1]);
+ nw_print_dotfile(argv[1]);
+ } else {
+ VTY_printf("error: include a filename!\r\n");
+ }
+ VTY_flush();
+}
+
+void sh_chan(int fd, int argc, char **argv) {
+ VTY_HEAD;
+ if (argc != 2) {
+ VTY_printf("%s <channel>\r\n", argv[0]);
+ } else {
+ int channel = atoi(argv[1]);
+ if (channel < 11 || channel > 26) {
+ VTY_printf("channel must be in [11:26]\r\n");
+ } else {
+ driver_config.channel = channel;
+ VTY_printf("setting channel to %i\r\n", channel);
+ configure_setparms(&driver_config, CONFIG_SET_PARM);
}
- return 0;
- case 'h':
- default:
- printf("ip-driver console\n");
- printf(" c: print configuration info\n");
- printf(" d <dotfile>: print dot-file of topology\n");
- printf(" i <nodeid>: invalidate a router\n");
- printf(" l: print link detail\n");
- printf(" p: print routes\n");
- printf(" t: recalculate routes\n");
- printf(" v {DEBUG INFO WARN ERROR FATAL}: set verbosity\n");
- printf(" s: print statistics\n");
- printf("\n");
- printf(" h: print this help\n");
}
+ VTY_flush();
+}
- return 0;
+#ifdef CENTRALIZED_ROUTING
+void sh_install(int fd, int argc, char **argv) {
+ VTY_HEAD;
+ int flags = 0;
+ struct split_ip_msg msg;
+ if (argc < 4) {
+ goto usage;
+ }
+ if (strcmp("HOP", argv[1]) == 0)
+ flags |= HYDRO_METHOD_HOP;
+ else if (strcmp("SRC", argv[1]) == 0) {
+ flags |= HYDRO_METHOD_SOURCE;
+ } else goto usage;
+
+ argc -= 4;
+ while (argc > 0) {
+ if (argv[argc+3][0] == 'R') {
+ flags |= HYDRO_INSTALL_REVERSE;
+ } else goto usage;
+ argc--;
+ }
+ memset(&msg, 0, sizeof(struct split_ip_msg));
+ memcpy(msg.hdr.ip6_src.s6_addr, __my_address.s6_addr, 8);
+ memcpy(msg.hdr.ip6_dst.s6_addr, __my_address.s6_addr, 8);
+ msg.hdr.ip6_src.s6_addr16[7] = htons(atoi(argv[2]));
+ msg.hdr.ip6_dst.s6_addr16[7] = htons(atoi(argv[3]));
+
+ VTY_printf("installing route between 0x%x and 0x%x\r\n", atoi(argv[2]), atoi(argv[3]));
+ install_route(&msg, flags);
+
+ VTY_flush();
+ return;
+ usage:
+ VTY_printf("%s <HOP | SRC> <n1> <n2> [REV]\r\n", argv[0]);
+ VTY_flush();
+}
+
+void sh_uninstall(int fd, int argc, char **argv) {
+ VTY_HEAD;
+ if (argc != 3) {
+ VTY_printf("%s <n1> <n2>\r\n", argv[0]);
+ VTY_flush();
+ return;
+ }
+ int n1 = atoi(argv[1]);
+ int n2 = atoi(argv[2]);
+ VTY_printf("uninstalling route from 0x%x to 0x%x\r\n", n1, n2);
+ uninstall_route(n1, n2);
+ VTY_flush();
+}
+#endif
+
+void sh_controller(int fd, int argc, char **argv) {
+ VTY_HEAD;
+ if (argc != 2) {
+ VTY_printf("%s <cid>\r\n", argv[0]);
+ } else {
+ int n = atoi(argv[1]);
+ get_insert_router(n);
+ nw_add_controller(n);
+ }
+ VTY_flush();
}
+struct vty_cmd vty_cmd_list[] = {{"help", print_help},
+ {"stats", print_stats},
+ {"links", nw_print_links},
+ {"route", nw_print_routes},
+ {"newroutes", nw_test_routes},
+ {"add", nw_add_sticky_edge},
+ {"inval", nw_inval_node_sh},
+ {"conf", config_print},
+ {"log", sh_loglevel},
+ {"dot", sh_dotfile},
+ {"chan", sh_chan},
+#ifdef CENTRALIZED_ROUTING
+ {"install", sh_install},
+ {"uninstall", sh_uninstall},
+#endif
+ {"controller", sh_controller},
+ {"shutdown", (void(*)(int,int,char**))driver_shutdown}};
+
/* shifts data between the serial port and the tun interface */
int serial_tunnel(int tun_fd) {
- char cmd_buf[2][1024], *cmd_cur;
- int cur_buf = 0;
fd_set fs;
- int maxfd = 0;
+ int maxfd = -1;
+ int usecs_remain = KEEPALIVE_INTERVAL;
time_t last_aging, current_time;
time(&last_aging);
-#ifndef SIM
- int pan_fd = serial_source_fd(ser_src);
+#ifndef SF_SRC
+ int pan_fd = opt_listenonly ? -1 : serial_source_fd(ser_src);
#else
- int pan_fd = sf_fd;
+ int pan_fd = opt_listenonly ? -1 : sf_fd;
#endif
- cmd_cur = cmd_buf[0];
-
- /* disable input buffering on stdin since we're going to accumulate
- the input outselves, and don't want to block */
- if (isatty(fileno(stdin))) {
- struct termios tio;
- /* disable it on the fd */
- if (tcgetattr(fileno(stdin), &tio))
- return -1;
- tio.c_lflag &= ~ICANON;
- if (tcsetattr(fileno(stdin), TCSANOW, &tio))
- return -1;
- /* and also in libc */
- setbuf(stdin, NULL);
- }
while (1) {
+ int n_fds;
+ struct timeval tv;
+ if (do_shutdown) return 0;
+
FD_ZERO(&fs);
- FD_SET(tun_fd, &fs);
- FD_SET(pan_fd, &fs);
- maxfd = max(tun_fd, pan_fd);
- if (isatty(fileno(stdin))) {
- FD_SET(fileno(stdin), &fs);
- maxfd = max(fileno(stdin), maxfd);
+ if (opt_listenonly) {
+ maxfd = -1;
+ } else {
+ FD_SET(tun_fd, &fs);
+ FD_SET(pan_fd, &fs);
+
+ maxfd = max(tun_fd, pan_fd);
}
+
if (radvd_fd >= 0) {
FD_SET(radvd_fd, &fs);
maxfd = max(radvd_fd, maxfd);
}
- if (select(maxfd + 1, &fs, NULL, NULL, NULL) < 0)
- continue;
+ maxfd = max(vty_add_fds(&fs), maxfd);
+ maxfd = max(routing_add_fds(&fs), maxfd);
-
- /* data available on tunnel device */
- if (FD_ISSET(tun_fd, &fs))
- while(tun_input());
+ // having a timeout also means that we poll for new packets every
+ // so often, which is apparently A Good Thing
+ tv.tv_sec = 0;
+ tv.tv_usec = KEEPALIVE_TIMEOUT;
+ if ((n_fds = select(maxfd + 1, &fs, NULL, NULL, &tv)) < 0) {
+ continue;
+ }
+ usecs_remain -= (KEEPALIVE_TIMEOUT - tv.tv_usec);
+ if (usecs_remain <= 0) {
+ if (keepalive_needed) {
+ configure_setparms(&driver_config, CONFIG_KEEPALIVE);
+ } else keepalive_needed = 1;
- if (FD_ISSET(pan_fd, &fs))
- while(serial_input());
-
- if (FD_ISSET(fileno(stdin), &fs)) {
- *cmd_cur++ = getc(stdin);
- if (*(cmd_cur - 1) == '\n' ||
- cmd_cur - cmd_buf[cur_buf] == 1024) {
- *cmd_cur = '\0';
- if (cmd_cur == cmd_buf[cur_buf] + 1) {
- eval_cmd(cmd_buf[(cur_buf + 1) % 2]);
- } else {
- eval_cmd(cmd_buf[cur_buf]);
- cur_buf = (cur_buf + 1) % 2;
- }
- cmd_cur = cmd_buf[cur_buf];
- }
+ usecs_remain = KEEPALIVE_INTERVAL;
}
+ if (!opt_listenonly) {
+ int more_data;
+ /* check for data */
+ do {
+ more_data = tun_input();
+ more_data = serial_input() || more_data ;
+ } while (more_data);
+ }
+
+ vty_process(&fs);
+ routing_process(&fs);
+
if (radvd_fd >= 0 && FD_ISSET(radvd_fd, &fs)) {
radvd_process();
}
-#ifndef SIM
-/* if (tcdrain(pan_fd) < 0) { */
-/* fatal("tcdrain error: %i\n", errno); */
-/* exit(3); */
-/* } */
-#endif
-
/* end of data available */
time(¤t_time);
if (current_time > last_aging + (FRAG_EXPIRE_TIME / 1024)) {
}
}
- 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);
}
if (argc - optind != 2) {
-#ifndef SIM
- fatal("usage: %s [-c config] <device> <rate>\n", argv[0]);
+#ifndef SF_SRC
+ fatal("usage: %s [-c config] [-n] <device> <rate>\n", argv[0]);
#else
fatal("usage: %s [-c config] <host> <port>\n", argv[0]);
#endif
exit(2);
}
-#ifdef DBG_TRACK_FLOWS
- dbg_file = fopen("dbg.txt", "w");
- if (dbg_file == NULL) {
- perror("main: opening dbg file:");
- exit(1);
- }
- signal(SIGUSR2, truncate_dbg);
-#endif
+ fifo_open();
+ signal(SIGINT, driver_shutdown);
if (config_parse(def_configfile, &driver_config) != 0) {
fatal ("config parse of %s failed!\n", def_configfile);
}
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;
}
#include "lib6lowpan.h"
#include "tun_dev.h"
+#include "logging.h"
/*
return fd;
failed:
- perror("tun_open");
+ log_fatal_perror("tun_open");
close(fd);
return -1;
}
/* 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;
}
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;
}
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;
}
--- /dev/null
+
+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
--- /dev/null
+/*
+ * "Copyright (c) 2008, 2009 The Regents of the University of California.
+ * All rights reserved."
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice, the following
+ * two paragraphs and the author appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
+ *
+ */
+
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+#include "logging.h"
+#include "vty.h"
+
+
+void do_echo(int fd, int argc, char ** argv) {
+ VTY_HEAD;
+ if (argc > 1) {
+ VTY_printf("%s\r\n", argv[1]);
+ VTY_flush();
+ }
+}
+
+struct vty_cmd echo = {"echo", do_echo};
+
+void shutdown() {
+ vty_shutdown();
+ exit(0);
+}
+
+int main(int argc, char **argv) {
+ int maxfd;
+ fd_set fds;
+ struct vty_cmd_table t;
+ log_init();
+ log_setlevel(LOGLVL_DEBUG);
+
+ signal(SIGINT, shutdown);
+
+ t.n = 1;
+ t.table = &echo;
+
+
+ vty_init(&t, atoi(argv[1]));
+ while (1) {
+ FD_ZERO(&fds);
+ maxfd = vty_add_fds(&fds);
+
+ select(maxfd+1, &fds, NULL, NULL, NULL);
+
+ vty_process(&fds);
+ }
+ info("Done, exiting\n");
+
+}
--- /dev/null
+/*
+ * "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 --;
+ }
+}
--- /dev/null
+/*
+ * "Copyright (c) 2008 The Regents of the University of California.
+ * All rights reserved."
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice, the following
+ * two paragraphs and the author appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
+ *
+ */
+/*
+ * @author Stephen Dawson-Haggerty <stevedh@eecs.berkeley.edu>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <signal.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include "vty.h"
+#include "../logging.h"
+
+#define max(X,Y) (((X) > (Y)) ? (X) : (Y))
+
+typedef enum {
+ FALSE = 0,
+ TRUE = 1,
+} bool;
+
+enum {
+ VTY_REMOVE_PENDING = 0x1,
+};
+
+struct vty_client {
+ int flags;
+ int readfd;
+ int writefd;
+ struct sockaddr_in ep;
+ struct vty_client *next;
+
+ int buf_off;
+ unsigned char buf[1024];
+};
+
+static int sock = -1;
+static struct vty_client *conns = NULL;
+static struct vty_cmd_table *cmd_tab;
+static char prompt_str[40];
+
+int vty_init(struct vty_cmd_table * cmds, short port) {
+ struct sockaddr_in si_me;
+ struct vty_client *tty_client;
+ int len, yes = 1;
+
+ conns = NULL;
+ cmd_tab = cmds;
+
+ strncpy(prompt_str, "blip:", 5);
+ gethostname(prompt_str+5, sizeof(prompt_str)- 5);
+ len=strlen(prompt_str+5);
+ prompt_str[len+5]='>';
+ prompt_str[len+6]=' ';
+ prompt_str[len+7]='\0';
+
+ if (isatty(fileno(stdin))) {
+ setbuf(stdin, NULL);
+ tty_client = (struct vty_client *)malloc(sizeof(struct vty_client));
+ memset(tty_client, 0, sizeof(struct vty_client));
+ tty_client->flags = 0;
+ tty_client->readfd = fileno(stdin);
+ tty_client->writefd = fileno(stdout);
+ tty_client->next = NULL;
+ conns = tty_client;
+ }
+
+ sock = socket(PF_INET, SOCK_STREAM, 0);
+ if (sock < 0) {
+ log_fatal_perror("vty: socket");
+ return -1;
+ }
+
+ if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) {
+ log_fatal_perror("vty: setsockopt");
+ goto abort;
+ }
+
+ si_me.sin_family = AF_INET;
+ si_me.sin_port = htons(port);
+ si_me.sin_addr.s_addr = htonl(INADDR_ANY);
+ if (bind(sock, (struct sockaddr *)&si_me, sizeof(si_me)) < 0) {
+ log_fatal_perror("vty: bind");
+ goto abort;
+ }
+
+ if (listen(sock, 2) < 0) {
+ log_fatal_perror("vty: listen");
+ goto abort;
+ }
+
+ return 0;
+ abort:
+ close(sock);
+ sock = -1;
+ return -1;
+}
+
+int vty_add_fds(fd_set *fds) {
+ int maxfd;
+ struct vty_client *cur;
+ if (sock >= 0) FD_SET(sock, fds);
+ maxfd = sock;
+
+ for (cur = conns; cur != NULL; cur = cur->next) {
+ if (cur->flags & VTY_REMOVE_PENDING) continue;
+ FD_SET(cur->readfd, fds);
+ maxfd = max(maxfd, cur->readfd);
+ }
+ return maxfd;
+}
+
+static void vty_print_string(struct vty_client *c, const char *fmt, ...) {
+ char buf[1024];
+ int len;
+ va_list ap;
+ va_start(ap, fmt);
+ len = vsnprintf(buf, 1024, fmt, ap);
+ write(c->writefd, buf, len);
+}
+
+static void prompt(struct vty_client *c) {
+ vty_print_string(c, prompt_str);
+}
+
+static void vty_new_connection() {
+ struct vty_client * c = malloc(sizeof(struct vty_client));
+ socklen_t len;
+ if (c == NULL) return;
+
+ len = sizeof(struct sockaddr_in);
+ c->readfd = c->writefd = accept(sock, (struct sockaddr *)&c->ep, &len);
+ if (c->readfd < 0) {
+ error("Accept failed!\n");
+ log_fatal_perror(0);
+ free(c);
+ return;
+ }
+ c->buf_off = 0;
+
+ info("VTY: new connection accepted from %s\n", inet_ntoa(c->ep.sin_addr));
+ vty_print_string(c, "Welcome to the blip console!\r\n");
+ vty_print_string(c, " type 'help' to print the command options\r\n");
+ prompt(c);
+ c->flags = 0;
+ c->next = conns;
+ conns = c;
+}
+
+void vty_close_connection(struct vty_client *c) {
+ close(c->readfd);
+ if (c->readfd != c->writefd) close(c->writefd);
+ c->flags |= VTY_REMOVE_PENDING;
+}
+
+
+void vty_dispatch_command(struct vty_client *c) {
+ int argc, i;
+ char *argv[N_ARGS];
+ init_argv((char *)c->buf, c->buf_off, argv, &argc);
+
+ if (argc > 0) {
+ for (i = 0; i < cmd_tab->n; i++) {
+ if (strncmp(argv[0], cmd_tab->table[i].name,
+ strlen(cmd_tab->table[i].name)) == 0) {
+ cmd_tab->table[i].fn(c->writefd, argc, argv);
+ break;
+ }
+
+ if (strncmp(argv[0], "quit", 4) == 0) {
+ vty_close_connection(c);
+ return;
+ }
+ }
+ }
+ prompt(c);
+}
+
+void vty_handle_data(struct vty_client *c) {
+ int len, i;
+ bool prompt_pending = FALSE;
+ len = read(c->readfd, c->buf + c->buf_off, sizeof(c->buf) - c->buf_off);
+ if (len <= 0) {
+ warn("Invalid read on connection from %s: closing\n",
+ inet_ntoa(c->ep.sin_addr));
+ vty_close_connection(c);
+ }
+ c->buf_off += len;
+ // try to scan the whole line we're building up and remove/process
+ // any telnet escapes in there
+ for (i = 0; i < c->buf_off; i++) {
+ int escape_len;
+
+ if (c->buf[i] == 255) {
+ escape_len = 2;
+ // process and remove a command;
+ // the command code is in buf[i+1]
+ switch (c->buf[i+1]) {
+ case TELNET_INTERRUPT:
+ // ignore the command buffer we've accumulated
+ memmove(&c->buf[0], &c->buf[i+2], c->buf_off - i - 2);
+ c->buf_off -= i + 2;
+ i = -1;
+ prompt_pending = TRUE;
+ continue;
+ }
+ if (c->buf[i+1] >= 250) {
+ unsigned char response[3];
+ // we don't do __anything__
+ response[0] = 255;
+ response[1] = TELNET_WONT;
+ response[2] = c->buf[i+2];
+ write(c->writefd, response, 3);
+ escape_len++;
+ }
+
+ // this isn't like the most efficient parser ever, but since we
+ // don't ask for anything and reply to everyone with DONT it seems okay.
+ memmove(&c->buf[i], &c->buf[i+escape_len],
+ c->buf_off - (i + escape_len));
+ c->buf_off -= escape_len;
+ // restart processing at the same place
+ i--;
+ } else if (c->buf[i] == 4) {
+ // EOT : make C-d work
+ vty_close_connection(c);
+ }
+ // technically, clients are supposed to send \r\n as a newline.
+ // however, the client in busybox (an important one) doesn't
+ // escape the terminal input and so only sends \n.
+ if (/* i > 0 && c->buf[i-1] == '\r' && */ c->buf[i] == '\n') {
+ c->buf[i] = '\0';
+ prompt_pending = FALSE;
+ vty_dispatch_command(c);
+
+ // start a new command at the head of the buffer
+ memmove(&c->buf[0], &c->buf[i+1], c->buf_off - i - 1);
+ c->buf_off -= i + 1;
+ i = -1;
+ }
+ }
+
+ if (prompt_pending) {
+ vty_print_string(c, "\r\n");
+ prompt(c);
+ prompt_pending = FALSE;
+ }
+}
+
+int vty_process(fd_set *fds) {
+ struct vty_client *prev, *cur, *next;
+ if (sock >= 0 && FD_ISSET(sock, fds)) {
+ vty_new_connection();
+ }
+ for (cur = conns; cur != NULL; cur = cur->next) {
+ if (FD_ISSET(cur->readfd, fds)) {
+ vty_handle_data(cur);
+ }
+ }
+
+ prev = NULL;
+ cur = conns;
+ while (cur != NULL) {
+ next = cur->next;
+ if (cur->flags & VTY_REMOVE_PENDING) {
+ info("VTY: removing connection with endpoint %s\n",
+ inet_ntoa(cur->ep.sin_addr));
+ free(cur);
+ if (cur == conns) conns = next;
+ if (prev != NULL) prev->next = next;
+ } else {
+ prev = cur;
+ }
+ cur = next;
+ }
+
+ return 0;
+}
+
+void vty_shutdown() {
+ struct vty_client *cur = conns, *next;
+ if (sock >= 0) close(sock);
+
+ while (cur != NULL) {
+ next = cur->next;
+ if (!(cur->flags & VTY_REMOVE_PENDING)) {
+ close(cur->readfd);
+ if (cur->readfd != cur->writefd) close(cur->writefd);
+ }
+ free(cur);
+ cur = next;
+ }
+}
--- /dev/null
+/*
+ * "Copyright (c) 2008 The Regents of the University of California.
+ * All rights reserved."
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice, the following
+ * two paragraphs and the author appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
+ *
+ */
+/*
+ * @author Stephen Dawson-Haggerty <stevedh@eecs.berkeley.edu>
+ *
+ * This is a very simple set of functions to allow a program using a
+ * single blocking select() loop to include a telnet server. Most of
+ * the telnet RFC854 protocol is not implemented; this just gives you
+ * an easy way to add a simple shell that doesn't do much.
+ *
+ * Readline-like editing would be nice; unfortunatly readline itself
+ * is GPL, so it's not an option.
+ */
+
+#ifndef _VTY_H_
+#define _VTY_H_
+
+#include <unistd.h>
+#include <sys/select.h>
+
+// helpful macros since you can't do straight printf() on a socket
+#define VTY_HEAD char __vty_buf[4096]; int __vty_len = 0
+#define VTY_printf(fmt, args...) __vty_len += snprintf(__vty_buf + __vty_len, 4096 - __vty_len, \
+ fmt, ## args)
+#define VTY_flush() write(fd, __vty_buf, __vty_len); __vty_len = 0
+
+#define VTYNAMSIZ 16
+
+// set these up and pass it to vty_init(). the only builtin is 'quit'.
+struct vty_cmd {
+ char name[VTYNAMSIZ];
+ void (*fn)(int fd, int argc, char **argv);
+};
+
+struct vty_cmd_table {
+ int n;
+ struct vty_cmd * table;
+};
+
+int vty_init(struct vty_cmd_table *cmd_tab, short port);
+int vty_add_fds(fd_set *fds);
+int vty_process(fd_set *fds);
+void vty_shutdown();
+
+// defined in util.c N_ARGS is the maximum number length of argv.
+#define N_ARGS 30
+void init_argv(char *cmd, int len, char **argv, int *argc);
+
+
+// values from telnet rfc854. We don't implement very much at all of
+// the telnet protocol
+#define TELNET_INTERRUPT 244
+#define TELNET_WONT 252
+
+#endif
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,
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;
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
*/
};
-/*
- * 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];
};
IP_NUMBER_FRAGMENTS = 12,
};
+#ifndef BLIP_L2_RETRIES
+#define BLIP_L2_RETRIES 10
+#endif
+
#endif
--- /dev/null
+/*
+ * "Copyright (c) 2008, 2009 The Regents of the University of California.
+ * All rights reserved."
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice, the following
+ * two paragraphs and the author appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
+ *
+ */
+#ifndef TRACKFLOWS_H_
+#define TRACKFLOWS_H_
+
+#ifndef PC
+enum {
+ AM_FLOW_ID_MSG = 248,
+};
+
+nx_struct flow_id {
+ nxle_uint16_t id;
+};
+
+nx_struct flow_id_msg {
+ nx_struct flow_id flow;
+ nxle_uint16_t src;
+ nxle_uint16_t dst;
+ nxle_uint16_t local_address;
+ nxle_uint8_t nxt_hdr;
+ nxle_uint8_t n_attempts;
+ nx_struct {
+ nxle_uint16_t next_hop;
+ nxle_uint16_t tx;
+ } attempts[3];
+};
+#else
+
+#include <stdint.h>
+struct flow_id {
+ uint16_t id;
+};
+
+
+struct flow_id_msg {
+ uint16_t flow;
+ uint16_t src;
+ uint16_t dst;
+ uint16_t local_address;
+ uint8_t nxt_hdr;
+ uint8_t n_attempts;
+ struct {
+ uint16_t next_hop;
+ uint16_t tx;
+ } attempts[3];
+};
+#endif
+
+#endif
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 {
CONFIG_ERROR_BOOTED,
};
+enum {
+ KEEPALIVE_INTERVAL = 500000,
+ KEEPALIVE_TIMEOUT = 5000,
+};
+
#ifndef PC
uint16_t delay;
} retx;
struct {
- hw_addr_t addr;
+ ieee154_saddr_t addr;
uint8_t channel;
} rf;
} __attribute__((packed)) config_cmd_t;
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;
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
*/
* IP metadata and routing structures
*/
struct ip_metadata {
- hw_addr_t sender;
+ ieee154_saddr_t sender;
uint8_t lqi;
uint8_t padding[1];
};
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
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
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
+/*
+ * "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_
*/
#ifndef _LIB6LOWPAN_H_
#define _LIB6LOWPAN_H_
-
#include <stdint.h>
#include <stddef.h>
#include "6lowpan.h"
#include "ip.h"
-#ifdef __TARGET_mips__
-// #warning "Using big endian byte order"
-#define ntoh16(X) (X)
-#define hton16(X) (X)
-#define ntoh32(X) (X)
-#define hton32(X) (X)
+#if defined(PC) || defined(__TARGET_mips__)
+// use library versions if on linux
+#include <netinet/in.h>
+#define ntoh16(X) ntohs(X)
+#define hton16(X) htons(X)
+#define ntoh32(X) ntohl(X)
+#define hton32(X) htonl(X)
+
+#if defined(PC)
+#define leton16(X) hton16(X)
+#ifndef htole16
+#define htole16(X) (X)
+#endif
+#else
#define leton16(X) (((((uint16_t)(X)) << 8) | ((uint16_t)(X) >> 8)) & 0xffff)
#define htole16(X) leton16(X)
-#else
-// #warning "Using little endian byte order"
-#define ntoh16(X) (((((uint16_t)(X)) >> 8) | ((uint16_t)(X) << 8)) & 0xffff)
-#define hton16(X) (((((uint16_t)(X)) << 8) | ((uint16_t)(X) >> 8)) & 0xffff)
+#endif
+
+#else
+// otherwise have to provide our own
+
#define leton16(X) hton16(X)
+#ifndef htole16
#define htole16(X) (X)
-#define ntoh32(X) ((((uint32_t)(X) >> 24) & 0x000000ff)| \
- ((((uint32_t)(X) >> 8)) & 0x0000ff00) | \
- ((((uint32_t)(X) << 8)) & 0x00ff0000) | \
- ((((uint32_t)(X) << 24)) & 0xff000000))
-
-#define hton32(X) ((((uint32_t)(X) << 24) & 0xff000000)| \
- ((((uint32_t)(X) << 8)) & 0x00ff0000) | \
- ((((uint32_t)(X) >> 8)) & 0x0000ff00) | \
- ((((uint32_t)(X) >> 24)) & 0x000000ff))
#endif
+#define ntoh16(X) (((((uint16_t)(X)) >> 8) | ((uint16_t)(X) << 8)) & 0xffff)
+#define hton16(X) (((((uint16_t)(X)) << 8) | ((uint16_t)(X) >> 8)) & 0xffff)
+
+/* this is much more efficient since gcc can insert swpb now. */
+static uint32_t __attribute__((unused)) ntoh32(uint32_t i) {
+ uint16_t lo = (uint16_t)i;
+ uint16_t hi = (uint16_t)(i >> 16);
+ lo = (lo << 8) | (lo >> 8);
+ hi = (hi << 8) | (hi >> 8);
+ return (((uint32_t)lo) << 16) | ((uint32_t)hi);
+}
+#define hton32(X) ntoh32(X)
#define ntohs(X) ntoh16(X)
#define htons(X) hton16(X)
-
#define ntohl(X) ntoh32(X)
#define htonl(X) hton32(X)
+#endif
+
#ifdef DEF_MEMCPY
#define memcpy(X,Y,Z) ip_memcpy(X,Y,Z)
/*
* 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
* 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
/*
* 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'.
// 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.
*/
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;
SOURCES=lib6lowpan.c lib6lowpanIP.c lib6lowpanFrag.c
INCLUDE=../include/
+IP_HDRS=$(INCLUDE)/6lowpan.h $(INCLUDE)/ip.h $(INCLUDE)/lib6lowpan.h
###############
##
AR=ar
endif
-CFLAGS=-DPC -g -I$(INCLUDE)
+CFLAGS=-DPC -g -I$(INCLUDE)
TEST=testhc.c
###############
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)
+/*
+ * "Copyright (c) 2008, 2009 The Regents of the University of California.
+ * All rights reserved."
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice, the following
+ * two paragraphs and the author appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
+ *
+ */
#ifndef NO_IP_MALLOC
#include <stdint.h>
#include <stdio.h>
* 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)
* 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;
/*
* 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;
*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
*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
*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
*((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
-/*l
+/*
* "Copyright (c) 2008 The Regents of the University of California.
* All rights reserved."
*
}
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] &&
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 &&
addr[13] == 0));
}
+#if LIB6LOWPAN_FULL
/*
* return the length of the compressed fields in buf
*/
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)
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;
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.
// 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
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 {
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;
u_info->payload_offset += nhdr_len;
extra_header_length += nhdr_len;
}
+
+ u_info->transport_ptr = dest;
}
u_info->payload_start = buf;
* 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)) ||
/* } */
+
+#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)))
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
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
+
+/*
+ * "Copyright (c) 2008, 2009 The Regents of the University of California.
+ * All rights reserved."
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice, the following
+ * two paragraphs and the author appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
+ *
+ */
#include <stdio.h>
#include <stdint.h>
-// #include <assert.h>
#include <string.h>
#include "tcplib.h"
struct circ_buf {
- uint8_t *map;
- uint16_t map_len;
uint8_t *data_start;
uint8_t *data_head;
uint16_t data_len;
uint32_t head_seqno;
};
-int circ_buf_init(void *data, int len, uint32_t seqno, int incl_map) {
+int circ_buf_init(void *data, int len, uint32_t seqno) {
struct circ_buf *b = (struct circ_buf *)data;
- int bitmap_len = ((len - sizeof(struct circ_buf)) / 9);
- // int data_len = bitmap_len * 8;
-
- // printf("circ_buf_init: len: %i data_len: %i bitmap_len: %i\n", len, data_len, bitmap_len);
- // assert(bitmap_len + data_len + sizeof(struct circ_buf) <= len);
if (len < sizeof(struct circ_buf))
return -1;
- if (incl_map) {
- b->map = (uint8_t *)(b + 1);
- b->map_len = bitmap_len;
- b->data_start = b->map + bitmap_len;
- b->data_len= bitmap_len * 8;
- memset(b->map, 0, bitmap_len * 9);
- } else {
- b->map = NULL;
- b->map_len = 0;
- b->data_start = (uint8_t *)(b + 1);
- b->data_len = len - sizeof(struct circ_buf);
- memset(b->data_start, 0, b->data_len);
- }
- b->data_head = b->data_start;
+ b->data_head = b->data_start = (uint8_t *)(b + 1);
+ b->data_len = len - sizeof(struct circ_buf);
b->head_seqno = seqno;
-
- // printf("circ_buf_init: buf: %p data_start: %p data_head: %p data_len: %i\n",
- // b, b->data_start, b->data_head, b->data_len);
-
return 0;
}
-#define BIT_SET(off,map) map[(off)/8] |= (1 << (7 - ((off) % 8)))
-#define BIT_UNSET(off,map) map[(off)/8] &= ~(1 << (7 - ((off) % 8)))
-#define BIT_ISSET(off, map) map[(off)/8] & 1 << (7 - (off) % 8)
-
-static void bitmap_mark(struct circ_buf *b, uint8_t *data, int len) {
- int offset = data - b->data_start;
- if (b->map_len == 0) return;
- while (len-- > 0) {
- BIT_SET(offset, b->map);
- offset = (offset + 1) % b->data_len;
- }
-}
-
-/* return the sequence number of the first byte of data in the buffer;
- this is what the stack can ACK. */
uint32_t circ_get_seqno(void *buf) {
struct circ_buf *b = (struct circ_buf *)buf;
return b->head_seqno;
}
-void circ_set_seqno(void *buf, uint32_t seqno) {
- struct circ_buf *b = (struct circ_buf *)buf;
- b->head_seqno = seqno;
-}
-
-uint16_t circ_get_window(void *buf) {
- struct circ_buf *b = (struct circ_buf *)buf;
- return b->data_len;
-}
-
-/* read as many contiguous bytes from the head of the buffer as
- * possible, and update the internal data structures to shorten the
- * buffer
- *
- * buf: the circular buffer
- * data: a pointer which will be updated with the location of the data
- * return: the number of bytes available
- */
-int circ_buf_read_head(void *buf, char **data) {
- struct circ_buf *b = (struct circ_buf *)buf;
- int off = b->data_head - b->data_start;
- int rlen = 0;
- *data = b->data_head;
- while (BIT_ISSET(off, b->map) && off < b->data_len) {
- BIT_UNSET(off, b->map);
- rlen++;
- b->head_seqno++;
- b->data_head ++;
- if (b->data_head == b->data_start + b->data_len)
- b->data_head = b->data_start;
- off++;
- }
- return rlen;
-}
-
-
static void get_ptr_off_1(struct circ_buf *b, uint32_t sseqno, int len,
uint8_t **writeptr, int *w_len) {
uint8_t *endptr = b->data_start + b->data_len;
int offset;
*writeptr = NULL;
- *w_len = 0;
+ *w_len = len;
/* write up to either the end of the buffer */
offset = sseqno - b->head_seqno;
if (b->data_head + offset < endptr) {
- *w_len = len;
*writeptr = b->data_head + offset;
- if (*writeptr + *w_len > endptr) {
- *w_len = endptr - *writeptr;
- }
+ } else {
+ offset -= (endptr - b->data_head);
+ *writeptr = b->data_start + offset;
+ }
+ if (*writeptr + *w_len > endptr) {
+ *w_len = endptr - *writeptr;
}
}
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;
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
+/*
+ * "Copyright (c) 2008, 2009 The Regents of the University of California.
+ * All rights reserved."
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice, the following
+ * two paragraphs and the author appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
+ *
+ */
#ifndef __CIRC_H_
#define __CIRC_H_
#include <stdint.h>
-int circ_buf_init(void *data, int len, uint32_t seqno, int inc_map);
+int circ_buf_init(void *data, int len, uint32_t seqno);
-int circ_buf_write(void *buf, uint32_t sseqno,
+int circ_buf_write(char *buf, uint32_t sseqno,
uint8_t *data, int len);
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
+/*
+ * "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
*
return 1;
}
+#ifdef PC
+#include <arpa/inet.h>
+
+void print_conn(struct tcplib_sock *sock) {
+ char addr_buf[32];
+ printf("tcplib socket state: %i:\n", sock->state);
+ inet_ntop(AF_INET6, sock->l_ep.sin6_addr.s6_addr, addr_buf, 32);
+ printf(" local ep: %s port: %u\n", addr_buf, ntohs(sock->l_ep.sin6_port));
+ inet_ntop(AF_INET6, sock->r_ep.sin6_addr.s6_addr, addr_buf, 32);
+ printf(" remote ep: %s port: %u\n", addr_buf, ntohs(sock->r_ep.sin6_port));
+ printf(" tx buf length: %i\n", sock->tx_buf_len);
+}
+void print_headers(struct ip6_hdr *iph, struct tcp_hdr *tcph) {
+ char addr_buf[32];
+ printf("headers ip length: %i:\n", ntohs(iph->plen));
+ inet_ntop(AF_INET6, iph->ip6_src.s6_addr, addr_buf, 32);
+ printf(" source: %s port: %u\n", addr_buf, ntohs(tcph->srcport));
+ inet_ntop(AF_INET6, iph->ip6_dst.s6_addr, addr_buf, 32);
+ printf(" remote ep: %s port: %u\n", addr_buf, ntohs(tcph->dstport));
+ printf(" tcp seqno: %u ackno: %u\n", ntohl(tcph->seqno), ntohl(tcph->ackno));
+}
+#endif
+
static struct tcplib_sock *conn_lookup(struct ip6_hdr *iph,
struct tcp_hdr *tcph) {
struct tcplib_sock *iter;
- printfUART("looking up conns...\n");
+ //printf("looking up conns: %p %p\n", iph, tcph);
+ // print_headers(iph, tcph);
for (iter = conns; iter != NULL; iter = iter->next) {
+ // print_conn(iter);
printf("conn lport: %i\n", ntohs(iter->l_ep.sin6_port));
if (((memcmp(iph->ip6_dst.s6_addr, iter->l_ep.sin6_addr.s6_addr, 16) == 0) ||
isInaddrAny(&iter->l_ep.sin6_addr)) &&
return (struct tcp_hdr *)((msg->headers == NULL) ? msg->data :
msg->headers->hdr.data);
}
+ return NULL;
}
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;
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");
}
}
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;
// 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);
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);
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);
/* 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);
}
}
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
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;
}
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;
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) {
// 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
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;
}
} 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;
}
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) {
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;
}
/* 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");
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 */
/* 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;
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);
}
}
+/*
+ * "Copyright (c) 2008, 2009 The Regents of the University of California.
+ * All rights reserved."
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice, the following
+ * two paragraphs and the author appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
+ *
+ */
#ifndef TCPLIB_H_
#define TCPLIB_H_
+/*
+ * tcplib: a simple tcp implemented in a library
+ * @author Stephen Dawson-Haggerty <stevedh@eecs.berkeley.edu>
+ *
+ *
+ */
+
// #include <netinet/in.h>
#include "ip.h"
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;
/* 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;
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;
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
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
+/*
+ * "Copyright (c) 2008, 2009 The Regents of the University of California.
+ * All rights reserved."
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice, the following
+ * two paragraphs and the author appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
+ *
+ */
#include <stdio.h>
+#include <string.h>
#include "circ.h"
-void do_head_read(void *buf) {
- char *read_data;
- int i, data_len;
- data_len = circ_buf_read_head(buf, (void **)&read_data);
- printf("buf_read_head: %i\n", data_len);
- for (i = 0; i < data_len; i++)
- putc(((char *)read_data)[i], stdout);
- putc('\n', stdout);
-}
+/* void do_head_read(void *buf) { */
+/* char *read_data; */
+/* int i, data_len; */
+/* data_len = circ_buf_read_head(buf, (void **)&read_data); */
+/* printf("buf_read_head: %i\n", data_len); */
+/* for (i = 0; i < data_len; i++) */
+/* putc(((char *)read_data)[i], stdout); */
+/* putc('\n', stdout); */
+/* } */
void do_read(void *buf, uint32_t sseqno) {
char data[20];
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++)
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); */
+/*
+ * "Copyright (c) 2008, 2009 The Regents of the University of California.
+ * All rights reserved."
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice, the following
+ * two paragraphs and the author appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
+ *
+ */
#include <stdlib.h>
#include <unistd.h>
#include <linux/if.h>
#include <signal.h>
#include <string.h>
+#include <limits.h>
#include "ip.h"
#include "ip_malloc.h"
-#define BUFSZ 1024
-#define LOSS_RATE_RECPR 100
+#define BUFSZ 1000
+#define LOSS_RATE_RECPR 200
+#define LOSS_RATE_TRANS 200
int sock = 0;
-uint8_t iface_addr[16] = {0x20, 0x01, 0x00, 0x00, 0xde, 0xad, 0xbe, 0xef,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01};
-
+struct in6_addr iface_addr[16] = {{{0x20, 0x05, 0x00, 0x00, 0x00, 0x0, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}}};
struct sockaddr_in6 laddr;
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"); */
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);
}
}
struct timeval timeout;
FD_ZERO(&fds);
FD_SET(sock, &fds);
+ FD_SET(fileno(stdin), &fds);
timeout.tv_sec = 0;
timeout.tv_usec = 500000;
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;
FD_ZERO(&fds);
FD_SET(sock, &fds);
+ FD_SET(fileno(stdin), &fds);
}
tun_close(sock, dev);
}
# 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
--- /dev/null
+#!/usr/bin/env python
+
+# Copyright (c) 2007 Johns Hopkins University.
+# All rights reserved.
+#
+# Permission to use, copy, modify, and distribute this software and its
+# documentation for any purpose, without fee, and without written
+# agreement is hereby granted, provided that the above copyright
+# notice, the (updated) modification history and the author appear in
+# all copies of this source code.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS'
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, LOSS OF USE, DATA,
+# OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+# THE POSSIBILITY OF SUCH DAMAGE.
+
+# @author Razvan Musaloiu-E. <razvanm@cs.jhu.edu>
+# @author Chieh-Jan Mike Liang <cliang4@cs.jhu.edu>
+
+# b6lowpan/nwprog port:
+# @author Stephen Dawson-Haggerty <stevedh@cs.berkeley.edu>
+
+import sys, stat, struct, subprocess, time, os.path, socket, getopt, re
+try:
+ import tos
+except ImportError:
+ import posix
+ sys.path = [os.path.join(posix.environ['TOSROOT'], 'support', 'sdk', 'python')] + sys.path
+ import tos
+from datetime import datetime
+
+# Path to the python script that builds Deluge image from XML
+PATH_PY_BUILD_IMAGE = os.path.join(os.path.dirname(sys.argv[0]), 'tos-build-deluge-image')
+
+# Commands for NWProg
+NWPROG_CMD_ERASE = 1
+NWPROG_CMD_WRITE = 2
+NWPROG_CMD_READ = 3
+
+
+# Deluge parameters
+DELUGE_MAX_PAGES = 128
+DELUGE_IDENT_OFFSET = 0
+DELUGE_IDENT_SIZE = 128
+
+NWPROG_PORT = 5213
+NWPROG_PKT_SIZE = 64
+NWPROG_REQ_FMT = "!BBH"
+NWPROG_REPLY_FMT = "!BBBBH"
+
+ERROR_SUCCESS = 0
+nRetries = 3
+
+class CommandFailedException:
+ pass
+
+def send_command(cmd_str, retries):
+ s.sendto(cmd_str, (remote, NWPROG_PORT))
+ s.settimeout(3)
+ (real_cmd, real_imgno, real_offset) = struct.unpack(NWPROG_REQ_FMT, cmd_str[0:4])
+ try:
+ data, addr = s.recvfrom(1024)
+ # make sure this is the guy we're programming
+ if (addr[0] == remote):
+ (error, pack, cmd, imgno, offset) = struct.unpack(NWPROG_REPLY_FMT, data)
+ if error != ERROR_SUCCESS or real_offset != offset or real_imgno != imgno:
+ print "WARNING: received error while sending block; retrying"
+ raise socket.timeout
+ else: return data
+ else:
+ print "WARNING: received unexpected reply from", addr[0]
+ return False
+ except socket.timeout:
+ # socket timeout out try again
+ if retries > 0:
+ return send_command(cmd_str, retries - 1)
+ else:
+ return False
+
+def erase(imgNum, none=None):
+ e_req = struct.pack(NWPROG_REQ_FMT, NWPROG_CMD_ERASE, imgNum, 0)
+ return send_command(e_req, 1)
+
+def read(imgNum, unused=None):
+ length = 40000
+ pkt_offset = 0
+ while length > 0:
+ sreqpkt = struct.pack(NWPROG_REQ_FMT, NWPROG_CMD_READ, imgNum, pkt_offset)
+
+ data = send_command(sreqpkt, 5)
+ if data != False:
+ (error, pack, cmd, imgno, offset) = struct.unpack(NWPROG_REPLY_FMT, data[0:6])
+ if offset == pkt_offset:
+ for c in data[6:]:
+ print >>sys.stderr, ord(c)
+ else:
+ print "ERROR: Out of sequence data: aborting"
+ sys.exit(1)
+ pkt_offset += len(data) - 6
+ length -= (len(data) - 6)
+ return True
+
+
+def write(imgNum, data):
+ length = len(data)
+ total_length = length # For progress bar
+ next_tick = 100 # For progress bar
+ start_time = time.time()
+
+ print "[0% 25% 50% 75% 100%]\r[",
+
+ pkt_offset = 0
+ pkt_length = 0
+
+ while length > 0:
+ if ((length * 100) / total_length) < next_tick:
+ next_tick = next_tick - 2
+ sys.stdout.write('-')
+ sys.stdout.flush()
+
+ # Calculates the payload size for the current packet
+ if length >= NWPROG_PKT_SIZE:
+ pkt_length = NWPROG_PKT_SIZE
+ else:
+ pkt_length = length
+
+ sreqpkt = struct.pack(NWPROG_REQ_FMT,
+ NWPROG_CMD_WRITE, imgNum, pkt_offset)
+
+ for i in data[pkt_offset:pkt_offset+pkt_length]:
+ sreqpkt += chr(i)
+
+ # Sends packet to serial
+ if not send_command(sreqpkt, 5):
+ print "\nReceived error from mote while programming"
+ print "Perhaps the block size is too large, or the flash is broken?"
+ return False
+
+ length -= pkt_length
+ pkt_offset += pkt_length
+
+
+ print '\r' + ' ' * 52,
+ elasped_time = time.time() - start_time
+ print "\r%s bytes in %.2f seconds (%.4f bytes/s)" % (total_length, elasped_time, int(total_length) / (elasped_time))
+
+ return True
+
+
+# Injects an image (specified by tos_image_xml) to an image volume
+def upload(imgNum, tos_image_xml):
+ # Checks for valid file path
+ try:
+ os.stat(tos_image_xml) # Checks whether tos_image_xml is a valid file
+ except:
+ print "ERROR: Unable to find the TOS image XML, \"%s\"" % tos_image_xml
+ return False
+ try:
+ os.stat(PATH_PY_BUILD_IMAGE) # Checks whether PATH_PY_BUILD_IMAGE is a valid file
+ except:
+ print "ERROR: Unable to find the image building utility, \"%s\"" % PATH_PY_BUILD_IMAGE
+ return False
+
+ # Creates binary image from the TOS image XML
+ print "--------------------------------------------------"
+ cmd = [PATH_PY_BUILD_IMAGE, "-i", str(imgNum), tos_image_xml]
+ print "Create image:", ' '.join(cmd)
+ p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ (out, err) = p.communicate(None)
+ print err,
+ print "--------------------------------------------------"
+
+ # Writes the new binary image
+ image = [struct.unpack("B", c)[0] for c in out]
+ if len(image) > 0 and erase(imgNum):
+ return write(imgNum, image)
+ else:
+ print "Could not proceed: image size is zero or erase failed"
+
+ return False
+
+
+def print_usage():
+ print
+ print "Usage: %s <(-e|-u) image_number> <-f app_xml> [options] [ip_address]" % sys.argv[0]
+ print " -u --upload Upload a compiled TinyOS application"
+ print " -r --read Read back a volume"
+ print " -e --erase Erase an image in the external flash"
+ print " -f --appfile The tos_image.xml file to upload"
+ print " -m --motelist A file containing a list of IPv6 addresses to upload to"
+ print " -r --retries The number of times to retry each operation (currently %i)" % nRetries
+ print " -p --payload-sz How much payload to include in every packet (currently %i)" % NWPROG_PKT_SIZE
+ print " -d --dudfile File to write list of motes which did not program (default: stdout)"
+ print
+
+def checkImgNum(imgNum):
+ # Checks for valid image number format
+ try:
+ imgNum = int(imgNum)
+ except:
+ print "ERROR: Image number is not valid"
+ sys.exit(-1)
+ return imgNum
+
+# ======== MAIN ======== #
+if __name__ == '__main__':
+
+ try:
+ opts, args = getopt.getopt(sys.argv[1:], "e:u:m:f:r:p:d:r:",
+ ["--erase", "--upload", "--motelist", "--appfile",
+ "--retries", "--payload", "--dudfile",
+ "--upload"])
+ except getopt.GetoptError, err:
+ print str(err)
+ print_usage()
+ sys.exit(1)
+
+ imgNum = None
+ uploadFile = None
+ appFile = None
+ dudFile = None
+
+ for o, a in opts:
+ if o in ["-e", "--erase"]:
+ imgNum = checkImgNum(a)
+ cmd = "eras"
+ elif o in ["-u", "--upload"]:
+ imgNum = checkImgNum(a)
+ cmd = "upload"
+ elif o in ["-r", "--read"]:
+ imgNum = checkImgNum(a)
+ cmd = "read"
+ elif o in ["-m", "--motelist"]:
+ uploadFile = a
+ elif o in ["-f", "--appfile"]:
+ appFile = a
+ elif o in ["-r", "--retries"]:
+ nRetries = int(a)
+ elif o in ["-p", "--payload-sz"]:
+ NWPROG_PKT_SIZE = int(a)
+ elif o in ["-d", "--dudfile"]:
+ dudFile = a
+
+ if imgNum == None or (cmd != "eras" and cmd != "read" and appFile == None):
+ print_usage()
+ sys.exit(1)
+
+ upload_list = []
+ if uploadFile == None:
+ upload_list = [(ip, nRetries) for ip in args]
+ else:
+ fp = open(uploadFile, "r")
+ rexp = re.compile("^.*#")
+ for ip in fp.readlines():
+ if re.match(rexp,ip): continue
+ upload_list.append( (ip.strip().lower(), nRetries) )
+ fp.close()
+
+ if cmd == 'upload': cmd_fn = upload
+ elif cmd == 'read': cmd_fn = read
+ else: cmd_fn = erase
+
+ print "%sing %i motes" % (cmd, len(upload_list))
+ print "retries: %i payload: %i" % (nRetries, NWPROG_PKT_SIZE)
+
+ for t in range(0, nRetries):
+ for i in range(0, len(upload_list)):
+ remote, tries_left = upload_list[i]
+ if tries_left <= 0: continue
+ print "%sing %s, %i tries remaining ..." % (cmd, remote, tries_left)
+ try:
+ s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
+ if not cmd_fn(imgNum, appFile):
+ upload_list[i] = (remote, tries_left - 1)
+ else:
+ upload_list[i] = (remote, -1)
+ print "Success!"
+ s.close()
+ except KeyboardInterrupt:
+ print "Interrupted; exiting"
+ sys.exit(2)
+ except Exception, e:
+ print "Received unexpected exception while programming"
+ print str(e)
+ s.close()
+ pass
+
+ printedHeading = False
+ if dudFile != None:
+ dudFp = open(dudFile, "w")
+ else: dudFp = sys.stdout
+
+ for i in range(0, len(upload_list)):
+ remote, tries_left = upload_list[i]
+ if tries_left == 0 and not printedHeading:
+ printedHeading = True
+ print "WARNING: not all motes were succesfully %sed!" % cmd
+ if tries_left == 0:
+ print >>dudFp, remote
+
+ if dudFp != sys.stdout:
+ dudFp.close()
ICMP_EXT_TYPE_BEACON = 17,
};
+#ifndef LOW_POWER_LISTENING /* parameters for CSMA MAC */
enum {
// jitter start requests by 10 seconds
TRICKLE_JITTER = 10240,
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 */
nx_uint8_t type;
nx_uint8_t length;
nx_uint16_t metric;
+ nx_uint8_t pad[4];
} rqual_t;
struct icmp_stats {
#include <lib6lowpan.h>
#include <6lowpan.h>
#include <ip_malloc.h>
+#include <Statistics.h>
#include "in_cksum.h"
#include "PrintfUART.h"
#include "ICMP.h"
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);
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;
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);
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);
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",
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.
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++;
} 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);
}
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);
}
#include <message.h>
#include <lib6lowpan.h>
+#include <Statistics.h>
enum {
N_PARENTS = 3,
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
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;
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;
uint8_t frags_sent;
bool failed;
uint8_t refcount;
+ uint8_t local_flow_label;
} send_info_t;
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;
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];
} 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
}
} 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;
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;
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;
#include "IPDispatch.h"
#include "table.h"
#include "PrintfUART.h"
-#ifdef PRINTF_LIBRARY
-#include "printf.h"
-#endif
/*
* Provides IP layer reception to applications on motes.
interface SplitControl;
// interface for protocols not requiring special hand-holding
interface IP[uint8_t nxt_hdr];
+
interface Statistics<ip_statistics_t>;
+
+ // IPv6 Extension headers are very useful, but somewhat tricky to
+ // handle in a pretty way. This is my attempt.
+
+ // for inspecting/modifying extension headers on incomming packets
+ interface IPExtensions;
+
}
uses {
interface Boot;
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;
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,
};
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
//
////////////////////////////////////////
-#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) {
#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();
}
}
event void Boot.booted() {
- CHECK_NODE_ID;
call Statistics.clear();
ip_malloc_init();
*/
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;
}
event void ExpireTimer.fired() {
- CHECK_NODE_ID;
table_map(&recon_cache, reconstruct_age);
table_map(&forward_cache, forward_age);
* 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++) {
* 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;
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)) {
// - 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
// 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
}
// 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;
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
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);
}
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
// 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);
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);
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);
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);
if (s_entry != NULL)
call SendEntryPool.put(s_entry);
- stats.fw_drop++;
+ BLIP_STATS_INCR(stats.fw_drop);
fwd->timeout = T_FAILED1;
goto fail;
}
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();
fail:
dbg("Drops", "drops: receive()\n");;
- stats.rx_drop++;
+ BLIP_STATS_INCR(stats.rx_drop);
done:
return msg;
}
* Send-side functionality
*/
+
+
task void sendTask() {
send_entry_t *s_entry;
if (radioBusy || state != S_RUNNING) return;
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);
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) {
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");
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.
* 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) {
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) {
}
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;
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();
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);
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;
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);
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() {
* 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() {
--- /dev/null
+
+/*
+ * Provides various functions for dealing with IP extension header
+ * processing
+
+ *
+ */
+
+#include <ip_malloc.h>
+
+module IPExtensionP {
+ provides {
+ // for inserting destination and hop-by-hop headers on outgoing packets.
+ // routing headers are handled through the IPRouting interface
+ interface Init;
+ interface TLVHeader as HopByHopExt[uint8_t client];
+ interface TLVHeader as DestinationExt[uint8_t client];
+ interface InternalIPExtension;
+ }
+} implementation {
+
+ struct generic_header *ext_dest, *ext_hop;
+
+ command error_t Init.init() {
+ ext_hop = ext_dest = NULL;
+ return SUCCESS;
+ }
+
+ struct tlv_hdr *destopt_get(int i, int nxt_hdr, struct ip6_hdr *iph) {
+ return signal DestinationExt.getHeader[i](0, nxt_hdr, iph);
+ }
+ struct tlv_hdr *hopopt_get(struct ip6_hdr *iph, int i) { //, uint8_t nxt_hdr) {
+ // return signal HopByHopExt.getHeader[i](label, iph, nxt_hdr);
+ return NULL;
+ }
+
+ /* build up a sequence of TLV headers for hop-by-hop or
+ destination only extension headers */
+ struct generic_header *buildTLVHdr(struct split_ip_msg *msg,
+ int which,
+ int n, int nxt_hdr) {
+ // allocate generic headers for all the possible TLV-encoded
+ // headers we might get
+ int i;
+ uint8_t *buf = ip_malloc(sizeof(struct ip6_ext) + (sizeof(struct generic_header) * (n + 1)));
+ struct ip6_ext *real_hdr;
+ struct generic_header *ghdrs;
+ if (buf == NULL) return NULL;
+ ghdrs = (struct generic_header *)buf;
+ real_hdr = (struct ip6_ext *)(ghdrs + (n + 1));
+
+
+ real_hdr->len = sizeof(struct ip6_ext);
+
+ ghdrs[0].len = sizeof(struct ip6_ext);
+ ghdrs[0].hdr.data = (uint8_t *)real_hdr;
+ ghdrs[0].next = msg->headers;
+
+ for (i = 0; i < n; i++) {
+ struct tlv_hdr *this_hdr;
+ if (which == 0) {
+ printfUART("adding destination idx %i\n", i);
+ this_hdr = signal DestinationExt.getHeader[i](0, nxt_hdr, &msg->hdr);
+ } else {
+ this_hdr = signal HopByHopExt.getHeader[i](0, nxt_hdr, &msg->hdr);
+ }
+
+ printfUART("buildTLV: got %p\n", this_hdr);
+ if (this_hdr == NULL) continue;
+
+ real_hdr->len += this_hdr->len;
+ ghdrs[i+1].len = this_hdr->len;
+ ghdrs[i+1].hdr.data = (uint8_t *)this_hdr;
+ ghdrs[i].next = &ghdrs[i+1];
+ ghdrs[i+1].next = msg->headers;
+ }
+ if (real_hdr->len == sizeof(struct ip6_ext)) {
+ ip_free(buf);
+ return NULL;
+ } else {
+ real_hdr->nxt_hdr = msg->hdr.nxt_hdr;
+ msg->headers = ghdrs;
+ return ghdrs;
+ }
+ }
+
+ command void InternalIPExtension.addHeaders(struct split_ip_msg *msg,
+ uint8_t nxt_hdr,
+ uint16_t label) {
+
+ ext_dest = ext_hop = NULL;
+ msg->hdr.nxt_hdr = nxt_hdr;
+ ext_dest = buildTLVHdr(msg, 0, 1, nxt_hdr);
+ if (ext_dest != NULL) msg->hdr.nxt_hdr = IPV6_DEST;
+
+ ext_hop = buildTLVHdr(msg, 1, 1, msg->hdr.nxt_hdr);
+ if (ext_hop != NULL) msg->hdr.nxt_hdr = IPV6_HOP;
+ }
+
+ command void InternalIPExtension.free() {
+ if (ext_dest != NULL) ip_free(ext_dest);
+ if (ext_hop != NULL) ip_free(ext_hop);
+ ext_dest = ext_hop = NULL;
+ // signal HopByHopExt.free[0]();
+ // signal DestinationExt.free[0]();
+ }
+
+#if 0
+ void ip_dump_msg(struct split_ip_msg *msg) {
+ struct generic_header *cur = msg->headers;
+ int i;
+ printfUART("DUMPING IP PACKET\n ");
+ for (i = 0; i < sizeof(struct ip6_hdr); i++)
+ printfUART("0x%x ", ((uint8_t *)&msg->hdr)[i]);
+ printfUART("\n");
+
+ while (cur != NULL) {
+ printfUART(" header [%i]: ", cur->len);
+ for (i = 0; i < cur->len; i++)
+ printfUART("0x%x ", cur->hdr.data[i]);
+ printfUART("\n");
+ cur = cur->next;
+ }
+
+ printfUART("data [%i]: ", msg->data_len);
+ for (i = 0; i < msg->data_len; i++)
+ printfUART("0x%x ", ((uint8_t *)msg->data)[i]);
+ printfUART("\n\n");
+ }
+#endif
+
+ default event struct tlv_hdr *DestinationExt.getHeader[uint8_t i](int label,int nxt_hdr,
+ struct ip6_hdr *msg) {
+ printfUART("default dest handler?\n");
+ return NULL;
+ }
+
+ default event struct tlv_hdr *HopByHopExt.getHeader[uint8_t i](int label,int nxt_hdr,
+ struct ip6_hdr *msg) {
+ return NULL;
+ }
+
+
+}
--- /dev/null
+
+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) {
+
+ }
+
+}
module IPRoutingP {
provides interface IPRouting;
provides interface Statistics<route_statistics_t>;
+
+ uses interface IPExtensions;
+ uses interface TLVHeader as DestinationExt;
uses interface ICMP;
uses interface Boot;
uses interface IPAddress;
} implementation {
+#ifdef PRINTFUART_ENABLED
+/* #undef dbg */
+/* #define dbg(X, fmt, args...) printfUART(fmt, ## args) */
+#endif
+
enum {
SHORT_EPOCH = 0,
LONG_EPOCH = 1,
//route_statistics_t stats;
uint16_t last_qual;
uint8_t last_hops;
+ uint16_t reportSeqno;
uint8_t num_low_neigh;
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();
}
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) {
}
}
- 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
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;
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;
last_qual = 0xffff;
last_hops = 0xff;
num_low_neigh = 0;
+ reportSeqno = call Random.rand16();
+
call Statistics.clear();
call SortTimer.startPeriodic(1024L * 60);
|| 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;
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;
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
}
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
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 {
}
}
- 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];
* 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) {
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;
* 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;
*
* 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);
// 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;
// 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);
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++) {
}
#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++) {
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;
}
/*
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.
dbg("Evictions", "performing evict: %i\n", i);
evictNeighbor(&neigh_table[i]);
i --;
-#endif
+// #endif
evicted = TRUE;
}
}
--- /dev/null
+/*
+ * "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
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);
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;
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++) {
}
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;
}
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;
}
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]() { }
-
-
-
-
}
--- /dev/null
+
+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];
+
+}
--- /dev/null
+
+#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) { }
+
+}
+#include <Statistics.h>
+
configuration UdpC {
- provides interface UDP[uint8_t clnt];
+ provides interface UDP[uint8_t clnt];
+ provides interface Statistics<udp_statistics_t>;
} implementation {
components MainC, IPDispatchC, UdpP, IPAddressC;
UDP = UdpP;
+ Statistics = UdpP;
MainC -> UdpP.Init;
UdpP.IP -> IPDispatchC.IP[IANA_UDP];
#include <ip_malloc.h>
#include <in_cksum.h>
+#include <Statistics.h>
module UdpP {
provides interface UDP[uint8_t clnt];
provides interface Init;
+ provides interface Statistics<udp_statistics_t>;
uses interface IP;
uses interface IPAddress;
} implementation {
+#ifdef PRINTFUART_ENABLED
+#undef dbg
+#define dbg(X,fmt, args...) printfUART(fmt, ##args)
+#endif
+
enum {
N_CLIENTS = uniqueCount("UDP_CLIENT"),
};
+ udp_statistics_t stats;
uint16_t local_ports[N_CLIENTS];
enum {
}
command error_t Init.init() {
+ call Statistics.clear();
ip_memclr((uint8_t *)local_ports, sizeof(uint16_t) * N_CLIENTS);
return SUCCESS;
}
return SUCCESS;
}
-
event void IP.recv(struct ip6_hdr *iph,
void *payload,
struct ip_metadata *meta) {
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);
}
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));
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) {
--- /dev/null
+
+ @title blip documentation
+ @author Stephen Dawson-Haggerty stevedh@eecs.berkeley.edu
+ @release public
+---------------------------------------------------------------------
+
+ 1. Installation
+
+ - This is only going to work on linux.
+
+ - The recommended version of TinyOS is a recent CVS checkout. This
+ is necessary for appropriate radio stack support.
+
+ - Make sure the c serial tools are built in
+ $TOS_ROOT/support/sdk/c/sf. You may need to run ./bootstrap,
+ ./configure, and make in that folder to generate libmote.a.
+
+ - Add two environment variables to your startup scripts:
+ export LOWPAN_ROOT=~/svn/code/b6lowpan/
+ export TOSMAKE_PATH="$LOWPAN_ROOT/support/make"
+ where LOWPAN_ROOT is replaced with the path to the blip top
+ level directory.
+
+ - Optionally, have a look at $TOS_ROOT/support/sdk/c/sf/serialsource.c.
+ There is an enum which defines ACK_TIMEOUT = 1000000 (one second in
+ usecs). This is much too long and will cause a lot of jitter when
+ (not if) serial writes fail. Changing it to 100000 is worthwhile.
+ You will need to rebuild libmote.a by typing 'make' in that folder
+ after making this change. (SDH : this was true up to a little past
+ version 2.1. It is now false.)
+
+ 2. Building
+
+ - Build a test app:
+ * cd to $LOWPAN_ROOT/apps/UDPEcho/ and try typing `make <platform> blip`
+ - Build the IEEE802.15.4 bridge to your computer
+ * cd to $LOWPAN_ROOT/apps/IPBaseStation/ and `make <platform> blip`
+ - Build the driver
+ * cd to $LOWPAN_ROOT/support/sdk/c/blip and type `make`
+
+ 3. Running
+
+ - Install IPBaseStation on a mote. This will be your
+ computer's interface to the world of low-power radio.
+
+ - Start the driver (once you've built it)
+ * cd $LOWPAN_ROOT/support/sdk/c/blip
+ * edit the config file $LOWPAN_ROOT/support/sdk/c/blip/serial_tun.conf
+ * set 'addr' you would like your computer's interface to use on the PAN
+ * set 'proxy' to the network device you would like to proxy
+ neighbor advertisements on
+ * sudo ./ip-driver /dev/ttyUSB0 telosb
+ (replace the device and baud with whatever you're using)
+ The config file is assumed to be in the CWD when ip-driver starts;
+ if this is not the case it may be specified using '-c <config file>'
+
+ - The driver registers itself on the 2001:470:1f04:56d::/64
+ subnet (or whatever you have specified in the config file).
+
+ - If you program a few motes with UDPEcho, their addresses are formed
+ with octets 15 and 16 of the IPv6 address comming from the
+ 802.15.4 short address you programmed them with. Octets 9-14
+ are zero, so the address formed is:
+
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | network prefix | zero | id |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+ ICMPv6 DAD is not performed.
+
+ - For instance, if you program a mote with ID 101 (0x65), you can try
+ ping6 2001:470:1f04:56d::65
+ tracert6 2001:470:1f04:56d::65
+ nc6 -u 2001:470:1f04:56d::65 7
+ nc6 -u 2001:470:1f04:56d::65 2000
+
+ UDPEcho runs an echo service on port 7, and a simple shell on
+ port 2000; type 'help' for a list of commands.
+
+ - The motes can also report back statistics every 15 seconds over
+ UDP. They will send these reports to an address specified in the
+ application make file; however these reports are disabled by default.
+ You can observe these statistics using the Listener.py
+ script in $LOWPAN_ROOT/apps/UDPEcho/: `python Listener.py`.
+
+ - The driver provides a simple console when running, which allows you
+ to inspect and manipulates routes, and view statistics. The
+ console runs as a telnet service on port 6106.
+
+ - A good way of understanding what is happening is to start wireshark
+ on tun0; you should be able to observe the neighbor discovery
+ process as motes boot. You may also notice messages sent to
+ ff05::1; these are routing updates. They are sent from a
+ binary exponential timer with a maximum period of 5 minutes to
+ inform the router of mote's presence; however, they are
+ suppressed by data traffic since the routing updates will be
+ piggybacked on it.
+
+ - Further reading: doc/ contains a numbers of README's related to
+ pieces of blip such as the socket interface, the shell, and
+ network programming support. For more technical details on
+ IPv6, please see any reference on the subject. Many of the
+ documents produced by the IETF ROLL and 6lowpan working groups
+ are relevent to this design space.
--- /dev/null
+
+ @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.
+
--- /dev/null
+
+ @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.
--- /dev/null
+
+ @title Meraki Documentation
+ @author Stephen Dawson-Haggerty stevedh@eecs.berkeley.edu
+ @release public
+---------------------------------------------------------------------
+
+What is it?
+---------------------------------------------------------------------
+nwprog is a method of over-the-air programming. It uses much of the
+machinery Deluge has developed, like the boot loader and flash layout,
+but substitutes a simpler transport using UDP for Deluge's
+dissemination algorithm. This means that it is point-to-point, and
+not incredibly appropriate for reprogramming an entire network all at
+once.
+
+How do I get it?
+---------------------------------------------------------------------
+It is included with the b6lowpan stack. It reuses much of the Deluge
+code directly from the TinyOS tree without shadowing the files.
+
+Differences from Deluge?
+---------------------------------------------------------------------
+ - no dissemination
+ - no base station or serial port for injection
+
+ The application is very simple: flash is formatted into several
+volumes (a golden image and three application volumes), which are used
+to store application images. Flash management, boot loading, and
+image formatting are all provided by Deluge.
+
+How to use it?
+---------------------------------------------------------------------
+Build your application with support by include a line in your
+application Makefile, and include the IPDispatchC component.
+== application makefile ==
+BOOTLOADER=tosboot
+== </snip> ==
+Also, it is necessary to include a volumes xml file for your flash
+chip; examples for the stm25p and at45db are present in apps/UDPEcho.
+
+First built the tosboot bootloader for your platform by going to
+tinyos-2.x/tos/lib/tosboot and typing `make <platform>`.
+
+Then just build and install your application like usual. If
+networking is working, you should have no problem following the rest
+of the instructions.
+
+Interactions with the motes happen using the 'nwprog' tool in a shell.
+Connect the shell with `nc6 -u 2001:470:1f04:56d::65 2000`.
+It has three commands:
+ `nwprog list`: examine the flash and print out information on volumes
+ containing images believed to be valid
+ `nwprog reboot`: reboot into the same image
+ `nwprog boot N`: reboot, and flash the mote with the binary stored in
+ volume N
+
+In order to upload new images, use the tos-nwprog tool, located in
+$LOWPAN_ROOT/tools/tinyos/misc. This tool provides minimal
+functionality; only erasing and uploading are supported.
+
+ `./tos-nwprog 2001:470:1f04:56d::65 -e 0`: erase image 0 from the
+ mote at the given IP address.
+ `./tos-nwprog 2001:470:1f04:56d::65 -u 0 tos_image.xml`: upload the
+ image in tos_image.xml to volume 0 on the mote at the IP
+ address. This will erase the volume before uploading it.
+
+To integrate with your own application, there are several internal
+interfaces which can be used to examine the flash. Looking at the
+example code in UDPShellP component is the best way of finding out
+about these.
--- /dev/null
+
+ @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
--- /dev/null
+
+ @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.
+
+
--- /dev/null
+
+ @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
--- /dev/null
+
+ @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;
*/
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.
#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);
--- /dev/null
+
+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);
+
+}
* 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);
*
*
*/
- 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);
/*
* 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
--- /dev/null
+
+interface InternalIPExtension {
+
+ command void addHeaders(struct split_ip_msg *msg, uint8_t nxt_hdr, uint16_t label);
+
+ command void free();
+
+}
--- /dev/null
+
+#include <ip.h>
+
+interface TLVHeader {
+ event struct tlv_hdr *getHeader(int label,int nxt_hdr,
+ struct ip6_hdr *msg);
+
+ event void free();
+}
/*
* 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);
/*
* 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);
* terminate a connection.
*/
command error_t close();
+ command error_t abort();
/*
* notify the app that the socket connection has been closed or
* local side has given up.
*/
event void closed(error_t e);
+
+ /*
+ * returns TRUE if all previously sent data has been ACKed
+ */
+ event void acked();
+
+
}
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{
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;
+#include <BinaryShell.h>
#include "StorageVolumes.h"
#include "Deluge.h"
} implementation {
// send and receive pages
- components MainC, IPDispatchC;
+ components MainC, new UdpSocketC();
components NetProgC, NWProgP;
BootImage = NWProgP;
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;
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();
#include <Storage.h>
#include <Shell.h>
+#include <BinaryShell.h>
#include "imgNum2volumeId.h"
#include "Deluge.h"
-
+#include "PrintfUART.h"
module NWProgP {
provides interface BootImage;
uses {
interface UDP as Recv;
interface StorageMap[uint8_t imag_num];
interface NetProg;
+ interface BlockRead[uint8_t img_num];
interface BlockWrite[uint8_t img_num];
interface Resource;
- interface ShellCommand;
interface DelugeMetadata;
interface Timer<TMilli> as RebootTimer;
+
event void storageReady();
+
+#ifdef BINARY_SHELL
+ interface BinaryCommand as ShellCommand;
+#else
+ interface ShellCommand;
+#endif
}
} implementation {
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) {
}
event void Boot.booted() {
+#ifdef PARANOID
+ paranoid_read = FALSE;
+#endif
state = S_IDLE;
+ call Recv.bind(5213);
}
void sendDone(error_t error) {
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;
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;
}
if (error != SUCCESS) {
sendDone(error);
- call Resource.release();
+ if (call Resource.isOwner()) {
+ call Resource.release();
+ }
} else {
state = S_BUSY;
}
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) {
/*
* Shell command implementation
*/
- char *nwprog_help_str = "nwprog [list | boot <imgno> [when] | reboot]\n";
uint8_t nwprog_currentvol, nwprog_validvols;
uint8_t boot_image;
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
}
}
call BootImage.boot(boot_image);
}
+#ifdef BINARY_SHELL
+ event void ShellCommand.dispatch(nx_struct cmd_payload *data, int len) {
+ nx_struct prog_req *req = (nx_struct prog_req *)data->data;
+ nx_struct cmd_payload *rep;
+ prog_reply_t *rc;
+ int error = NWPROG_ERROR_OK;
+
+ switch (req->cmd) {
+ case NWPROG_CMD_LIST:
+ nwprog_currentvol = 0;
+ nwprog_validvols = 0;
+ call DelugeMetadata.read(imgNum2volumeId(nwprog_currentvol));
+ return;
+ break;
+ case NWPROG_CMD_BOOT:
+ call ShellCommand.write(data, len);
+ boot_image = imgNum2volumeId(req->imgno);
+ call RebootTimer.startOneShot(req->cmd_data.when);
+ break;
+ case NWPROG_CMD_REBOOT:
+ call BootImage.reboot();
+ break;
+ }
+ }
+#else
event char *ShellCommand.eval(int argc, char **argv) {
+ char *nwprog_help_str = "nwprog [list | boot <imgno> [when] | reboot]\n";
if (argc >= 2) {
if (memcmp(argv[1], "list", 4) == 0) {
nwprog_currentvol = 0;
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);
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) {}
+
}
+/*
+ * "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
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;
}
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
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) {
+/*
+ * "Copyright (c) 2008, 2009 The Regents of the University of California.
+ * All rights reserved."
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written agreement is
+ * hereby granted, provided that the above copyright notice, the following
+ * two paragraphs and the author appear in all copies of this software.
+ *
+ * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+ * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
+ * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
+ *
+ */
#include <stdlib.h>
#include "table.h"
+/*
+ * "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_