]> oss.titaniummirror.com Git - tinyos-2.x.git/blobdiff - support/sdk/c/blip/driver/radvd-wrapper.c
Merge TinyOS 2.1.1 into master.
[tinyos-2.x.git] / support / sdk / c / blip / driver / radvd-wrapper.c
diff --git a/support/sdk/c/blip/driver/radvd-wrapper.c b/support/sdk/c/blip/driver/radvd-wrapper.c
new file mode 100644 (file)
index 0000000..97723e4
--- /dev/null
@@ -0,0 +1,198 @@
+/*
+ * "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>
+ *
+ * Alternate set of call points for the IPv6 router advertisement
+ * daemon.  Using this interface the daemon may be integrated into
+ * another program (like ip-driver).  radvd is distributed under a
+ * BSD-like license.
+ *
+ * radvd_init() must be called to set up state for the specified
+ *   interface.  If successful, it will return a file descriptor;
+ *   radvd_process() must be called whenever there is pending data on
+ *   this descriptor (ie, from a select() loop.)
+ *
+ * radvd has its own logging infrastructure; by default radvd_init()
+ * sends that log to stderr and makes no attempt to integrate it with
+ * whatever logging facilities may be availabile.  See radvd/log.c for
+ * more.
+ *
+ * NB: radvd uses SIGALRM for its internal timer.  Thus, once
+ * radvd_init() has been called, SIGALRM must not be used elsewhere in
+ * the application.
+ *
+ */
+
+
+#include "radvd-1.0/includes.h"
+#include "radvd-1.0/radvd.h"
+#include "radvd-1.0/pathnames.h"
+
+#include "logging.h"
+#include "config.h"
+
+struct Interface *iface;
+int sock;
+
+void radvd_timer_handler(void *data) {
+  struct Interface *iface = (struct Interface *) data;
+  double next;
+
+  dlog(LOG_DEBUG, 4, "timer_handler called for %s", iface->Name);
+
+  send_ra(sock, iface, NULL);
+
+  next = rand_between(iface->MinRtrAdvInterval, iface->MaxRtrAdvInterval); 
+
+  if (iface->init_racount < MAX_INITIAL_RTR_ADVERTISEMENTS) {
+    iface->init_racount++;
+    next = min(MAX_INITIAL_RTR_ADVERT_INTERVAL, next);
+  }
+
+  set_timer(&iface->tm, next);
+}
+
+void radvd_reset_adverts(void) {
+  if (iface->AdvSendAdvert) {
+    /* send an initial advertisement */
+    send_ra(sock, iface, NULL);
+    
+    iface->init_racount = 0;
+
+    set_timer(&iface->tm,
+              min(MAX_INITIAL_RTR_ADVERT_INTERVAL,
+                  iface->MaxRtrAdvInterval));
+  }
+}
+
+
+void radvd_kickoff_adverts(void) {
+  init_timer(&iface->tm, radvd_timer_handler, (void *) iface);
+  if (iface->AdvSendAdvert) {
+    /* send an initial advertisement */
+    send_ra(sock, iface, NULL);
+    
+    iface->init_racount++;
+
+    set_timer(&iface->tm,
+              min(MAX_INITIAL_RTR_ADVERT_INTERVAL,
+                  iface->MaxRtrAdvInterval));
+  }
+}
+
+void radvd_process() {
+  unsigned char msg[MSG_SIZE];
+  int len, hoplimit;
+  struct sockaddr_in6 rcv_addr;
+  struct in6_pktinfo *pkt_info = NULL;
+  
+  len = recv_rs_ra(sock, msg, &rcv_addr, &pkt_info, &hoplimit);
+  if (len > 0)
+    process(sock, iface, msg, len, 
+            &rcv_addr, pkt_info, hoplimit);
+  
+}
+
+
+/* Set up all the radvd internal stuff from our own configuration */
+int radvd_init(char *ifname, struct config *c) {
+  struct AdvPrefix *prefix;
+  sigset_t oset, nset;
+
+
+  if (log_open(L_STDERR, "radvd", NULL, -1) < 0) {
+    error("log_open\n");
+    return -1;
+  }
+  srand((unsigned int)time(NULL));
+  info("starting radvd on device %s\n", ifname);
+
+  sock = open_icmpv6_socket();
+  if (sock < 0) {
+    error("open_icmpv6_socket\n");
+    return -1;
+  }
+  sigemptyset(&nset);
+  sigaddset(&nset, SIGALRM);
+  sigprocmask(SIG_UNBLOCK, &nset, &oset);
+  if (sigismember(&oset, SIGALRM))
+    flog(LOG_WARNING, "SIGALRM has been unblocked. Your startup environment might be wrong.");
+
+
+  /* setup the radvd struct Interface to know about all our defaults */
+  iface = malloc(sizeof(struct Interface));
+  if (iface == NULL)
+    return -1;
+
+  iface_init_defaults(iface);
+  strncpy(iface->Name, ifname, IFNAMSIZ-1);
+  iface->Name[IFNAMSIZ-1] = '\0';
+
+  iface->next = NULL;
+  iface->AdvSendAdvert = 1;
+
+  /* check the interface exists... this probably shouldn't fail */
+  if (check_device(sock, iface) < 0) {
+    error("check_device!\n");
+    return -1;
+  }
+  
+  if (setup_deviceinfo(sock, iface) < 0) {
+    error("setup_deviceinfo\n");
+    return -1;
+  }
+  if (check_iface(iface) < 0) {
+    error("check_iface\n");
+    return -1;
+  }
+  if (setup_linklocal_addr(sock, iface) < 0) {
+    error("setup_linklocal_addr\n");
+    return -1;
+  }
+  if (setup_allrouters_membership(sock, iface) < 0) {
+    error("setup_allrouters_membership\n");
+    return -1;
+  }
+
+
+  /* set up the prefix we're advertising from the config struct we get passed in. */
+  prefix = malloc(sizeof(struct AdvPrefix));
+  if (prefix == NULL)
+    return -1;
+
+  prefix_init_defaults(prefix);
+  prefix->PrefixLen = 64;
+  memcpy(&prefix->Prefix, c->router_addr.s6_addr, sizeof(struct in6_addr));
+  prefix->next = NULL;
+
+  iface->AdvPrefixList = prefix;
+
+
+  // config_interface();
+  radvd_kickoff_adverts();
+
+  set_debuglevel(0);
+
+  return sock;
+}