]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
Merge branch 'net-next-2.6-v6ready-20080703' of git://git.linux-ipv6.org/gitroot...
authorDavid S. Miller <davem@davemloft.net>
Thu, 3 Jul 2008 10:07:58 +0000 (03:07 -0700)
committerDavid S. Miller <davem@davemloft.net>
Thu, 3 Jul 2008 10:07:58 +0000 (03:07 -0700)
13 files changed:
Documentation/networking/ip-sysctl.txt
include/linux/igmp.h
include/linux/ipv6.h
include/linux/mroute.h
include/linux/mroute6.h
net/ipv4/af_inet.c
net/ipv4/ipmr.c
net/ipv6/addrconf.c
net/ipv6/af_inet6.c
net/ipv6/ip6_input.c
net/ipv6/ip6_output.c
net/ipv6/ip6mr.c
net/ipv6/route.c

index 71c7bea97160609f7c029a71fc9bf658772a5da5..72f6d52e52e6e6886321fa3af37248819a41262c 100644 (file)
@@ -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.
index f5a1a0db2e8ecb5d79c25d1483610c93e29546ac..7bb3c095c15b4fb33d0ffd227ac9d39f86b9d297 100644 (file)
@@ -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 *);
index cde056e0818172aeb7a5ae8d69998fb83d41796e..391ad0843a46af6b4af10abc5b7b552a26d95c0e 100644 (file)
@@ -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
 };
 
index de4decfa1bfc7a9ef0f0f3399055b34f33fd73f7..07112ee9293a5aa25b8186db6e19c990c7863f11 100644 (file)
@@ -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
 {
index e7989593142be626d5c73ecc18be5baf0497cd51..5cf50473a10f0f6877263bb822a59c865b66163f 100644 (file)
@@ -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
 {
index 42bd24b64b57b9ce84701de040c3686c2db950b5..dc411335c14fdb876e0576df3919ad33e25e7615 100644 (file)
@@ -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();
 
index 300ab0c2919e846d2cb1b148d64b02d43c7d38bc..438fab9c62a052cbdadc49d159b7d68a03b4815b 100644 (file)
@@ -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;
 }
index 84127d854cfcba1d2007d1149bfa96ef49363e83..2ec73e62202c18b741adc862168c7e0da854be3a 100644 (file)
@@ -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 */
                }
index 3ce8d2f318c6e385b349d4ae1171f8edc0b4c6ed..3d828bc4b1cf97cbfcbd1df9e76c5b357b37a9c4 100644 (file)
@@ -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 @@ netfilter_fail:
 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();
 
index 34e5a96623aece79e56c80a94d16d333df310273..ea81c614dde2be1cf70c42f955ab96af3489b29e 100644 (file)
@@ -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;
index fd7cd1bfe1510e4e71fcd000b02087a8c4280d97..0981c1ef305797322ab0b703a4aba609efcbbfc2 100644 (file)
@@ -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,
index 90e763073dc5fdebf09b4fd538594118c8215ec7..cfac26d674ede45d76fb199ce154297c7cf59609 100644 (file)
@@ -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)
 {
index 751e98f9b8b40fc5d2b5d797038a85a20cb3c121..5d6c166dfbb6e087e0f634d69d305d1f1912fdda 100644 (file)
@@ -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);