struct icmpv6_nd_ra {
                        __u8            hop_limit;
 #if defined(__LITTLE_ENDIAN_BITFIELD)
-                       __u8            reserved:6,
+                       __u8            reserved:4,
+                                       router_pref:2,
                                        other:1,
                                        managed:1;
 
 #elif defined(__BIG_ENDIAN_BITFIELD)
                        __u8            managed:1,
                                        other:1,
-                                       reserved:6;
+                                       router_pref:2,
+                                       reserved:4;
 #else
 #error "Please fix <asm/byteorder.h>"
 #endif
 #define icmp6_addrconf_managed icmp6_dataun.u_nd_ra.managed
 #define icmp6_addrconf_other   icmp6_dataun.u_nd_ra.other
 #define icmp6_rt_lifetime      icmp6_dataun.u_nd_ra.rt_lifetime
+#define icmp6_router_pref      icmp6_dataun.u_nd_ra.router_pref
 };
 
+#define ICMPV6_ROUTER_PREF_LOW         0x3
+#define ICMPV6_ROUTER_PREF_MEDIUM      0x0
+#define ICMPV6_ROUTER_PREF_HIGH                0x1
+#define ICMPV6_ROUTER_PREF_INVALID     0x2
 
 #define ICMPV6_DEST_UNREACH            1
 #define ICMPV6_PKT_TOOBIG              2
 
 #define RTF_FLOW       0x02000000      /* flow significant route       */
 #define RTF_POLICY     0x04000000      /* policy route                 */
 
+#define RTF_PREF(pref) ((pref) << 27)
+#define RTF_PREF_MASK  0x18000000
+
 #define RTF_LOCAL      0x80000000
 
+#ifdef __KERNEL__
+#define IPV6_EXTRACT_PREF(flag)        (((flag) & RTF_PREF_MASK) >> 27)
+#define IPV6_DECODE_PREF(pref) ((pref) ^ 2)    /* 1:low,2:med,3:high */
+#endif
+
 struct in6_rtmsg {
        struct in6_addr         rtmsg_dst;
        struct in6_addr         rtmsg_src;
 
 extern struct rt6_info *       rt6_get_dflt_router(struct in6_addr *addr,
                                                    struct net_device *dev);
 extern struct rt6_info *       rt6_add_dflt_router(struct in6_addr *gwaddr,
-                                                   struct net_device *dev);
+                                                   struct net_device *dev,
+                                                   unsigned int pref);
 
 extern void                    rt6_purge_dflt_routers(void);
 
 
 
          See <file:Documentation/networking/ip-sysctl.txt> for details.
 
+config IPV6_ROUTER_PREF
+       bool "IPv6: Router Preference (RFC 4191) support"
+       depends on IPV6
+       ---help---
+         Router Preference is an optional extension to the Router
+         Advertisement message to improve the ability of hosts
+         to pick more appropriate router, especially when the hosts
+         is placed in a multi-homed network.
+
+         If unsure, say N.
+
 config INET6_AH
        tristate "IPv6: AH transformation"
        depends on IPV6
 
        int lifetime;
        struct ndisc_options ndopts;
        int optlen;
+       unsigned int pref = 0;
 
        __u8 * opt = (__u8 *)(ra_msg + 1);
 
 
        lifetime = ntohs(ra_msg->icmph.icmp6_rt_lifetime);
 
+#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)
+               pref = ICMPV6_ROUTER_PREF_MEDIUM;
+#endif
+
        rt = rt6_get_dflt_router(&skb->nh.ipv6h->saddr, skb->dev);
 
        if (rt)
                ND_PRINTK3(KERN_DEBUG
                           "ICMPv6 RA: adding default router.\n");
 
-               rt = rt6_add_dflt_router(&skb->nh.ipv6h->saddr, skb->dev);
+               rt = rt6_add_dflt_router(&skb->nh.ipv6h->saddr, skb->dev, pref);
                if (rt == NULL) {
                        ND_PRINTK0(KERN_ERR
                                   "ICMPv6 RA: %s() failed to add default route.\n",
                        return;
                }
                neigh->flags |= NTF_ROUTER;
+       } else if (rt) {
+               rt->rt6i_flags |= (rt->rt6i_flags & ~RTF_PREF_MASK) | RTF_PREF(pref);
        }
 
        if (rt)
 
        int m = rt6_check_dev(rt, oif);
        if (!m && (strict & RT6_SELECT_F_IFACE))
                return -1;
+#ifdef CONFIG_IPV6_ROUTER_PREF
+       m |= IPV6_DECODE_PREF(IPV6_EXTRACT_PREF(rt->rt6i_flags)) << 2;
+#endif
        if (rt6_check_neigh(rt))
-               m |= 4;
+               m |= 16;
        else if (strict & RT6_SELECT_F_REACHABLE)
                return -1;
        return m;
 }
 
 struct rt6_info *rt6_add_dflt_router(struct in6_addr *gwaddr,
-                                    struct net_device *dev)
+                                    struct net_device *dev,
+                                    unsigned int pref)
 {
        struct in6_rtmsg rtmsg;
 
        rtmsg.rtmsg_type = RTMSG_NEWROUTE;
        ipv6_addr_copy(&rtmsg.rtmsg_gateway, gwaddr);
        rtmsg.rtmsg_metric = 1024;
-       rtmsg.rtmsg_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT | RTF_UP | RTF_EXPIRES;
+       rtmsg.rtmsg_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT | RTF_UP | RTF_EXPIRES |
+                           RTF_PREF(pref);
 
        rtmsg.rtmsg_ifindex = dev->ifindex;