changeset 300:58c748750ca6

Improve IPv6 routing.
author gthomas
date Sat, 17 Aug 2002 00:03:03 +0000
parents 78a5b319acd3
children 7de36227e601
files packages/net/common/current/ChangeLog packages/net/common/current/src/ipv6_routing_thread.c
diffstat 2 files changed, 258 insertions(+), 70 deletions(-) [+]
line wrap: on
line diff
--- a/packages/net/common/current/ChangeLog
+++ b/packages/net/common/current/ChangeLog
@@ -1,3 +1,9 @@
+2002-08-16  Gary Thomas  <gthomas@ecoscentric.com> (on behalf of)
+2002-08-16  Louis Hamilton <hamilton@redhat.com>	
+
+	* src/ipv6_routing_thread.c: General improvements (from Red Hat)
+	for better compliance.
+
 2002-08-14  Jonathan Larmour  <jifl@ecoscentric.com>
 
 	* src/getserv.c: Include errno.h as errno is used.
--- a/packages/net/common/current/src/ipv6_routing_thread.c
+++ b/packages/net/common/current/src/ipv6_routing_thread.c
@@ -19,7 +19,7 @@
 //#####DESCRIPTIONBEGIN####
 //
 // Author(s):    gthomas
-// Contributors: gthomas
+// Contributors: gthomas, lhamilton
 // Date:         2002-04-16
 // Purpose:      
 // Description:  
@@ -51,96 +51,277 @@
 #include <netinet6/in6_var.h>
 #include <netinet6/nd6.h>
 
+#include <stdio.h>
 #include <unistd.h>
 #include <stdlib.h>
 #include <string.h>
 
-#define ALLROUTER       "ff02::2"
+void _show_all_interfaces(void);
+
+#define DBG_PRINT                          1
+#define ALLROUTER                  "ff02::2"
 
-#define STACK_SIZE CYGNUM_HAL_STACK_SIZE_TYPICAL+2048
+#define STACK_SIZE    CYGNUM_HAL_STACK_SIZE_TYPICAL+2048
+#define _1_MILLION                   1000000
+#define STATE_DELAY                        0
+#define STATE_PROBE                        1
+#define STATE_IDLE                         2
+
+#define MAX_RTR_SOLICITATIONS              3
+#define SEL_TIMEOUT_IDLE                 145
+#define SECONDS_TILL_RS_SEND      (12*60*60)
+
 static char rs_stack[STACK_SIZE];
 static cyg_thread rs_thread_data;
 static cyg_handle_t rs_thread_handle;
