Commit 44d28ab1 authored by David S. Miller's avatar David S. Miller

Merge branch 'net-next-2.6-v6ready-20080703' of...

Merge branch 'net-next-2.6-v6ready-20080703' of git://git.linux-ipv6.org/gitroot/yoshfuji/linux-2.6-next
parents 40b215e5 e0835f8f
......@@ -1025,6 +1025,17 @@ max_addresses - INTEGER
autoconfigured addresses.
Default: 16
disable_ipv6 - BOOLEAN
Disable IPv6 operation.
Default: FALSE (enable IPv6 operation)
accept_dad - INTEGER
Whether to accept DAD (Duplicate Address Detection).
0: Disable DAD
1: Enable DAD (default)
2: Enable DAD, and disable IPv6 operation if MAC-based duplicate
link-local address has been found.
icmp/*:
ratelimit - INTEGER
Limit the maximal rates for sending ICMPv6 packets.
......
......@@ -228,7 +228,6 @@ extern int ip_mc_msfget(struct sock *sk, struct ip_msfilter *msf,
extern int ip_mc_gsfget(struct sock *sk, struct group_filter *gsf,
struct group_filter __user *optval, int __user *optlen);
extern int ip_mc_sf_allow(struct sock *sk, __be32 local, __be32 rmt, int dif);
extern void ip_mr_init(void);
extern void ip_mc_init_dev(struct in_device *);
extern void ip_mc_destroy_dev(struct in_device *);
extern void ip_mc_up(struct in_device *);
......
......@@ -163,6 +163,8 @@ struct ipv6_devconf {
#ifdef CONFIG_IPV6_MROUTE
__s32 mc_forwarding;
#endif
__s32 disable_ipv6;
__s32 accept_dad;
void *sysctl;
};
......@@ -194,6 +196,8 @@ enum {
DEVCONF_OPTIMISTIC_DAD,
DEVCONF_ACCEPT_SOURCE_ROUTE,
DEVCONF_MC_FORWARDING,
DEVCONF_DISABLE_IPV6,
DEVCONF_ACCEPT_DAD,
DEVCONF_MAX
};
......
......@@ -144,11 +144,37 @@ static inline int ip_mroute_opt(int opt)
}
#endif
#ifdef CONFIG_IP_MROUTE
extern int ip_mroute_setsockopt(struct sock *, int, char __user *, int);
extern int ip_mroute_getsockopt(struct sock *, int, char __user *, int __user *);
extern int ipmr_ioctl(struct sock *sk, int cmd, void __user *arg);
extern void ip_mr_init(void);
extern int ip_mr_init(void);
#else
static inline
int ip_mroute_setsockopt(struct sock *sock,
int optname, char __user *optval, int optlen)
{
return -ENOPROTOOPT;
}
static inline
int ip_mroute_getsockopt(struct sock *sock,
int optname, char __user *optval, int __user *optlen)
{
return -ENOPROTOOPT;
}
static inline
int ipmr_ioctl(struct sock *sk, int cmd, void __user *arg)
{
return -ENOIOCTLCMD;
}
static inline int ip_mr_init(void)
{
return 0;
}
#endif
struct vif_device
{
......
......@@ -131,11 +131,44 @@ static inline int ip6_mroute_opt(int opt)
struct sock;
#ifdef CONFIG_IPV6_MROUTE
extern int ip6_mroute_setsockopt(struct sock *, int, char __user *, int);
extern int ip6_mroute_getsockopt(struct sock *, int, char __user *, int __user *);
extern int ip6_mr_input(struct sk_buff *skb);
extern int ip6mr_ioctl(struct sock *sk, int cmd, void __user *arg);
extern void ip6_mr_init(void);
extern int ip6_mr_init(void);
extern void ip6_mr_cleanup(void);
#else
static inline
int ip6_mroute_setsockopt(struct sock *sock,
int optname, char __user *optval, int optlen)
{
return -ENOPROTOOPT;
}
static inline
int ip6_mroute_getsockopt(struct sock *sock,
int optname, char __user *optval, int __user *optlen)
{
return -ENOPROTOOPT;
}
static inline
int ip6mr_ioctl(struct sock *sk, int cmd, void __user *arg)
{
return -ENOIOCTLCMD;
}
static inline int ip6_mr_init(void)
{
return 0;
}
static inline void ip6_mr_cleanup(void)
{
return;
}
#endif
struct mif_device
{
......
......@@ -1479,14 +1479,15 @@ static int __init inet_init(void)
* Initialise the multicast router
*/
#if defined(CONFIG_IP_MROUTE)
ip_mr_init();
if (ip_mr_init())
printk(KERN_CRIT "inet_init: Cannot init ipv4 mroute\n");
#endif
/*
* Initialise per-cpu ipv4 mibs
*/
if (init_ipv4_mibs())
printk(KERN_CRIT "inet_init: Cannot init ipv4 mibs\n"); ;
printk(KERN_CRIT "inet_init: Cannot init ipv4 mibs\n");
ipv4_proc_init();
......
......@@ -1878,16 +1878,36 @@ static struct net_protocol pim_protocol = {
* Setup for IP multicast routing
*/
void __init ip_mr_init(void)
int __init ip_mr_init(void)
{
int err;
mrt_cachep = kmem_cache_create("ip_mrt_cache",
sizeof(struct mfc_cache),
0, SLAB_HWCACHE_ALIGN|SLAB_PANIC,
NULL);
if (!mrt_cachep)
return -ENOMEM;
setup_timer(&ipmr_expire_timer, ipmr_expire_process, 0);
register_netdevice_notifier(&ip_mr_notifier);
err = register_netdevice_notifier(&ip_mr_notifier);
if (err)
goto reg_notif_fail;
#ifdef CONFIG_PROC_FS
proc_net_fops_create(&init_net, "ip_mr_vif", 0, &ipmr_vif_fops);
proc_net_fops_create(&init_net, "ip_mr_cache", 0, &ipmr_mfc_fops);
err = -ENOMEM;
if (!proc_net_fops_create(&init_net, "ip_mr_vif", 0, &ipmr_vif_fops))
goto proc_vif_fail;
if (!proc_net_fops_create(&init_net, "ip_mr_cache", 0, &ipmr_mfc_fops))
goto proc_cache_fail;
#endif
return 0;
reg_notif_fail:
kmem_cache_destroy(mrt_cachep);
#ifdef CONFIG_PROC_FS
proc_vif_fail:
unregister_netdevice_notifier(&ip_mr_notifier);
proc_cache_fail:
proc_net_remove(&init_net, "ip_mr_vif");
#endif
return err;
}
......@@ -119,6 +119,7 @@ static void ipv6_regen_rndid(unsigned long data);
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);
/*
......@@ -183,6 +184,8 @@ struct ipv6_devconf ipv6_devconf __read_mostly = {
#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 = {
......@@ -215,6 +218,8 @@ 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 */
......@@ -378,6 +383,9 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *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
......@@ -578,6 +586,13 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
struct rt6_info *rt;
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) {
......@@ -1412,6 +1427,20 @@ static void addrconf_dad_stop(struct inet6_ifaddr *ifp)
void addrconf_dad_failure(struct inet6_ifaddr *ifp)
{
struct inet6_dev *idev = ifp->idev;
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;
}
}
if (net_ratelimit())
printk(KERN_INFO "%s: duplicate address detected!\n", ifp->idev->dev->name);
addrconf_dad_stop(ifp);
......@@ -2744,6 +2773,7 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags)
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);
......@@ -2791,6 +2821,11 @@ static void addrconf_dad_timer(unsigned long data)
read_unlock_bh(&idev->lock);
goto out;
}
if (idev->cnf.accept_dad > 1 && idev->cnf.disable_ipv6) {
read_unlock_bh(&idev->lock);
addrconf_dad_failure(ifp);
return;
}
spin_lock_bh(&ifp->lock);
if (ifp->probes == 0) {
/*
......@@ -3650,6 +3685,8 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf,
#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)
......@@ -4208,6 +4245,22 @@ static struct addrconf_sysctl_table
.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 */
}
......
......@@ -59,9 +59,7 @@
#include <asm/uaccess.h>
#include <asm/system.h>
#ifdef CONFIG_IPV6_MROUTE
#include <linux/mroute6.h>
#endif
MODULE_AUTHOR("Cast of dozens");
MODULE_DESCRIPTION("IPv6 protocol stack for Linux");
......@@ -952,9 +950,9 @@ static int __init inet6_init(void)
err = icmpv6_init();
if (err)
goto icmp_fail;
#ifdef CONFIG_IPV6_MROUTE
ip6_mr_init();
#endif
err = ip6_mr_init();
if (err)
goto ipmr_fail;
err = ndisc_init();
if (err)
goto ndisc_fail;
......@@ -1057,6 +1055,8 @@ static int __init inet6_init(void)
igmp_fail:
ndisc_cleanup();
ndisc_fail:
ip6_mr_cleanup();
ipmr_fail:
icmpv6_cleanup();
icmp_fail:
unregister_pernet_subsys(&inet6_net_ops);
......@@ -1111,6 +1111,7 @@ static void __exit inet6_exit(void)
ipv6_netfilter_fini();
igmp6_cleanup();
ndisc_cleanup();
ip6_mr_cleanup();
icmpv6_cleanup();
rawv6_exit();
......
......@@ -71,7 +71,8 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt
IP6_INC_STATS_BH(idev, IPSTATS_MIB_INRECEIVES);
if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) {
if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL ||
!idev || unlikely(idev->cnf.disable_ipv6)) {
IP6_INC_STATS_BH(idev, IPSTATS_MIB_INDISCARDS);
rcu_read_unlock();
goto out;
......
......@@ -173,6 +173,13 @@ static inline int ip6_skb_dst_mtu(struct sk_buff *skb)
int ip6_output(struct sk_buff *skb)
{
struct inet6_dev *idev = ip6_dst_idev(skb->dst);
if (unlikely(idev->cnf.disable_ipv6)) {
IP6_INC_STATS(idev, IPSTATS_MIB_OUTDISCARDS);
kfree_skb(skb);
return 0;
}
if ((skb->len > ip6_skb_dst_mtu(skb) && !skb_is_gso(skb)) ||
dst_allfrag(skb->dst))
return ip6_fragment(skb, ip6_output2);
......@@ -498,7 +505,8 @@ int ip6_forward(struct sk_buff *skb)
int addrtype = ipv6_addr_type(&hdr->saddr);
/* This check is security critical. */
if (addrtype & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LOOPBACK))
if (addrtype == IPV6_ADDR_ANY ||
addrtype & (IPV6_ADDR_MULTICAST | IPV6_ADDR_LOOPBACK))
goto error;
if (addrtype & IPV6_ADDR_LINKLOCAL) {
icmpv6_send(skb, ICMPV6_DEST_UNREACH,
......
......@@ -948,23 +948,51 @@ static struct notifier_block ip6_mr_notifier = {
* Setup for IP multicast routing
*/
void __init ip6_mr_init(void)
int __init ip6_mr_init(void)
{
int err;
mrt_cachep = kmem_cache_create("ip6_mrt_cache",
sizeof(struct mfc6_cache),
0, SLAB_HWCACHE_ALIGN,
NULL);
if (!mrt_cachep)
panic("cannot allocate ip6_mrt_cache");
return -ENOMEM;
setup_timer(&ipmr_expire_timer, ipmr_expire_process, 0);
register_netdevice_notifier(&ip6_mr_notifier);
err = register_netdevice_notifier(&ip6_mr_notifier);
if (err)
goto reg_notif_fail;
#ifdef CONFIG_PROC_FS
err = -ENOMEM;
if (!proc_net_fops_create(&init_net, "ip6_mr_vif", 0, &ip6mr_vif_fops))
goto proc_vif_fail;
if (!proc_net_fops_create(&init_net, "ip6_mr_cache",
0, &ip6mr_mfc_fops))
goto proc_cache_fail;
#endif
return 0;
reg_notif_fail:
kmem_cache_destroy(mrt_cachep);
#ifdef CONFIG_PROC_FS
proc_net_fops_create(&init_net, "ip6_mr_vif", 0, &ip6mr_vif_fops);
proc_net_fops_create(&init_net, "ip6_mr_cache", 0, &ip6mr_mfc_fops);
proc_vif_fail:
unregister_netdevice_notifier(&ip6_mr_notifier);
proc_cache_fail:
proc_net_remove(&init_net, "ip6_mr_vif");
#endif
return err;
}
void ip6_mr_cleanup(void)
{
#ifdef CONFIG_PROC_FS
proc_net_remove(&init_net, "ip6_mr_cache");
proc_net_remove(&init_net, "ip6_mr_vif");
#endif
unregister_netdevice_notifier(&ip6_mr_notifier);
del_timer(&ipmr_expire_timer);
kmem_cache_destroy(mrt_cachep);
}
static int ip6mr_mfc_add(struct mf6cctl *mfc, int mrtsock)
{
......
......@@ -228,7 +228,7 @@ static __inline__ int rt6_check_expired(const struct rt6_info *rt)
static inline int rt6_need_strict(struct in6_addr *daddr)
{
return (ipv6_addr_type(daddr) &
(IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL));
(IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL | IPV6_ADDR_LOOPBACK));
}
/*
......@@ -237,15 +237,20 @@ static inline int rt6_need_strict(struct in6_addr *daddr)
static inline struct rt6_info *rt6_device_match(struct net *net,
struct rt6_info *rt,
struct in6_addr *saddr,
int oif,
int flags)
{
struct rt6_info *local = NULL;
struct rt6_info *sprt;
if (oif) {
for (sprt = rt; sprt; sprt = sprt->u.dst.rt6_next) {
struct net_device *dev = sprt->rt6i_dev;
if (!oif && ipv6_addr_any(saddr))
goto out;
for (sprt = rt; sprt; sprt = sprt->u.dst.rt6_next) {
struct net_device *dev = sprt->rt6i_dev;
if (oif) {
if (dev->ifindex == oif)
return sprt;
if (dev->flags & IFF_LOOPBACK) {
......@@ -259,14 +264,21 @@ static inline struct rt6_info *rt6_device_match(struct net *net,
}
local = sprt;
}
} else {
if (ipv6_chk_addr(net, saddr, dev,
flags & RT6_LOOKUP_F_IFACE))
return sprt;
}
}
if (oif) {
if (local)
return local;
if (flags & RT6_LOOKUP_F_IFACE)
return net->ipv6.ip6_null_entry;
}
out:
return rt;
}
......@@ -539,7 +551,7 @@ static struct rt6_info *ip6_pol_route_lookup(struct net *net,
fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src);
restart:
rt = fn->leaf;
rt = rt6_device_match(net, rt, fl->oif, flags);
rt = rt6_device_match(net, rt, &fl->fl6_src, fl->oif, flags);
BACKTRACK(net, &fl->fl6_src);
out:
dst_use(&rt->u.dst, jiffies);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment