linux 2.6.16.38 w/ vs2.0.3-rc1
[linux-2.6.git] / net / ipv6 / addrconf.c
index 5c1b33f..c5b8b7a 100644 (file)
@@ -40,6 +40,7 @@
  *                                             status etc.
  */
 
+#include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/types.h>
 #include <linux/socket.h>
@@ -77,6 +78,8 @@
 
 #ifdef CONFIG_IPV6_PRIVACY
 #include <linux/random.h>
+#include <linux/crypto.h>
+#include <linux/scatterlist.h>
 #endif
 
 #include <asm/uaccess.h>
@@ -107,6 +110,8 @@ static int __ipv6_try_regen_rndid(struct inet6_dev *idev, struct in6_addr *tmpad
 static void ipv6_regen_rndid(unsigned long data);
 
 static int desync_factor = MAX_DESYNC_FACTOR * HZ;
+static struct crypto_tfm *md5_tfm;
+static DEFINE_SPINLOCK(md5_tfm_lock);
 #endif
 
 static int ipv6_count_addresses(struct inet6_dev *idev);
@@ -142,7 +147,7 @@ static void inet6_prefix_notify(int event, struct inet6_dev *idev,
                                struct prefix_info *pinfo);
 static int ipv6_chk_same_addr(const struct in6_addr *addr, struct net_device *dev);
 
-static ATOMIC_NOTIFIER_HEAD(inet6addr_chain);
+static struct notifier_block *inet6addr_chain;
 
 struct ipv6_devconf ipv6_devconf = {
        .forwarding             = 0,
@@ -164,15 +169,6 @@ struct ipv6_devconf ipv6_devconf = {
        .max_desync_factor      = MAX_DESYNC_FACTOR,
 #endif
        .max_addresses          = IPV6_MAX_ADDRESSES,
-       .accept_ra_defrtr       = 1,
-       .accept_ra_pinfo        = 1,
-#ifdef CONFIG_IPV6_ROUTER_PREF
-       .accept_ra_rtr_pref     = 1,
-       .rtr_probe_interval     = 60 * HZ,
-#ifdef CONFIG_IPV6_ROUTE_INFO
-       .accept_ra_rt_info_max_plen = 0,
-#endif
-#endif
 };
 
 static struct ipv6_devconf ipv6_devconf_dflt = {
@@ -194,15 +190,6 @@ static struct ipv6_devconf ipv6_devconf_dflt = {
        .max_desync_factor      = MAX_DESYNC_FACTOR,
 #endif
        .max_addresses          = IPV6_MAX_ADDRESSES,
-       .accept_ra_defrtr       = 1,
-       .accept_ra_pinfo        = 1,
-#ifdef CONFIG_IPV6_ROUTER_PREF
-       .accept_ra_rtr_pref     = 1,
-       .rtr_probe_interval     = 60 * HZ,
-#ifdef CONFIG_IPV6_ROUTE_INFO
-       .accept_ra_rt_info_max_plen = 0,
-#endif
-#endif
 };
 
 /* IPv6 Wildcard Address and Loopback Address defined by RFC2553 */
@@ -334,89 +321,96 @@ void in6_dev_finish_destroy(struct inet6_dev *idev)
 static struct inet6_dev * ipv6_add_dev(struct net_device *dev)
 {
        struct inet6_dev *ndev;
+       struct in6_addr maddr;
 
        ASSERT_RTNL();
 
        if (dev->mtu < IPV6_MIN_MTU)
                return NULL;
 
-       ndev = kzalloc(sizeof(struct inet6_dev), GFP_KERNEL);
+       ndev = kmalloc(sizeof(struct inet6_dev), GFP_KERNEL);
 
-       if (ndev == NULL)
-               return NULL;
+       if (ndev) {
+               memset(ndev, 0, sizeof(struct inet6_dev));
 
-       rwlock_init(&ndev->lock);
-       ndev->dev = dev;
-       memcpy(&ndev->cnf, &ipv6_devconf_dflt, sizeof(ndev->cnf));
-       ndev->cnf.mtu6 = dev->mtu;
-       ndev->cnf.sysctl = NULL;
-       ndev->nd_parms = neigh_parms_alloc(dev, &nd_tbl);
-       if (ndev->nd_parms == NULL) {
-               kfree(ndev);
-               return NULL;
-       }
-       /* We refer to the device */
-       dev_hold(dev);
-
-       if (snmp6_alloc_dev(ndev) < 0) {
-               ADBG((KERN_WARNING
-                       "%s(): cannot allocate memory for statistics; dev=%s.\n",
-                       __FUNCTION__, dev->name));
-               neigh_parms_release(&nd_tbl, ndev->nd_parms);
-               ndev->dead = 1;
-               in6_dev_finish_destroy(ndev);
-               return NULL;
-       }
+               rwlock_init(&ndev->lock);
+               ndev->dev = dev;
+               memcpy(&ndev->cnf, &ipv6_devconf_dflt, sizeof(ndev->cnf));
+               ndev->cnf.mtu6 = dev->mtu;
+               ndev->cnf.sysctl = NULL;
+               ndev->nd_parms = neigh_parms_alloc(dev, &nd_tbl);
+               if (ndev->nd_parms == NULL) {
+                       kfree(ndev);
+                       return NULL;
+               }
+               /* We refer to the device */
+               dev_hold(dev);
+
+               if (snmp6_alloc_dev(ndev) < 0) {
+                       ADBG((KERN_WARNING
+                               "%s(): cannot allocate memory for statistics; dev=%s.\n",
+                               __FUNCTION__, dev->name));
+                       neigh_parms_release(&nd_tbl, ndev->nd_parms);
+                       ndev->dead = 1;
+                       in6_dev_finish_destroy(ndev);
+                       return NULL;
+               }
 
-       if (snmp6_register_dev(ndev) < 0) {
-               ADBG((KERN_WARNING
-                       "%s(): cannot create /proc/net/dev_snmp6/%s\n",
-                       __FUNCTION__, dev->name));
-               neigh_parms_release(&nd_tbl, ndev->nd_parms);
-               ndev->dead = 1;
-               in6_dev_finish_destroy(ndev);
-               return NULL;
-       }
+               if (snmp6_register_dev(ndev) < 0) {
+                       ADBG((KERN_WARNING
+                               "%s(): cannot create /proc/net/dev_snmp6/%s\n",
+                               __FUNCTION__, dev->name));
+                       neigh_parms_release(&nd_tbl, ndev->nd_parms);
+                       ndev->dead = 1;
+                       in6_dev_finish_destroy(ndev);
+                       return NULL;
+               }
 
-       /* One reference from device.  We must do this before
-        * we invoke __ipv6_regen_rndid().
-        */
-       in6_dev_hold(ndev);
+               /* One reference from device.  We must do this before
+                * we invoke __ipv6_regen_rndid().
+                */
+               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;
-       if ((dev->flags&IFF_LOOPBACK) ||
-           dev->type == ARPHRD_TUNNEL ||
-           dev->type == ARPHRD_NONE ||
-           dev->type == ARPHRD_SIT) {
-               printk(KERN_INFO
-                      "%s: Disabled Privacy Extensions\n",
-                      dev->name);
-               ndev->cnf.use_tempaddr = -1;
-       } else {
-               in6_dev_hold(ndev);
-               ipv6_regen_rndid((unsigned long) ndev);
-       }
+               get_random_bytes(ndev->rndid, sizeof(ndev->rndid));
+               get_random_bytes(ndev->entropy, sizeof(ndev->entropy));
+               init_timer(&ndev->regen_timer);
+               ndev->regen_timer.function = ipv6_regen_rndid;
+               ndev->regen_timer.data = (unsigned long) ndev;
+               if ((dev->flags&IFF_LOOPBACK) ||
+                   dev->type == ARPHRD_TUNNEL ||
+                   dev->type == ARPHRD_NONE ||
+                   dev->type == ARPHRD_SIT) {
+                       printk(KERN_INFO
+                              "%s: Disabled Privacy Extensions\n",
+                              dev->name);
+                       ndev->cnf.use_tempaddr = -1;
+               } else {
+                       in6_dev_hold(ndev);
+                       ipv6_regen_rndid((unsigned long) ndev);
+               }
 #endif
 
-       if (netif_carrier_ok(dev))
-               ndev->if_flags |= IF_READY;
-
-       write_lock_bh(&addrconf_lock);
-       dev->ip6_ptr = ndev;
-       write_unlock_bh(&addrconf_lock);
+               if (netif_carrier_ok(dev))
+                       ndev->if_flags |= IF_READY;
 
-       ipv6_mc_init_dev(ndev);
-       ndev->tstamp = jiffies;
+               ipv6_mc_init_dev(ndev);
+               ndev->tstamp = jiffies;
 #ifdef CONFIG_SYSCTL
-       neigh_sysctl_register(dev, ndev->nd_parms, NET_IPV6,
-                             NET_IPV6_NEIGH, "ipv6",
-                             &ndisc_ifinfo_sysctl_change,
-                             NULL);
-       addrconf_sysctl_register(ndev, &ndev->cnf);
+               neigh_sysctl_register(dev, ndev->nd_parms, NET_IPV6, 
+                                     NET_IPV6_NEIGH, "ipv6",
+                                     &ndisc_ifinfo_sysctl_change,
+                                     NULL);
+               addrconf_sysctl_register(ndev, &ndev->cnf);
 #endif
+               write_lock_bh(&addrconf_lock);
+               dev->ip6_ptr = ndev;
+               write_unlock_bh(&addrconf_lock);
+
+               /* Join all-node multicast group */
+               ipv6_addr_all_nodes(&maddr);
+               ipv6_dev_mc_inc(dev, &maddr);
+       }
        return ndev;
 }
 
@@ -508,26 +502,6 @@ void inet6_ifa_finish_destroy(struct inet6_ifaddr *ifp)
        kfree(ifp);
 }
 
-static void
-ipv6_link_dev_addr(struct inet6_dev *idev, struct inet6_ifaddr *ifp)
-{
-       struct inet6_ifaddr *ifa, **ifap;
-       int ifp_scope = ipv6_addr_src_scope(&ifp->addr);
-
-       /*
-        * Each device address list is sorted in order of scope -
-        * global before linklocal.
-        */
-       for (ifap = &idev->addr_list; (ifa = *ifap) != NULL;
-            ifap = &ifa->if_next) {
-               if (ifp_scope >= ipv6_addr_src_scope(&ifa->addr))
-                       break;
-       }
-
-       ifp->if_next = *ifap;
-       *ifap = ifp;
-}
-
 /* On success it returns ifp with increased reference count */
 
 static struct inet6_ifaddr *
@@ -554,7 +528,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
                goto out;
        }
 
-       ifa = kzalloc(sizeof(struct inet6_ifaddr), GFP_ATOMIC);
+       ifa = kmalloc(sizeof(struct inet6_ifaddr), GFP_ATOMIC);
 
        if (ifa == NULL) {
                ADBG(("ipv6_add_addr: malloc failed\n"));
@@ -568,6 +542,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
                goto out;
        }
 
+       memset(ifa, 0, sizeof(struct inet6_ifaddr));
        ipv6_addr_copy(&ifa->addr, addr);
 
        spin_lock_init(&ifa->lock);
@@ -578,8 +553,6 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
        ifa->flags = flags | IFA_F_TENTATIVE;
        ifa->cstamp = ifa->tstamp = jiffies;
 
-       ifa->rt = rt;
-
        ifa->idev = idev;
        in6_dev_hold(idev);
        /* For caller */
@@ -595,7 +568,8 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
 
        write_lock(&idev->lock);
        /* Add to inet6_dev unicast addr list. */
-       ipv6_link_dev_addr(idev, ifa);
+       ifa->if_next = idev->addr_list;
+       idev->addr_list = ifa;
 
 #ifdef CONFIG_IPV6_PRIVACY
        if (ifa->flags&IFA_F_TEMPORARY) {
@@ -605,13 +579,15 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
        }
 #endif
 
+       ifa->rt = rt;
+
        in6_ifa_hold(ifa);
        write_unlock(&idev->lock);
 out2:
        read_unlock_bh(&addrconf_lock);
 
        if (likely(err == 0))
-               atomic_notifier_call_chain(&inet6addr_chain, NETDEV_UP, ifa);
+               notifier_call_chain(&inet6addr_chain, NETDEV_UP, ifa);
        else {
                kfree(ifa);
                ifa = ERR_PTR(err);
@@ -706,7 +682,7 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)
 
        ipv6_ifa_notify(RTM_DELADDR, ifp);
 
-       atomic_notifier_call_chain(&inet6addr_chain, NETDEV_DOWN, ifp);
+       notifier_call_chain(&inet6addr_chain,NETDEV_DOWN,ifp);
 
        addrconf_del_timer(ifp);
 
@@ -1006,7 +982,7 @@ int ipv6_dev_get_saddr(struct net_device *daddr_dev,
                                        continue;
                        } else if (score.scope < hiscore.scope) {
                                if (score.scope < daddr_scope)
-                                       break; /* addresses sorted by scope */
+                                       continue;
                                else {
                                        score.rule = 2;
                                        goto record_it;
@@ -1342,67 +1318,52 @@ static void addrconf_leave_anycast(struct inet6_ifaddr *ifp)
        __ipv6_dev_ac_dec(ifp->idev, &addr);
 }
 
-static int addrconf_ifid_eui48(u8 *eui, struct net_device *dev)
-{
-       if (dev->addr_len != ETH_ALEN)
-               return -1;
-       memcpy(eui, dev->dev_addr, 3);
-       memcpy(eui + 5, dev->dev_addr + 3, 3);
-
-       /*
-        * The zSeries OSA network cards can be shared among various
-        * OS instances, but the OSA cards have only one MAC address.
-        * This leads to duplicate address conflicts in conjunction
-        * with IPv6 if more than one instance uses the same card.
-        *
-        * The driver for these cards can deliver a unique 16-bit
-        * identifier for each instance sharing the same card.  It is
-        * placed instead of 0xFFFE in the interface identifier.  The
-        * "u" bit of the interface identifier is not inverted in this
-        * case.  Hence the resulting interface identifier has local
-        * scope according to RFC2373.
-        */
-       if (dev->dev_id) {
-               eui[3] = (dev->dev_id >> 8) & 0xFF;
-               eui[4] = dev->dev_id & 0xFF;
-       } else {
-               eui[3] = 0xFF;
-               eui[4] = 0xFE;
-               eui[0] ^= 2;
-       }
-       return 0;
-}
-
-static int addrconf_ifid_arcnet(u8 *eui, struct net_device *dev)
-{
-       /* XXX: inherit EUI-64 from other interface -- yoshfuji */
-       if (dev->addr_len != ARCNET_ALEN)
-               return -1;
-       memset(eui, 0, 7);
-       eui[7] = *(u8*)dev->dev_addr;
-       return 0;
-}
-
-static int addrconf_ifid_infiniband(u8 *eui, struct net_device *dev)
-{
-       if (dev->addr_len != INFINIBAND_ALEN)
-               return -1;
-       memcpy(eui, dev->dev_addr + 12, 8);
-       eui[0] |= 2;
-       return 0;
-}
-
 static int ipv6_generate_eui64(u8 *eui, struct net_device *dev)
 {
        switch (dev->type) {
        case ARPHRD_ETHER:
        case ARPHRD_FDDI:
        case ARPHRD_IEEE802_TR:
-               return addrconf_ifid_eui48(eui, dev);
+               if (dev->addr_len != ETH_ALEN)
+                       return -1;
+               memcpy(eui, dev->dev_addr, 3);
+               memcpy(eui + 5, dev->dev_addr + 3, 3);
+
+               /*
+                * The zSeries OSA network cards can be shared among various
+                * OS instances, but the OSA cards have only one MAC address.
+                * This leads to duplicate address conflicts in conjunction
+                * with IPv6 if more than one instance uses the same card.
+                * 
+                * The driver for these cards can deliver a unique 16-bit
+                * identifier for each instance sharing the same card.  It is
+                * placed instead of 0xFFFE in the interface identifier.  The
+                * "u" bit of the interface identifier is not inverted in this
+                * case.  Hence the resulting interface identifier has local
+                * scope according to RFC2373.
+                */
+               if (dev->dev_id) {
+                       eui[3] = (dev->dev_id >> 8) & 0xFF;
+                       eui[4] = dev->dev_id & 0xFF;
+               } else {
+                       eui[3] = 0xFF;
+                       eui[4] = 0xFE;
+                       eui[0] ^= 2;
+               }
+               return 0;
        case ARPHRD_ARCNET:
-               return addrconf_ifid_arcnet(eui, dev);
+               /* XXX: inherit EUI-64 from other interface -- yoshfuji */
+               if (dev->addr_len != ARCNET_ALEN)
+                       return -1;
+               memset(eui, 0, 7);
+               eui[7] = *(u8*)dev->dev_addr;
+               return 0;
        case ARPHRD_INFINIBAND:
-               return addrconf_ifid_infiniband(eui, dev);
+               if (dev->addr_len != INFINIBAND_ALEN)
+                       return -1;
+               memcpy(eui, dev->dev_addr + 12, 8);
+               eui[0] |= 2;
+               return 0;
        }
        return -1;
 }
@@ -1428,9 +1389,34 @@ static int ipv6_inherit_eui64(u8 *eui, struct inet6_dev *idev)
 /* (re)generation of randomized interface identifier (RFC 3041 3.2, 3.5) */
 static int __ipv6_regen_rndid(struct inet6_dev *idev)
 {
+       struct net_device *dev;
+       struct scatterlist sg[2];
+
+       sg_set_buf(&sg[0], idev->entropy, 8);
+       sg_set_buf(&sg[1], idev->work_eui64, 8);
+
+       dev = idev->dev;
+
+       if (ipv6_generate_eui64(idev->work_eui64, dev)) {
+               printk(KERN_INFO
+                       "__ipv6_regen_rndid(idev=%p): cannot get EUI64 identifier; use random bytes.\n",
+                       idev);
+               get_random_bytes(idev->work_eui64, sizeof(idev->work_eui64));
+       }
 regen:
-       get_random_bytes(idev->rndid, sizeof(idev->rndid));
+       spin_lock(&md5_tfm_lock);
+       if (unlikely(md5_tfm == NULL)) {
+               spin_unlock(&md5_tfm_lock);
+               return -1;
+       }
+       crypto_digest_init(md5_tfm);
+       crypto_digest_update(md5_tfm, sg, 2);
+       crypto_digest_final(md5_tfm, idev->work_digest);
+       spin_unlock(&md5_tfm_lock);
+
+       memcpy(idev->rndid, &idev->work_digest[0], 8);
        idev->rndid[0] &= ~0x02;
+       memcpy(idev->entropy, &idev->work_digest[8], 8);
 
        /*
         * <draft-ietf-ipngwg-temp-addresses-v2-00.txt>:
@@ -1869,21 +1855,15 @@ err_exit:
 /*
  *     Manual configuration of address on an interface
  */
-static int inet6_addr_add(int ifindex, struct in6_addr *pfx, int plen,
-                         __u32 prefered_lft, __u32 valid_lft)
+static int inet6_addr_add(int ifindex, struct in6_addr *pfx, int plen)
 {
        struct inet6_ifaddr *ifp;
        struct inet6_dev *idev;
        struct net_device *dev;
-       __u8 ifa_flags = 0;
        int scope;
 
        ASSERT_RTNL();
        
-       /* check the lifetime */
-       if (!valid_lft || prefered_lft > valid_lft)
-               return -EINVAL;
-
        if ((dev = __dev_get_by_index(ifindex)) == NULL)
                return -ENODEV;
        
@@ -1895,29 +1875,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)
-               ifa_flags |= IFA_F_PERMANENT;
-       else if (valid_lft >= 0x7FFFFFFF/HZ)
-               valid_lft = 0x7FFFFFFF/HZ;
-
-       if (prefered_lft == 0)
-               ifa_flags |= IFA_F_DEPRECATED;
-       else if ((prefered_lft >= 0x7FFFFFFF/HZ) &&
-                (prefered_lft != INFINITY_LIFE_TIME))
-               prefered_lft = 0x7FFFFFFF/HZ;
-
-       ifp = ipv6_add_addr(idev, pfx, plen, scope, ifa_flags);
-
+       ifp = ipv6_add_addr(idev, pfx, plen, scope, IFA_F_PERMANENT);
        if (!IS_ERR(ifp)) {
-               spin_lock_bh(&ifp->lock);
-               ifp->valid_lft = valid_lft;
-               ifp->prefered_lft = prefered_lft;
-               ifp->tstamp = jiffies;
-               spin_unlock_bh(&ifp->lock);
-
                addrconf_dad_start(ifp, 0);
                in6_ifa_put(ifp);
-               addrconf_verify(0);
                return 0;
        }
 
@@ -1970,8 +1931,7 @@ int addrconf_add_ifaddr(void __user *arg)
                return -EFAULT;
 
        rtnl_lock();
-       err = inet6_addr_add(ireq.ifr6_ifindex, &ireq.ifr6_addr, ireq.ifr6_prefixlen,
-                            INFINITY_LIFE_TIME, INFINITY_LIFE_TIME);
+       err = inet6_addr_add(ireq.ifr6_ifindex, &ireq.ifr6_addr, ireq.ifr6_prefixlen);
        rtnl_unlock();
        return err;
 }
@@ -2196,6 +2156,7 @@ static void addrconf_ip6_tnl_config(struct net_device *dev)
                return;
        }
        ip6_tnl_add_linklocal(idev);
+       addrconf_add_mroute(dev);
 }
 
 static int addrconf_notify(struct notifier_block *this, unsigned long event, 
@@ -2514,7 +2475,6 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags)
        spin_lock_bh(&ifp->lock);
 
        if (dev->flags&(IFF_NOARP|IFF_LOOPBACK) ||
-           !(dev->flags&IFF_MULTICAST) ||
            !(ifp->flags&IFA_F_TENTATIVE)) {
                ifp->flags &= ~IFA_F_TENTATIVE;
                spin_unlock_bh(&ifp->lock);
@@ -2599,7 +2559,6 @@ static void addrconf_dad_completed(struct inet6_ifaddr *ifp)
        if (ifp->idev->cnf.forwarding == 0 &&
            ifp->idev->cnf.rtr_solicits > 0 &&
            (dev->flags&IFF_LOOPBACK) == 0 &&
-           (dev->flags & IFF_MULTICAST) &&
            (ipv6_addr_type(&ifp->addr) & IPV6_ADDR_LINKLOCAL)) {
                struct in6_addr all_routers;
 
@@ -2725,10 +2684,11 @@ static int if6_seq_open(struct inode *inode, struct file *file)
 {
        struct seq_file *seq;
        int rc = -ENOMEM;
-       struct if6_iter_state *s = kzalloc(sizeof(*s), GFP_KERNEL);
+       struct if6_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL);
 
        if (!s)
                goto out;
+       memset(s, 0, sizeof(*s));
 
        rc = seq_open(file, &if6_seq_ops);
        if (rc)
@@ -2802,16 +2762,12 @@ restart:
                                        ifp->idev->nd_parms->retrans_time / HZ;
 #endif
 
-                       if (ifp->valid_lft != INFINITY_LIFE_TIME &&
-                           age >= ifp->valid_lft) {
+                       if (age >= ifp->valid_lft) {
                                spin_unlock(&ifp->lock);
                                in6_ifa_hold(ifp);
                                read_unlock(&addrconf_hash_lock);
                                ipv6_del_addr(ifp);
                                goto restart;
-                       } else if (ifp->prefered_lft == INFINITY_LIFE_TIME) {
-                               spin_unlock(&ifp->lock);
-                               continue;
                        } else if (age >= ifp->prefered_lft) {
                                /* jiffies - ifp->tsamp > age >= ifp->prefered_lft */
                                int deprecate = 0;
@@ -2888,8 +2844,7 @@ inet6_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
                pfx = RTA_DATA(rta[IFA_ADDRESS-1]);
        }
        if (rta[IFA_LOCAL-1]) {
-               if (RTA_PAYLOAD(rta[IFA_LOCAL-1]) < sizeof(*pfx) ||
-                   (pfx && memcmp(pfx, RTA_DATA(rta[IFA_LOCAL-1]), sizeof(*pfx))))
+               if (pfx && memcmp(pfx, RTA_DATA(rta[IFA_LOCAL-1]), sizeof(*pfx)))
                        return -EINVAL;
                pfx = RTA_DATA(rta[IFA_LOCAL-1]);
        }
@@ -2899,62 +2854,12 @@ inet6_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
        return inet6_addr_del(ifm->ifa_index, pfx, ifm->ifa_prefixlen);
 }
 
-static int
-inet6_addr_modify(int ifindex, struct in6_addr *pfx,
-                 __u32 prefered_lft, __u32 valid_lft)
-{
-       struct inet6_ifaddr *ifp = NULL;
-       struct net_device *dev;
-       int ifa_flags = 0;
-
-       if ((dev = __dev_get_by_index(ifindex)) == NULL)
-               return -ENODEV;
-
-       if (!(dev->flags&IFF_UP))
-               return -ENETDOWN;
-
-       if (!valid_lft || (prefered_lft > valid_lft))
-               return -EINVAL;
-
-       ifp = ipv6_get_ifaddr(pfx, dev, 1);
-       if (ifp == NULL)
-               return -ENOENT;
-
-       if (valid_lft == INFINITY_LIFE_TIME)
-               ifa_flags = IFA_F_PERMANENT;
-       else if (valid_lft >= 0x7FFFFFFF/HZ)
-               valid_lft = 0x7FFFFFFF/HZ;
-
-       if (prefered_lft == 0)
-               ifa_flags = IFA_F_DEPRECATED;
-       else if ((prefered_lft >= 0x7FFFFFFF/HZ) &&
-                (prefered_lft != INFINITY_LIFE_TIME))
-               prefered_lft = 0x7FFFFFFF/HZ;
-
-       spin_lock_bh(&ifp->lock);
-       ifp->flags = (ifp->flags & ~(IFA_F_DEPRECATED|IFA_F_PERMANENT)) | ifa_flags;
-
-       ifp->tstamp = jiffies;
-       ifp->valid_lft = valid_lft;
-       ifp->prefered_lft = prefered_lft;
-
-       spin_unlock_bh(&ifp->lock);
-       if (!(ifp->flags&IFA_F_TENTATIVE))
-               ipv6_ifa_notify(0, ifp);
-       in6_ifa_put(ifp);
-
-       addrconf_verify(0);
-
-       return 0;
-}
-
 static int
 inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 {
        struct rtattr  **rta = arg;
        struct ifaddrmsg *ifm = NLMSG_DATA(nlh);
        struct in6_addr *pfx;
-       __u32 valid_lft = INFINITY_LIFE_TIME, prefered_lft = INFINITY_LIFE_TIME;
 
        pfx = NULL;
        if (rta[IFA_ADDRESS-1]) {
@@ -2963,34 +2868,14 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
                pfx = RTA_DATA(rta[IFA_ADDRESS-1]);
        }
        if (rta[IFA_LOCAL-1]) {
-               if (RTA_PAYLOAD(rta[IFA_LOCAL-1]) < sizeof(*pfx) ||
-                   (pfx && memcmp(pfx, RTA_DATA(rta[IFA_LOCAL-1]), sizeof(*pfx))))
+               if (pfx && memcmp(pfx, RTA_DATA(rta[IFA_LOCAL-1]), sizeof(*pfx)))
                        return -EINVAL;
                pfx = RTA_DATA(rta[IFA_LOCAL-1]);
        }
        if (pfx == NULL)
                return -EINVAL;
 
-       if (rta[IFA_CACHEINFO-1]) {
-               struct ifa_cacheinfo *ci;
-               if (RTA_PAYLOAD(rta[IFA_CACHEINFO-1]) < sizeof(*ci))
-                       return -EINVAL;
-               ci = RTA_DATA(rta[IFA_CACHEINFO-1]);
-               valid_lft = ci->ifa_valid;
-               prefered_lft = ci->ifa_prefered;
-       }
-
-       if (nlh->nlmsg_flags & NLM_F_REPLACE) {
-               int ret;
-               ret = inet6_addr_modify(ifm->ifa_index, pfx,
-                                       prefered_lft, valid_lft);
-               if (ret == 0 || !(nlh->nlmsg_flags & NLM_F_CREATE))
-                       return ret;
-       }
-
-       return inet6_addr_add(ifm->ifa_index, pfx, ifm->ifa_prefixlen,
-                             prefered_lft, valid_lft);
-
+       return inet6_addr_add(ifm->ifa_index, pfx, ifm->ifa_prefixlen);
 }
 
 /* Maximum length of ifa_cacheinfo attributes */
@@ -3231,62 +3116,6 @@ static int inet6_dump_ifacaddr(struct sk_buff *skb, struct netlink_callback *cb)
        return inet6_dump_addr(skb, cb, type);
 }
 
-static int inet6_rtm_getaddr(struct sk_buff *in_skb,
-               struct nlmsghdr* nlh, void *arg)
-{
-       struct rtattr **rta = arg;
-       struct ifaddrmsg *ifm = NLMSG_DATA(nlh);
-       struct in6_addr *addr = NULL;
-       struct net_device *dev = NULL;
-       struct inet6_ifaddr *ifa;
-       struct sk_buff *skb;
-       int size = NLMSG_SPACE(sizeof(struct ifaddrmsg) + INET6_IFADDR_RTA_SPACE);
-       int err;
-
-       if (rta[IFA_ADDRESS-1]) {
-               if (RTA_PAYLOAD(rta[IFA_ADDRESS-1]) < sizeof(*addr))
-                       return -EINVAL;
-               addr = RTA_DATA(rta[IFA_ADDRESS-1]);
-       }
-       if (rta[IFA_LOCAL-1]) {
-               if (RTA_PAYLOAD(rta[IFA_LOCAL-1]) < sizeof(*addr) ||
-                   (addr && memcmp(addr, RTA_DATA(rta[IFA_LOCAL-1]), sizeof(*addr))))
-                       return -EINVAL;
-               addr = RTA_DATA(rta[IFA_LOCAL-1]);
-       }
-       if (addr == NULL)
-               return -EINVAL;
-
-       if (ifm->ifa_index)
-               dev = __dev_get_by_index(ifm->ifa_index);
-
-       if ((ifa = ipv6_get_ifaddr(addr, dev, 1)) == NULL)
-               return -EADDRNOTAVAIL;
-
-       if ((skb = alloc_skb(size, GFP_KERNEL)) == NULL) {
-               err = -ENOBUFS;
-               goto out;
-       }
-
-       NETLINK_CB(skb).dst_pid = NETLINK_CB(in_skb).pid;
-       err = inet6_fill_ifaddr(skb, ifa, NETLINK_CB(in_skb).pid,
-                               nlh->nlmsg_seq, RTM_NEWADDR, 0);
-       if (err < 0) {
-               err = -EMSGSIZE;
-               goto out_free;
-       }
-
-       err = netlink_unicast(rtnl, skb, NETLINK_CB(in_skb).pid, MSG_DONTWAIT);
-       if (err > 0)
-               err = 0;
-out:
-       in6_ifa_put(ifa);
-       return err;
-out_free:
-       kfree_skb(skb);
-       goto out;
-}
-
 static void inet6_ifa_notify(int event, struct inet6_ifaddr *ifa)
 {
        struct sk_buff *skb;
@@ -3329,15 +3158,6 @@ static void inline ipv6_store_devconf(struct ipv6_devconf *cnf,
        array[DEVCONF_MAX_DESYNC_FACTOR] = cnf->max_desync_factor;
 #endif
        array[DEVCONF_MAX_ADDRESSES] = cnf->max_addresses;
-       array[DEVCONF_ACCEPT_RA_DEFRTR] = cnf->accept_ra_defrtr;
-       array[DEVCONF_ACCEPT_RA_PINFO] = cnf->accept_ra_pinfo;
-#ifdef CONFIG_IPV6_ROUTER_PREF
-       array[DEVCONF_ACCEPT_RA_RTR_PREF] = cnf->accept_ra_rtr_pref;
-       array[DEVCONF_RTR_PROBE_INTERVAL] = cnf->rtr_probe_interval;
-#ifdef CONFIV_IPV6_ROUTE_INFO
-       array[DEVCONF_ACCEPT_RA_RT_INFO_MAX_PLEN] = cnf->accept_ra_rt_info_max_plen;
-#endif
-#endif
 }
 
 /* Maximum length of ifinfomsg attributes */
@@ -3533,8 +3353,7 @@ static struct rtnetlink_link inet6_rtnetlink_table[RTM_NR_MSGTYPES] = {
        [RTM_GETLINK - RTM_BASE] = { .dumpit    = inet6_dump_ifinfo, },
        [RTM_NEWADDR - RTM_BASE] = { .doit      = inet6_rtm_newaddr, },
        [RTM_DELADDR - RTM_BASE] = { .doit      = inet6_rtm_deladdr, },
-       [RTM_GETADDR - RTM_BASE] = { .doit      = inet6_rtm_getaddr,
-                                    .dumpit    = inet6_dump_ifaddr, },
+       [RTM_GETADDR - RTM_BASE] = { .dumpit    = inet6_dump_ifaddr, },
        [RTM_GETMULTICAST - RTM_BASE] = { .dumpit = inet6_dump_ifmcaddr, },
        [RTM_GETANYCAST - RTM_BASE] = { .dumpit = inet6_dump_ifacaddr, },
        [RTM_NEWROUTE - RTM_BASE] = { .doit     = inet6_rtm_newroute, },
@@ -3810,51 +3629,6 @@ static struct addrconf_sysctl_table
                        .mode           =       0644,
                        .proc_handler   =       &proc_dointvec,
                },
-               {
-                       .ctl_name       =       NET_IPV6_ACCEPT_RA_DEFRTR,
-                       .procname       =       "accept_ra_defrtr",
-                       .data           =       &ipv6_devconf.accept_ra_defrtr,
-                       .maxlen         =       sizeof(int),
-                       .mode           =       0644,
-                       .proc_handler   =       &proc_dointvec,
-               },
-               {
-                       .ctl_name       =       NET_IPV6_ACCEPT_RA_PINFO,
-                       .procname       =       "accept_ra_pinfo",
-                       .data           =       &ipv6_devconf.accept_ra_pinfo,
-                       .maxlen         =       sizeof(int),
-                       .mode           =       0644,
-                       .proc_handler   =       &proc_dointvec,
-               },
-#ifdef CONFIG_IPV6_ROUTER_PREF
-               {
-                       .ctl_name       =       NET_IPV6_ACCEPT_RA_RTR_PREF,
-                       .procname       =       "accept_ra_rtr_pref",
-                       .data           =       &ipv6_devconf.accept_ra_rtr_pref,
-                       .maxlen         =       sizeof(int),
-                       .mode           =       0644,
-                       .proc_handler   =       &proc_dointvec,
-               },
-               {
-                       .ctl_name       =       NET_IPV6_RTR_PROBE_INTERVAL,
-                       .procname       =       "router_probe_interval",
-                       .data           =       &ipv6_devconf.rtr_probe_interval,
-                       .maxlen         =       sizeof(int),
-                       .mode           =       0644,
-                       .proc_handler   =       &proc_dointvec_jiffies,
-                       .strategy       =       &sysctl_jiffies,
-               },
-#ifdef CONFIV_IPV6_ROUTE_INFO
-               {
-                       .ctl_name       =       NET_IPV6_ACCEPT_RA_RT_INFO_MAX_PLEN,
-                       .procname       =       "accept_ra_rt_info_max_plen",
-                       .data           =       &ipv6_devconf.accept_ra_rt_info_max_plen,
-                       .maxlen         =       sizeof(int),
-                       .mode           =       0644,
-                       .proc_handler   =       &proc_dointvec,
-               },
-#endif
-#endif
                {
                        .ctl_name       =       0,      /* sentinel */
                }
@@ -3985,12 +3759,12 @@ static void addrconf_sysctl_unregister(struct ipv6_devconf *p)
 
 int register_inet6addr_notifier(struct notifier_block *nb)
 {
-        return atomic_notifier_chain_register(&inet6addr_chain, nb);
+        return notifier_chain_register(&inet6addr_chain, nb);
 }
 
 int unregister_inet6addr_notifier(struct notifier_block *nb)
 {
-        return atomic_notifier_chain_unregister(&inet6addr_chain,nb);
+        return notifier_chain_unregister(&inet6addr_chain,nb);
 }
 
 /*
@@ -4030,6 +3804,13 @@ int __init addrconf_init(void)
 
        register_netdevice_notifier(&ipv6_dev_notf);
 
+#ifdef CONFIG_IPV6_PRIVACY
+       md5_tfm = crypto_alloc_tfm("md5", 0);
+       if (unlikely(md5_tfm == NULL))
+               printk(KERN_WARNING
+                       "failed to load transform for md5\n");
+#endif
+
        addrconf_verify(0);
        rtnetlink_links[PF_INET6] = inet6_rtnetlink_table;
 #ifdef CONFIG_SYSCTL
@@ -4092,6 +3873,11 @@ void __exit addrconf_cleanup(void)
 
        rtnl_unlock();
 
+#ifdef CONFIG_IPV6_PRIVACY
+       crypto_free_tfm(md5_tfm);
+       md5_tfm = NULL;
+#endif
+
 #ifdef CONFIG_PROC_FS
        proc_net_remove("if_inet6");
 #endif