Merge branch 'upstream-linus' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik...
[pandora-kernel.git] / net / ipv6 / ndisc.c
index 966ab6b..dfa20d3 100644 (file)
@@ -156,7 +156,11 @@ struct neigh_table nd_tbl = {
 
 /* ND options */
 struct ndisc_options {
-       struct nd_opt_hdr *nd_opt_array[__ND_OPT_MAX];
+       struct nd_opt_hdr *nd_opt_array[__ND_OPT_ARRAY_MAX];
+#ifdef CONFIG_IPV6_ROUTE_INFO
+       struct nd_opt_hdr *nd_opts_ri;
+       struct nd_opt_hdr *nd_opts_ri_end;
+#endif
 };
 
 #define nd_opts_src_lladdr     nd_opt_array[ND_OPT_SOURCE_LL_ADDR]
@@ -255,6 +259,13 @@ static struct ndisc_options *ndisc_parse_options(u8 *opt, int opt_len,
                        if (ndopts->nd_opt_array[nd_opt->nd_opt_type] == 0)
                                ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt;
                        break;
+#ifdef CONFIG_IPV6_ROUTE_INFO
+               case ND_OPT_ROUTE_INFO:
+                       ndopts->nd_opts_ri_end = nd_opt;
+                       if (!ndopts->nd_opts_ri)
+                               ndopts->nd_opts_ri = nd_opt;
+                       break;
+#endif
                default:
                        /*
                         * Unknown options must be silently ignored,
@@ -1090,7 +1101,8 @@ static void ndisc_router_discovery(struct sk_buff *skb)
 #ifdef CONFIG_IPV6_ROUTER_PREF
        pref = ra_msg->icmph.icmp6_router_pref;
        /* 10b is handled as if it were 00b (medium) */
-       if (pref == ICMPV6_ROUTER_PREF_INVALID)
+       if (pref == ICMPV6_ROUTER_PREF_INVALID ||
+           in6_dev->cnf.accept_ra_rtr_pref)
                pref = ICMPV6_ROUTER_PREF_MEDIUM;
 #endif
 
@@ -1201,6 +1213,20 @@ skip_defrtr:
                             NEIGH_UPDATE_F_ISROUTER);
        }
 
+#ifdef CONFIG_IPV6_ROUTE_INFO
+       if (in6_dev->cnf.accept_ra_rtr_pref && ndopts.nd_opts_ri) {
+               struct nd_opt_hdr *p;
+               for (p = ndopts.nd_opts_ri;
+                    p;
+                    p = ndisc_next_option(p, ndopts.nd_opts_ri_end)) {
+                       if (((struct route_info *)p)->prefix_len > in6_dev->cnf.accept_ra_rt_info_max_plen)
+                               continue;
+                       rt6_route_rcv(skb->dev, (u8*)p, (p->nd_opt_len) << 3,
+                                     &skb->nh.ipv6h->saddr);
+               }
+       }
+#endif
+
        if (in6_dev->cnf.accept_ra_pinfo && ndopts.nd_opts_pi) {
                struct nd_opt_hdr *p;
                for (p = ndopts.nd_opts_pi;