--- /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."
+ *
+ */
+/*
+ * Copyright (c) 2007 Matus Harvan
+ * All rights reserved
+ *
+ * Copyright (c) 2008 Stephen Dawson-Haggerty
+ * Extensivly modified to use lib6lowpan / b6lowpan.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <time.h>
+#include <stdarg.h>
+#include <termios.h>
+#include <errno.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <lib6lowpan/TrackFlows.h>
+#include <lib6lowpan/6lowpan.h>
+#include <lib6lowpan/ip.h>
+#include <lib6lowpan/lib6lowpan.h>
+#include <lib6lowpan/devconf.h>
+#include <lib6lowpan/IEEE154Packet.h>
+
+#include "serialsource.h"
+#include "serialpacket.h"
+#include "serialprotocol.h"
+#include "sfsource.h"
+
+#include "tun_dev.h"
+#include "routing.h"
+#include "logging.h"
+#include "config.h"
+#include "nwstate.h"
+#include "vty/vty.h"
+
+#define min(a,b) ( (a>b) ? b : a )
+#define max(a,b) ( (a>b) ? a : b )
+
+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();
+void radvd_reset_adverts(void);
+
+#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,
+};
+
+/*
+ */
+#ifdef __TARGET_mips__
+const char *def_configfile = "/etc/lowpan/serial_tun.conf";
+#else
+const char *def_configfile = "serial_tun.conf";
+#endif
+
+
+
+extern struct in6_addr __my_address;
+uint16_t local_seqno = 0;
+
+volatile sig_atomic_t config_success = 0;
+struct config driver_config;
+char dev[IFNAMSIZ];
+struct {
+ time_t boot_time;
+ unsigned long tx_pkts;
+ unsigned long tx_frags;
+ unsigned long tx_bytes;
+ unsigned long rx_pkts;
+ unsigned long rx_frags;
+ unsigned long rx_bytes;
+ 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
+
+
+/* ------------------------------------------------------------------------- */
+
+void stderr_msg(serial_source_msg problem)
+{
+ // fprintf(stderr, "Note: %s\n", msgs[problem]);
+}
+
+
+void print_ip_packet(struct split_ip_msg *msg) {
+ int i;
+ struct generic_header *g_hdr;
+ if (log_getlevel() > LOGLVL_DEBUG) return;
+
+ printf(" nxthdr: 0x%x hlim: 0x%x plen: %i\n", msg->hdr.nxt_hdr, msg->hdr.hlim, ntohs(msg->hdr.plen));
+ printf(" src: ");
+ for (i = 0; i < 16; i++) printf("0x%x ", msg->hdr.ip6_src.s6_addr[i]);
+ printf("\n");
+ printf(" dst: ");
+ for (i = 0; i < 16; i++) printf("0x%x ", msg->hdr.ip6_dst.s6_addr[i]);
+ printf("\n");
+
+ g_hdr = msg->headers;
+ while (g_hdr != NULL) {
+ printf("header [%i]: ", g_hdr->len);
+ for (i = 0; i < g_hdr->len; i++)
+ printf("0x%x ", g_hdr->hdr.data[i]);
+ printf("\n");
+ g_hdr = g_hdr->next;
+ }
+
+ printf("data [%i]:\n\t", msg->data_len);
+ for (i = 0; i < msg->data_len; i++) {
+ if (i == 0x40) {
+ printf (" ...\n");
+ break;
+ }
+ printf("0x%x ", msg->data[i]);
+ if (i % 16 == 15) printf("\n\t");
+ if (i % 16 == 7) printf (" ");
+ }
+ 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.
+ *
+ * does not free the payload buffer or the actual split_ip_msg struct,
+ * since those are malloc'ed seperatly in this implementation.
+ */
+void free_split_msg(struct split_ip_msg *msg) {
+ struct generic_header *cur, *next;
+ cur = msg->headers;
+ while (cur != NULL) {
+ next = cur->next;
+ if (cur->payload_malloced)
+ free(cur->hdr.data);
+ free(cur);
+ cur = next;
+ }
+}
+
+void configure_timeout() {
+ if (config_success == 0) {
+ fatal("configuring interface failed! aborting!\n");
+ exit(2);
+ } else {
+ signal(SIGALRM, SIG_DFL);
+ }
+}
+
+void configure_reboot() {
+ 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_REBOOT;
+
+ signal(SIGALRM, configure_timeout);
+ write_pan_packet(buf, CONFIGURE_MSG_SIZE + 1);
+ alarm(5);
+}
+
+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 = cmdno;
+ cmd->rf.addr = c->router_addr.s6_addr16[7]; // is network byte-order
+ cmd->rf.channel = c->channel;
+ cmd->retx.retries = htons(c->retries);
+ cmd->retx.delay = htons(30);
+
+ write_pan_packet(buf, CONFIGURE_MSG_SIZE + 1);
+}
+
+
+/* ------------------------------------------------------------------------- */
+/*
+ * the first byte the TOS serial stack sends is a dispatch byte. One
+ * dispatch value is for forwarded 802;.15.4 packets; we use a few
+ * others to talk directly to the attached IPBaseStation.
+ */
+void handle_other_pkt(uint8_t *data, int len) {
+ config_reply_t *rep;
+ switch (data[0]) {
+ case TOS_SERIAL_DEVCONF:
+ rep = (config_reply_t *)(&data[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, CONFIG_SET_PARM);
+ break;
+ default:
+ info("interface device successfully initialized\n");
+ config_success = 1;
+
+ /* put this here because we already use SIGALRM for the
+ configure timeout, and radvd needs it for its own timer. */
+ if (radvd_fd < 0 && (radvd_fd = radvd_init(dev, &driver_config)) < 0) {
+ fatal("radvd init failed!\n");
+ exit(1);
+ }
+ }
+ break;
+ default:
+ warn("received serial packet with unknown dispatch 0x%x\n",data[0]);
+ log_dump_serial_packet(data, len);
+ }
+}
+
+
+/* ------------------------------------------------------------------------- */
+/* handling of data arriving on the tun interface */
+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;
+
+ // don't include the length byte
+ radioPacket->fcf = htons(0x4188);
+ // dsn will get set on mote
+ radioPacket->destpan = 0;
+ radioPacket->dest = htole16(dest);
+ // src will get set on mote
+
+ serial[0] = SERIAL_TOS_SERIAL_802_15_4_ID;
+}
+
+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];
+ IEEE154_header_t *radioPacket = (IEEE154_header_t *)(serial + 1);
+#define PKTLEN(X) ((X)->length + 2)
+
+ uint8_t *lowpan = (uint8_t *)(radioPacket + 1);
+
+#define LOWPAN_PAYLOAD_LENGTH (LOWPAN_LINK_MTU - MAC_HEADER_SIZE \
+ - MAC_FOOTER_SIZE)
+
+ progress.offset = 0;
+
+ // and IEEE 802.15.4 header
+ // write_radio_header(serial, dest, frag_len);
+
+ while ((frag_len = getNextFrag(msg, &progress, lowpan,
+ LOWPAN_PAYLOAD_LENGTH)) > 0) {
+
+ //debug("frag len: 0x%x offset: 0x%x plen: 0x%x\n", frag_len, progress.offset * 8, ntohs(ip_header->plen));
+
+ write_radio_header(serial, dest, frag_len);
+
+ // if this is sent too fast, the base station can't keep up. The effect of this is
+ // we send incomplete fragment. 25ms seems to work pretty well.
+ // 6-9-08 : SDH : this is a bad fix that does not address the
+ // problem.
+ // at the very least, the serial ack's seem to be
+ // working, so we should be retrying if the ack is failing
+ // because the hardware cannot keep up.
+ // 9-17-09 : SDH : it seems we've tracked this down to packets
+ // arriving too fast to enqueue, especially at higher baud rates
+ // (115200). reenabled to prevent retries, which are very slow.
+#ifdef __TARGET_mips__
+ usleep(50000);
+#else
+ usleep(25000);
+#endif
+ log_dump_serial_packet(serial, PKTLEN(radioPacket));
+ result = write_pan_packet(serial, PKTLEN(radioPacket));
+ if (result != 0)
+ result = write_pan_packet(serial, PKTLEN(radioPacket));
+
+ debug("send_fragments: result: 0x%x len: 0x%x\n", result, frag_len);
+ log_dump_serial_packet(serial, PKTLEN(radioPacket));
+ stats.tx_frags++;
+ stats.tx_bytes += PKTLEN(radioPacket);
+ }
+ keepalive_needed = 0;
+ stats.tx_pkts++;
+}
+
+void icmp_unreachable(struct split_ip_msg *msg) {
+
+}
+
+/*
+ * this function takes a complete IP packet, and sends it out to a
+ * destination in the PAN. It will insert source routing headers and
+ * recompute L4 checksums as necessary.
+ *
+ */
+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\n");
+ if (routing_insert_route(msg)) goto fail;
+ break;
+
+ case ROUTE_WORMHOLE:
+ debug("Wormhole packet\n");
+
+ // fall through
+ case ROUTE_NO_ROUTE:
+ 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:
+ error("ip_to_pan: no route to host\n");
+ return 1;
+}
+
+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 *s;
+ struct rinstall_header *rih;
+ struct generic_header *g_hdr;
+ uint8_t removeSource = 1;
+ if (msg->hdr.nxt_hdr == NXTHDR_SOURCE) {
+ sh = msg->headers->hdr.sh;
+ upd_source_route(sh, msg->metadata.sender);
+
+ // Our thinking here is that if something is source_routed
+ // from inside the network and it is not destined to us
+ // then its either a rinstall being forwarded, or a path
+ // that's been set up, so we shouldn't strip it away
+ 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("Packet with source header not destined for me\n");
+
+ if ((sh->dispatch & IP_EXT_SOURCE_INVAL) != IP_EXT_SOURCE_INVAL) {
+ debug("Removing invalid source header\n");
+ removeSource = 0;
+ }
+
+ if ((sh->dispatch & IP_EXT_SOURCE_CONTROLLER) == IP_EXT_SOURCE_CONTROLLER) {
+ debug("WE sent this packet! dropping...\n");
+ return 1;
+ }
+
+
+ // If this is an rinstall header moving through, we need to
+ // updated the current position of the path, similar to
+ // what we do for source headers.
+ if (sh->nxt_hdr == NXTHDR_INSTALL) {
+ rih = msg->headers->next->hdr.rih;
+ rih->current++;
+ info("Incrementing current of rih to 0x%x\n", rih->current);
+ }
+ }
+ if (removeSource) {
+ msg->hdr.nxt_hdr = sh->nxt_hdr;
+ msg->hdr.plen = htons(ntohs(msg->hdr.plen) - sh->len);
+ g_hdr = msg->headers;
+ msg->headers = msg->headers->next;
+ free(g_hdr);
+ }
+ }
+ return 0;
+}
+#endif
+
+void handle_serial_packet(struct split_ip_msg *msg) {
+ path_t* tPath;
+ path_t* i;
+#ifdef CENTRALIZED_ROUTING
+ uint8_t flags = 0x00;
+#endif
+ if (ntohs(msg->hdr.plen) > INET_MTU - sizeof(struct ip6_hdr)) {
+ warn("handle_ip_packet: too long: 0x%x\n", ntohs(msg->hdr.plen));
+ return;
+ }
+
+ // print_ip_packet(msg);
+ print_ip_packet(msg);
+ if (process_extensions(msg))
+ return;
+
+ if (cmpPfx(msg->hdr.ip6_dst.s6_addr, __my_address.s6_addr) &&
+ msg->hdr.ip6_dst.s6_addr16[7] != __my_address.s6_addr16[7]) {
+ 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
+ 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])) {
+ 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
+ // case acks are issued by the destination on the packet
+ //
+ // We have to first select the flags that we want:
+
+ // 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) {
+ 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 {
+ // give it to linux
+ // need to remove route info here.
+ stats.rx_pkts++;
+ tun_write(tun_fd, msg);
+ debug("tun_write: wrote 0x%x bytes\n", sizeof(struct ip6_hdr) + ntohs(msg->hdr.plen));
+ }
+}
+
+void add_header_list(struct split_ip_msg *msg) {
+ uint8_t nxt_hdr;
+ 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]));
+ nxt_hdr = msg->hdr.nxt_hdr;
+ msg->headers = NULL;
+ g_list = &(msg->headers);
+ 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_hdr->next = NULL;
+ *g_list = g_hdr;
+ g_list = &g_hdr->next;
+
+ 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
+ */
+int tun_input()
+{
+ uint8_t buf[sizeof(struct split_ip_msg) + INET_MTU];
+ struct split_ip_msg *msg = (struct split_ip_msg *)buf;
+ int len;
+
+ len = tun_read(tun_fd, (void *)(&msg->pi), INET_MTU + sizeof(struct ip6_hdr));
+
+ if (len <= 0) {
+ return 0;
+ }
+ debug("tun_read: read 0x%x bytes\n", len);
+
+ if ((msg->hdr.vlfc[0] >> 4) != IPV6_VERSION) {
+ warn("tun_read: discarding non-ip packet\n");
+ goto fail;
+ }
+ if (ntohs(msg->hdr.plen) > INET_MTU - sizeof(struct ip6_hdr)) {
+ debug("tun_input: dropping packet due to length: 0x%x\n", ntohs(msg->hdr.plen));
+ goto fail;
+ }
+ if (msg->hdr.nxt_hdr == 0) {
+ debug("tun_input: dropping packet with IPv6 options\n");
+ goto fail;
+ }
+
+ add_header_list(msg);
+ msg->flow_id = local_seqno++;
+
+ ip_to_pan(msg);
+
+ free_split_msg(msg);
+
+ return 1;
+ fail:
+ /* error("Invalid packet or version received\n"); */
+ return 1;
+}
+
+/* ------------------------------------------------------------------------- */
+/* handling of data arriving on the serial port */
+
+reconstruct_t reconstructions [N_RECONSTRUCTIONS];
+
+void age_reconstructions() {
+ int i;
+ for (i = 0; i < N_RECONSTRUCTIONS; i++) {
+ // switch "active" buffers to "zombie"
+ if (reconstructions[i].timeout == T_ACTIVE) {
+ reconstructions[i].timeout = T_ZOMBIE;
+ } else if (reconstructions[i].timeout == T_ZOMBIE) {
+ reconstructions[i].timeout = T_UNUSED;
+ free(reconstructions[i].buf);
+ reconstructions[i].buf = NULL;
+ }
+ }
+}
+
+
+reconstruct_t *getReassembly(packed_lowmsg_t *lowmsg) {
+ int i, free_spot = N_RECONSTRUCTIONS + 1;
+ uint16_t mytag, size;
+ if (getFragDgramTag(lowmsg, &mytag)) return NULL;
+ if (getFragDgramSize(lowmsg, &size)) return NULL;
+
+ for (i = 0; i < N_RECONSTRUCTIONS; i++) {
+ if (reconstructions[i].timeout > T_UNUSED && reconstructions[i].tag == mytag) {
+ reconstructions[i].timeout = T_ACTIVE;
+ return &(reconstructions[i]);
+ }
+ if (reconstructions[i].timeout == T_UNUSED) free_spot = i;
+ }
+ // allocate a new struct for doing reassembly.
+ if (free_spot != N_RECONSTRUCTIONS + 1) {
+ // if we don't get the packet with the protocol in it first, we
+ // don't know who to ask for a buffer, and so give up.
+
+ reconstructions[free_spot].tag = mytag;
+
+ reconstructions[free_spot].size = size;
+ reconstructions[free_spot].buf = malloc(size + offsetof(struct split_ip_msg, hdr));
+ reconstructions[free_spot].bytes_rcvd = 0;
+ reconstructions[free_spot].timeout = T_ACTIVE;
+
+ debug("checking buffer size 0x%x\n", reconstructions[free_spot].size);
+ if (reconstructions[free_spot].buf == NULL) {
+ reconstructions[free_spot].timeout = T_UNUSED;
+ return NULL;
+ }
+ return &(reconstructions[free_spot]);
+ }
+ return NULL;
+}
+
+/*
+ * read data on serial port and send it to the tun interface
+ * does fragment reassembly
+ */
+int serial_input() {
+ packed_lowmsg_t pkt;
+ reconstruct_t *recon;
+ struct split_ip_msg *msg;
+ IEEE154_header_t *mac_hdr;
+
+ 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 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) {
+ 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);
+
+ // 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);
+
+ // for some reason these are little endian so we don't do any conversion.
+ pkt.src = mac_hdr->src;
+ pkt.dst = mac_hdr->dest;
+
+ log_dump_serial_packet(ser_data, ser_len);
+
+ pkt.headers = getHeaderBitmap(&pkt);
+ if (pkt.headers == LOWPAN_NALP_PATTERN) goto discard_packet;
+
+ stats.rx_frags++;
+ stats.rx_bytes += ser_len - 1;
+ if (hasFrag1Header(&pkt) || hasFragNHeader(&pkt)) {
+ unpack_info_t u_info;
+ uint8_t amount_here;
+
+ 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 {
+ uint8_t offset_cmpr;
+ uint16_t offset;
+ if (getFragDgramOffset(&pkt, &offset_cmpr)) goto discard_packet;
+ offset = offset_cmpr * 8;
+ payload = getLowpanPayload(&pkt);
+ amount_here = pkt.len - (payload - pkt.data);
+
+ if (offset + amount_here > recon->size) goto discard_packet;
+ ip_memcpy(((uint8_t *)&msg->hdr) + offset, payload, amount_here);
+ recon->bytes_rcvd += amount_here;
+
+ if (recon->size == recon->bytes_rcvd) {
+ // got all the fragments...
+ debug ("serial: reconstruction finished\n");
+ add_header_list(msg);
+
+ msg->metadata.sender = pkt.src;
+
+ handle_serial_packet(msg);
+
+ recon->timeout = T_UNUSED;
+ free_split_msg(msg);
+ free(recon->buf);
+ }
+ }
+
+ } else {
+ unpack_info_t u_info;
+ // 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));; */
+
+ ip_memcpy(u_info.header_end, u_info.payload_start, ntohs(msg->hdr.plen));
+
+ add_header_list(msg);
+
+ handle_serial_packet(msg);
+ free_split_msg(msg);
+ }
+ } else {
+ //printf("no data on serial port, but FD triggered select\n");
+ rv = 0;
+ }
+ discard_packet:
+ // debug("serial_input: discard packet\n");
+ free(ser_data);
+ return rv;
+}
+
+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\r\n",
+ stats.rx_pkts, stats.rx_frags, stats.rx_bytes);
+ VTY_printf(" transmit packets: %lu fragments: %lu bytes: %lu\r\n",
+ stats.tx_pkts, stats.tx_frags, stats.tx_bytes);
+ VTY_printf(" forward packets: %lu\r\n", stats.fw_pkts);
+ VTY_printf(" dag seqno: %hi\r\n", routing_get_seqno());
+ VTY_flush();
+}
+
+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(" rebuild : initiate a DAG recomputation\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);
+ }
+ }
+ 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);
+ }
+ }
+ VTY_flush();
+}
+
+#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();
+}
+
+void sh_incr_seqno(int fd, int argc, char **argv) {
+ VTY_HEAD;
+ VTY_printf("DAG seqno now %i\r\n", routing_incr_seqno());
+ radvd_reset_adverts();
+
+ VTY_flush();
+}
+
+struct vty_cmd vty_cmd_list[] = {{"help", print_help},
+ {"stats", print_stats},
+ {"links", nw_print_links},
+ {"routes", 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},
+ {"rebuild", sh_incr_seqno},
+#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) {
+ fd_set fs;
+ int maxfd = -1;
+ int usecs_remain = KEEPALIVE_INTERVAL;
+ time_t last_aging, current_time;
+ time(&last_aging);
+#ifndef SF_SRC
+ int pan_fd = opt_listenonly ? -1 : serial_source_fd(ser_src);
+#else
+ int pan_fd = opt_listenonly ? -1 : sf_fd;
+#endif
+
+ while (1) {
+ int n_fds;
+ struct timeval tv;
+ if (do_shutdown) return 0;
+
+ FD_ZERO(&fs);
+
+ 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);
+ }
+
+ maxfd = max(vty_add_fds(&fs), maxfd);
+ maxfd = max(routing_add_fds(&fs), maxfd);
+
+ // 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 && !opt_listenonly) {
+ configure_setparms(&driver_config, CONFIG_KEEPALIVE);
+ } else keepalive_needed = 1;
+
+ 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();
+ }
+
+ /* end of data available */
+ time(¤t_time);
+ if (current_time > last_aging + (FRAG_EXPIRE_TIME / 1024)) {
+ last_aging = current_time;
+ age_reconstructions();
+ }
+ }
+
+}
+
+int main(int argc, char **argv) {
+ int i, c;
+
+ time(&stats.boot_time);
+
+ log_init();
+ while ((c = getopt(argc, argv, "c:lt")) != -1) {
+ switch (c) {
+ case 'c':
+ def_configfile = optarg;
+ break;
+ case 'l':
+ opt_listenonly = 1;
+ info("Listen Only: will not attach to interface device\n");
+ 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 && !opt_listenonly) {
+#ifndef SF_SRC
+ fatal("usage: %s [-c config] [-l] <device> <rate>\n", argv[0]);
+#else
+ fatal("usage: %s [-c config] <host> <port>\n", argv[0]);
+#endif
+ exit(2);
+ }
+
+ fifo_open();
+ signal(SIGINT, driver_shutdown);
+
+ if (config_parse(def_configfile, &driver_config) != 0) {
+ fatal ("config parse of %s failed!\n", def_configfile);
+ exit(1);
+ }
+ globalPrefix = 1;
+ memcpy(&__my_address, &driver_config.router_addr, sizeof(struct in6_addr));
+
+
+ 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("telnet console server running on port %i\n", vty_port);
+ }
+
+
+ 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 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);
+ }
+#endif
+
+#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 */
+ info("driver shutting down\n");
+ vty_shutdown();
+ if (!opt_listenonly) {
+ tun_close(tun_fd, dev);
+ close_pan();
+ }
+ fifo_close();
+ return 0;
+}