X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=net%2Fipv6%2Faddrconf.c;fp=net%2Fipv6%2Faddrconf.c;h=c5b8b7a87006e6a134c067637203666fa27b0c0c;hb=64ba3f394c830ec48a1c31b53dcae312c56f1604;hp=5c1b33f40a5298f2a5252913804a0bc49cf6a79a;hpb=be1e6109ac94a859551f8e1774eb9a8469fe055c;p=linux-2.6.git diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 5c1b33f40..c5b8b7a87 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -40,6 +40,7 @@ * status etc. */ +#include #include #include #include @@ -77,6 +78,8 @@ #ifdef CONFIG_IPV6_PRIVACY #include +#include +#include #endif #include @@ -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); /* * : @@ -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