]> err.no Git - linux-2.6/blobdiff - net/ipv6/addrconf.c
[RAW]: Introduce raw_hashinfo structure
[linux-2.6] / net / ipv6 / addrconf.c
index 1bd8d818f8e9ec1b28b3ae74eae6d78975d03020..6c8b193474ba500b2f0a5a62d2e9d2d590c82e17 100644 (file)
@@ -366,9 +366,7 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev)
        in6_dev_hold(ndev);
 
 #ifdef CONFIG_IPV6_PRIVACY
-       init_timer(&ndev->regen_timer);
-       ndev->regen_timer.function = ipv6_regen_rndid;
-       ndev->regen_timer.data = (unsigned long) ndev;
+       setup_timer(&ndev->regen_timer, ipv6_regen_rndid, (unsigned long)ndev);
        if ((dev->flags&IFF_LOOPBACK) ||
            dev->type == ARPHRD_TUNNEL ||
 #if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE)
@@ -876,35 +874,6 @@ static inline int ipv6_saddr_preferred(int type)
        return 0;
 }
 
-/* static matching label */
-static inline int ipv6_saddr_label(const struct in6_addr *addr, int type)
-{
- /*
-  *    prefix (longest match)  label
-  *    -----------------------------
-  *    ::1/128                 0
-  *    ::/0                    1
-  *    2002::/16               2
-  *    ::/96                   3
-  *    ::ffff:0:0/96           4
-  *    fc00::/7                5
-  *    2001::/32               6
-  */
-       if (type & IPV6_ADDR_LOOPBACK)
-               return 0;
-       else if (type & IPV6_ADDR_COMPATv4)
-               return 3;
-       else if (type & IPV6_ADDR_MAPPED)
-               return 4;
-       else if (addr->s6_addr32[0] == htonl(0x20010000))
-               return 6;
-       else if (addr->s6_addr16[0] == htons(0x2002))
-               return 2;
-       else if ((addr->s6_addr[0] & 0xfe) == 0xfc)
-               return 5;
-       return 1;
-}
-
 int ipv6_dev_get_saddr(struct net_device *daddr_dev,
                       struct in6_addr *daddr, struct in6_addr *saddr)
 {
@@ -912,7 +881,8 @@ int ipv6_dev_get_saddr(struct net_device *daddr_dev,
        struct inet6_ifaddr *ifa_result = NULL;
        int daddr_type = __ipv6_addr_type(daddr);
        int daddr_scope = __ipv6_addr_src_scope(daddr_type);
-       u32 daddr_label = ipv6_saddr_label(daddr, daddr_type);
+       int daddr_ifindex = daddr_dev ? daddr_dev->ifindex : 0;
+       u32 daddr_label = ipv6_addr_label(daddr, daddr_type, daddr_ifindex);
        struct net_device *dev;
 
        memset(&hiscore, 0, sizeof(hiscore));
@@ -967,7 +937,7 @@ int ipv6_dev_get_saddr(struct net_device *daddr_dev,
                        if (unlikely(score.addr_type == IPV6_ADDR_ANY ||
                                     score.addr_type & IPV6_ADDR_MULTICAST)) {
                                LIMIT_NETDEBUG(KERN_DEBUG
-                                              "ADDRCONF: unspecified / multicast address"
+                                              "ADDRCONF: unspecified / multicast address "
                                               "assigned as unicast address on %s",
                                               dev->name);
                                continue;
@@ -1085,11 +1055,15 @@ int ipv6_dev_get_saddr(struct net_device *daddr_dev,
 
                        /* Rule 6: Prefer matching label */
                        if (hiscore.rule < 6) {
-                               if (ipv6_saddr_label(&ifa_result->addr, hiscore.addr_type) == daddr_label)
+                               if (ipv6_addr_label(&ifa_result->addr,
+                                                   hiscore.addr_type,
+                                                   ifa_result->idev->dev->ifindex) == daddr_label)
                                        hiscore.attrs |= IPV6_SADDR_SCORE_LABEL;
                                hiscore.rule++;
                        }
-                       if (ipv6_saddr_label(&ifa->addr, score.addr_type) == daddr_label) {
+                       if (ipv6_addr_label(&ifa->addr,
+                                           score.addr_type,
+                                           ifa->idev->dev->ifindex) == daddr_label) {
                                score.attrs |= IPV6_SADDR_SCORE_LABEL;
                                if (!(hiscore.attrs & IPV6_SADDR_SCORE_LABEL)) {
                                        score.rule = 6;
@@ -2293,6 +2267,9 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,
                                break;
                        }
 
+                       if (!idev && dev->mtu >= IPV6_MIN_MTU)
+                               idev = ipv6_add_dev(dev);
+
                        if (idev)
                                idev->if_flags |= IF_READY;
                } else {
@@ -2357,12 +2334,18 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,
                break;
 
        case NETDEV_CHANGEMTU:
-               if ( idev && dev->mtu >= IPV6_MIN_MTU) {
+               if (idev && dev->mtu >= IPV6_MIN_MTU) {
                        rt6_mtu_change(dev, dev->mtu);
                        idev->cnf.mtu6 = dev->mtu;
                        break;
                }
 
+               if (!idev && dev->mtu >= IPV6_MIN_MTU) {
+                       idev = ipv6_add_dev(dev);
+                       if (idev)
+                               break;
+               }
+
                /* MTU falled under IPV6_MIN_MTU. Stop IPv6 on this interface. */
 
        case NETDEV_DOWN:
@@ -2988,11 +2971,15 @@ static const struct nla_policy ifa_ipv6_policy[IFA_MAX+1] = {
 static int
 inet6_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 {
+       struct net *net = skb->sk->sk_net;
        struct ifaddrmsg *ifm;
        struct nlattr *tb[IFA_MAX+1];
        struct in6_addr *pfx;
        int err;
 
+       if (net != &init_net)
+               return -EINVAL;
+
        err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv6_policy);
        if (err < 0)
                return err;
@@ -3045,6 +3032,7 @@ static int inet6_addr_modify(struct inet6_ifaddr *ifp, u8 ifa_flags,
 static int
 inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 {
+       struct net *net = skb->sk->sk_net;
        struct ifaddrmsg *ifm;
        struct nlattr *tb[IFA_MAX+1];
        struct in6_addr *pfx;
@@ -3054,6 +3042,9 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
        u8 ifa_flags;
        int err;
 
+       if (net != &init_net)
+               return -EINVAL;
+
        err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv6_policy);
        if (err < 0)
                return err;
@@ -3327,26 +3318,42 @@ done:
 
 static int inet6_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
 {
+       struct net *net = skb->sk->sk_net;
        enum addr_type_t type = UNICAST_ADDR;
+
+       if (net != &init_net)
+               return 0;
+
        return inet6_dump_addr(skb, cb, type);
 }
 
 static int inet6_dump_ifmcaddr(struct sk_buff *skb, struct netlink_callback *cb)
 {
+       struct net *net = skb->sk->sk_net;
        enum addr_type_t type = MULTICAST_ADDR;
+
+       if (net != &init_net)
+               return 0;
+
        return inet6_dump_addr(skb, cb, type);
 }
 
 
 static int inet6_dump_ifacaddr(struct sk_buff *skb, struct netlink_callback *cb)
 {
+       struct net *net = skb->sk->sk_net;
        enum addr_type_t type = ANYCAST_ADDR;
+
+       if (net != &init_net)
+               return 0;
+
        return inet6_dump_addr(skb, cb, type);
 }
 
 static int inet6_rtm_getaddr(struct sk_buff *in_skb, struct nlmsghdr* nlh,
                             void *arg)
 {
+       struct net *net = in_skb->sk->sk_net;
        struct ifaddrmsg *ifm;
        struct nlattr *tb[IFA_MAX+1];
        struct in6_addr *addr = NULL;
@@ -3355,6 +3362,9 @@ static int inet6_rtm_getaddr(struct sk_buff *in_skb, struct nlmsghdr* nlh,
        struct sk_buff *skb;
        int err;
 
+       if (net != &init_net)
+               return -EINVAL;
+
        err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv6_policy);
        if (err < 0)
                goto errout;
@@ -3387,7 +3397,7 @@ static int inet6_rtm_getaddr(struct sk_buff *in_skb, struct nlmsghdr* nlh,
                kfree_skb(skb);
                goto errout_ifa;
        }
-       err = rtnl_unicast(skb, NETLINK_CB(in_skb).pid);
+       err = rtnl_unicast(skb, &init_net, NETLINK_CB(in_skb).pid);
 errout_ifa:
        in6_ifa_put(ifa);
 errout:
@@ -3410,10 +3420,10 @@ static void inet6_ifa_notify(int event, struct inet6_ifaddr *ifa)
                kfree_skb(skb);
                goto errout;
        }
-       err = rtnl_notify(skb, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC);
+       err = rtnl_notify(skb, &init_net, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC);
 errout:
        if (err < 0)
-               rtnl_set_sk_err(RTNLGRP_IPV6_IFADDR, err);
+               rtnl_set_sk_err(&init_net, RTNLGRP_IPV6_IFADDR, err);
 }
 
 static inline void ipv6_store_devconf(struct ipv6_devconf *cnf,
@@ -3572,11 +3582,15 @@ nla_put_failure:
 
 static int inet6_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
 {
+       struct net *net = skb->sk->sk_net;
        int idx, err;
        int s_idx = cb->args[0];
        struct net_device *dev;
        struct inet6_dev *idev;
 
+       if (net != &init_net)
+               return 0;
+
        read_lock(&dev_base_lock);
        idx = 0;
        for_each_netdev(&init_net, dev) {
@@ -3614,10 +3628,10 @@ void inet6_ifinfo_notify(int event, struct inet6_dev *idev)
                kfree_skb(skb);
                goto errout;
        }
-       err = rtnl_notify(skb, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC);
+       err = rtnl_notify(skb, &init_net, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC);
 errout:
        if (err < 0)
-               rtnl_set_sk_err(RTNLGRP_IPV6_IFADDR, err);
+               rtnl_set_sk_err(&init_net, RTNLGRP_IPV6_IFADDR, err);
 }
 
 static inline size_t inet6_prefix_nlmsg_size(void)
@@ -3683,10 +3697,10 @@ static void inet6_prefix_notify(int event, struct inet6_dev *idev,
                kfree_skb(skb);
                goto errout;
        }
-       err = rtnl_notify(skb, 0, RTNLGRP_IPV6_PREFIX, NULL, GFP_ATOMIC);
+       err = rtnl_notify(skb, &init_net, 0, RTNLGRP_IPV6_PREFIX, NULL, GFP_ATOMIC);
 errout:
        if (err < 0)
-               rtnl_set_sk_err(RTNLGRP_IPV6_PREFIX, err);
+               rtnl_set_sk_err(&init_net, RTNLGRP_IPV6_PREFIX, err);
 }
 
 static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
@@ -4176,7 +4190,13 @@ EXPORT_SYMBOL(unregister_inet6addr_notifier);
 
 int __init addrconf_init(void)
 {
-       int err = 0;
+       int err;
+
+       if ((err = ipv6_addr_label_init()) < 0) {
+               printk(KERN_CRIT "IPv6 Addrconf: cannot initialize default policy table: %d.\n",
+                       err);
+               return err;
+       }
 
        /* The addrconf netdev notifier requires that loopback_dev
         * has it's ipv6 private information allocated and setup
@@ -4227,6 +4247,8 @@ int __init addrconf_init(void)
        __rtnl_register(PF_INET6, RTM_GETMULTICAST, NULL, inet6_dump_ifmcaddr);
        __rtnl_register(PF_INET6, RTM_GETANYCAST, NULL, inet6_dump_ifacaddr);
 
+       ipv6_addr_label_rtnl_register();
+
 #ifdef CONFIG_SYSCTL
        addrconf_sysctl.sysctl_header =
                register_sysctl_table(addrconf_sysctl.addrconf_root_dir);