+static int s;
+static int probe=0;
+static int racount=0;
+static int state;
+static int badra;
+static int cc = sizeof(struct icmp6_hdr);
+static u_char outpack[sizeof(struct icmp6_hdr)];
+struct sockaddr_in6 to;
+static struct timeval select_timeout;
+static struct timeval last_ra_time;
+static struct timeval idle_expire;
+static struct icmp6stat *istat;
+extern struct icmp6stat cyg_icmp6stat;
 
 static void
 cyg_rs_exit(void)
 {
-    cyg_thread_exit();
+  diag_printf("<%s>\n", __FUNCTION__);
+  cyg_thread_exit();
+}
+
+static void
+dprnt(const char *msg, ...)
+{
+#ifdef DBG_PRINT
+  va_list ap;
+
+  va_start(ap, msg);
+  (void) vfprintf(stdout, msg, ap);
+  (void) fprintf(stdout, "\n");
+  va_end(ap);
+#endif
+}
+
+#ifdef DBG_PRINT
+void
+sleep_msg(char *str, int total)
+{
+  int hours, minutes;
+
+  hours = total / 3600;
+  total -= hours * 3600;
+  minutes = total / 60;
+  total -= minutes * 60;
+
+  if (hours > 0)
+    dprnt("%s: %d hr, %d min", str, hours, minutes);
+  else if (minutes > 0)
+    dprnt("%s: %d min, %d sec", str, minutes, total);
+  else
+    dprnt("%s: %d sec", str, total);
+}
+#endif
+
+void
+get_realtime(struct timeval *now)
+{
+  struct timespec tp;
+  clock_gettime(CLOCK_REALTIME, &tp);
+  now->tv_sec = tp.tv_sec;
+  now->tv_usec = 0;
+}
+
+void
+send_rs_packet(void)
+{
+  probe++;
+
+  dprnt("%s: probe=%d", __FUNCTION__, probe);
+
+  if (sendto(s, outpack, cc, 0, (struct sockaddr *)&to, to.sin6_len) < 0) {
+    dprnt("%s: can't send RS: %s", __FUNCTION__, strerror(errno));
+  }
+}
+
+void
+receive_ra_packet(void)
+{
+  int len;
+  char msg[1024];
+
+  dprnt("%s", __FUNCTION__);
+
+  len = read(s, msg, sizeof(msg));
+  if (len < 0) {
+    dprnt("  Can't read RA data: %s", strerror(errno));
+    return;
+  }
+  dprnt("packet data (buf len=%d) :", len);
+  diag_dump_buf(msg, len);
+
+  racount++;
+  get_realtime(&last_ra_time);
+  dprnt("racount=%d, timestamp=%d sec",
+	racount, last_ra_time.tv_sec);
+
+  if (badra != istat->icp6s_badra) {
+    /* BAD RA received by ipv6 stack (nd6_ra_input).
+       Resend RS packet. */
+    badra = istat->icp6s_badra;
+    dprnt("<Bad RA (Router Advertisement)>");
+    return;
+  }
+  /* Check the ICMPv6 RA Code */
+  if (msg[1] != 0) {
+    len = (int)msg[1];
+    dprnt("<Bad ICMPv6 Code: %d>", len);
+    return;
+  }
+
+  /* RA received, go idle for SECONDS_TILL_RS_SEND */
+  idle_expire.tv_sec = last_ra_time.tv_sec +
+    SECONDS_TILL_RS_SEND;
+  probe = 0;
+  select_timeout.tv_sec = SEL_TIMEOUT_IDLE;
+  if (state != STATE_IDLE)
+    dprnt("Going IDLE, thread listening");
+  state = STATE_IDLE;
+}
+
+void
+check_timer(void)
+{
+  struct timeval now;
+
+  if (state == STATE_DELAY) {
+    probe = 0;
+    select_timeout.tv_sec = RTR_SOLICITATION_INTERVAL;
+    state = STATE_PROBE;
+    send_rs_packet();
+  } else if (state == STATE_PROBE) {
+    dprnt("%s: state: PROBE", __FUNCTION__);
+    if (probe < MAX_RTR_SOLICITATIONS) {
+      send_rs_packet();
+    } else {
+      dprnt("Maximum %d rtr solicitations sent out",
+	    MAX_RTR_SOLICITATIONS);
+      get_realtime(&now);
+      probe = 0;
+      idle_expire.tv_sec = now.tv_sec +
+	SECONDS_TILL_RS_SEND;
+      dprnt("Going IDLE");
+      select_timeout.tv_sec = SEL_TIMEOUT_IDLE;
+      state = STATE_IDLE;
+#ifdef DBG_PRINT
+      sleep_msg("Thread listening (state=IDLE)",
+		SECONDS_TILL_RS_SEND);
+#endif
+    }
+  } else {
+    /* STATE_IDLE */
+    get_realtime(&now);
+    if (now.tv_sec >= idle_expire.tv_sec) {
+      dprnt("<Leaving IDLE; Woke up to retry RS send>");
+      select_timeout.tv_sec = 1;
+      state = STATE_DELAY;
+    }
+#ifdef DBG_PRINT
+    else if ((idle_expire.tv_sec - now.tv_sec) < (5 * 60)) {
+      sleep_msg("Coming out of IDLE in",
+		idle_expire.tv_sec - now.tv_sec);
+    }
+#endif
+  }
 }
 
 static void
 cyg_rs(cyg_addrword_t param)
 {
-    struct timeval tv;
-    struct addrinfo hints, *res;
-    int s, len, err;
-    struct sockaddr_in6 to;
-    struct icmp6_hdr *icp;
-    u_int hlim = 255;
-    u_char outpack[sizeof(struct icmp6_hdr)];
-    int cc = sizeof(struct icmp6_hdr);
-    fd_set fdset;
-    char msg[1024];
+  struct addrinfo hints, *res;
+  struct icmp6_hdr *icp;
+  struct icmp6_filter filt;
+  struct timeval loop_delay;
+  int err, status;
+  u_int hlim = 255;
+  fd_set fdset;
+
+  _show_all_interfaces();
 
-    _show_all_interfaces();
+  memset(&hints, 0, sizeof(hints));
+  hints.ai_family = AF_INET6;
+  err = getaddrinfo(ALLROUTER, NULL, &hints, &res);
+  if (err) {
+    dprnt("%s - failed to get ALL ROUTER: %s",
+		__FUNCTION__, gai_strerror(err));
+    cyg_rs_exit();
+  }
+  memcpy(&to, res->ai_addr, res->ai_addrlen);
+  *(u_int16_t *)&to.sin6_addr.s6_addr[2] = htons(1);
+
+  if ((s = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) {
+    dprnt("%s - can't open socket: %s",
+		__FUNCTION__, strerror(errno));
+    cyg_rs_exit();
+  }
+  if (setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
+		 &hlim, sizeof(hlim)) < 0) {
+    dprnt("%s - can't set IPV6 MULTICAST HOPS: %s",
+		__FUNCTION__, strerror(errno));
+    cyg_rs_exit();
+  }
 
-    memset(&hints, 0, sizeof(hints));
-    hints.ai_family = AF_INET6;
-    err = getaddrinfo(ALLROUTER, NULL, &hints, &res);
-    if (err) {
-        diag_printf("%s - failed to get ALL ROUTER: %s", 
-                    __FUNCTION__, gai_strerror(err));
-        cyg_rs_exit();
-    }
-    memcpy(&to, res->ai_addr, res->ai_addrlen);
-    *(u_int16_t *)&to.sin6_addr.s6_addr[2] = htons(1);
+  /* Specify to accept only router advertisements on the socket */
+  ICMP6_FILTER_SETBLOCKALL(&filt);
+  ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filt);
+  if (setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER,
+		 &filt, sizeof(filt)) < 0) {
+    dprnt("%s - can't set ICMP6 filter: %s",
+		__FUNCTION__, strerror(errno));
+    cyg_rs_exit();
+  }
+
+  idle_expire.tv_usec = 0;
+  select_timeout.tv_usec = 0;
+  last_ra_time.tv_usec = 0;
+  last_ra_time.tv_sec = 10;
+  select(0, 0, 0, 0, &last_ra_time);
 
