vserver 1.9.3
[linux-2.6.git] / net / ipv6 / anycast.c
index c966d06..a0de548 100644 (file)
@@ -202,7 +202,7 @@ int ipv6_sock_ac_drop(struct sock *sk, int ifindex, struct in6_addr *addr)
        struct ipv6_ac_socklist *pac, *prev_pac;
 
        write_lock_bh(&ipv6_sk_ac_lock);
-       prev_pac = 0;
+       prev_pac = NULL;
        for (pac = np->ipv6_ac_list; pac; pac = pac->acl_next) {
                if ((ifindex == 0 || pac->acl_ifindex == ifindex) &&
                     ipv6_addr_cmp(&pac->acl_addr, addr) == 0)
@@ -232,13 +232,13 @@ int ipv6_sock_ac_drop(struct sock *sk, int ifindex, struct in6_addr *addr)
 void ipv6_sock_ac_close(struct sock *sk)
 {
        struct ipv6_pinfo *np = inet6_sk(sk);
-       struct net_device *dev = 0;
+       struct net_device *dev = NULL;
        struct ipv6_ac_socklist *pac;
        int     prev_index;
 
        write_lock_bh(&ipv6_sk_ac_lock);
        pac = np->ipv6_ac_list;
-       np->ipv6_ac_list = 0;
+       np->ipv6_ac_list = NULL;
        write_unlock_bh(&ipv6_sk_ac_lock);
 
        prev_index = 0;
@@ -293,6 +293,7 @@ static void aca_put(struct ifacaddr6 *ac)
 {
        if (atomic_dec_and_test(&ac->aca_refcnt)) {
                in6_dev_put(ac->aca_idev);
+               dst_release(&ac->aca_rt->u.dst);
                kfree(ac);
        }
 }
@@ -304,6 +305,8 @@ int ipv6_dev_ac_inc(struct net_device *dev, struct in6_addr *addr)
 {
        struct ifacaddr6 *aca;
        struct inet6_dev *idev;
+       struct rt6_info *rt;
+       int err;
 
        idev = in6_dev_get(dev);
 
@@ -312,17 +315,15 @@ int ipv6_dev_ac_inc(struct net_device *dev, struct in6_addr *addr)
 
        write_lock_bh(&idev->lock);
        if (idev->dead) {
-               write_unlock_bh(&idev->lock);
-               in6_dev_put(idev);
-               return -ENODEV;
+               err = -ENODEV;
+               goto out;
        }
 
        for (aca = idev->ac_list; aca; aca = aca->aca_next) {
                if (ipv6_addr_cmp(&aca->aca_addr, addr) == 0) {
                        aca->aca_users++;
-                       write_unlock_bh(&idev->lock);
-                       in6_dev_put(idev);
-                       return 0;
+                       err = 0;
+                       goto out;
                }
        }
 
@@ -333,15 +334,22 @@ int ipv6_dev_ac_inc(struct net_device *dev, struct in6_addr *addr)
        aca = kmalloc(sizeof(struct ifacaddr6), GFP_ATOMIC);
 
        if (aca == NULL) {
-               write_unlock_bh(&idev->lock);
-               in6_dev_put(idev);
-               return -ENOMEM;
+               err = -ENOMEM;
+               goto out;
+       }
+
+       rt = addrconf_dst_alloc(idev, addr, 1);
+       if (IS_ERR(rt)) {
+               kfree(aca);
+               err = PTR_ERR(rt);
+               goto out;
        }
 
        memset(aca, 0, sizeof(struct ifacaddr6));
 
        ipv6_addr_copy(&aca->aca_addr, addr);
        aca->aca_idev = idev;
+       aca->aca_rt = rt;
        aca->aca_users = 1;
        /* aca_tstamp should be updated upon changes */
        aca->aca_cstamp = aca->aca_tstamp = jiffies;
@@ -352,28 +360,29 @@ int ipv6_dev_ac_inc(struct net_device *dev, struct in6_addr *addr)
        idev->ac_list = aca;
        write_unlock_bh(&idev->lock);
 
-       ip6_rt_addr_add(&aca->aca_addr, dev, 1);
+       dst_hold(&rt->u.dst);
+       if (ip6_ins_rt(rt, NULL, NULL))
+               dst_release(&rt->u.dst);
 
        addrconf_join_solict(dev, &aca->aca_addr);
 
        aca_put(aca);
        return 0;
+out:
+       write_unlock_bh(&idev->lock);
+       in6_dev_put(idev);
+       return err;
 }
 
 /*
  *     device anycast group decrement
  */
-int ipv6_dev_ac_dec(struct net_device *dev, struct in6_addr *addr)
+int __ipv6_dev_ac_dec(struct inet6_dev *idev, struct in6_addr *addr)
 {
-       struct inet6_dev *idev;
        struct ifacaddr6 *aca, *prev_aca;
 
-       idev = in6_dev_get(dev);
-       if (idev == NULL)
-               return -ENODEV;
-
        write_lock_bh(&idev->lock);
-       prev_aca = 0;
+       prev_aca = NULL;
        for (aca = idev->ac_list; aca; aca = aca->aca_next) {
                if (ipv6_addr_cmp(&aca->aca_addr, addr) == 0)
                        break;
@@ -381,12 +390,10 @@ int ipv6_dev_ac_dec(struct net_device *dev, struct in6_addr *addr)
        }
        if (!aca) {
                write_unlock_bh(&idev->lock);
-               in6_dev_put(idev);
                return -ENOENT;
        }
        if (--aca->aca_users > 0) {
                write_unlock_bh(&idev->lock);
-               in6_dev_put(idev);
                return 0;
        }
        if (prev_aca)
@@ -394,15 +401,29 @@ int ipv6_dev_ac_dec(struct net_device *dev, struct in6_addr *addr)
        else
                idev->ac_list = aca->aca_next;
        write_unlock_bh(&idev->lock);
-       addrconf_leave_solict(dev, &aca->aca_addr);
+       addrconf_leave_solict(idev, &aca->aca_addr);
 
-       ip6_rt_addr_del(&aca->aca_addr, dev);
+       dst_hold(&aca->aca_rt->u.dst);
+       if (ip6_del_rt(aca->aca_rt, NULL, NULL))
+               dst_free(&aca->aca_rt->u.dst);
+       else
+               dst_release(&aca->aca_rt->u.dst);
 
        aca_put(aca);
-       in6_dev_put(idev);
        return 0;
 }
 
+int ipv6_dev_ac_dec(struct net_device *dev, struct in6_addr *addr)
+{
+       int ret;
+       struct inet6_dev *idev = in6_dev_get(dev);
+       if (idev == NULL)
+               return -ENODEV;
+       ret = __ipv6_dev_ac_dec(idev, addr);
+       in6_dev_put(idev);
+       return ret;
+}
+       
 /*
  *     check if the interface has this anycast address
  */