Pull asus into release branch
[pandora-kernel.git] / net / ipv6 / addrconf.c
index 569a37d..452a82c 100644 (file)
@@ -172,6 +172,7 @@ struct ipv6_devconf ipv6_devconf __read_mostly = {
 #endif
 #endif
        .proxy_ndp              = 0,
+       .accept_source_route    = 0,    /* we do not accept RH0 by default. */
 };
 
 static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
@@ -203,6 +204,7 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
 #endif
 #endif
        .proxy_ndp              = 0,
+       .accept_source_route    = 0,    /* we do not accept RH0 by default. */
 };
 
 /* IPv6 Wildcard Address and Loopback Address defined by RFC2553 */
@@ -211,74 +213,6 @@ const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
 #endif
 const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
 
-#define IPV6_ADDR_SCOPE_TYPE(scope)    ((scope) << 16)
-
-static inline unsigned ipv6_addr_scope2type(unsigned scope)
-{
-       switch(scope) {
-       case IPV6_ADDR_SCOPE_NODELOCAL:
-               return (IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_NODELOCAL) |
-                       IPV6_ADDR_LOOPBACK);
-       case IPV6_ADDR_SCOPE_LINKLOCAL:
-               return (IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_LINKLOCAL) |
-                       IPV6_ADDR_LINKLOCAL);
-       case IPV6_ADDR_SCOPE_SITELOCAL:
-               return (IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_SITELOCAL) |
-                       IPV6_ADDR_SITELOCAL);
-       }
-       return IPV6_ADDR_SCOPE_TYPE(scope);
-}
-
-int __ipv6_addr_type(const struct in6_addr *addr)
-{
-       __be32 st;
-
-       st = addr->s6_addr32[0];
-
-       /* Consider all addresses with the first three bits different of
-          000 and 111 as unicasts.
-        */
-       if ((st & htonl(0xE0000000)) != htonl(0x00000000) &&
-           (st & htonl(0xE0000000)) != htonl(0xE0000000))
-               return (IPV6_ADDR_UNICAST |
-                       IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL));
-
-       if ((st & htonl(0xFF000000)) == htonl(0xFF000000)) {
-               /* multicast */
-               /* addr-select 3.1 */
-               return (IPV6_ADDR_MULTICAST |
-                       ipv6_addr_scope2type(IPV6_ADDR_MC_SCOPE(addr)));
-       }
-
-       if ((st & htonl(0xFFC00000)) == htonl(0xFE800000))
-               return (IPV6_ADDR_LINKLOCAL | IPV6_ADDR_UNICAST |
-                       IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_LINKLOCAL));               /* addr-select 3.1 */
-       if ((st & htonl(0xFFC00000)) == htonl(0xFEC00000))
-               return (IPV6_ADDR_SITELOCAL | IPV6_ADDR_UNICAST |
-                       IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_SITELOCAL));               /* addr-select 3.1 */
-
-       if ((addr->s6_addr32[0] | addr->s6_addr32[1]) == 0) {
-               if (addr->s6_addr32[2] == 0) {
-                       if (addr->s6_addr32[3] == 0)
-                               return IPV6_ADDR_ANY;
-
-                       if (addr->s6_addr32[3] == htonl(0x00000001))
-                               return (IPV6_ADDR_LOOPBACK | IPV6_ADDR_UNICAST |
-                                       IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_LINKLOCAL));       /* addr-select 3.4 */
-
-                       return (IPV6_ADDR_COMPATv4 | IPV6_ADDR_UNICAST |
-                               IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL));  /* addr-select 3.3 */
-               }
-
-               if (addr->s6_addr32[2] == htonl(0x0000ffff))
-                       return (IPV6_ADDR_MAPPED |
-                               IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL));  /* addr-select 3.3 */
-       }
-
-       return (IPV6_ADDR_RESERVED |
-               IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL));  /* addr-select 3.4 */
-}
-
 static void addrconf_del_timer(struct inet6_ifaddr *ifp)
 {
        if (del_timer(&ifp->timer))
@@ -410,10 +344,9 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev)
        }
 #endif
 
-       if (netif_carrier_ok(dev))
+       if (netif_running(dev) && netif_carrier_ok(dev))
                ndev->if_flags |= IF_READY;
 
-
        ipv6_mc_init_dev(ndev);
        ndev->tstamp = jiffies;
 #ifdef CONFIG_SYSCTL
