diff options
Diffstat (limited to 'net/ipv6')
41 files changed, 797 insertions, 979 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index de7a194a64ab..88fd8c5877ee 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
@@ -278,31 +278,31 @@ static void addrconf_mod_timer(struct inet6_ifaddr *ifp, | |||
278 | 278 | ||
279 | static int snmp6_alloc_dev(struct inet6_dev *idev) | 279 | static int snmp6_alloc_dev(struct inet6_dev *idev) |
280 | { | 280 | { |
281 | if (snmp_mib_init((void **)idev->stats.ipv6, | 281 | if (snmp_mib_init((void __percpu **)idev->stats.ipv6, |
282 | sizeof(struct ipstats_mib)) < 0) | 282 | sizeof(struct ipstats_mib)) < 0) |
283 | goto err_ip; | 283 | goto err_ip; |
284 | if (snmp_mib_init((void **)idev->stats.icmpv6, | 284 | if (snmp_mib_init((void __percpu **)idev->stats.icmpv6, |
285 | sizeof(struct icmpv6_mib)) < 0) | 285 | sizeof(struct icmpv6_mib)) < 0) |
286 | goto err_icmp; | 286 | goto err_icmp; |
287 | if (snmp_mib_init((void **)idev->stats.icmpv6msg, | 287 | if (snmp_mib_init((void __percpu **)idev->stats.icmpv6msg, |
288 | sizeof(struct icmpv6msg_mib)) < 0) | 288 | sizeof(struct icmpv6msg_mib)) < 0) |
289 | goto err_icmpmsg; | 289 | goto err_icmpmsg; |
290 | 290 | ||
291 | return 0; | 291 | return 0; |
292 | 292 | ||
293 | err_icmpmsg: | 293 | err_icmpmsg: |
294 | snmp_mib_free((void **)idev->stats.icmpv6); | 294 | snmp_mib_free((void __percpu **)idev->stats.icmpv6); |
295 | err_icmp: | 295 | err_icmp: |
296 | snmp_mib_free((void **)idev->stats.ipv6); | 296 | snmp_mib_free((void __percpu **)idev->stats.ipv6); |
297 | err_ip: | 297 | err_ip: |
298 | return -ENOMEM; | 298 | return -ENOMEM; |
299 | } | 299 | } |
300 | 300 | ||
301 | static void snmp6_free_dev(struct inet6_dev *idev) | 301 | static void snmp6_free_dev(struct inet6_dev *idev) |
302 | { | 302 | { |
303 | snmp_mib_free((void **)idev->stats.icmpv6msg); | 303 | snmp_mib_free((void __percpu **)idev->stats.icmpv6msg); |
304 | snmp_mib_free((void **)idev->stats.icmpv6); | 304 | snmp_mib_free((void __percpu **)idev->stats.icmpv6); |
305 | snmp_mib_free((void **)idev->stats.ipv6); | 305 | snmp_mib_free((void __percpu **)idev->stats.ipv6); |
306 | } | 306 | } |
307 | 307 | ||
308 | /* Nobody refers to this device, we may destroy it. */ | 308 | /* Nobody refers to this device, we may destroy it. */ |
@@ -502,8 +502,11 @@ static int addrconf_fixup_forwarding(struct ctl_table *table, int *p, int old) | |||
502 | if (p == &net->ipv6.devconf_dflt->forwarding) | 502 | if (p == &net->ipv6.devconf_dflt->forwarding) |
503 | return 0; | 503 | return 0; |
504 | 504 | ||
505 | if (!rtnl_trylock()) | 505 | if (!rtnl_trylock()) { |
506 | /* Restore the original values before restarting */ | ||
507 | *p = old; | ||
506 | return restart_syscall(); | 508 | return restart_syscall(); |
509 | } | ||
507 | 510 | ||
508 | if (p == &net->ipv6.devconf_all->forwarding) { | 511 | if (p == &net->ipv6.devconf_all->forwarding) { |
509 | __s32 newf = net->ipv6.devconf_all->forwarding; | 512 | __s32 newf = net->ipv6.devconf_all->forwarding; |
@@ -989,8 +992,7 @@ struct ipv6_saddr_dst { | |||
989 | 992 | ||
990 | static inline int ipv6_saddr_preferred(int type) | 993 | static inline int ipv6_saddr_preferred(int type) |
991 | { | 994 | { |
992 | if (type & (IPV6_ADDR_MAPPED|IPV6_ADDR_COMPATv4| | 995 | if (type & (IPV6_ADDR_MAPPED|IPV6_ADDR_COMPATv4|IPV6_ADDR_LOOPBACK)) |
993 | IPV6_ADDR_LOOPBACK|IPV6_ADDR_RESERVED)) | ||
994 | return 1; | 996 | return 1; |
995 | return 0; | 997 | return 0; |
996 | } | 998 | } |
@@ -2646,7 +2648,8 @@ static int addrconf_ifdown(struct net_device *dev, int how) | |||
2646 | 2648 | ||
2647 | write_lock_bh(&addrconf_hash_lock); | 2649 | write_lock_bh(&addrconf_hash_lock); |
2648 | while ((ifa = *bifa) != NULL) { | 2650 | while ((ifa = *bifa) != NULL) { |
2649 | if (ifa->idev == idev) { | 2651 | if (ifa->idev == idev && |
2652 | (how || !(ifa->flags&IFA_F_PERMANENT))) { | ||
2650 | *bifa = ifa->lst_next; | 2653 | *bifa = ifa->lst_next; |
2651 | ifa->lst_next = NULL; | 2654 | ifa->lst_next = NULL; |
2652 | addrconf_del_timer(ifa); | 2655 | addrconf_del_timer(ifa); |
@@ -2686,18 +2689,30 @@ static int addrconf_ifdown(struct net_device *dev, int how) | |||
2686 | write_lock_bh(&idev->lock); | 2689 | write_lock_bh(&idev->lock); |
2687 | } | 2690 | } |
2688 | #endif | 2691 | #endif |
2689 | while ((ifa = idev->addr_list) != NULL) { | 2692 | bifa = &idev->addr_list; |
2690 | idev->addr_list = ifa->if_next; | 2693 | while ((ifa = *bifa) != NULL) { |
2691 | ifa->if_next = NULL; | 2694 | if (how == 0 && (ifa->flags&IFA_F_PERMANENT)) { |
2692 | ifa->dead = 1; | 2695 | /* Retain permanent address on admin down */ |
2693 | addrconf_del_timer(ifa); | 2696 | bifa = &ifa->if_next; |
2694 | write_unlock_bh(&idev->lock); | 2697 | |
2698 | /* Restart DAD if needed when link comes back up */ | ||
2699 | if ( !((dev->flags&(IFF_NOARP|IFF_LOOPBACK)) || | ||
2700 | idev->cnf.accept_dad <= 0 || | ||
2701 | (ifa->flags & IFA_F_NODAD))) | ||
2702 | ifa->flags |= IFA_F_TENTATIVE; | ||
2703 | } else { | ||
2704 | *bifa = ifa->if_next; | ||
2705 | ifa->if_next = NULL; | ||
2695 | 2706 | ||
2696 | __ipv6_ifa_notify(RTM_DELADDR, ifa); | 2707 | ifa->dead = 1; |
2697 | atomic_notifier_call_chain(&inet6addr_chain, NETDEV_DOWN, ifa); | 2708 | write_unlock_bh(&idev->lock); |
2698 | in6_ifa_put(ifa); | ||
2699 | 2709 | ||
2700 | write_lock_bh(&idev->lock); | 2710 | __ipv6_ifa_notify(RTM_DELADDR, ifa); |
2711 | atomic_notifier_call_chain(&inet6addr_chain, NETDEV_DOWN, ifa); | ||
2712 | in6_ifa_put(ifa); | ||
2713 | |||
2714 | write_lock_bh(&idev->lock); | ||
2715 | } | ||
2701 | } | 2716 | } |
2702 | write_unlock_bh(&idev->lock); | 2717 | write_unlock_bh(&idev->lock); |
2703 | 2718 | ||
@@ -2789,14 +2804,14 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags) | |||
2789 | read_lock_bh(&idev->lock); | 2804 | read_lock_bh(&idev->lock); |
2790 | if (ifp->dead) | 2805 | if (ifp->dead) |
2791 | goto out; | 2806 | goto out; |
2792 | spin_lock_bh(&ifp->lock); | ||
2793 | 2807 | ||
2808 | spin_lock(&ifp->lock); | ||
2794 | if (dev->flags&(IFF_NOARP|IFF_LOOPBACK) || | 2809 | if (dev->flags&(IFF_NOARP|IFF_LOOPBACK) || |
2795 | idev->cnf.accept_dad < 1 || | 2810 | idev->cnf.accept_dad < 1 || |
2796 | !(ifp->flags&IFA_F_TENTATIVE) || | 2811 | !(ifp->flags&IFA_F_TENTATIVE) || |
2797 | ifp->flags & IFA_F_NODAD) { | 2812 | ifp->flags & IFA_F_NODAD) { |
2798 | ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC|IFA_F_DADFAILED); | 2813 | ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC|IFA_F_DADFAILED); |
2799 | spin_unlock_bh(&ifp->lock); | 2814 | spin_unlock(&ifp->lock); |
2800 | read_unlock_bh(&idev->lock); | 2815 | read_unlock_bh(&idev->lock); |
2801 | 2816 | ||
2802 | addrconf_dad_completed(ifp); | 2817 | addrconf_dad_completed(ifp); |
@@ -2804,7 +2819,7 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags) | |||
2804 | } | 2819 | } |
2805 | 2820 | ||
2806 | if (!(idev->if_flags & IF_READY)) { | 2821 | if (!(idev->if_flags & IF_READY)) { |
2807 | spin_unlock_bh(&ifp->lock); | 2822 | spin_unlock(&ifp->lock); |
2808 | read_unlock_bh(&idev->lock); | 2823 | read_unlock_bh(&idev->lock); |
2809 | /* | 2824 | /* |
2810 | * If the device is not ready: | 2825 | * If the device is not ready: |
@@ -2824,7 +2839,7 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags) | |||
2824 | ip6_ins_rt(ifp->rt); | 2839 | ip6_ins_rt(ifp->rt); |
2825 | 2840 | ||
2826 | addrconf_dad_kick(ifp); | 2841 | addrconf_dad_kick(ifp); |
2827 | spin_unlock_bh(&ifp->lock); | 2842 | spin_unlock(&ifp->lock); |
2828 | out: | 2843 | out: |
2829 | read_unlock_bh(&idev->lock); | 2844 | read_unlock_bh(&idev->lock); |
2830 | } | 2845 | } |
@@ -2840,14 +2855,15 @@ static void addrconf_dad_timer(unsigned long data) | |||
2840 | read_unlock_bh(&idev->lock); | 2855 | read_unlock_bh(&idev->lock); |
2841 | goto out; | 2856 | goto out; |
2842 | } | 2857 | } |
2843 | spin_lock_bh(&ifp->lock); | 2858 | |
2859 | spin_lock(&ifp->lock); | ||
2844 | if (ifp->probes == 0) { | 2860 | if (ifp->probes == 0) { |
2845 | /* | 2861 | /* |
2846 | * DAD was successful | 2862 | * DAD was successful |
2847 | */ | 2863 | */ |
2848 | 2864 | ||
2849 | ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC|IFA_F_DADFAILED); | 2865 | ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC|IFA_F_DADFAILED); |
2850 | spin_unlock_bh(&ifp->lock); | 2866 | spin_unlock(&ifp->lock); |
2851 | read_unlock_bh(&idev->lock); | 2867 | read_unlock_bh(&idev->lock); |
2852 | 2868 | ||
2853 | addrconf_dad_completed(ifp); | 2869 | addrconf_dad_completed(ifp); |
@@ -2857,7 +2873,7 @@ static void addrconf_dad_timer(unsigned long data) | |||
2857 | 2873 | ||
2858 | ifp->probes--; | 2874 | ifp->probes--; |
2859 | addrconf_mod_timer(ifp, AC_DAD, ifp->idev->nd_parms->retrans_time); | 2875 | addrconf_mod_timer(ifp, AC_DAD, ifp->idev->nd_parms->retrans_time); |
2860 | spin_unlock_bh(&ifp->lock); | 2876 | spin_unlock(&ifp->lock); |
2861 | read_unlock_bh(&idev->lock); | 2877 | read_unlock_bh(&idev->lock); |
2862 | 2878 | ||
2863 | /* send a neighbour solicitation for our addr */ | 2879 | /* send a neighbour solicitation for our addr */ |
@@ -2905,12 +2921,12 @@ static void addrconf_dad_run(struct inet6_dev *idev) { | |||
2905 | 2921 | ||
2906 | read_lock_bh(&idev->lock); | 2922 | read_lock_bh(&idev->lock); |
2907 | for (ifp = idev->addr_list; ifp; ifp = ifp->if_next) { | 2923 | for (ifp = idev->addr_list; ifp; ifp = ifp->if_next) { |
2908 | spin_lock_bh(&ifp->lock); | 2924 | spin_lock(&ifp->lock); |
2909 | if (!(ifp->flags & IFA_F_TENTATIVE)) { | 2925 | if (!(ifp->flags & IFA_F_TENTATIVE)) { |
2910 | spin_unlock_bh(&ifp->lock); | 2926 | spin_unlock(&ifp->lock); |
2911 | continue; | 2927 | continue; |
2912 | } | 2928 | } |
2913 | spin_unlock_bh(&ifp->lock); | 2929 | spin_unlock(&ifp->lock); |
2914 | addrconf_dad_kick(ifp); | 2930 | addrconf_dad_kick(ifp); |
2915 | } | 2931 | } |
2916 | read_unlock_bh(&idev->lock); | 2932 | read_unlock_bh(&idev->lock); |
@@ -3027,14 +3043,14 @@ static const struct file_operations if6_fops = { | |||
3027 | .release = seq_release_net, | 3043 | .release = seq_release_net, |
3028 | }; | 3044 | }; |
3029 | 3045 | ||
3030 | static int if6_proc_net_init(struct net *net) | 3046 | static int __net_init if6_proc_net_init(struct net *net) |
3031 | { | 3047 | { |
3032 | if (!proc_net_fops_create(net, "if_inet6", S_IRUGO, &if6_fops)) | 3048 | if (!proc_net_fops_create(net, "if_inet6", S_IRUGO, &if6_fops)) |
3033 | return -ENOMEM; | 3049 | return -ENOMEM; |
3034 | return 0; | 3050 | return 0; |
3035 | } | 3051 | } |
3036 | 3052 | ||
3037 | static void if6_proc_net_exit(struct net *net) | 3053 | static void __net_exit if6_proc_net_exit(struct net *net) |
3038 | { | 3054 | { |
3039 | proc_net_remove(net, "if_inet6"); | 3055 | proc_net_remove(net, "if_inet6"); |
3040 | } | 3056 | } |
@@ -3752,8 +3768,8 @@ static inline size_t inet6_if_nlmsg_size(void) | |||
3752 | ); | 3768 | ); |
3753 | } | 3769 | } |
3754 | 3770 | ||
3755 | static inline void __snmp6_fill_stats(u64 *stats, void **mib, int items, | 3771 | static inline void __snmp6_fill_stats(u64 *stats, void __percpu **mib, |
3756 | int bytes) | 3772 | int items, int bytes) |
3757 | { | 3773 | { |
3758 | int i; | 3774 | int i; |
3759 | int pad = bytes - sizeof(u64) * items; | 3775 | int pad = bytes - sizeof(u64) * items; |
@@ -3772,10 +3788,10 @@ static void snmp6_fill_stats(u64 *stats, struct inet6_dev *idev, int attrtype, | |||
3772 | { | 3788 | { |
3773 | switch(attrtype) { | 3789 | switch(attrtype) { |
3774 | case IFLA_INET6_STATS: | 3790 | case IFLA_INET6_STATS: |
3775 | __snmp6_fill_stats(stats, (void **)idev->stats.ipv6, IPSTATS_MIB_MAX, bytes); | 3791 | __snmp6_fill_stats(stats, (void __percpu **)idev->stats.ipv6, IPSTATS_MIB_MAX, bytes); |
3776 | break; | 3792 | break; |
3777 | case IFLA_INET6_ICMP6STATS: | 3793 | case IFLA_INET6_ICMP6STATS: |
3778 | __snmp6_fill_stats(stats, (void **)idev->stats.icmpv6, ICMP6_MIB_MAX, bytes); | 3794 | __snmp6_fill_stats(stats, (void __percpu **)idev->stats.icmpv6, ICMP6_MIB_MAX, bytes); |
3779 | break; | 3795 | break; |
3780 | } | 3796 | } |
3781 | } | 3797 | } |
@@ -4028,12 +4044,15 @@ int addrconf_sysctl_forward(ctl_table *ctl, int write, | |||
4028 | { | 4044 | { |
4029 | int *valp = ctl->data; | 4045 | int *valp = ctl->data; |
4030 | int val = *valp; | 4046 | int val = *valp; |
4047 | loff_t pos = *ppos; | ||
4031 | int ret; | 4048 | int ret; |
4032 | 4049 | ||
4033 | ret = proc_dointvec(ctl, write, buffer, lenp, ppos); | 4050 | ret = proc_dointvec(ctl, write, buffer, lenp, ppos); |
4034 | 4051 | ||
4035 | if (write) | 4052 | if (write) |
4036 | ret = addrconf_fixup_forwarding(ctl, valp, val); | 4053 | ret = addrconf_fixup_forwarding(ctl, valp, val); |
4054 | if (ret) | ||
4055 | *ppos = pos; | ||
4037 | return ret; | 4056 | return ret; |
4038 | } | 4057 | } |
4039 | 4058 | ||
@@ -4075,8 +4094,11 @@ static int addrconf_disable_ipv6(struct ctl_table *table, int *p, int old) | |||
4075 | if (p == &net->ipv6.devconf_dflt->disable_ipv6) | 4094 | if (p == &net->ipv6.devconf_dflt->disable_ipv6) |
4076 | return 0; | 4095 | return 0; |
4077 | 4096 | ||
4078 | if (!rtnl_trylock()) | 4097 | if (!rtnl_trylock()) { |
4098 | /* Restore the original values before restarting */ | ||
4099 | *p = old; | ||
4079 | return restart_syscall(); | 4100 | return restart_syscall(); |
4101 | } | ||
4080 | 4102 | ||
4081 | if (p == &net->ipv6.devconf_all->disable_ipv6) { | 4103 | if (p == &net->ipv6.devconf_all->disable_ipv6) { |
4082 | __s32 newf = net->ipv6.devconf_all->disable_ipv6; | 4104 | __s32 newf = net->ipv6.devconf_all->disable_ipv6; |
@@ -4095,12 +4117,15 @@ int addrconf_sysctl_disable(ctl_table *ctl, int write, | |||
4095 | { | 4117 | { |
4096 | int *valp = ctl->data; | 4118 | int *valp = ctl->data; |
4097 | int val = *valp; | 4119 | int val = *valp; |
4120 | loff_t pos = *ppos; | ||
4098 | int ret; | 4121 | int ret; |
4099 | 4122 | ||
4100 | ret = proc_dointvec(ctl, write, buffer, lenp, ppos); | 4123 | ret = proc_dointvec(ctl, write, buffer, lenp, ppos); |
4101 | 4124 | ||
4102 | if (write) | 4125 | if (write) |
4103 | ret = addrconf_disable_ipv6(ctl, valp, val); | 4126 | ret = addrconf_disable_ipv6(ctl, valp, val); |
4127 | if (ret) | ||
4128 | *ppos = pos; | ||
4104 | return ret; | 4129 | return ret; |
4105 | } | 4130 | } |
4106 | 4131 | ||
@@ -4402,8 +4427,7 @@ static void __addrconf_sysctl_unregister(struct ipv6_devconf *p) | |||
4402 | 4427 | ||
4403 | static void addrconf_sysctl_register(struct inet6_dev *idev) | 4428 | static void addrconf_sysctl_register(struct inet6_dev *idev) |
4404 | { | 4429 | { |
4405 | neigh_sysctl_register(idev->dev, idev->nd_parms, NET_IPV6, | 4430 | neigh_sysctl_register(idev->dev, idev->nd_parms, "ipv6", |
4406 | NET_IPV6_NEIGH, "ipv6", | ||
4407 | &ndisc_ifinfo_sysctl_change); | 4431 | &ndisc_ifinfo_sysctl_change); |
4408 | __addrconf_sysctl_register(dev_net(idev->dev), idev->dev->name, | 4432 | __addrconf_sysctl_register(dev_net(idev->dev), idev->dev->name, |
4409 | idev, &idev->cnf); | 4433 | idev, &idev->cnf); |
@@ -4418,7 +4442,7 @@ static void addrconf_sysctl_unregister(struct inet6_dev *idev) | |||
4418 | 4442 | ||
4419 | #endif | 4443 | #endif |
4420 | 4444 | ||
4421 | static int addrconf_init_net(struct net *net) | 4445 | static int __net_init addrconf_init_net(struct net *net) |
4422 | { | 4446 | { |
4423 | int err; | 4447 | int err; |
4424 | struct ipv6_devconf *all, *dflt; | 4448 | struct ipv6_devconf *all, *dflt; |
@@ -4467,7 +4491,7 @@ err_alloc_all: | |||
4467 | return err; | 4491 | return err; |
4468 | } | 4492 | } |
4469 | 4493 | ||
4470 | static void addrconf_exit_net(struct net *net) | 4494 | static void __net_exit addrconf_exit_net(struct net *net) |
4471 | { | 4495 | { |
4472 | #ifdef CONFIG_SYSCTL | 4496 | #ifdef CONFIG_SYSCTL |
4473 | __addrconf_sysctl_unregister(net->ipv6.devconf_dflt); | 4497 | __addrconf_sysctl_unregister(net->ipv6.devconf_dflt); |
diff --git a/net/ipv6/addrconf_core.c b/net/ipv6/addrconf_core.c index 3f82e9542eda..6b03826552e1 100644 --- a/net/ipv6/addrconf_core.c +++ b/net/ipv6/addrconf_core.c | |||
@@ -72,7 +72,7 @@ int __ipv6_addr_type(const struct in6_addr *addr) | |||
72 | IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL)); /* addr-select 3.3 */ | 72 | IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL)); /* addr-select 3.3 */ |
73 | } | 73 | } |
74 | 74 | ||
75 | return (IPV6_ADDR_RESERVED | | 75 | return (IPV6_ADDR_UNICAST | |
76 | IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL)); /* addr-select 3.4 */ | 76 | IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL)); /* addr-select 3.4 */ |
77 | } | 77 | } |
78 | EXPORT_SYMBOL(__ipv6_addr_type); | 78 | EXPORT_SYMBOL(__ipv6_addr_type); |
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 12e69d364dd5..37d14e735c27 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c | |||
@@ -971,41 +971,41 @@ static void ipv6_packet_cleanup(void) | |||
971 | 971 | ||
972 | static int __net_init ipv6_init_mibs(struct net *net) | 972 | static int __net_init ipv6_init_mibs(struct net *net) |
973 | { | 973 | { |
974 | if (snmp_mib_init((void **)net->mib.udp_stats_in6, | 974 | if (snmp_mib_init((void __percpu **)net->mib.udp_stats_in6, |
975 | sizeof (struct udp_mib)) < 0) | 975 | sizeof (struct udp_mib)) < 0) |
976 | return -ENOMEM; | 976 | return -ENOMEM; |
977 | if (snmp_mib_init((void **)net->mib.udplite_stats_in6, | 977 | if (snmp_mib_init((void __percpu **)net->mib.udplite_stats_in6, |
978 | sizeof (struct udp_mib)) < 0) | 978 | sizeof (struct udp_mib)) < 0) |
979 | goto err_udplite_mib; | 979 | goto err_udplite_mib; |
980 | if (snmp_mib_init((void **)net->mib.ipv6_statistics, | 980 | if (snmp_mib_init((void __percpu **)net->mib.ipv6_statistics, |
981 | sizeof(struct ipstats_mib)) < 0) | 981 | sizeof(struct ipstats_mib)) < 0) |
982 | goto err_ip_mib; | 982 | goto err_ip_mib; |
983 | if (snmp_mib_init((void **)net->mib.icmpv6_statistics, | 983 | if (snmp_mib_init((void __percpu **)net->mib.icmpv6_statistics, |
984 | sizeof(struct icmpv6_mib)) < 0) | 984 | sizeof(struct icmpv6_mib)) < 0) |
985 | goto err_icmp_mib; | 985 | goto err_icmp_mib; |
986 | if (snmp_mib_init((void **)net->mib.icmpv6msg_statistics, | 986 | if (snmp_mib_init((void __percpu **)net->mib.icmpv6msg_statistics, |
987 | sizeof(struct icmpv6msg_mib)) < 0) | 987 | sizeof(struct icmpv6msg_mib)) < 0) |
988 | goto err_icmpmsg_mib; | 988 | goto err_icmpmsg_mib; |
989 | return 0; | 989 | return 0; |
990 | 990 | ||
991 | err_icmpmsg_mib: | 991 | err_icmpmsg_mib: |
992 | snmp_mib_free((void **)net->mib.icmpv6_statistics); | 992 | snmp_mib_free((void __percpu **)net->mib.icmpv6_statistics); |
993 | err_icmp_mib: | 993 | err_icmp_mib: |
994 | snmp_mib_free((void **)net->mib.ipv6_statistics); | 994 | snmp_mib_free((void __percpu **)net->mib.ipv6_statistics); |
995 | err_ip_mib: | 995 | err_ip_mib: |
996 | snmp_mib_free((void **)net->mib.udplite_stats_in6); | 996 | snmp_mib_free((void __percpu **)net->mib.udplite_stats_in6); |
997 | err_udplite_mib: | 997 | err_udplite_mib: |
998 | snmp_mib_free((void **)net->mib.udp_stats_in6); | 998 | snmp_mib_free((void __percpu **)net->mib.udp_stats_in6); |
999 | return -ENOMEM; | 999 | return -ENOMEM; |
1000 | } | 1000 | } |
1001 | 1001 | ||
1002 | static void __net_exit ipv6_cleanup_mibs(struct net *net) | 1002 | static void ipv6_cleanup_mibs(struct net *net) |
1003 | { | 1003 | { |
1004 | snmp_mib_free((void **)net->mib.udp_stats_in6); | 1004 | snmp_mib_free((void __percpu **)net->mib.udp_stats_in6); |
1005 | snmp_mib_free((void **)net->mib.udplite_stats_in6); | 1005 | snmp_mib_free((void __percpu **)net->mib.udplite_stats_in6); |
1006 | snmp_mib_free((void **)net->mib.ipv6_statistics); | 1006 | snmp_mib_free((void __percpu **)net->mib.ipv6_statistics); |
1007 | snmp_mib_free((void **)net->mib.icmpv6_statistics); | 1007 | snmp_mib_free((void __percpu **)net->mib.icmpv6_statistics); |
1008 | snmp_mib_free((void **)net->mib.icmpv6msg_statistics); | 1008 | snmp_mib_free((void __percpu **)net->mib.icmpv6msg_statistics); |
1009 | } | 1009 | } |
1010 | 1010 | ||
1011 | static int __net_init inet6_net_init(struct net *net) | 1011 | static int __net_init inet6_net_init(struct net *net) |
@@ -1042,7 +1042,7 @@ out: | |||
1042 | #endif | 1042 | #endif |
1043 | } | 1043 | } |
1044 | 1044 | ||
1045 | static void inet6_net_exit(struct net *net) | 1045 | static void __net_exit inet6_net_exit(struct net *net) |
1046 | { | 1046 | { |
1047 | #ifdef CONFIG_PROC_FS | 1047 | #ifdef CONFIG_PROC_FS |
1048 | udp6_proc_exit(net); | 1048 | udp6_proc_exit(net); |
diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c index c2f300c314be..5ac89025f9de 100644 --- a/net/ipv6/ah6.c +++ b/net/ipv6/ah6.c | |||
@@ -614,7 +614,7 @@ static void ah6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
614 | type != ICMPV6_PKT_TOOBIG) | 614 | type != ICMPV6_PKT_TOOBIG) |
615 | return; | 615 | return; |
616 | 616 | ||
617 | x = xfrm_state_lookup(net, (xfrm_address_t *)&iph->daddr, ah->spi, IPPROTO_AH, AF_INET6); | 617 | x = xfrm_state_lookup(net, skb->mark, (xfrm_address_t *)&iph->daddr, ah->spi, IPPROTO_AH, AF_INET6); |
618 | if (!x) | 618 | if (!x) |
619 | return; | 619 | return; |
620 | 620 | ||
diff --git a/net/ipv6/anycast.c b/net/ipv6/anycast.c index f1c74c8ef9de..c4f6ca32fa74 100644 --- a/net/ipv6/anycast.c +++ b/net/ipv6/anycast.c | |||
@@ -538,7 +538,7 @@ static const struct file_operations ac6_seq_fops = { | |||
538 | .release = seq_release_net, | 538 | .release = seq_release_net, |
539 | }; | 539 | }; |
540 | 540 | ||
541 | int ac6_proc_init(struct net *net) | 541 | int __net_init ac6_proc_init(struct net *net) |
542 | { | 542 | { |
543 | if (!proc_net_fops_create(net, "anycast6", S_IRUGO, &ac6_seq_fops)) | 543 | if (!proc_net_fops_create(net, "anycast6", S_IRUGO, &ac6_seq_fops)) |
544 | return -ENOMEM; | 544 | return -ENOMEM; |
diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c index 668a46b655e6..ee9b93bdd6a2 100644 --- a/net/ipv6/esp6.c +++ b/net/ipv6/esp6.c | |||
@@ -365,7 +365,7 @@ static void esp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
365 | type != ICMPV6_PKT_TOOBIG) | 365 | type != ICMPV6_PKT_TOOBIG) |
366 | return; | 366 | return; |
367 | 367 | ||
368 | x = xfrm_state_lookup(net, (xfrm_address_t *)&iph->daddr, esph->spi, IPPROTO_ESP, AF_INET6); | 368 | x = xfrm_state_lookup(net, skb->mark, (xfrm_address_t *)&iph->daddr, esph->spi, IPPROTO_ESP, AF_INET6); |
369 | if (!x) | 369 | if (!x) |
370 | return; | 370 | return; |
371 | printk(KERN_DEBUG "pmtu discovery on SA ESP/%08x/%pI6\n", | 371 | printk(KERN_DEBUG "pmtu discovery on SA ESP/%08x/%pI6\n", |
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c index 4bac362b1335..074f2c084f9f 100644 --- a/net/ipv6/exthdrs.c +++ b/net/ipv6/exthdrs.c | |||
@@ -481,7 +481,7 @@ looped_back: | |||
481 | IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)), | 481 | IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)), |
482 | IPSTATS_MIB_INHDRERRORS); | 482 | IPSTATS_MIB_INHDRERRORS); |
483 | icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT, | 483 | icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT, |
484 | 0, skb->dev); | 484 | 0); |
485 | kfree_skb(skb); | 485 | kfree_skb(skb); |
486 | return -1; | 486 | return -1; |
487 | } | 487 | } |
diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c index b7aa7c64cc4a..551882b9dfd6 100644 --- a/net/ipv6/fib6_rules.c +++ b/net/ipv6/fib6_rules.c | |||
@@ -262,7 +262,7 @@ static struct fib_rules_ops fib6_rules_ops_template = { | |||
262 | .fro_net = &init_net, | 262 | .fro_net = &init_net, |
263 | }; | 263 | }; |
264 | 264 | ||
265 | static int fib6_rules_net_init(struct net *net) | 265 | static int __net_init fib6_rules_net_init(struct net *net) |
266 | { | 266 | { |
267 | struct fib_rules_ops *ops; | 267 | struct fib_rules_ops *ops; |
268 | int err = -ENOMEM; | 268 | int err = -ENOMEM; |
@@ -291,7 +291,7 @@ out_fib6_rules_ops: | |||
291 | goto out; | 291 | goto out; |
292 | } | 292 | } |
293 | 293 | ||
294 | static void fib6_rules_net_exit(struct net *net) | 294 | static void __net_exit fib6_rules_net_exit(struct net *net) |
295 | { | 295 | { |
296 | fib_rules_unregister(net->ipv6.fib6_rules_ops); | 296 | fib_rules_unregister(net->ipv6.fib6_rules_ops); |
297 | } | 297 | } |
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 4ae661bc3677..eb9abe24bdf0 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c | |||
@@ -67,11 +67,6 @@ | |||
67 | #include <asm/uaccess.h> | 67 | #include <asm/uaccess.h> |
68 | #include <asm/system.h> | 68 | #include <asm/system.h> |
69 | 69 | ||
70 | DEFINE_SNMP_STAT(struct icmpv6_mib, icmpv6_statistics) __read_mostly; | ||
71 | EXPORT_SYMBOL(icmpv6_statistics); | ||
72 | DEFINE_SNMP_STAT(struct icmpv6msg_mib, icmpv6msg_statistics) __read_mostly; | ||
73 | EXPORT_SYMBOL(icmpv6msg_statistics); | ||
74 | |||
75 | /* | 70 | /* |
76 | * The ICMP socket(s). This is the most convenient way to flow control | 71 | * The ICMP socket(s). This is the most convenient way to flow control |
77 | * our ICMP output as well as maintain a clean interface throughout | 72 | * our ICMP output as well as maintain a clean interface throughout |
@@ -119,7 +114,7 @@ static __inline__ void icmpv6_xmit_unlock(struct sock *sk) | |||
119 | */ | 114 | */ |
120 | void icmpv6_param_prob(struct sk_buff *skb, u8 code, int pos) | 115 | void icmpv6_param_prob(struct sk_buff *skb, u8 code, int pos) |
121 | { | 116 | { |
122 | icmpv6_send(skb, ICMPV6_PARAMPROB, code, pos, skb->dev); | 117 | icmpv6_send(skb, ICMPV6_PARAMPROB, code, pos); |
123 | kfree_skb(skb); | 118 | kfree_skb(skb); |
124 | } | 119 | } |
125 | 120 | ||
@@ -305,8 +300,7 @@ static inline void mip6_addr_swap(struct sk_buff *skb) {} | |||
305 | /* | 300 | /* |
306 | * Send an ICMP message in response to a packet in error | 301 | * Send an ICMP message in response to a packet in error |
307 | */ | 302 | */ |
308 | void icmpv6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info, | 303 | void icmpv6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info) |
309 | struct net_device *dev) | ||
310 | { | 304 | { |
311 | struct net *net = dev_net(skb->dev); | 305 | struct net *net = dev_net(skb->dev); |
312 | struct inet6_dev *idev = NULL; | 306 | struct inet6_dev *idev = NULL; |
@@ -951,7 +945,7 @@ ctl_table ipv6_icmp_table_template[] = { | |||
951 | { }, | 945 | { }, |
952 | }; | 946 | }; |
953 | 947 | ||
954 | struct ctl_table *ipv6_icmp_sysctl_init(struct net *net) | 948 | struct ctl_table * __net_init ipv6_icmp_sysctl_init(struct net *net) |
955 | { | 949 | { |
956 | struct ctl_table *table; | 950 | struct ctl_table *table; |
957 | 951 | ||
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 0e93ca56eb69..2f9847924fa5 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c | |||
@@ -93,29 +93,20 @@ static __u32 rt_sernum; | |||
93 | 93 | ||
94 | static void fib6_gc_timer_cb(unsigned long arg); | 94 | static void fib6_gc_timer_cb(unsigned long arg); |
95 | 95 | ||
96 | static struct fib6_walker_t fib6_walker_list = { | 96 | static LIST_HEAD(fib6_walkers); |
97 | .prev = &fib6_walker_list, | 97 | #define FOR_WALKERS(w) list_for_each_entry(w, &fib6_walkers, lh) |
98 | .next = &fib6_walker_list, | ||
99 | }; | ||
100 | |||
101 | #define FOR_WALKERS(w) for ((w)=fib6_walker_list.next; (w) != &fib6_walker_list; (w)=(w)->next) | ||
102 | 98 | ||
103 | static inline void fib6_walker_link(struct fib6_walker_t *w) | 99 | static inline void fib6_walker_link(struct fib6_walker_t *w) |
104 | { | 100 | { |
105 | write_lock_bh(&fib6_walker_lock); | 101 | write_lock_bh(&fib6_walker_lock); |
106 | w->next = fib6_walker_list.next; | 102 | list_add(&w->lh, &fib6_walkers); |
107 | w->prev = &fib6_walker_list; | ||
108 | w->next->prev = w; | ||
109 | w->prev->next = w; | ||
110 | write_unlock_bh(&fib6_walker_lock); | 103 | write_unlock_bh(&fib6_walker_lock); |
111 | } | 104 | } |
112 | 105 | ||
113 | static inline void fib6_walker_unlink(struct fib6_walker_t *w) | 106 | static inline void fib6_walker_unlink(struct fib6_walker_t *w) |
114 | { | 107 | { |
115 | write_lock_bh(&fib6_walker_lock); | 108 | write_lock_bh(&fib6_walker_lock); |
116 | w->next->prev = w->prev; | 109 | list_del(&w->lh); |
117 | w->prev->next = w->next; | ||
118 | w->prev = w->next = w; | ||
119 | write_unlock_bh(&fib6_walker_lock); | 110 | write_unlock_bh(&fib6_walker_lock); |
120 | } | 111 | } |
121 | static __inline__ u32 fib6_new_sernum(void) | 112 | static __inline__ u32 fib6_new_sernum(void) |
@@ -239,7 +230,7 @@ struct fib6_table *fib6_get_table(struct net *net, u32 id) | |||
239 | return NULL; | 230 | return NULL; |
240 | } | 231 | } |
241 | 232 | ||
242 | static void fib6_tables_init(struct net *net) | 233 | static void __net_init fib6_tables_init(struct net *net) |
243 | { | 234 | { |
244 | fib6_link_table(net, net->ipv6.fib6_main_tbl); | 235 | fib6_link_table(net, net->ipv6.fib6_main_tbl); |
245 | fib6_link_table(net, net->ipv6.fib6_local_tbl); | 236 | fib6_link_table(net, net->ipv6.fib6_local_tbl); |
@@ -262,7 +253,7 @@ struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi *fl, | |||
262 | return (struct dst_entry *) lookup(net, net->ipv6.fib6_main_tbl, fl, flags); | 253 | return (struct dst_entry *) lookup(net, net->ipv6.fib6_main_tbl, fl, flags); |
263 | } | 254 | } |
264 | 255 | ||
265 | static void fib6_tables_init(struct net *net) | 256 | static void __net_init fib6_tables_init(struct net *net) |
266 | { | 257 | { |
267 | fib6_link_table(net, net->ipv6.fib6_main_tbl); | 258 | fib6_link_table(net, net->ipv6.fib6_main_tbl); |
268 | } | 259 | } |
@@ -319,12 +310,26 @@ static int fib6_dump_table(struct fib6_table *table, struct sk_buff *skb, | |||
319 | w->root = &table->tb6_root; | 310 | w->root = &table->tb6_root; |
320 | 311 | ||
321 | if (cb->args[4] == 0) { | 312 | if (cb->args[4] == 0) { |
313 | w->count = 0; | ||
314 | w->skip = 0; | ||
315 | |||
322 | read_lock_bh(&table->tb6_lock); | 316 | read_lock_bh(&table->tb6_lock); |
323 | res = fib6_walk(w); | 317 | res = fib6_walk(w); |
324 | read_unlock_bh(&table->tb6_lock); | 318 | read_unlock_bh(&table->tb6_lock); |
325 | if (res > 0) | 319 | if (res > 0) { |
326 | cb->args[4] = 1; | 320 | cb->args[4] = 1; |
321 | cb->args[5] = w->root->fn_sernum; | ||
322 | } | ||
327 | } else { | 323 | } else { |
324 | if (cb->args[5] != w->root->fn_sernum) { | ||
325 | /* Begin at the root if the tree changed */ | ||
326 | cb->args[5] = w->root->fn_sernum; | ||
327 | w->state = FWS_INIT; | ||
328 | w->node = w->root; | ||
329 | w->skip = w->count; | ||
330 | } else | ||
331 | w->skip = 0; | ||
332 | |||
328 | read_lock_bh(&table->tb6_lock); | 333 | read_lock_bh(&table->tb6_lock); |
329 | res = fib6_walk_continue(w); | 334 | res = fib6_walk_continue(w); |
330 | read_unlock_bh(&table->tb6_lock); | 335 | read_unlock_bh(&table->tb6_lock); |
@@ -1250,9 +1255,18 @@ static int fib6_walk_continue(struct fib6_walker_t *w) | |||
1250 | w->leaf = fn->leaf; | 1255 | w->leaf = fn->leaf; |
1251 | case FWS_C: | 1256 | case FWS_C: |
1252 | if (w->leaf && fn->fn_flags&RTN_RTINFO) { | 1257 | if (w->leaf && fn->fn_flags&RTN_RTINFO) { |
1253 | int err = w->func(w); | 1258 | int err; |
1259 | |||
1260 | if (w->count < w->skip) { | ||
1261 | w->count++; | ||
1262 | continue; | ||
1263 | } | ||
1264 | |||
1265 | err = w->func(w); | ||
1254 | if (err) | 1266 | if (err) |
1255 | return err; | 1267 | return err; |
1268 | |||
1269 | w->count++; | ||
1256 | continue; | 1270 | continue; |
1257 | } | 1271 | } |
1258 | w->state = FWS_U; | 1272 | w->state = FWS_U; |
@@ -1346,6 +1360,8 @@ static void fib6_clean_tree(struct net *net, struct fib6_node *root, | |||
1346 | c.w.root = root; | 1360 | c.w.root = root; |
1347 | c.w.func = fib6_clean_node; | 1361 | c.w.func = fib6_clean_node; |
1348 | c.w.prune = prune; | 1362 | c.w.prune = prune; |
1363 | c.w.count = 0; | ||
1364 | c.w.skip = 0; | ||
1349 | c.func = func; | 1365 | c.func = func; |
1350 | c.arg = arg; | 1366 | c.arg = arg; |
1351 | c.net = net; | 1367 | c.net = net; |
@@ -1469,7 +1485,7 @@ static void fib6_gc_timer_cb(unsigned long arg) | |||
1469 | fib6_run_gc(0, (struct net *)arg); | 1485 | fib6_run_gc(0, (struct net *)arg); |
1470 | } | 1486 | } |
1471 | 1487 | ||
1472 | static int fib6_net_init(struct net *net) | 1488 | static int __net_init fib6_net_init(struct net *net) |
1473 | { | 1489 | { |
1474 | setup_timer(&net->ipv6.ip6_fib_timer, fib6_gc_timer_cb, (unsigned long)net); | 1490 | setup_timer(&net->ipv6.ip6_fib_timer, fib6_gc_timer_cb, (unsigned long)net); |
1475 | 1491 | ||
diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c index 6e7bffa2205e..e41eba8aacf1 100644 --- a/net/ipv6/ip6_flowlabel.c +++ b/net/ipv6/ip6_flowlabel.c | |||
@@ -154,7 +154,7 @@ static void ip6_fl_gc(unsigned long dummy) | |||
154 | write_unlock(&ip6_fl_lock); | 154 | write_unlock(&ip6_fl_lock); |
155 | } | 155 | } |
156 | 156 | ||
157 | static void ip6_fl_purge(struct net *net) | 157 | static void __net_exit ip6_fl_purge(struct net *net) |
158 | { | 158 | { |
159 | int i; | 159 | int i; |
160 | 160 | ||
@@ -735,7 +735,7 @@ static const struct file_operations ip6fl_seq_fops = { | |||
735 | .release = seq_release_net, | 735 | .release = seq_release_net, |
736 | }; | 736 | }; |
737 | 737 | ||
738 | static int ip6_flowlabel_proc_init(struct net *net) | 738 | static int __net_init ip6_flowlabel_proc_init(struct net *net) |
739 | { | 739 | { |
740 | if (!proc_net_fops_create(net, "ip6_flowlabel", | 740 | if (!proc_net_fops_create(net, "ip6_flowlabel", |
741 | S_IRUGO, &ip6fl_seq_fops)) | 741 | S_IRUGO, &ip6fl_seq_fops)) |
@@ -743,7 +743,7 @@ static int ip6_flowlabel_proc_init(struct net *net) | |||
743 | return 0; | 743 | return 0; |
744 | } | 744 | } |
745 | 745 | ||
746 | static void ip6_flowlabel_proc_fini(struct net *net) | 746 | static void __net_exit ip6_flowlabel_proc_fini(struct net *net) |
747 | { | 747 | { |
748 | proc_net_remove(net, "ip6_flowlabel"); | 748 | proc_net_remove(net, "ip6_flowlabel"); |
749 | } | 749 | } |
@@ -754,11 +754,10 @@ static inline int ip6_flowlabel_proc_init(struct net *net) | |||
754 | } | 754 | } |
755 | static inline void ip6_flowlabel_proc_fini(struct net *net) | 755 | static inline void ip6_flowlabel_proc_fini(struct net *net) |
756 | { | 756 | { |
757 | return ; | ||
758 | } | 757 | } |
759 | #endif | 758 | #endif |
760 | 759 | ||
761 | static inline void ip6_flowlabel_net_exit(struct net *net) | 760 | static void __net_exit ip6_flowlabel_net_exit(struct net *net) |
762 | { | 761 | { |
763 | ip6_fl_purge(net); | 762 | ip6_fl_purge(net); |
764 | ip6_flowlabel_proc_fini(net); | 763 | ip6_flowlabel_proc_fini(net); |
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c index 237e2dba6e94..e28f9203deca 100644 --- a/net/ipv6/ip6_input.c +++ b/net/ipv6/ip6_input.c | |||
@@ -216,8 +216,7 @@ resubmit: | |||
216 | IP6_INC_STATS_BH(net, idev, | 216 | IP6_INC_STATS_BH(net, idev, |
217 | IPSTATS_MIB_INUNKNOWNPROTOS); | 217 | IPSTATS_MIB_INUNKNOWNPROTOS); |
218 | icmpv6_send(skb, ICMPV6_PARAMPROB, | 218 | icmpv6_send(skb, ICMPV6_PARAMPROB, |
219 | ICMPV6_UNK_NEXTHDR, nhoff, | 219 | ICMPV6_UNK_NEXTHDR, nhoff); |
220 | skb->dev); | ||
221 | } | 220 | } |
222 | } else | 221 | } else |
223 | IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_INDELIVERS); | 222 | IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_INDELIVERS); |
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index eb6d09728633..dabf108ad811 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c | |||
@@ -267,7 +267,7 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl, | |||
267 | if (net_ratelimit()) | 267 | if (net_ratelimit()) |
268 | printk(KERN_DEBUG "IPv6: sending pkt_too_big to self\n"); | 268 | printk(KERN_DEBUG "IPv6: sending pkt_too_big to self\n"); |
269 | skb->dev = dst->dev; | 269 | skb->dev = dst->dev; |
270 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev); | 270 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); |
271 | IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_FRAGFAILS); | 271 | IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_FRAGFAILS); |
272 | kfree_skb(skb); | 272 | kfree_skb(skb); |
273 | return -EMSGSIZE; | 273 | return -EMSGSIZE; |
@@ -402,6 +402,7 @@ int ip6_forward(struct sk_buff *skb) | |||
402 | struct ipv6hdr *hdr = ipv6_hdr(skb); | 402 | struct ipv6hdr *hdr = ipv6_hdr(skb); |
403 | struct inet6_skb_parm *opt = IP6CB(skb); | 403 | struct inet6_skb_parm *opt = IP6CB(skb); |
404 | struct net *net = dev_net(dst->dev); | 404 | struct net *net = dev_net(dst->dev); |
405 | u32 mtu; | ||
405 | 406 | ||
406 | if (net->ipv6.devconf_all->forwarding == 0) | 407 | if (net->ipv6.devconf_all->forwarding == 0) |
407 | goto error; | 408 | goto error; |
@@ -441,8 +442,7 @@ int ip6_forward(struct sk_buff *skb) | |||
441 | if (hdr->hop_limit <= 1) { | 442 | if (hdr->hop_limit <= 1) { |
442 | /* Force OUTPUT device used as source address */ | 443 | /* Force OUTPUT device used as source address */ |
443 | skb->dev = dst->dev; | 444 | skb->dev = dst->dev; |
444 | icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT, | 445 | icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT, 0); |
445 | 0, skb->dev); | ||
446 | IP6_INC_STATS_BH(net, | 446 | IP6_INC_STATS_BH(net, |
447 | ip6_dst_idev(dst), IPSTATS_MIB_INHDRERRORS); | 447 | ip6_dst_idev(dst), IPSTATS_MIB_INHDRERRORS); |
448 | 448 | ||
@@ -504,15 +504,19 @@ int ip6_forward(struct sk_buff *skb) | |||
504 | goto error; | 504 | goto error; |
505 | if (addrtype & IPV6_ADDR_LINKLOCAL) { | 505 | if (addrtype & IPV6_ADDR_LINKLOCAL) { |
506 | icmpv6_send(skb, ICMPV6_DEST_UNREACH, | 506 | icmpv6_send(skb, ICMPV6_DEST_UNREACH, |
507 | ICMPV6_NOT_NEIGHBOUR, 0, skb->dev); | 507 | ICMPV6_NOT_NEIGHBOUR, 0); |
508 | goto error; | 508 | goto error; |
509 | } | 509 | } |
510 | } | 510 | } |
511 | 511 | ||
512 | if (skb->len > dst_mtu(dst)) { | 512 | mtu = dst_mtu(dst); |
513 | if (mtu < IPV6_MIN_MTU) | ||
514 | mtu = IPV6_MIN_MTU; | ||
515 | |||
516 | if (skb->len > mtu) { | ||
513 | /* Again, force OUTPUT device used as source address */ | 517 | /* Again, force OUTPUT device used as source address */ |
514 | skb->dev = dst->dev; | 518 | skb->dev = dst->dev; |
515 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, dst_mtu(dst), skb->dev); | 519 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); |
516 | IP6_INC_STATS_BH(net, | 520 | IP6_INC_STATS_BH(net, |
517 | ip6_dst_idev(dst), IPSTATS_MIB_INTOOBIGERRORS); | 521 | ip6_dst_idev(dst), IPSTATS_MIB_INTOOBIGERRORS); |
518 | IP6_INC_STATS_BH(net, | 522 | IP6_INC_STATS_BH(net, |
@@ -622,12 +626,11 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) | |||
622 | mtu = ip6_skb_dst_mtu(skb); | 626 | mtu = ip6_skb_dst_mtu(skb); |
623 | 627 | ||
624 | /* We must not fragment if the socket is set to force MTU discovery | 628 | /* We must not fragment if the socket is set to force MTU discovery |
625 | * or if the skb it not generated by a local socket. (This last | 629 | * or if the skb it not generated by a local socket. |
626 | * check should be redundant, but it's free.) | ||
627 | */ | 630 | */ |
628 | if (!skb->local_df) { | 631 | if (!skb->local_df) { |
629 | skb->dev = skb_dst(skb)->dev; | 632 | skb->dev = skb_dst(skb)->dev; |
630 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev); | 633 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); |
631 | IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), | 634 | IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), |
632 | IPSTATS_MIB_FRAGFAILS); | 635 | IPSTATS_MIB_FRAGFAILS); |
633 | kfree_skb(skb); | 636 | kfree_skb(skb); |
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index d453d07b0dfe..138980eec214 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c | |||
@@ -74,7 +74,6 @@ MODULE_LICENSE("GPL"); | |||
74 | (addr)->s6_addr32[2] ^ (addr)->s6_addr32[3]) & \ | 74 | (addr)->s6_addr32[2] ^ (addr)->s6_addr32[3]) & \ |
75 | (HASH_SIZE - 1)) | 75 | (HASH_SIZE - 1)) |
76 | 76 | ||
77 | static void ip6_fb_tnl_dev_init(struct net_device *dev); | ||
78 | static void ip6_tnl_dev_init(struct net_device *dev); | 77 | static void ip6_tnl_dev_init(struct net_device *dev); |
79 | static void ip6_tnl_dev_setup(struct net_device *dev); | 78 | static void ip6_tnl_dev_setup(struct net_device *dev); |
80 | 79 | ||
@@ -623,7 +622,7 @@ ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
623 | if (rt && rt->rt6i_dev) | 622 | if (rt && rt->rt6i_dev) |
624 | skb2->dev = rt->rt6i_dev; | 623 | skb2->dev = rt->rt6i_dev; |
625 | 624 | ||
626 | icmpv6_send(skb2, rel_type, rel_code, rel_info, skb2->dev); | 625 | icmpv6_send(skb2, rel_type, rel_code, rel_info); |
627 | 626 | ||
628 | if (rt) | 627 | if (rt) |
629 | dst_release(&rt->u.dst); | 628 | dst_release(&rt->u.dst); |
@@ -1015,7 +1014,7 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev) | |||
1015 | tel = (struct ipv6_tlv_tnl_enc_lim *)&skb_network_header(skb)[offset]; | 1014 | tel = (struct ipv6_tlv_tnl_enc_lim *)&skb_network_header(skb)[offset]; |
1016 | if (tel->encap_limit == 0) { | 1015 | if (tel->encap_limit == 0) { |
1017 | icmpv6_send(skb, ICMPV6_PARAMPROB, | 1016 | icmpv6_send(skb, ICMPV6_PARAMPROB, |
1018 | ICMPV6_HDR_FIELD, offset + 2, skb->dev); | 1017 | ICMPV6_HDR_FIELD, offset + 2); |
1019 | return -1; | 1018 | return -1; |
1020 | } | 1019 | } |
1021 | encap_limit = tel->encap_limit - 1; | 1020 | encap_limit = tel->encap_limit - 1; |
@@ -1034,7 +1033,7 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev) | |||
1034 | err = ip6_tnl_xmit2(skb, dev, dsfield, &fl, encap_limit, &mtu); | 1033 | err = ip6_tnl_xmit2(skb, dev, dsfield, &fl, encap_limit, &mtu); |
1035 | if (err != 0) { | 1034 | if (err != 0) { |
1036 | if (err == -EMSGSIZE) | 1035 | if (err == -EMSGSIZE) |
1037 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, dev); | 1036 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); |
1038 | return -1; | 1037 | return -1; |
1039 | } | 1038 | } |
1040 | 1039 | ||
@@ -1364,7 +1363,7 @@ static void ip6_tnl_dev_init(struct net_device *dev) | |||
1364 | * Return: 0 | 1363 | * Return: 0 |
1365 | **/ | 1364 | **/ |
1366 | 1365 | ||
1367 | static void ip6_fb_tnl_dev_init(struct net_device *dev) | 1366 | static void __net_init ip6_fb_tnl_dev_init(struct net_device *dev) |
1368 | { | 1367 | { |
1369 | struct ip6_tnl *t = netdev_priv(dev); | 1368 | struct ip6_tnl *t = netdev_priv(dev); |
1370 | struct net *net = dev_net(dev); | 1369 | struct net *net = dev_net(dev); |
@@ -1388,7 +1387,7 @@ static struct xfrm6_tunnel ip6ip6_handler = { | |||
1388 | .priority = 1, | 1387 | .priority = 1, |
1389 | }; | 1388 | }; |
1390 | 1389 | ||
1391 | static void ip6_tnl_destroy_tunnels(struct ip6_tnl_net *ip6n) | 1390 | static void __net_exit ip6_tnl_destroy_tunnels(struct ip6_tnl_net *ip6n) |
1392 | { | 1391 | { |
1393 | int h; | 1392 | int h; |
1394 | struct ip6_tnl *t; | 1393 | struct ip6_tnl *t; |
@@ -1407,7 +1406,7 @@ static void ip6_tnl_destroy_tunnels(struct ip6_tnl_net *ip6n) | |||
1407 | unregister_netdevice_many(&list); | 1406 | unregister_netdevice_many(&list); |
1408 | } | 1407 | } |
1409 | 1408 | ||
1410 | static int ip6_tnl_init_net(struct net *net) | 1409 | static int __net_init ip6_tnl_init_net(struct net *net) |
1411 | { | 1410 | { |
1412 | struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); | 1411 | struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); |
1413 | int err; | 1412 | int err; |
@@ -1436,7 +1435,7 @@ err_alloc_dev: | |||
1436 | return err; | 1435 | return err; |
1437 | } | 1436 | } |
1438 | 1437 | ||
1439 | static void ip6_tnl_exit_net(struct net *net) | 1438 | static void __net_exit ip6_tnl_exit_net(struct net *net) |
1440 | { | 1439 | { |
1441 | struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); | 1440 | struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); |
1442 | 1441 | ||
@@ -1462,27 +1461,29 @@ static int __init ip6_tunnel_init(void) | |||
1462 | { | 1461 | { |
1463 | int err; | 1462 | int err; |
1464 | 1463 | ||
1465 | if (xfrm6_tunnel_register(&ip4ip6_handler, AF_INET)) { | 1464 | err = register_pernet_device(&ip6_tnl_net_ops); |
1465 | if (err < 0) | ||
1466 | goto out_pernet; | ||
1467 | |||
1468 | err = xfrm6_tunnel_register(&ip4ip6_handler, AF_INET); | ||
1469 | if (err < 0) { | ||
1466 | printk(KERN_ERR "ip6_tunnel init: can't register ip4ip6\n"); | 1470 | printk(KERN_ERR "ip6_tunnel init: can't register ip4ip6\n"); |
1467 | err = -EAGAIN; | 1471 | goto out_ip4ip6; |
1468 | goto out; | ||
1469 | } | 1472 | } |
1470 | 1473 | ||
1471 | if (xfrm6_tunnel_register(&ip6ip6_handler, AF_INET6)) { | 1474 | err = xfrm6_tunnel_register(&ip6ip6_handler, AF_INET6); |
1475 | if (err < 0) { | ||
1472 | printk(KERN_ERR "ip6_tunnel init: can't register ip6ip6\n"); | 1476 | printk(KERN_ERR "ip6_tunnel init: can't register ip6ip6\n"); |
1473 | err = -EAGAIN; | 1477 | goto out_ip6ip6; |
1474 | goto unreg_ip4ip6; | ||
1475 | } | 1478 | } |
1476 | 1479 | ||
1477 | err = register_pernet_device(&ip6_tnl_net_ops); | ||
1478 | if (err < 0) | ||
1479 | goto err_pernet; | ||
1480 | return 0; | 1480 | return 0; |
1481 | err_pernet: | 1481 | |
1482 | xfrm6_tunnel_deregister(&ip6ip6_handler, AF_INET6); | 1482 | out_ip6ip6: |
1483 | unreg_ip4ip6: | ||
1484 | xfrm6_tunnel_deregister(&ip4ip6_handler, AF_INET); | 1483 | xfrm6_tunnel_deregister(&ip4ip6_handler, AF_INET); |
1485 | out: | 1484 | out_ip4ip6: |
1485 | unregister_pernet_device(&ip6_tnl_net_ops); | ||
1486 | out_pernet: | ||
1486 | return err; | 1487 | return err; |
1487 | } | 1488 | } |
1488 | 1489 | ||
diff --git a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c index 2f2a5ca2c878..85cccd6ed0b7 100644 --- a/net/ipv6/ipcomp6.c +++ b/net/ipv6/ipcomp6.c | |||
@@ -53,6 +53,7 @@ | |||
53 | static void ipcomp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | 53 | static void ipcomp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, |
54 | u8 type, u8 code, int offset, __be32 info) | 54 | u8 type, u8 code, int offset, __be32 info) |
55 | { | 55 | { |
56 | struct net *net = dev_net(skb->dev); | ||
56 | __be32 spi; | 57 | __be32 spi; |
57 | struct ipv6hdr *iph = (struct ipv6hdr*)skb->data; | 58 | struct ipv6hdr *iph = (struct ipv6hdr*)skb->data; |
58 | struct ip_comp_hdr *ipcomph = | 59 | struct ip_comp_hdr *ipcomph = |
@@ -63,7 +64,7 @@ static void ipcomp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
63 | return; | 64 | return; |
64 | 65 | ||
65 | spi = htonl(ntohs(ipcomph->cpi)); | 66 | spi = htonl(ntohs(ipcomph->cpi)); |
66 | x = xfrm_state_lookup(&init_net, (xfrm_address_t *)&iph->daddr, spi, IPPROTO_COMP, AF_INET6); | 67 | x = xfrm_state_lookup(net, skb->mark, (xfrm_address_t *)&iph->daddr, spi, IPPROTO_COMP, AF_INET6); |
67 | if (!x) | 68 | if (!x) |
68 | return; | 69 | return; |
69 | 70 | ||
@@ -74,14 +75,15 @@ static void ipcomp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
74 | 75 | ||
75 | static struct xfrm_state *ipcomp6_tunnel_create(struct xfrm_state *x) | 76 | static struct xfrm_state *ipcomp6_tunnel_create(struct xfrm_state *x) |
76 | { | 77 | { |
78 | struct net *net = xs_net(x); | ||
77 | struct xfrm_state *t = NULL; | 79 | struct xfrm_state *t = NULL; |
78 | 80 | ||
79 | t = xfrm_state_alloc(&init_net); | 81 | t = xfrm_state_alloc(net); |
80 | if (!t) | 82 | if (!t) |
81 | goto out; | 83 | goto out; |
82 | 84 | ||
83 | t->id.proto = IPPROTO_IPV6; | 85 | t->id.proto = IPPROTO_IPV6; |
84 | t->id.spi = xfrm6_tunnel_alloc_spi((xfrm_address_t *)&x->props.saddr); | 86 | t->id.spi = xfrm6_tunnel_alloc_spi(net, (xfrm_address_t *)&x->props.saddr); |
85 | if (!t->id.spi) | 87 | if (!t->id.spi) |
86 | goto error; | 88 | goto error; |
87 | 89 | ||
@@ -90,6 +92,7 @@ static struct xfrm_state *ipcomp6_tunnel_create(struct xfrm_state *x) | |||
90 | t->props.family = AF_INET6; | 92 | t->props.family = AF_INET6; |
91 | t->props.mode = x->props.mode; | 93 | t->props.mode = x->props.mode; |
92 | memcpy(t->props.saddr.a6, x->props.saddr.a6, sizeof(struct in6_addr)); | 94 | memcpy(t->props.saddr.a6, x->props.saddr.a6, sizeof(struct in6_addr)); |
95 | memcpy(&t->mark, &x->mark, sizeof(t->mark)); | ||
93 | 96 | ||
94 | if (xfrm_init_state(t)) | 97 | if (xfrm_init_state(t)) |
95 | goto error; | 98 | goto error; |
@@ -108,13 +111,15 @@ error: | |||
108 | 111 | ||
109 | static int ipcomp6_tunnel_attach(struct xfrm_state *x) | 112 | static int ipcomp6_tunnel_attach(struct xfrm_state *x) |
110 | { | 113 | { |
114 | struct net *net = xs_net(x); | ||
111 | int err = 0; | 115 | int err = 0; |
112 | struct xfrm_state *t = NULL; | 116 | struct xfrm_state *t = NULL; |
113 | __be32 spi; | 117 | __be32 spi; |
118 | u32 mark = x->mark.m & x->mark.v; | ||
114 | 119 | ||
115 | spi = xfrm6_tunnel_spi_lookup((xfrm_address_t *)&x->props.saddr); | 120 | spi = xfrm6_tunnel_spi_lookup(net, (xfrm_address_t *)&x->props.saddr); |
116 | if (spi) | 121 | if (spi) |
117 | t = xfrm_state_lookup(&init_net, (xfrm_address_t *)&x->id.daddr, | 122 | t = xfrm_state_lookup(net, mark, (xfrm_address_t *)&x->id.daddr, |
118 | spi, IPPROTO_IPV6, AF_INET6); | 123 | spi, IPPROTO_IPV6, AF_INET6); |
119 | if (!t) { | 124 | if (!t) { |
120 | t = ipcomp6_tunnel_create(x); | 125 | t = ipcomp6_tunnel_create(x); |
@@ -154,16 +159,12 @@ static int ipcomp6_init_state(struct xfrm_state *x) | |||
154 | if (x->props.mode == XFRM_MODE_TUNNEL) { | 159 | if (x->props.mode == XFRM_MODE_TUNNEL) { |
155 | err = ipcomp6_tunnel_attach(x); | 160 | err = ipcomp6_tunnel_attach(x); |
156 | if (err) | 161 | if (err) |
157 | goto error_tunnel; | 162 | goto out; |
158 | } | 163 | } |
159 | 164 | ||
160 | err = 0; | 165 | err = 0; |
161 | out: | 166 | out: |
162 | return err; | 167 | return err; |
163 | error_tunnel: | ||
164 | ipcomp_destroy(x); | ||
165 | |||
166 | goto out; | ||
167 | } | 168 | } |
168 | 169 | ||
169 | static const struct xfrm_type ipcomp6_type = | 170 | static const struct xfrm_type ipcomp6_type = |
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index 1f9c44442e65..bcd971915969 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c | |||
@@ -793,10 +793,10 @@ static void mld_add_delrec(struct inet6_dev *idev, struct ifmcaddr6 *im) | |||
793 | } | 793 | } |
794 | spin_unlock_bh(&im->mca_lock); | 794 | spin_unlock_bh(&im->mca_lock); |
795 | 795 | ||
796 | write_lock_bh(&idev->mc_lock); | 796 | spin_lock_bh(&idev->mc_lock); |
797 | pmc->next = idev->mc_tomb; | 797 | pmc->next = idev->mc_tomb; |
798 | idev->mc_tomb = pmc; | 798 | idev->mc_tomb = pmc; |
799 | write_unlock_bh(&idev->mc_lock); | 799 | spin_unlock_bh(&idev->mc_lock); |
800 | } | 800 | } |
801 | 801 | ||
802 | static void mld_del_delrec(struct inet6_dev *idev, struct in6_addr *pmca) | 802 | static void mld_del_delrec(struct inet6_dev *idev, struct in6_addr *pmca) |
@@ -804,7 +804,7 @@ static void mld_del_delrec(struct inet6_dev *idev, struct in6_addr *pmca) | |||
804 | struct ifmcaddr6 *pmc, *pmc_prev; | 804 | struct ifmcaddr6 *pmc, *pmc_prev; |
805 | struct ip6_sf_list *psf, *psf_next; | 805 | struct ip6_sf_list *psf, *psf_next; |
806 | 806 | ||
807 | write_lock_bh(&idev->mc_lock); | 807 | spin_lock_bh(&idev->mc_lock); |
808 | pmc_prev = NULL; | 808 | pmc_prev = NULL; |
809 | for (pmc=idev->mc_tomb; pmc; pmc=pmc->next) { | 809 | for (pmc=idev->mc_tomb; pmc; pmc=pmc->next) { |
810 | if (ipv6_addr_equal(&pmc->mca_addr, pmca)) | 810 | if (ipv6_addr_equal(&pmc->mca_addr, pmca)) |
@@ -817,7 +817,8 @@ static void mld_del_delrec(struct inet6_dev *idev, struct in6_addr *pmca) | |||
817 | else | 817 | else |
818 | idev->mc_tomb = pmc->next; | 818 | idev->mc_tomb = pmc->next; |
819 | } | 819 | } |
820 | write_unlock_bh(&idev->mc_lock); | 820 | spin_unlock_bh(&idev->mc_lock); |
821 | |||
821 | if (pmc) { | 822 | if (pmc) { |
822 | for (psf=pmc->mca_tomb; psf; psf=psf_next) { | 823 | for (psf=pmc->mca_tomb; psf; psf=psf_next) { |
823 | psf_next = psf->sf_next; | 824 | psf_next = psf->sf_next; |
@@ -832,10 +833,10 @@ static void mld_clear_delrec(struct inet6_dev *idev) | |||
832 | { | 833 | { |
833 | struct ifmcaddr6 *pmc, *nextpmc; | 834 | struct ifmcaddr6 *pmc, *nextpmc; |
834 | 835 | ||
835 | write_lock_bh(&idev->mc_lock); | 836 | spin_lock_bh(&idev->mc_lock); |
836 | pmc = idev->mc_tomb; | 837 | pmc = idev->mc_tomb; |
837 | idev->mc_tomb = NULL; | 838 | idev->mc_tomb = NULL; |
838 | write_unlock_bh(&idev->mc_lock); | 839 | spin_unlock_bh(&idev->mc_lock); |
839 | 840 | ||
840 | for (; pmc; pmc = nextpmc) { | 841 | for (; pmc; pmc = nextpmc) { |
841 | nextpmc = pmc->next; | 842 | nextpmc = pmc->next; |
@@ -1696,7 +1697,7 @@ static void mld_send_cr(struct inet6_dev *idev) | |||
1696 | int type, dtype; | 1697 | int type, dtype; |
1697 | 1698 | ||
1698 | read_lock_bh(&idev->lock); | 1699 | read_lock_bh(&idev->lock); |
1699 | write_lock_bh(&idev->mc_lock); | 1700 | spin_lock(&idev->mc_lock); |
1700 | 1701 | ||
1701 | /* deleted MCA's */ | 1702 | /* deleted MCA's */ |
1702 | pmc_prev = NULL; | 1703 | pmc_prev = NULL; |
@@ -1730,7 +1731,7 @@ static void mld_send_cr(struct inet6_dev *idev) | |||
1730 | } else | 1731 | } else |
1731 | pmc_prev = pmc; | 1732 | pmc_prev = pmc; |
1732 | } | 1733 | } |
1733 | write_unlock_bh(&idev->mc_lock); | 1734 | spin_unlock(&idev->mc_lock); |
1734 | 1735 | ||
1735 | /* change recs */ | 1736 | /* change recs */ |
1736 | for (pmc=idev->mc_list; pmc; pmc=pmc->next) { | 1737 | for (pmc=idev->mc_list; pmc; pmc=pmc->next) { |
@@ -2311,7 +2312,7 @@ void ipv6_mc_up(struct inet6_dev *idev) | |||
2311 | void ipv6_mc_init_dev(struct inet6_dev *idev) | 2312 | void ipv6_mc_init_dev(struct inet6_dev *idev) |
2312 | { | 2313 | { |
2313 | write_lock_bh(&idev->lock); | 2314 | write_lock_bh(&idev->lock); |
2314 | rwlock_init(&idev->mc_lock); | 2315 | spin_lock_init(&idev->mc_lock); |
2315 | idev->mc_gq_running = 0; | 2316 | idev->mc_gq_running = 0; |
2316 | setup_timer(&idev->mc_gq_timer, mld_gq_timer_expire, | 2317 | setup_timer(&idev->mc_gq_timer, mld_gq_timer_expire, |
2317 | (unsigned long)idev); | 2318 | (unsigned long)idev); |
@@ -2646,7 +2647,7 @@ static const struct file_operations igmp6_mcf_seq_fops = { | |||
2646 | .release = seq_release_net, | 2647 | .release = seq_release_net, |
2647 | }; | 2648 | }; |
2648 | 2649 | ||
2649 | static int igmp6_proc_init(struct net *net) | 2650 | static int __net_init igmp6_proc_init(struct net *net) |
2650 | { | 2651 | { |
2651 | int err; | 2652 | int err; |
2652 | 2653 | ||
@@ -2666,23 +2667,22 @@ out_proc_net_igmp6: | |||
2666 | goto out; | 2667 | goto out; |
2667 | } | 2668 | } |
2668 | 2669 | ||
2669 | static void igmp6_proc_exit(struct net *net) | 2670 | static void __net_exit igmp6_proc_exit(struct net *net) |
2670 | { | 2671 | { |
2671 | proc_net_remove(net, "mcfilter6"); | 2672 | proc_net_remove(net, "mcfilter6"); |
2672 | proc_net_remove(net, "igmp6"); | 2673 | proc_net_remove(net, "igmp6"); |
2673 | } | 2674 | } |
2674 | #else | 2675 | #else |
2675 | static int igmp6_proc_init(struct net *net) | 2676 | static inline int igmp6_proc_init(struct net *net) |
2676 | { | 2677 | { |
2677 | return 0; | 2678 | return 0; |
2678 | } | 2679 | } |
2679 | static void igmp6_proc_exit(struct net *net) | 2680 | static inline void igmp6_proc_exit(struct net *net) |
2680 | { | 2681 | { |
2681 | ; | ||
2682 | } | 2682 | } |
2683 | #endif | 2683 | #endif |
2684 | 2684 | ||
2685 | static int igmp6_net_init(struct net *net) | 2685 | static int __net_init igmp6_net_init(struct net *net) |
2686 | { | 2686 | { |
2687 | int err; | 2687 | int err; |
2688 | 2688 | ||
@@ -2708,7 +2708,7 @@ out_sock_create: | |||
2708 | goto out; | 2708 | goto out; |
2709 | } | 2709 | } |
2710 | 2710 | ||
2711 | static void igmp6_net_exit(struct net *net) | 2711 | static void __net_exit igmp6_net_exit(struct net *net) |
2712 | { | 2712 | { |
2713 | inet_ctl_sock_destroy(net->ipv6.igmp_sk); | 2713 | inet_ctl_sock_destroy(net->ipv6.igmp_sk); |
2714 | igmp6_proc_exit(net); | 2714 | igmp6_proc_exit(net); |
diff --git a/net/ipv6/mip6.c b/net/ipv6/mip6.c index f797e8c6f3b3..2794b6002836 100644 --- a/net/ipv6/mip6.c +++ b/net/ipv6/mip6.c | |||
@@ -56,7 +56,7 @@ static inline void *mip6_padn(__u8 *data, __u8 padlen) | |||
56 | 56 | ||
57 | static inline void mip6_param_prob(struct sk_buff *skb, u8 code, int pos) | 57 | static inline void mip6_param_prob(struct sk_buff *skb, u8 code, int pos) |
58 | { | 58 | { |
59 | icmpv6_send(skb, ICMPV6_PARAMPROB, code, pos, skb->dev); | 59 | icmpv6_send(skb, ICMPV6_PARAMPROB, code, pos); |
60 | } | 60 | } |
61 | 61 | ||
62 | static int mip6_mh_len(int type) | 62 | static int mip6_mh_len(int type) |
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index c45852798092..8bcc4b7db3bf 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c | |||
@@ -1772,7 +1772,7 @@ int ndisc_ifinfo_sysctl_change(struct ctl_table *ctl, int write, void __user *bu | |||
1772 | 1772 | ||
1773 | #endif | 1773 | #endif |
1774 | 1774 | ||
1775 | static int ndisc_net_init(struct net *net) | 1775 | static int __net_init ndisc_net_init(struct net *net) |
1776 | { | 1776 | { |
1777 | struct ipv6_pinfo *np; | 1777 | struct ipv6_pinfo *np; |
1778 | struct sock *sk; | 1778 | struct sock *sk; |
@@ -1797,7 +1797,7 @@ static int ndisc_net_init(struct net *net) | |||
1797 | return 0; | 1797 | return 0; |
1798 | } | 1798 | } |
1799 | 1799 | ||
1800 | static void ndisc_net_exit(struct net *net) | 1800 | static void __net_exit ndisc_net_exit(struct net *net) |
1801 | { | 1801 | { |
1802 | inet_ctl_sock_destroy(net->ipv6.ndisc_sk); | 1802 | inet_ctl_sock_destroy(net->ipv6.ndisc_sk); |
1803 | } | 1803 | } |
@@ -1820,8 +1820,7 @@ int __init ndisc_init(void) | |||
1820 | neigh_table_init(&nd_tbl); | 1820 | neigh_table_init(&nd_tbl); |
1821 | 1821 | ||
1822 | #ifdef CONFIG_SYSCTL | 1822 | #ifdef CONFIG_SYSCTL |
1823 | err = neigh_sysctl_register(NULL, &nd_tbl.parms, NET_IPV6, | 1823 | err = neigh_sysctl_register(NULL, &nd_tbl.parms, "ipv6", |
1824 | NET_IPV6_NEIGH, "ipv6", | ||
1825 | &ndisc_ifinfo_sysctl_change); | 1824 | &ndisc_ifinfo_sysctl_change); |
1826 | if (err) | 1825 | if (err) |
1827 | goto out_unregister_pernet; | 1826 | goto out_unregister_pernet; |
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 480d7f8c9802..9210e312edf1 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/netfilter_ipv6/ip6_tables.h> | 29 | #include <linux/netfilter_ipv6/ip6_tables.h> |
30 | #include <linux/netfilter/x_tables.h> | 30 | #include <linux/netfilter/x_tables.h> |
31 | #include <net/netfilter/nf_log.h> | 31 | #include <net/netfilter/nf_log.h> |
32 | #include "../../netfilter/xt_repldata.h" | ||
32 | 33 | ||
33 | MODULE_LICENSE("GPL"); | 34 | MODULE_LICENSE("GPL"); |
34 | MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>"); | 35 | MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>"); |
@@ -67,6 +68,12 @@ do { \ | |||
67 | #define inline | 68 | #define inline |
68 | #endif | 69 | #endif |
69 | 70 | ||
71 | void *ip6t_alloc_initial_table(const struct xt_table *info) | ||
72 | { | ||
73 | return xt_alloc_initial_table(ip6t, IP6T); | ||
74 | } | ||
75 | EXPORT_SYMBOL_GPL(ip6t_alloc_initial_table); | ||
76 | |||
70 | /* | 77 | /* |
71 | We keep a set of rules for each CPU, so we can avoid write-locking | 78 | We keep a set of rules for each CPU, so we can avoid write-locking |
72 | them in the softirq when updating the counters and therefore | 79 | them in the softirq when updating the counters and therefore |
@@ -201,7 +208,7 @@ ip6t_error(struct sk_buff *skb, const struct xt_target_param *par) | |||
201 | 208 | ||
202 | /* Performance critical - called for every packet */ | 209 | /* Performance critical - called for every packet */ |
203 | static inline bool | 210 | static inline bool |
204 | do_match(struct ip6t_entry_match *m, const struct sk_buff *skb, | 211 | do_match(const struct ip6t_entry_match *m, const struct sk_buff *skb, |
205 | struct xt_match_param *par) | 212 | struct xt_match_param *par) |
206 | { | 213 | { |
207 | par->match = m->u.kernel.match; | 214 | par->match = m->u.kernel.match; |
@@ -215,7 +222,7 @@ do_match(struct ip6t_entry_match *m, const struct sk_buff *skb, | |||
215 | } | 222 | } |
216 | 223 | ||
217 | static inline struct ip6t_entry * | 224 | static inline struct ip6t_entry * |
218 | get_entry(void *base, unsigned int offset) | 225 | get_entry(const void *base, unsigned int offset) |
219 | { | 226 | { |
220 | return (struct ip6t_entry *)(base + offset); | 227 | return (struct ip6t_entry *)(base + offset); |
221 | } | 228 | } |
@@ -229,6 +236,12 @@ static inline bool unconditional(const struct ip6t_ip6 *ipv6) | |||
229 | return memcmp(ipv6, &uncond, sizeof(uncond)) == 0; | 236 | return memcmp(ipv6, &uncond, sizeof(uncond)) == 0; |
230 | } | 237 | } |
231 | 238 | ||
239 | static inline const struct ip6t_entry_target * | ||
240 | ip6t_get_target_c(const struct ip6t_entry *e) | ||
241 | { | ||
242 | return ip6t_get_target((struct ip6t_entry *)e); | ||
243 | } | ||
244 | |||
232 | #if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \ | 245 | #if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \ |
233 | defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE) | 246 | defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE) |
234 | /* This cries for unification! */ | 247 | /* This cries for unification! */ |
@@ -264,11 +277,11 @@ static struct nf_loginfo trace_loginfo = { | |||
264 | 277 | ||
265 | /* Mildly perf critical (only if packet tracing is on) */ | 278 | /* Mildly perf critical (only if packet tracing is on) */ |
266 | static inline int | 279 | static inline int |
267 | get_chainname_rulenum(struct ip6t_entry *s, struct ip6t_entry *e, | 280 | get_chainname_rulenum(const struct ip6t_entry *s, const struct ip6t_entry *e, |
268 | const char *hookname, const char **chainname, | 281 | const char *hookname, const char **chainname, |
269 | const char **comment, unsigned int *rulenum) | 282 | const char **comment, unsigned int *rulenum) |
270 | { | 283 | { |
271 | struct ip6t_standard_target *t = (void *)ip6t_get_target(s); | 284 | const struct ip6t_standard_target *t = (void *)ip6t_get_target_c(s); |
272 | 285 | ||
273 | if (strcmp(t->target.u.kernel.target->name, IP6T_ERROR_TARGET) == 0) { | 286 | if (strcmp(t->target.u.kernel.target->name, IP6T_ERROR_TARGET) == 0) { |
274 | /* Head of user chain: ERROR target with chainname */ | 287 | /* Head of user chain: ERROR target with chainname */ |
@@ -294,17 +307,18 @@ get_chainname_rulenum(struct ip6t_entry *s, struct ip6t_entry *e, | |||
294 | return 0; | 307 | return 0; |
295 | } | 308 | } |
296 | 309 | ||
297 | static void trace_packet(struct sk_buff *skb, | 310 | static void trace_packet(const struct sk_buff *skb, |
298 | unsigned int hook, | 311 | unsigned int hook, |
299 | const struct net_device *in, | 312 | const struct net_device *in, |
300 | const struct net_device *out, | 313 | const struct net_device *out, |
301 | const char *tablename, | 314 | const char *tablename, |
302 | struct xt_table_info *private, | 315 | const struct xt_table_info *private, |
303 | struct ip6t_entry *e) | 316 | const struct ip6t_entry *e) |
304 | { | 317 | { |
305 | void *table_base; | 318 | const void *table_base; |
306 | const struct ip6t_entry *root; | 319 | const struct ip6t_entry *root; |
307 | const char *hookname, *chainname, *comment; | 320 | const char *hookname, *chainname, *comment; |
321 | const struct ip6t_entry *iter; | ||
308 | unsigned int rulenum = 0; | 322 | unsigned int rulenum = 0; |
309 | 323 | ||
310 | table_base = private->entries[smp_processor_id()]; | 324 | table_base = private->entries[smp_processor_id()]; |
@@ -313,10 +327,10 @@ static void trace_packet(struct sk_buff *skb, | |||
313 | hookname = chainname = hooknames[hook]; | 327 | hookname = chainname = hooknames[hook]; |
314 | comment = comments[NF_IP6_TRACE_COMMENT_RULE]; | 328 | comment = comments[NF_IP6_TRACE_COMMENT_RULE]; |
315 | 329 | ||
316 | IP6T_ENTRY_ITERATE(root, | 330 | xt_entry_foreach(iter, root, private->size - private->hook_entry[hook]) |
317 | private->size - private->hook_entry[hook], | 331 | if (get_chainname_rulenum(iter, e, hookname, |
318 | get_chainname_rulenum, | 332 | &chainname, &comment, &rulenum) != 0) |
319 | e, hookname, &chainname, &comment, &rulenum); | 333 | break; |
320 | 334 | ||
321 | nf_log_packet(AF_INET6, hook, skb, in, out, &trace_loginfo, | 335 | nf_log_packet(AF_INET6, hook, skb, in, out, &trace_loginfo, |
322 | "TRACE: %s:%s:%s:%u ", | 336 | "TRACE: %s:%s:%s:%u ", |
@@ -345,9 +359,9 @@ ip6t_do_table(struct sk_buff *skb, | |||
345 | /* Initializing verdict to NF_DROP keeps gcc happy. */ | 359 | /* Initializing verdict to NF_DROP keeps gcc happy. */ |
346 | unsigned int verdict = NF_DROP; | 360 | unsigned int verdict = NF_DROP; |
347 | const char *indev, *outdev; | 361 | const char *indev, *outdev; |
348 | void *table_base; | 362 | const void *table_base; |
349 | struct ip6t_entry *e, *back; | 363 | struct ip6t_entry *e, *back; |
350 | struct xt_table_info *private; | 364 | const struct xt_table_info *private; |
351 | struct xt_match_param mtpar; | 365 | struct xt_match_param mtpar; |
352 | struct xt_target_param tgpar; | 366 | struct xt_target_param tgpar; |
353 | 367 | ||
@@ -378,22 +392,27 @@ ip6t_do_table(struct sk_buff *skb, | |||
378 | back = get_entry(table_base, private->underflow[hook]); | 392 | back = get_entry(table_base, private->underflow[hook]); |
379 | 393 | ||
380 | do { | 394 | do { |
381 | struct ip6t_entry_target *t; | 395 | const struct ip6t_entry_target *t; |
396 | const struct xt_entry_match *ematch; | ||
382 | 397 | ||
383 | IP_NF_ASSERT(e); | 398 | IP_NF_ASSERT(e); |
384 | IP_NF_ASSERT(back); | 399 | IP_NF_ASSERT(back); |
385 | if (!ip6_packet_match(skb, indev, outdev, &e->ipv6, | 400 | if (!ip6_packet_match(skb, indev, outdev, &e->ipv6, |
386 | &mtpar.thoff, &mtpar.fragoff, &hotdrop) || | 401 | &mtpar.thoff, &mtpar.fragoff, &hotdrop)) { |
387 | IP6T_MATCH_ITERATE(e, do_match, skb, &mtpar) != 0) { | 402 | no_match: |
388 | e = ip6t_next_entry(e); | 403 | e = ip6t_next_entry(e); |
389 | continue; | 404 | continue; |
390 | } | 405 | } |
391 | 406 | ||
407 | xt_ematch_foreach(ematch, e) | ||
408 | if (do_match(ematch, skb, &mtpar) != 0) | ||
409 | goto no_match; | ||
410 | |||
392 | ADD_COUNTER(e->counters, | 411 | ADD_COUNTER(e->counters, |
393 | ntohs(ipv6_hdr(skb)->payload_len) + | 412 | ntohs(ipv6_hdr(skb)->payload_len) + |
394 | sizeof(struct ipv6hdr), 1); | 413 | sizeof(struct ipv6hdr), 1); |
395 | 414 | ||
396 | t = ip6t_get_target(e); | 415 | t = ip6t_get_target_c(e); |
397 | IP_NF_ASSERT(t->u.kernel.target); | 416 | IP_NF_ASSERT(t->u.kernel.target); |
398 | 417 | ||
399 | #if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \ | 418 | #if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \ |
@@ -475,7 +494,7 @@ ip6t_do_table(struct sk_buff *skb, | |||
475 | /* Figures out from what hook each rule can be called: returns 0 if | 494 | /* Figures out from what hook each rule can be called: returns 0 if |
476 | there are loops. Puts hook bitmask in comefrom. */ | 495 | there are loops. Puts hook bitmask in comefrom. */ |
477 | static int | 496 | static int |
478 | mark_source_chains(struct xt_table_info *newinfo, | 497 | mark_source_chains(const struct xt_table_info *newinfo, |
479 | unsigned int valid_hooks, void *entry0) | 498 | unsigned int valid_hooks, void *entry0) |
480 | { | 499 | { |
481 | unsigned int hook; | 500 | unsigned int hook; |
@@ -493,8 +512,8 @@ mark_source_chains(struct xt_table_info *newinfo, | |||
493 | e->counters.pcnt = pos; | 512 | e->counters.pcnt = pos; |
494 | 513 | ||
495 | for (;;) { | 514 | for (;;) { |
496 | struct ip6t_standard_target *t | 515 | const struct ip6t_standard_target *t |
497 | = (void *)ip6t_get_target(e); | 516 | = (void *)ip6t_get_target_c(e); |
498 | int visited = e->comefrom & (1 << hook); | 517 | int visited = e->comefrom & (1 << hook); |
499 | 518 | ||
500 | if (e->comefrom & (1 << NF_INET_NUMHOOKS)) { | 519 | if (e->comefrom & (1 << NF_INET_NUMHOOKS)) { |
@@ -584,27 +603,23 @@ mark_source_chains(struct xt_table_info *newinfo, | |||
584 | return 1; | 603 | return 1; |
585 | } | 604 | } |
586 | 605 | ||
587 | static int | 606 | static void cleanup_match(struct ip6t_entry_match *m, struct net *net) |
588 | cleanup_match(struct ip6t_entry_match *m, unsigned int *i) | ||
589 | { | 607 | { |
590 | struct xt_mtdtor_param par; | 608 | struct xt_mtdtor_param par; |
591 | 609 | ||
592 | if (i && (*i)-- == 0) | 610 | par.net = net; |
593 | return 1; | ||
594 | |||
595 | par.match = m->u.kernel.match; | 611 | par.match = m->u.kernel.match; |
596 | par.matchinfo = m->data; | 612 | par.matchinfo = m->data; |
597 | par.family = NFPROTO_IPV6; | 613 | par.family = NFPROTO_IPV6; |
598 | if (par.match->destroy != NULL) | 614 | if (par.match->destroy != NULL) |
599 | par.match->destroy(&par); | 615 | par.match->destroy(&par); |
600 | module_put(par.match->me); | 616 | module_put(par.match->me); |
601 | return 0; | ||
602 | } | 617 | } |
603 | 618 | ||
604 | static int | 619 | static int |
605 | check_entry(struct ip6t_entry *e, const char *name) | 620 | check_entry(const struct ip6t_entry *e, const char *name) |
606 | { | 621 | { |
607 | struct ip6t_entry_target *t; | 622 | const struct ip6t_entry_target *t; |
608 | 623 | ||
609 | if (!ip6_checkentry(&e->ipv6)) { | 624 | if (!ip6_checkentry(&e->ipv6)) { |
610 | duprintf("ip_tables: ip check failed %p %s.\n", e, name); | 625 | duprintf("ip_tables: ip check failed %p %s.\n", e, name); |
@@ -615,15 +630,14 @@ check_entry(struct ip6t_entry *e, const char *name) | |||
615 | e->next_offset) | 630 | e->next_offset) |
616 | return -EINVAL; | 631 | return -EINVAL; |
617 | 632 | ||
618 | t = ip6t_get_target(e); | 633 | t = ip6t_get_target_c(e); |
619 | if (e->target_offset + t->u.target_size > e->next_offset) | 634 | if (e->target_offset + t->u.target_size > e->next_offset) |
620 | return -EINVAL; | 635 | return -EINVAL; |
621 | 636 | ||
622 | return 0; | 637 | return 0; |
623 | } | 638 | } |
624 | 639 | ||
625 | static int check_match(struct ip6t_entry_match *m, struct xt_mtchk_param *par, | 640 | static int check_match(struct ip6t_entry_match *m, struct xt_mtchk_param *par) |
626 | unsigned int *i) | ||
627 | { | 641 | { |
628 | const struct ip6t_ip6 *ipv6 = par->entryinfo; | 642 | const struct ip6t_ip6 *ipv6 = par->entryinfo; |
629 | int ret; | 643 | int ret; |
@@ -638,13 +652,11 @@ static int check_match(struct ip6t_entry_match *m, struct xt_mtchk_param *par, | |||
638 | par.match->name); | 652 | par.match->name); |
639 | return ret; | 653 | return ret; |
640 | } | 654 | } |
641 | ++*i; | ||
642 | return 0; | 655 | return 0; |
643 | } | 656 | } |
644 | 657 | ||
645 | static int | 658 | static int |
646 | find_check_match(struct ip6t_entry_match *m, struct xt_mtchk_param *par, | 659 | find_check_match(struct ip6t_entry_match *m, struct xt_mtchk_param *par) |
647 | unsigned int *i) | ||
648 | { | 660 | { |
649 | struct xt_match *match; | 661 | struct xt_match *match; |
650 | int ret; | 662 | int ret; |
@@ -658,7 +670,7 @@ find_check_match(struct ip6t_entry_match *m, struct xt_mtchk_param *par, | |||
658 | } | 670 | } |
659 | m->u.kernel.match = match; | 671 | m->u.kernel.match = match; |
660 | 672 | ||
661 | ret = check_match(m, par, i); | 673 | ret = check_match(m, par); |
662 | if (ret) | 674 | if (ret) |
663 | goto err; | 675 | goto err; |
664 | 676 | ||
@@ -668,10 +680,11 @@ err: | |||
668 | return ret; | 680 | return ret; |
669 | } | 681 | } |
670 | 682 | ||
671 | static int check_target(struct ip6t_entry *e, const char *name) | 683 | static int check_target(struct ip6t_entry *e, struct net *net, const char *name) |
672 | { | 684 | { |
673 | struct ip6t_entry_target *t = ip6t_get_target(e); | 685 | struct ip6t_entry_target *t = ip6t_get_target(e); |
674 | struct xt_tgchk_param par = { | 686 | struct xt_tgchk_param par = { |
687 | .net = net, | ||
675 | .table = name, | 688 | .table = name, |
676 | .entryinfo = e, | 689 | .entryinfo = e, |
677 | .target = t->u.kernel.target, | 690 | .target = t->u.kernel.target, |
@@ -693,27 +706,32 @@ static int check_target(struct ip6t_entry *e, const char *name) | |||
693 | } | 706 | } |
694 | 707 | ||
695 | static int | 708 | static int |
696 | find_check_entry(struct ip6t_entry *e, const char *name, unsigned int size, | 709 | find_check_entry(struct ip6t_entry *e, struct net *net, const char *name, |
697 | unsigned int *i) | 710 | unsigned int size) |
698 | { | 711 | { |
699 | struct ip6t_entry_target *t; | 712 | struct ip6t_entry_target *t; |
700 | struct xt_target *target; | 713 | struct xt_target *target; |
701 | int ret; | 714 | int ret; |
702 | unsigned int j; | 715 | unsigned int j; |
703 | struct xt_mtchk_param mtpar; | 716 | struct xt_mtchk_param mtpar; |
717 | struct xt_entry_match *ematch; | ||
704 | 718 | ||
705 | ret = check_entry(e, name); | 719 | ret = check_entry(e, name); |
706 | if (ret) | 720 | if (ret) |
707 | return ret; | 721 | return ret; |
708 | 722 | ||
709 | j = 0; | 723 | j = 0; |
724 | mtpar.net = net; | ||
710 | mtpar.table = name; | 725 | mtpar.table = name; |
711 | mtpar.entryinfo = &e->ipv6; | 726 | mtpar.entryinfo = &e->ipv6; |
712 | mtpar.hook_mask = e->comefrom; | 727 | mtpar.hook_mask = e->comefrom; |
713 | mtpar.family = NFPROTO_IPV6; | 728 | mtpar.family = NFPROTO_IPV6; |
714 | ret = IP6T_MATCH_ITERATE(e, find_check_match, &mtpar, &j); | 729 | xt_ematch_foreach(ematch, e) { |
715 | if (ret != 0) | 730 | ret = find_check_match(ematch, &mtpar); |
716 | goto cleanup_matches; | 731 | if (ret != 0) |
732 | goto cleanup_matches; | ||
733 | ++j; | ||
734 | } | ||
717 | 735 | ||
718 | t = ip6t_get_target(e); | 736 | t = ip6t_get_target(e); |
719 | target = try_then_request_module(xt_find_target(AF_INET6, | 737 | target = try_then_request_module(xt_find_target(AF_INET6, |
@@ -727,27 +745,29 @@ find_check_entry(struct ip6t_entry *e, const char *name, unsigned int size, | |||
727 | } | 745 | } |
728 | t->u.kernel.target = target; | 746 | t->u.kernel.target = target; |
729 | 747 | ||
730 | ret = check_target(e, name); | 748 | ret = check_target(e, net, name); |
731 | if (ret) | 749 | if (ret) |
732 | goto err; | 750 | goto err; |
733 | |||
734 | (*i)++; | ||
735 | return 0; | 751 | return 0; |
736 | err: | 752 | err: |
737 | module_put(t->u.kernel.target->me); | 753 | module_put(t->u.kernel.target->me); |
738 | cleanup_matches: | 754 | cleanup_matches: |
739 | IP6T_MATCH_ITERATE(e, cleanup_match, &j); | 755 | xt_ematch_foreach(ematch, e) { |
756 | if (j-- == 0) | ||
757 | break; | ||
758 | cleanup_match(ematch, net); | ||
759 | } | ||
740 | return ret; | 760 | return ret; |
741 | } | 761 | } |
742 | 762 | ||
743 | static bool check_underflow(struct ip6t_entry *e) | 763 | static bool check_underflow(const struct ip6t_entry *e) |
744 | { | 764 | { |
745 | const struct ip6t_entry_target *t; | 765 | const struct ip6t_entry_target *t; |
746 | unsigned int verdict; | 766 | unsigned int verdict; |
747 | 767 | ||
748 | if (!unconditional(&e->ipv6)) | 768 | if (!unconditional(&e->ipv6)) |
749 | return false; | 769 | return false; |
750 | t = ip6t_get_target(e); | 770 | t = ip6t_get_target_c(e); |
751 | if (strcmp(t->u.user.name, XT_STANDARD_TARGET) != 0) | 771 | if (strcmp(t->u.user.name, XT_STANDARD_TARGET) != 0) |
752 | return false; | 772 | return false; |
753 | verdict = ((struct ip6t_standard_target *)t)->verdict; | 773 | verdict = ((struct ip6t_standard_target *)t)->verdict; |
@@ -758,12 +778,11 @@ static bool check_underflow(struct ip6t_entry *e) | |||
758 | static int | 778 | static int |
759 | check_entry_size_and_hooks(struct ip6t_entry *e, | 779 | check_entry_size_and_hooks(struct ip6t_entry *e, |
760 | struct xt_table_info *newinfo, | 780 | struct xt_table_info *newinfo, |
761 | unsigned char *base, | 781 | const unsigned char *base, |
762 | unsigned char *limit, | 782 | const unsigned char *limit, |
763 | const unsigned int *hook_entries, | 783 | const unsigned int *hook_entries, |
764 | const unsigned int *underflows, | 784 | const unsigned int *underflows, |
765 | unsigned int valid_hooks, | 785 | unsigned int valid_hooks) |
766 | unsigned int *i) | ||
767 | { | 786 | { |
768 | unsigned int h; | 787 | unsigned int h; |
769 | 788 | ||
@@ -800,50 +819,41 @@ check_entry_size_and_hooks(struct ip6t_entry *e, | |||
800 | /* Clear counters and comefrom */ | 819 | /* Clear counters and comefrom */ |
801 | e->counters = ((struct xt_counters) { 0, 0 }); | 820 | e->counters = ((struct xt_counters) { 0, 0 }); |
802 | e->comefrom = 0; | 821 | e->comefrom = 0; |
803 | |||
804 | (*i)++; | ||
805 | return 0; | 822 | return 0; |
806 | } | 823 | } |
807 | 824 | ||
808 | static int | 825 | static void cleanup_entry(struct ip6t_entry *e, struct net *net) |
809 | cleanup_entry(struct ip6t_entry *e, unsigned int *i) | ||
810 | { | 826 | { |
811 | struct xt_tgdtor_param par; | 827 | struct xt_tgdtor_param par; |
812 | struct ip6t_entry_target *t; | 828 | struct ip6t_entry_target *t; |
813 | 829 | struct xt_entry_match *ematch; | |
814 | if (i && (*i)-- == 0) | ||
815 | return 1; | ||
816 | 830 | ||
817 | /* Cleanup all matches */ | 831 | /* Cleanup all matches */ |
818 | IP6T_MATCH_ITERATE(e, cleanup_match, NULL); | 832 | xt_ematch_foreach(ematch, e) |
833 | cleanup_match(ematch, net); | ||
819 | t = ip6t_get_target(e); | 834 | t = ip6t_get_target(e); |
820 | 835 | ||
836 | par.net = net; | ||
821 | par.target = t->u.kernel.target; | 837 | par.target = t->u.kernel.target; |
822 | par.targinfo = t->data; | 838 | par.targinfo = t->data; |
823 | par.family = NFPROTO_IPV6; | 839 | par.family = NFPROTO_IPV6; |
824 | if (par.target->destroy != NULL) | 840 | if (par.target->destroy != NULL) |
825 | par.target->destroy(&par); | 841 | par.target->destroy(&par); |
826 | module_put(par.target->me); | 842 | module_put(par.target->me); |
827 | return 0; | ||
828 | } | 843 | } |
829 | 844 | ||
830 | /* Checks and translates the user-supplied table segment (held in | 845 | /* Checks and translates the user-supplied table segment (held in |
831 | newinfo) */ | 846 | newinfo) */ |
832 | static int | 847 | static int |
833 | translate_table(const char *name, | 848 | translate_table(struct net *net, struct xt_table_info *newinfo, void *entry0, |
834 | unsigned int valid_hooks, | 849 | const struct ip6t_replace *repl) |
835 | struct xt_table_info *newinfo, | ||
836 | void *entry0, | ||
837 | unsigned int size, | ||
838 | unsigned int number, | ||
839 | const unsigned int *hook_entries, | ||
840 | const unsigned int *underflows) | ||
841 | { | 850 | { |
851 | struct ip6t_entry *iter; | ||
842 | unsigned int i; | 852 | unsigned int i; |
843 | int ret; | 853 | int ret = 0; |
844 | 854 | ||
845 | newinfo->size = size; | 855 | newinfo->size = repl->size; |
846 | newinfo->number = number; | 856 | newinfo->number = repl->num_entries; |
847 | 857 | ||
848 | /* Init all hooks to impossible value. */ | 858 | /* Init all hooks to impossible value. */ |
849 | for (i = 0; i < NF_INET_NUMHOOKS; i++) { | 859 | for (i = 0; i < NF_INET_NUMHOOKS; i++) { |
@@ -854,49 +864,58 @@ translate_table(const char *name, | |||
854 | duprintf("translate_table: size %u\n", newinfo->size); | 864 | duprintf("translate_table: size %u\n", newinfo->size); |
855 | i = 0; | 865 | i = 0; |
856 | /* Walk through entries, checking offsets. */ | 866 | /* Walk through entries, checking offsets. */ |
857 | ret = IP6T_ENTRY_ITERATE(entry0, newinfo->size, | 867 | xt_entry_foreach(iter, entry0, newinfo->size) { |
858 | check_entry_size_and_hooks, | 868 | ret = check_entry_size_and_hooks(iter, newinfo, entry0, |
859 | newinfo, | 869 | entry0 + repl->size, |
860 | entry0, | 870 | repl->hook_entry, |
861 | entry0 + size, | 871 | repl->underflow, |
862 | hook_entries, underflows, valid_hooks, &i); | 872 | repl->valid_hooks); |
863 | if (ret != 0) | 873 | if (ret != 0) |
864 | return ret; | 874 | return ret; |
875 | ++i; | ||
876 | } | ||
865 | 877 | ||
866 | if (i != number) { | 878 | if (i != repl->num_entries) { |
867 | duprintf("translate_table: %u not %u entries\n", | 879 | duprintf("translate_table: %u not %u entries\n", |
868 | i, number); | 880 | i, repl->num_entries); |
869 | return -EINVAL; | 881 | return -EINVAL; |
870 | } | 882 | } |
871 | 883 | ||
872 | /* Check hooks all assigned */ | 884 | /* Check hooks all assigned */ |
873 | for (i = 0; i < NF_INET_NUMHOOKS; i++) { | 885 | for (i = 0; i < NF_INET_NUMHOOKS; i++) { |
874 | /* Only hooks which are valid */ | 886 | /* Only hooks which are valid */ |
875 | if (!(valid_hooks & (1 << i))) | 887 | if (!(repl->valid_hooks & (1 << i))) |
876 | continue; | 888 | continue; |
877 | if (newinfo->hook_entry[i] == 0xFFFFFFFF) { | 889 | if (newinfo->hook_entry[i] == 0xFFFFFFFF) { |
878 | duprintf("Invalid hook entry %u %u\n", | 890 | duprintf("Invalid hook entry %u %u\n", |
879 | i, hook_entries[i]); | 891 | i, repl->hook_entry[i]); |
880 | return -EINVAL; | 892 | return -EINVAL; |
881 | } | 893 | } |
882 | if (newinfo->underflow[i] == 0xFFFFFFFF) { | 894 | if (newinfo->underflow[i] == 0xFFFFFFFF) { |
883 | duprintf("Invalid underflow %u %u\n", | 895 | duprintf("Invalid underflow %u %u\n", |
884 | i, underflows[i]); | 896 | i, repl->underflow[i]); |
885 | return -EINVAL; | 897 | return -EINVAL; |
886 | } | 898 | } |
887 | } | 899 | } |
888 | 900 | ||
889 | if (!mark_source_chains(newinfo, valid_hooks, entry0)) | 901 | if (!mark_source_chains(newinfo, repl->valid_hooks, entry0)) |
890 | return -ELOOP; | 902 | return -ELOOP; |
891 | 903 | ||
892 | /* Finally, each sanity check must pass */ | 904 | /* Finally, each sanity check must pass */ |
893 | i = 0; | 905 | i = 0; |
894 | ret = IP6T_ENTRY_ITERATE(entry0, newinfo->size, | 906 | xt_entry_foreach(iter, entry0, newinfo->size) { |
895 | find_check_entry, name, size, &i); | 907 | ret = find_check_entry(iter, net, repl->name, repl->size); |
908 | if (ret != 0) | ||
909 | break; | ||
910 | ++i; | ||
911 | } | ||
896 | 912 | ||
897 | if (ret != 0) { | 913 | if (ret != 0) { |
898 | IP6T_ENTRY_ITERATE(entry0, newinfo->size, | 914 | xt_entry_foreach(iter, entry0, newinfo->size) { |
899 | cleanup_entry, &i); | 915 | if (i-- == 0) |
916 | break; | ||
917 | cleanup_entry(iter, net); | ||
918 | } | ||
900 | return ret; | 919 | return ret; |
901 | } | 920 | } |
902 | 921 | ||
@@ -909,33 +928,11 @@ translate_table(const char *name, | |||
909 | return ret; | 928 | return ret; |
910 | } | 929 | } |
911 | 930 | ||
912 | /* Gets counters. */ | ||
913 | static inline int | ||
914 | add_entry_to_counter(const struct ip6t_entry *e, | ||
915 | struct xt_counters total[], | ||
916 | unsigned int *i) | ||
917 | { | ||
918 | ADD_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt); | ||
919 | |||
920 | (*i)++; | ||
921 | return 0; | ||
922 | } | ||
923 | |||
924 | static inline int | ||
925 | set_entry_to_counter(const struct ip6t_entry *e, | ||
926 | struct ip6t_counters total[], | ||
927 | unsigned int *i) | ||
928 | { | ||
929 | SET_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt); | ||
930 | |||
931 | (*i)++; | ||
932 | return 0; | ||
933 | } | ||
934 | |||
935 | static void | 931 | static void |
936 | get_counters(const struct xt_table_info *t, | 932 | get_counters(const struct xt_table_info *t, |
937 | struct xt_counters counters[]) | 933 | struct xt_counters counters[]) |
938 | { | 934 | { |
935 | struct ip6t_entry *iter; | ||
939 | unsigned int cpu; | 936 | unsigned int cpu; |
940 | unsigned int i; | 937 | unsigned int i; |
941 | unsigned int curcpu; | 938 | unsigned int curcpu; |
@@ -951,32 +948,32 @@ get_counters(const struct xt_table_info *t, | |||
951 | curcpu = smp_processor_id(); | 948 | curcpu = smp_processor_id(); |
952 | 949 | ||
953 | i = 0; | 950 | i = 0; |
954 | IP6T_ENTRY_ITERATE(t->entries[curcpu], | 951 | xt_entry_foreach(iter, t->entries[curcpu], t->size) { |
955 | t->size, | 952 | SET_COUNTER(counters[i], iter->counters.bcnt, |
956 | set_entry_to_counter, | 953 | iter->counters.pcnt); |
957 | counters, | 954 | ++i; |
958 | &i); | 955 | } |
959 | 956 | ||
960 | for_each_possible_cpu(cpu) { | 957 | for_each_possible_cpu(cpu) { |
961 | if (cpu == curcpu) | 958 | if (cpu == curcpu) |
962 | continue; | 959 | continue; |
963 | i = 0; | 960 | i = 0; |
964 | xt_info_wrlock(cpu); | 961 | xt_info_wrlock(cpu); |
965 | IP6T_ENTRY_ITERATE(t->entries[cpu], | 962 | xt_entry_foreach(iter, t->entries[cpu], t->size) { |
966 | t->size, | 963 | ADD_COUNTER(counters[i], iter->counters.bcnt, |
967 | add_entry_to_counter, | 964 | iter->counters.pcnt); |
968 | counters, | 965 | ++i; |
969 | &i); | 966 | } |
970 | xt_info_wrunlock(cpu); | 967 | xt_info_wrunlock(cpu); |
971 | } | 968 | } |
972 | local_bh_enable(); | 969 | local_bh_enable(); |
973 | } | 970 | } |
974 | 971 | ||
975 | static struct xt_counters *alloc_counters(struct xt_table *table) | 972 | static struct xt_counters *alloc_counters(const struct xt_table *table) |
976 | { | 973 | { |
977 | unsigned int countersize; | 974 | unsigned int countersize; |
978 | struct xt_counters *counters; | 975 | struct xt_counters *counters; |
979 | struct xt_table_info *private = table->private; | 976 | const struct xt_table_info *private = table->private; |
980 | 977 | ||
981 | /* We need atomic snapshot of counters: rest doesn't change | 978 | /* We need atomic snapshot of counters: rest doesn't change |
982 | (other than comefrom, which userspace doesn't care | 979 | (other than comefrom, which userspace doesn't care |
@@ -994,11 +991,11 @@ static struct xt_counters *alloc_counters(struct xt_table *table) | |||
994 | 991 | ||
995 | static int | 992 | static int |
996 | copy_entries_to_user(unsigned int total_size, | 993 | copy_entries_to_user(unsigned int total_size, |
997 | struct xt_table *table, | 994 | const struct xt_table *table, |
998 | void __user *userptr) | 995 | void __user *userptr) |
999 | { | 996 | { |
1000 | unsigned int off, num; | 997 | unsigned int off, num; |
1001 | struct ip6t_entry *e; | 998 | const struct ip6t_entry *e; |
1002 | struct xt_counters *counters; | 999 | struct xt_counters *counters; |
1003 | const struct xt_table_info *private = table->private; | 1000 | const struct xt_table_info *private = table->private; |
1004 | int ret = 0; | 1001 | int ret = 0; |
@@ -1050,7 +1047,7 @@ copy_entries_to_user(unsigned int total_size, | |||
1050 | } | 1047 | } |
1051 | } | 1048 | } |
1052 | 1049 | ||
1053 | t = ip6t_get_target(e); | 1050 | t = ip6t_get_target_c(e); |
1054 | if (copy_to_user(userptr + off + e->target_offset | 1051 | if (copy_to_user(userptr + off + e->target_offset |
1055 | + offsetof(struct ip6t_entry_target, | 1052 | + offsetof(struct ip6t_entry_target, |
1056 | u.user.name), | 1053 | u.user.name), |
@@ -1067,7 +1064,7 @@ copy_entries_to_user(unsigned int total_size, | |||
1067 | } | 1064 | } |
1068 | 1065 | ||
1069 | #ifdef CONFIG_COMPAT | 1066 | #ifdef CONFIG_COMPAT |
1070 | static void compat_standard_from_user(void *dst, void *src) | 1067 | static void compat_standard_from_user(void *dst, const void *src) |
1071 | { | 1068 | { |
1072 | int v = *(compat_int_t *)src; | 1069 | int v = *(compat_int_t *)src; |
1073 | 1070 | ||
@@ -1076,7 +1073,7 @@ static void compat_standard_from_user(void *dst, void *src) | |||
1076 | memcpy(dst, &v, sizeof(v)); | 1073 | memcpy(dst, &v, sizeof(v)); |
1077 | } | 1074 | } |
1078 | 1075 | ||
1079 | static int compat_standard_to_user(void __user *dst, void *src) | 1076 | static int compat_standard_to_user(void __user *dst, const void *src) |
1080 | { | 1077 | { |
1081 | compat_int_t cv = *(int *)src; | 1078 | compat_int_t cv = *(int *)src; |
1082 | 1079 | ||
@@ -1085,25 +1082,20 @@ static int compat_standard_to_user(void __user *dst, void *src) | |||
1085 | return copy_to_user(dst, &cv, sizeof(cv)) ? -EFAULT : 0; | 1082 | return copy_to_user(dst, &cv, sizeof(cv)) ? -EFAULT : 0; |
1086 | } | 1083 | } |
1087 | 1084 | ||
1088 | static inline int | 1085 | static int compat_calc_entry(const struct ip6t_entry *e, |
1089 | compat_calc_match(struct ip6t_entry_match *m, int *size) | ||
1090 | { | ||
1091 | *size += xt_compat_match_offset(m->u.kernel.match); | ||
1092 | return 0; | ||
1093 | } | ||
1094 | |||
1095 | static int compat_calc_entry(struct ip6t_entry *e, | ||
1096 | const struct xt_table_info *info, | 1086 | const struct xt_table_info *info, |
1097 | void *base, struct xt_table_info *newinfo) | 1087 | const void *base, struct xt_table_info *newinfo) |
1098 | { | 1088 | { |
1099 | struct ip6t_entry_target *t; | 1089 | const struct xt_entry_match *ematch; |
1090 | const struct ip6t_entry_target *t; | ||
1100 | unsigned int entry_offset; | 1091 | unsigned int entry_offset; |
1101 | int off, i, ret; | 1092 | int off, i, ret; |
1102 | 1093 | ||
1103 | off = sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry); | 1094 | off = sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry); |
1104 | entry_offset = (void *)e - base; | 1095 | entry_offset = (void *)e - base; |
1105 | IP6T_MATCH_ITERATE(e, compat_calc_match, &off); | 1096 | xt_ematch_foreach(ematch, e) |
1106 | t = ip6t_get_target(e); | 1097 | off += xt_compat_match_offset(ematch->u.kernel.match); |
1098 | t = ip6t_get_target_c(e); | ||
1107 | off += xt_compat_target_offset(t->u.kernel.target); | 1099 | off += xt_compat_target_offset(t->u.kernel.target); |
1108 | newinfo->size -= off; | 1100 | newinfo->size -= off; |
1109 | ret = xt_compat_add_offset(AF_INET6, entry_offset, off); | 1101 | ret = xt_compat_add_offset(AF_INET6, entry_offset, off); |
@@ -1124,7 +1116,9 @@ static int compat_calc_entry(struct ip6t_entry *e, | |||
1124 | static int compat_table_info(const struct xt_table_info *info, | 1116 | static int compat_table_info(const struct xt_table_info *info, |
1125 | struct xt_table_info *newinfo) | 1117 | struct xt_table_info *newinfo) |
1126 | { | 1118 | { |
1119 | struct ip6t_entry *iter; | ||
1127 | void *loc_cpu_entry; | 1120 | void *loc_cpu_entry; |
1121 | int ret; | ||
1128 | 1122 | ||
1129 | if (!newinfo || !info) | 1123 | if (!newinfo || !info) |
1130 | return -EINVAL; | 1124 | return -EINVAL; |
@@ -1133,13 +1127,17 @@ static int compat_table_info(const struct xt_table_info *info, | |||
1133 | memcpy(newinfo, info, offsetof(struct xt_table_info, entries)); | 1127 | memcpy(newinfo, info, offsetof(struct xt_table_info, entries)); |
1134 | newinfo->initial_entries = 0; | 1128 | newinfo->initial_entries = 0; |
1135 | loc_cpu_entry = info->entries[raw_smp_processor_id()]; | 1129 | loc_cpu_entry = info->entries[raw_smp_processor_id()]; |
1136 | return IP6T_ENTRY_ITERATE(loc_cpu_entry, info->size, | 1130 | xt_entry_foreach(iter, loc_cpu_entry, info->size) { |
1137 | compat_calc_entry, info, loc_cpu_entry, | 1131 | ret = compat_calc_entry(iter, info, loc_cpu_entry, newinfo); |
1138 | newinfo); | 1132 | if (ret != 0) |
1133 | return ret; | ||
1134 | } | ||
1135 | return 0; | ||
1139 | } | 1136 | } |
1140 | #endif | 1137 | #endif |
1141 | 1138 | ||
1142 | static int get_info(struct net *net, void __user *user, int *len, int compat) | 1139 | static int get_info(struct net *net, void __user *user, |
1140 | const int *len, int compat) | ||
1143 | { | 1141 | { |
1144 | char name[IP6T_TABLE_MAXNAMELEN]; | 1142 | char name[IP6T_TABLE_MAXNAMELEN]; |
1145 | struct xt_table *t; | 1143 | struct xt_table *t; |
@@ -1164,10 +1162,10 @@ static int get_info(struct net *net, void __user *user, int *len, int compat) | |||
1164 | if (t && !IS_ERR(t)) { | 1162 | if (t && !IS_ERR(t)) { |
1165 | struct ip6t_getinfo info; | 1163 | struct ip6t_getinfo info; |
1166 | const struct xt_table_info *private = t->private; | 1164 | const struct xt_table_info *private = t->private; |
1167 | |||
1168 | #ifdef CONFIG_COMPAT | 1165 | #ifdef CONFIG_COMPAT |
1166 | struct xt_table_info tmp; | ||
1167 | |||
1169 | if (compat) { | 1168 | if (compat) { |
1170 | struct xt_table_info tmp; | ||
1171 | ret = compat_table_info(private, &tmp); | 1169 | ret = compat_table_info(private, &tmp); |
1172 | xt_compat_flush_offsets(AF_INET6); | 1170 | xt_compat_flush_offsets(AF_INET6); |
1173 | private = &tmp; | 1171 | private = &tmp; |
@@ -1199,7 +1197,8 @@ static int get_info(struct net *net, void __user *user, int *len, int compat) | |||
1199 | } | 1197 | } |
1200 | 1198 | ||
1201 | static int | 1199 | static int |
1202 | get_entries(struct net *net, struct ip6t_get_entries __user *uptr, int *len) | 1200 | get_entries(struct net *net, struct ip6t_get_entries __user *uptr, |
1201 | const int *len) | ||
1203 | { | 1202 | { |
1204 | int ret; | 1203 | int ret; |
1205 | struct ip6t_get_entries get; | 1204 | struct ip6t_get_entries get; |
@@ -1247,6 +1246,7 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks, | |||
1247 | struct xt_table_info *oldinfo; | 1246 | struct xt_table_info *oldinfo; |
1248 | struct xt_counters *counters; | 1247 | struct xt_counters *counters; |
1249 | const void *loc_cpu_old_entry; | 1248 | const void *loc_cpu_old_entry; |
1249 | struct ip6t_entry *iter; | ||
1250 | 1250 | ||
1251 | ret = 0; | 1251 | ret = 0; |
1252 | counters = vmalloc_node(num_counters * sizeof(struct xt_counters), | 1252 | counters = vmalloc_node(num_counters * sizeof(struct xt_counters), |
@@ -1290,8 +1290,9 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks, | |||
1290 | 1290 | ||
1291 | /* Decrease module usage counts and free resource */ | 1291 | /* Decrease module usage counts and free resource */ |
1292 | loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()]; | 1292 | loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()]; |
1293 | IP6T_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry, | 1293 | xt_entry_foreach(iter, loc_cpu_old_entry, oldinfo->size) |
1294 | NULL); | 1294 | cleanup_entry(iter, net); |
1295 | |||
1295 | xt_free_table_info(oldinfo); | 1296 | xt_free_table_info(oldinfo); |
1296 | if (copy_to_user(counters_ptr, counters, | 1297 | if (copy_to_user(counters_ptr, counters, |
1297 | sizeof(struct xt_counters) * num_counters) != 0) | 1298 | sizeof(struct xt_counters) * num_counters) != 0) |
@@ -1310,12 +1311,13 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks, | |||
1310 | } | 1311 | } |
1311 | 1312 | ||
1312 | static int | 1313 | static int |
1313 | do_replace(struct net *net, void __user *user, unsigned int len) | 1314 | do_replace(struct net *net, const void __user *user, unsigned int len) |
1314 | { | 1315 | { |
1315 | int ret; | 1316 | int ret; |
1316 | struct ip6t_replace tmp; | 1317 | struct ip6t_replace tmp; |
1317 | struct xt_table_info *newinfo; | 1318 | struct xt_table_info *newinfo; |
1318 | void *loc_cpu_entry; | 1319 | void *loc_cpu_entry; |
1320 | struct ip6t_entry *iter; | ||
1319 | 1321 | ||
1320 | if (copy_from_user(&tmp, user, sizeof(tmp)) != 0) | 1322 | if (copy_from_user(&tmp, user, sizeof(tmp)) != 0) |
1321 | return -EFAULT; | 1323 | return -EFAULT; |
@@ -1336,9 +1338,7 @@ do_replace(struct net *net, void __user *user, unsigned int len) | |||
1336 | goto free_newinfo; | 1338 | goto free_newinfo; |
1337 | } | 1339 | } |
1338 | 1340 | ||
1339 | ret = translate_table(tmp.name, tmp.valid_hooks, | 1341 | ret = translate_table(net, newinfo, loc_cpu_entry, &tmp); |
1340 | newinfo, loc_cpu_entry, tmp.size, tmp.num_entries, | ||
1341 | tmp.hook_entry, tmp.underflow); | ||
1342 | if (ret != 0) | 1342 | if (ret != 0) |
1343 | goto free_newinfo; | 1343 | goto free_newinfo; |
1344 | 1344 | ||
@@ -1351,27 +1351,15 @@ do_replace(struct net *net, void __user *user, unsigned int len) | |||
1351 | return 0; | 1351 | return 0; |
1352 | 1352 | ||
1353 | free_newinfo_untrans: | 1353 | free_newinfo_untrans: |
1354 | IP6T_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry, NULL); | 1354 | xt_entry_foreach(iter, loc_cpu_entry, newinfo->size) |
1355 | cleanup_entry(iter, net); | ||
1355 | free_newinfo: | 1356 | free_newinfo: |
1356 | xt_free_table_info(newinfo); | 1357 | xt_free_table_info(newinfo); |
1357 | return ret; | 1358 | return ret; |
1358 | } | 1359 | } |
1359 | 1360 | ||
1360 | /* We're lazy, and add to the first CPU; overflow works its fey magic | ||
1361 | * and everything is OK. */ | ||
1362 | static int | 1361 | static int |
1363 | add_counter_to_entry(struct ip6t_entry *e, | 1362 | do_add_counters(struct net *net, const void __user *user, unsigned int len, |
1364 | const struct xt_counters addme[], | ||
1365 | unsigned int *i) | ||
1366 | { | ||
1367 | ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt); | ||
1368 | |||
1369 | (*i)++; | ||
1370 | return 0; | ||
1371 | } | ||
1372 | |||
1373 | static int | ||
1374 | do_add_counters(struct net *net, void __user *user, unsigned int len, | ||
1375 | int compat) | 1363 | int compat) |
1376 | { | 1364 | { |
1377 | unsigned int i, curcpu; | 1365 | unsigned int i, curcpu; |
@@ -1385,6 +1373,7 @@ do_add_counters(struct net *net, void __user *user, unsigned int len, | |||
1385 | const struct xt_table_info *private; | 1373 | const struct xt_table_info *private; |
1386 | int ret = 0; | 1374 | int ret = 0; |
1387 | const void *loc_cpu_entry; | 1375 | const void *loc_cpu_entry; |
1376 | struct ip6t_entry *iter; | ||
1388 | #ifdef CONFIG_COMPAT | 1377 | #ifdef CONFIG_COMPAT |
1389 | struct compat_xt_counters_info compat_tmp; | 1378 | struct compat_xt_counters_info compat_tmp; |
1390 | 1379 | ||
@@ -1443,11 +1432,10 @@ do_add_counters(struct net *net, void __user *user, unsigned int len, | |||
1443 | curcpu = smp_processor_id(); | 1432 | curcpu = smp_processor_id(); |
1444 | xt_info_wrlock(curcpu); | 1433 | xt_info_wrlock(curcpu); |
1445 | loc_cpu_entry = private->entries[curcpu]; | 1434 | loc_cpu_entry = private->entries[curcpu]; |
1446 | IP6T_ENTRY_ITERATE(loc_cpu_entry, | 1435 | xt_entry_foreach(iter, loc_cpu_entry, private->size) { |
1447 | private->size, | 1436 | ADD_COUNTER(iter->counters, paddc[i].bcnt, paddc[i].pcnt); |
1448 | add_counter_to_entry, | 1437 | ++i; |
1449 | paddc, | 1438 | } |
1450 | &i); | ||
1451 | xt_info_wrunlock(curcpu); | 1439 | xt_info_wrunlock(curcpu); |
1452 | 1440 | ||
1453 | unlock_up_free: | 1441 | unlock_up_free: |
@@ -1476,45 +1464,40 @@ struct compat_ip6t_replace { | |||
1476 | static int | 1464 | static int |
1477 | compat_copy_entry_to_user(struct ip6t_entry *e, void __user **dstptr, | 1465 | compat_copy_entry_to_user(struct ip6t_entry *e, void __user **dstptr, |
1478 | unsigned int *size, struct xt_counters *counters, | 1466 | unsigned int *size, struct xt_counters *counters, |
1479 | unsigned int *i) | 1467 | unsigned int i) |
1480 | { | 1468 | { |
1481 | struct ip6t_entry_target *t; | 1469 | struct ip6t_entry_target *t; |
1482 | struct compat_ip6t_entry __user *ce; | 1470 | struct compat_ip6t_entry __user *ce; |
1483 | u_int16_t target_offset, next_offset; | 1471 | u_int16_t target_offset, next_offset; |
1484 | compat_uint_t origsize; | 1472 | compat_uint_t origsize; |
1485 | int ret; | 1473 | const struct xt_entry_match *ematch; |
1474 | int ret = 0; | ||
1486 | 1475 | ||
1487 | ret = -EFAULT; | ||
1488 | origsize = *size; | 1476 | origsize = *size; |
1489 | ce = (struct compat_ip6t_entry __user *)*dstptr; | 1477 | ce = (struct compat_ip6t_entry __user *)*dstptr; |
1490 | if (copy_to_user(ce, e, sizeof(struct ip6t_entry))) | 1478 | if (copy_to_user(ce, e, sizeof(struct ip6t_entry)) != 0 || |
1491 | goto out; | 1479 | copy_to_user(&ce->counters, &counters[i], |
1492 | 1480 | sizeof(counters[i])) != 0) | |
1493 | if (copy_to_user(&ce->counters, &counters[*i], sizeof(counters[*i]))) | 1481 | return -EFAULT; |
1494 | goto out; | ||
1495 | 1482 | ||
1496 | *dstptr += sizeof(struct compat_ip6t_entry); | 1483 | *dstptr += sizeof(struct compat_ip6t_entry); |
1497 | *size -= sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry); | 1484 | *size -= sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry); |
1498 | 1485 | ||
1499 | ret = IP6T_MATCH_ITERATE(e, xt_compat_match_to_user, dstptr, size); | 1486 | xt_ematch_foreach(ematch, e) { |
1487 | ret = xt_compat_match_to_user(ematch, dstptr, size); | ||
1488 | if (ret != 0) | ||
1489 | return ret; | ||
1490 | } | ||
1500 | target_offset = e->target_offset - (origsize - *size); | 1491 | target_offset = e->target_offset - (origsize - *size); |
1501 | if (ret) | ||
1502 | goto out; | ||
1503 | t = ip6t_get_target(e); | 1492 | t = ip6t_get_target(e); |
1504 | ret = xt_compat_target_to_user(t, dstptr, size); | 1493 | ret = xt_compat_target_to_user(t, dstptr, size); |
1505 | if (ret) | 1494 | if (ret) |
1506 | goto out; | 1495 | return ret; |
1507 | ret = -EFAULT; | ||
1508 | next_offset = e->next_offset - (origsize - *size); | 1496 | next_offset = e->next_offset - (origsize - *size); |
1509 | if (put_user(target_offset, &ce->target_offset)) | 1497 | if (put_user(target_offset, &ce->target_offset) != 0 || |
1510 | goto out; | 1498 | put_user(next_offset, &ce->next_offset) != 0) |
1511 | if (put_user(next_offset, &ce->next_offset)) | 1499 | return -EFAULT; |
1512 | goto out; | ||
1513 | |||
1514 | (*i)++; | ||
1515 | return 0; | 1500 | return 0; |
1516 | out: | ||
1517 | return ret; | ||
1518 | } | 1501 | } |
1519 | 1502 | ||
1520 | static int | 1503 | static int |
@@ -1522,7 +1505,7 @@ compat_find_calc_match(struct ip6t_entry_match *m, | |||
1522 | const char *name, | 1505 | const char *name, |
1523 | const struct ip6t_ip6 *ipv6, | 1506 | const struct ip6t_ip6 *ipv6, |
1524 | unsigned int hookmask, | 1507 | unsigned int hookmask, |
1525 | int *size, unsigned int *i) | 1508 | int *size) |
1526 | { | 1509 | { |
1527 | struct xt_match *match; | 1510 | struct xt_match *match; |
1528 | 1511 | ||
@@ -1536,47 +1519,32 @@ compat_find_calc_match(struct ip6t_entry_match *m, | |||
1536 | } | 1519 | } |
1537 | m->u.kernel.match = match; | 1520 | m->u.kernel.match = match; |
1538 | *size += xt_compat_match_offset(match); | 1521 | *size += xt_compat_match_offset(match); |
1539 | |||
1540 | (*i)++; | ||
1541 | return 0; | ||
1542 | } | ||
1543 | |||
1544 | static int | ||
1545 | compat_release_match(struct ip6t_entry_match *m, unsigned int *i) | ||
1546 | { | ||
1547 | if (i && (*i)-- == 0) | ||
1548 | return 1; | ||
1549 | |||
1550 | module_put(m->u.kernel.match->me); | ||
1551 | return 0; | 1522 | return 0; |
1552 | } | 1523 | } |
1553 | 1524 | ||
1554 | static int | 1525 | static void compat_release_entry(struct compat_ip6t_entry *e) |
1555 | compat_release_entry(struct compat_ip6t_entry *e, unsigned int *i) | ||
1556 | { | 1526 | { |
1557 | struct ip6t_entry_target *t; | 1527 | struct ip6t_entry_target *t; |
1558 | 1528 | struct xt_entry_match *ematch; | |
1559 | if (i && (*i)-- == 0) | ||
1560 | return 1; | ||
1561 | 1529 | ||
1562 | /* Cleanup all matches */ | 1530 | /* Cleanup all matches */ |
1563 | COMPAT_IP6T_MATCH_ITERATE(e, compat_release_match, NULL); | 1531 | xt_ematch_foreach(ematch, e) |
1532 | module_put(ematch->u.kernel.match->me); | ||
1564 | t = compat_ip6t_get_target(e); | 1533 | t = compat_ip6t_get_target(e); |
1565 | module_put(t->u.kernel.target->me); | 1534 | module_put(t->u.kernel.target->me); |
1566 | return 0; | ||
1567 | } | 1535 | } |
1568 | 1536 | ||
1569 | static int | 1537 | static int |
1570 | check_compat_entry_size_and_hooks(struct compat_ip6t_entry *e, | 1538 | check_compat_entry_size_and_hooks(struct compat_ip6t_entry *e, |
1571 | struct xt_table_info *newinfo, | 1539 | struct xt_table_info *newinfo, |
1572 | unsigned int *size, | 1540 | unsigned int *size, |
1573 | unsigned char *base, | 1541 | const unsigned char *base, |
1574 | unsigned char *limit, | 1542 | const unsigned char *limit, |
1575 | unsigned int *hook_entries, | 1543 | const unsigned int *hook_entries, |
1576 | unsigned int *underflows, | 1544 | const unsigned int *underflows, |
1577 | unsigned int *i, | ||
1578 | const char *name) | 1545 | const char *name) |
1579 | { | 1546 | { |
1547 | struct xt_entry_match *ematch; | ||
1580 | struct ip6t_entry_target *t; | 1548 | struct ip6t_entry_target *t; |
1581 | struct xt_target *target; | 1549 | struct xt_target *target; |
1582 | unsigned int entry_offset; | 1550 | unsigned int entry_offset; |
@@ -1605,10 +1573,13 @@ check_compat_entry_size_and_hooks(struct compat_ip6t_entry *e, | |||
1605 | off = sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry); | 1573 | off = sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry); |
1606 | entry_offset = (void *)e - (void *)base; | 1574 | entry_offset = (void *)e - (void *)base; |
1607 | j = 0; | 1575 | j = 0; |
1608 | ret = COMPAT_IP6T_MATCH_ITERATE(e, compat_find_calc_match, name, | 1576 | xt_ematch_foreach(ematch, e) { |
1609 | &e->ipv6, e->comefrom, &off, &j); | 1577 | ret = compat_find_calc_match(ematch, name, |
1610 | if (ret != 0) | 1578 | &e->ipv6, e->comefrom, &off); |
1611 | goto release_matches; | 1579 | if (ret != 0) |
1580 | goto release_matches; | ||
1581 | ++j; | ||
1582 | } | ||
1612 | 1583 | ||
1613 | t = compat_ip6t_get_target(e); | 1584 | t = compat_ip6t_get_target(e); |
1614 | target = try_then_request_module(xt_find_target(AF_INET6, | 1585 | target = try_then_request_module(xt_find_target(AF_INET6, |
@@ -1640,14 +1611,16 @@ check_compat_entry_size_and_hooks(struct compat_ip6t_entry *e, | |||
1640 | /* Clear counters and comefrom */ | 1611 | /* Clear counters and comefrom */ |
1641 | memset(&e->counters, 0, sizeof(e->counters)); | 1612 | memset(&e->counters, 0, sizeof(e->counters)); |
1642 | e->comefrom = 0; | 1613 | e->comefrom = 0; |
1643 | |||
1644 | (*i)++; | ||
1645 | return 0; | 1614 | return 0; |
1646 | 1615 | ||
1647 | out: | 1616 | out: |
1648 | module_put(t->u.kernel.target->me); | 1617 | module_put(t->u.kernel.target->me); |
1649 | release_matches: | 1618 | release_matches: |
1650 | IP6T_MATCH_ITERATE(e, compat_release_match, &j); | 1619 | xt_ematch_foreach(ematch, e) { |
1620 | if (j-- == 0) | ||
1621 | break; | ||
1622 | module_put(ematch->u.kernel.match->me); | ||
1623 | } | ||
1651 | return ret; | 1624 | return ret; |
1652 | } | 1625 | } |
1653 | 1626 | ||
@@ -1661,6 +1634,7 @@ compat_copy_entry_from_user(struct compat_ip6t_entry *e, void **dstptr, | |||
1661 | struct ip6t_entry *de; | 1634 | struct ip6t_entry *de; |
1662 | unsigned int origsize; | 1635 | unsigned int origsize; |
1663 | int ret, h; | 1636 | int ret, h; |
1637 | struct xt_entry_match *ematch; | ||
1664 | 1638 | ||
1665 | ret = 0; | 1639 | ret = 0; |
1666 | origsize = *size; | 1640 | origsize = *size; |
@@ -1671,10 +1645,11 @@ compat_copy_entry_from_user(struct compat_ip6t_entry *e, void **dstptr, | |||
1671 | *dstptr += sizeof(struct ip6t_entry); | 1645 | *dstptr += sizeof(struct ip6t_entry); |
1672 | *size += sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry); | 1646 | *size += sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry); |
1673 | 1647 | ||
1674 | ret = COMPAT_IP6T_MATCH_ITERATE(e, xt_compat_match_from_user, | 1648 | xt_ematch_foreach(ematch, e) { |
1675 | dstptr, size); | 1649 | ret = xt_compat_match_from_user(ematch, dstptr, size); |
1676 | if (ret) | 1650 | if (ret != 0) |
1677 | return ret; | 1651 | return ret; |
1652 | } | ||
1678 | de->target_offset = e->target_offset - (origsize - *size); | 1653 | de->target_offset = e->target_offset - (origsize - *size); |
1679 | t = compat_ip6t_get_target(e); | 1654 | t = compat_ip6t_get_target(e); |
1680 | target = t->u.kernel.target; | 1655 | target = t->u.kernel.target; |
@@ -1690,36 +1665,44 @@ compat_copy_entry_from_user(struct compat_ip6t_entry *e, void **dstptr, | |||
1690 | return ret; | 1665 | return ret; |
1691 | } | 1666 | } |
1692 | 1667 | ||
1693 | static int compat_check_entry(struct ip6t_entry *e, const char *name, | 1668 | static int compat_check_entry(struct ip6t_entry *e, struct net *net, |
1694 | unsigned int *i) | 1669 | const char *name) |
1695 | { | 1670 | { |
1696 | unsigned int j; | 1671 | unsigned int j; |
1697 | int ret; | 1672 | int ret = 0; |
1698 | struct xt_mtchk_param mtpar; | 1673 | struct xt_mtchk_param mtpar; |
1674 | struct xt_entry_match *ematch; | ||
1699 | 1675 | ||
1700 | j = 0; | 1676 | j = 0; |
1677 | mtpar.net = net; | ||
1701 | mtpar.table = name; | 1678 | mtpar.table = name; |
1702 | mtpar.entryinfo = &e->ipv6; | 1679 | mtpar.entryinfo = &e->ipv6; |
1703 | mtpar.hook_mask = e->comefrom; | 1680 | mtpar.hook_mask = e->comefrom; |
1704 | mtpar.family = NFPROTO_IPV6; | 1681 | mtpar.family = NFPROTO_IPV6; |
1705 | ret = IP6T_MATCH_ITERATE(e, check_match, &mtpar, &j); | 1682 | xt_ematch_foreach(ematch, e) { |
1706 | if (ret) | 1683 | ret = check_match(ematch, &mtpar); |
1707 | goto cleanup_matches; | 1684 | if (ret != 0) |
1685 | goto cleanup_matches; | ||
1686 | ++j; | ||
1687 | } | ||
1708 | 1688 | ||
1709 | ret = check_target(e, name); | 1689 | ret = check_target(e, net, name); |
1710 | if (ret) | 1690 | if (ret) |
1711 | goto cleanup_matches; | 1691 | goto cleanup_matches; |
1712 | |||
1713 | (*i)++; | ||
1714 | return 0; | 1692 | return 0; |
1715 | 1693 | ||
1716 | cleanup_matches: | 1694 | cleanup_matches: |
1717 | IP6T_MATCH_ITERATE(e, cleanup_match, &j); | 1695 | xt_ematch_foreach(ematch, e) { |
1696 | if (j-- == 0) | ||
1697 | break; | ||
1698 | cleanup_match(ematch, net); | ||
1699 | } | ||
1718 | return ret; | 1700 | return ret; |
1719 | } | 1701 | } |
1720 | 1702 | ||
1721 | static int | 1703 | static int |
1722 | translate_compat_table(const char *name, | 1704 | translate_compat_table(struct net *net, |
1705 | const char *name, | ||
1723 | unsigned int valid_hooks, | 1706 | unsigned int valid_hooks, |
1724 | struct xt_table_info **pinfo, | 1707 | struct xt_table_info **pinfo, |
1725 | void **pentry0, | 1708 | void **pentry0, |
@@ -1731,8 +1714,10 @@ translate_compat_table(const char *name, | |||
1731 | unsigned int i, j; | 1714 | unsigned int i, j; |
1732 | struct xt_table_info *newinfo, *info; | 1715 | struct xt_table_info *newinfo, *info; |
1733 | void *pos, *entry0, *entry1; | 1716 | void *pos, *entry0, *entry1; |
1717 | struct compat_ip6t_entry *iter0; | ||
1718 | struct ip6t_entry *iter1; | ||
1734 | unsigned int size; | 1719 | unsigned int size; |
1735 | int ret; | 1720 | int ret = 0; |
1736 | 1721 | ||
1737 | info = *pinfo; | 1722 | info = *pinfo; |
1738 | entry0 = *pentry0; | 1723 | entry0 = *pentry0; |
@@ -1749,13 +1734,17 @@ translate_compat_table(const char *name, | |||
1749 | j = 0; | 1734 | j = 0; |
1750 | xt_compat_lock(AF_INET6); | 1735 | xt_compat_lock(AF_INET6); |
1751 | /* Walk through entries, checking offsets. */ | 1736 | /* Walk through entries, checking offsets. */ |
1752 | ret = COMPAT_IP6T_ENTRY_ITERATE(entry0, total_size, | 1737 | xt_entry_foreach(iter0, entry0, total_size) { |
1753 | check_compat_entry_size_and_hooks, | 1738 | ret = check_compat_entry_size_and_hooks(iter0, info, &size, |
1754 | info, &size, entry0, | 1739 | entry0, |
1755 | entry0 + total_size, | 1740 | entry0 + total_size, |
1756 | hook_entries, underflows, &j, name); | 1741 | hook_entries, |
1757 | if (ret != 0) | 1742 | underflows, |
1758 | goto out_unlock; | 1743 | name); |
1744 | if (ret != 0) | ||
1745 | goto out_unlock; | ||
1746 | ++j; | ||
1747 | } | ||
1759 | 1748 | ||
1760 | ret = -EINVAL; | 1749 | ret = -EINVAL; |
1761 | if (j != number) { | 1750 | if (j != number) { |
@@ -1794,9 +1783,12 @@ translate_compat_table(const char *name, | |||
1794 | entry1 = newinfo->entries[raw_smp_processor_id()]; | 1783 | entry1 = newinfo->entries[raw_smp_processor_id()]; |
1795 | pos = entry1; | 1784 | pos = entry1; |
1796 | size = total_size; | 1785 | size = total_size; |
1797 | ret = COMPAT_IP6T_ENTRY_ITERATE(entry0, total_size, | 1786 | xt_entry_foreach(iter0, entry0, total_size) { |
1798 | compat_copy_entry_from_user, | 1787 | ret = compat_copy_entry_from_user(iter0, &pos, &size, |
1799 | &pos, &size, name, newinfo, entry1); | 1788 | name, newinfo, entry1); |
1789 | if (ret != 0) | ||
1790 | break; | ||
1791 | } | ||
1800 | xt_compat_flush_offsets(AF_INET6); | 1792 | xt_compat_flush_offsets(AF_INET6); |
1801 | xt_compat_unlock(AF_INET6); | 1793 | xt_compat_unlock(AF_INET6); |
1802 | if (ret) | 1794 | if (ret) |
@@ -1807,13 +1799,32 @@ translate_compat_table(const char *name, | |||
1807 | goto free_newinfo; | 1799 | goto free_newinfo; |
1808 | 1800 | ||
1809 | i = 0; | 1801 | i = 0; |
1810 | ret = IP6T_ENTRY_ITERATE(entry1, newinfo->size, compat_check_entry, | 1802 | xt_entry_foreach(iter1, entry1, newinfo->size) { |
1811 | name, &i); | 1803 | ret = compat_check_entry(iter1, net, name); |
1804 | if (ret != 0) | ||
1805 | break; | ||
1806 | ++i; | ||
1807 | } | ||
1812 | if (ret) { | 1808 | if (ret) { |
1809 | /* | ||
1810 | * The first i matches need cleanup_entry (calls ->destroy) | ||
1811 | * because they had called ->check already. The other j-i | ||
1812 | * entries need only release. | ||
1813 | */ | ||
1814 | int skip = i; | ||
1813 | j -= i; | 1815 | j -= i; |
1814 | COMPAT_IP6T_ENTRY_ITERATE_CONTINUE(entry0, newinfo->size, i, | 1816 | xt_entry_foreach(iter0, entry0, newinfo->size) { |
1815 | compat_release_entry, &j); | 1817 | if (skip-- > 0) |
1816 | IP6T_ENTRY_ITERATE(entry1, newinfo->size, cleanup_entry, &i); | 1818 | continue; |
1819 | if (j-- == 0) | ||
1820 | break; | ||
1821 | compat_release_entry(iter0); | ||
1822 | } | ||
1823 | xt_entry_foreach(iter1, entry1, newinfo->size) { | ||
1824 | if (i-- == 0) | ||
1825 | break; | ||
1826 | cleanup_entry(iter1, net); | ||
1827 | } | ||
1817 | xt_free_table_info(newinfo); | 1828 | xt_free_table_info(newinfo); |
1818 | return ret; | 1829 | return ret; |
1819 | } | 1830 | } |
@@ -1831,7 +1842,11 @@ translate_compat_table(const char *name, | |||
1831 | free_newinfo: | 1842 | free_newinfo: |
1832 | xt_free_table_info(newinfo); | 1843 | xt_free_table_info(newinfo); |
1833 | out: | 1844 | out: |
1834 | COMPAT_IP6T_ENTRY_ITERATE(entry0, total_size, compat_release_entry, &j); | 1845 | xt_entry_foreach(iter0, entry0, total_size) { |
1846 | if (j-- == 0) | ||
1847 | break; | ||
1848 | compat_release_entry(iter0); | ||
1849 | } | ||
1835 | return ret; | 1850 | return ret; |
1836 | out_unlock: | 1851 | out_unlock: |
1837 | xt_compat_flush_offsets(AF_INET6); | 1852 | xt_compat_flush_offsets(AF_INET6); |
@@ -1846,6 +1861,7 @@ compat_do_replace(struct net *net, void __user *user, unsigned int len) | |||
1846 | struct compat_ip6t_replace tmp; | 1861 | struct compat_ip6t_replace tmp; |
1847 | struct xt_table_info *newinfo; | 1862 | struct xt_table_info *newinfo; |
1848 | void *loc_cpu_entry; | 1863 | void *loc_cpu_entry; |
1864 | struct ip6t_entry *iter; | ||
1849 | 1865 | ||
1850 | if (copy_from_user(&tmp, user, sizeof(tmp)) != 0) | 1866 | if (copy_from_user(&tmp, user, sizeof(tmp)) != 0) |
1851 | return -EFAULT; | 1867 | return -EFAULT; |
@@ -1868,7 +1884,7 @@ compat_do_replace(struct net *net, void __user *user, unsigned int len) | |||
1868 | goto free_newinfo; | 1884 | goto free_newinfo; |
1869 | } | 1885 | } |
1870 | 1886 | ||
1871 | ret = translate_compat_table(tmp.name, tmp.valid_hooks, | 1887 | ret = translate_compat_table(net, tmp.name, tmp.valid_hooks, |
1872 | &newinfo, &loc_cpu_entry, tmp.size, | 1888 | &newinfo, &loc_cpu_entry, tmp.size, |
1873 | tmp.num_entries, tmp.hook_entry, | 1889 | tmp.num_entries, tmp.hook_entry, |
1874 | tmp.underflow); | 1890 | tmp.underflow); |
@@ -1884,7 +1900,8 @@ compat_do_replace(struct net *net, void __user *user, unsigned int len) | |||
1884 | return 0; | 1900 | return 0; |
1885 | 1901 | ||
1886 | free_newinfo_untrans: | 1902 | free_newinfo_untrans: |
1887 | IP6T_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry, NULL); | 1903 | xt_entry_foreach(iter, loc_cpu_entry, newinfo->size) |
1904 | cleanup_entry(iter, net); | ||
1888 | free_newinfo: | 1905 | free_newinfo: |
1889 | xt_free_table_info(newinfo); | 1906 | xt_free_table_info(newinfo); |
1890 | return ret; | 1907 | return ret; |
@@ -1933,6 +1950,7 @@ compat_copy_entries_to_user(unsigned int total_size, struct xt_table *table, | |||
1933 | int ret = 0; | 1950 | int ret = 0; |
1934 | const void *loc_cpu_entry; | 1951 | const void *loc_cpu_entry; |
1935 | unsigned int i = 0; | 1952 | unsigned int i = 0; |
1953 | struct ip6t_entry *iter; | ||
1936 | 1954 | ||
1937 | counters = alloc_counters(table); | 1955 | counters = alloc_counters(table); |
1938 | if (IS_ERR(counters)) | 1956 | if (IS_ERR(counters)) |
@@ -1945,9 +1963,12 @@ compat_copy_entries_to_user(unsigned int total_size, struct xt_table *table, | |||
1945 | loc_cpu_entry = private->entries[raw_smp_processor_id()]; | 1963 | loc_cpu_entry = private->entries[raw_smp_processor_id()]; |
1946 | pos = userptr; | 1964 | pos = userptr; |
1947 | size = total_size; | 1965 | size = total_size; |
1948 | ret = IP6T_ENTRY_ITERATE(loc_cpu_entry, total_size, | 1966 | xt_entry_foreach(iter, loc_cpu_entry, total_size) { |
1949 | compat_copy_entry_to_user, | 1967 | ret = compat_copy_entry_to_user(iter, &pos, |
1950 | &pos, &size, counters, &i); | 1968 | &size, counters, i++); |
1969 | if (ret != 0) | ||
1970 | break; | ||
1971 | } | ||
1951 | 1972 | ||
1952 | vfree(counters); | 1973 | vfree(counters); |
1953 | return ret; | 1974 | return ret; |
@@ -2121,11 +2142,7 @@ struct xt_table *ip6t_register_table(struct net *net, | |||
2121 | loc_cpu_entry = newinfo->entries[raw_smp_processor_id()]; | 2142 | loc_cpu_entry = newinfo->entries[raw_smp_processor_id()]; |
2122 | memcpy(loc_cpu_entry, repl->entries, repl->size); | 2143 | memcpy(loc_cpu_entry, repl->entries, repl->size); |
2123 | 2144 | ||
2124 | ret = translate_table(table->name, table->valid_hooks, | 2145 | ret = translate_table(net, newinfo, loc_cpu_entry, repl); |
2125 | newinfo, loc_cpu_entry, repl->size, | ||
2126 | repl->num_entries, | ||
2127 | repl->hook_entry, | ||
2128 | repl->underflow); | ||
2129 | if (ret != 0) | 2146 | if (ret != 0) |
2130 | goto out_free; | 2147 | goto out_free; |
2131 | 2148 | ||
@@ -2142,17 +2159,19 @@ out: | |||
2142 | return ERR_PTR(ret); | 2159 | return ERR_PTR(ret); |
2143 | } | 2160 | } |
2144 | 2161 | ||
2145 | void ip6t_unregister_table(struct xt_table *table) | 2162 | void ip6t_unregister_table(struct net *net, struct xt_table *table) |
2146 | { | 2163 | { |
2147 | struct xt_table_info *private; | 2164 | struct xt_table_info *private; |
2148 | void *loc_cpu_entry; | 2165 | void *loc_cpu_entry; |
2149 | struct module *table_owner = table->me; | 2166 | struct module *table_owner = table->me; |
2167 | struct ip6t_entry *iter; | ||
2150 | 2168 | ||
2151 | private = xt_unregister_table(table); | 2169 | private = xt_unregister_table(table); |
2152 | 2170 | ||
2153 | /* Decrease module usage counts and free resources */ | 2171 | /* Decrease module usage counts and free resources */ |
2154 | loc_cpu_entry = private->entries[raw_smp_processor_id()]; | 2172 | loc_cpu_entry = private->entries[raw_smp_processor_id()]; |
2155 | IP6T_ENTRY_ITERATE(loc_cpu_entry, private->size, cleanup_entry, NULL); | 2173 | xt_entry_foreach(iter, loc_cpu_entry, private->size) |
2174 | cleanup_entry(iter, net); | ||
2156 | if (private->number > private->initial_entries) | 2175 | if (private->number > private->initial_entries) |
2157 | module_put(table_owner); | 2176 | module_put(table_owner); |
2158 | xt_free_table_info(private); | 2177 | xt_free_table_info(private); |
diff --git a/net/ipv6/netfilter/ip6t_REJECT.c b/net/ipv6/netfilter/ip6t_REJECT.c index 8311ca31816a..dd8afbaf00a8 100644 --- a/net/ipv6/netfilter/ip6t_REJECT.c +++ b/net/ipv6/netfilter/ip6t_REJECT.c | |||
@@ -169,7 +169,7 @@ send_unreach(struct net *net, struct sk_buff *skb_in, unsigned char code, | |||
169 | if (hooknum == NF_INET_LOCAL_OUT && skb_in->dev == NULL) | 169 | if (hooknum == NF_INET_LOCAL_OUT && skb_in->dev == NULL) |
170 | skb_in->dev = net->loopback_dev; | 170 | skb_in->dev = net->loopback_dev; |
171 | 171 | ||
172 | icmpv6_send(skb_in, ICMPV6_DEST_UNREACH, code, 0, NULL); | 172 | icmpv6_send(skb_in, ICMPV6_DEST_UNREACH, code, 0); |
173 | } | 173 | } |
174 | 174 | ||
175 | static unsigned int | 175 | static unsigned int |
diff --git a/net/ipv6/netfilter/ip6table_filter.c b/net/ipv6/netfilter/ip6table_filter.c index ad378efd0eb8..36b72cafc227 100644 --- a/net/ipv6/netfilter/ip6table_filter.c +++ b/net/ipv6/netfilter/ip6table_filter.c | |||
@@ -21,99 +21,26 @@ MODULE_DESCRIPTION("ip6tables filter table"); | |||
21 | (1 << NF_INET_FORWARD) | \ | 21 | (1 << NF_INET_FORWARD) | \ |
22 | (1 << NF_INET_LOCAL_OUT)) | 22 | (1 << NF_INET_LOCAL_OUT)) |
23 | 23 | ||
24 | static struct | ||
25 | { | ||
26 | struct ip6t_replace repl; | ||
27 | struct ip6t_standard entries[3]; | ||
28 | struct ip6t_error term; | ||
29 | } initial_table __net_initdata = { | ||
30 | .repl = { | ||
31 | .name = "filter", | ||
32 | .valid_hooks = FILTER_VALID_HOOKS, | ||
33 | .num_entries = 4, | ||
34 | .size = sizeof(struct ip6t_standard) * 3 + sizeof(struct ip6t_error), | ||
35 | .hook_entry = { | ||
36 | [NF_INET_LOCAL_IN] = 0, | ||
37 | [NF_INET_FORWARD] = sizeof(struct ip6t_standard), | ||
38 | [NF_INET_LOCAL_OUT] = sizeof(struct ip6t_standard) * 2 | ||
39 | }, | ||
40 | .underflow = { | ||
41 | [NF_INET_LOCAL_IN] = 0, | ||
42 | [NF_INET_FORWARD] = sizeof(struct ip6t_standard), | ||
43 | [NF_INET_LOCAL_OUT] = sizeof(struct ip6t_standard) * 2 | ||
44 | }, | ||
45 | }, | ||
46 | .entries = { | ||
47 | IP6T_STANDARD_INIT(NF_ACCEPT), /* LOCAL_IN */ | ||
48 | IP6T_STANDARD_INIT(NF_ACCEPT), /* FORWARD */ | ||
49 | IP6T_STANDARD_INIT(NF_ACCEPT), /* LOCAL_OUT */ | ||
50 | }, | ||
51 | .term = IP6T_ERROR_INIT, /* ERROR */ | ||
52 | }; | ||
53 | |||
54 | static const struct xt_table packet_filter = { | 24 | static const struct xt_table packet_filter = { |
55 | .name = "filter", | 25 | .name = "filter", |
56 | .valid_hooks = FILTER_VALID_HOOKS, | 26 | .valid_hooks = FILTER_VALID_HOOKS, |
57 | .me = THIS_MODULE, | 27 | .me = THIS_MODULE, |
58 | .af = NFPROTO_IPV6, | 28 | .af = NFPROTO_IPV6, |
29 | .priority = NF_IP6_PRI_FILTER, | ||
59 | }; | 30 | }; |
60 | 31 | ||
61 | /* The work comes in here from netfilter.c. */ | 32 | /* The work comes in here from netfilter.c. */ |
62 | static unsigned int | 33 | static unsigned int |
63 | ip6t_in_hook(unsigned int hook, | 34 | ip6table_filter_hook(unsigned int hook, struct sk_buff *skb, |
64 | struct sk_buff *skb, | 35 | const struct net_device *in, const struct net_device *out, |
65 | const struct net_device *in, | 36 | int (*okfn)(struct sk_buff *)) |
66 | const struct net_device *out, | ||
67 | int (*okfn)(struct sk_buff *)) | ||
68 | { | ||
69 | return ip6t_do_table(skb, hook, in, out, | ||
70 | dev_net(in)->ipv6.ip6table_filter); | ||
71 | } | ||
72 | |||
73 | static unsigned int | ||
74 | ip6t_local_out_hook(unsigned int hook, | ||
75 | struct sk_buff *skb, | ||
76 | const struct net_device *in, | ||
77 | const struct net_device *out, | ||
78 | int (*okfn)(struct sk_buff *)) | ||
79 | { | 37 | { |
80 | #if 0 | 38 | const struct net *net = dev_net((in != NULL) ? in : out); |
81 | /* root is playing with raw sockets. */ | ||
82 | if (skb->len < sizeof(struct iphdr) || | ||
83 | ip_hdrlen(skb) < sizeof(struct iphdr)) { | ||
84 | if (net_ratelimit()) | ||
85 | printk("ip6t_hook: happy cracking.\n"); | ||
86 | return NF_ACCEPT; | ||
87 | } | ||
88 | #endif | ||
89 | 39 | ||
90 | return ip6t_do_table(skb, hook, in, out, | 40 | return ip6t_do_table(skb, hook, in, out, net->ipv6.ip6table_filter); |
91 | dev_net(out)->ipv6.ip6table_filter); | ||
92 | } | 41 | } |
93 | 42 | ||
94 | static struct nf_hook_ops ip6t_ops[] __read_mostly = { | 43 | static struct nf_hook_ops *filter_ops __read_mostly; |
95 | { | ||
96 | .hook = ip6t_in_hook, | ||
97 | .owner = THIS_MODULE, | ||
98 | .pf = NFPROTO_IPV6, | ||
99 | .hooknum = NF_INET_LOCAL_IN, | ||
100 | .priority = NF_IP6_PRI_FILTER, | ||
101 | }, | ||
102 | { | ||
103 | .hook = ip6t_in_hook, | ||
104 | .owner = THIS_MODULE, | ||
105 | .pf = NFPROTO_IPV6, | ||
106 | .hooknum = NF_INET_FORWARD, | ||
107 | .priority = NF_IP6_PRI_FILTER, | ||
108 | }, | ||
109 | { | ||
110 | .hook = ip6t_local_out_hook, | ||
111 | .owner = THIS_MODULE, | ||
112 | .pf = NFPROTO_IPV6, | ||
113 | .hooknum = NF_INET_LOCAL_OUT, | ||
114 | .priority = NF_IP6_PRI_FILTER, | ||
115 | }, | ||
116 | }; | ||
117 | 44 | ||
118 | /* Default to forward because I got too much mail already. */ | 45 | /* Default to forward because I got too much mail already. */ |
119 | static int forward = NF_ACCEPT; | 46 | static int forward = NF_ACCEPT; |
@@ -121,9 +48,18 @@ module_param(forward, bool, 0000); | |||
121 | 48 | ||
122 | static int __net_init ip6table_filter_net_init(struct net *net) | 49 | static int __net_init ip6table_filter_net_init(struct net *net) |
123 | { | 50 | { |
124 | /* Register table */ | 51 | struct ip6t_replace *repl; |
52 | |||
53 | repl = ip6t_alloc_initial_table(&packet_filter); | ||
54 | if (repl == NULL) | ||
55 | return -ENOMEM; | ||
56 | /* Entry 1 is the FORWARD hook */ | ||
57 | ((struct ip6t_standard *)repl->entries)[1].target.verdict = | ||
58 | -forward - 1; | ||
59 | |||
125 | net->ipv6.ip6table_filter = | 60 | net->ipv6.ip6table_filter = |
126 | ip6t_register_table(net, &packet_filter, &initial_table.repl); | 61 | ip6t_register_table(net, &packet_filter, repl); |
62 | kfree(repl); | ||
127 | if (IS_ERR(net->ipv6.ip6table_filter)) | 63 | if (IS_ERR(net->ipv6.ip6table_filter)) |
128 | return PTR_ERR(net->ipv6.ip6table_filter); | 64 | return PTR_ERR(net->ipv6.ip6table_filter); |
129 | return 0; | 65 | return 0; |
@@ -131,7 +67,7 @@ static int __net_init ip6table_filter_net_init(struct net *net) | |||
131 | 67 | ||
132 | static void __net_exit ip6table_filter_net_exit(struct net *net) | 68 | static void __net_exit ip6table_filter_net_exit(struct net *net) |
133 | { | 69 | { |
134 | ip6t_unregister_table(net->ipv6.ip6table_filter); | 70 | ip6t_unregister_table(net, net->ipv6.ip6table_filter); |
135 | } | 71 | } |
136 | 72 | ||
137 | static struct pernet_operations ip6table_filter_net_ops = { | 73 | static struct pernet_operations ip6table_filter_net_ops = { |
@@ -148,17 +84,16 @@ static int __init ip6table_filter_init(void) | |||
148 | return -EINVAL; | 84 | return -EINVAL; |
149 | } | 85 | } |
150 | 86 | ||
151 | /* Entry 1 is the FORWARD hook */ | ||
152 | initial_table.entries[1].target.verdict = -forward - 1; | ||
153 | |||
154 | ret = register_pernet_subsys(&ip6table_filter_net_ops); | 87 | ret = register_pernet_subsys(&ip6table_filter_net_ops); |
155 | if (ret < 0) | 88 | if (ret < 0) |
156 | return ret; | 89 | return ret; |
157 | 90 | ||
158 | /* Register hooks */ | 91 | /* Register hooks */ |
159 | ret = nf_register_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops)); | 92 | filter_ops = xt_hook_link(&packet_filter, ip6table_filter_hook); |
160 | if (ret < 0) | 93 | if (IS_ERR(filter_ops)) { |
94 | ret = PTR_ERR(filter_ops); | ||
161 | goto cleanup_table; | 95 | goto cleanup_table; |
96 | } | ||
162 | 97 | ||
163 | return ret; | 98 | return ret; |
164 | 99 | ||
@@ -169,7 +104,7 @@ static int __init ip6table_filter_init(void) | |||
169 | 104 | ||
170 | static void __exit ip6table_filter_fini(void) | 105 | static void __exit ip6table_filter_fini(void) |
171 | { | 106 | { |
172 | nf_unregister_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops)); | 107 | xt_hook_unlink(&packet_filter, filter_ops); |
173 | unregister_pernet_subsys(&ip6table_filter_net_ops); | 108 | unregister_pernet_subsys(&ip6table_filter_net_ops); |
174 | } | 109 | } |
175 | 110 | ||
diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c index a929c19d30e3..7844e557c0ec 100644 --- a/net/ipv6/netfilter/ip6table_mangle.c +++ b/net/ipv6/netfilter/ip6table_mangle.c | |||
@@ -21,80 +21,17 @@ MODULE_DESCRIPTION("ip6tables mangle table"); | |||
21 | (1 << NF_INET_LOCAL_OUT) | \ | 21 | (1 << NF_INET_LOCAL_OUT) | \ |
22 | (1 << NF_INET_POST_ROUTING)) | 22 | (1 << NF_INET_POST_ROUTING)) |
23 | 23 | ||
24 | static const struct | ||
25 | { | ||
26 | struct ip6t_replace repl; | ||
27 | struct ip6t_standard entries[5]; | ||
28 | struct ip6t_error term; | ||
29 | } initial_table __net_initdata = { | ||
30 | .repl = { | ||
31 | .name = "mangle", | ||
32 | .valid_hooks = MANGLE_VALID_HOOKS, | ||
33 | .num_entries = 6, | ||
34 | .size = sizeof(struct ip6t_standard) * 5 + sizeof(struct ip6t_error), | ||
35 | .hook_entry = { | ||
36 | [NF_INET_PRE_ROUTING] = 0, | ||
37 | [NF_INET_LOCAL_IN] = sizeof(struct ip6t_standard), | ||
38 | [NF_INET_FORWARD] = sizeof(struct ip6t_standard) * 2, | ||
39 | [NF_INET_LOCAL_OUT] = sizeof(struct ip6t_standard) * 3, | ||
40 | [NF_INET_POST_ROUTING] = sizeof(struct ip6t_standard) * 4, | ||
41 | }, | ||
42 | .underflow = { | ||
43 | [NF_INET_PRE_ROUTING] = 0, | ||
44 | [NF_INET_LOCAL_IN] = sizeof(struct ip6t_standard), | ||
45 | [NF_INET_FORWARD] = sizeof(struct ip6t_standard) * 2, | ||
46 | [NF_INET_LOCAL_OUT] = sizeof(struct ip6t_standard) * 3, | ||
47 | [NF_INET_POST_ROUTING] = sizeof(struct ip6t_standard) * 4, | ||
48 | }, | ||
49 | }, | ||
50 | .entries = { | ||
51 | IP6T_STANDARD_INIT(NF_ACCEPT), /* PRE_ROUTING */ | ||
52 | IP6T_STANDARD_INIT(NF_ACCEPT), /* LOCAL_IN */ | ||
53 | IP6T_STANDARD_INIT(NF_ACCEPT), /* FORWARD */ | ||
54 | IP6T_STANDARD_INIT(NF_ACCEPT), /* LOCAL_OUT */ | ||
55 | IP6T_STANDARD_INIT(NF_ACCEPT), /* POST_ROUTING */ | ||
56 | }, | ||
57 | .term = IP6T_ERROR_INIT, /* ERROR */ | ||
58 | }; | ||
59 | |||
60 | static const struct xt_table packet_mangler = { | 24 | static const struct xt_table packet_mangler = { |
61 | .name = "mangle", | 25 | .name = "mangle", |
62 | .valid_hooks = MANGLE_VALID_HOOKS, | 26 | .valid_hooks = MANGLE_VALID_HOOKS, |
63 | .me = THIS_MODULE, | 27 | .me = THIS_MODULE, |
64 | .af = NFPROTO_IPV6, | 28 | .af = NFPROTO_IPV6, |
29 | .priority = NF_IP6_PRI_MANGLE, | ||
65 | }; | 30 | }; |
66 | 31 | ||
67 | /* The work comes in here from netfilter.c. */ | ||
68 | static unsigned int | ||
69 | ip6t_in_hook(unsigned int hook, | ||
70 | struct sk_buff *skb, | ||
71 | const struct net_device *in, | ||
72 | const struct net_device *out, | ||
73 | int (*okfn)(struct sk_buff *)) | ||
74 | { | ||
75 | return ip6t_do_table(skb, hook, in, out, | ||
76 | dev_net(in)->ipv6.ip6table_mangle); | ||
77 | } | ||
78 | |||
79 | static unsigned int | ||
80 | ip6t_post_routing_hook(unsigned int hook, | ||
81 | struct sk_buff *skb, | ||
82 | const struct net_device *in, | ||
83 | const struct net_device *out, | ||
84 | int (*okfn)(struct sk_buff *)) | ||
85 | { | ||
86 | return ip6t_do_table(skb, hook, in, out, | ||
87 | dev_net(out)->ipv6.ip6table_mangle); | ||
88 | } | ||
89 | |||
90 | static unsigned int | 32 | static unsigned int |
91 | ip6t_local_out_hook(unsigned int hook, | 33 | ip6t_mangle_out(struct sk_buff *skb, const struct net_device *out) |
92 | struct sk_buff *skb, | ||
93 | const struct net_device *in, | ||
94 | const struct net_device *out, | ||
95 | int (*okfn)(struct sk_buff *)) | ||
96 | { | 34 | { |
97 | |||
98 | unsigned int ret; | 35 | unsigned int ret; |
99 | struct in6_addr saddr, daddr; | 36 | struct in6_addr saddr, daddr; |
100 | u_int8_t hop_limit; | 37 | u_int8_t hop_limit; |
@@ -119,7 +56,7 @@ ip6t_local_out_hook(unsigned int hook, | |||
119 | /* flowlabel and prio (includes version, which shouldn't change either */ | 56 | /* flowlabel and prio (includes version, which shouldn't change either */ |
120 | flowlabel = *((u_int32_t *)ipv6_hdr(skb)); | 57 | flowlabel = *((u_int32_t *)ipv6_hdr(skb)); |
121 | 58 | ||
122 | ret = ip6t_do_table(skb, hook, in, out, | 59 | ret = ip6t_do_table(skb, NF_INET_LOCAL_OUT, NULL, out, |
123 | dev_net(out)->ipv6.ip6table_mangle); | 60 | dev_net(out)->ipv6.ip6table_mangle); |
124 | 61 | ||
125 | if (ret != NF_DROP && ret != NF_STOLEN && | 62 | if (ret != NF_DROP && ret != NF_STOLEN && |
@@ -132,49 +69,33 @@ ip6t_local_out_hook(unsigned int hook, | |||
132 | return ret; | 69 | return ret; |
133 | } | 70 | } |
134 | 71 | ||
135 | static struct nf_hook_ops ip6t_ops[] __read_mostly = { | 72 | /* The work comes in here from netfilter.c. */ |
136 | { | 73 | static unsigned int |
137 | .hook = ip6t_in_hook, | 74 | ip6table_mangle_hook(unsigned int hook, struct sk_buff *skb, |
138 | .owner = THIS_MODULE, | 75 | const struct net_device *in, const struct net_device *out, |
139 | .pf = NFPROTO_IPV6, | 76 | int (*okfn)(struct sk_buff *)) |
140 | .hooknum = NF_INET_PRE_ROUTING, | 77 | { |
141 | .priority = NF_IP6_PRI_MANGLE, | 78 | if (hook == NF_INET_LOCAL_OUT) |
142 | }, | 79 | return ip6t_mangle_out(skb, out); |
143 | { | 80 | if (hook == NF_INET_POST_ROUTING) |
144 | .hook = ip6t_in_hook, | 81 | return ip6t_do_table(skb, hook, in, out, |
145 | .owner = THIS_MODULE, | 82 | dev_net(out)->ipv6.ip6table_mangle); |
146 | .pf = NFPROTO_IPV6, | 83 | /* INPUT/FORWARD */ |
147 | .hooknum = NF_INET_LOCAL_IN, | 84 | return ip6t_do_table(skb, hook, in, out, |
148 | .priority = NF_IP6_PRI_MANGLE, | 85 | dev_net(in)->ipv6.ip6table_mangle); |
149 | }, | 86 | } |
150 | { | ||
151 | .hook = ip6t_in_hook, | ||
152 | .owner = THIS_MODULE, | ||
153 | .pf = NFPROTO_IPV6, | ||
154 | .hooknum = NF_INET_FORWARD, | ||
155 | .priority = NF_IP6_PRI_MANGLE, | ||
156 | }, | ||
157 | { | ||
158 | .hook = ip6t_local_out_hook, | ||
159 | .owner = THIS_MODULE, | ||
160 | .pf = NFPROTO_IPV6, | ||
161 | .hooknum = NF_INET_LOCAL_OUT, | ||
162 | .priority = NF_IP6_PRI_MANGLE, | ||
163 | }, | ||
164 | { | ||
165 | .hook = ip6t_post_routing_hook, | ||
166 | .owner = THIS_MODULE, | ||
167 | .pf = NFPROTO_IPV6, | ||
168 | .hooknum = NF_INET_POST_ROUTING, | ||
169 | .priority = NF_IP6_PRI_MANGLE, | ||
170 | }, | ||
171 | }; | ||
172 | 87 | ||
88 | static struct nf_hook_ops *mangle_ops __read_mostly; | ||
173 | static int __net_init ip6table_mangle_net_init(struct net *net) | 89 | static int __net_init ip6table_mangle_net_init(struct net *net) |
174 | { | 90 | { |
175 | /* Register table */ | 91 | struct ip6t_replace *repl; |
92 | |||
93 | repl = ip6t_alloc_initial_table(&packet_mangler); | ||
94 | if (repl == NULL) | ||
95 | return -ENOMEM; | ||
176 | net->ipv6.ip6table_mangle = | 96 | net->ipv6.ip6table_mangle = |
177 | ip6t_register_table(net, &packet_mangler, &initial_table.repl); | 97 | ip6t_register_table(net, &packet_mangler, repl); |
98 | kfree(repl); | ||
178 | if (IS_ERR(net->ipv6.ip6table_mangle)) | 99 | if (IS_ERR(net->ipv6.ip6table_mangle)) |
179 | return PTR_ERR(net->ipv6.ip6table_mangle); | 100 | return PTR_ERR(net->ipv6.ip6table_mangle); |
180 | return 0; | 101 | return 0; |
@@ -182,7 +103,7 @@ static int __net_init ip6table_mangle_net_init(struct net *net) | |||
182 | 103 | ||
183 | static void __net_exit ip6table_mangle_net_exit(struct net *net) | 104 | static void __net_exit ip6table_mangle_net_exit(struct net *net) |
184 | { | 105 | { |
185 | ip6t_unregister_table(net->ipv6.ip6table_mangle); | 106 | ip6t_unregister_table(net, net->ipv6.ip6table_mangle); |
186 | } | 107 | } |
187 | 108 | ||
188 | static struct pernet_operations ip6table_mangle_net_ops = { | 109 | static struct pernet_operations ip6table_mangle_net_ops = { |
@@ -199,9 +120,11 @@ static int __init ip6table_mangle_init(void) | |||
199 | return ret; | 120 | return ret; |
200 | 121 | ||
201 | /* Register hooks */ | 122 | /* Register hooks */ |
202 | ret = nf_register_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops)); | 123 | mangle_ops = xt_hook_link(&packet_mangler, ip6table_mangle_hook); |
203 | if (ret < 0) | 124 | if (IS_ERR(mangle_ops)) { |
125 | ret = PTR_ERR(mangle_ops); | ||
204 | goto cleanup_table; | 126 | goto cleanup_table; |
127 | } | ||
205 | 128 | ||
206 | return ret; | 129 | return ret; |
207 | 130 | ||
@@ -212,7 +135,7 @@ static int __init ip6table_mangle_init(void) | |||
212 | 135 | ||
213 | static void __exit ip6table_mangle_fini(void) | 136 | static void __exit ip6table_mangle_fini(void) |
214 | { | 137 | { |
215 | nf_unregister_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops)); | 138 | xt_hook_unlink(&packet_mangler, mangle_ops); |
216 | unregister_pernet_subsys(&ip6table_mangle_net_ops); | 139 | unregister_pernet_subsys(&ip6table_mangle_net_ops); |
217 | } | 140 | } |
218 | 141 | ||
diff --git a/net/ipv6/netfilter/ip6table_raw.c b/net/ipv6/netfilter/ip6table_raw.c index ed1a1180f3b3..aef31a29de9e 100644 --- a/net/ipv6/netfilter/ip6table_raw.c +++ b/net/ipv6/netfilter/ip6table_raw.c | |||
@@ -8,85 +8,37 @@ | |||
8 | 8 | ||
9 | #define RAW_VALID_HOOKS ((1 << NF_INET_PRE_ROUTING) | (1 << NF_INET_LOCAL_OUT)) | 9 | #define RAW_VALID_HOOKS ((1 << NF_INET_PRE_ROUTING) | (1 << NF_INET_LOCAL_OUT)) |
10 | 10 | ||
11 | static const struct | ||
12 | { | ||
13 | struct ip6t_replace repl; | ||
14 | struct ip6t_standard entries[2]; | ||
15 | struct ip6t_error term; | ||
16 | } initial_table __net_initdata = { | ||
17 | .repl = { | ||
18 | .name = "raw", | ||
19 | .valid_hooks = RAW_VALID_HOOKS, | ||
20 | .num_entries = 3, | ||
21 | .size = sizeof(struct ip6t_standard) * 2 + sizeof(struct ip6t_error), | ||
22 | .hook_entry = { | ||
23 | [NF_INET_PRE_ROUTING] = 0, | ||
24 | [NF_INET_LOCAL_OUT] = sizeof(struct ip6t_standard) | ||
25 | }, | ||
26 | .underflow = { | ||
27 | [NF_INET_PRE_ROUTING] = 0, | ||
28 | [NF_INET_LOCAL_OUT] = sizeof(struct ip6t_standard) | ||
29 | }, | ||
30 | }, | ||
31 | .entries = { | ||
32 | IP6T_STANDARD_INIT(NF_ACCEPT), /* PRE_ROUTING */ | ||
33 | IP6T_STANDARD_INIT(NF_ACCEPT), /* LOCAL_OUT */ | ||
34 | }, | ||
35 | .term = IP6T_ERROR_INIT, /* ERROR */ | ||
36 | }; | ||
37 | |||
38 | static const struct xt_table packet_raw = { | 11 | static const struct xt_table packet_raw = { |
39 | .name = "raw", | 12 | .name = "raw", |
40 | .valid_hooks = RAW_VALID_HOOKS, | 13 | .valid_hooks = RAW_VALID_HOOKS, |
41 | .me = THIS_MODULE, | 14 | .me = THIS_MODULE, |
42 | .af = NFPROTO_IPV6, | 15 | .af = NFPROTO_IPV6, |
16 | .priority = NF_IP6_PRI_FIRST, | ||
43 | }; | 17 | }; |
44 | 18 | ||
45 | /* The work comes in here from netfilter.c. */ | 19 | /* The work comes in here from netfilter.c. */ |
46 | static unsigned int | 20 | static unsigned int |
47 | ip6t_pre_routing_hook(unsigned int hook, | 21 | ip6table_raw_hook(unsigned int hook, struct sk_buff *skb, |
48 | struct sk_buff *skb, | 22 | const struct net_device *in, const struct net_device *out, |
49 | const struct net_device *in, | 23 | int (*okfn)(struct sk_buff *)) |
50 | const struct net_device *out, | ||
51 | int (*okfn)(struct sk_buff *)) | ||
52 | { | 24 | { |
53 | return ip6t_do_table(skb, hook, in, out, | 25 | const struct net *net = dev_net((in != NULL) ? in : out); |
54 | dev_net(in)->ipv6.ip6table_raw); | ||
55 | } | ||
56 | 26 | ||
57 | static unsigned int | 27 | return ip6t_do_table(skb, hook, in, out, net->ipv6.ip6table_raw); |
58 | ip6t_local_out_hook(unsigned int hook, | ||
59 | struct sk_buff *skb, | ||
60 | const struct net_device *in, | ||
61 | const struct net_device *out, | ||
62 | int (*okfn)(struct sk_buff *)) | ||
63 | { | ||
64 | return ip6t_do_table(skb, hook, in, out, | ||
65 | dev_net(out)->ipv6.ip6table_raw); | ||
66 | } | 28 | } |
67 | 29 | ||
68 | static struct nf_hook_ops ip6t_ops[] __read_mostly = { | 30 | static struct nf_hook_ops *rawtable_ops __read_mostly; |
69 | { | ||
70 | .hook = ip6t_pre_routing_hook, | ||
71 | .pf = NFPROTO_IPV6, | ||
72 | .hooknum = NF_INET_PRE_ROUTING, | ||
73 | .priority = NF_IP6_PRI_FIRST, | ||
74 | .owner = THIS_MODULE, | ||
75 | }, | ||
76 | { | ||
77 | .hook = ip6t_local_out_hook, | ||
78 | .pf = NFPROTO_IPV6, | ||
79 | .hooknum = NF_INET_LOCAL_OUT, | ||
80 | .priority = NF_IP6_PRI_FIRST, | ||
81 | .owner = THIS_MODULE, | ||
82 | }, | ||
83 | }; | ||
84 | 31 | ||
85 | static int __net_init ip6table_raw_net_init(struct net *net) | 32 | static int __net_init ip6table_raw_net_init(struct net *net) |
86 | { | 33 | { |
87 | /* Register table */ | 34 | struct ip6t_replace *repl; |
35 | |||
36 | repl = ip6t_alloc_initial_table(&packet_raw); | ||
37 | if (repl == NULL) | ||
38 | return -ENOMEM; | ||
88 | net->ipv6.ip6table_raw = | 39 | net->ipv6.ip6table_raw = |
89 | ip6t_register_table(net, &packet_raw, &initial_table.repl); | 40 | ip6t_register_table(net, &packet_raw, repl); |
41 | kfree(repl); | ||
90 | if (IS_ERR(net->ipv6.ip6table_raw)) | 42 | if (IS_ERR(net->ipv6.ip6table_raw)) |
91 | return PTR_ERR(net->ipv6.ip6table_raw); | 43 | return PTR_ERR(net->ipv6.ip6table_raw); |
92 | return 0; | 44 | return 0; |
@@ -94,7 +46,7 @@ static int __net_init ip6table_raw_net_init(struct net *net) | |||
94 | 46 | ||
95 | static void __net_exit ip6table_raw_net_exit(struct net *net) | 47 | static void __net_exit ip6table_raw_net_exit(struct net *net) |
96 | { | 48 | { |
97 | ip6t_unregister_table(net->ipv6.ip6table_raw); | 49 | ip6t_unregister_table(net, net->ipv6.ip6table_raw); |
98 | } | 50 | } |
99 | 51 | ||
100 | static struct pernet_operations ip6table_raw_net_ops = { | 52 | static struct pernet_operations ip6table_raw_net_ops = { |
@@ -111,9 +63,11 @@ static int __init ip6table_raw_init(void) | |||
111 | return ret; | 63 | return ret; |
112 | 64 | ||
113 | /* Register hooks */ | 65 | /* Register hooks */ |
114 | ret = nf_register_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops)); | 66 | rawtable_ops = xt_hook_link(&packet_raw, ip6table_raw_hook); |
115 | if (ret < 0) | 67 | if (IS_ERR(rawtable_ops)) { |
68 | ret = PTR_ERR(rawtable_ops); | ||
116 | goto cleanup_table; | 69 | goto cleanup_table; |
70 | } | ||
117 | 71 | ||
118 | return ret; | 72 | return ret; |
119 | 73 | ||
@@ -124,7 +78,7 @@ static int __init ip6table_raw_init(void) | |||
124 | 78 | ||
125 | static void __exit ip6table_raw_fini(void) | 79 | static void __exit ip6table_raw_fini(void) |
126 | { | 80 | { |
127 | nf_unregister_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops)); | 81 | xt_hook_unlink(&packet_raw, rawtable_ops); |
128 | unregister_pernet_subsys(&ip6table_raw_net_ops); | 82 | unregister_pernet_subsys(&ip6table_raw_net_ops); |
129 | } | 83 | } |
130 | 84 | ||
diff --git a/net/ipv6/netfilter/ip6table_security.c b/net/ipv6/netfilter/ip6table_security.c index 41b444c60934..0824d865aa9b 100644 --- a/net/ipv6/netfilter/ip6table_security.c +++ b/net/ipv6/netfilter/ip6table_security.c | |||
@@ -26,106 +26,37 @@ MODULE_DESCRIPTION("ip6tables security table, for MAC rules"); | |||
26 | (1 << NF_INET_FORWARD) | \ | 26 | (1 << NF_INET_FORWARD) | \ |
27 | (1 << NF_INET_LOCAL_OUT) | 27 | (1 << NF_INET_LOCAL_OUT) |
28 | 28 | ||
29 | static const struct | ||
30 | { | ||
31 | struct ip6t_replace repl; | ||
32 | struct ip6t_standard entries[3]; | ||
33 | struct ip6t_error term; | ||
34 | } initial_table __net_initdata = { | ||
35 | .repl = { | ||
36 | .name = "security", | ||
37 | .valid_hooks = SECURITY_VALID_HOOKS, | ||
38 | .num_entries = 4, | ||
39 | .size = sizeof(struct ip6t_standard) * 3 + sizeof(struct ip6t_error), | ||
40 | .hook_entry = { | ||
41 | [NF_INET_LOCAL_IN] = 0, | ||
42 | [NF_INET_FORWARD] = sizeof(struct ip6t_standard), | ||
43 | [NF_INET_LOCAL_OUT] = sizeof(struct ip6t_standard) * 2, | ||
44 | }, | ||
45 | .underflow = { | ||
46 | [NF_INET_LOCAL_IN] = 0, | ||
47 | [NF_INET_FORWARD] = sizeof(struct ip6t_standard), | ||
48 | [NF_INET_LOCAL_OUT] = sizeof(struct ip6t_standard) * 2, | ||
49 | }, | ||
50 | }, | ||
51 | .entries = { | ||
52 | IP6T_STANDARD_INIT(NF_ACCEPT), /* LOCAL_IN */ | ||
53 | IP6T_STANDARD_INIT(NF_ACCEPT), /* FORWARD */ | ||
54 | IP6T_STANDARD_INIT(NF_ACCEPT), /* LOCAL_OUT */ | ||
55 | }, | ||
56 | .term = IP6T_ERROR_INIT, /* ERROR */ | ||
57 | }; | ||
58 | |||
59 | static const struct xt_table security_table = { | 29 | static const struct xt_table security_table = { |
60 | .name = "security", | 30 | .name = "security", |
61 | .valid_hooks = SECURITY_VALID_HOOKS, | 31 | .valid_hooks = SECURITY_VALID_HOOKS, |
62 | .me = THIS_MODULE, | 32 | .me = THIS_MODULE, |
63 | .af = NFPROTO_IPV6, | 33 | .af = NFPROTO_IPV6, |
34 | .priority = NF_IP6_PRI_SECURITY, | ||
64 | }; | 35 | }; |
65 | 36 | ||
66 | static unsigned int | 37 | static unsigned int |
67 | ip6t_local_in_hook(unsigned int hook, | 38 | ip6table_security_hook(unsigned int hook, struct sk_buff *skb, |
68 | struct sk_buff *skb, | 39 | const struct net_device *in, |
69 | const struct net_device *in, | 40 | const struct net_device *out, |
70 | const struct net_device *out, | 41 | int (*okfn)(struct sk_buff *)) |
71 | int (*okfn)(struct sk_buff *)) | ||
72 | { | ||
73 | return ip6t_do_table(skb, hook, in, out, | ||
74 | dev_net(in)->ipv6.ip6table_security); | ||
75 | } | ||
76 | |||
77 | static unsigned int | ||
78 | ip6t_forward_hook(unsigned int hook, | ||
79 | struct sk_buff *skb, | ||
80 | const struct net_device *in, | ||
81 | const struct net_device *out, | ||
82 | int (*okfn)(struct sk_buff *)) | ||
83 | { | 42 | { |
84 | return ip6t_do_table(skb, hook, in, out, | 43 | const struct net *net = dev_net((in != NULL) ? in : out); |
85 | dev_net(in)->ipv6.ip6table_security); | ||
86 | } | ||
87 | 44 | ||
88 | static unsigned int | 45 | return ip6t_do_table(skb, hook, in, out, net->ipv6.ip6table_security); |
89 | ip6t_local_out_hook(unsigned int hook, | ||
90 | struct sk_buff *skb, | ||
91 | const struct net_device *in, | ||
92 | const struct net_device *out, | ||
93 | int (*okfn)(struct sk_buff *)) | ||
94 | { | ||
95 | /* TBD: handle short packets via raw socket */ | ||
96 | return ip6t_do_table(skb, hook, in, out, | ||
97 | dev_net(out)->ipv6.ip6table_security); | ||
98 | } | 46 | } |
99 | 47 | ||
100 | static struct nf_hook_ops ip6t_ops[] __read_mostly = { | 48 | static struct nf_hook_ops *sectbl_ops __read_mostly; |
101 | { | ||
102 | .hook = ip6t_local_in_hook, | ||
103 | .owner = THIS_MODULE, | ||
104 | .pf = NFPROTO_IPV6, | ||
105 | .hooknum = NF_INET_LOCAL_IN, | ||
106 | .priority = NF_IP6_PRI_SECURITY, | ||
107 | }, | ||
108 | { | ||
109 | .hook = ip6t_forward_hook, | ||
110 | .owner = THIS_MODULE, | ||
111 | .pf = NFPROTO_IPV6, | ||
112 | .hooknum = NF_INET_FORWARD, | ||
113 | .priority = NF_IP6_PRI_SECURITY, | ||
114 | }, | ||
115 | { | ||
116 | .hook = ip6t_local_out_hook, | ||
117 | .owner = THIS_MODULE, | ||
118 | .pf = NFPROTO_IPV6, | ||
119 | .hooknum = NF_INET_LOCAL_OUT, | ||
120 | .priority = NF_IP6_PRI_SECURITY, | ||
121 | }, | ||
122 | }; | ||
123 | 49 | ||
124 | static int __net_init ip6table_security_net_init(struct net *net) | 50 | static int __net_init ip6table_security_net_init(struct net *net) |
125 | { | 51 | { |
126 | net->ipv6.ip6table_security = | 52 | struct ip6t_replace *repl; |
127 | ip6t_register_table(net, &security_table, &initial_table.repl); | ||
128 | 53 | ||
54 | repl = ip6t_alloc_initial_table(&security_table); | ||
55 | if (repl == NULL) | ||
56 | return -ENOMEM; | ||
57 | net->ipv6.ip6table_security = | ||
58 | ip6t_register_table(net, &security_table, repl); | ||
59 | kfree(repl); | ||
129 | if (IS_ERR(net->ipv6.ip6table_security)) | 60 | if (IS_ERR(net->ipv6.ip6table_security)) |
130 | return PTR_ERR(net->ipv6.ip6table_security); | 61 | return PTR_ERR(net->ipv6.ip6table_security); |
131 | 62 | ||
@@ -134,7 +65,7 @@ static int __net_init ip6table_security_net_init(struct net *net) | |||
134 | 65 | ||
135 | static void __net_exit ip6table_security_net_exit(struct net *net) | 66 | static void __net_exit ip6table_security_net_exit(struct net *net) |
136 | { | 67 | { |
137 | ip6t_unregister_table(net->ipv6.ip6table_security); | 68 | ip6t_unregister_table(net, net->ipv6.ip6table_security); |
138 | } | 69 | } |
139 | 70 | ||
140 | static struct pernet_operations ip6table_security_net_ops = { | 71 | static struct pernet_operations ip6table_security_net_ops = { |
@@ -150,9 +81,11 @@ static int __init ip6table_security_init(void) | |||
150 | if (ret < 0) | 81 | if (ret < 0) |
151 | return ret; | 82 | return ret; |
152 | 83 | ||
153 | ret = nf_register_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops)); | 84 | sectbl_ops = xt_hook_link(&security_table, ip6table_security_hook); |
154 | if (ret < 0) | 85 | if (IS_ERR(sectbl_ops)) { |
86 | ret = PTR_ERR(sectbl_ops); | ||
155 | goto cleanup_table; | 87 | goto cleanup_table; |
88 | } | ||
156 | 89 | ||
157 | return ret; | 90 | return ret; |
158 | 91 | ||
@@ -163,7 +96,7 @@ cleanup_table: | |||
163 | 96 | ||
164 | static void __exit ip6table_security_fini(void) | 97 | static void __exit ip6table_security_fini(void) |
165 | { | 98 | { |
166 | nf_unregister_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops)); | 99 | xt_hook_unlink(&security_table, sectbl_ops); |
167 | unregister_pernet_subsys(&ip6table_security_net_ops); | 100 | unregister_pernet_subsys(&ip6table_security_net_ops); |
168 | } | 101 | } |
169 | 102 | ||
diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c index 0956ebabbff2..996c3f41fecd 100644 --- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c +++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <net/netfilter/nf_conntrack_l4proto.h> | 27 | #include <net/netfilter/nf_conntrack_l4proto.h> |
28 | #include <net/netfilter/nf_conntrack_l3proto.h> | 28 | #include <net/netfilter/nf_conntrack_l3proto.h> |
29 | #include <net/netfilter/nf_conntrack_core.h> | 29 | #include <net/netfilter/nf_conntrack_core.h> |
30 | #include <net/netfilter/nf_conntrack_zones.h> | ||
30 | #include <net/netfilter/ipv6/nf_conntrack_ipv6.h> | 31 | #include <net/netfilter/ipv6/nf_conntrack_ipv6.h> |
31 | #include <net/netfilter/nf_log.h> | 32 | #include <net/netfilter/nf_log.h> |
32 | 33 | ||
@@ -191,15 +192,20 @@ out: | |||
191 | static enum ip6_defrag_users nf_ct6_defrag_user(unsigned int hooknum, | 192 | static enum ip6_defrag_users nf_ct6_defrag_user(unsigned int hooknum, |
192 | struct sk_buff *skb) | 193 | struct sk_buff *skb) |
193 | { | 194 | { |
195 | u16 zone = NF_CT_DEFAULT_ZONE; | ||
196 | |||
197 | if (skb->nfct) | ||
198 | zone = nf_ct_zone((struct nf_conn *)skb->nfct); | ||
199 | |||
194 | #ifdef CONFIG_BRIDGE_NETFILTER | 200 | #ifdef CONFIG_BRIDGE_NETFILTER |
195 | if (skb->nf_bridge && | 201 | if (skb->nf_bridge && |
196 | skb->nf_bridge->mask & BRNF_NF_BRIDGE_PREROUTING) | 202 | skb->nf_bridge->mask & BRNF_NF_BRIDGE_PREROUTING) |
197 | return IP6_DEFRAG_CONNTRACK_BRIDGE_IN; | 203 | return IP6_DEFRAG_CONNTRACK_BRIDGE_IN + zone; |
198 | #endif | 204 | #endif |
199 | if (hooknum == NF_INET_PRE_ROUTING) | 205 | if (hooknum == NF_INET_PRE_ROUTING) |
200 | return IP6_DEFRAG_CONNTRACK_IN; | 206 | return IP6_DEFRAG_CONNTRACK_IN + zone; |
201 | else | 207 | else |
202 | return IP6_DEFRAG_CONNTRACK_OUT; | 208 | return IP6_DEFRAG_CONNTRACK_OUT + zone; |
203 | 209 | ||
204 | } | 210 | } |
205 | 211 | ||
@@ -212,7 +218,7 @@ static unsigned int ipv6_defrag(unsigned int hooknum, | |||
212 | struct sk_buff *reasm; | 218 | struct sk_buff *reasm; |
213 | 219 | ||
214 | /* Previously seen (loopback)? */ | 220 | /* Previously seen (loopback)? */ |
215 | if (skb->nfct) | 221 | if (skb->nfct && !nf_ct_is_template((struct nf_conn *)skb->nfct)) |
216 | return NF_ACCEPT; | 222 | return NF_ACCEPT; |
217 | 223 | ||
218 | reasm = nf_ct_frag6_gather(skb, nf_ct6_defrag_user(hooknum, skb)); | 224 | reasm = nf_ct_frag6_gather(skb, nf_ct6_defrag_user(hooknum, skb)); |
diff --git a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c index c7b8bd1d7984..9be81776415e 100644 --- a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c +++ b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <net/netfilter/nf_conntrack_tuple.h> | 23 | #include <net/netfilter/nf_conntrack_tuple.h> |
24 | #include <net/netfilter/nf_conntrack_l4proto.h> | 24 | #include <net/netfilter/nf_conntrack_l4proto.h> |
25 | #include <net/netfilter/nf_conntrack_core.h> | 25 | #include <net/netfilter/nf_conntrack_core.h> |
26 | #include <net/netfilter/nf_conntrack_zones.h> | ||
26 | #include <net/netfilter/ipv6/nf_conntrack_icmpv6.h> | 27 | #include <net/netfilter/ipv6/nf_conntrack_icmpv6.h> |
27 | #include <net/netfilter/nf_log.h> | 28 | #include <net/netfilter/nf_log.h> |
28 | 29 | ||
@@ -128,7 +129,7 @@ static bool icmpv6_new(struct nf_conn *ct, const struct sk_buff *skb, | |||
128 | } | 129 | } |
129 | 130 | ||
130 | static int | 131 | static int |
131 | icmpv6_error_message(struct net *net, | 132 | icmpv6_error_message(struct net *net, struct nf_conn *tmpl, |
132 | struct sk_buff *skb, | 133 | struct sk_buff *skb, |
133 | unsigned int icmp6off, | 134 | unsigned int icmp6off, |
134 | enum ip_conntrack_info *ctinfo, | 135 | enum ip_conntrack_info *ctinfo, |
@@ -137,6 +138,7 @@ icmpv6_error_message(struct net *net, | |||
137 | struct nf_conntrack_tuple intuple, origtuple; | 138 | struct nf_conntrack_tuple intuple, origtuple; |
138 | const struct nf_conntrack_tuple_hash *h; | 139 | const struct nf_conntrack_tuple_hash *h; |
139 | const struct nf_conntrack_l4proto *inproto; | 140 | const struct nf_conntrack_l4proto *inproto; |
141 | u16 zone = tmpl ? nf_ct_zone(tmpl) : NF_CT_DEFAULT_ZONE; | ||
140 | 142 | ||
141 | NF_CT_ASSERT(skb->nfct == NULL); | 143 | NF_CT_ASSERT(skb->nfct == NULL); |
142 | 144 | ||
@@ -163,7 +165,7 @@ icmpv6_error_message(struct net *net, | |||
163 | 165 | ||
164 | *ctinfo = IP_CT_RELATED; | 166 | *ctinfo = IP_CT_RELATED; |
165 | 167 | ||
166 | h = nf_conntrack_find_get(net, &intuple); | 168 | h = nf_conntrack_find_get(net, zone, &intuple); |
167 | if (!h) { | 169 | if (!h) { |
168 | pr_debug("icmpv6_error: no match\n"); | 170 | pr_debug("icmpv6_error: no match\n"); |
169 | return -NF_ACCEPT; | 171 | return -NF_ACCEPT; |
@@ -179,7 +181,8 @@ icmpv6_error_message(struct net *net, | |||
179 | } | 181 | } |
180 | 182 | ||
181 | static int | 183 | static int |
182 | icmpv6_error(struct net *net, struct sk_buff *skb, unsigned int dataoff, | 184 | icmpv6_error(struct net *net, struct nf_conn *tmpl, |
185 | struct sk_buff *skb, unsigned int dataoff, | ||
183 | enum ip_conntrack_info *ctinfo, u_int8_t pf, unsigned int hooknum) | 186 | enum ip_conntrack_info *ctinfo, u_int8_t pf, unsigned int hooknum) |
184 | { | 187 | { |
185 | const struct icmp6hdr *icmp6h; | 188 | const struct icmp6hdr *icmp6h; |
@@ -215,7 +218,7 @@ icmpv6_error(struct net *net, struct sk_buff *skb, unsigned int dataoff, | |||
215 | if (icmp6h->icmp6_type >= 128) | 218 | if (icmp6h->icmp6_type >= 128) |
216 | return NF_ACCEPT; | 219 | return NF_ACCEPT; |
217 | 220 | ||
218 | return icmpv6_error_message(net, skb, dataoff, ctinfo, hooknum); | 221 | return icmpv6_error_message(net, tmpl, skb, dataoff, ctinfo, hooknum); |
219 | } | 222 | } |
220 | 223 | ||
221 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) | 224 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) |
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c index 624a54832a7c..f1171b744650 100644 --- a/net/ipv6/netfilter/nf_conntrack_reasm.c +++ b/net/ipv6/netfilter/nf_conntrack_reasm.c | |||
@@ -45,9 +45,6 @@ | |||
45 | #include <linux/kernel.h> | 45 | #include <linux/kernel.h> |
46 | #include <linux/module.h> | 46 | #include <linux/module.h> |
47 | 47 | ||
48 | #define NF_CT_FRAG6_HIGH_THRESH 262144 /* == 256*1024 */ | ||
49 | #define NF_CT_FRAG6_LOW_THRESH 196608 /* == 192*1024 */ | ||
50 | #define NF_CT_FRAG6_TIMEOUT IPV6_FRAG_TIMEOUT | ||
51 | 48 | ||
52 | struct nf_ct_frag6_skb_cb | 49 | struct nf_ct_frag6_skb_cb |
53 | { | 50 | { |
@@ -472,7 +469,7 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev) | |||
472 | 469 | ||
473 | /* all original skbs are linked into the NFCT_FRAG6_CB(head).orig */ | 470 | /* all original skbs are linked into the NFCT_FRAG6_CB(head).orig */ |
474 | fp = skb_shinfo(head)->frag_list; | 471 | fp = skb_shinfo(head)->frag_list; |
475 | if (NFCT_FRAG6_CB(fp)->orig == NULL) | 472 | if (fp && NFCT_FRAG6_CB(fp)->orig == NULL) |
476 | /* at above code, head skb is divided into two skbs. */ | 473 | /* at above code, head skb is divided into two skbs. */ |
477 | fp = fp->next; | 474 | fp = fp->next; |
478 | 475 | ||
@@ -598,12 +595,6 @@ struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb, u32 user) | |||
598 | hdr = ipv6_hdr(clone); | 595 | hdr = ipv6_hdr(clone); |
599 | fhdr = (struct frag_hdr *)skb_transport_header(clone); | 596 | fhdr = (struct frag_hdr *)skb_transport_header(clone); |
600 | 597 | ||
601 | if (!(fhdr->frag_off & htons(0xFFF9))) { | ||
602 | pr_debug("Invalid fragment offset\n"); | ||
603 | /* It is not a fragmented frame */ | ||
604 | goto ret_orig; | ||
605 | } | ||
606 | |||
607 | if (atomic_read(&nf_init_frags.mem) > nf_init_frags.high_thresh) | 598 | if (atomic_read(&nf_init_frags.mem) > nf_init_frags.high_thresh) |
608 | nf_ct_frag6_evictor(); | 599 | nf_ct_frag6_evictor(); |
609 | 600 | ||
@@ -670,8 +661,8 @@ int nf_ct_frag6_init(void) | |||
670 | nf_frags.frag_expire = nf_ct_frag6_expire; | 661 | nf_frags.frag_expire = nf_ct_frag6_expire; |
671 | nf_frags.secret_interval = 10 * 60 * HZ; | 662 | nf_frags.secret_interval = 10 * 60 * HZ; |
672 | nf_init_frags.timeout = IPV6_FRAG_TIMEOUT; | 663 | nf_init_frags.timeout = IPV6_FRAG_TIMEOUT; |
673 | nf_init_frags.high_thresh = 256 * 1024; | 664 | nf_init_frags.high_thresh = IPV6_FRAG_HIGH_THRESH; |
674 | nf_init_frags.low_thresh = 192 * 1024; | 665 | nf_init_frags.low_thresh = IPV6_FRAG_LOW_THRESH; |
675 | inet_frags_init_net(&nf_init_frags); | 666 | inet_frags_init_net(&nf_init_frags); |
676 | inet_frags_init(&nf_frags); | 667 | inet_frags_init(&nf_frags); |
677 | 668 | ||
diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c index c9605c3ad91f..58344c0fbd13 100644 --- a/net/ipv6/proc.c +++ b/net/ipv6/proc.c | |||
@@ -59,7 +59,7 @@ static const struct file_operations sockstat6_seq_fops = { | |||
59 | .release = single_release_net, | 59 | .release = single_release_net, |
60 | }; | 60 | }; |
61 | 61 | ||
62 | static struct snmp_mib snmp6_ipstats_list[] = { | 62 | static const struct snmp_mib snmp6_ipstats_list[] = { |
63 | /* ipv6 mib according to RFC 2465 */ | 63 | /* ipv6 mib according to RFC 2465 */ |
64 | SNMP_MIB_ITEM("Ip6InReceives", IPSTATS_MIB_INPKTS), | 64 | SNMP_MIB_ITEM("Ip6InReceives", IPSTATS_MIB_INPKTS), |
65 | SNMP_MIB_ITEM("Ip6InHdrErrors", IPSTATS_MIB_INHDRERRORS), | 65 | SNMP_MIB_ITEM("Ip6InHdrErrors", IPSTATS_MIB_INHDRERRORS), |
@@ -92,7 +92,7 @@ static struct snmp_mib snmp6_ipstats_list[] = { | |||
92 | SNMP_MIB_SENTINEL | 92 | SNMP_MIB_SENTINEL |
93 | }; | 93 | }; |
94 | 94 | ||
95 | static struct snmp_mib snmp6_icmp6_list[] = { | 95 | static const struct snmp_mib snmp6_icmp6_list[] = { |
96 | /* icmpv6 mib according to RFC 2466 */ | 96 | /* icmpv6 mib according to RFC 2466 */ |
97 | SNMP_MIB_ITEM("Icmp6InMsgs", ICMP6_MIB_INMSGS), | 97 | SNMP_MIB_ITEM("Icmp6InMsgs", ICMP6_MIB_INMSGS), |
98 | SNMP_MIB_ITEM("Icmp6InErrors", ICMP6_MIB_INERRORS), | 98 | SNMP_MIB_ITEM("Icmp6InErrors", ICMP6_MIB_INERRORS), |
@@ -120,7 +120,7 @@ static const char *const icmp6type2name[256] = { | |||
120 | }; | 120 | }; |
121 | 121 | ||
122 | 122 | ||
123 | static struct snmp_mib snmp6_udp6_list[] = { | 123 | static const struct snmp_mib snmp6_udp6_list[] = { |
124 | SNMP_MIB_ITEM("Udp6InDatagrams", UDP_MIB_INDATAGRAMS), | 124 | SNMP_MIB_ITEM("Udp6InDatagrams", UDP_MIB_INDATAGRAMS), |
125 | SNMP_MIB_ITEM("Udp6NoPorts", UDP_MIB_NOPORTS), | 125 | SNMP_MIB_ITEM("Udp6NoPorts", UDP_MIB_NOPORTS), |
126 | SNMP_MIB_ITEM("Udp6InErrors", UDP_MIB_INERRORS), | 126 | SNMP_MIB_ITEM("Udp6InErrors", UDP_MIB_INERRORS), |
@@ -128,7 +128,7 @@ static struct snmp_mib snmp6_udp6_list[] = { | |||
128 | SNMP_MIB_SENTINEL | 128 | SNMP_MIB_SENTINEL |
129 | }; | 129 | }; |
130 | 130 | ||
131 | static struct snmp_mib snmp6_udplite6_list[] = { | 131 | static const struct snmp_mib snmp6_udplite6_list[] = { |
132 | SNMP_MIB_ITEM("UdpLite6InDatagrams", UDP_MIB_INDATAGRAMS), | 132 | SNMP_MIB_ITEM("UdpLite6InDatagrams", UDP_MIB_INDATAGRAMS), |
133 | SNMP_MIB_ITEM("UdpLite6NoPorts", UDP_MIB_NOPORTS), | 133 | SNMP_MIB_ITEM("UdpLite6NoPorts", UDP_MIB_NOPORTS), |
134 | SNMP_MIB_ITEM("UdpLite6InErrors", UDP_MIB_INERRORS), | 134 | SNMP_MIB_ITEM("UdpLite6InErrors", UDP_MIB_INERRORS), |
@@ -136,7 +136,7 @@ static struct snmp_mib snmp6_udplite6_list[] = { | |||
136 | SNMP_MIB_SENTINEL | 136 | SNMP_MIB_SENTINEL |
137 | }; | 137 | }; |
138 | 138 | ||
139 | static void snmp6_seq_show_icmpv6msg(struct seq_file *seq, void **mib) | 139 | static void snmp6_seq_show_icmpv6msg(struct seq_file *seq, void __percpu **mib) |
140 | { | 140 | { |
141 | char name[32]; | 141 | char name[32]; |
142 | int i; | 142 | int i; |
@@ -170,8 +170,8 @@ static void snmp6_seq_show_icmpv6msg(struct seq_file *seq, void **mib) | |||
170 | return; | 170 | return; |
171 | } | 171 | } |
172 | 172 | ||
173 | static inline void | 173 | static void snmp6_seq_show_item(struct seq_file *seq, void __percpu **mib, |
174 | snmp6_seq_show_item(struct seq_file *seq, void **mib, struct snmp_mib *itemlist) | 174 | const struct snmp_mib *itemlist) |
175 | { | 175 | { |
176 | int i; | 176 | int i; |
177 | for (i=0; itemlist[i].name; i++) | 177 | for (i=0; itemlist[i].name; i++) |
@@ -183,14 +183,15 @@ static int snmp6_seq_show(struct seq_file *seq, void *v) | |||
183 | { | 183 | { |
184 | struct net *net = (struct net *)seq->private; | 184 | struct net *net = (struct net *)seq->private; |
185 | 185 | ||
186 | snmp6_seq_show_item(seq, (void **)net->mib.ipv6_statistics, | 186 | snmp6_seq_show_item(seq, (void __percpu **)net->mib.ipv6_statistics, |
187 | snmp6_ipstats_list); | 187 | snmp6_ipstats_list); |
188 | snmp6_seq_show_item(seq, (void **)net->mib.icmpv6_statistics, | 188 | snmp6_seq_show_item(seq, (void __percpu **)net->mib.icmpv6_statistics, |
189 | snmp6_icmp6_list); | 189 | snmp6_icmp6_list); |
190 | snmp6_seq_show_icmpv6msg(seq, (void **)net->mib.icmpv6msg_statistics); | 190 | snmp6_seq_show_icmpv6msg(seq, |
191 | snmp6_seq_show_item(seq, (void **)net->mib.udp_stats_in6, | 191 | (void __percpu **)net->mib.icmpv6msg_statistics); |
192 | snmp6_seq_show_item(seq, (void __percpu **)net->mib.udp_stats_in6, | ||
192 | snmp6_udp6_list); | 193 | snmp6_udp6_list); |
193 | snmp6_seq_show_item(seq, (void **)net->mib.udplite_stats_in6, | 194 | snmp6_seq_show_item(seq, (void __percpu **)net->mib.udplite_stats_in6, |
194 | snmp6_udplite6_list); | 195 | snmp6_udplite6_list); |
195 | return 0; | 196 | return 0; |
196 | } | 197 | } |
@@ -213,9 +214,11 @@ static int snmp6_dev_seq_show(struct seq_file *seq, void *v) | |||
213 | struct inet6_dev *idev = (struct inet6_dev *)seq->private; | 214 | struct inet6_dev *idev = (struct inet6_dev *)seq->private; |
214 | 215 | ||
215 | seq_printf(seq, "%-32s\t%u\n", "ifIndex", idev->dev->ifindex); | 216 | seq_printf(seq, "%-32s\t%u\n", "ifIndex", idev->dev->ifindex); |
216 | snmp6_seq_show_item(seq, (void **)idev->stats.ipv6, snmp6_ipstats_list); | 217 | snmp6_seq_show_item(seq, (void __percpu **)idev->stats.ipv6, |
217 | snmp6_seq_show_item(seq, (void **)idev->stats.icmpv6, snmp6_icmp6_list); | 218 | snmp6_ipstats_list); |
218 | snmp6_seq_show_icmpv6msg(seq, (void **)idev->stats.icmpv6msg); | 219 | snmp6_seq_show_item(seq, (void __percpu **)idev->stats.icmpv6, |
220 | snmp6_icmp6_list); | ||
221 | snmp6_seq_show_icmpv6msg(seq, (void __percpu **)idev->stats.icmpv6msg); | ||
219 | return 0; | 222 | return 0; |
220 | } | 223 | } |
221 | 224 | ||
@@ -259,7 +262,7 @@ int snmp6_unregister_dev(struct inet6_dev *idev) | |||
259 | struct net *net = dev_net(idev->dev); | 262 | struct net *net = dev_net(idev->dev); |
260 | if (!net->mib.proc_net_devsnmp6) | 263 | if (!net->mib.proc_net_devsnmp6) |
261 | return -ENOENT; | 264 | return -ENOENT; |
262 | if (!idev || !idev->stats.proc_dir_entry) | 265 | if (!idev->stats.proc_dir_entry) |
263 | return -EINVAL; | 266 | return -EINVAL; |
264 | remove_proc_entry(idev->stats.proc_dir_entry->name, | 267 | remove_proc_entry(idev->stats.proc_dir_entry->name, |
265 | net->mib.proc_net_devsnmp6); | 268 | net->mib.proc_net_devsnmp6); |
@@ -267,7 +270,7 @@ int snmp6_unregister_dev(struct inet6_dev *idev) | |||
267 | return 0; | 270 | return 0; |
268 | } | 271 | } |
269 | 272 | ||
270 | static int ipv6_proc_init_net(struct net *net) | 273 | static int __net_init ipv6_proc_init_net(struct net *net) |
271 | { | 274 | { |
272 | if (!proc_net_fops_create(net, "sockstat6", S_IRUGO, | 275 | if (!proc_net_fops_create(net, "sockstat6", S_IRUGO, |
273 | &sockstat6_seq_fops)) | 276 | &sockstat6_seq_fops)) |
@@ -288,7 +291,7 @@ proc_dev_snmp6_fail: | |||
288 | return -ENOMEM; | 291 | return -ENOMEM; |
289 | } | 292 | } |
290 | 293 | ||
291 | static void ipv6_proc_exit_net(struct net *net) | 294 | static void __net_exit ipv6_proc_exit_net(struct net *net) |
292 | { | 295 | { |
293 | proc_net_remove(net, "sockstat6"); | 296 | proc_net_remove(net, "sockstat6"); |
294 | proc_net_remove(net, "dev_snmp6"); | 297 | proc_net_remove(net, "dev_snmp6"); |
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 926ce8eeffaf..ed31c37c6e39 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c | |||
@@ -1275,7 +1275,7 @@ static const struct file_operations raw6_seq_fops = { | |||
1275 | .release = seq_release_net, | 1275 | .release = seq_release_net, |
1276 | }; | 1276 | }; |
1277 | 1277 | ||
1278 | static int raw6_init_net(struct net *net) | 1278 | static int __net_init raw6_init_net(struct net *net) |
1279 | { | 1279 | { |
1280 | if (!proc_net_fops_create(net, "raw6", S_IRUGO, &raw6_seq_fops)) | 1280 | if (!proc_net_fops_create(net, "raw6", S_IRUGO, &raw6_seq_fops)) |
1281 | return -ENOMEM; | 1281 | return -ENOMEM; |
@@ -1283,7 +1283,7 @@ static int raw6_init_net(struct net *net) | |||
1283 | return 0; | 1283 | return 0; |
1284 | } | 1284 | } |
1285 | 1285 | ||
1286 | static void raw6_exit_net(struct net *net) | 1286 | static void __net_exit raw6_exit_net(struct net *net) |
1287 | { | 1287 | { |
1288 | proc_net_remove(net, "raw6"); | 1288 | proc_net_remove(net, "raw6"); |
1289 | } | 1289 | } |
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index 2cddea3bd6be..a555156e9779 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c | |||
@@ -228,7 +228,7 @@ static void ip6_frag_expire(unsigned long data) | |||
228 | pointer directly, device might already disappeared. | 228 | pointer directly, device might already disappeared. |
229 | */ | 229 | */ |
230 | fq->q.fragments->dev = dev; | 230 | fq->q.fragments->dev = dev; |
231 | icmpv6_send(fq->q.fragments, ICMPV6_TIME_EXCEED, ICMPV6_EXC_FRAGTIME, 0, dev); | 231 | icmpv6_send(fq->q.fragments, ICMPV6_TIME_EXCEED, ICMPV6_EXC_FRAGTIME, 0); |
232 | out_rcu_unlock: | 232 | out_rcu_unlock: |
233 | rcu_read_unlock(); | 233 | rcu_read_unlock(); |
234 | out: | 234 | out: |
@@ -237,8 +237,7 @@ out: | |||
237 | } | 237 | } |
238 | 238 | ||
239 | static __inline__ struct frag_queue * | 239 | static __inline__ struct frag_queue * |
240 | fq_find(struct net *net, __be32 id, struct in6_addr *src, struct in6_addr *dst, | 240 | fq_find(struct net *net, __be32 id, struct in6_addr *src, struct in6_addr *dst) |
241 | struct inet6_dev *idev) | ||
242 | { | 241 | { |
243 | struct inet_frag_queue *q; | 242 | struct inet_frag_queue *q; |
244 | struct ip6_create_arg arg; | 243 | struct ip6_create_arg arg; |
@@ -254,13 +253,9 @@ fq_find(struct net *net, __be32 id, struct in6_addr *src, struct in6_addr *dst, | |||
254 | 253 | ||
255 | q = inet_frag_find(&net->ipv6.frags, &ip6_frags, &arg, hash); | 254 | q = inet_frag_find(&net->ipv6.frags, &ip6_frags, &arg, hash); |
256 | if (q == NULL) | 255 | if (q == NULL) |
257 | goto oom; | 256 | return NULL; |
258 | 257 | ||
259 | return container_of(q, struct frag_queue, q); | 258 | return container_of(q, struct frag_queue, q); |
260 | |||
261 | oom: | ||
262 | IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_REASMFAILS); | ||
263 | return NULL; | ||
264 | } | 259 | } |
265 | 260 | ||
266 | static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, | 261 | static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, |
@@ -606,8 +601,8 @@ static int ipv6_frag_rcv(struct sk_buff *skb) | |||
606 | if (atomic_read(&net->ipv6.frags.mem) > net->ipv6.frags.high_thresh) | 601 | if (atomic_read(&net->ipv6.frags.mem) > net->ipv6.frags.high_thresh) |
607 | ip6_evictor(net, ip6_dst_idev(skb_dst(skb))); | 602 | ip6_evictor(net, ip6_dst_idev(skb_dst(skb))); |
608 | 603 | ||
609 | if ((fq = fq_find(net, fhdr->identification, &hdr->saddr, &hdr->daddr, | 604 | fq = fq_find(net, fhdr->identification, &hdr->saddr, &hdr->daddr); |
610 | ip6_dst_idev(skb_dst(skb)))) != NULL) { | 605 | if (fq != NULL) { |
611 | int ret; | 606 | int ret; |
612 | 607 | ||
613 | spin_lock(&fq->q.lock); | 608 | spin_lock(&fq->q.lock); |
@@ -672,7 +667,7 @@ static struct ctl_table ip6_frags_ctl_table[] = { | |||
672 | { } | 667 | { } |
673 | }; | 668 | }; |
674 | 669 | ||
675 | static int ip6_frags_ns_sysctl_register(struct net *net) | 670 | static int __net_init ip6_frags_ns_sysctl_register(struct net *net) |
676 | { | 671 | { |
677 | struct ctl_table *table; | 672 | struct ctl_table *table; |
678 | struct ctl_table_header *hdr; | 673 | struct ctl_table_header *hdr; |
@@ -702,7 +697,7 @@ err_alloc: | |||
702 | return -ENOMEM; | 697 | return -ENOMEM; |
703 | } | 698 | } |
704 | 699 | ||
705 | static void ip6_frags_ns_sysctl_unregister(struct net *net) | 700 | static void __net_exit ip6_frags_ns_sysctl_unregister(struct net *net) |
706 | { | 701 | { |
707 | struct ctl_table *table; | 702 | struct ctl_table *table; |
708 | 703 | ||
@@ -745,10 +740,10 @@ static inline void ip6_frags_sysctl_unregister(void) | |||
745 | } | 740 | } |
746 | #endif | 741 | #endif |
747 | 742 | ||
748 | static int ipv6_frags_init_net(struct net *net) | 743 | static int __net_init ipv6_frags_init_net(struct net *net) |
749 | { | 744 | { |
750 | net->ipv6.frags.high_thresh = 256 * 1024; | 745 | net->ipv6.frags.high_thresh = IPV6_FRAG_HIGH_THRESH; |
751 | net->ipv6.frags.low_thresh = 192 * 1024; | 746 | net->ipv6.frags.low_thresh = IPV6_FRAG_LOW_THRESH; |
752 | net->ipv6.frags.timeout = IPV6_FRAG_TIMEOUT; | 747 | net->ipv6.frags.timeout = IPV6_FRAG_TIMEOUT; |
753 | 748 | ||
754 | inet_frags_init_net(&net->ipv6.frags); | 749 | inet_frags_init_net(&net->ipv6.frags); |
@@ -756,7 +751,7 @@ static int ipv6_frags_init_net(struct net *net) | |||
756 | return ip6_frags_ns_sysctl_register(net); | 751 | return ip6_frags_ns_sysctl_register(net); |
757 | } | 752 | } |
758 | 753 | ||
759 | static void ipv6_frags_exit_net(struct net *net) | 754 | static void __net_exit ipv6_frags_exit_net(struct net *net) |
760 | { | 755 | { |
761 | ip6_frags_ns_sysctl_unregister(net); | 756 | ip6_frags_ns_sysctl_unregister(net); |
762 | inet_frags_exit_net(&net->ipv6.frags, &ip6_frags); | 757 | inet_frags_exit_net(&net->ipv6.frags, &ip6_frags); |
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index c2bd74c5f8d9..b08879e97f22 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
@@ -909,7 +909,7 @@ static void ip6_link_failure(struct sk_buff *skb) | |||
909 | { | 909 | { |
910 | struct rt6_info *rt; | 910 | struct rt6_info *rt; |
911 | 911 | ||
912 | icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0, skb->dev); | 912 | icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0); |
913 | 913 | ||
914 | rt = (struct rt6_info *) skb_dst(skb); | 914 | rt = (struct rt6_info *) skb_dst(skb); |
915 | if (rt) { | 915 | if (rt) { |
@@ -1873,7 +1873,7 @@ static int ip6_pkt_drop(struct sk_buff *skb, u8 code, int ipstats_mib_noroutes) | |||
1873 | switch (ipstats_mib_noroutes) { | 1873 | switch (ipstats_mib_noroutes) { |
1874 | case IPSTATS_MIB_INNOROUTES: | 1874 | case IPSTATS_MIB_INNOROUTES: |
1875 | type = ipv6_addr_type(&ipv6_hdr(skb)->daddr); | 1875 | type = ipv6_addr_type(&ipv6_hdr(skb)->daddr); |
1876 | if (type == IPV6_ADDR_ANY || type == IPV6_ADDR_RESERVED) { | 1876 | if (type == IPV6_ADDR_ANY) { |
1877 | IP6_INC_STATS(dev_net(dst->dev), ip6_dst_idev(dst), | 1877 | IP6_INC_STATS(dev_net(dst->dev), ip6_dst_idev(dst), |
1878 | IPSTATS_MIB_INADDRERRORS); | 1878 | IPSTATS_MIB_INADDRERRORS); |
1879 | break; | 1879 | break; |
@@ -1884,7 +1884,7 @@ static int ip6_pkt_drop(struct sk_buff *skb, u8 code, int ipstats_mib_noroutes) | |||
1884 | ipstats_mib_noroutes); | 1884 | ipstats_mib_noroutes); |
1885 | break; | 1885 | break; |
1886 | } | 1886 | } |
1887 | icmpv6_send(skb, ICMPV6_DEST_UNREACH, code, 0, skb->dev); | 1887 | icmpv6_send(skb, ICMPV6_DEST_UNREACH, code, 0); |
1888 | kfree_skb(skb); | 1888 | kfree_skb(skb); |
1889 | return 0; | 1889 | return 0; |
1890 | } | 1890 | } |
@@ -2612,7 +2612,7 @@ ctl_table ipv6_route_table_template[] = { | |||
2612 | { } | 2612 | { } |
2613 | }; | 2613 | }; |
2614 | 2614 | ||
2615 | struct ctl_table *ipv6_route_sysctl_init(struct net *net) | 2615 | struct ctl_table * __net_init ipv6_route_sysctl_init(struct net *net) |
2616 | { | 2616 | { |
2617 | struct ctl_table *table; | 2617 | struct ctl_table *table; |
2618 | 2618 | ||
@@ -2637,7 +2637,7 @@ struct ctl_table *ipv6_route_sysctl_init(struct net *net) | |||
2637 | } | 2637 | } |
2638 | #endif | 2638 | #endif |
2639 | 2639 | ||
2640 | static int ip6_route_net_init(struct net *net) | 2640 | static int __net_init ip6_route_net_init(struct net *net) |
2641 | { | 2641 | { |
2642 | int ret = -ENOMEM; | 2642 | int ret = -ENOMEM; |
2643 | 2643 | ||
@@ -2702,7 +2702,7 @@ out_ip6_dst_ops: | |||
2702 | goto out; | 2702 | goto out; |
2703 | } | 2703 | } |
2704 | 2704 | ||
2705 | static void ip6_route_net_exit(struct net *net) | 2705 | static void __net_exit ip6_route_net_exit(struct net *net) |
2706 | { | 2706 | { |
2707 | #ifdef CONFIG_PROC_FS | 2707 | #ifdef CONFIG_PROC_FS |
2708 | proc_net_remove(net, "ipv6_route"); | 2708 | proc_net_remove(net, "ipv6_route"); |
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 976e68244b99..b1eea811be48 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c | |||
@@ -62,7 +62,6 @@ | |||
62 | #define HASH_SIZE 16 | 62 | #define HASH_SIZE 16 |
63 | #define HASH(addr) (((__force u32)addr^((__force u32)addr>>4))&0xF) | 63 | #define HASH(addr) (((__force u32)addr^((__force u32)addr>>4))&0xF) |
64 | 64 | ||
65 | static void ipip6_fb_tunnel_init(struct net_device *dev); | ||
66 | static void ipip6_tunnel_init(struct net_device *dev); | 65 | static void ipip6_tunnel_init(struct net_device *dev); |
67 | static void ipip6_tunnel_setup(struct net_device *dev); | 66 | static void ipip6_tunnel_setup(struct net_device *dev); |
68 | 67 | ||
@@ -364,7 +363,6 @@ ipip6_tunnel_add_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a, int chg) | |||
364 | goto out; | 363 | goto out; |
365 | } | 364 | } |
366 | 365 | ||
367 | INIT_RCU_HEAD(&p->rcu_head); | ||
368 | p->next = t->prl; | 366 | p->next = t->prl; |
369 | p->addr = a->addr; | 367 | p->addr = a->addr; |
370 | p->flags = a->flags; | 368 | p->flags = a->flags; |
@@ -745,7 +743,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, | |||
745 | skb_dst(skb)->ops->update_pmtu(skb_dst(skb), mtu); | 743 | skb_dst(skb)->ops->update_pmtu(skb_dst(skb), mtu); |
746 | 744 | ||
747 | if (skb->len > mtu) { | 745 | if (skb->len > mtu) { |
748 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, dev); | 746 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); |
749 | ip_rt_put(rt); | 747 | ip_rt_put(rt); |
750 | goto tx_error; | 748 | goto tx_error; |
751 | } | 749 | } |
@@ -1120,7 +1118,7 @@ static void ipip6_tunnel_init(struct net_device *dev) | |||
1120 | ipip6_tunnel_bind_dev(dev); | 1118 | ipip6_tunnel_bind_dev(dev); |
1121 | } | 1119 | } |
1122 | 1120 | ||
1123 | static void ipip6_fb_tunnel_init(struct net_device *dev) | 1121 | static void __net_init ipip6_fb_tunnel_init(struct net_device *dev) |
1124 | { | 1122 | { |
1125 | struct ip_tunnel *tunnel = netdev_priv(dev); | 1123 | struct ip_tunnel *tunnel = netdev_priv(dev); |
1126 | struct iphdr *iph = &tunnel->parms.iph; | 1124 | struct iphdr *iph = &tunnel->parms.iph; |
@@ -1145,7 +1143,7 @@ static struct xfrm_tunnel sit_handler = { | |||
1145 | .priority = 1, | 1143 | .priority = 1, |
1146 | }; | 1144 | }; |
1147 | 1145 | ||
1148 | static void sit_destroy_tunnels(struct sit_net *sitn, struct list_head *head) | 1146 | static void __net_exit sit_destroy_tunnels(struct sit_net *sitn, struct list_head *head) |
1149 | { | 1147 | { |
1150 | int prio; | 1148 | int prio; |
1151 | 1149 | ||
@@ -1162,7 +1160,7 @@ static void sit_destroy_tunnels(struct sit_net *sitn, struct list_head *head) | |||
1162 | } | 1160 | } |
1163 | } | 1161 | } |
1164 | 1162 | ||
1165 | static int sit_init_net(struct net *net) | 1163 | static int __net_init sit_init_net(struct net *net) |
1166 | { | 1164 | { |
1167 | struct sit_net *sitn = net_generic(net, sit_net_id); | 1165 | struct sit_net *sitn = net_generic(net, sit_net_id); |
1168 | int err; | 1166 | int err; |
@@ -1195,7 +1193,7 @@ err_alloc_dev: | |||
1195 | return err; | 1193 | return err; |
1196 | } | 1194 | } |
1197 | 1195 | ||
1198 | static void sit_exit_net(struct net *net) | 1196 | static void __net_exit sit_exit_net(struct net *net) |
1199 | { | 1197 | { |
1200 | struct sit_net *sitn = net_generic(net, sit_net_id); | 1198 | struct sit_net *sitn = net_generic(net, sit_net_id); |
1201 | LIST_HEAD(list); | 1199 | LIST_HEAD(list); |
@@ -1228,15 +1226,14 @@ static int __init sit_init(void) | |||
1228 | 1226 | ||
1229 | printk(KERN_INFO "IPv6 over IPv4 tunneling driver\n"); | 1227 | printk(KERN_INFO "IPv6 over IPv4 tunneling driver\n"); |
1230 | 1228 | ||
1231 | if (xfrm4_tunnel_register(&sit_handler, AF_INET6) < 0) { | ||
1232 | printk(KERN_INFO "sit init: Can't add protocol\n"); | ||
1233 | return -EAGAIN; | ||
1234 | } | ||
1235 | |||
1236 | err = register_pernet_device(&sit_net_ops); | 1229 | err = register_pernet_device(&sit_net_ops); |
1237 | if (err < 0) | 1230 | if (err < 0) |
1238 | xfrm4_tunnel_deregister(&sit_handler, AF_INET6); | 1231 | return err; |
1239 | 1232 | err = xfrm4_tunnel_register(&sit_handler, AF_INET6); | |
1233 | if (err < 0) { | ||
1234 | unregister_pernet_device(&sit_net_ops); | ||
1235 | printk(KERN_INFO "sit init: Can't add protocol\n"); | ||
1236 | } | ||
1240 | return err; | 1237 | return err; |
1241 | } | 1238 | } |
1242 | 1239 | ||
diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c index 7208a06576c6..34d1f0690d7e 100644 --- a/net/ipv6/syncookies.c +++ b/net/ipv6/syncookies.c | |||
@@ -269,7 +269,8 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) | |||
269 | req->window_clamp = tp->window_clamp ? :dst_metric(dst, RTAX_WINDOW); | 269 | req->window_clamp = tp->window_clamp ? :dst_metric(dst, RTAX_WINDOW); |
270 | tcp_select_initial_window(tcp_full_space(sk), req->mss, | 270 | tcp_select_initial_window(tcp_full_space(sk), req->mss, |
271 | &req->rcv_wnd, &req->window_clamp, | 271 | &req->rcv_wnd, &req->window_clamp, |
272 | ireq->wscale_ok, &rcv_wscale); | 272 | ireq->wscale_ok, &rcv_wscale, |
273 | dst_metric(dst, RTAX_INITRWND)); | ||
273 | 274 | ||
274 | ireq->rcv_wscale = rcv_wscale; | 275 | ireq->rcv_wscale = rcv_wscale; |
275 | 276 | ||
diff --git a/net/ipv6/sysctl_net_ipv6.c b/net/ipv6/sysctl_net_ipv6.c index c690736885b4..f841d93bf987 100644 --- a/net/ipv6/sysctl_net_ipv6.c +++ b/net/ipv6/sysctl_net_ipv6.c | |||
@@ -55,7 +55,7 @@ struct ctl_path net_ipv6_ctl_path[] = { | |||
55 | }; | 55 | }; |
56 | EXPORT_SYMBOL_GPL(net_ipv6_ctl_path); | 56 | EXPORT_SYMBOL_GPL(net_ipv6_ctl_path); |
57 | 57 | ||
58 | static int ipv6_sysctl_net_init(struct net *net) | 58 | static int __net_init ipv6_sysctl_net_init(struct net *net) |
59 | { | 59 | { |
60 | struct ctl_table *ipv6_table; | 60 | struct ctl_table *ipv6_table; |
61 | struct ctl_table *ipv6_route_table; | 61 | struct ctl_table *ipv6_route_table; |
@@ -98,7 +98,7 @@ out_ipv6_table: | |||
98 | goto out; | 98 | goto out; |
99 | } | 99 | } |
100 | 100 | ||
101 | static void ipv6_sysctl_net_exit(struct net *net) | 101 | static void __net_exit ipv6_sysctl_net_exit(struct net *net) |
102 | { | 102 | { |
103 | struct ctl_table *ipv6_table; | 103 | struct ctl_table *ipv6_table; |
104 | struct ctl_table *ipv6_route_table; | 104 | struct ctl_table *ipv6_route_table; |
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index febfd595a40d..6963a6b6763e 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c | |||
@@ -520,6 +520,13 @@ done: | |||
520 | return err; | 520 | return err; |
521 | } | 521 | } |
522 | 522 | ||
523 | static int tcp_v6_rtx_synack(struct sock *sk, struct request_sock *req, | ||
524 | struct request_values *rvp) | ||
525 | { | ||
526 | TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_RETRANSSEGS); | ||
527 | return tcp_v6_send_synack(sk, req, rvp); | ||
528 | } | ||
529 | |||
523 | static inline void syn_flood_warning(struct sk_buff *skb) | 530 | static inline void syn_flood_warning(struct sk_buff *skb) |
524 | { | 531 | { |
525 | #ifdef CONFIG_SYN_COOKIES | 532 | #ifdef CONFIG_SYN_COOKIES |
@@ -876,7 +883,7 @@ static int tcp_v6_inbound_md5_hash (struct sock *sk, struct sk_buff *skb) | |||
876 | 883 | ||
877 | if (genhash || memcmp(hash_location, newhash, 16) != 0) { | 884 | if (genhash || memcmp(hash_location, newhash, 16) != 0) { |
878 | if (net_ratelimit()) { | 885 | if (net_ratelimit()) { |
879 | printk(KERN_INFO "MD5 Hash %s for (%pI6, %u)->(%pI6, %u)\n", | 886 | printk(KERN_INFO "MD5 Hash %s for [%pI6c]:%u->[%pI6c]:%u\n", |
880 | genhash ? "failed" : "mismatch", | 887 | genhash ? "failed" : "mismatch", |
881 | &ip6h->saddr, ntohs(th->source), | 888 | &ip6h->saddr, ntohs(th->source), |
882 | &ip6h->daddr, ntohs(th->dest)); | 889 | &ip6h->daddr, ntohs(th->dest)); |
@@ -890,10 +897,11 @@ static int tcp_v6_inbound_md5_hash (struct sock *sk, struct sk_buff *skb) | |||
890 | struct request_sock_ops tcp6_request_sock_ops __read_mostly = { | 897 | struct request_sock_ops tcp6_request_sock_ops __read_mostly = { |
891 | .family = AF_INET6, | 898 | .family = AF_INET6, |
892 | .obj_size = sizeof(struct tcp6_request_sock), | 899 | .obj_size = sizeof(struct tcp6_request_sock), |
893 | .rtx_syn_ack = tcp_v6_send_synack, | 900 | .rtx_syn_ack = tcp_v6_rtx_synack, |
894 | .send_ack = tcp_v6_reqsk_send_ack, | 901 | .send_ack = tcp_v6_reqsk_send_ack, |
895 | .destructor = tcp_v6_reqsk_destructor, | 902 | .destructor = tcp_v6_reqsk_destructor, |
896 | .send_reset = tcp_v6_send_reset | 903 | .send_reset = tcp_v6_send_reset, |
904 | .syn_ack_timeout = tcp_syn_ack_timeout, | ||
897 | }; | 905 | }; |
898 | 906 | ||
899 | #ifdef CONFIG_TCP_MD5SIG | 907 | #ifdef CONFIG_TCP_MD5SIG |
@@ -2105,7 +2113,7 @@ static struct tcp_seq_afinfo tcp6_seq_afinfo = { | |||
2105 | }, | 2113 | }, |
2106 | }; | 2114 | }; |
2107 | 2115 | ||
2108 | int tcp6_proc_init(struct net *net) | 2116 | int __net_init tcp6_proc_init(struct net *net) |
2109 | { | 2117 | { |
2110 | return tcp_proc_register(net, &tcp6_seq_afinfo); | 2118 | return tcp_proc_register(net, &tcp6_seq_afinfo); |
2111 | } | 2119 | } |
@@ -2174,18 +2182,18 @@ static struct inet_protosw tcpv6_protosw = { | |||
2174 | INET_PROTOSW_ICSK, | 2182 | INET_PROTOSW_ICSK, |
2175 | }; | 2183 | }; |
2176 | 2184 | ||
2177 | static int tcpv6_net_init(struct net *net) | 2185 | static int __net_init tcpv6_net_init(struct net *net) |
2178 | { | 2186 | { |
2179 | return inet_ctl_sock_create(&net->ipv6.tcp_sk, PF_INET6, | 2187 | return inet_ctl_sock_create(&net->ipv6.tcp_sk, PF_INET6, |
2180 | SOCK_RAW, IPPROTO_TCP, net); | 2188 | SOCK_RAW, IPPROTO_TCP, net); |
2181 | } | 2189 | } |
2182 | 2190 | ||
2183 | static void tcpv6_net_exit(struct net *net) | 2191 | static void __net_exit tcpv6_net_exit(struct net *net) |
2184 | { | 2192 | { |
2185 | inet_ctl_sock_destroy(net->ipv6.tcp_sk); | 2193 | inet_ctl_sock_destroy(net->ipv6.tcp_sk); |
2186 | } | 2194 | } |
2187 | 2195 | ||
2188 | static void tcpv6_net_exit_batch(struct list_head *net_exit_list) | 2196 | static void __net_exit tcpv6_net_exit_batch(struct list_head *net_exit_list) |
2189 | { | 2197 | { |
2190 | inet_twsk_purge(&tcp_hashinfo, &tcp_death_row, AF_INET6); | 2198 | inet_twsk_purge(&tcp_hashinfo, &tcp_death_row, AF_INET6); |
2191 | } | 2199 | } |
diff --git a/net/ipv6/tunnel6.c b/net/ipv6/tunnel6.c index 51e2832d13a6..e17bc1dfc1a4 100644 --- a/net/ipv6/tunnel6.c +++ b/net/ipv6/tunnel6.c | |||
@@ -98,7 +98,7 @@ static int tunnel6_rcv(struct sk_buff *skb) | |||
98 | if (!handler->handler(skb)) | 98 | if (!handler->handler(skb)) |
99 | return 0; | 99 | return 0; |
100 | 100 | ||
101 | icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0, skb->dev); | 101 | icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0); |
102 | 102 | ||
103 | drop: | 103 | drop: |
104 | kfree_skb(skb); | 104 | kfree_skb(skb); |
@@ -116,7 +116,7 @@ static int tunnel46_rcv(struct sk_buff *skb) | |||
116 | if (!handler->handler(skb)) | 116 | if (!handler->handler(skb)) |
117 | return 0; | 117 | return 0; |
118 | 118 | ||
119 | icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0, skb->dev); | 119 | icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0); |
120 | 120 | ||
121 | drop: | 121 | drop: |
122 | kfree_skb(skb); | 122 | kfree_skb(skb); |
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 69ebdbe78c47..52b8347ae3b2 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c | |||
@@ -322,7 +322,7 @@ int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk, | |||
322 | struct ipv6_pinfo *np = inet6_sk(sk); | 322 | struct ipv6_pinfo *np = inet6_sk(sk); |
323 | struct inet_sock *inet = inet_sk(sk); | 323 | struct inet_sock *inet = inet_sk(sk); |
324 | struct sk_buff *skb; | 324 | struct sk_buff *skb; |
325 | unsigned int ulen, copied; | 325 | unsigned int ulen; |
326 | int peeked; | 326 | int peeked; |
327 | int err; | 327 | int err; |
328 | int is_udplite = IS_UDPLITE(sk); | 328 | int is_udplite = IS_UDPLITE(sk); |
@@ -341,10 +341,9 @@ try_again: | |||
341 | goto out; | 341 | goto out; |
342 | 342 | ||
343 | ulen = skb->len - sizeof(struct udphdr); | 343 | ulen = skb->len - sizeof(struct udphdr); |
344 | copied = len; | 344 | if (len > ulen) |
345 | if (copied > ulen) | 345 | len = ulen; |
346 | copied = ulen; | 346 | else if (len < ulen) |
347 | else if (copied < ulen) | ||
348 | msg->msg_flags |= MSG_TRUNC; | 347 | msg->msg_flags |= MSG_TRUNC; |
349 | 348 | ||
350 | is_udp4 = (skb->protocol == htons(ETH_P_IP)); | 349 | is_udp4 = (skb->protocol == htons(ETH_P_IP)); |
@@ -355,14 +354,14 @@ try_again: | |||
355 | * coverage checksum (UDP-Lite), do it before the copy. | 354 | * coverage checksum (UDP-Lite), do it before the copy. |
356 | */ | 355 | */ |
357 | 356 | ||
358 | if (copied < ulen || UDP_SKB_CB(skb)->partial_cov) { | 357 | if (len < ulen || UDP_SKB_CB(skb)->partial_cov) { |
359 | if (udp_lib_checksum_complete(skb)) | 358 | if (udp_lib_checksum_complete(skb)) |
360 | goto csum_copy_err; | 359 | goto csum_copy_err; |
361 | } | 360 | } |
362 | 361 | ||
363 | if (skb_csum_unnecessary(skb)) | 362 | if (skb_csum_unnecessary(skb)) |
364 | err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), | 363 | err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), |
365 | msg->msg_iov, copied ); | 364 | msg->msg_iov,len); |
366 | else { | 365 | else { |
367 | err = skb_copy_and_csum_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov); | 366 | err = skb_copy_and_csum_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov); |
368 | if (err == -EINVAL) | 367 | if (err == -EINVAL) |
@@ -411,7 +410,7 @@ try_again: | |||
411 | datagram_recv_ctl(sk, msg, skb); | 410 | datagram_recv_ctl(sk, msg, skb); |
412 | } | 411 | } |
413 | 412 | ||
414 | err = copied; | 413 | err = len; |
415 | if (flags & MSG_TRUNC) | 414 | if (flags & MSG_TRUNC) |
416 | err = ulen; | 415 | err = ulen; |
417 | 416 | ||
@@ -681,12 +680,11 @@ static inline int udp6_csum_init(struct sk_buff *skb, struct udphdr *uh, | |||
681 | int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable, | 680 | int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable, |
682 | int proto) | 681 | int proto) |
683 | { | 682 | { |
683 | struct net *net = dev_net(skb->dev); | ||
684 | struct sock *sk; | 684 | struct sock *sk; |
685 | struct udphdr *uh; | 685 | struct udphdr *uh; |
686 | struct net_device *dev = skb->dev; | ||
687 | struct in6_addr *saddr, *daddr; | 686 | struct in6_addr *saddr, *daddr; |
688 | u32 ulen = 0; | 687 | u32 ulen = 0; |
689 | struct net *net = dev_net(skb->dev); | ||
690 | 688 | ||
691 | if (!pskb_may_pull(skb, sizeof(struct udphdr))) | 689 | if (!pskb_may_pull(skb, sizeof(struct udphdr))) |
692 | goto short_packet; | 690 | goto short_packet; |
@@ -745,7 +743,7 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable, | |||
745 | UDP6_INC_STATS_BH(net, UDP_MIB_NOPORTS, | 743 | UDP6_INC_STATS_BH(net, UDP_MIB_NOPORTS, |
746 | proto == IPPROTO_UDPLITE); | 744 | proto == IPPROTO_UDPLITE); |
747 | 745 | ||
748 | icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0, dev); | 746 | icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0); |
749 | 747 | ||
750 | kfree_skb(skb); | 748 | kfree_skb(skb); |
751 | return 0; | 749 | return 0; |
@@ -1396,7 +1394,7 @@ static struct udp_seq_afinfo udp6_seq_afinfo = { | |||
1396 | }, | 1394 | }, |
1397 | }; | 1395 | }; |
1398 | 1396 | ||
1399 | int udp6_proc_init(struct net *net) | 1397 | int __net_init udp6_proc_init(struct net *net) |
1400 | { | 1398 | { |
1401 | return udp_proc_register(net, &udp6_seq_afinfo); | 1399 | return udp_proc_register(net, &udp6_seq_afinfo); |
1402 | } | 1400 | } |
diff --git a/net/ipv6/udplite.c b/net/ipv6/udplite.c index 6ea6938919e6..5f48fadc27f7 100644 --- a/net/ipv6/udplite.c +++ b/net/ipv6/udplite.c | |||
@@ -104,12 +104,12 @@ static struct udp_seq_afinfo udplite6_seq_afinfo = { | |||
104 | }, | 104 | }, |
105 | }; | 105 | }; |
106 | 106 | ||
107 | static int udplite6_proc_init_net(struct net *net) | 107 | static int __net_init udplite6_proc_init_net(struct net *net) |
108 | { | 108 | { |
109 | return udp_proc_register(net, &udplite6_seq_afinfo); | 109 | return udp_proc_register(net, &udplite6_seq_afinfo); |
110 | } | 110 | } |
111 | 111 | ||
112 | static void udplite6_proc_exit_net(struct net *net) | 112 | static void __net_exit udplite6_proc_exit_net(struct net *net) |
113 | { | 113 | { |
114 | udp_proc_unregister(net, &udplite6_seq_afinfo); | 114 | udp_proc_unregister(net, &udplite6_seq_afinfo); |
115 | } | 115 | } |
diff --git a/net/ipv6/xfrm6_input.c b/net/ipv6/xfrm6_input.c index 9084582d236b..2bc98ede1235 100644 --- a/net/ipv6/xfrm6_input.c +++ b/net/ipv6/xfrm6_input.c | |||
@@ -101,7 +101,7 @@ int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr, | |||
101 | break; | 101 | break; |
102 | } | 102 | } |
103 | 103 | ||
104 | x = xfrm_state_lookup_byaddr(net, dst, src, proto, AF_INET6); | 104 | x = xfrm_state_lookup_byaddr(net, skb->mark, dst, src, proto, AF_INET6); |
105 | if (!x) | 105 | if (!x) |
106 | continue; | 106 | continue; |
107 | 107 | ||
diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c index c4f4eef032a3..0c92112dcba3 100644 --- a/net/ipv6/xfrm6_output.c +++ b/net/ipv6/xfrm6_output.c | |||
@@ -38,7 +38,7 @@ static int xfrm6_tunnel_check_size(struct sk_buff *skb) | |||
38 | 38 | ||
39 | if (!skb->local_df && skb->len > mtu) { | 39 | if (!skb->local_df && skb->len > mtu) { |
40 | skb->dev = dst->dev; | 40 | skb->dev = dst->dev; |
41 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev); | 41 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); |
42 | ret = -EMSGSIZE; | 42 | ret = -EMSGSIZE; |
43 | } | 43 | } |
44 | 44 | ||
diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c index 438831d33593..fa85a7d22dc4 100644 --- a/net/ipv6/xfrm6_tunnel.c +++ b/net/ipv6/xfrm6_tunnel.c | |||
@@ -30,6 +30,25 @@ | |||
30 | #include <linux/ipv6.h> | 30 | #include <linux/ipv6.h> |
31 | #include <linux/icmpv6.h> | 31 | #include <linux/icmpv6.h> |
32 | #include <linux/mutex.h> | 32 | #include <linux/mutex.h> |
33 | #include <net/netns/generic.h> | ||
34 | |||
35 | #define XFRM6_TUNNEL_SPI_BYADDR_HSIZE 256 | ||
36 | #define XFRM6_TUNNEL_SPI_BYSPI_HSIZE 256 | ||
37 | |||
38 | #define XFRM6_TUNNEL_SPI_MIN 1 | ||
39 | #define XFRM6_TUNNEL_SPI_MAX 0xffffffff | ||
40 | |||
41 | struct xfrm6_tunnel_net { | ||
42 | struct hlist_head spi_byaddr[XFRM6_TUNNEL_SPI_BYADDR_HSIZE]; | ||
43 | struct hlist_head spi_byspi[XFRM6_TUNNEL_SPI_BYSPI_HSIZE]; | ||
44 | u32 spi; | ||
45 | }; | ||
46 | |||
47 | static int xfrm6_tunnel_net_id __read_mostly; | ||
48 | static inline struct xfrm6_tunnel_net *xfrm6_tunnel_pernet(struct net *net) | ||
49 | { | ||
50 | return net_generic(net, xfrm6_tunnel_net_id); | ||
51 | } | ||
33 | 52 | ||
34 | /* | 53 | /* |
35 | * xfrm_tunnel_spi things are for allocating unique id ("spi") | 54 | * xfrm_tunnel_spi things are for allocating unique id ("spi") |
@@ -46,19 +65,8 @@ struct xfrm6_tunnel_spi { | |||
46 | 65 | ||
47 | static DEFINE_SPINLOCK(xfrm6_tunnel_spi_lock); | 66 | static DEFINE_SPINLOCK(xfrm6_tunnel_spi_lock); |
48 | 67 | ||
49 | static u32 xfrm6_tunnel_spi; | ||
50 | |||
51 | #define XFRM6_TUNNEL_SPI_MIN 1 | ||
52 | #define XFRM6_TUNNEL_SPI_MAX 0xffffffff | ||
53 | |||
54 | static struct kmem_cache *xfrm6_tunnel_spi_kmem __read_mostly; | 68 | static struct kmem_cache *xfrm6_tunnel_spi_kmem __read_mostly; |
55 | 69 | ||
56 | #define XFRM6_TUNNEL_SPI_BYADDR_HSIZE 256 | ||
57 | #define XFRM6_TUNNEL_SPI_BYSPI_HSIZE 256 | ||
58 | |||
59 | static struct hlist_head xfrm6_tunnel_spi_byaddr[XFRM6_TUNNEL_SPI_BYADDR_HSIZE]; | ||
60 | static struct hlist_head xfrm6_tunnel_spi_byspi[XFRM6_TUNNEL_SPI_BYSPI_HSIZE]; | ||
61 | |||
62 | static inline unsigned xfrm6_tunnel_spi_hash_byaddr(xfrm_address_t *addr) | 70 | static inline unsigned xfrm6_tunnel_spi_hash_byaddr(xfrm_address_t *addr) |
63 | { | 71 | { |
64 | unsigned h; | 72 | unsigned h; |
@@ -76,50 +84,14 @@ static inline unsigned xfrm6_tunnel_spi_hash_byspi(u32 spi) | |||
76 | return spi % XFRM6_TUNNEL_SPI_BYSPI_HSIZE; | 84 | return spi % XFRM6_TUNNEL_SPI_BYSPI_HSIZE; |
77 | } | 85 | } |
78 | 86 | ||
79 | 87 | static struct xfrm6_tunnel_spi *__xfrm6_tunnel_spi_lookup(struct net *net, xfrm_address_t *saddr) | |
80 | static int xfrm6_tunnel_spi_init(void) | ||
81 | { | ||
82 | int i; | ||
83 | |||
84 | xfrm6_tunnel_spi = 0; | ||
85 | xfrm6_tunnel_spi_kmem = kmem_cache_create("xfrm6_tunnel_spi", | ||
86 | sizeof(struct xfrm6_tunnel_spi), | ||
87 | 0, SLAB_HWCACHE_ALIGN, | ||
88 | NULL); | ||
89 | if (!xfrm6_tunnel_spi_kmem) | ||
90 | return -ENOMEM; | ||
91 | |||
92 | for (i = 0; i < XFRM6_TUNNEL_SPI_BYADDR_HSIZE; i++) | ||
93 | INIT_HLIST_HEAD(&xfrm6_tunnel_spi_byaddr[i]); | ||
94 | for (i = 0; i < XFRM6_TUNNEL_SPI_BYSPI_HSIZE; i++) | ||
95 | INIT_HLIST_HEAD(&xfrm6_tunnel_spi_byspi[i]); | ||
96 | return 0; | ||
97 | } | ||
98 | |||
99 | static void xfrm6_tunnel_spi_fini(void) | ||
100 | { | ||
101 | int i; | ||
102 | |||
103 | for (i = 0; i < XFRM6_TUNNEL_SPI_BYADDR_HSIZE; i++) { | ||
104 | if (!hlist_empty(&xfrm6_tunnel_spi_byaddr[i])) | ||
105 | return; | ||
106 | } | ||
107 | for (i = 0; i < XFRM6_TUNNEL_SPI_BYSPI_HSIZE; i++) { | ||
108 | if (!hlist_empty(&xfrm6_tunnel_spi_byspi[i])) | ||
109 | return; | ||
110 | } | ||
111 | rcu_barrier(); | ||
112 | kmem_cache_destroy(xfrm6_tunnel_spi_kmem); | ||
113 | xfrm6_tunnel_spi_kmem = NULL; | ||
114 | } | ||
115 | |||
116 | static struct xfrm6_tunnel_spi *__xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr) | ||
117 | { | 88 | { |
89 | struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net); | ||
118 | struct xfrm6_tunnel_spi *x6spi; | 90 | struct xfrm6_tunnel_spi *x6spi; |
119 | struct hlist_node *pos; | 91 | struct hlist_node *pos; |
120 | 92 | ||
121 | hlist_for_each_entry_rcu(x6spi, pos, | 93 | hlist_for_each_entry_rcu(x6spi, pos, |
122 | &xfrm6_tunnel_spi_byaddr[xfrm6_tunnel_spi_hash_byaddr(saddr)], | 94 | &xfrm6_tn->spi_byaddr[xfrm6_tunnel_spi_hash_byaddr(saddr)], |
123 | list_byaddr) { | 95 | list_byaddr) { |
124 | if (memcmp(&x6spi->addr, saddr, sizeof(x6spi->addr)) == 0) | 96 | if (memcmp(&x6spi->addr, saddr, sizeof(x6spi->addr)) == 0) |
125 | return x6spi; | 97 | return x6spi; |
@@ -128,13 +100,13 @@ static struct xfrm6_tunnel_spi *__xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr) | |||
128 | return NULL; | 100 | return NULL; |
129 | } | 101 | } |
130 | 102 | ||
131 | __be32 xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr) | 103 | __be32 xfrm6_tunnel_spi_lookup(struct net *net, xfrm_address_t *saddr) |
132 | { | 104 | { |
133 | struct xfrm6_tunnel_spi *x6spi; | 105 | struct xfrm6_tunnel_spi *x6spi; |
134 | u32 spi; | 106 | u32 spi; |
135 | 107 | ||
136 | rcu_read_lock_bh(); | 108 | rcu_read_lock_bh(); |
137 | x6spi = __xfrm6_tunnel_spi_lookup(saddr); | 109 | x6spi = __xfrm6_tunnel_spi_lookup(net, saddr); |
138 | spi = x6spi ? x6spi->spi : 0; | 110 | spi = x6spi ? x6spi->spi : 0; |
139 | rcu_read_unlock_bh(); | 111 | rcu_read_unlock_bh(); |
140 | return htonl(spi); | 112 | return htonl(spi); |
@@ -142,14 +114,15 @@ __be32 xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr) | |||
142 | 114 | ||
143 | EXPORT_SYMBOL(xfrm6_tunnel_spi_lookup); | 115 | EXPORT_SYMBOL(xfrm6_tunnel_spi_lookup); |
144 | 116 | ||
145 | static int __xfrm6_tunnel_spi_check(u32 spi) | 117 | static int __xfrm6_tunnel_spi_check(struct net *net, u32 spi) |
146 | { | 118 | { |
119 | struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net); | ||
147 | struct xfrm6_tunnel_spi *x6spi; | 120 | struct xfrm6_tunnel_spi *x6spi; |
148 | int index = xfrm6_tunnel_spi_hash_byspi(spi); | 121 | int index = xfrm6_tunnel_spi_hash_byspi(spi); |
149 | struct hlist_node *pos; | 122 | struct hlist_node *pos; |
150 | 123 | ||
151 | hlist_for_each_entry(x6spi, pos, | 124 | hlist_for_each_entry(x6spi, pos, |
152 | &xfrm6_tunnel_spi_byspi[index], | 125 | &xfrm6_tn->spi_byspi[index], |
153 | list_byspi) { | 126 | list_byspi) { |
154 | if (x6spi->spi == spi) | 127 | if (x6spi->spi == spi) |
155 | return -1; | 128 | return -1; |
@@ -157,61 +130,61 @@ static int __xfrm6_tunnel_spi_check(u32 spi) | |||
157 | return index; | 130 | return index; |
158 | } | 131 | } |
159 | 132 | ||
160 | static u32 __xfrm6_tunnel_alloc_spi(xfrm_address_t *saddr) | 133 | static u32 __xfrm6_tunnel_alloc_spi(struct net *net, xfrm_address_t *saddr) |
161 | { | 134 | { |
135 | struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net); | ||
162 | u32 spi; | 136 | u32 spi; |
163 | struct xfrm6_tunnel_spi *x6spi; | 137 | struct xfrm6_tunnel_spi *x6spi; |
164 | int index; | 138 | int index; |
165 | 139 | ||
166 | if (xfrm6_tunnel_spi < XFRM6_TUNNEL_SPI_MIN || | 140 | if (xfrm6_tn->spi < XFRM6_TUNNEL_SPI_MIN || |
167 | xfrm6_tunnel_spi >= XFRM6_TUNNEL_SPI_MAX) | 141 | xfrm6_tn->spi >= XFRM6_TUNNEL_SPI_MAX) |
168 | xfrm6_tunnel_spi = XFRM6_TUNNEL_SPI_MIN; | 142 | xfrm6_tn->spi = XFRM6_TUNNEL_SPI_MIN; |
169 | else | 143 | else |
170 | xfrm6_tunnel_spi++; | 144 | xfrm6_tn->spi++; |
171 | 145 | ||
172 | for (spi = xfrm6_tunnel_spi; spi <= XFRM6_TUNNEL_SPI_MAX; spi++) { | 146 | for (spi = xfrm6_tn->spi; spi <= XFRM6_TUNNEL_SPI_MAX; spi++) { |
173 | index = __xfrm6_tunnel_spi_check(spi); | 147 | index = __xfrm6_tunnel_spi_check(net, spi); |
174 | if (index >= 0) | 148 | if (index >= 0) |
175 | goto alloc_spi; | 149 | goto alloc_spi; |
176 | } | 150 | } |
177 | for (spi = XFRM6_TUNNEL_SPI_MIN; spi < xfrm6_tunnel_spi; spi++) { | 151 | for (spi = XFRM6_TUNNEL_SPI_MIN; spi < xfrm6_tn->spi; spi++) { |
178 | index = __xfrm6_tunnel_spi_check(spi); | 152 | index = __xfrm6_tunnel_spi_check(net, spi); |
179 | if (index >= 0) | 153 | if (index >= 0) |
180 | goto alloc_spi; | 154 | goto alloc_spi; |
181 | } | 155 | } |
182 | spi = 0; | 156 | spi = 0; |
183 | goto out; | 157 | goto out; |
184 | alloc_spi: | 158 | alloc_spi: |
185 | xfrm6_tunnel_spi = spi; | 159 | xfrm6_tn->spi = spi; |
186 | x6spi = kmem_cache_alloc(xfrm6_tunnel_spi_kmem, GFP_ATOMIC); | 160 | x6spi = kmem_cache_alloc(xfrm6_tunnel_spi_kmem, GFP_ATOMIC); |
187 | if (!x6spi) | 161 | if (!x6spi) |
188 | goto out; | 162 | goto out; |
189 | 163 | ||
190 | INIT_RCU_HEAD(&x6spi->rcu_head); | ||
191 | memcpy(&x6spi->addr, saddr, sizeof(x6spi->addr)); | 164 | memcpy(&x6spi->addr, saddr, sizeof(x6spi->addr)); |
192 | x6spi->spi = spi; | 165 | x6spi->spi = spi; |
193 | atomic_set(&x6spi->refcnt, 1); | 166 | atomic_set(&x6spi->refcnt, 1); |
194 | 167 | ||
195 | hlist_add_head_rcu(&x6spi->list_byspi, &xfrm6_tunnel_spi_byspi[index]); | 168 | hlist_add_head_rcu(&x6spi->list_byspi, &xfrm6_tn->spi_byspi[index]); |
196 | 169 | ||
197 | index = xfrm6_tunnel_spi_hash_byaddr(saddr); | 170 | index = xfrm6_tunnel_spi_hash_byaddr(saddr); |
198 | hlist_add_head_rcu(&x6spi->list_byaddr, &xfrm6_tunnel_spi_byaddr[index]); | 171 | hlist_add_head_rcu(&x6spi->list_byaddr, &xfrm6_tn->spi_byaddr[index]); |
199 | out: | 172 | out: |
200 | return spi; | 173 | return spi; |
201 | } | 174 | } |
202 | 175 | ||
203 | __be32 xfrm6_tunnel_alloc_spi(xfrm_address_t *saddr) | 176 | __be32 xfrm6_tunnel_alloc_spi(struct net *net, xfrm_address_t *saddr) |
204 | { | 177 | { |
205 | struct xfrm6_tunnel_spi *x6spi; | 178 | struct xfrm6_tunnel_spi *x6spi; |
206 | u32 spi; | 179 | u32 spi; |
207 | 180 | ||
208 | spin_lock_bh(&xfrm6_tunnel_spi_lock); | 181 | spin_lock_bh(&xfrm6_tunnel_spi_lock); |
209 | x6spi = __xfrm6_tunnel_spi_lookup(saddr); | 182 | x6spi = __xfrm6_tunnel_spi_lookup(net, saddr); |
210 | if (x6spi) { | 183 | if (x6spi) { |
211 | atomic_inc(&x6spi->refcnt); | 184 | atomic_inc(&x6spi->refcnt); |
212 | spi = x6spi->spi; | 185 | spi = x6spi->spi; |
213 | } else | 186 | } else |
214 | spi = __xfrm6_tunnel_alloc_spi(saddr); | 187 | spi = __xfrm6_tunnel_alloc_spi(net, saddr); |
215 | spin_unlock_bh(&xfrm6_tunnel_spi_lock); | 188 | spin_unlock_bh(&xfrm6_tunnel_spi_lock); |
216 | 189 | ||
217 | return htonl(spi); | 190 | return htonl(spi); |
@@ -225,15 +198,16 @@ static void x6spi_destroy_rcu(struct rcu_head *head) | |||
225 | container_of(head, struct xfrm6_tunnel_spi, rcu_head)); | 198 | container_of(head, struct xfrm6_tunnel_spi, rcu_head)); |
226 | } | 199 | } |
227 | 200 | ||
228 | void xfrm6_tunnel_free_spi(xfrm_address_t *saddr) | 201 | void xfrm6_tunnel_free_spi(struct net *net, xfrm_address_t *saddr) |
229 | { | 202 | { |
203 | struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net); | ||
230 | struct xfrm6_tunnel_spi *x6spi; | 204 | struct xfrm6_tunnel_spi *x6spi; |
231 | struct hlist_node *pos, *n; | 205 | struct hlist_node *pos, *n; |
232 | 206 | ||
233 | spin_lock_bh(&xfrm6_tunnel_spi_lock); | 207 | spin_lock_bh(&xfrm6_tunnel_spi_lock); |
234 | 208 | ||
235 | hlist_for_each_entry_safe(x6spi, pos, n, | 209 | hlist_for_each_entry_safe(x6spi, pos, n, |
236 | &xfrm6_tunnel_spi_byaddr[xfrm6_tunnel_spi_hash_byaddr(saddr)], | 210 | &xfrm6_tn->spi_byaddr[xfrm6_tunnel_spi_hash_byaddr(saddr)], |
237 | list_byaddr) | 211 | list_byaddr) |
238 | { | 212 | { |
239 | if (memcmp(&x6spi->addr, saddr, sizeof(x6spi->addr)) == 0) { | 213 | if (memcmp(&x6spi->addr, saddr, sizeof(x6spi->addr)) == 0) { |
@@ -263,10 +237,11 @@ static int xfrm6_tunnel_input(struct xfrm_state *x, struct sk_buff *skb) | |||
263 | 237 | ||
264 | static int xfrm6_tunnel_rcv(struct sk_buff *skb) | 238 | static int xfrm6_tunnel_rcv(struct sk_buff *skb) |
265 | { | 239 | { |
240 | struct net *net = dev_net(skb->dev); | ||
266 | struct ipv6hdr *iph = ipv6_hdr(skb); | 241 | struct ipv6hdr *iph = ipv6_hdr(skb); |
267 | __be32 spi; | 242 | __be32 spi; |
268 | 243 | ||
269 | spi = xfrm6_tunnel_spi_lookup((xfrm_address_t *)&iph->saddr); | 244 | spi = xfrm6_tunnel_spi_lookup(net, (xfrm_address_t *)&iph->saddr); |
270 | return xfrm6_rcv_spi(skb, IPPROTO_IPV6, spi) > 0 ? : 0; | 245 | return xfrm6_rcv_spi(skb, IPPROTO_IPV6, spi) > 0 ? : 0; |
271 | } | 246 | } |
272 | 247 | ||
@@ -326,7 +301,9 @@ static int xfrm6_tunnel_init_state(struct xfrm_state *x) | |||
326 | 301 | ||
327 | static void xfrm6_tunnel_destroy(struct xfrm_state *x) | 302 | static void xfrm6_tunnel_destroy(struct xfrm_state *x) |
328 | { | 303 | { |
329 | xfrm6_tunnel_free_spi((xfrm_address_t *)&x->props.saddr); | 304 | struct net *net = xs_net(x); |
305 | |||
306 | xfrm6_tunnel_free_spi(net, (xfrm_address_t *)&x->props.saddr); | ||
330 | } | 307 | } |
331 | 308 | ||
332 | static const struct xfrm_type xfrm6_tunnel_type = { | 309 | static const struct xfrm_type xfrm6_tunnel_type = { |
@@ -351,34 +328,73 @@ static struct xfrm6_tunnel xfrm46_tunnel_handler = { | |||
351 | .priority = 2, | 328 | .priority = 2, |
352 | }; | 329 | }; |
353 | 330 | ||
331 | static int __net_init xfrm6_tunnel_net_init(struct net *net) | ||
332 | { | ||
333 | struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net); | ||
334 | unsigned int i; | ||
335 | |||
336 | for (i = 0; i < XFRM6_TUNNEL_SPI_BYADDR_HSIZE; i++) | ||
337 | INIT_HLIST_HEAD(&xfrm6_tn->spi_byaddr[i]); | ||
338 | for (i = 0; i < XFRM6_TUNNEL_SPI_BYSPI_HSIZE; i++) | ||
339 | INIT_HLIST_HEAD(&xfrm6_tn->spi_byspi[i]); | ||
340 | xfrm6_tn->spi = 0; | ||
341 | |||
342 | return 0; | ||
343 | } | ||
344 | |||
345 | static void __net_exit xfrm6_tunnel_net_exit(struct net *net) | ||
346 | { | ||
347 | } | ||
348 | |||
349 | static struct pernet_operations xfrm6_tunnel_net_ops = { | ||
350 | .init = xfrm6_tunnel_net_init, | ||
351 | .exit = xfrm6_tunnel_net_exit, | ||
352 | .id = &xfrm6_tunnel_net_id, | ||
353 | .size = sizeof(struct xfrm6_tunnel_net), | ||
354 | }; | ||
355 | |||
354 | static int __init xfrm6_tunnel_init(void) | 356 | static int __init xfrm6_tunnel_init(void) |
355 | { | 357 | { |
356 | if (xfrm_register_type(&xfrm6_tunnel_type, AF_INET6) < 0) | 358 | int rv; |
357 | goto err; | 359 | |
358 | if (xfrm6_tunnel_register(&xfrm6_tunnel_handler, AF_INET6)) | 360 | xfrm6_tunnel_spi_kmem = kmem_cache_create("xfrm6_tunnel_spi", |
359 | goto unreg; | 361 | sizeof(struct xfrm6_tunnel_spi), |
360 | if (xfrm6_tunnel_register(&xfrm46_tunnel_handler, AF_INET)) | 362 | 0, SLAB_HWCACHE_ALIGN, |
361 | goto dereg6; | 363 | NULL); |
362 | if (xfrm6_tunnel_spi_init() < 0) | 364 | if (!xfrm6_tunnel_spi_kmem) |
363 | goto dereg46; | 365 | return -ENOMEM; |
366 | rv = register_pernet_subsys(&xfrm6_tunnel_net_ops); | ||
367 | if (rv < 0) | ||
368 | goto out_pernet; | ||
369 | rv = xfrm_register_type(&xfrm6_tunnel_type, AF_INET6); | ||
370 | if (rv < 0) | ||
371 | goto out_type; | ||
372 | rv = xfrm6_tunnel_register(&xfrm6_tunnel_handler, AF_INET6); | ||
373 | if (rv < 0) | ||
374 | goto out_xfrm6; | ||
375 | rv = xfrm6_tunnel_register(&xfrm46_tunnel_handler, AF_INET); | ||
376 | if (rv < 0) | ||
377 | goto out_xfrm46; | ||
364 | return 0; | 378 | return 0; |
365 | 379 | ||
366 | dereg46: | 380 | out_xfrm46: |
367 | xfrm6_tunnel_deregister(&xfrm46_tunnel_handler, AF_INET); | ||
368 | dereg6: | ||
369 | xfrm6_tunnel_deregister(&xfrm6_tunnel_handler, AF_INET6); | 381 | xfrm6_tunnel_deregister(&xfrm6_tunnel_handler, AF_INET6); |
370 | unreg: | 382 | out_xfrm6: |
371 | xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6); | 383 | xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6); |
372 | err: | 384 | out_type: |
373 | return -EAGAIN; | 385 | unregister_pernet_subsys(&xfrm6_tunnel_net_ops); |
386 | out_pernet: | ||
387 | kmem_cache_destroy(xfrm6_tunnel_spi_kmem); | ||
388 | return rv; | ||
374 | } | 389 | } |
375 | 390 | ||
376 | static void __exit xfrm6_tunnel_fini(void) | 391 | static void __exit xfrm6_tunnel_fini(void) |
377 | { | 392 | { |
378 | xfrm6_tunnel_spi_fini(); | ||
379 | xfrm6_tunnel_deregister(&xfrm46_tunnel_handler, AF_INET); | 393 | xfrm6_tunnel_deregister(&xfrm46_tunnel_handler, AF_INET); |
380 | xfrm6_tunnel_deregister(&xfrm6_tunnel_handler, AF_INET6); | 394 | xfrm6_tunnel_deregister(&xfrm6_tunnel_handler, AF_INET6); |
381 | xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6); | 395 | xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6); |
396 | unregister_pernet_subsys(&xfrm6_tunnel_net_ops); | ||
397 | kmem_cache_destroy(xfrm6_tunnel_spi_kmem); | ||
382 | } | 398 | } |
383 | 399 | ||
384 | module_init(xfrm6_tunnel_init); | 400 | module_init(xfrm6_tunnel_init); |