* status etc.
*/
+#include <linux/config.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
#ifdef CONFIG_IPV6_PRIVACY
#include <linux/random.h>
+#include <linux/crypto.h>
+#include <linux/scatterlist.h>
#endif
#include <asm/uaccess.h>
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);
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,
.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 = {
.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 */
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;
}
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 *
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"));
goto out;
}
+ memset(ifa, 0, sizeof(struct inet6_ifaddr));
ipv6_addr_copy(&ifa->addr, addr);
spin_lock_init(&ifa->lock);
ifa->flags = flags | IFA_F_TENTATIVE;
ifa->cstamp = ifa->tstamp = jiffies;
- ifa->rt = rt;
-
ifa->idev = idev;
in6_dev_hold(idev);
/* For caller */
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) {
}
#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);
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);
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;
__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;
}
/* (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>:
/*
* 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;
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;
}
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;
}
return;
}
ip6_tnl_add_linklocal(idev);
+ addrconf_add_mroute(dev);
}
static int addrconf_notify(struct notifier_block *this, unsigned long event,
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);
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;
{
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)
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;
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]);
}
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]) {
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 */
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;
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 */
[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, },
.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 */
}
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);
}
/*
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
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