-    if ((s = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) {
-        diag_printf("%s - can't open socket: %s\n", 
-                    __FUNCTION__, strerror(errno));
-        cyg_rs_exit();
-    }
-    if (setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, 
-                   &hlim, sizeof(hlim)) < 0) {
-        diag_printf("%s - can set IPV6 MULTICAST HOPS: %s\n",
-                    __FUNCTION__, strerror(errno));
-        cyg_rs_exit();
+  racount = 0;
+  istat = &(cyg_icmp6stat);
+  badra = istat->icp6s_badra;
+
+  icp = (struct icmp6_hdr *)outpack;
+  icp->icmp6_type = ND_ROUTER_SOLICIT;
+  icp->icmp6_code = 0;
+  icp->icmp6_cksum = 0;
+  icp->icmp6_data32[0] = 0; /* RS reserved field */
+  state = STATE_DELAY;
+
+  while (true) {
+    FD_ZERO(&fdset);
+    FD_SET(s, &fdset);
+
+    check_timer();
+
+    status = select(s + 1, &fdset, NULL, NULL, &select_timeout);
+    if (status < 0) {
+      dprnt("%s - select: %s", strerror(errno));
+      continue;
     }
-
-    tv.tv_sec = 15;
-    tv.tv_usec = 0;
-    select(0, 0, 0, 0, &tv);  // Sleeps for tv
-
-    icp = (struct icmp6_hdr *)outpack;
-    icp->icmp6_type = ND_ROUTER_SOLICIT;
-    icp->icmp6_code = 0;
-    icp->icmp6_cksum = 0;
-    icp->icmp6_data32[0] = 0; /* RS reserved field */
+    if (status == 1)
+      receive_ra_packet();
 
-    while (true) {
-	if (sendto(s, outpack, cc, 0, (struct sockaddr *)&to, to.sin6_len) < 0) {
-           diag_printf("%s - can't send RS: %s\n",
-                       __FUNCTION__, strerror(errno));
-        }
-        // See if a router gives back an answer
-	FD_ZERO(&fdset);
-	FD_SET(s, &fdset);
-	tv.tv_sec = RTR_SOLICITATION_INTERVAL;
-	tv.tv_usec = 0;
-	if (select(s + 1, &fdset, NULL, NULL, &tv) == 1) {
-            len = read(s, msg, sizeof(msg));
-            if (len < 0) {
-                diag_printf("%s - can't read router message: %s\n",
-                            __FUNCTION__, strerror(errno));
-            } else {
-                diag_printf("%s - router message\n", __FUNCTION__);
-                diag_dump_buf(msg, len);
-            }
-	}
-        tv.tv_sec = CYGINT_NET_IPV6_ROUTING_THREAD_PERIOD - RTR_SOLICITATION_INTERVAL;
-        tv.tv_usec = 0;
-        select(0, 0, 0, 0, &tv);  // Sleeps for tv
-    }
+    loop_delay.tv_sec = 2;
+    loop_delay.tv_usec = 0;
+    select(0, 0, 0, 0, &loop_delay);
+  }
+  /* NOTREACHED */
 }
 
 void
@@ -156,6 +337,7 @@ ipv6_start_routing_thread(void)
         &rs_thread_handle,                       // Handle
         &rs_thread_data                          // Thread data structure
         );
-    cyg_thread_resume(rs_thread_handle);    // Start it
+    cyg_thread_resume(rs_thread_handle);         // Start it
     diag_printf("IPv6 routing thread started\n");
 }
+