@@ -468,6 +401,8 @@ static void dev_forward_change(struct inet6_dev *idev)
                        ipv6_dev_mc_dec(dev, &addr);
        }
        for (ifa=idev->addr_list; ifa; ifa=ifa->if_next) {
+               if (ifa->flags&IFA_F_TENTATIVE)
+                       continue;
                if (idev->cnf.forwarding)
                        addrconf_join_anycast(ifa);
                else
@@ -874,7 +809,7 @@ struct ipv6_saddr_score {
 #define IPV6_SADDR_SCORE_LABEL         0x0020
 #define IPV6_SADDR_SCORE_PRIVACY       0x0040
 
-static int inline ipv6_saddr_preferred(int type)
+static inline int ipv6_saddr_preferred(int type)
 {
        if (type & (IPV6_ADDR_MAPPED|IPV6_ADDR_COMPATv4|
                    IPV6_ADDR_LOOPBACK|IPV6_ADDR_RESERVED))
@@ -883,7 +818,7 @@ static int inline ipv6_saddr_preferred(int type)
 }
 
 /* static matching label */
-static int inline ipv6_saddr_label(const struct in6_addr *addr, int type)
+static inline int ipv6_saddr_label(const struct in6_addr *addr, int type)
 {
  /*
   *    prefix (longest match)  label
@@ -1910,6 +1845,7 @@ static int inet6_addr_add(int ifindex, struct in6_addr *pfx, int plen,
        struct inet6_dev *idev;
        struct net_device *dev;
        int scope;
+       u32 flags = RTF_EXPIRES;
 
        ASSERT_RTNL();
 
@@ -1925,9 +1861,10 @@ static int inet6_addr_add(int ifindex, struct in6_addr *pfx, int plen,
 
        scope = ipv6_addr_scope(pfx);
 
-       if (valid_lft == INFINITY_LIFE_TIME)
+       if (valid_lft == INFINITY_LIFE_TIME) {
                ifa_flags |= IFA_F_PERMANENT;
-       else if (valid_lft >= 0x7FFFFFFF/HZ)
+               flags = 0;
+       } else if (valid_lft >= 0x7FFFFFFF/HZ)
                valid_lft = 0x7FFFFFFF/HZ;
 
        if (prefered_lft == 0)
@@ -1945,6 +1882,8 @@ static int inet6_addr_add(int ifindex, struct in6_addr *pfx, int plen,
                ifp->tstamp = jiffies;
                spin_unlock_bh(&ifp->lock);
 
+               addrconf_prefix_route(&ifp->addr, ifp->prefix_len, dev,
+                                     jiffies_to_clock_t(valid_lft * HZ), flags);
                addrconf_dad_start(ifp, 0);
                in6_ifa_put(ifp);
                addrconf_verify(0);
@@ -2124,6 +2063,7 @@ static void addrconf_add_linklocal(struct inet6_dev *idev, struct in6_addr *addr
 
        ifp = ipv6_add_addr(idev, addr, 64, IFA_LINK, IFA_F_PERMANENT);
        if (!IS_ERR(ifp)) {
+               addrconf_prefix_route(&ifp->addr, ifp->prefix_len, idev->dev, 0, 0);
                addrconf_dad_start(ifp, 0);
                in6_ifa_put(ifp);
        }
@@ -2240,6 +2180,14 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,
        int run_pending = 0;
 
        switch(event) {
+       case NETDEV_REGISTER:
+               if (!idev) {
+                       idev = ipv6_add_dev(dev);
+                       if (!idev)
+                               printk(KERN_WARNING "IPv6: add_dev failed for %s\n",
+                                       dev->name);
+               }
+               break;
        case NETDEV_UP:
        case NETDEV_CHANGE:
                if (event == NETDEV_UP) {
@@ -2538,10 +2486,6 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags)
 
        addrconf_join_solict(dev, &ifp->addr);
 
-       if (ifp->prefix_len != 128 && (ifp->flags&IFA_F_PERMANENT))
-               addrconf_prefix_route(&ifp->addr, ifp->prefix_len, dev, 0,
-                                       flags);
-
        net_srandom(ifp->addr.s6_addr32[3]);
 
        read_lock_bh(&idev->lock);
@@ -2972,12 +2916,15 @@ inet6_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 static int inet6_addr_modify(struct inet6_ifaddr *ifp, u8 ifa_flags,
                             u32 prefered_lft, u32 valid_lft)
 {
+       u32 flags = RTF_EXPIRES;
+
        if (!valid_lft || (prefered_lft > valid_lft))
                return -EINVAL;
 
-       if (valid_lft == INFINITY_LIFE_TIME)
+       if (valid_lft == INFINITY_LIFE_TIME) {
                ifa_flags |= IFA_F_PERMANENT;
-       else if (valid_lft >= 0x7FFFFFFF/HZ)
+               flags = 0;
+       } else if (valid_lft >= 0x7FFFFFFF/HZ)
                valid_lft = 0x7FFFFFFF/HZ;
 
        if (prefered_lft == 0)
@@ -2996,6 +2943,8 @@ static int inet6_addr_modify(struct inet6_ifaddr *ifp, u8 ifa_flags,
        if (!(ifp->flags&IFA_F_TENTATIVE))
                ipv6_ifa_notify(0, ifp);
 
+       addrconf_prefix_route(&ifp->addr, ifp->prefix_len, ifp->idev->dev,
+                             jiffies_to_clock_t(valid_lft * HZ), flags);
        addrconf_verify(0);
 
        return 0;
@@ -3374,7 +3323,7 @@ errout:
                rtnl_set_sk_err(RTNLGRP_IPV6_IFADDR, err);
 }
 
-static void inline ipv6_store_devconf(struct ipv6_devconf *cnf,
+static inline void ipv6_store_devconf(struct ipv6_devconf *cnf,
                                __s32 *array, int bytes)
 {
        BUG_ON(bytes < (DEVCONF_MAX * 4));
@@ -3409,6 +3358,7 @@ static void inline ipv6_store_devconf(struct ipv6_devconf *cnf,
 #endif
 #endif
        array[DEVCONF_PROXY_NDP] = cnf->proxy_ndp;
+       array[DEVCONF_ACCEPT_SOURCE_ROUTE] = cnf->accept_source_route;
 }
 
 static inline size_t inet6_if_nlmsg_size(void)
@@ -3936,6 +3886,14 @@ static struct addrconf_sysctl_table
                        .mode           =       0644,
                        .proc_handler   =       &proc_dointvec,
                },
+               {
+                       .ctl_name       =       NET_IPV6_ACCEPT_SOURCE_ROUTE,
+                       .procname       =       "accept_source_route",
+                       .data           =       &ipv6_devconf.accept_source_route,
+                       .maxlen         =       sizeof(int),
+                       .mode           =       0644,
+                       .proc_handler   =       &proc_dointvec,
+               },
                {
                        .ctl_name       =       0,      /* sentinel */
                }