#include <linux/errno.h>
#include <linux/types.h>
+#include <linux/kernel.h>
#include <linux/socket.h>
#include <linux/sockios.h>
#include <linux/net.h>
static int desync_factor = MAX_DESYNC_FACTOR * HZ;
#endif
+static int ipv6_generate_eui64(u8 *eui, struct net_device *dev);
static int ipv6_count_addresses(struct inet6_dev *idev);
/*
static ATOMIC_NOTIFIER_HEAD(inet6addr_chain);
-struct ipv6_devconf ipv6_devconf __read_mostly = {
+static struct ipv6_devconf ipv6_devconf __read_mostly = {
.forwarding = 0,
.hop_limit = IPV6_DEFAULT_HOPLIMIT,
.mtu6 = IPV6_MIN_MTU,
#endif
.proxy_ndp = 0,
.accept_source_route = 0, /* we do not accept RH0 by default. */
+ .disable_ipv6 = 0,
+ .accept_dad = 1,
};
static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
#endif
.proxy_ndp = 0,
.accept_source_route = 0, /* we do not accept RH0 by default. */
+ .disable_ipv6 = 0,
+ .accept_dad = 1,
};
/* IPv6 Wildcard Address and Loopback Address defined by RFC2553 */
const struct in6_addr in6addr_linklocal_allrouters = IN6ADDR_LINKLOCAL_ALLROUTERS_INIT;
/* Check if a valid qdisc is available */
-static inline int addrconf_qdisc_ok(struct net_device *dev)
+static inline bool addrconf_qdisc_ok(const struct net_device *dev)
{
- return (dev->qdisc != &noop_qdisc);
+ return !qdisc_tx_is_noop(dev);
}
/* Check if a route is valid prefix route */
void in6_dev_finish_destroy(struct inet6_dev *idev)
{
struct net_device *dev = idev->dev;
- BUG_TRAP(idev->addr_list==NULL);
- BUG_TRAP(idev->mc_list==NULL);
+
+ WARN_ON(idev->addr_list != NULL);
+ WARN_ON(idev->mc_list != NULL);
+
#ifdef NET_REFCNT_DEBUG
printk(KERN_DEBUG "in6_dev_finish_destroy: %s\n", dev ? dev->name : "NIL");
#endif
kfree(ndev);
return NULL;
}
+ if (ndev->cnf.forwarding)
+ dev_disable_lro(dev);
/* We refer to the device */
dev_hold(dev);
*/
in6_dev_hold(ndev);
+ if (dev->flags & (IFF_NOARP | IFF_LOOPBACK))
+ ndev->cnf.accept_dad = -1;
+
#if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE)
if (dev->type == ARPHRD_SIT && (dev->priv_flags & IFF_ISATAP)) {
printk(KERN_INFO
if (!idev)
return;
dev = idev->dev;
+ if (idev->cnf.forwarding)
+ dev_disable_lro(dev);
if (dev && (dev->flags & IFF_MULTICAST)) {
if (idev->cnf.forwarding)
ipv6_dev_mc_inc(dev, &in6addr_linklocal_allrouters);
read_unlock(&dev_base_lock);
}
-static void addrconf_fixup_forwarding(struct ctl_table *table, int *p, int old)
+static int addrconf_fixup_forwarding(struct ctl_table *table, int *p, int old)
{
struct net *net;
net = (struct net *)table->extra2;
if (p == &net->ipv6.devconf_dflt->forwarding)
- return;
+ return 0;
+
+ if (!rtnl_trylock())
+ return -ERESTARTSYS;
if (p == &net->ipv6.devconf_all->forwarding) {
__s32 newf = net->ipv6.devconf_all->forwarding;
addrconf_forward_change(net, newf);
} else if ((!*p) ^ (!old))
dev_forward_change((struct inet6_dev *)table->extra1);
+ rtnl_unlock();
if (*p)
rt6_purge_dflt_routers(net);
+ return 1;
}
#endif
void inet6_ifa_finish_destroy(struct inet6_ifaddr *ifp)
{
- BUG_TRAP(ifp->if_next==NULL);
- BUG_TRAP(ifp->lst_next==NULL);
+ WARN_ON(ifp->if_next != NULL);
+ WARN_ON(ifp->lst_next != NULL);
+
#ifdef NET_REFCNT_DEBUG
printk(KERN_DEBUG "inet6_ifa_finish_destroy\n");
#endif
{
struct inet6_ifaddr *ifa = NULL;
struct rt6_info *rt;
+ struct net *net = dev_net(idev->dev);
int hash;
int err = 0;
+ int addr_type = ipv6_addr_type(addr);
+
+ if (addr_type == IPV6_ADDR_ANY ||
+ addr_type & IPV6_ADDR_MULTICAST ||
+ (!(idev->dev->flags & IFF_LOOPBACK) &&
+ addr_type & IPV6_ADDR_LOOPBACK))
+ return ERR_PTR(-EADDRNOTAVAIL);
rcu_read_lock_bh();
if (idev->dead) {
goto out2;
}
+ if (idev->cnf.disable_ipv6 || net->ipv6.devconf_all->disable_ipv6) {
+ err = -EACCES;
+ goto out2;
+ }
+
write_lock(&addrconf_hash_lock);
/* Ignore adding duplicate addresses on an interface */
}
write_unlock_bh(&idev->lock);
+ addrconf_del_timer(ifp);
+
ipv6_ifa_notify(RTM_DELADDR, ifp);
atomic_notifier_call_chain(&inet6addr_chain, NETDEV_DOWN, ifp);
- addrconf_del_timer(ifp);
-
/*
* Purge or update corresponding prefix
*
return ret;
}
-int ipv6_dev_get_saddr(struct net_device *dst_dev,
+int ipv6_dev_get_saddr(struct net *net, struct net_device *dst_dev,
const struct in6_addr *daddr, unsigned int prefs,
struct in6_addr *saddr)
{
struct ipv6_saddr_score scores[2],
*score = &scores[0], *hiscore = &scores[1];
- struct net *net = dev_net(dst_dev);
struct ipv6_saddr_dst dst;
struct net_device *dev;
int dst_type;
}
break;
} else if (minihiscore < miniscore) {
- struct ipv6_saddr_score *tmp;
-
if (hiscore->ifa)
in6_ifa_put(hiscore->ifa);
in6_ifa_hold(score->ifa);
- tmp = hiscore;
- hiscore = score;
- score = tmp;
+ swap(hiscore, score);
/* restore our iterator */
score->ifa = hiscore->ifa;
return ifp;
}
-int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2)
-{
- const struct in6_addr *sk_rcv_saddr6 = &inet6_sk(sk)->rcv_saddr;
- const struct in6_addr *sk2_rcv_saddr6 = inet6_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);
- int addr_type2 = sk2_rcv_saddr6 ? ipv6_addr_type(sk2_rcv_saddr6) : IPV6_ADDR_MAPPED;
-
- if (!sk2_rcv_saddr && !sk_ipv6only)
- return 1;
-
- if (addr_type2 == IPV6_ADDR_ANY &&
- !(sk2_ipv6only && addr_type == IPV6_ADDR_MAPPED))
- return 1;
-
- if (addr_type == IPV6_ADDR_ANY &&
- !(sk_ipv6only && addr_type2 == IPV6_ADDR_MAPPED))
- return 1;
-
- if (sk2_rcv_saddr6 &&
- ipv6_addr_equal(sk_rcv_saddr6, sk2_rcv_saddr6))
- return 1;
-
- if (addr_type == IPV6_ADDR_MAPPED &&
- !sk2_ipv6only &&
- (!sk2_rcv_saddr || !sk_rcv_saddr || sk_rcv_saddr == sk2_rcv_saddr))
- return 1;
-
- return 0;
-}
-
/* Gets referenced address, destroys ifaddr */
static void addrconf_dad_stop(struct inet6_ifaddr *ifp)
void addrconf_dad_failure(struct inet6_ifaddr *ifp)
{
+ struct inet6_dev *idev = ifp->idev;
+
if (net_ratelimit())
- printk(KERN_INFO "%s: duplicate address detected!\n", ifp->idev->dev->name);
+ printk(KERN_INFO "%s: IPv6 duplicate address detected!\n",
+ ifp->idev->dev->name);
+
+ if (idev->cnf.accept_dad > 1 && !idev->cnf.disable_ipv6) {
+ struct in6_addr addr;
+
+ addr.s6_addr32[0] = htonl(0xfe800000);
+ addr.s6_addr32[1] = 0;
+
+ if (!ipv6_generate_eui64(addr.s6_addr + 8, idev->dev) &&
+ ipv6_addr_equal(&ifp->addr, &addr)) {
+ /* DAD failed for link-local based on MAC address */
+ idev->cnf.disable_ipv6 = 1;
+
+ printk(KERN_INFO "%s: IPv6 being disabled!\n",
+ ifp->idev->dev->name);
+ }
+ }
+
addrconf_dad_stop(ifp);
}
.fc_dst_len = plen,
.fc_flags = RTF_UP | flags,
.fc_nlinfo.nl_net = dev_net(dev),
+ .fc_protocol = RTPROT_KERNEL,
};
ipv6_addr_copy(&cfg.fc_dst, pfx);
struct inet6_ifaddr * ifp;
struct in6_addr addr;
int create = 0, update_lft = 0;
+ struct net *net = dev_net(dev);
if (pinfo->prefix_len == 64) {
memcpy(&addr, &pinfo->prefix, 8);
ok:
- ifp = ipv6_get_ifaddr(dev_net(dev), &addr, dev, 1);
+ ifp = ipv6_get_ifaddr(net, &addr, dev, 1);
if (ifp == NULL && valid_lft) {
int max_addresses = in6_dev->cnf.max_addresses;
#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
if (in6_dev->cnf.optimistic_dad &&
- !ipv6_devconf.forwarding)
+ !net->ipv6.devconf_all->forwarding)
addr_flags = IFA_F_OPTIMISTIC;
#endif
#if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE)
if (dev->type == ARPHRD_SIT) {
+ const struct net_device_ops *ops = dev->netdev_ops;
struct ifreq ifr;
- mm_segment_t oldfs;
struct ip_tunnel_parm p;
err = -EADDRNOTAVAIL;
p.iph.ttl = 64;
ifr.ifr_ifru.ifru_data = (__force void __user *)&p;
- oldfs = get_fs(); set_fs(KERNEL_DS);
- err = dev->do_ioctl(dev, &ifr, SIOCADDTUNNEL);
- set_fs(oldfs);
+ if (ops->ndo_do_ioctl) {
+ mm_segment_t oldfs = get_fs();
+
+ set_fs(KERNEL_DS);
+ err = ops->ndo_do_ioctl(dev, &ifr, SIOCADDTUNNEL);
+ set_fs(oldfs);
+ } else
+ err = -EOPNOTSUPP;
if (err == 0) {
err = -ENOBUFS;
return err;
}
+static void add_addr(struct inet6_dev *idev, const struct in6_addr *addr,
+ int plen, int scope)
+{
+ struct inet6_ifaddr *ifp;
+
+ ifp = ipv6_add_addr(idev, addr, plen, scope, IFA_F_PERMANENT);
+ if (!IS_ERR(ifp)) {
+ spin_lock_bh(&ifp->lock);
+ ifp->flags &= ~IFA_F_TENTATIVE;
+ spin_unlock_bh(&ifp->lock);
+ ipv6_ifa_notify(RTM_NEWADDR, ifp);
+ in6_ifa_put(ifp);
+ }
+}
+
#if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE)
static void sit_add_v4_addrs(struct inet6_dev *idev)
{
- struct inet6_ifaddr * ifp;
struct in6_addr addr;
struct net_device *dev;
struct net *net = dev_net(idev->dev);
}
if (addr.s6_addr32[3]) {
- ifp = ipv6_add_addr(idev, &addr, 128, scope, IFA_F_PERMANENT);
- if (!IS_ERR(ifp)) {
- spin_lock_bh(&ifp->lock);
- ifp->flags &= ~IFA_F_TENTATIVE;
- spin_unlock_bh(&ifp->lock);
- ipv6_ifa_notify(RTM_NEWADDR, ifp);
- in6_ifa_put(ifp);
- }
+ add_addr(idev, &addr, 128, scope);
return;
}
else
plen = 96;
- ifp = ipv6_add_addr(idev, &addr, plen, flag,
- IFA_F_PERMANENT);
- if (!IS_ERR(ifp)) {
- spin_lock_bh(&ifp->lock);
- ifp->flags &= ~IFA_F_TENTATIVE;
- spin_unlock_bh(&ifp->lock);
- ipv6_ifa_notify(RTM_NEWADDR, ifp);
- in6_ifa_put(ifp);
- }
+ add_addr(idev, &addr, plen, flag);
}
}
}
static void init_loopback(struct net_device *dev)
{
struct inet6_dev *idev;
- struct inet6_ifaddr * ifp;
/* ::1 */
return;
}
- ifp = ipv6_add_addr(idev, &in6addr_loopback, 128, IFA_HOST, IFA_F_PERMANENT);
- if (!IS_ERR(ifp)) {
- spin_lock_bh(&ifp->lock);
- ifp->flags &= ~IFA_F_TENTATIVE;
- spin_unlock_bh(&ifp->lock);
- ipv6_ifa_notify(RTM_NEWADDR, ifp);
- in6_ifa_put(ifp);
- }
+ add_addr(idev, &in6addr_loopback, 128, IFA_HOST);
}
static void addrconf_add_linklocal(struct inet6_dev *idev, struct in6_addr *addr)
#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
if (idev->cnf.optimistic_dad &&
- !ipv6_devconf.forwarding)
+ !dev_net(idev->dev)->ipv6.devconf_all->forwarding)
addr_flags |= IFA_F_OPTIMISTIC;
#endif
if (!idev && dev->mtu >= IPV6_MIN_MTU)
idev = ipv6_add_dev(dev);
- if (idev)
+ if (idev) {
idev->if_flags |= IF_READY;
+ run_pending = 1;
+ }
} else {
if (!addrconf_qdisc_ok(dev)) {
/* device is still not ready. */
ASSERT_RTNL();
- if ((dev->flags & IFF_LOOPBACK) && how == 1)
- how = 0;
-
rt6_ifdown(net, dev);
neigh_ifdown(&nd_tbl, dev);
spin_lock_bh(&ifp->lock);
if (dev->flags&(IFF_NOARP|IFF_LOOPBACK) ||
+ idev->cnf.accept_dad < 1 ||
!(ifp->flags&IFA_F_TENTATIVE) ||
ifp->flags & IFA_F_NODAD) {
ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC);
static int if6_seq_show(struct seq_file *seq, void *v)
{
struct inet6_ifaddr *ifp = (struct inet6_ifaddr *)v;
- seq_printf(seq,
- NIP6_SEQFMT " %02x %02x %02x %02x %8s\n",
- NIP6(ifp->addr),
+ seq_printf(seq, "%pi6 %02x %02x %02x %02x %8s\n",
+ &ifp->addr,
ifp->idev->dev->ifindex,
ifp->prefix_len,
ifp->scope,
kfree_skb(skb);
goto errout;
}
- err = rtnl_notify(skb, net, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC);
+ rtnl_notify(skb, net, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC);
+ return;
errout:
if (err < 0)
rtnl_set_sk_err(net, RTNLGRP_IPV6_IFADDR, err);
#ifdef CONFIG_IPV6_MROUTE
array[DEVCONF_MC_FORWARDING] = cnf->mc_forwarding;
#endif
+ array[DEVCONF_DISABLE_IPV6] = cnf->disable_ipv6;
+ array[DEVCONF_ACCEPT_DAD] = cnf->accept_dad;
}
static inline size_t inet6_if_nlmsg_size(void)
kfree_skb(skb);
goto errout;
}
- err = rtnl_notify(skb, net, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC);
+ rtnl_notify(skb, net, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC);
+ return;
errout:
if (err < 0)
rtnl_set_sk_err(net, RTNLGRP_IPV6_IFADDR, err);
kfree_skb(skb);
goto errout;
}
- err = rtnl_notify(skb, net, 0, RTNLGRP_IPV6_PREFIX, NULL, GFP_ATOMIC);
+ rtnl_notify(skb, net, 0, RTNLGRP_IPV6_PREFIX, NULL, GFP_ATOMIC);
+ return;
errout:
if (err < 0)
rtnl_set_sk_err(net, RTNLGRP_IPV6_PREFIX, err);
ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos);
if (write)
- addrconf_fixup_forwarding(ctl, valp, val);
+ ret = addrconf_fixup_forwarding(ctl, valp, val);
return ret;
}
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)
}
*valp = new;
- addrconf_fixup_forwarding(table, valp, val);
- return 1;
+ return addrconf_fixup_forwarding(table, valp, val);
}
static struct addrconf_sysctl_table
.data = &ipv6_devconf.forwarding,
.maxlen = sizeof(int),
.mode = 0644,
- .proc_handler = &addrconf_sysctl_forward,
- .strategy = &addrconf_sysctl_forward_strategy,
+ .proc_handler = addrconf_sysctl_forward,
+ .strategy = addrconf_sysctl_forward_strategy,
},
{
.ctl_name = NET_IPV6_HOP_LIMIT,
.data = &ipv6_devconf.mtu6,
.maxlen = sizeof(int),
.mode = 0644,
- .proc_handler = &proc_dointvec,
+ .proc_handler = proc_dointvec,
},
{
.ctl_name = NET_IPV6_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,
.data = &ipv6_devconf.accept_redirects,
.maxlen = sizeof(int),
.mode = 0644,
- .proc_handler = &proc_dointvec,
+ .proc_handler = proc_dointvec,
},
{
.ctl_name = NET_IPV6_AUTOCONF,
.data = &ipv6_devconf.autoconf,
.maxlen = sizeof(int),
.mode = 0644,
- .proc_handler = &proc_dointvec,
+ .proc_handler = proc_dointvec,
},
{
.ctl_name = NET_IPV6_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,
.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,
.data = &ipv6_devconf.rtr_solicit_interval,
.maxlen = sizeof(int),
.mode = 0644,
- .proc_handler = &proc_dointvec_jiffies,
- .strategy = &sysctl_jiffies,
+ .proc_handler = proc_dointvec_jiffies,
+ .strategy = sysctl_jiffies,
},
{
.ctl_name = NET_IPV6_RTR_SOLICIT_DELAY,
.data = &ipv6_devconf.rtr_solicit_delay,
.maxlen = sizeof(int),
.mode = 0644,
- .proc_handler = &proc_dointvec_jiffies,
- .strategy = &sysctl_jiffies,
+ .proc_handler = proc_dointvec_jiffies,
+ .strategy = sysctl_jiffies,
},
{
.ctl_name = NET_IPV6_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
{
.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,
.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,
.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,
.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,
.data = &ipv6_devconf.max_desync_factor,
.maxlen = sizeof(int),
.mode = 0644,
- .proc_handler = &proc_dointvec,
+ .proc_handler = proc_dointvec,
},
#endif
{
.data = &ipv6_devconf.max_addresses,
.maxlen = sizeof(int),
.mode = 0644,
- .proc_handler = &proc_dointvec,
+ .proc_handler = proc_dointvec,
},
{
.ctl_name = NET_IPV6_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,
.data = &ipv6_devconf.accept_ra_pinfo,
.maxlen = sizeof(int),
.mode = 0644,
- .proc_handler = &proc_dointvec,
+ .proc_handler = proc_dointvec,
},
#ifdef CONFIG_IPV6_ROUTER_PREF
{
.data = &ipv6_devconf.accept_ra_rtr_pref,
.maxlen = sizeof(int),
.mode = 0644,
- .proc_handler = &proc_dointvec,
+ .proc_handler = proc_dointvec,
},
{
.ctl_name = NET_IPV6_RTR_PROBE_INTERVAL,
.data = &ipv6_devconf.rtr_probe_interval,
.maxlen = sizeof(int),
.mode = 0644,
- .proc_handler = &proc_dointvec_jiffies,
- .strategy = &sysctl_jiffies,
+ .proc_handler = proc_dointvec_jiffies,
+ .strategy = sysctl_jiffies,
},
#ifdef CONFIG_IPV6_ROUTE_INFO
{
.data = &ipv6_devconf.accept_ra_rt_info_max_plen,
.maxlen = sizeof(int),
.mode = 0644,
- .proc_handler = &proc_dointvec,
+ .proc_handler = proc_dointvec,
},
#endif
#endif
.data = &ipv6_devconf.proxy_ndp,
.maxlen = sizeof(int),
.mode = 0644,
- .proc_handler = &proc_dointvec,
+ .proc_handler = proc_dointvec,
},
{
.ctl_name = NET_IPV6_ACCEPT_SOURCE_ROUTE,
.data = &ipv6_devconf.accept_source_route,
.maxlen = sizeof(int),
.mode = 0644,
- .proc_handler = &proc_dointvec,
+ .proc_handler = proc_dointvec,
},
#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
{
.data = &ipv6_devconf.optimistic_dad,
.maxlen = sizeof(int),
.mode = 0644,
- .proc_handler = &proc_dointvec,
+ .proc_handler = proc_dointvec,
},
#endif
.procname = "mc_forwarding",
.data = &ipv6_devconf.mc_forwarding,
.maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = &proc_dointvec,
+ .mode = 0444,
+ .proc_handler = proc_dointvec,
},
#endif
{
+ .ctl_name = CTL_UNNUMBERED,
+ .procname = "disable_ipv6",
+ .data = &ipv6_devconf.disable_ipv6,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
+ },
+ {
+ .ctl_name = CTL_UNNUMBERED,
+ .procname = "accept_dad",
+ .data = &ipv6_devconf.accept_dad,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
+ },
+ {
.ctl_name = 0, /* sentinel */
}
},
EXPORT_SYMBOL(unregister_inet6addr_notifier);
-static void addrconf_net_exit(struct net *net)
-{
- struct net_device *dev;
-
- rtnl_lock();
- /* clean dev list */
- for_each_netdev(net, dev) {
- if (__in6_dev_get(dev) == NULL)
- continue;
- addrconf_ifdown(dev, 1);
- }
- addrconf_ifdown(net->loopback_dev, 2);
- rtnl_unlock();
-}
-
-static struct pernet_operations addrconf_net_ops = {
- .exit = addrconf_net_exit,
-};
-
/*
* Init / cleanup code
*/
if (err)
goto errlo;
- err = register_pernet_device(&addrconf_net_ops);
- if (err)
- return err;
-
register_netdevice_notifier(&ipv6_dev_notf);
addrconf_verify(0);
void addrconf_cleanup(void)
{
struct inet6_ifaddr *ifa;
+ struct net_device *dev;
int i;
unregister_netdevice_notifier(&ipv6_dev_notf);
- unregister_pernet_device(&addrconf_net_ops);
-
unregister_pernet_subsys(&addrconf_ops);
rtnl_lock();
+ /* clean dev list */
+ for_each_netdev(&init_net, dev) {
+ if (__in6_dev_get(dev) == NULL)
+ continue;
+ addrconf_ifdown(dev, 1);
+ }
+ addrconf_ifdown(init_net.loopback_dev, 2);
+
/*
* Check hash table.
*/
del_timer(&addr_chk_timer);
rtnl_unlock();
-
- unregister_pernet_subsys(&addrconf_net_ops);
}