#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"; */
-
-}