Index: kernel/linux22/net/ipv6/route.c
===================================================================
RCS file: /cvsroot/usagi/usagi/kernel/linux22/net/ipv6/route.c,v
retrieving revision 1.12
retrieving revision 1.14
diff -u -r1.12 -r1.14
--- kernel/linux22/net/ipv6/route.c     2001/08/19 18:37:42     1.12
+++ kernel/linux22/net/ipv6/route.c     2001/08/22 13:22:36     1.14
@@ -1,4 +1,4 @@
-/* $USAGI: route.c,v 1.12 2001/08/19 18:37:42 yoshfuji Exp $ */
+/* $USAGI: route.c,v 1.14 2001/08/22 13:22:36 yoshfuji Exp $ */

/*
 *     Linux INET6 implementation
@@ -15,6 +15,17 @@
 *      2 of the License, or (at your option) any later version.
 */

+/*     Changes:
+ *
+ *     yoshfuji@USAGI
+ *             reworked default router selection.
+ *             - respect outgoing interface
+ *             - select from (probably) reachable routers (i.e.
+ *             routers in REACHABLE, STALE, DELAY or PROBE states).
+ *             - always select the same router if it is (probably)
+ *             reachable.  otherwise, round-robin the list.
+ */
+
#include <linux/config.h>
#include <linux/errno.h>
#include <linux/types.h>
@@ -252,6 +263,7 @@
                *      SHOULD round robin
                */
               if (rt6_dflt_pointer) {
+                       int ok = 0;
                       for (sprt = rt6_dflt_pointer->u.next;
                            sprt; sprt = sprt->u.next) {
                               if (sprt->u.dst.error == 0) {
@@ -260,23 +272,53 @@
                               }
                       }
                       for (sprt = rt;
-                            !match && sprt && sprt != rt6_dflt_pointer;
-                            sprt = sprt->u.next) {
+                            sprt; sprt = sprt->u.next) {
+                               if (sprt == rt6_dflt_pointer) {
+                                       ok = 1;
+                                       break;
+                               }
                               if (sprt->u.dst.error == 0) {
                                       match = sprt;
                                       break;
                               }
+                       }
+                       if (!ok) {
+                               /* rt6_dflt_router is for others */
+                               match = NULL;
+                       }
+               }
+       }
+
+       if (match) {
+               if (rt6_dflt_pointer != match)
+                       RT6_TRACE1(KERN_INFO
+                                       "changed default router: %p->%p\n",
+                                       rt6_dflt_pointer, match);
+               rt6_dflt_pointer = match;
+       }
+
+       if (!match) {
+               /*
+                * Last Resort: if no default routers found,
+                * use addrconf default route.
+                * We don't record this route.
+                */
+               for (sprt = ip6_routing_table.leaf;
+                    sprt; sprt = sprt->u.next) {
+                       if ((sprt->rt6i_flags & RTF_DEFAULT) &&
+                           (!oif ||
+                            (sprt->rt6i_dev &&
+                             sprt->rt6i_dev->ifindex == oif))) {
+                               match = sprt;
+                               break;
                       }
-                       if (!match)
-                               match = rt6_dflt_pointer;       /*XXX*/
+               }
+               if (!match) {
+                       /* no default route.  give up. */
+                       match = &ip6_null_entry;
               }
       }

-       if (rt6_dflt_pointer != match)
-               RT6_TRACE1(KERN_INFO
-                               "changed default router: %p->%p\n",
-                               rt6_dflt_pointer, match);
-       rt6_dflt_pointer = match;
       return match;
}