* Linux INET6 implementation
*
* Authors:
- * Pedro Roque <roque@di.fc.ul.pt>
+ * Pedro Roque <roque@di.fc.ul.pt>
* Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
*
* $Id: addrconf.c,v 1.69 2001/10/31 21:55:54 davem Exp $
#include <linux/types.h>
#include <linux/socket.h>
#include <linux/sockios.h>
-#include <linux/sched.h>
#include <linux/net.h>
#include <linux/in6.h>
#include <linux/netdevice.h>
#ifdef CONFIG_IPV6_PRIVACY
static int __ipv6_regen_rndid(struct inet6_dev *idev);
-static int __ipv6_try_regen_rndid(struct inet6_dev *idev, struct in6_addr *tmpaddr);
+static int __ipv6_try_regen_rndid(struct inet6_dev *idev, struct in6_addr *tmpaddr);
static void ipv6_regen_rndid(unsigned long data);
static int desync_factor = MAX_DESYNC_FACTOR * HZ;
static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifa);
static void ipv6_ifa_notify(int event, struct inet6_ifaddr *ifa);
-static void inet6_prefix_notify(int event, struct inet6_dev *idev,
+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);
#endif
const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
-#define IPV6_ADDR_SCOPE_TYPE(scope) ((scope) << 16)
-
-static inline unsigned ipv6_addr_scope2type(unsigned scope)
-{
- switch(scope) {
- case IPV6_ADDR_SCOPE_NODELOCAL:
- return (IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_NODELOCAL) |
- IPV6_ADDR_LOOPBACK);
- case IPV6_ADDR_SCOPE_LINKLOCAL:
- return (IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_LINKLOCAL) |
- IPV6_ADDR_LINKLOCAL);
- case IPV6_ADDR_SCOPE_SITELOCAL:
- return (IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_SITELOCAL) |
- IPV6_ADDR_SITELOCAL);
- }
- return IPV6_ADDR_SCOPE_TYPE(scope);
-}
-
-int __ipv6_addr_type(const struct in6_addr *addr)
-{
- u32 st;
-
- st = addr->s6_addr32[0];
-
- /* Consider all addresses with the first three bits different of
- 000 and 111 as unicasts.
- */
- if ((st & htonl(0xE0000000)) != htonl(0x00000000) &&
- (st & htonl(0xE0000000)) != htonl(0xE0000000))
- return (IPV6_ADDR_UNICAST |
- IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL));
-
- if ((st & htonl(0xFF000000)) == htonl(0xFF000000)) {
- /* multicast */
- /* addr-select 3.1 */
- return (IPV6_ADDR_MULTICAST |
- ipv6_addr_scope2type(IPV6_ADDR_MC_SCOPE(addr)));
- }
-
- if ((st & htonl(0xFFC00000)) == htonl(0xFE800000))
- return (IPV6_ADDR_LINKLOCAL | IPV6_ADDR_UNICAST |
- IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_LINKLOCAL)); /* addr-select 3.1 */
- if ((st & htonl(0xFFC00000)) == htonl(0xFEC00000))
- return (IPV6_ADDR_SITELOCAL | IPV6_ADDR_UNICAST |
- IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_SITELOCAL)); /* addr-select 3.1 */
-
- if ((addr->s6_addr32[0] | addr->s6_addr32[1]) == 0) {
- if (addr->s6_addr32[2] == 0) {
- if (addr->s6_addr32[3] == 0)
- return IPV6_ADDR_ANY;
-
- if (addr->s6_addr32[3] == htonl(0x00000001))
- return (IPV6_ADDR_LOOPBACK | IPV6_ADDR_UNICAST |
- IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_LINKLOCAL)); /* addr-select 3.4 */
-
- return (IPV6_ADDR_COMPATv4 | IPV6_ADDR_UNICAST |
- IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL)); /* addr-select 3.3 */
- }
-
- if (addr->s6_addr32[2] == htonl(0x0000ffff))
- return (IPV6_ADDR_MAPPED |
- IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL)); /* addr-select 3.3 */
- }
-
- return (IPV6_ADDR_RESERVED |
- IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL)); /* addr-select 3.4 */
-}
-
static void addrconf_del_timer(struct inet6_ifaddr *ifp)
{
if (del_timer(&ifp->timer))
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 = kzalloc(sizeof(struct inet6_dev), GFP_KERNEL);
- if (ndev == NULL)
- return NULL;
+ if (ndev == NULL)
+ return NULL;
rwlock_init(&ndev->lock);
ndev->dev = dev;
ndev->regen_timer.data = (unsigned long) ndev;
if ((dev->flags&IFF_LOOPBACK) ||
dev->type == ARPHRD_TUNNEL ||
- dev->type == ARPHRD_NONE ||
- dev->type == ARPHRD_SIT) {
+#if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE)
+ dev->type == ARPHRD_SIT ||
+#endif
+ dev->type == ARPHRD_NONE) {
printk(KERN_INFO
"%s: Disabled Privacy Extensions\n",
dev->name);
}
#endif
- if (netif_carrier_ok(dev))
- ndev->if_flags |= IF_READY;
-
- /* protected by rtnl_lock */
- rcu_assign_pointer(dev->ip6_ptr, ndev);
-
ipv6_mc_init_dev(ndev);
ndev->tstamp = jiffies;
#ifdef CONFIG_SYSCTL
NULL);
addrconf_sysctl_register(ndev, &ndev->cnf);
#endif
+ /* protected by rtnl_lock */
+ rcu_assign_pointer(dev->ip6_ptr, ndev);
+
+ /* Join all-node multicast group */
+ ipv6_addr_all_nodes(&maddr);
+ ipv6_dev_mc_inc(dev, &maddr);
+
return ndev;
}
dev = idev->dev;
if (dev && (dev->flags & IFF_MULTICAST)) {
ipv6_addr_all_routers(&addr);
-
+
if (idev->cnf.forwarding)
ipv6_dev_mc_inc(dev, &addr);
else
ipv6_dev_mc_dec(dev, &addr);
}
for (ifa=idev->addr_list; ifa; ifa=ifa->if_next) {
+ if (ifa->flags&IFA_F_TENTATIVE)
+ continue;
if (idev->cnf.forwarding)
addrconf_join_anycast(ifa);
else
tmp_valid_lft = min_t(__u32,
ifp->valid_lft,
idev->cnf.temp_valid_lft);
- tmp_prefered_lft = min_t(__u32,
- ifp->prefered_lft,
+ tmp_prefered_lft = min_t(__u32,
+ ifp->prefered_lft,
idev->cnf.temp_prefered_lft - desync_factor / HZ);
tmp_plen = ifp->prefix_len;
max_addresses = idev->cnf.max_addresses;
write_unlock(&idev->lock);
ift = !max_addresses ||
- ipv6_count_addresses(idev) < max_addresses ?
+ ipv6_count_addresses(idev) < max_addresses ?
ipv6_add_addr(idev, &addr, tmp_plen,
ipv6_addr_type(&addr)&IPV6_ADDR_SCOPE_MASK, IFA_F_TEMPORARY) : NULL;
if (!ift || IS_ERR(ift)) {
#define IPV6_SADDR_SCORE_LABEL 0x0020
#define IPV6_SADDR_SCORE_PRIVACY 0x0040
-static int inline ipv6_saddr_preferred(int type)
+static inline int ipv6_saddr_preferred(int type)
{
if (type & (IPV6_ADDR_MAPPED|IPV6_ADDR_COMPATv4|
IPV6_ADDR_LOOPBACK|IPV6_ADDR_RESERVED))
}
/* static matching label */
-static int inline ipv6_saddr_label(const struct in6_addr *addr, int type)
+static inline int ipv6_saddr_label(const struct in6_addr *addr, int type)
{
/*
* prefix (longest match) label
continue;
}
- /* Rule 4: Prefer home address -- not implemented yet */
+ /* Rule 4: Prefer home address */
+#ifdef CONFIG_IPV6_MIP6
+ if (hiscore.rule < 4) {
+ if (ifa_result->flags & IFA_F_HOMEADDRESS)
+ hiscore.attrs |= IPV6_SADDR_SCORE_HOA;
+ hiscore.rule++;
+ }
+ if (ifa->flags & IFA_F_HOMEADDRESS) {
+ score.attrs |= IPV6_SADDR_SCORE_HOA;
+ if (!(ifa_result->flags & IFA_F_HOMEADDRESS)) {
+ score.rule = 4;
+ goto record_it;
+ }
+ } else {
+ if (hiscore.attrs & IPV6_SADDR_SCORE_HOA)
+ continue;
+ }
+#else
if (hiscore.rule < 4)
hiscore.rule++;
+#endif
/* Rule 5: Prefer outgoing interface */
if (hiscore.rule < 5) {
if (!ifa_result)
return -EADDRNOTAVAIL;
-
+
ipv6_addr_copy(saddr, &ifa_result->addr);
in6_ifa_put(ifa_result);
return 0;
int ipv6_get_saddr(struct dst_entry *dst,
struct in6_addr *daddr, struct in6_addr *saddr)
{
- return ipv6_dev_get_saddr(dst ? ((struct rt6_info *)dst)->rt6i_idev->dev : NULL, daddr, saddr);
+ return ipv6_dev_get_saddr(dst ? ip6_dst_idev(dst)->dev : NULL, daddr, saddr);
}
{
const struct in6_addr *sk_rcv_saddr6 = &inet6_sk(sk)->rcv_saddr;
const struct in6_addr *sk2_rcv_saddr6 = inet6_rcv_saddr(sk2);
- u32 sk_rcv_saddr = inet_sk(sk)->rcv_saddr;
- u32 sk2_rcv_saddr = inet_rcv_saddr(sk2);
+ __be32 sk_rcv_saddr = inet_sk(sk)->rcv_saddr;
+ __be32 sk2_rcv_saddr = inet_rcv_saddr(sk2);
int sk_ipv6only = ipv6_only_sock(sk);
int sk2_ipv6only = inet_v6_ipv6only(sk2);
int addr_type = ipv6_addr_type(sk_rcv_saddr6);
* - value 0
* - XXX: already assigned to an address on the device
*/
- if (idev->rndid[0] == 0xfd &&
+ if (idev->rndid[0] == 0xfd &&
(idev->rndid[1]&idev->rndid[2]&idev->rndid[3]&idev->rndid[4]&idev->rndid[5]&idev->rndid[6]) == 0xff &&
(idev->rndid[7]&0x80))
goto regen;
if (__ipv6_regen_rndid(idev) < 0)
goto out;
-
+
expires = jiffies +
- idev->cnf.temp_prefered_lft * HZ -
+ idev->cnf.temp_prefered_lft * HZ -
idev->cnf.regen_max_retry * idev->cnf.dad_transmits * idev->nd_parms->retrans_time - desync_factor;
if (time_before(expires, jiffies)) {
printk(KERN_WARNING
This thing is done here expecting that the whole
class of non-broadcast devices need not cloning.
*/
+#if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE)
if (dev->type == ARPHRD_SIT && (dev->flags & IFF_POINTOPOINT))
cfg.fc_flags |= RTF_NONEXTHOP;
+#endif
ip6_route_add(&cfg);
}
ip6_route_add(&cfg);
}
+#if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE)
static void sit_route_add(struct net_device *dev)
{
struct fib6_config cfg = {
/* prefix length - 96 bits "::d.d.d.d" */
ip6_route_add(&cfg);
}
+#endif
static void addrconf_add_lroute(struct net_device *dev)
{
struct inet6_dev *in6_dev;
pinfo = (struct prefix_info *) opt;
-
+
if (len < sizeof(struct prefix_info)) {
ADBG(("addrconf: prefix option too short\n"));
return;
}
-
+
/*
* Validation checks ([ADDRCONF], page 19)
*/
* When a new public address is created as described in [ADDRCONF],
* also create a new temporary address.
*/
- read_unlock_bh(&in6_dev->lock);
+ read_unlock_bh(&in6_dev->lock);
ipv6_create_tempaddr(ifp, NULL);
} else {
read_unlock_bh(&in6_dev->lock);
if (dev == NULL)
goto err_exit;
+#if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE)
if (dev->type == ARPHRD_SIT) {
struct ifreq ifr;
mm_segment_t oldfs;
err = dev_open(dev);
}
}
+#endif
err_exit:
rtnl_unlock();
* 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)
+ __u8 ifa_flags, __u32 prefered_lft, __u32 valid_lft)
{
struct inet6_ifaddr *ifp;
struct inet6_dev *idev;
struct net_device *dev;
- __u8 ifa_flags = 0;
int scope;
+ u32 flags = RTF_EXPIRES;
ASSERT_RTNL();
-
+
/* check the lifetime */
if (!valid_lft || prefered_lft > valid_lft)
return -EINVAL;
if ((dev = __dev_get_by_index(ifindex)) == NULL)
return -ENODEV;
-
+
if ((idev = addrconf_add_dev(dev)) == NULL)
return -ENOBUFS;
scope = ipv6_addr_scope(pfx);
- if (valid_lft == INFINITY_LIFE_TIME)
+ if (valid_lft == INFINITY_LIFE_TIME) {
ifa_flags |= IFA_F_PERMANENT;
- else if (valid_lft >= 0x7FFFFFFF/HZ)
+ flags = 0;
+ } else if (valid_lft >= 0x7FFFFFFF/HZ)
valid_lft = 0x7FFFFFFF/HZ;
if (prefered_lft == 0)
ifp->tstamp = jiffies;
spin_unlock_bh(&ifp->lock);
+ addrconf_prefix_route(&ifp->addr, ifp->prefix_len, dev,
+ jiffies_to_clock_t(valid_lft * HZ), flags);
addrconf_dad_start(ifp, 0);
in6_ifa_put(ifp);
addrconf_verify(0);
struct inet6_ifaddr *ifp;
struct inet6_dev *idev;
struct net_device *dev;
-
+
if ((dev = __dev_get_by_index(ifindex)) == NULL)
return -ENODEV;
ipv6_addr_equal(pfx, &ifp->addr)) {
in6_ifa_hold(ifp);
read_unlock_bh(&idev->lock);
-
+
ipv6_del_addr(ifp);
/* If the last address is deleted administratively,
{
struct in6_ifreq ireq;
int err;
-
+
if (!capable(CAP_NET_ADMIN))
return -EPERM;
-
+
if (copy_from_user(&ireq, arg, sizeof(struct in6_ifreq)))
return -EFAULT;
rtnl_lock();
err = inet6_addr_add(ireq.ifr6_ifindex, &ireq.ifr6_addr, ireq.ifr6_prefixlen,
- INFINITY_LIFE_TIME, INFINITY_LIFE_TIME);
+ IFA_F_PERMANENT, INFINITY_LIFE_TIME, INFINITY_LIFE_TIME);
rtnl_unlock();
return err;
}
{
struct in6_ifreq ireq;
int err;
-
+
if (!capable(CAP_NET_ADMIN))
return -EPERM;
return err;
}
+#if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE)
static void sit_add_v4_addrs(struct inet6_dev *idev)
{
struct inet6_ifaddr * ifp;
return;
}
- for (dev = dev_base; dev != NULL; dev = dev->next) {
+ for (dev = dev_base; dev != NULL; dev = dev->next) {
struct in_device * in_dev = __in_dev_get_rtnl(dev);
if (in_dev && (dev->flags & IFF_UP)) {
struct in_ifaddr * ifa;
}
}
}
- }
+ }
}
+#endif
static void init_loopback(struct net_device *dev)
{
ifp = ipv6_add_addr(idev, addr, 64, IFA_LINK, IFA_F_PERMANENT);
if (!IS_ERR(ifp)) {
+ addrconf_prefix_route(&ifp->addr, ifp->prefix_len, idev->dev, 0, 0);
addrconf_dad_start(ifp, 0);
in6_ifa_put(ifp);
}
ASSERT_RTNL();
- if ((dev->type != ARPHRD_ETHER) &&
+ if ((dev->type != ARPHRD_ETHER) &&
(dev->type != ARPHRD_FDDI) &&
(dev->type != ARPHRD_IEEE802_TR) &&
(dev->type != ARPHRD_ARCNET) &&
addrconf_add_linklocal(idev, &addr);
}
+#if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE)
static void addrconf_sit_config(struct net_device *dev)
{
struct inet6_dev *idev;
ASSERT_RTNL();
- /*
- * Configure the tunnel with one of our IPv4
- * addresses... we should configure all of
+ /*
+ * Configure the tunnel with one of our IPv4
+ * addresses... we should configure all of
* our v4 addrs in the tunnel
*/
} else
sit_route_add(dev);
}
+#endif
static inline int
ipv6_inherit_linklocal(struct inet6_dev *idev, struct net_device *link_dev)
ip6_tnl_add_linklocal(idev);
}
-static int addrconf_notify(struct notifier_block *this, unsigned long event,
+static int addrconf_notify(struct notifier_block *this, unsigned long event,
void * data)
{
struct net_device *dev = (struct net_device *) data;
int run_pending = 0;
switch(event) {
+ case NETDEV_REGISTER:
+ if (!idev) {
+ idev = ipv6_add_dev(dev);
+ if (!idev)
+ printk(KERN_WARNING "IPv6: add_dev failed for %s\n",
+ dev->name);
+ }
+ break;
case NETDEV_UP:
case NETDEV_CHANGE:
if (event == NETDEV_UP) {
}
switch(dev->type) {
+#if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE)
case ARPHRD_SIT:
addrconf_sit_config(dev);
break;
+#endif
case ARPHRD_TUNNEL6:
addrconf_ip6_tnl_config(dev);
break;
return -ENODEV;
/* Step 1: remove reference to ipv6 device from parent device.
- Do not dev_put!
+ Do not dev_put!
*/
if (how == 1) {
idev->dead = 1;
/* Step 5: netlink notification of this interface */
idev->tstamp = jiffies;
inet6_ifinfo_notify(RTM_DELLINK, idev);
-
+
/* Shot the device (if unregistered) */
if (how == 1) {
addrconf_join_solict(dev, &ifp->addr);
- if (ifp->prefix_len != 128 && (ifp->flags&IFA_F_PERMANENT))
- addrconf_prefix_route(&ifp->addr, ifp->prefix_len, dev, 0,
- flags);
-
net_srandom(ifp->addr.s6_addr32[3]);
read_lock_bh(&idev->lock);
spin_lock_bh(&ifp->lock);
if (dev->flags&(IFF_NOARP|IFF_LOOPBACK) ||
- !(ifp->flags&IFA_F_TENTATIVE)) {
+ !(ifp->flags&IFA_F_TENTATIVE) ||
+ ifp->flags & IFA_F_NODAD) {
ifp->flags &= ~IFA_F_TENTATIVE;
spin_unlock_bh(&ifp->lock);
read_unlock_bh(&idev->lock);
goto out;
}
-static struct file_operations if6_fops = {
+static const struct file_operations if6_fops = {
.owner = THIS_MODULE,
.open = if6_seq_open,
.read = seq_read,
}
#endif /* CONFIG_PROC_FS */
+#ifdef CONFIG_IPV6_MIP6
+/* Check if address is a home address configured on any interface. */
+int ipv6_chk_home_addr(struct in6_addr *addr)
+{
+ int ret = 0;
+ struct inet6_ifaddr * ifp;
+ u8 hash = ipv6_addr_hash(addr);
+ read_lock_bh(&addrconf_hash_lock);
+ for (ifp = inet6_addr_lst[hash]; ifp; ifp = ifp->lst_next) {
+ if (ipv6_addr_cmp(&ifp->addr, addr) == 0 &&
+ (ifp->flags & IFA_F_HOMEADDRESS)) {
+ ret = 1;
+ break;
+ }
+ }
+ read_unlock_bh(&addrconf_hash_lock);
+ return ret;
+}
+#endif
+
/*
* Periodic address status verification
*/
age = (now - ifp->tstamp) / HZ;
#ifdef CONFIG_IPV6_PRIVACY
- regen_advance = ifp->idev->cnf.regen_max_retry *
- ifp->idev->cnf.dad_transmits *
+ regen_advance = ifp->idev->cnf.regen_max_retry *
+ ifp->idev->cnf.dad_transmits *
ifp->idev->nd_parms->retrans_time / HZ;
#endif
return inet6_addr_del(ifm->ifa_index, pfx, ifm->ifa_prefixlen);
}
-static int inet6_addr_modify(struct inet6_ifaddr *ifp, u32 prefered_lft,
- u32 valid_lft)
+static int inet6_addr_modify(struct inet6_ifaddr *ifp, u8 ifa_flags,
+ u32 prefered_lft, u32 valid_lft)
{
- int ifa_flags = 0;
+ u32 flags = RTF_EXPIRES;
if (!valid_lft || (prefered_lft > valid_lft))
return -EINVAL;
- if (valid_lft == INFINITY_LIFE_TIME)
- ifa_flags = IFA_F_PERMANENT;
- else if (valid_lft >= 0x7FFFFFFF/HZ)
+ if (valid_lft == INFINITY_LIFE_TIME) {
+ ifa_flags |= IFA_F_PERMANENT;
+ flags = 0;
+ } else if (valid_lft >= 0x7FFFFFFF/HZ)
valid_lft = 0x7FFFFFFF/HZ;
if (prefered_lft == 0)
- ifa_flags = IFA_F_DEPRECATED;
+ 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->flags = (ifp->flags & ~(IFA_F_DEPRECATED | IFA_F_PERMANENT | IFA_F_NODAD | IFA_F_HOMEADDRESS)) | ifa_flags;
ifp->tstamp = jiffies;
ifp->valid_lft = valid_lft;
ifp->prefered_lft = prefered_lft;
if (!(ifp->flags&IFA_F_TENTATIVE))
ipv6_ifa_notify(0, ifp);
+ addrconf_prefix_route(&ifp->addr, ifp->prefix_len, ifp->idev->dev,
+ jiffies_to_clock_t(valid_lft * HZ), flags);
addrconf_verify(0);
return 0;
struct in6_addr *pfx;
struct inet6_ifaddr *ifa;
struct net_device *dev;
- u32 valid_lft, preferred_lft;
+ u32 valid_lft = INFINITY_LIFE_TIME, preferred_lft = INFINITY_LIFE_TIME;
+ u8 ifa_flags;
int err;
err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv6_policy);
if (dev == NULL)
return -ENODEV;
+ /* We ignore other flags so far. */
+ ifa_flags = ifm->ifa_flags & (IFA_F_NODAD | IFA_F_HOMEADDRESS);
+
ifa = ipv6_get_ifaddr(pfx, dev, 1);
if (ifa == NULL) {
/*
* userspace alreay relies on not having to provide this.
*/
return inet6_addr_add(ifm->ifa_index, pfx, ifm->ifa_prefixlen,
- preferred_lft, valid_lft);
+ ifa_flags, preferred_lft, valid_lft);
}
if (nlh->nlmsg_flags & NLM_F_EXCL ||
!(nlh->nlmsg_flags & NLM_F_REPLACE))
err = -EEXIST;
else
- err = inet6_addr_modify(ifa, preferred_lft, valid_lft);
+ err = inet6_addr_modify(ifa, ifa_flags, preferred_lft, valid_lft);
in6_ifa_put(ifa);
static inline int inet6_ifaddr_msgsize(void)
{
- return nlmsg_total_size(sizeof(struct ifaddrmsg) +
- nla_total_size(16) +
- nla_total_size(sizeof(struct ifa_cacheinfo)) +
- 128);
+ return NLMSG_ALIGN(sizeof(struct ifaddrmsg))
+ + nla_total_size(16) /* IFA_ADDRESS */
+ + nla_total_size(sizeof(struct ifa_cacheinfo));
}
static int inet6_fill_ifaddr(struct sk_buff *skb, struct inet6_ifaddr *ifa,
nlh = nlmsg_put(skb, pid, seq, event, sizeof(struct ifaddrmsg), flags);
if (nlh == NULL)
- return -ENOBUFS;
+ return -EMSGSIZE;
put_ifaddrmsg(nlh, ifa->prefix_len, ifa->flags, rt_scope(ifa->scope),
ifa->idev->dev->ifindex);
}
if (nla_put(skb, IFA_ADDRESS, 16, &ifa->addr) < 0 ||
- put_cacheinfo(skb, ifa->cstamp, ifa->tstamp, preferred, valid) < 0)
- return nlmsg_cancel(skb, nlh);
+ put_cacheinfo(skb, ifa->cstamp, ifa->tstamp, preferred, valid) < 0) {
+ nlmsg_cancel(skb, nlh);
+ return -EMSGSIZE;
+ }
return nlmsg_end(skb, nlh);
}
nlh = nlmsg_put(skb, pid, seq, event, sizeof(struct ifaddrmsg), flags);
if (nlh == NULL)
- return -ENOBUFS;
+ return -EMSGSIZE;
put_ifaddrmsg(nlh, 128, IFA_F_PERMANENT, scope, ifindex);
if (nla_put(skb, IFA_MULTICAST, 16, &ifmca->mca_addr) < 0 ||
put_cacheinfo(skb, ifmca->mca_cstamp, ifmca->mca_tstamp,
- INFINITY_LIFE_TIME, INFINITY_LIFE_TIME) < 0)
- return nlmsg_cancel(skb, nlh);
+ INFINITY_LIFE_TIME, INFINITY_LIFE_TIME) < 0) {
+ nlmsg_cancel(skb, nlh);
+ return -EMSGSIZE;
+ }
return nlmsg_end(skb, nlh);
}
nlh = nlmsg_put(skb, pid, seq, event, sizeof(struct ifaddrmsg), flags);
if (nlh == NULL)
- return -ENOBUFS;
+ return -EMSGSIZE;
put_ifaddrmsg(nlh, 128, IFA_F_PERMANENT, scope, ifindex);
if (nla_put(skb, IFA_ANYCAST, 16, &ifaca->aca_addr) < 0 ||
put_cacheinfo(skb, ifaca->aca_cstamp, ifaca->aca_tstamp,
- INFINITY_LIFE_TIME, INFINITY_LIFE_TIME) < 0)
- return nlmsg_cancel(skb, nlh);
+ INFINITY_LIFE_TIME, INFINITY_LIFE_TIME) < 0) {
+ nlmsg_cancel(skb, nlh);
+ return -EMSGSIZE;
+ }
return nlmsg_end(skb, nlh);
}
s_idx = cb->args[0];
s_ip_idx = ip_idx = cb->args[1];
read_lock(&dev_base_lock);
-
+
for (dev = dev_base, idx = 0; dev; dev = dev->next, idx++) {
if (idx < s_idx)
continue;
ifa = ifa->if_next, ip_idx++) {
if (ip_idx < s_ip_idx)
continue;
- if ((err = inet6_fill_ifaddr(skb, ifa,
- NETLINK_CB(cb->skb).pid,
+ if ((err = inet6_fill_ifaddr(skb, ifa,
+ NETLINK_CB(cb->skb).pid,
cb->nlh->nlmsg_seq, RTM_NEWADDR,
NLM_F_MULTI)) <= 0)
goto done;
break;
case MULTICAST_ADDR:
/* multicast address */
- for (ifmca = idev->mc_list; ifmca;
+ for (ifmca = idev->mc_list; ifmca;
ifmca = ifmca->next, ip_idx++) {
if (ip_idx < s_ip_idx)
continue;
- if ((err = inet6_fill_ifmcaddr(skb, ifmca,
- NETLINK_CB(cb->skb).pid,
+ if ((err = inet6_fill_ifmcaddr(skb, ifmca,
+ NETLINK_CB(cb->skb).pid,
cb->nlh->nlmsg_seq, RTM_GETMULTICAST,
NLM_F_MULTI)) <= 0)
goto done;
ifaca = ifaca->aca_next, ip_idx++) {
if (ip_idx < s_ip_idx)
continue;
- if ((err = inet6_fill_ifacaddr(skb, ifaca,
- NETLINK_CB(cb->skb).pid,
+ if ((err = inet6_fill_ifacaddr(skb, ifaca,
+ NETLINK_CB(cb->skb).pid,
cb->nlh->nlmsg_seq, RTM_GETANYCAST,
- NLM_F_MULTI)) <= 0)
+ NLM_F_MULTI)) <= 0)
goto done;
}
break;
err = inet6_fill_ifaddr(skb, ifa, NETLINK_CB(in_skb).pid,
nlh->nlmsg_seq, RTM_NEWADDR, 0);
if (err < 0) {
+ /* -EMSGSIZE implies BUG in inet6_ifaddr_msgsize() */
+ WARN_ON(err == -EMSGSIZE);
kfree_skb(skb);
goto errout_ifa;
}
-
err = rtnl_unicast(skb, NETLINK_CB(in_skb).pid);
errout_ifa:
in6_ifa_put(ifa);
err = inet6_fill_ifaddr(skb, ifa, 0, 0, event, 0);
if (err < 0) {
+ /* -EMSGSIZE implies BUG in inet6_ifaddr_msgsize() */
+ WARN_ON(err == -EMSGSIZE);
kfree_skb(skb);
goto errout;
}
-
err = rtnl_notify(skb, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC);
errout:
if (err < 0)
rtnl_set_sk_err(RTNLGRP_IPV6_IFADDR, err);
}
-static void inline ipv6_store_devconf(struct ipv6_devconf *cnf,
+static inline void ipv6_store_devconf(struct ipv6_devconf *cnf,
__s32 *array, int bytes)
{
+ BUG_ON(bytes < (DEVCONF_MAX * 4));
+
memset(array, 0, bytes);
array[DEVCONF_FORWARDING] = cnf->forwarding;
array[DEVCONF_HOPLIMIT] = cnf->hop_limit;
#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
+#ifdef CONFIG_IPV6_ROUTE_INFO
array[DEVCONF_ACCEPT_RA_RT_INFO_MAX_PLEN] = cnf->accept_ra_rt_info_max_plen;
#endif
#endif
array[DEVCONF_PROXY_NDP] = cnf->proxy_ndp;
}
-/* Maximum length of ifinfomsg attributes */
-#define INET6_IFINFO_RTA_SPACE \
- RTA_SPACE(IFNAMSIZ) /* IFNAME */ + \
- RTA_SPACE(MAX_ADDR_LEN) /* ADDRESS */ + \
- RTA_SPACE(sizeof(u32)) /* MTU */ + \
- RTA_SPACE(sizeof(int)) /* LINK */ + \
- RTA_SPACE(0) /* PROTINFO */ + \
- RTA_SPACE(sizeof(u32)) /* FLAGS */ + \
- RTA_SPACE(sizeof(struct ifla_cacheinfo)) /* CACHEINFO */ + \
- RTA_SPACE(sizeof(__s32[DEVCONF_MAX])) /* CONF */
-
-static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev,
+static inline size_t inet6_if_nlmsg_size(void)
+{
+ return NLMSG_ALIGN(sizeof(struct ifinfomsg))
+ + nla_total_size(IFNAMSIZ) /* IFLA_IFNAME */
+ + nla_total_size(MAX_ADDR_LEN) /* IFLA_ADDRESS */
+ + nla_total_size(4) /* IFLA_MTU */
+ + nla_total_size(4) /* IFLA_LINK */
+ + nla_total_size( /* IFLA_PROTINFO */
+ nla_total_size(4) /* IFLA_INET6_FLAGS */
+ + nla_total_size(sizeof(struct ifla_cacheinfo))
+ + nla_total_size(DEVCONF_MAX * 4) /* IFLA_INET6_CONF */
+ );
+}
+
+static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev,
u32 pid, u32 seq, int event, unsigned int flags)
{
- struct net_device *dev = idev->dev;
- __s32 *array = NULL;
- struct ifinfomsg *r;
- struct nlmsghdr *nlh;
- unsigned char *b = skb->tail;
- struct rtattr *subattr;
- __u32 mtu = dev->mtu;
- struct ifla_cacheinfo ci;
-
- nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*r), flags);
- r = NLMSG_DATA(nlh);
- r->ifi_family = AF_INET6;
- r->__ifi_pad = 0;
- r->ifi_type = dev->type;
- r->ifi_index = dev->ifindex;
- r->ifi_flags = dev_get_flags(dev);
- r->ifi_change = 0;
-
- RTA_PUT(skb, IFLA_IFNAME, strlen(dev->name)+1, dev->name);
+ struct net_device *dev = idev->dev;
+ struct nlattr *conf;
+ struct ifinfomsg *hdr;
+ struct nlmsghdr *nlh;
+ void *protoinfo;
+ struct ifla_cacheinfo ci;
+
+ nlh = nlmsg_put(skb, pid, seq, event, sizeof(*hdr), flags);
+ if (nlh == NULL)
+ return -EMSGSIZE;
+
+ hdr = nlmsg_data(nlh);
+ hdr->ifi_family = AF_INET6;
+ hdr->__ifi_pad = 0;
+ hdr->ifi_type = dev->type;
+ hdr->ifi_index = dev->ifindex;
+ hdr->ifi_flags = dev_get_flags(dev);
+ hdr->ifi_change = 0;
+
+ NLA_PUT_STRING(skb, IFLA_IFNAME, dev->name);
if (dev->addr_len)
- RTA_PUT(skb, IFLA_ADDRESS, dev->addr_len, dev->dev_addr);
+ NLA_PUT(skb, IFLA_ADDRESS, dev->addr_len, dev->dev_addr);
- RTA_PUT(skb, IFLA_MTU, sizeof(mtu), &mtu);
+ NLA_PUT_U32(skb, IFLA_MTU, dev->mtu);
if (dev->ifindex != dev->iflink)
- RTA_PUT(skb, IFLA_LINK, sizeof(int), &dev->iflink);
-
- subattr = (struct rtattr*)skb->tail;
+ NLA_PUT_U32(skb, IFLA_LINK, dev->iflink);
- RTA_PUT(skb, IFLA_PROTINFO, 0, NULL);
+ protoinfo = nla_nest_start(skb, IFLA_PROTINFO);
+ if (protoinfo == NULL)
+ goto nla_put_failure;
- /* return the device flags */
- RTA_PUT(skb, IFLA_INET6_FLAGS, sizeof(__u32), &idev->if_flags);
+ NLA_PUT_U32(skb, IFLA_INET6_FLAGS, idev->if_flags);
- /* return interface cacheinfo */
ci.max_reasm_len = IPV6_MAXPLEN;
ci.tstamp = (__u32)(TIME_DELTA(idev->tstamp, INITIAL_JIFFIES) / HZ * 100
+ TIME_DELTA(idev->tstamp, INITIAL_JIFFIES) % HZ * 100 / HZ);
ci.reachable_time = idev->nd_parms->reachable_time;
ci.retrans_time = idev->nd_parms->retrans_time;
- RTA_PUT(skb, IFLA_INET6_CACHEINFO, sizeof(ci), &ci);
-
- /* return the device sysctl params */
- if ((array = kmalloc(DEVCONF_MAX * sizeof(*array), GFP_ATOMIC)) == NULL)
- goto rtattr_failure;
- ipv6_store_devconf(&idev->cnf, array, DEVCONF_MAX * sizeof(*array));
- RTA_PUT(skb, IFLA_INET6_CONF, DEVCONF_MAX * sizeof(*array), array);
+ NLA_PUT(skb, IFLA_INET6_CACHEINFO, sizeof(ci), &ci);
+
+ conf = nla_reserve(skb, IFLA_INET6_CONF, DEVCONF_MAX * sizeof(s32));
+ if (conf == NULL)
+ goto nla_put_failure;
+ ipv6_store_devconf(&idev->cnf, nla_data(conf), nla_len(conf));
/* XXX - Statistics/MC not implemented */
- subattr->rta_len = skb->tail - (u8*)subattr;
- nlh->nlmsg_len = skb->tail - b;
- kfree(array);
- return skb->len;
+ nla_nest_end(skb, protoinfo);
+ return nlmsg_end(skb, nlh);
-nlmsg_failure:
-rtattr_failure:
- kfree(array);
- skb_trim(skb, b - skb->data);
- return -1;
+nla_put_failure:
+ nlmsg_cancel(skb, nlh);
+ return -EMSGSIZE;
}
static int inet6_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
continue;
if ((idev = in6_dev_get(dev)) == NULL)
continue;
- err = inet6_fill_ifinfo(skb, idev, NETLINK_CB(cb->skb).pid,
+ err = inet6_fill_ifinfo(skb, idev, NETLINK_CB(cb->skb).pid,
cb->nlh->nlmsg_seq, RTM_NEWLINK, NLM_F_MULTI);
in6_dev_put(idev);
if (err <= 0)
void inet6_ifinfo_notify(int event, struct inet6_dev *idev)
{
struct sk_buff *skb;
- int payload = sizeof(struct ifinfomsg) + INET6_IFINFO_RTA_SPACE;
int err = -ENOBUFS;
-
- skb = nlmsg_new(nlmsg_total_size(payload), GFP_ATOMIC);
+
+ skb = nlmsg_new(inet6_if_nlmsg_size(), GFP_ATOMIC);
if (skb == NULL)
goto errout;
err = inet6_fill_ifinfo(skb, idev, 0, 0, event, 0);
if (err < 0) {
+ /* -EMSGSIZE implies BUG in inet6_if_nlmsg_size() */
+ WARN_ON(err == -EMSGSIZE);
kfree_skb(skb);
goto errout;
}
-
err = rtnl_notify(skb, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC);
errout:
if (err < 0)
rtnl_set_sk_err(RTNLGRP_IPV6_IFADDR, err);
}
-/* Maximum length of prefix_cacheinfo attributes */
-#define INET6_PREFIX_RTA_SPACE \
- RTA_SPACE(sizeof(((struct prefix_info *)NULL)->prefix)) /* ADDRESS */ + \
- RTA_SPACE(sizeof(struct prefix_cacheinfo)) /* CACHEINFO */
+static inline size_t inet6_prefix_nlmsg_size(void)
+{
+ return NLMSG_ALIGN(sizeof(struct prefixmsg))
+ + nla_total_size(sizeof(struct in6_addr))
+ + nla_total_size(sizeof(struct prefix_cacheinfo));
+}
static int inet6_fill_prefix(struct sk_buff *skb, struct inet6_dev *idev,
- struct prefix_info *pinfo, u32 pid, u32 seq,
- int event, unsigned int flags)
+ struct prefix_info *pinfo, u32 pid, u32 seq,
+ int event, unsigned int flags)
{
- struct prefixmsg *pmsg;
- struct nlmsghdr *nlh;
- unsigned char *b = skb->tail;
+ struct prefixmsg *pmsg;
+ struct nlmsghdr *nlh;
struct prefix_cacheinfo ci;
- nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*pmsg), flags);
- pmsg = NLMSG_DATA(nlh);
+ nlh = nlmsg_put(skb, pid, seq, event, sizeof(*pmsg), flags);
+ if (nlh == NULL)
+ return -EMSGSIZE;
+
+ pmsg = nlmsg_data(nlh);
pmsg->prefix_family = AF_INET6;
pmsg->prefix_pad1 = 0;
pmsg->prefix_pad2 = 0;
pmsg->prefix_len = pinfo->prefix_len;
pmsg->prefix_type = pinfo->type;
pmsg->prefix_pad3 = 0;
-
pmsg->prefix_flags = 0;
if (pinfo->onlink)
pmsg->prefix_flags |= IF_PREFIX_ONLINK;
if (pinfo->autoconf)
pmsg->prefix_flags |= IF_PREFIX_AUTOCONF;
- RTA_PUT(skb, PREFIX_ADDRESS, sizeof(pinfo->prefix), &pinfo->prefix);
+ NLA_PUT(skb, PREFIX_ADDRESS, sizeof(pinfo->prefix), &pinfo->prefix);
ci.preferred_time = ntohl(pinfo->prefered);
ci.valid_time = ntohl(pinfo->valid);
- RTA_PUT(skb, PREFIX_CACHEINFO, sizeof(ci), &ci);
+ NLA_PUT(skb, PREFIX_CACHEINFO, sizeof(ci), &ci);
- nlh->nlmsg_len = skb->tail - b;
- return skb->len;
+ return nlmsg_end(skb, nlh);
-nlmsg_failure:
-rtattr_failure:
- skb_trim(skb, b - skb->data);
- return -1;
+nla_put_failure:
+ nlmsg_cancel(skb, nlh);
+ return -EMSGSIZE;
}
-static void inet6_prefix_notify(int event, struct inet6_dev *idev,
+static void inet6_prefix_notify(int event, struct inet6_dev *idev,
struct prefix_info *pinfo)
{
struct sk_buff *skb;
- int payload = sizeof(struct prefixmsg) + INET6_PREFIX_RTA_SPACE;
int err = -ENOBUFS;
- skb = nlmsg_new(nlmsg_total_size(payload), GFP_ATOMIC);
+ skb = nlmsg_new(inet6_prefix_nlmsg_size(), GFP_ATOMIC);
if (skb == NULL)
goto errout;
err = inet6_fill_prefix(skb, idev, pinfo, 0, 0, event, 0);
if (err < 0) {
+ /* -EMSGSIZE implies BUG in inet6_prefix_nlmsg_size() */
+ WARN_ON(err == -EMSGSIZE);
kfree_skb(skb);
goto errout;
}
-
err = rtnl_notify(skb, 0, RTNLGRP_IPV6_PREFIX, NULL, GFP_ATOMIC);
errout:
if (err < 0)
rt6_purge_dflt_routers();
}
- return ret;
+ return ret;
}
-static int addrconf_sysctl_forward_strategy(ctl_table *table,
+static int addrconf_sysctl_forward_strategy(ctl_table *table,
int __user *name, int nlen,
void __user *oldval,
size_t __user *oldlenp,
- void __user *newval, size_t newlen,
- void **context)
+ void __user *newval, size_t newlen)
{
int *valp = table->data;
int new;
} addrconf_sysctl __read_mostly = {
.sysctl_header = NULL,
.addrconf_vars = {
- {
+ {
.ctl_name = NET_IPV6_FORWARDING,
.procname = "forwarding",
- .data = &ipv6_devconf.forwarding,
+ .data = &ipv6_devconf.forwarding,
.maxlen = sizeof(int),
.mode = 0644,
- .proc_handler = &addrconf_sysctl_forward,
+ .proc_handler = &addrconf_sysctl_forward,
.strategy = &addrconf_sysctl_forward_strategy,
},
{
.ctl_name = NET_IPV6_HOP_LIMIT,
.procname = "hop_limit",
- .data = &ipv6_devconf.hop_limit,
+ .data = &ipv6_devconf.hop_limit,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = proc_dointvec,
.ctl_name = NET_IPV6_MTU,
.procname = "mtu",
.data = &ipv6_devconf.mtu6,
- .maxlen = sizeof(int),
+ .maxlen = sizeof(int),
.mode = 0644,
- .proc_handler = &proc_dointvec,
+ .proc_handler = &proc_dointvec,
},
{
.ctl_name = NET_IPV6_ACCEPT_RA,
.procname = "accept_ra",
- .data = &ipv6_devconf.accept_ra,
+ .data = &ipv6_devconf.accept_ra,
.maxlen = sizeof(int),
.mode = 0644,
- .proc_handler = &proc_dointvec,
+ .proc_handler = &proc_dointvec,
},
{
.ctl_name = NET_IPV6_ACCEPT_REDIRECTS,
.procname = "accept_redirects",
- .data = &ipv6_devconf.accept_redirects,
+ .data = &ipv6_devconf.accept_redirects,
.maxlen = sizeof(int),
.mode = 0644,
- .proc_handler = &proc_dointvec,
+ .proc_handler = &proc_dointvec,
},
{
.ctl_name = NET_IPV6_AUTOCONF,
.procname = "autoconf",
- .data = &ipv6_devconf.autoconf,
+ .data = &ipv6_devconf.autoconf,
.maxlen = sizeof(int),
.mode = 0644,
- .proc_handler = &proc_dointvec,
+ .proc_handler = &proc_dointvec,
},
{
.ctl_name = NET_IPV6_DAD_TRANSMITS,
.procname = "dad_transmits",
- .data = &ipv6_devconf.dad_transmits,
+ .data = &ipv6_devconf.dad_transmits,
.maxlen = sizeof(int),
.mode = 0644,
- .proc_handler = &proc_dointvec,
+ .proc_handler = &proc_dointvec,
},
{
.ctl_name = NET_IPV6_RTR_SOLICITS,
.procname = "router_solicitations",
- .data = &ipv6_devconf.rtr_solicits,
+ .data = &ipv6_devconf.rtr_solicits,
.maxlen = sizeof(int),
.mode = 0644,
- .proc_handler = &proc_dointvec,
+ .proc_handler = &proc_dointvec,
},
{
.ctl_name = NET_IPV6_RTR_SOLICIT_INTERVAL,
.procname = "router_solicitation_interval",
- .data = &ipv6_devconf.rtr_solicit_interval,
+ .data = &ipv6_devconf.rtr_solicit_interval,
.maxlen = sizeof(int),
.mode = 0644,
- .proc_handler = &proc_dointvec_jiffies,
+ .proc_handler = &proc_dointvec_jiffies,
.strategy = &sysctl_jiffies,
},
{
.ctl_name = NET_IPV6_RTR_SOLICIT_DELAY,
.procname = "router_solicitation_delay",
- .data = &ipv6_devconf.rtr_solicit_delay,
+ .data = &ipv6_devconf.rtr_solicit_delay,
.maxlen = sizeof(int),
.mode = 0644,
- .proc_handler = &proc_dointvec_jiffies,
+ .proc_handler = &proc_dointvec_jiffies,
.strategy = &sysctl_jiffies,
},
{
.ctl_name = NET_IPV6_FORCE_MLD_VERSION,
.procname = "force_mld_version",
- .data = &ipv6_devconf.force_mld_version,
+ .data = &ipv6_devconf.force_mld_version,
.maxlen = sizeof(int),
.mode = 0644,
- .proc_handler = &proc_dointvec,
+ .proc_handler = &proc_dointvec,
},
#ifdef CONFIG_IPV6_PRIVACY
{
.ctl_name = NET_IPV6_USE_TEMPADDR,
.procname = "use_tempaddr",
- .data = &ipv6_devconf.use_tempaddr,
+ .data = &ipv6_devconf.use_tempaddr,
.maxlen = sizeof(int),
.mode = 0644,
- .proc_handler = &proc_dointvec,
+ .proc_handler = &proc_dointvec,
},
{
.ctl_name = NET_IPV6_TEMP_VALID_LFT,
.procname = "temp_valid_lft",
- .data = &ipv6_devconf.temp_valid_lft,
+ .data = &ipv6_devconf.temp_valid_lft,
.maxlen = sizeof(int),
.mode = 0644,
- .proc_handler = &proc_dointvec,
+ .proc_handler = &proc_dointvec,
},
{
.ctl_name = NET_IPV6_TEMP_PREFERED_LFT,
.procname = "temp_prefered_lft",
- .data = &ipv6_devconf.temp_prefered_lft,
+ .data = &ipv6_devconf.temp_prefered_lft,
.maxlen = sizeof(int),
.mode = 0644,
- .proc_handler = &proc_dointvec,
+ .proc_handler = &proc_dointvec,
},
{
.ctl_name = NET_IPV6_REGEN_MAX_RETRY,
.procname = "regen_max_retry",
- .data = &ipv6_devconf.regen_max_retry,
+ .data = &ipv6_devconf.regen_max_retry,
.maxlen = sizeof(int),
.mode = 0644,
- .proc_handler = &proc_dointvec,
+ .proc_handler = &proc_dointvec,
},
{
.ctl_name = NET_IPV6_MAX_DESYNC_FACTOR,
.procname = "max_desync_factor",
- .data = &ipv6_devconf.max_desync_factor,
+ .data = &ipv6_devconf.max_desync_factor,
.maxlen = sizeof(int),
.mode = 0644,
- .proc_handler = &proc_dointvec,
+ .proc_handler = &proc_dointvec,
},
#endif
{
{
.ctl_name = NET_IPV6_ACCEPT_RA_DEFRTR,
.procname = "accept_ra_defrtr",
- .data = &ipv6_devconf.accept_ra_defrtr,
+ .data = &ipv6_devconf.accept_ra_defrtr,
.maxlen = sizeof(int),
.mode = 0644,
- .proc_handler = &proc_dointvec,
+ .proc_handler = &proc_dointvec,
},
{
.ctl_name = NET_IPV6_ACCEPT_RA_PINFO,
.procname = "accept_ra_pinfo",
- .data = &ipv6_devconf.accept_ra_pinfo,
+ .data = &ipv6_devconf.accept_ra_pinfo,
.maxlen = sizeof(int),
.mode = 0644,
- .proc_handler = &proc_dointvec,
+ .proc_handler = &proc_dointvec,
},
#ifdef CONFIG_IPV6_ROUTER_PREF
{
.proc_handler = &proc_dointvec_jiffies,
.strategy = &sysctl_jiffies,
},
-#ifdef CONFIV_IPV6_ROUTE_INFO
+#ifdef CONFIG_IPV6_ROUTE_INFO
{
.ctl_name = NET_IPV6_ACCEPT_RA_RT_INFO_MAX_PLEN,
.procname = "accept_ra_rt_info_max_plen",
struct addrconf_sysctl_table *t;
char *dev_name = NULL;
- t = kmalloc(sizeof(*t), GFP_KERNEL);
+ t = kmemdup(&addrconf_sysctl, sizeof(*t), GFP_KERNEL);
if (t == NULL)
return;
- memcpy(t, &addrconf_sysctl, sizeof(*t));
for (i=0; t->addrconf_vars[i].data; i++) {
t->addrconf_vars[i].data += (char*)p - (char*)&ipv6_devconf;
- t->addrconf_vars[i].de = NULL;
t->addrconf_vars[i].extra1 = idev; /* embedded; no ref */
}
if (dev) {
- dev_name = dev->name;
+ dev_name = dev->name;
t->addrconf_dev[0].ctl_name = dev->ifindex;
} else {
dev_name = "default";
t->addrconf_dev[0].ctl_name = NET_PROTO_CONF_DEFAULT;
}
- /*
- * Make a copy of dev_name, because '.procname' is regarded as const
+ /*
+ * Make a copy of dev_name, because '.procname' is regarded as const
* by sysctl and we wouldn't want anyone to change it under our feet
* (see SIOCSIFNAME).
- */
+ */
dev_name = kstrdup(dev_name, GFP_KERNEL);
if (!dev_name)
goto free;
t->addrconf_dev[0].procname = dev_name;
t->addrconf_dev[0].child = t->addrconf_vars;
- t->addrconf_dev[0].de = NULL;
t->addrconf_conf_dir[0].child = t->addrconf_dev;
- t->addrconf_conf_dir[0].de = NULL;
t->addrconf_proto_dir[0].child = t->addrconf_conf_dir;
- t->addrconf_proto_dir[0].de = NULL;
t->addrconf_root_dir[0].child = t->addrconf_proto_dir;
- t->addrconf_root_dir[0].de = NULL;
- t->sysctl_header = register_sysctl_table(t->addrconf_root_dir, 0);
+ t->sysctl_header = register_sysctl_table(t->addrconf_root_dir);
if (t->sysctl_header == NULL)
goto free_procname;
else
int register_inet6addr_notifier(struct notifier_block *nb)
{
- return atomic_notifier_chain_register(&inet6addr_chain, nb);
+ return atomic_notifier_chain_register(&inet6addr_chain, nb);
}
int unregister_inet6addr_notifier(struct notifier_block *nb)
{
- return atomic_notifier_chain_unregister(&inet6addr_chain,nb);
+ return atomic_notifier_chain_unregister(&inet6addr_chain,nb);
}
/*
rtnetlink_links[PF_INET6] = inet6_rtnetlink_table;
#ifdef CONFIG_SYSCTL
addrconf_sysctl.sysctl_header =
- register_sysctl_table(addrconf_sysctl.addrconf_root_dir, 0);
+ register_sysctl_table(addrconf_sysctl.addrconf_root_dir);
addrconf_sysctl_register(NULL, &ipv6_devconf_dflt);
#endif
void __exit addrconf_cleanup(void)
{
- struct net_device *dev;
- struct inet6_dev *idev;
- struct inet6_ifaddr *ifa;
+ struct net_device *dev;
+ struct inet6_dev *idev;
+ struct inet6_ifaddr *ifa;
int i;
unregister_netdevice_notifier(&ipv6_dev_notf);