diff options
Diffstat (limited to 'net/ipv6')
55 files changed, 2315 insertions, 1921 deletions
diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig index ead6c7a42f44..a578096152ab 100644 --- a/net/ipv6/Kconfig +++ b/net/ipv6/Kconfig | |||
@@ -170,6 +170,25 @@ config IPV6_SIT | |||
170 | 170 | ||
171 | Saying M here will produce a module called sit. If unsure, say Y. | 171 | Saying M here will produce a module called sit. If unsure, say Y. |
172 | 172 | ||
173 | config IPV6_SIT_6RD | ||
174 | bool "IPv6: IPv6 Rapid Deployment (6RD) (EXPERIMENTAL)" | ||
175 | depends on IPV6_SIT && EXPERIMENTAL | ||
176 | default n | ||
177 | ---help--- | ||
178 | IPv6 Rapid Deployment (6rd; draft-ietf-softwire-ipv6-6rd) builds upon | ||
179 | mechanisms of 6to4 (RFC3056) to enable a service provider to rapidly | ||
180 | deploy IPv6 unicast service to IPv4 sites to which it provides | ||
181 | customer premise equipment. Like 6to4, it utilizes stateless IPv6 in | ||
182 | IPv4 encapsulation in order to transit IPv4-only network | ||
183 | infrastructure. Unlike 6to4, a 6rd service provider uses an IPv6 | ||
184 | prefix of its own in place of the fixed 6to4 prefix. | ||
185 | |||
186 | With this option enabled, the SIT driver offers 6rd functionality by | ||
187 | providing additional ioctl API to configure the IPv6 Prefix for in | ||
188 | stead of static 2002::/16 for 6to4. | ||
189 | |||
190 | If unsure, say N. | ||
191 | |||
173 | config IPV6_NDISC_NODETYPE | 192 | config IPV6_NDISC_NODETYPE |
174 | bool | 193 | bool |
175 | 194 | ||
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 1fd0a3d775d2..413054f02aab 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
@@ -53,6 +53,7 @@ | |||
53 | #include <linux/route.h> | 53 | #include <linux/route.h> |
54 | #include <linux/inetdevice.h> | 54 | #include <linux/inetdevice.h> |
55 | #include <linux/init.h> | 55 | #include <linux/init.h> |
56 | #include <linux/slab.h> | ||
56 | #ifdef CONFIG_SYSCTL | 57 | #ifdef CONFIG_SYSCTL |
57 | #include <linux/sysctl.h> | 58 | #include <linux/sysctl.h> |
58 | #endif | 59 | #endif |
@@ -278,31 +279,31 @@ static void addrconf_mod_timer(struct inet6_ifaddr *ifp, | |||
278 | 279 | ||
279 | static int snmp6_alloc_dev(struct inet6_dev *idev) | 280 | static int snmp6_alloc_dev(struct inet6_dev *idev) |
280 | { | 281 | { |
281 | if (snmp_mib_init((void **)idev->stats.ipv6, | 282 | if (snmp_mib_init((void __percpu **)idev->stats.ipv6, |
282 | sizeof(struct ipstats_mib)) < 0) | 283 | sizeof(struct ipstats_mib)) < 0) |
283 | goto err_ip; | 284 | goto err_ip; |
284 | if (snmp_mib_init((void **)idev->stats.icmpv6, | 285 | if (snmp_mib_init((void __percpu **)idev->stats.icmpv6, |
285 | sizeof(struct icmpv6_mib)) < 0) | 286 | sizeof(struct icmpv6_mib)) < 0) |
286 | goto err_icmp; | 287 | goto err_icmp; |
287 | if (snmp_mib_init((void **)idev->stats.icmpv6msg, | 288 | if (snmp_mib_init((void __percpu **)idev->stats.icmpv6msg, |
288 | sizeof(struct icmpv6msg_mib)) < 0) | 289 | sizeof(struct icmpv6msg_mib)) < 0) |
289 | goto err_icmpmsg; | 290 | goto err_icmpmsg; |
290 | 291 | ||
291 | return 0; | 292 | return 0; |
292 | 293 | ||
293 | err_icmpmsg: | 294 | err_icmpmsg: |
294 | snmp_mib_free((void **)idev->stats.icmpv6); | 295 | snmp_mib_free((void __percpu **)idev->stats.icmpv6); |
295 | err_icmp: | 296 | err_icmp: |
296 | snmp_mib_free((void **)idev->stats.ipv6); | 297 | snmp_mib_free((void __percpu **)idev->stats.ipv6); |
297 | err_ip: | 298 | err_ip: |
298 | return -ENOMEM; | 299 | return -ENOMEM; |
299 | } | 300 | } |
300 | 301 | ||
301 | static void snmp6_free_dev(struct inet6_dev *idev) | 302 | static void snmp6_free_dev(struct inet6_dev *idev) |
302 | { | 303 | { |
303 | snmp_mib_free((void **)idev->stats.icmpv6msg); | 304 | snmp_mib_free((void __percpu **)idev->stats.icmpv6msg); |
304 | snmp_mib_free((void **)idev->stats.icmpv6); | 305 | snmp_mib_free((void __percpu **)idev->stats.icmpv6); |
305 | snmp_mib_free((void **)idev->stats.ipv6); | 306 | snmp_mib_free((void __percpu **)idev->stats.ipv6); |
306 | } | 307 | } |
307 | 308 | ||
308 | /* Nobody refers to this device, we may destroy it. */ | 309 | /* Nobody refers to this device, we may destroy it. */ |
@@ -481,9 +482,8 @@ static void addrconf_forward_change(struct net *net, __s32 newf) | |||
481 | struct net_device *dev; | 482 | struct net_device *dev; |
482 | struct inet6_dev *idev; | 483 | struct inet6_dev *idev; |
483 | 484 | ||
484 | read_lock(&dev_base_lock); | 485 | rcu_read_lock(); |
485 | for_each_netdev(net, dev) { | 486 | for_each_netdev_rcu(net, dev) { |
486 | rcu_read_lock(); | ||
487 | idev = __in6_dev_get(dev); | 487 | idev = __in6_dev_get(dev); |
488 | if (idev) { | 488 | if (idev) { |
489 | int changed = (!idev->cnf.forwarding) ^ (!newf); | 489 | int changed = (!idev->cnf.forwarding) ^ (!newf); |
@@ -491,9 +491,8 @@ static void addrconf_forward_change(struct net *net, __s32 newf) | |||
491 | if (changed) | 491 | if (changed) |
492 | dev_forward_change(idev); | 492 | dev_forward_change(idev); |
493 | } | 493 | } |
494 | rcu_read_unlock(); | ||
495 | } | 494 | } |
496 | read_unlock(&dev_base_lock); | 495 | rcu_read_unlock(); |
497 | } | 496 | } |
498 | 497 | ||
499 | static int addrconf_fixup_forwarding(struct ctl_table *table, int *p, int old) | 498 | static int addrconf_fixup_forwarding(struct ctl_table *table, int *p, int old) |
@@ -504,8 +503,11 @@ static int addrconf_fixup_forwarding(struct ctl_table *table, int *p, int old) | |||
504 | if (p == &net->ipv6.devconf_dflt->forwarding) | 503 | if (p == &net->ipv6.devconf_dflt->forwarding) |
505 | return 0; | 504 | return 0; |
506 | 505 | ||
507 | if (!rtnl_trylock()) | 506 | if (!rtnl_trylock()) { |
507 | /* Restore the original values before restarting */ | ||
508 | *p = old; | ||
508 | return restart_syscall(); | 509 | return restart_syscall(); |
510 | } | ||
509 | 511 | ||
510 | if (p == &net->ipv6.devconf_all->forwarding) { | 512 | if (p == &net->ipv6.devconf_all->forwarding) { |
511 | __s32 newf = net->ipv6.devconf_all->forwarding; | 513 | __s32 newf = net->ipv6.devconf_all->forwarding; |
@@ -991,8 +993,7 @@ struct ipv6_saddr_dst { | |||
991 | 993 | ||
992 | static inline int ipv6_saddr_preferred(int type) | 994 | static inline int ipv6_saddr_preferred(int type) |
993 | { | 995 | { |
994 | if (type & (IPV6_ADDR_MAPPED|IPV6_ADDR_COMPATv4| | 996 | if (type & (IPV6_ADDR_MAPPED|IPV6_ADDR_COMPATv4|IPV6_ADDR_LOOPBACK)) |
995 | IPV6_ADDR_LOOPBACK|IPV6_ADDR_RESERVED)) | ||
996 | return 1; | 997 | return 1; |
997 | return 0; | 998 | return 0; |
998 | } | 999 | } |
@@ -1137,10 +1138,9 @@ int ipv6_dev_get_saddr(struct net *net, struct net_device *dst_dev, | |||
1137 | hiscore->rule = -1; | 1138 | hiscore->rule = -1; |
1138 | hiscore->ifa = NULL; | 1139 | hiscore->ifa = NULL; |
1139 | 1140 | ||
1140 | read_lock(&dev_base_lock); | ||
1141 | rcu_read_lock(); | 1141 | rcu_read_lock(); |
1142 | 1142 | ||
1143 | for_each_netdev(net, dev) { | 1143 | for_each_netdev_rcu(net, dev) { |
1144 | struct inet6_dev *idev; | 1144 | struct inet6_dev *idev; |
1145 | 1145 | ||
1146 | /* Candidate Source Address (section 4) | 1146 | /* Candidate Source Address (section 4) |
@@ -1235,7 +1235,6 @@ try_nextdev: | |||
1235 | read_unlock_bh(&idev->lock); | 1235 | read_unlock_bh(&idev->lock); |
1236 | } | 1236 | } |
1237 | rcu_read_unlock(); | 1237 | rcu_read_unlock(); |
1238 | read_unlock(&dev_base_lock); | ||
1239 | 1238 | ||
1240 | if (!hiscore->ifa) | 1239 | if (!hiscore->ifa) |
1241 | return -EADDRNOTAVAIL; | 1240 | return -EADDRNOTAVAIL; |
@@ -1382,6 +1381,8 @@ static void addrconf_dad_stop(struct inet6_ifaddr *ifp, int dad_failed) | |||
1382 | if (dad_failed) | 1381 | if (dad_failed) |
1383 | ifp->flags |= IFA_F_DADFAILED; | 1382 | ifp->flags |= IFA_F_DADFAILED; |
1384 | spin_unlock_bh(&ifp->lock); | 1383 | spin_unlock_bh(&ifp->lock); |
1384 | if (dad_failed) | ||
1385 | ipv6_ifa_notify(0, ifp); | ||
1385 | in6_ifa_put(ifp); | 1386 | in6_ifa_put(ifp); |
1386 | #ifdef CONFIG_IPV6_PRIVACY | 1387 | #ifdef CONFIG_IPV6_PRIVACY |
1387 | } else if (ifp->flags&IFA_F_TEMPORARY) { | 1388 | } else if (ifp->flags&IFA_F_TEMPORARY) { |
@@ -2617,7 +2618,7 @@ static void addrconf_bonding_change(struct net_device *dev, unsigned long event) | |||
2617 | static int addrconf_ifdown(struct net_device *dev, int how) | 2618 | static int addrconf_ifdown(struct net_device *dev, int how) |
2618 | { | 2619 | { |
2619 | struct inet6_dev *idev; | 2620 | struct inet6_dev *idev; |
2620 | struct inet6_ifaddr *ifa, **bifa; | 2621 | struct inet6_ifaddr *ifa, *keep_list, **bifa; |
2621 | struct net *net = dev_net(dev); | 2622 | struct net *net = dev_net(dev); |
2622 | int i; | 2623 | int i; |
2623 | 2624 | ||
@@ -2650,11 +2651,12 @@ static int addrconf_ifdown(struct net_device *dev, int how) | |||
2650 | 2651 | ||
2651 | write_lock_bh(&addrconf_hash_lock); | 2652 | write_lock_bh(&addrconf_hash_lock); |
2652 | while ((ifa = *bifa) != NULL) { | 2653 | while ((ifa = *bifa) != NULL) { |
2653 | if (ifa->idev == idev) { | 2654 | if (ifa->idev == idev && |
2655 | (how || !(ifa->flags&IFA_F_PERMANENT) || | ||
2656 | ipv6_addr_type(&ifa->addr) & IPV6_ADDR_LINKLOCAL)) { | ||
2654 | *bifa = ifa->lst_next; | 2657 | *bifa = ifa->lst_next; |
2655 | ifa->lst_next = NULL; | 2658 | ifa->lst_next = NULL; |
2656 | addrconf_del_timer(ifa); | 2659 | __in6_ifa_put(ifa); |
2657 | in6_ifa_put(ifa); | ||
2658 | continue; | 2660 | continue; |
2659 | } | 2661 | } |
2660 | bifa = &ifa->lst_next; | 2662 | bifa = &ifa->lst_next; |
@@ -2690,11 +2692,40 @@ static int addrconf_ifdown(struct net_device *dev, int how) | |||
2690 | write_lock_bh(&idev->lock); | 2692 | write_lock_bh(&idev->lock); |
2691 | } | 2693 | } |
2692 | #endif | 2694 | #endif |
2695 | keep_list = NULL; | ||
2696 | bifa = &keep_list; | ||
2693 | while ((ifa = idev->addr_list) != NULL) { | 2697 | while ((ifa = idev->addr_list) != NULL) { |
2694 | idev->addr_list = ifa->if_next; | 2698 | idev->addr_list = ifa->if_next; |
2695 | ifa->if_next = NULL; | 2699 | ifa->if_next = NULL; |
2696 | ifa->dead = 1; | 2700 | |
2697 | addrconf_del_timer(ifa); | 2701 | addrconf_del_timer(ifa); |
2702 | |||
2703 | /* If just doing link down, and address is permanent | ||
2704 | and not link-local, then retain it. */ | ||
2705 | if (how == 0 && | ||
2706 | (ifa->flags&IFA_F_PERMANENT) && | ||
2707 | !(ipv6_addr_type(&ifa->addr) & IPV6_ADDR_LINKLOCAL)) { | ||
2708 | |||
2709 | /* Move to holding list */ | ||
2710 | *bifa = ifa; | ||
2711 | bifa = &ifa->if_next; | ||
2712 | |||
2713 | /* If not doing DAD on this address, just keep it. */ | ||
2714 | if ((dev->flags&(IFF_NOARP|IFF_LOOPBACK)) || | ||
2715 | idev->cnf.accept_dad <= 0 || | ||
2716 | (ifa->flags & IFA_F_NODAD)) | ||
2717 | continue; | ||
2718 | |||
2719 | /* If it was tentative already, no need to notify */ | ||
2720 | if (ifa->flags & IFA_F_TENTATIVE) | ||
2721 | continue; | ||
2722 | |||
2723 | /* Flag it for later restoration when link comes up */ | ||
2724 | ifa->flags |= IFA_F_TENTATIVE; | ||
2725 | in6_ifa_hold(ifa); | ||
2726 | } else { | ||
2727 | ifa->dead = 1; | ||
2728 | } | ||
2698 | write_unlock_bh(&idev->lock); | 2729 | write_unlock_bh(&idev->lock); |
2699 | 2730 | ||
2700 | __ipv6_ifa_notify(RTM_DELADDR, ifa); | 2731 | __ipv6_ifa_notify(RTM_DELADDR, ifa); |
@@ -2703,6 +2734,9 @@ static int addrconf_ifdown(struct net_device *dev, int how) | |||
2703 | 2734 | ||
2704 | write_lock_bh(&idev->lock); | 2735 | write_lock_bh(&idev->lock); |
2705 | } | 2736 | } |
2737 | |||
2738 | idev->addr_list = keep_list; | ||
2739 | |||
2706 | write_unlock_bh(&idev->lock); | 2740 | write_unlock_bh(&idev->lock); |
2707 | 2741 | ||
2708 | /* Step 5: Discard multicast list */ | 2742 | /* Step 5: Discard multicast list */ |
@@ -2728,28 +2762,29 @@ static int addrconf_ifdown(struct net_device *dev, int how) | |||
2728 | static void addrconf_rs_timer(unsigned long data) | 2762 | static void addrconf_rs_timer(unsigned long data) |
2729 | { | 2763 | { |
2730 | struct inet6_ifaddr *ifp = (struct inet6_ifaddr *) data; | 2764 | struct inet6_ifaddr *ifp = (struct inet6_ifaddr *) data; |
2765 | struct inet6_dev *idev = ifp->idev; | ||
2731 | 2766 | ||
2732 | if (ifp->idev->cnf.forwarding) | 2767 | read_lock(&idev->lock); |
2768 | if (idev->dead || !(idev->if_flags & IF_READY)) | ||
2733 | goto out; | 2769 | goto out; |
2734 | 2770 | ||
2735 | if (ifp->idev->if_flags & IF_RA_RCVD) { | 2771 | if (idev->cnf.forwarding) |
2736 | /* | 2772 | goto out; |
2737 | * Announcement received after solicitation | 2773 | |
2738 | * was sent | 2774 | /* Announcement received after solicitation was sent */ |
2739 | */ | 2775 | if (idev->if_flags & IF_RA_RCVD) |
2740 | goto out; | 2776 | goto out; |
2741 | } | ||
2742 | 2777 | ||
2743 | spin_lock(&ifp->lock); | 2778 | spin_lock(&ifp->lock); |
2744 | if (ifp->probes++ < ifp->idev->cnf.rtr_solicits) { | 2779 | if (ifp->probes++ < idev->cnf.rtr_solicits) { |
2745 | /* The wait after the last probe can be shorter */ | 2780 | /* The wait after the last probe can be shorter */ |
2746 | addrconf_mod_timer(ifp, AC_RS, | 2781 | addrconf_mod_timer(ifp, AC_RS, |
2747 | (ifp->probes == ifp->idev->cnf.rtr_solicits) ? | 2782 | (ifp->probes == idev->cnf.rtr_solicits) ? |
2748 | ifp->idev->cnf.rtr_solicit_delay : | 2783 | idev->cnf.rtr_solicit_delay : |
2749 | ifp->idev->cnf.rtr_solicit_interval); | 2784 | idev->cnf.rtr_solicit_interval); |
2750 | spin_unlock(&ifp->lock); | 2785 | spin_unlock(&ifp->lock); |
2751 | 2786 | ||
2752 | ndisc_send_rs(ifp->idev->dev, &ifp->addr, &in6addr_linklocal_allrouters); | 2787 | ndisc_send_rs(idev->dev, &ifp->addr, &in6addr_linklocal_allrouters); |
2753 | } else { | 2788 | } else { |
2754 | spin_unlock(&ifp->lock); | 2789 | spin_unlock(&ifp->lock); |
2755 | /* | 2790 | /* |
@@ -2757,10 +2792,11 @@ static void addrconf_rs_timer(unsigned long data) | |||
2757 | * assumption any longer. | 2792 | * assumption any longer. |
2758 | */ | 2793 | */ |
2759 | printk(KERN_DEBUG "%s: no IPv6 routers present\n", | 2794 | printk(KERN_DEBUG "%s: no IPv6 routers present\n", |
2760 | ifp->idev->dev->name); | 2795 | idev->dev->name); |
2761 | } | 2796 | } |
2762 | 2797 | ||
2763 | out: | 2798 | out: |
2799 | read_unlock(&idev->lock); | ||
2764 | in6_ifa_put(ifp); | 2800 | in6_ifa_put(ifp); |
2765 | } | 2801 | } |
2766 | 2802 | ||
@@ -2793,14 +2829,14 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags) | |||
2793 | read_lock_bh(&idev->lock); | 2829 | read_lock_bh(&idev->lock); |
2794 | if (ifp->dead) | 2830 | if (ifp->dead) |
2795 | goto out; | 2831 | goto out; |
2796 | spin_lock_bh(&ifp->lock); | ||
2797 | 2832 | ||
2833 | spin_lock(&ifp->lock); | ||
2798 | if (dev->flags&(IFF_NOARP|IFF_LOOPBACK) || | 2834 | if (dev->flags&(IFF_NOARP|IFF_LOOPBACK) || |
2799 | idev->cnf.accept_dad < 1 || | 2835 | idev->cnf.accept_dad < 1 || |
2800 | !(ifp->flags&IFA_F_TENTATIVE) || | 2836 | !(ifp->flags&IFA_F_TENTATIVE) || |
2801 | ifp->flags & IFA_F_NODAD) { | 2837 | ifp->flags & IFA_F_NODAD) { |
2802 | ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC|IFA_F_DADFAILED); | 2838 | ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC|IFA_F_DADFAILED); |
2803 | spin_unlock_bh(&ifp->lock); | 2839 | spin_unlock(&ifp->lock); |
2804 | read_unlock_bh(&idev->lock); | 2840 | read_unlock_bh(&idev->lock); |
2805 | 2841 | ||
2806 | addrconf_dad_completed(ifp); | 2842 | addrconf_dad_completed(ifp); |
@@ -2808,7 +2844,7 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags) | |||
2808 | } | 2844 | } |
2809 | 2845 | ||
2810 | if (!(idev->if_flags & IF_READY)) { | 2846 | if (!(idev->if_flags & IF_READY)) { |
2811 | spin_unlock_bh(&ifp->lock); | 2847 | spin_unlock(&ifp->lock); |
2812 | read_unlock_bh(&idev->lock); | 2848 | read_unlock_bh(&idev->lock); |
2813 | /* | 2849 | /* |
2814 | * If the device is not ready: | 2850 | * If the device is not ready: |
@@ -2828,7 +2864,7 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags) | |||
2828 | ip6_ins_rt(ifp->rt); | 2864 | ip6_ins_rt(ifp->rt); |
2829 | 2865 | ||
2830 | addrconf_dad_kick(ifp); | 2866 | addrconf_dad_kick(ifp); |
2831 | spin_unlock_bh(&ifp->lock); | 2867 | spin_unlock(&ifp->lock); |
2832 | out: | 2868 | out: |
2833 | read_unlock_bh(&idev->lock); | 2869 | read_unlock_bh(&idev->lock); |
2834 | } | 2870 | } |
@@ -2839,20 +2875,21 @@ static void addrconf_dad_timer(unsigned long data) | |||
2839 | struct inet6_dev *idev = ifp->idev; | 2875 | struct inet6_dev *idev = ifp->idev; |
2840 | struct in6_addr mcaddr; | 2876 | struct in6_addr mcaddr; |
2841 | 2877 | ||
2842 | read_lock_bh(&idev->lock); | 2878 | read_lock(&idev->lock); |
2843 | if (idev->dead) { | 2879 | if (idev->dead || !(idev->if_flags & IF_READY)) { |
2844 | read_unlock_bh(&idev->lock); | 2880 | read_unlock(&idev->lock); |
2845 | goto out; | 2881 | goto out; |
2846 | } | 2882 | } |
2847 | spin_lock_bh(&ifp->lock); | 2883 | |
2884 | spin_lock(&ifp->lock); | ||
2848 | if (ifp->probes == 0) { | 2885 | if (ifp->probes == 0) { |
2849 | /* | 2886 | /* |
2850 | * DAD was successful | 2887 | * DAD was successful |
2851 | */ | 2888 | */ |
2852 | 2889 | ||
2853 | ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC|IFA_F_DADFAILED); | 2890 | ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC|IFA_F_DADFAILED); |
2854 | spin_unlock_bh(&ifp->lock); | 2891 | spin_unlock(&ifp->lock); |
2855 | read_unlock_bh(&idev->lock); | 2892 | read_unlock(&idev->lock); |
2856 | 2893 | ||
2857 | addrconf_dad_completed(ifp); | 2894 | addrconf_dad_completed(ifp); |
2858 | 2895 | ||
@@ -2861,8 +2898,8 @@ static void addrconf_dad_timer(unsigned long data) | |||
2861 | 2898 | ||
2862 | ifp->probes--; | 2899 | ifp->probes--; |
2863 | addrconf_mod_timer(ifp, AC_DAD, ifp->idev->nd_parms->retrans_time); | 2900 | addrconf_mod_timer(ifp, AC_DAD, ifp->idev->nd_parms->retrans_time); |
2864 | spin_unlock_bh(&ifp->lock); | 2901 | spin_unlock(&ifp->lock); |
2865 | read_unlock_bh(&idev->lock); | 2902 | read_unlock(&idev->lock); |
2866 | 2903 | ||
2867 | /* send a neighbour solicitation for our addr */ | 2904 | /* send a neighbour solicitation for our addr */ |
2868 | addrconf_addr_solict_mult(&ifp->addr, &mcaddr); | 2905 | addrconf_addr_solict_mult(&ifp->addr, &mcaddr); |
@@ -2909,12 +2946,12 @@ static void addrconf_dad_run(struct inet6_dev *idev) { | |||
2909 | 2946 | ||
2910 | read_lock_bh(&idev->lock); | 2947 | read_lock_bh(&idev->lock); |
2911 | for (ifp = idev->addr_list; ifp; ifp = ifp->if_next) { | 2948 | for (ifp = idev->addr_list; ifp; ifp = ifp->if_next) { |
2912 | spin_lock_bh(&ifp->lock); | 2949 | spin_lock(&ifp->lock); |
2913 | if (!(ifp->flags & IFA_F_TENTATIVE)) { | 2950 | if (!(ifp->flags & IFA_F_TENTATIVE)) { |
2914 | spin_unlock_bh(&ifp->lock); | 2951 | spin_unlock(&ifp->lock); |
2915 | continue; | 2952 | continue; |
2916 | } | 2953 | } |
2917 | spin_unlock_bh(&ifp->lock); | 2954 | spin_unlock(&ifp->lock); |
2918 | addrconf_dad_kick(ifp); | 2955 | addrconf_dad_kick(ifp); |
2919 | } | 2956 | } |
2920 | read_unlock_bh(&idev->lock); | 2957 | read_unlock_bh(&idev->lock); |
@@ -3031,14 +3068,14 @@ static const struct file_operations if6_fops = { | |||
3031 | .release = seq_release_net, | 3068 | .release = seq_release_net, |
3032 | }; | 3069 | }; |
3033 | 3070 | ||
3034 | static int if6_proc_net_init(struct net *net) | 3071 | static int __net_init if6_proc_net_init(struct net *net) |
3035 | { | 3072 | { |
3036 | if (!proc_net_fops_create(net, "if_inet6", S_IRUGO, &if6_fops)) | 3073 | if (!proc_net_fops_create(net, "if_inet6", S_IRUGO, &if6_fops)) |
3037 | return -ENOMEM; | 3074 | return -ENOMEM; |
3038 | return 0; | 3075 | return 0; |
3039 | } | 3076 | } |
3040 | 3077 | ||
3041 | static void if6_proc_net_exit(struct net *net) | 3078 | static void __net_exit if6_proc_net_exit(struct net *net) |
3042 | { | 3079 | { |
3043 | proc_net_remove(net, "if_inet6"); | 3080 | proc_net_remove(net, "if_inet6"); |
3044 | } | 3081 | } |
@@ -3485,85 +3522,114 @@ enum addr_type_t | |||
3485 | ANYCAST_ADDR, | 3522 | ANYCAST_ADDR, |
3486 | }; | 3523 | }; |
3487 | 3524 | ||
3525 | /* called with rcu_read_lock() */ | ||
3526 | static int in6_dump_addrs(struct inet6_dev *idev, struct sk_buff *skb, | ||
3527 | struct netlink_callback *cb, enum addr_type_t type, | ||
3528 | int s_ip_idx, int *p_ip_idx) | ||
3529 | { | ||
3530 | struct inet6_ifaddr *ifa; | ||
3531 | struct ifmcaddr6 *ifmca; | ||
3532 | struct ifacaddr6 *ifaca; | ||
3533 | int err = 1; | ||
3534 | int ip_idx = *p_ip_idx; | ||
3535 | |||
3536 | read_lock_bh(&idev->lock); | ||
3537 | switch (type) { | ||
3538 | case UNICAST_ADDR: | ||
3539 | /* unicast address incl. temp addr */ | ||
3540 | for (ifa = idev->addr_list; ifa; | ||
3541 | ifa = ifa->if_next, ip_idx++) { | ||
3542 | if (ip_idx < s_ip_idx) | ||
3543 | continue; | ||
3544 | err = inet6_fill_ifaddr(skb, ifa, | ||
3545 | NETLINK_CB(cb->skb).pid, | ||
3546 | cb->nlh->nlmsg_seq, | ||
3547 | RTM_NEWADDR, | ||
3548 | NLM_F_MULTI); | ||
3549 | if (err <= 0) | ||
3550 | break; | ||
3551 | } | ||
3552 | break; | ||
3553 | case MULTICAST_ADDR: | ||
3554 | /* multicast address */ | ||
3555 | for (ifmca = idev->mc_list; ifmca; | ||
3556 | ifmca = ifmca->next, ip_idx++) { | ||
3557 | if (ip_idx < s_ip_idx) | ||
3558 | continue; | ||
3559 | err = inet6_fill_ifmcaddr(skb, ifmca, | ||
3560 | NETLINK_CB(cb->skb).pid, | ||
3561 | cb->nlh->nlmsg_seq, | ||
3562 | RTM_GETMULTICAST, | ||
3563 | NLM_F_MULTI); | ||
3564 | if (err <= 0) | ||
3565 | break; | ||
3566 | } | ||
3567 | break; | ||
3568 | case ANYCAST_ADDR: | ||
3569 | /* anycast address */ | ||
3570 | for (ifaca = idev->ac_list; ifaca; | ||
3571 | ifaca = ifaca->aca_next, ip_idx++) { | ||
3572 | if (ip_idx < s_ip_idx) | ||
3573 | continue; | ||
3574 | err = inet6_fill_ifacaddr(skb, ifaca, | ||
3575 | NETLINK_CB(cb->skb).pid, | ||
3576 | cb->nlh->nlmsg_seq, | ||
3577 | RTM_GETANYCAST, | ||
3578 | NLM_F_MULTI); | ||
3579 | if (err <= 0) | ||
3580 | break; | ||
3581 | } | ||
3582 | break; | ||
3583 | default: | ||
3584 | break; | ||
3585 | } | ||
3586 | read_unlock_bh(&idev->lock); | ||
3587 | *p_ip_idx = ip_idx; | ||
3588 | return err; | ||
3589 | } | ||
3590 | |||
3488 | static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb, | 3591 | static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb, |
3489 | enum addr_type_t type) | 3592 | enum addr_type_t type) |
3490 | { | 3593 | { |
3594 | struct net *net = sock_net(skb->sk); | ||
3595 | int h, s_h; | ||
3491 | int idx, ip_idx; | 3596 | int idx, ip_idx; |
3492 | int s_idx, s_ip_idx; | 3597 | int s_idx, s_ip_idx; |
3493 | int err = 1; | ||
3494 | struct net_device *dev; | 3598 | struct net_device *dev; |
3495 | struct inet6_dev *idev = NULL; | 3599 | struct inet6_dev *idev; |
3496 | struct inet6_ifaddr *ifa; | 3600 | struct hlist_head *head; |
3497 | struct ifmcaddr6 *ifmca; | 3601 | struct hlist_node *node; |
3498 | struct ifacaddr6 *ifaca; | ||
3499 | struct net *net = sock_net(skb->sk); | ||
3500 | 3602 | ||
3501 | s_idx = cb->args[0]; | 3603 | s_h = cb->args[0]; |
3502 | s_ip_idx = ip_idx = cb->args[1]; | 3604 | s_idx = idx = cb->args[1]; |
3605 | s_ip_idx = ip_idx = cb->args[2]; | ||
3503 | 3606 | ||
3504 | idx = 0; | 3607 | rcu_read_lock(); |
3505 | for_each_netdev(net, dev) { | 3608 | for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) { |
3506 | if (idx < s_idx) | 3609 | idx = 0; |
3507 | goto cont; | 3610 | head = &net->dev_index_head[h]; |
3508 | if (idx > s_idx) | 3611 | hlist_for_each_entry_rcu(dev, node, head, index_hlist) { |
3509 | s_ip_idx = 0; | 3612 | if (idx < s_idx) |
3510 | ip_idx = 0; | 3613 | goto cont; |
3511 | if ((idev = in6_dev_get(dev)) == NULL) | 3614 | if (h > s_h || idx > s_idx) |
3512 | goto cont; | 3615 | s_ip_idx = 0; |
3513 | read_lock_bh(&idev->lock); | 3616 | ip_idx = 0; |
3514 | switch (type) { | 3617 | if ((idev = __in6_dev_get(dev)) == NULL) |
3515 | case UNICAST_ADDR: | 3618 | goto cont; |
3516 | /* unicast address incl. temp addr */ | 3619 | |
3517 | for (ifa = idev->addr_list; ifa; | 3620 | if (in6_dump_addrs(idev, skb, cb, type, |
3518 | ifa = ifa->if_next, ip_idx++) { | 3621 | s_ip_idx, &ip_idx) <= 0) |
3519 | if (ip_idx < s_ip_idx) | 3622 | goto done; |
3520 | continue; | ||
3521 | err = inet6_fill_ifaddr(skb, ifa, | ||
3522 | NETLINK_CB(cb->skb).pid, | ||
3523 | cb->nlh->nlmsg_seq, | ||
3524 | RTM_NEWADDR, | ||
3525 | NLM_F_MULTI); | ||
3526 | } | ||
3527 | break; | ||
3528 | case MULTICAST_ADDR: | ||
3529 | /* multicast address */ | ||
3530 | for (ifmca = idev->mc_list; ifmca; | ||
3531 | ifmca = ifmca->next, ip_idx++) { | ||
3532 | if (ip_idx < s_ip_idx) | ||
3533 | continue; | ||
3534 | err = inet6_fill_ifmcaddr(skb, ifmca, | ||
3535 | NETLINK_CB(cb->skb).pid, | ||
3536 | cb->nlh->nlmsg_seq, | ||
3537 | RTM_GETMULTICAST, | ||
3538 | NLM_F_MULTI); | ||
3539 | } | ||
3540 | break; | ||
3541 | case ANYCAST_ADDR: | ||
3542 | /* anycast address */ | ||
3543 | for (ifaca = idev->ac_list; ifaca; | ||
3544 | ifaca = ifaca->aca_next, ip_idx++) { | ||
3545 | if (ip_idx < s_ip_idx) | ||
3546 | continue; | ||
3547 | err = inet6_fill_ifacaddr(skb, ifaca, | ||
3548 | NETLINK_CB(cb->skb).pid, | ||
3549 | cb->nlh->nlmsg_seq, | ||
3550 | RTM_GETANYCAST, | ||
3551 | NLM_F_MULTI); | ||
3552 | } | ||
3553 | break; | ||
3554 | default: | ||
3555 | break; | ||
3556 | } | ||
3557 | read_unlock_bh(&idev->lock); | ||
3558 | in6_dev_put(idev); | ||
3559 | |||
3560 | if (err <= 0) | ||
3561 | break; | ||
3562 | cont: | 3623 | cont: |
3563 | idx++; | 3624 | idx++; |
3625 | } | ||
3564 | } | 3626 | } |
3565 | cb->args[0] = idx; | 3627 | done: |
3566 | cb->args[1] = ip_idx; | 3628 | rcu_read_unlock(); |
3629 | cb->args[0] = h; | ||
3630 | cb->args[1] = idx; | ||
3631 | cb->args[2] = ip_idx; | ||
3632 | |||
3567 | return skb->len; | 3633 | return skb->len; |
3568 | } | 3634 | } |
3569 | 3635 | ||
@@ -3708,6 +3774,7 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf, | |||
3708 | #endif | 3774 | #endif |
3709 | array[DEVCONF_DISABLE_IPV6] = cnf->disable_ipv6; | 3775 | array[DEVCONF_DISABLE_IPV6] = cnf->disable_ipv6; |
3710 | array[DEVCONF_ACCEPT_DAD] = cnf->accept_dad; | 3776 | array[DEVCONF_ACCEPT_DAD] = cnf->accept_dad; |
3777 | array[DEVCONF_FORCE_TLLAO] = cnf->force_tllao; | ||
3711 | } | 3778 | } |
3712 | 3779 | ||
3713 | static inline size_t inet6_if_nlmsg_size(void) | 3780 | static inline size_t inet6_if_nlmsg_size(void) |
@@ -3726,8 +3793,8 @@ static inline size_t inet6_if_nlmsg_size(void) | |||
3726 | ); | 3793 | ); |
3727 | } | 3794 | } |
3728 | 3795 | ||
3729 | static inline void __snmp6_fill_stats(u64 *stats, void **mib, int items, | 3796 | static inline void __snmp6_fill_stats(u64 *stats, void __percpu **mib, |
3730 | int bytes) | 3797 | int items, int bytes) |
3731 | { | 3798 | { |
3732 | int i; | 3799 | int i; |
3733 | int pad = bytes - sizeof(u64) * items; | 3800 | int pad = bytes - sizeof(u64) * items; |
@@ -3746,10 +3813,10 @@ static void snmp6_fill_stats(u64 *stats, struct inet6_dev *idev, int attrtype, | |||
3746 | { | 3813 | { |
3747 | switch(attrtype) { | 3814 | switch(attrtype) { |
3748 | case IFLA_INET6_STATS: | 3815 | case IFLA_INET6_STATS: |
3749 | __snmp6_fill_stats(stats, (void **)idev->stats.ipv6, IPSTATS_MIB_MAX, bytes); | 3816 | __snmp6_fill_stats(stats, (void __percpu **)idev->stats.ipv6, IPSTATS_MIB_MAX, bytes); |
3750 | break; | 3817 | break; |
3751 | case IFLA_INET6_ICMP6STATS: | 3818 | case IFLA_INET6_ICMP6STATS: |
3752 | __snmp6_fill_stats(stats, (void **)idev->stats.icmpv6, ICMP6_MIB_MAX, bytes); | 3819 | __snmp6_fill_stats(stats, (void __percpu **)idev->stats.icmpv6, ICMP6_MIB_MAX, bytes); |
3753 | break; | 3820 | break; |
3754 | } | 3821 | } |
3755 | } | 3822 | } |
@@ -3826,28 +3893,39 @@ nla_put_failure: | |||
3826 | static int inet6_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) | 3893 | static int inet6_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) |
3827 | { | 3894 | { |
3828 | struct net *net = sock_net(skb->sk); | 3895 | struct net *net = sock_net(skb->sk); |
3829 | int idx, err; | 3896 | int h, s_h; |
3830 | int s_idx = cb->args[0]; | 3897 | int idx = 0, s_idx; |
3831 | struct net_device *dev; | 3898 | struct net_device *dev; |
3832 | struct inet6_dev *idev; | 3899 | struct inet6_dev *idev; |
3900 | struct hlist_head *head; | ||
3901 | struct hlist_node *node; | ||
3833 | 3902 | ||
3834 | read_lock(&dev_base_lock); | 3903 | s_h = cb->args[0]; |
3835 | idx = 0; | 3904 | s_idx = cb->args[1]; |
3836 | for_each_netdev(net, dev) { | 3905 | |
3837 | if (idx < s_idx) | 3906 | rcu_read_lock(); |
3838 | goto cont; | 3907 | for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) { |
3839 | if ((idev = in6_dev_get(dev)) == NULL) | 3908 | idx = 0; |
3840 | goto cont; | 3909 | head = &net->dev_index_head[h]; |
3841 | err = inet6_fill_ifinfo(skb, idev, NETLINK_CB(cb->skb).pid, | 3910 | hlist_for_each_entry_rcu(dev, node, head, index_hlist) { |
3842 | cb->nlh->nlmsg_seq, RTM_NEWLINK, NLM_F_MULTI); | 3911 | if (idx < s_idx) |
3843 | in6_dev_put(idev); | 3912 | goto cont; |
3844 | if (err <= 0) | 3913 | idev = __in6_dev_get(dev); |
3845 | break; | 3914 | if (!idev) |
3915 | goto cont; | ||
3916 | if (inet6_fill_ifinfo(skb, idev, | ||
3917 | NETLINK_CB(cb->skb).pid, | ||
3918 | cb->nlh->nlmsg_seq, | ||
3919 | RTM_NEWLINK, NLM_F_MULTI) <= 0) | ||
3920 | goto out; | ||
3846 | cont: | 3921 | cont: |
3847 | idx++; | 3922 | idx++; |
3923 | } | ||
3848 | } | 3924 | } |
3849 | read_unlock(&dev_base_lock); | 3925 | out: |
3850 | cb->args[0] = idx; | 3926 | rcu_read_unlock(); |
3927 | cb->args[1] = idx; | ||
3928 | cb->args[0] = h; | ||
3851 | 3929 | ||
3852 | return skb->len; | 3930 | return skb->len; |
3853 | } | 3931 | } |
@@ -3991,50 +4069,18 @@ int addrconf_sysctl_forward(ctl_table *ctl, int write, | |||
3991 | { | 4069 | { |
3992 | int *valp = ctl->data; | 4070 | int *valp = ctl->data; |
3993 | int val = *valp; | 4071 | int val = *valp; |
4072 | loff_t pos = *ppos; | ||
3994 | int ret; | 4073 | int ret; |
3995 | 4074 | ||
3996 | ret = proc_dointvec(ctl, write, buffer, lenp, ppos); | 4075 | ret = proc_dointvec(ctl, write, buffer, lenp, ppos); |
3997 | 4076 | ||
3998 | if (write) | 4077 | if (write) |
3999 | ret = addrconf_fixup_forwarding(ctl, valp, val); | 4078 | ret = addrconf_fixup_forwarding(ctl, valp, val); |
4079 | if (ret) | ||
4080 | *ppos = pos; | ||
4000 | return ret; | 4081 | return ret; |
4001 | } | 4082 | } |
4002 | 4083 | ||
4003 | static int addrconf_sysctl_forward_strategy(ctl_table *table, | ||
4004 | void __user *oldval, | ||
4005 | size_t __user *oldlenp, | ||
4006 | void __user *newval, size_t newlen) | ||
4007 | { | ||
4008 | int *valp = table->data; | ||
4009 | int val = *valp; | ||
4010 | int new; | ||
4011 | |||
4012 | if (!newval || !newlen) | ||
4013 | return 0; | ||
4014 | if (newlen != sizeof(int)) | ||
4015 | return -EINVAL; | ||
4016 | if (get_user(new, (int __user *)newval)) | ||
4017 | return -EFAULT; | ||
4018 | if (new == *valp) | ||
4019 | return 0; | ||
4020 | if (oldval && oldlenp) { | ||
4021 | size_t len; | ||
4022 | if (get_user(len, oldlenp)) | ||
4023 | return -EFAULT; | ||
4024 | if (len) { | ||
4025 | if (len > table->maxlen) | ||
4026 | len = table->maxlen; | ||
4027 | if (copy_to_user(oldval, valp, len)) | ||
4028 | return -EFAULT; | ||
4029 | if (put_user(len, oldlenp)) | ||
4030 | return -EFAULT; | ||
4031 | } | ||
4032 | } | ||
4033 | |||
4034 | *valp = new; | ||
4035 | return addrconf_fixup_forwarding(table, valp, val); | ||
4036 | } | ||
4037 | |||
4038 | static void dev_disable_change(struct inet6_dev *idev) | 4084 | static void dev_disable_change(struct inet6_dev *idev) |
4039 | { | 4085 | { |
4040 | if (!idev || !idev->dev) | 4086 | if (!idev || !idev->dev) |
@@ -4051,9 +4097,8 @@ static void addrconf_disable_change(struct net *net, __s32 newf) | |||
4051 | struct net_device *dev; | 4097 | struct net_device *dev; |
4052 | struct inet6_dev *idev; | 4098 | struct inet6_dev *idev; |
4053 | 4099 | ||
4054 | read_lock(&dev_base_lock); | 4100 | rcu_read_lock(); |
4055 | for_each_netdev(net, dev) { | 4101 | for_each_netdev_rcu(net, dev) { |
4056 | rcu_read_lock(); | ||
4057 | idev = __in6_dev_get(dev); | 4102 | idev = __in6_dev_get(dev); |
4058 | if (idev) { | 4103 | if (idev) { |
4059 | int changed = (!idev->cnf.disable_ipv6) ^ (!newf); | 4104 | int changed = (!idev->cnf.disable_ipv6) ^ (!newf); |
@@ -4061,9 +4106,8 @@ static void addrconf_disable_change(struct net *net, __s32 newf) | |||
4061 | if (changed) | 4106 | if (changed) |
4062 | dev_disable_change(idev); | 4107 | dev_disable_change(idev); |
4063 | } | 4108 | } |
4064 | rcu_read_unlock(); | ||
4065 | } | 4109 | } |
4066 | read_unlock(&dev_base_lock); | 4110 | rcu_read_unlock(); |
4067 | } | 4111 | } |
4068 | 4112 | ||
4069 | static int addrconf_disable_ipv6(struct ctl_table *table, int *p, int old) | 4113 | static int addrconf_disable_ipv6(struct ctl_table *table, int *p, int old) |
@@ -4075,8 +4119,11 @@ static int addrconf_disable_ipv6(struct ctl_table *table, int *p, int old) | |||
4075 | if (p == &net->ipv6.devconf_dflt->disable_ipv6) | 4119 | if (p == &net->ipv6.devconf_dflt->disable_ipv6) |
4076 | return 0; | 4120 | return 0; |
4077 | 4121 | ||
4078 | if (!rtnl_trylock()) | 4122 | if (!rtnl_trylock()) { |
4123 | /* Restore the original values before restarting */ | ||
4124 | *p = old; | ||
4079 | return restart_syscall(); | 4125 | return restart_syscall(); |
4126 | } | ||
4080 | 4127 | ||
4081 | if (p == &net->ipv6.devconf_all->disable_ipv6) { | 4128 | if (p == &net->ipv6.devconf_all->disable_ipv6) { |
4082 | __s32 newf = net->ipv6.devconf_all->disable_ipv6; | 4129 | __s32 newf = net->ipv6.devconf_all->disable_ipv6; |
@@ -4095,12 +4142,15 @@ int addrconf_sysctl_disable(ctl_table *ctl, int write, | |||
4095 | { | 4142 | { |
4096 | int *valp = ctl->data; | 4143 | int *valp = ctl->data; |
4097 | int val = *valp; | 4144 | int val = *valp; |
4145 | loff_t pos = *ppos; | ||
4098 | int ret; | 4146 | int ret; |
4099 | 4147 | ||
4100 | ret = proc_dointvec(ctl, write, buffer, lenp, ppos); | 4148 | ret = proc_dointvec(ctl, write, buffer, lenp, ppos); |
4101 | 4149 | ||
4102 | if (write) | 4150 | if (write) |
4103 | ret = addrconf_disable_ipv6(ctl, valp, val); | 4151 | ret = addrconf_disable_ipv6(ctl, valp, val); |
4152 | if (ret) | ||
4153 | *ppos = pos; | ||
4104 | return ret; | 4154 | return ret; |
4105 | } | 4155 | } |
4106 | 4156 | ||
@@ -4113,16 +4163,13 @@ static struct addrconf_sysctl_table | |||
4113 | .sysctl_header = NULL, | 4163 | .sysctl_header = NULL, |
4114 | .addrconf_vars = { | 4164 | .addrconf_vars = { |
4115 | { | 4165 | { |
4116 | .ctl_name = NET_IPV6_FORWARDING, | ||
4117 | .procname = "forwarding", | 4166 | .procname = "forwarding", |
4118 | .data = &ipv6_devconf.forwarding, | 4167 | .data = &ipv6_devconf.forwarding, |
4119 | .maxlen = sizeof(int), | 4168 | .maxlen = sizeof(int), |
4120 | .mode = 0644, | 4169 | .mode = 0644, |
4121 | .proc_handler = addrconf_sysctl_forward, | 4170 | .proc_handler = addrconf_sysctl_forward, |
4122 | .strategy = addrconf_sysctl_forward_strategy, | ||
4123 | }, | 4171 | }, |
4124 | { | 4172 | { |
4125 | .ctl_name = NET_IPV6_HOP_LIMIT, | ||
4126 | .procname = "hop_limit", | 4173 | .procname = "hop_limit", |
4127 | .data = &ipv6_devconf.hop_limit, | 4174 | .data = &ipv6_devconf.hop_limit, |
4128 | .maxlen = sizeof(int), | 4175 | .maxlen = sizeof(int), |
@@ -4130,7 +4177,6 @@ static struct addrconf_sysctl_table | |||
4130 | .proc_handler = proc_dointvec, | 4177 | .proc_handler = proc_dointvec, |
4131 | }, | 4178 | }, |
4132 | { | 4179 | { |
4133 | .ctl_name = NET_IPV6_MTU, | ||
4134 | .procname = "mtu", | 4180 | .procname = "mtu", |
4135 | .data = &ipv6_devconf.mtu6, | 4181 | .data = &ipv6_devconf.mtu6, |
4136 | .maxlen = sizeof(int), | 4182 | .maxlen = sizeof(int), |
@@ -4138,7 +4184,6 @@ static struct addrconf_sysctl_table | |||
4138 | .proc_handler = proc_dointvec, | 4184 | .proc_handler = proc_dointvec, |
4139 | }, | 4185 | }, |
4140 | { | 4186 | { |
4141 | .ctl_name = NET_IPV6_ACCEPT_RA, | ||
4142 | .procname = "accept_ra", | 4187 | .procname = "accept_ra", |
4143 | .data = &ipv6_devconf.accept_ra, | 4188 | .data = &ipv6_devconf.accept_ra, |
4144 | .maxlen = sizeof(int), | 4189 | .maxlen = sizeof(int), |
@@ -4146,7 +4191,6 @@ static struct addrconf_sysctl_table | |||
4146 | .proc_handler = proc_dointvec, | 4191 | .proc_handler = proc_dointvec, |
4147 | }, | 4192 | }, |
4148 | { | 4193 | { |
4149 | .ctl_name = NET_IPV6_ACCEPT_REDIRECTS, | ||
4150 | .procname = "accept_redirects", | 4194 | .procname = "accept_redirects", |
4151 | .data = &ipv6_devconf.accept_redirects, | 4195 | .data = &ipv6_devconf.accept_redirects, |
4152 | .maxlen = sizeof(int), | 4196 | .maxlen = sizeof(int), |
@@ -4154,7 +4198,6 @@ static struct addrconf_sysctl_table | |||
4154 | .proc_handler = proc_dointvec, | 4198 | .proc_handler = proc_dointvec, |
4155 | }, | 4199 | }, |
4156 | { | 4200 | { |
4157 | .ctl_name = NET_IPV6_AUTOCONF, | ||
4158 | .procname = "autoconf", | 4201 | .procname = "autoconf", |
4159 | .data = &ipv6_devconf.autoconf, | 4202 | .data = &ipv6_devconf.autoconf, |
4160 | .maxlen = sizeof(int), | 4203 | .maxlen = sizeof(int), |
@@ -4162,7 +4205,6 @@ static struct addrconf_sysctl_table | |||
4162 | .proc_handler = proc_dointvec, | 4205 | .proc_handler = proc_dointvec, |
4163 | }, | 4206 | }, |
4164 | { | 4207 | { |
4165 | .ctl_name = NET_IPV6_DAD_TRANSMITS, | ||
4166 | .procname = "dad_transmits", | 4208 | .procname = "dad_transmits", |
4167 | .data = &ipv6_devconf.dad_transmits, | 4209 | .data = &ipv6_devconf.dad_transmits, |
4168 | .maxlen = sizeof(int), | 4210 | .maxlen = sizeof(int), |
@@ -4170,7 +4212,6 @@ static struct addrconf_sysctl_table | |||
4170 | .proc_handler = proc_dointvec, | 4212 | .proc_handler = proc_dointvec, |
4171 | }, | 4213 | }, |
4172 | { | 4214 | { |
4173 | .ctl_name = NET_IPV6_RTR_SOLICITS, | ||
4174 | .procname = "router_solicitations", | 4215 | .procname = "router_solicitations", |
4175 | .data = &ipv6_devconf.rtr_solicits, | 4216 | .data = &ipv6_devconf.rtr_solicits, |
4176 | .maxlen = sizeof(int), | 4217 | .maxlen = sizeof(int), |
@@ -4178,25 +4219,20 @@ static struct addrconf_sysctl_table | |||
4178 | .proc_handler = proc_dointvec, | 4219 | .proc_handler = proc_dointvec, |
4179 | }, | 4220 | }, |
4180 | { | 4221 | { |
4181 | .ctl_name = NET_IPV6_RTR_SOLICIT_INTERVAL, | ||
4182 | .procname = "router_solicitation_interval", | 4222 | .procname = "router_solicitation_interval", |
4183 | .data = &ipv6_devconf.rtr_solicit_interval, | 4223 | .data = &ipv6_devconf.rtr_solicit_interval, |
4184 | .maxlen = sizeof(int), | 4224 | .maxlen = sizeof(int), |
4185 | .mode = 0644, | 4225 | .mode = 0644, |
4186 | .proc_handler = proc_dointvec_jiffies, | 4226 | .proc_handler = proc_dointvec_jiffies, |
4187 | .strategy = sysctl_jiffies, | ||
4188 | }, | 4227 | }, |
4189 | { | 4228 | { |
4190 | .ctl_name = NET_IPV6_RTR_SOLICIT_DELAY, | ||
4191 | .procname = "router_solicitation_delay", | 4229 | .procname = "router_solicitation_delay", |
4192 | .data = &ipv6_devconf.rtr_solicit_delay, | 4230 | .data = &ipv6_devconf.rtr_solicit_delay, |
4193 | .maxlen = sizeof(int), | 4231 | .maxlen = sizeof(int), |
4194 | .mode = 0644, | 4232 | .mode = 0644, |
4195 | .proc_handler = proc_dointvec_jiffies, | 4233 | .proc_handler = proc_dointvec_jiffies, |
4196 | .strategy = sysctl_jiffies, | ||
4197 | }, | 4234 | }, |
4198 | { | 4235 | { |
4199 | .ctl_name = NET_IPV6_FORCE_MLD_VERSION, | ||
4200 | .procname = "force_mld_version", | 4236 | .procname = "force_mld_version", |
4201 | .data = &ipv6_devconf.force_mld_version, | 4237 | .data = &ipv6_devconf.force_mld_version, |
4202 | .maxlen = sizeof(int), | 4238 | .maxlen = sizeof(int), |
@@ -4205,7 +4241,6 @@ static struct addrconf_sysctl_table | |||
4205 | }, | 4241 | }, |
4206 | #ifdef CONFIG_IPV6_PRIVACY | 4242 | #ifdef CONFIG_IPV6_PRIVACY |
4207 | { | 4243 | { |
4208 | .ctl_name = NET_IPV6_USE_TEMPADDR, | ||
4209 | .procname = "use_tempaddr", | 4244 | .procname = "use_tempaddr", |
4210 | .data = &ipv6_devconf.use_tempaddr, | 4245 | .data = &ipv6_devconf.use_tempaddr, |
4211 | .maxlen = sizeof(int), | 4246 | .maxlen = sizeof(int), |
@@ -4213,7 +4248,6 @@ static struct addrconf_sysctl_table | |||
4213 | .proc_handler = proc_dointvec, | 4248 | .proc_handler = proc_dointvec, |
4214 | }, | 4249 | }, |
4215 | { | 4250 | { |
4216 | .ctl_name = NET_IPV6_TEMP_VALID_LFT, | ||
4217 | .procname = "temp_valid_lft", | 4251 | .procname = "temp_valid_lft", |
4218 | .data = &ipv6_devconf.temp_valid_lft, | 4252 | .data = &ipv6_devconf.temp_valid_lft, |
4219 | .maxlen = sizeof(int), | 4253 | .maxlen = sizeof(int), |
@@ -4221,7 +4255,6 @@ static struct addrconf_sysctl_table | |||
4221 | .proc_handler = proc_dointvec, | 4255 | .proc_handler = proc_dointvec, |
4222 | }, | 4256 | }, |
4223 | { | 4257 | { |
4224 | .ctl_name = NET_IPV6_TEMP_PREFERED_LFT, | ||
4225 | .procname = "temp_prefered_lft", | 4258 | .procname = "temp_prefered_lft", |
4226 | .data = &ipv6_devconf.temp_prefered_lft, | 4259 | .data = &ipv6_devconf.temp_prefered_lft, |
4227 | .maxlen = sizeof(int), | 4260 | .maxlen = sizeof(int), |
@@ -4229,7 +4262,6 @@ static struct addrconf_sysctl_table | |||
4229 | .proc_handler = proc_dointvec, | 4262 | .proc_handler = proc_dointvec, |
4230 | }, | 4263 | }, |
4231 | { | 4264 | { |
4232 | .ctl_name = NET_IPV6_REGEN_MAX_RETRY, | ||
4233 | .procname = "regen_max_retry", | 4265 | .procname = "regen_max_retry", |
4234 | .data = &ipv6_devconf.regen_max_retry, | 4266 | .data = &ipv6_devconf.regen_max_retry, |
4235 | .maxlen = sizeof(int), | 4267 | .maxlen = sizeof(int), |
@@ -4237,7 +4269,6 @@ static struct addrconf_sysctl_table | |||
4237 | .proc_handler = proc_dointvec, | 4269 | .proc_handler = proc_dointvec, |
4238 | }, | 4270 | }, |
4239 | { | 4271 | { |
4240 | .ctl_name = NET_IPV6_MAX_DESYNC_FACTOR, | ||
4241 | .procname = "max_desync_factor", | 4272 | .procname = "max_desync_factor", |
4242 | .data = &ipv6_devconf.max_desync_factor, | 4273 | .data = &ipv6_devconf.max_desync_factor, |
4243 | .maxlen = sizeof(int), | 4274 | .maxlen = sizeof(int), |
@@ -4246,7 +4277,6 @@ static struct addrconf_sysctl_table | |||
4246 | }, | 4277 | }, |
4247 | #endif | 4278 | #endif |
4248 | { | 4279 | { |
4249 | .ctl_name = NET_IPV6_MAX_ADDRESSES, | ||
4250 | .procname = "max_addresses", | 4280 | .procname = "max_addresses", |
4251 | .data = &ipv6_devconf.max_addresses, | 4281 | .data = &ipv6_devconf.max_addresses, |
4252 | .maxlen = sizeof(int), | 4282 | .maxlen = sizeof(int), |
@@ -4254,7 +4284,6 @@ static struct addrconf_sysctl_table | |||
4254 | .proc_handler = proc_dointvec, | 4284 | .proc_handler = proc_dointvec, |
4255 | }, | 4285 | }, |
4256 | { | 4286 | { |
4257 | .ctl_name = NET_IPV6_ACCEPT_RA_DEFRTR, | ||
4258 | .procname = "accept_ra_defrtr", | 4287 | .procname = "accept_ra_defrtr", |
4259 | .data = &ipv6_devconf.accept_ra_defrtr, | 4288 | .data = &ipv6_devconf.accept_ra_defrtr, |
4260 | .maxlen = sizeof(int), | 4289 | .maxlen = sizeof(int), |
@@ -4262,7 +4291,6 @@ static struct addrconf_sysctl_table | |||
4262 | .proc_handler = proc_dointvec, | 4291 | .proc_handler = proc_dointvec, |
4263 | }, | 4292 | }, |
4264 | { | 4293 | { |
4265 | .ctl_name = NET_IPV6_ACCEPT_RA_PINFO, | ||
4266 | .procname = "accept_ra_pinfo", | 4294 | .procname = "accept_ra_pinfo", |
4267 | .data = &ipv6_devconf.accept_ra_pinfo, | 4295 | .data = &ipv6_devconf.accept_ra_pinfo, |
4268 | .maxlen = sizeof(int), | 4296 | .maxlen = sizeof(int), |
@@ -4271,7 +4299,6 @@ static struct addrconf_sysctl_table | |||
4271 | }, | 4299 | }, |
4272 | #ifdef CONFIG_IPV6_ROUTER_PREF | 4300 | #ifdef CONFIG_IPV6_ROUTER_PREF |
4273 | { | 4301 | { |
4274 | .ctl_name = NET_IPV6_ACCEPT_RA_RTR_PREF, | ||
4275 | .procname = "accept_ra_rtr_pref", | 4302 | .procname = "accept_ra_rtr_pref", |
4276 | .data = &ipv6_devconf.accept_ra_rtr_pref, | 4303 | .data = &ipv6_devconf.accept_ra_rtr_pref, |
4277 | .maxlen = sizeof(int), | 4304 | .maxlen = sizeof(int), |
@@ -4279,17 +4306,14 @@ static struct addrconf_sysctl_table | |||
4279 | .proc_handler = proc_dointvec, | 4306 | .proc_handler = proc_dointvec, |
4280 | }, | 4307 | }, |
4281 | { | 4308 | { |
4282 | .ctl_name = NET_IPV6_RTR_PROBE_INTERVAL, | ||
4283 | .procname = "router_probe_interval", | 4309 | .procname = "router_probe_interval", |
4284 | .data = &ipv6_devconf.rtr_probe_interval, | 4310 | .data = &ipv6_devconf.rtr_probe_interval, |
4285 | .maxlen = sizeof(int), | 4311 | .maxlen = sizeof(int), |
4286 | .mode = 0644, | 4312 | .mode = 0644, |
4287 | .proc_handler = proc_dointvec_jiffies, | 4313 | .proc_handler = proc_dointvec_jiffies, |
4288 | .strategy = sysctl_jiffies, | ||
4289 | }, | 4314 | }, |
4290 | #ifdef CONFIG_IPV6_ROUTE_INFO | 4315 | #ifdef CONFIG_IPV6_ROUTE_INFO |
4291 | { | 4316 | { |
4292 | .ctl_name = NET_IPV6_ACCEPT_RA_RT_INFO_MAX_PLEN, | ||
4293 | .procname = "accept_ra_rt_info_max_plen", | 4317 | .procname = "accept_ra_rt_info_max_plen", |
4294 | .data = &ipv6_devconf.accept_ra_rt_info_max_plen, | 4318 | .data = &ipv6_devconf.accept_ra_rt_info_max_plen, |
4295 | .maxlen = sizeof(int), | 4319 | .maxlen = sizeof(int), |
@@ -4299,7 +4323,6 @@ static struct addrconf_sysctl_table | |||
4299 | #endif | 4323 | #endif |
4300 | #endif | 4324 | #endif |
4301 | { | 4325 | { |
4302 | .ctl_name = NET_IPV6_PROXY_NDP, | ||
4303 | .procname = "proxy_ndp", | 4326 | .procname = "proxy_ndp", |
4304 | .data = &ipv6_devconf.proxy_ndp, | 4327 | .data = &ipv6_devconf.proxy_ndp, |
4305 | .maxlen = sizeof(int), | 4328 | .maxlen = sizeof(int), |
@@ -4307,7 +4330,6 @@ static struct addrconf_sysctl_table | |||
4307 | .proc_handler = proc_dointvec, | 4330 | .proc_handler = proc_dointvec, |
4308 | }, | 4331 | }, |
4309 | { | 4332 | { |
4310 | .ctl_name = NET_IPV6_ACCEPT_SOURCE_ROUTE, | ||
4311 | .procname = "accept_source_route", | 4333 | .procname = "accept_source_route", |
4312 | .data = &ipv6_devconf.accept_source_route, | 4334 | .data = &ipv6_devconf.accept_source_route, |
4313 | .maxlen = sizeof(int), | 4335 | .maxlen = sizeof(int), |
@@ -4316,7 +4338,6 @@ static struct addrconf_sysctl_table | |||
4316 | }, | 4338 | }, |
4317 | #ifdef CONFIG_IPV6_OPTIMISTIC_DAD | 4339 | #ifdef CONFIG_IPV6_OPTIMISTIC_DAD |
4318 | { | 4340 | { |
4319 | .ctl_name = CTL_UNNUMBERED, | ||
4320 | .procname = "optimistic_dad", | 4341 | .procname = "optimistic_dad", |
4321 | .data = &ipv6_devconf.optimistic_dad, | 4342 | .data = &ipv6_devconf.optimistic_dad, |
4322 | .maxlen = sizeof(int), | 4343 | .maxlen = sizeof(int), |
@@ -4327,7 +4348,6 @@ static struct addrconf_sysctl_table | |||
4327 | #endif | 4348 | #endif |
4328 | #ifdef CONFIG_IPV6_MROUTE | 4349 | #ifdef CONFIG_IPV6_MROUTE |
4329 | { | 4350 | { |
4330 | .ctl_name = CTL_UNNUMBERED, | ||
4331 | .procname = "mc_forwarding", | 4351 | .procname = "mc_forwarding", |
4332 | .data = &ipv6_devconf.mc_forwarding, | 4352 | .data = &ipv6_devconf.mc_forwarding, |
4333 | .maxlen = sizeof(int), | 4353 | .maxlen = sizeof(int), |
@@ -4336,16 +4356,13 @@ static struct addrconf_sysctl_table | |||
4336 | }, | 4356 | }, |
4337 | #endif | 4357 | #endif |
4338 | { | 4358 | { |
4339 | .ctl_name = CTL_UNNUMBERED, | ||
4340 | .procname = "disable_ipv6", | 4359 | .procname = "disable_ipv6", |
4341 | .data = &ipv6_devconf.disable_ipv6, | 4360 | .data = &ipv6_devconf.disable_ipv6, |
4342 | .maxlen = sizeof(int), | 4361 | .maxlen = sizeof(int), |
4343 | .mode = 0644, | 4362 | .mode = 0644, |
4344 | .proc_handler = addrconf_sysctl_disable, | 4363 | .proc_handler = addrconf_sysctl_disable, |
4345 | .strategy = sysctl_intvec, | ||
4346 | }, | 4364 | }, |
4347 | { | 4365 | { |
4348 | .ctl_name = CTL_UNNUMBERED, | ||
4349 | .procname = "accept_dad", | 4366 | .procname = "accept_dad", |
4350 | .data = &ipv6_devconf.accept_dad, | 4367 | .data = &ipv6_devconf.accept_dad, |
4351 | .maxlen = sizeof(int), | 4368 | .maxlen = sizeof(int), |
@@ -4353,13 +4370,20 @@ static struct addrconf_sysctl_table | |||
4353 | .proc_handler = proc_dointvec, | 4370 | .proc_handler = proc_dointvec, |
4354 | }, | 4371 | }, |
4355 | { | 4372 | { |
4356 | .ctl_name = 0, /* sentinel */ | 4373 | .procname = "force_tllao", |
4374 | .data = &ipv6_devconf.force_tllao, | ||
4375 | .maxlen = sizeof(int), | ||
4376 | .mode = 0644, | ||
4377 | .proc_handler = proc_dointvec | ||
4378 | }, | ||
4379 | { | ||
4380 | /* sentinel */ | ||
4357 | } | 4381 | } |
4358 | }, | 4382 | }, |
4359 | }; | 4383 | }; |
4360 | 4384 | ||
4361 | static int __addrconf_sysctl_register(struct net *net, char *dev_name, | 4385 | static int __addrconf_sysctl_register(struct net *net, char *dev_name, |
4362 | int ctl_name, struct inet6_dev *idev, struct ipv6_devconf *p) | 4386 | struct inet6_dev *idev, struct ipv6_devconf *p) |
4363 | { | 4387 | { |
4364 | int i; | 4388 | int i; |
4365 | struct addrconf_sysctl_table *t; | 4389 | struct addrconf_sysctl_table *t; |
@@ -4367,9 +4391,9 @@ static int __addrconf_sysctl_register(struct net *net, char *dev_name, | |||
4367 | #define ADDRCONF_CTL_PATH_DEV 3 | 4391 | #define ADDRCONF_CTL_PATH_DEV 3 |
4368 | 4392 | ||
4369 | struct ctl_path addrconf_ctl_path[] = { | 4393 | struct ctl_path addrconf_ctl_path[] = { |
4370 | { .procname = "net", .ctl_name = CTL_NET, }, | 4394 | { .procname = "net", }, |
4371 | { .procname = "ipv6", .ctl_name = NET_IPV6, }, | 4395 | { .procname = "ipv6", }, |
4372 | { .procname = "conf", .ctl_name = NET_IPV6_CONF, }, | 4396 | { .procname = "conf", }, |
4373 | { /* to be set */ }, | 4397 | { /* to be set */ }, |
4374 | { }, | 4398 | { }, |
4375 | }; | 4399 | }; |
@@ -4395,7 +4419,6 @@ static int __addrconf_sysctl_register(struct net *net, char *dev_name, | |||
4395 | goto free; | 4419 | goto free; |
4396 | 4420 | ||
4397 | addrconf_ctl_path[ADDRCONF_CTL_PATH_DEV].procname = t->dev_name; | 4421 | addrconf_ctl_path[ADDRCONF_CTL_PATH_DEV].procname = t->dev_name; |
4398 | addrconf_ctl_path[ADDRCONF_CTL_PATH_DEV].ctl_name = ctl_name; | ||
4399 | 4422 | ||
4400 | t->sysctl_header = register_net_sysctl_table(net, addrconf_ctl_path, | 4423 | t->sysctl_header = register_net_sysctl_table(net, addrconf_ctl_path, |
4401 | t->addrconf_vars); | 4424 | t->addrconf_vars); |
@@ -4429,12 +4452,10 @@ static void __addrconf_sysctl_unregister(struct ipv6_devconf *p) | |||
4429 | 4452 | ||
4430 | static void addrconf_sysctl_register(struct inet6_dev *idev) | 4453 | static void addrconf_sysctl_register(struct inet6_dev *idev) |
4431 | { | 4454 | { |
4432 | neigh_sysctl_register(idev->dev, idev->nd_parms, NET_IPV6, | 4455 | neigh_sysctl_register(idev->dev, idev->nd_parms, "ipv6", |
4433 | NET_IPV6_NEIGH, "ipv6", | 4456 | &ndisc_ifinfo_sysctl_change); |
4434 | &ndisc_ifinfo_sysctl_change, | ||
4435 | ndisc_ifinfo_sysctl_strategy); | ||
4436 | __addrconf_sysctl_register(dev_net(idev->dev), idev->dev->name, | 4457 | __addrconf_sysctl_register(dev_net(idev->dev), idev->dev->name, |
4437 | idev->dev->ifindex, idev, &idev->cnf); | 4458 | idev, &idev->cnf); |
4438 | } | 4459 | } |
4439 | 4460 | ||
4440 | static void addrconf_sysctl_unregister(struct inet6_dev *idev) | 4461 | static void addrconf_sysctl_unregister(struct inet6_dev *idev) |
@@ -4446,7 +4467,7 @@ static void addrconf_sysctl_unregister(struct inet6_dev *idev) | |||
4446 | 4467 | ||
4447 | #endif | 4468 | #endif |
4448 | 4469 | ||
4449 | static int addrconf_init_net(struct net *net) | 4470 | static int __net_init addrconf_init_net(struct net *net) |
4450 | { | 4471 | { |
4451 | int err; | 4472 | int err; |
4452 | struct ipv6_devconf *all, *dflt; | 4473 | struct ipv6_devconf *all, *dflt; |
@@ -4455,7 +4476,7 @@ static int addrconf_init_net(struct net *net) | |||
4455 | all = &ipv6_devconf; | 4476 | all = &ipv6_devconf; |
4456 | dflt = &ipv6_devconf_dflt; | 4477 | dflt = &ipv6_devconf_dflt; |
4457 | 4478 | ||
4458 | if (net != &init_net) { | 4479 | if (!net_eq(net, &init_net)) { |
4459 | all = kmemdup(all, sizeof(ipv6_devconf), GFP_KERNEL); | 4480 | all = kmemdup(all, sizeof(ipv6_devconf), GFP_KERNEL); |
4460 | if (all == NULL) | 4481 | if (all == NULL) |
4461 | goto err_alloc_all; | 4482 | goto err_alloc_all; |
@@ -4473,13 +4494,11 @@ static int addrconf_init_net(struct net *net) | |||
4473 | net->ipv6.devconf_dflt = dflt; | 4494 | net->ipv6.devconf_dflt = dflt; |
4474 | 4495 | ||
4475 | #ifdef CONFIG_SYSCTL | 4496 | #ifdef CONFIG_SYSCTL |
4476 | err = __addrconf_sysctl_register(net, "all", NET_PROTO_CONF_ALL, | 4497 | err = __addrconf_sysctl_register(net, "all", NULL, all); |
4477 | NULL, all); | ||
4478 | if (err < 0) | 4498 | if (err < 0) |
4479 | goto err_reg_all; | 4499 | goto err_reg_all; |
4480 | 4500 | ||
4481 | err = __addrconf_sysctl_register(net, "default", NET_PROTO_CONF_DEFAULT, | 4501 | err = __addrconf_sysctl_register(net, "default", NULL, dflt); |
4482 | NULL, dflt); | ||
4483 | if (err < 0) | 4502 | if (err < 0) |
4484 | goto err_reg_dflt; | 4503 | goto err_reg_dflt; |
4485 | #endif | 4504 | #endif |
@@ -4497,13 +4516,13 @@ err_alloc_all: | |||
4497 | return err; | 4516 | return err; |
4498 | } | 4517 | } |
4499 | 4518 | ||
4500 | static void addrconf_exit_net(struct net *net) | 4519 | static void __net_exit addrconf_exit_net(struct net *net) |
4501 | { | 4520 | { |
4502 | #ifdef CONFIG_SYSCTL | 4521 | #ifdef CONFIG_SYSCTL |
4503 | __addrconf_sysctl_unregister(net->ipv6.devconf_dflt); | 4522 | __addrconf_sysctl_unregister(net->ipv6.devconf_dflt); |
4504 | __addrconf_sysctl_unregister(net->ipv6.devconf_all); | 4523 | __addrconf_sysctl_unregister(net->ipv6.devconf_all); |
4505 | #endif | 4524 | #endif |
4506 | if (net != &init_net) { | 4525 | if (!net_eq(net, &init_net)) { |
4507 | kfree(net->ipv6.devconf_dflt); | 4526 | kfree(net->ipv6.devconf_dflt); |
4508 | kfree(net->ipv6.devconf_all); | 4527 | kfree(net->ipv6.devconf_all); |
4509 | } | 4528 | } |
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/addrlabel.c b/net/ipv6/addrlabel.c index 6ff73c4c126a..ae404c9a746c 100644 --- a/net/ipv6/addrlabel.c +++ b/net/ipv6/addrlabel.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <linux/list.h> | 13 | #include <linux/list.h> |
14 | #include <linux/rcupdate.h> | 14 | #include <linux/rcupdate.h> |
15 | #include <linux/in6.h> | 15 | #include <linux/in6.h> |
16 | #include <linux/slab.h> | ||
16 | #include <net/addrconf.h> | 17 | #include <net/addrconf.h> |
17 | #include <linux/if_addrlabel.h> | 18 | #include <linux/if_addrlabel.h> |
18 | #include <linux/netlink.h> | 19 | #include <linux/netlink.h> |
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index e127a32f9540..3f9e86b15e0d 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c | |||
@@ -36,6 +36,7 @@ | |||
36 | #include <linux/proc_fs.h> | 36 | #include <linux/proc_fs.h> |
37 | #include <linux/stat.h> | 37 | #include <linux/stat.h> |
38 | #include <linux/init.h> | 38 | #include <linux/init.h> |
39 | #include <linux/slab.h> | ||
39 | 40 | ||
40 | #include <linux/inet.h> | 41 | #include <linux/inet.h> |
41 | #include <linux/netdevice.h> | 42 | #include <linux/netdevice.h> |
@@ -95,7 +96,8 @@ static __inline__ struct ipv6_pinfo *inet6_sk_generic(struct sock *sk) | |||
95 | return (struct ipv6_pinfo *)(((u8 *)sk) + offset); | 96 | return (struct ipv6_pinfo *)(((u8 *)sk) + offset); |
96 | } | 97 | } |
97 | 98 | ||
98 | static int inet6_create(struct net *net, struct socket *sock, int protocol) | 99 | static int inet6_create(struct net *net, struct socket *sock, int protocol, |
100 | int kern) | ||
99 | { | 101 | { |
100 | struct inet_sock *inet; | 102 | struct inet_sock *inet; |
101 | struct ipv6_pinfo *np; | 103 | struct ipv6_pinfo *np; |
@@ -158,7 +160,7 @@ lookup_protocol: | |||
158 | } | 160 | } |
159 | 161 | ||
160 | err = -EPERM; | 162 | err = -EPERM; |
161 | if (answer->capability > 0 && !capable(answer->capability)) | 163 | if (sock->type == SOCK_RAW && !kern && !capable(CAP_NET_RAW)) |
162 | goto out_rcu_unlock; | 164 | goto out_rcu_unlock; |
163 | 165 | ||
164 | sock->ops = answer->ops; | 166 | sock->ops = answer->ops; |
@@ -185,7 +187,7 @@ lookup_protocol: | |||
185 | inet->is_icsk = (INET_PROTOSW_ICSK & answer_flags) != 0; | 187 | inet->is_icsk = (INET_PROTOSW_ICSK & answer_flags) != 0; |
186 | 188 | ||
187 | if (SOCK_RAW == sock->type) { | 189 | if (SOCK_RAW == sock->type) { |
188 | inet->num = protocol; | 190 | inet->inet_num = protocol; |
189 | if (IPPROTO_RAW == protocol) | 191 | if (IPPROTO_RAW == protocol) |
190 | inet->hdrincl = 1; | 192 | inet->hdrincl = 1; |
191 | } | 193 | } |
@@ -198,7 +200,7 @@ lookup_protocol: | |||
198 | 200 | ||
199 | inet_sk(sk)->pinet6 = np = inet6_sk_generic(sk); | 201 | inet_sk(sk)->pinet6 = np = inet6_sk_generic(sk); |
200 | np->hop_limit = -1; | 202 | np->hop_limit = -1; |
201 | np->mcast_hops = -1; | 203 | np->mcast_hops = IPV6_DEFAULT_MCASTHOPS; |
202 | np->mc_loop = 1; | 204 | np->mc_loop = 1; |
203 | np->pmtudisc = IPV6_PMTUDISC_WANT; | 205 | np->pmtudisc = IPV6_PMTUDISC_WANT; |
204 | np->ipv6only = net->ipv6.sysctl.bindv6only; | 206 | np->ipv6only = net->ipv6.sysctl.bindv6only; |
@@ -228,12 +230,12 @@ lookup_protocol: | |||
228 | */ | 230 | */ |
229 | sk_refcnt_debug_inc(sk); | 231 | sk_refcnt_debug_inc(sk); |
230 | 232 | ||
231 | if (inet->num) { | 233 | if (inet->inet_num) { |
232 | /* It assumes that any protocol which allows | 234 | /* It assumes that any protocol which allows |
233 | * the user to assign a number at socket | 235 | * the user to assign a number at socket |
234 | * creation time automatically shares. | 236 | * creation time automatically shares. |
235 | */ | 237 | */ |
236 | inet->sport = htons(inet->num); | 238 | inet->inet_sport = htons(inet->inet_num); |
237 | sk->sk_prot->hash(sk); | 239 | sk->sk_prot->hash(sk); |
238 | } | 240 | } |
239 | if (sk->sk_prot->init) { | 241 | if (sk->sk_prot->init) { |
@@ -281,7 +283,7 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) | |||
281 | lock_sock(sk); | 283 | lock_sock(sk); |
282 | 284 | ||
283 | /* Check these errors (active socket, double bind). */ | 285 | /* Check these errors (active socket, double bind). */ |
284 | if (sk->sk_state != TCP_CLOSE || inet->num) { | 286 | if (sk->sk_state != TCP_CLOSE || inet->inet_num) { |
285 | err = -EINVAL; | 287 | err = -EINVAL; |
286 | goto out; | 288 | goto out; |
287 | } | 289 | } |
@@ -314,6 +316,7 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) | |||
314 | if (addr_type != IPV6_ADDR_ANY) { | 316 | if (addr_type != IPV6_ADDR_ANY) { |
315 | struct net_device *dev = NULL; | 317 | struct net_device *dev = NULL; |
316 | 318 | ||
319 | rcu_read_lock(); | ||
317 | if (addr_type & IPV6_ADDR_LINKLOCAL) { | 320 | if (addr_type & IPV6_ADDR_LINKLOCAL) { |
318 | if (addr_len >= sizeof(struct sockaddr_in6) && | 321 | if (addr_len >= sizeof(struct sockaddr_in6) && |
319 | addr->sin6_scope_id) { | 322 | addr->sin6_scope_id) { |
@@ -326,12 +329,12 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) | |||
326 | /* Binding to link-local address requires an interface */ | 329 | /* Binding to link-local address requires an interface */ |
327 | if (!sk->sk_bound_dev_if) { | 330 | if (!sk->sk_bound_dev_if) { |
328 | err = -EINVAL; | 331 | err = -EINVAL; |
329 | goto out; | 332 | goto out_unlock; |
330 | } | 333 | } |
331 | dev = dev_get_by_index(net, sk->sk_bound_dev_if); | 334 | dev = dev_get_by_index_rcu(net, sk->sk_bound_dev_if); |
332 | if (!dev) { | 335 | if (!dev) { |
333 | err = -ENODEV; | 336 | err = -ENODEV; |
334 | goto out; | 337 | goto out_unlock; |
335 | } | 338 | } |
336 | } | 339 | } |
337 | 340 | ||
@@ -342,19 +345,16 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) | |||
342 | if (!(addr_type & IPV6_ADDR_MULTICAST)) { | 345 | if (!(addr_type & IPV6_ADDR_MULTICAST)) { |
343 | if (!ipv6_chk_addr(net, &addr->sin6_addr, | 346 | if (!ipv6_chk_addr(net, &addr->sin6_addr, |
344 | dev, 0)) { | 347 | dev, 0)) { |
345 | if (dev) | ||
346 | dev_put(dev); | ||
347 | err = -EADDRNOTAVAIL; | 348 | err = -EADDRNOTAVAIL; |
348 | goto out; | 349 | goto out_unlock; |
349 | } | 350 | } |
350 | } | 351 | } |
351 | if (dev) | 352 | rcu_read_unlock(); |
352 | dev_put(dev); | ||
353 | } | 353 | } |
354 | } | 354 | } |
355 | 355 | ||
356 | inet->rcv_saddr = v4addr; | 356 | inet->inet_rcv_saddr = v4addr; |
357 | inet->saddr = v4addr; | 357 | inet->inet_saddr = v4addr; |
358 | 358 | ||
359 | ipv6_addr_copy(&np->rcv_saddr, &addr->sin6_addr); | 359 | ipv6_addr_copy(&np->rcv_saddr, &addr->sin6_addr); |
360 | 360 | ||
@@ -375,12 +375,15 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) | |||
375 | } | 375 | } |
376 | if (snum) | 376 | if (snum) |
377 | sk->sk_userlocks |= SOCK_BINDPORT_LOCK; | 377 | sk->sk_userlocks |= SOCK_BINDPORT_LOCK; |
378 | inet->sport = htons(inet->num); | 378 | inet->inet_sport = htons(inet->inet_num); |
379 | inet->dport = 0; | 379 | inet->inet_dport = 0; |
380 | inet->daddr = 0; | 380 | inet->inet_daddr = 0; |
381 | out: | 381 | out: |
382 | release_sock(sk); | 382 | release_sock(sk); |
383 | return err; | 383 | return err; |
384 | out_unlock: | ||
385 | rcu_read_unlock(); | ||
386 | goto out; | ||
384 | } | 387 | } |
385 | 388 | ||
386 | EXPORT_SYMBOL(inet6_bind); | 389 | EXPORT_SYMBOL(inet6_bind); |
@@ -441,12 +444,12 @@ int inet6_getname(struct socket *sock, struct sockaddr *uaddr, | |||
441 | sin->sin6_flowinfo = 0; | 444 | sin->sin6_flowinfo = 0; |
442 | sin->sin6_scope_id = 0; | 445 | sin->sin6_scope_id = 0; |
443 | if (peer) { | 446 | if (peer) { |
444 | if (!inet->dport) | 447 | if (!inet->inet_dport) |
445 | return -ENOTCONN; | 448 | return -ENOTCONN; |
446 | if (((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_SYN_SENT)) && | 449 | if (((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_SYN_SENT)) && |
447 | peer == 1) | 450 | peer == 1) |
448 | return -ENOTCONN; | 451 | return -ENOTCONN; |
449 | sin->sin6_port = inet->dport; | 452 | sin->sin6_port = inet->inet_dport; |
450 | ipv6_addr_copy(&sin->sin6_addr, &np->daddr); | 453 | ipv6_addr_copy(&sin->sin6_addr, &np->daddr); |
451 | if (np->sndflow) | 454 | if (np->sndflow) |
452 | sin->sin6_flowinfo = np->flow_label; | 455 | sin->sin6_flowinfo = np->flow_label; |
@@ -456,7 +459,7 @@ int inet6_getname(struct socket *sock, struct sockaddr *uaddr, | |||
456 | else | 459 | else |
457 | ipv6_addr_copy(&sin->sin6_addr, &np->rcv_saddr); | 460 | ipv6_addr_copy(&sin->sin6_addr, &np->rcv_saddr); |
458 | 461 | ||
459 | sin->sin6_port = inet->sport; | 462 | sin->sin6_port = inet->inet_sport; |
460 | } | 463 | } |
461 | if (ipv6_addr_type(&sin->sin6_addr) & IPV6_ADDR_LINKLOCAL) | 464 | if (ipv6_addr_type(&sin->sin6_addr) & IPV6_ADDR_LINKLOCAL) |
462 | sin->sin6_scope_id = sk->sk_bound_dev_if; | 465 | sin->sin6_scope_id = sk->sk_bound_dev_if; |
@@ -552,7 +555,7 @@ const struct proto_ops inet6_dgram_ops = { | |||
552 | #endif | 555 | #endif |
553 | }; | 556 | }; |
554 | 557 | ||
555 | static struct net_proto_family inet6_family_ops = { | 558 | static const struct net_proto_family inet6_family_ops = { |
556 | .family = PF_INET6, | 559 | .family = PF_INET6, |
557 | .create = inet6_create, | 560 | .create = inet6_create, |
558 | .owner = THIS_MODULE, | 561 | .owner = THIS_MODULE, |
@@ -654,8 +657,9 @@ int inet6_sk_rebuild_header(struct sock *sk) | |||
654 | ipv6_addr_copy(&fl.fl6_src, &np->saddr); | 657 | ipv6_addr_copy(&fl.fl6_src, &np->saddr); |
655 | fl.fl6_flowlabel = np->flow_label; | 658 | fl.fl6_flowlabel = np->flow_label; |
656 | fl.oif = sk->sk_bound_dev_if; | 659 | fl.oif = sk->sk_bound_dev_if; |
657 | fl.fl_ip_dport = inet->dport; | 660 | fl.mark = sk->sk_mark; |
658 | fl.fl_ip_sport = inet->sport; | 661 | fl.fl_ip_dport = inet->inet_dport; |
662 | fl.fl_ip_sport = inet->inet_sport; | ||
659 | security_sk_classify_flow(sk, &fl); | 663 | security_sk_classify_flow(sk, &fl); |
660 | 664 | ||
661 | if (np->opt && np->opt->srcrt) { | 665 | if (np->opt && np->opt->srcrt) { |
@@ -968,41 +972,41 @@ static void ipv6_packet_cleanup(void) | |||
968 | 972 | ||
969 | static int __net_init ipv6_init_mibs(struct net *net) | 973 | static int __net_init ipv6_init_mibs(struct net *net) |
970 | { | 974 | { |
971 | if (snmp_mib_init((void **)net->mib.udp_stats_in6, | 975 | if (snmp_mib_init((void __percpu **)net->mib.udp_stats_in6, |
972 | sizeof (struct udp_mib)) < 0) | 976 | sizeof (struct udp_mib)) < 0) |
973 | return -ENOMEM; | 977 | return -ENOMEM; |
974 | if (snmp_mib_init((void **)net->mib.udplite_stats_in6, | 978 | if (snmp_mib_init((void __percpu **)net->mib.udplite_stats_in6, |
975 | sizeof (struct udp_mib)) < 0) | 979 | sizeof (struct udp_mib)) < 0) |
976 | goto err_udplite_mib; | 980 | goto err_udplite_mib; |
977 | if (snmp_mib_init((void **)net->mib.ipv6_statistics, | 981 | if (snmp_mib_init((void __percpu **)net->mib.ipv6_statistics, |
978 | sizeof(struct ipstats_mib)) < 0) | 982 | sizeof(struct ipstats_mib)) < 0) |
979 | goto err_ip_mib; | 983 | goto err_ip_mib; |
980 | if (snmp_mib_init((void **)net->mib.icmpv6_statistics, | 984 | if (snmp_mib_init((void __percpu **)net->mib.icmpv6_statistics, |
981 | sizeof(struct icmpv6_mib)) < 0) | 985 | sizeof(struct icmpv6_mib)) < 0) |
982 | goto err_icmp_mib; | 986 | goto err_icmp_mib; |
983 | if (snmp_mib_init((void **)net->mib.icmpv6msg_statistics, | 987 | if (snmp_mib_init((void __percpu **)net->mib.icmpv6msg_statistics, |
984 | sizeof(struct icmpv6msg_mib)) < 0) | 988 | sizeof(struct icmpv6msg_mib)) < 0) |
985 | goto err_icmpmsg_mib; | 989 | goto err_icmpmsg_mib; |
986 | return 0; | 990 | return 0; |
987 | 991 | ||
988 | err_icmpmsg_mib: | 992 | err_icmpmsg_mib: |
989 | snmp_mib_free((void **)net->mib.icmpv6_statistics); | 993 | snmp_mib_free((void __percpu **)net->mib.icmpv6_statistics); |
990 | err_icmp_mib: | 994 | err_icmp_mib: |
991 | snmp_mib_free((void **)net->mib.ipv6_statistics); | 995 | snmp_mib_free((void __percpu **)net->mib.ipv6_statistics); |
992 | err_ip_mib: | 996 | err_ip_mib: |
993 | snmp_mib_free((void **)net->mib.udplite_stats_in6); | 997 | snmp_mib_free((void __percpu **)net->mib.udplite_stats_in6); |
994 | err_udplite_mib: | 998 | err_udplite_mib: |
995 | snmp_mib_free((void **)net->mib.udp_stats_in6); | 999 | snmp_mib_free((void __percpu **)net->mib.udp_stats_in6); |
996 | return -ENOMEM; | 1000 | return -ENOMEM; |
997 | } | 1001 | } |
998 | 1002 | ||
999 | static void __net_exit ipv6_cleanup_mibs(struct net *net) | 1003 | static void ipv6_cleanup_mibs(struct net *net) |
1000 | { | 1004 | { |
1001 | snmp_mib_free((void **)net->mib.udp_stats_in6); | 1005 | snmp_mib_free((void __percpu **)net->mib.udp_stats_in6); |
1002 | snmp_mib_free((void **)net->mib.udplite_stats_in6); | 1006 | snmp_mib_free((void __percpu **)net->mib.udplite_stats_in6); |
1003 | snmp_mib_free((void **)net->mib.ipv6_statistics); | 1007 | snmp_mib_free((void __percpu **)net->mib.ipv6_statistics); |
1004 | snmp_mib_free((void **)net->mib.icmpv6_statistics); | 1008 | snmp_mib_free((void __percpu **)net->mib.icmpv6_statistics); |
1005 | snmp_mib_free((void **)net->mib.icmpv6msg_statistics); | 1009 | snmp_mib_free((void __percpu **)net->mib.icmpv6msg_statistics); |
1006 | } | 1010 | } |
1007 | 1011 | ||
1008 | static int __net_init inet6_net_init(struct net *net) | 1012 | static int __net_init inet6_net_init(struct net *net) |
@@ -1039,7 +1043,7 @@ out: | |||
1039 | #endif | 1043 | #endif |
1040 | } | 1044 | } |
1041 | 1045 | ||
1042 | static void inet6_net_exit(struct net *net) | 1046 | static void __net_exit inet6_net_exit(struct net *net) |
1043 | { | 1047 | { |
1044 | #ifdef CONFIG_PROC_FS | 1048 | #ifdef CONFIG_PROC_FS |
1045 | udp6_proc_exit(net); | 1049 | udp6_proc_exit(net); |
diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c index c1589e2f1dc9..ee82d4ef26ce 100644 --- a/net/ipv6/ah6.c +++ b/net/ipv6/ah6.c | |||
@@ -24,18 +24,93 @@ | |||
24 | * This file is derived from net/ipv4/ah.c. | 24 | * This file is derived from net/ipv4/ah.c. |
25 | */ | 25 | */ |
26 | 26 | ||
27 | #include <crypto/hash.h> | ||
27 | #include <linux/module.h> | 28 | #include <linux/module.h> |
29 | #include <linux/slab.h> | ||
28 | #include <net/ip.h> | 30 | #include <net/ip.h> |
29 | #include <net/ah.h> | 31 | #include <net/ah.h> |
30 | #include <linux/crypto.h> | 32 | #include <linux/crypto.h> |
31 | #include <linux/pfkeyv2.h> | 33 | #include <linux/pfkeyv2.h> |
32 | #include <linux/spinlock.h> | ||
33 | #include <linux/string.h> | 34 | #include <linux/string.h> |
35 | #include <linux/scatterlist.h> | ||
34 | #include <net/icmp.h> | 36 | #include <net/icmp.h> |
35 | #include <net/ipv6.h> | 37 | #include <net/ipv6.h> |
36 | #include <net/protocol.h> | 38 | #include <net/protocol.h> |
37 | #include <net/xfrm.h> | 39 | #include <net/xfrm.h> |
38 | 40 | ||
41 | #define IPV6HDR_BASELEN 8 | ||
42 | |||
43 | struct tmp_ext { | ||
44 | #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) | ||
45 | struct in6_addr saddr; | ||
46 | #endif | ||
47 | struct in6_addr daddr; | ||
48 | char hdrs[0]; | ||
49 | }; | ||
50 | |||
51 | struct ah_skb_cb { | ||
52 | struct xfrm_skb_cb xfrm; | ||
53 | void *tmp; | ||
54 | }; | ||
55 | |||
56 | #define AH_SKB_CB(__skb) ((struct ah_skb_cb *)&((__skb)->cb[0])) | ||
57 | |||
58 | static void *ah_alloc_tmp(struct crypto_ahash *ahash, int nfrags, | ||
59 | unsigned int size) | ||
60 | { | ||
61 | unsigned int len; | ||
62 | |||
63 | len = size + crypto_ahash_digestsize(ahash) + | ||
64 | (crypto_ahash_alignmask(ahash) & | ||
65 | ~(crypto_tfm_ctx_alignment() - 1)); | ||
66 | |||
67 | len = ALIGN(len, crypto_tfm_ctx_alignment()); | ||
68 | |||
69 | len += sizeof(struct ahash_request) + crypto_ahash_reqsize(ahash); | ||
70 | len = ALIGN(len, __alignof__(struct scatterlist)); | ||
71 | |||
72 | len += sizeof(struct scatterlist) * nfrags; | ||
73 | |||
74 | return kmalloc(len, GFP_ATOMIC); | ||
75 | } | ||
76 | |||
77 | static inline struct tmp_ext *ah_tmp_ext(void *base) | ||
78 | { | ||
79 | return base + IPV6HDR_BASELEN; | ||
80 | } | ||
81 | |||
82 | static inline u8 *ah_tmp_auth(u8 *tmp, unsigned int offset) | ||
83 | { | ||
84 | return tmp + offset; | ||
85 | } | ||
86 | |||
87 | static inline u8 *ah_tmp_icv(struct crypto_ahash *ahash, void *tmp, | ||
88 | unsigned int offset) | ||
89 | { | ||
90 | return PTR_ALIGN((u8 *)tmp + offset, crypto_ahash_alignmask(ahash) + 1); | ||
91 | } | ||
92 | |||
93 | static inline struct ahash_request *ah_tmp_req(struct crypto_ahash *ahash, | ||
94 | u8 *icv) | ||
95 | { | ||
96 | struct ahash_request *req; | ||
97 | |||
98 | req = (void *)PTR_ALIGN(icv + crypto_ahash_digestsize(ahash), | ||
99 | crypto_tfm_ctx_alignment()); | ||
100 | |||
101 | ahash_request_set_tfm(req, ahash); | ||
102 | |||
103 | return req; | ||
104 | } | ||
105 | |||
106 | static inline struct scatterlist *ah_req_sg(struct crypto_ahash *ahash, | ||
107 | struct ahash_request *req) | ||
108 | { | ||
109 | return (void *)ALIGN((unsigned long)(req + 1) + | ||
110 | crypto_ahash_reqsize(ahash), | ||
111 | __alignof__(struct scatterlist)); | ||
112 | } | ||
113 | |||
39 | static int zero_out_mutable_opts(struct ipv6_opt_hdr *opthdr) | 114 | static int zero_out_mutable_opts(struct ipv6_opt_hdr *opthdr) |
40 | { | 115 | { |
41 | u8 *opt = (u8 *)opthdr; | 116 | u8 *opt = (u8 *)opthdr; |
@@ -218,24 +293,85 @@ static int ipv6_clear_mutable_options(struct ipv6hdr *iph, int len, int dir) | |||
218 | return 0; | 293 | return 0; |
219 | } | 294 | } |
220 | 295 | ||
296 | static void ah6_output_done(struct crypto_async_request *base, int err) | ||
297 | { | ||
298 | int extlen; | ||
299 | u8 *iph_base; | ||
300 | u8 *icv; | ||
301 | struct sk_buff *skb = base->data; | ||
302 | struct xfrm_state *x = skb_dst(skb)->xfrm; | ||
303 | struct ah_data *ahp = x->data; | ||
304 | struct ipv6hdr *top_iph = ipv6_hdr(skb); | ||
305 | struct ip_auth_hdr *ah = ip_auth_hdr(skb); | ||
306 | struct tmp_ext *iph_ext; | ||
307 | |||
308 | extlen = skb_network_header_len(skb) - sizeof(struct ipv6hdr); | ||
309 | if (extlen) | ||
310 | extlen += sizeof(*iph_ext); | ||
311 | |||
312 | iph_base = AH_SKB_CB(skb)->tmp; | ||
313 | iph_ext = ah_tmp_ext(iph_base); | ||
314 | icv = ah_tmp_icv(ahp->ahash, iph_ext, extlen); | ||
315 | |||
316 | memcpy(ah->auth_data, icv, ahp->icv_trunc_len); | ||
317 | memcpy(top_iph, iph_base, IPV6HDR_BASELEN); | ||
318 | |||
319 | if (extlen) { | ||
320 | #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) | ||
321 | memcpy(&top_iph->saddr, iph_ext, extlen); | ||
322 | #else | ||
323 | memcpy(&top_iph->daddr, iph_ext, extlen); | ||
324 | #endif | ||
325 | } | ||
326 | |||
327 | err = ah->nexthdr; | ||
328 | |||
329 | kfree(AH_SKB_CB(skb)->tmp); | ||
330 | xfrm_output_resume(skb, err); | ||
331 | } | ||
332 | |||
221 | static int ah6_output(struct xfrm_state *x, struct sk_buff *skb) | 333 | static int ah6_output(struct xfrm_state *x, struct sk_buff *skb) |
222 | { | 334 | { |
223 | int err; | 335 | int err; |
336 | int nfrags; | ||
224 | int extlen; | 337 | int extlen; |
338 | u8 *iph_base; | ||
339 | u8 *icv; | ||
340 | u8 nexthdr; | ||
341 | struct sk_buff *trailer; | ||
342 | struct crypto_ahash *ahash; | ||
343 | struct ahash_request *req; | ||
344 | struct scatterlist *sg; | ||
225 | struct ipv6hdr *top_iph; | 345 | struct ipv6hdr *top_iph; |
226 | struct ip_auth_hdr *ah; | 346 | struct ip_auth_hdr *ah; |
227 | struct ah_data *ahp; | 347 | struct ah_data *ahp; |
228 | u8 nexthdr; | 348 | struct tmp_ext *iph_ext; |
229 | char tmp_base[8]; | 349 | |
230 | struct { | 350 | ahp = x->data; |
231 | #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) | 351 | ahash = ahp->ahash; |
232 | struct in6_addr saddr; | 352 | |
233 | #endif | 353 | if ((err = skb_cow_data(skb, 0, &trailer)) < 0) |
234 | struct in6_addr daddr; | 354 | goto out; |
235 | char hdrs[0]; | 355 | nfrags = err; |
236 | } *tmp_ext; | ||
237 | 356 | ||
238 | skb_push(skb, -skb_network_offset(skb)); | 357 | skb_push(skb, -skb_network_offset(skb)); |
358 | extlen = skb_network_header_len(skb) - sizeof(struct ipv6hdr); | ||
359 | if (extlen) | ||
360 | extlen += sizeof(*iph_ext); | ||
361 | |||
362 | err = -ENOMEM; | ||
363 | iph_base = ah_alloc_tmp(ahash, nfrags, IPV6HDR_BASELEN + extlen); | ||
364 | if (!iph_base) | ||
365 | goto out; | ||
366 | |||
367 | iph_ext = ah_tmp_ext(iph_base); | ||
368 | icv = ah_tmp_icv(ahash, iph_ext, extlen); | ||
369 | req = ah_tmp_req(ahash, icv); | ||
370 | sg = ah_req_sg(ahash, req); | ||
371 | |||
372 | ah = ip_auth_hdr(skb); | ||
373 | memset(ah->auth_data, 0, ahp->icv_trunc_len); | ||
374 | |||
239 | top_iph = ipv6_hdr(skb); | 375 | top_iph = ipv6_hdr(skb); |
240 | top_iph->payload_len = htons(skb->len - sizeof(*top_iph)); | 376 | top_iph->payload_len = htons(skb->len - sizeof(*top_iph)); |
241 | 377 | ||
@@ -245,31 +381,22 @@ static int ah6_output(struct xfrm_state *x, struct sk_buff *skb) | |||
245 | /* When there are no extension headers, we only need to save the first | 381 | /* When there are no extension headers, we only need to save the first |
246 | * 8 bytes of the base IP header. | 382 | * 8 bytes of the base IP header. |
247 | */ | 383 | */ |
248 | memcpy(tmp_base, top_iph, sizeof(tmp_base)); | 384 | memcpy(iph_base, top_iph, IPV6HDR_BASELEN); |
249 | 385 | ||
250 | tmp_ext = NULL; | ||
251 | extlen = skb_transport_offset(skb) - sizeof(struct ipv6hdr); | ||
252 | if (extlen) { | 386 | if (extlen) { |
253 | extlen += sizeof(*tmp_ext); | ||
254 | tmp_ext = kmalloc(extlen, GFP_ATOMIC); | ||
255 | if (!tmp_ext) { | ||
256 | err = -ENOMEM; | ||
257 | goto error; | ||
258 | } | ||
259 | #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) | 387 | #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) |
260 | memcpy(tmp_ext, &top_iph->saddr, extlen); | 388 | memcpy(iph_ext, &top_iph->saddr, extlen); |
261 | #else | 389 | #else |
262 | memcpy(tmp_ext, &top_iph->daddr, extlen); | 390 | memcpy(iph_ext, &top_iph->daddr, extlen); |
263 | #endif | 391 | #endif |
264 | err = ipv6_clear_mutable_options(top_iph, | 392 | err = ipv6_clear_mutable_options(top_iph, |
265 | extlen - sizeof(*tmp_ext) + | 393 | extlen - sizeof(*iph_ext) + |
266 | sizeof(*top_iph), | 394 | sizeof(*top_iph), |
267 | XFRM_POLICY_OUT); | 395 | XFRM_POLICY_OUT); |
268 | if (err) | 396 | if (err) |
269 | goto error_free_iph; | 397 | goto out_free; |
270 | } | 398 | } |
271 | 399 | ||
272 | ah = ip_auth_hdr(skb); | ||
273 | ah->nexthdr = nexthdr; | 400 | ah->nexthdr = nexthdr; |
274 | 401 | ||
275 | top_iph->priority = 0; | 402 | top_iph->priority = 0; |
@@ -278,36 +405,80 @@ static int ah6_output(struct xfrm_state *x, struct sk_buff *skb) | |||
278 | top_iph->flow_lbl[2] = 0; | 405 | top_iph->flow_lbl[2] = 0; |
279 | top_iph->hop_limit = 0; | 406 | top_iph->hop_limit = 0; |
280 | 407 | ||
281 | ahp = x->data; | ||
282 | ah->hdrlen = (XFRM_ALIGN8(sizeof(*ah) + ahp->icv_trunc_len) >> 2) - 2; | 408 | ah->hdrlen = (XFRM_ALIGN8(sizeof(*ah) + ahp->icv_trunc_len) >> 2) - 2; |
283 | 409 | ||
284 | ah->reserved = 0; | 410 | ah->reserved = 0; |
285 | ah->spi = x->id.spi; | 411 | ah->spi = x->id.spi; |
286 | ah->seq_no = htonl(XFRM_SKB_CB(skb)->seq.output); | 412 | ah->seq_no = htonl(XFRM_SKB_CB(skb)->seq.output); |
287 | 413 | ||
288 | spin_lock_bh(&x->lock); | 414 | sg_init_table(sg, nfrags); |
289 | err = ah_mac_digest(ahp, skb, ah->auth_data); | 415 | skb_to_sgvec(skb, sg, 0, skb->len); |
290 | memcpy(ah->auth_data, ahp->work_icv, ahp->icv_trunc_len); | ||
291 | spin_unlock_bh(&x->lock); | ||
292 | 416 | ||
293 | if (err) | 417 | ahash_request_set_crypt(req, sg, icv, skb->len); |
294 | goto error_free_iph; | 418 | ahash_request_set_callback(req, 0, ah6_output_done, skb); |
419 | |||
420 | AH_SKB_CB(skb)->tmp = iph_base; | ||
295 | 421 | ||
296 | memcpy(top_iph, tmp_base, sizeof(tmp_base)); | 422 | err = crypto_ahash_digest(req); |
297 | if (tmp_ext) { | 423 | if (err) { |
424 | if (err == -EINPROGRESS) | ||
425 | goto out; | ||
426 | |||
427 | if (err == -EBUSY) | ||
428 | err = NET_XMIT_DROP; | ||
429 | goto out_free; | ||
430 | } | ||
431 | |||
432 | memcpy(ah->auth_data, icv, ahp->icv_trunc_len); | ||
433 | memcpy(top_iph, iph_base, IPV6HDR_BASELEN); | ||
434 | |||
435 | if (extlen) { | ||
298 | #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) | 436 | #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) |
299 | memcpy(&top_iph->saddr, tmp_ext, extlen); | 437 | memcpy(&top_iph->saddr, iph_ext, extlen); |
300 | #else | 438 | #else |
301 | memcpy(&top_iph->daddr, tmp_ext, extlen); | 439 | memcpy(&top_iph->daddr, iph_ext, extlen); |
302 | #endif | 440 | #endif |
303 | error_free_iph: | ||
304 | kfree(tmp_ext); | ||
305 | } | 441 | } |
306 | 442 | ||
307 | error: | 443 | out_free: |
444 | kfree(iph_base); | ||
445 | out: | ||
308 | return err; | 446 | return err; |
309 | } | 447 | } |
310 | 448 | ||
449 | static void ah6_input_done(struct crypto_async_request *base, int err) | ||
450 | { | ||
451 | u8 *auth_data; | ||
452 | u8 *icv; | ||
453 | u8 *work_iph; | ||
454 | struct sk_buff *skb = base->data; | ||
455 | struct xfrm_state *x = xfrm_input_state(skb); | ||
456 | struct ah_data *ahp = x->data; | ||
457 | struct ip_auth_hdr *ah = ip_auth_hdr(skb); | ||
458 | int hdr_len = skb_network_header_len(skb); | ||
459 | int ah_hlen = (ah->hdrlen + 2) << 2; | ||
460 | |||
461 | work_iph = AH_SKB_CB(skb)->tmp; | ||
462 | auth_data = ah_tmp_auth(work_iph, hdr_len); | ||
463 | icv = ah_tmp_icv(ahp->ahash, auth_data, ahp->icv_trunc_len); | ||
464 | |||
465 | err = memcmp(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG: 0; | ||
466 | if (err) | ||
467 | goto out; | ||
468 | |||
469 | skb->network_header += ah_hlen; | ||
470 | memcpy(skb_network_header(skb), work_iph, hdr_len); | ||
471 | __skb_pull(skb, ah_hlen + hdr_len); | ||
472 | skb_set_transport_header(skb, -hdr_len); | ||
473 | |||
474 | err = ah->nexthdr; | ||
475 | out: | ||
476 | kfree(AH_SKB_CB(skb)->tmp); | ||
477 | xfrm_input_resume(skb, err); | ||
478 | } | ||
479 | |||
480 | |||
481 | |||
311 | static int ah6_input(struct xfrm_state *x, struct sk_buff *skb) | 482 | static int ah6_input(struct xfrm_state *x, struct sk_buff *skb) |
312 | { | 483 | { |
313 | /* | 484 | /* |
@@ -325,14 +496,21 @@ static int ah6_input(struct xfrm_state *x, struct sk_buff *skb) | |||
325 | * There is offset of AH before IPv6 header after the process. | 496 | * There is offset of AH before IPv6 header after the process. |
326 | */ | 497 | */ |
327 | 498 | ||
499 | u8 *auth_data; | ||
500 | u8 *icv; | ||
501 | u8 *work_iph; | ||
502 | struct sk_buff *trailer; | ||
503 | struct crypto_ahash *ahash; | ||
504 | struct ahash_request *req; | ||
505 | struct scatterlist *sg; | ||
328 | struct ip_auth_hdr *ah; | 506 | struct ip_auth_hdr *ah; |
329 | struct ipv6hdr *ip6h; | 507 | struct ipv6hdr *ip6h; |
330 | struct ah_data *ahp; | 508 | struct ah_data *ahp; |
331 | unsigned char *tmp_hdr = NULL; | ||
332 | u16 hdr_len; | 509 | u16 hdr_len; |
333 | u16 ah_hlen; | 510 | u16 ah_hlen; |
334 | int nexthdr; | 511 | int nexthdr; |
335 | int err = -EINVAL; | 512 | int nfrags; |
513 | int err = -ENOMEM; | ||
336 | 514 | ||
337 | if (!pskb_may_pull(skb, sizeof(struct ip_auth_hdr))) | 515 | if (!pskb_may_pull(skb, sizeof(struct ip_auth_hdr))) |
338 | goto out; | 516 | goto out; |
@@ -345,9 +523,11 @@ static int ah6_input(struct xfrm_state *x, struct sk_buff *skb) | |||
345 | 523 | ||
346 | skb->ip_summed = CHECKSUM_NONE; | 524 | skb->ip_summed = CHECKSUM_NONE; |
347 | 525 | ||
348 | hdr_len = skb->data - skb_network_header(skb); | 526 | hdr_len = skb_network_header_len(skb); |
349 | ah = (struct ip_auth_hdr *)skb->data; | 527 | ah = (struct ip_auth_hdr *)skb->data; |
350 | ahp = x->data; | 528 | ahp = x->data; |
529 | ahash = ahp->ahash; | ||
530 | |||
351 | nexthdr = ah->nexthdr; | 531 | nexthdr = ah->nexthdr; |
352 | ah_hlen = (ah->hdrlen + 2) << 2; | 532 | ah_hlen = (ah->hdrlen + 2) << 2; |
353 | 533 | ||
@@ -358,48 +538,67 @@ static int ah6_input(struct xfrm_state *x, struct sk_buff *skb) | |||
358 | if (!pskb_may_pull(skb, ah_hlen)) | 538 | if (!pskb_may_pull(skb, ah_hlen)) |
359 | goto out; | 539 | goto out; |
360 | 540 | ||
361 | tmp_hdr = kmemdup(skb_network_header(skb), hdr_len, GFP_ATOMIC); | ||
362 | if (!tmp_hdr) | ||
363 | goto out; | ||
364 | ip6h = ipv6_hdr(skb); | 541 | ip6h = ipv6_hdr(skb); |
542 | |||
543 | skb_push(skb, hdr_len); | ||
544 | |||
545 | if ((err = skb_cow_data(skb, 0, &trailer)) < 0) | ||
546 | goto out; | ||
547 | nfrags = err; | ||
548 | |||
549 | work_iph = ah_alloc_tmp(ahash, nfrags, hdr_len + ahp->icv_trunc_len); | ||
550 | if (!work_iph) | ||
551 | goto out; | ||
552 | |||
553 | auth_data = ah_tmp_auth(work_iph, hdr_len); | ||
554 | icv = ah_tmp_icv(ahash, auth_data, ahp->icv_trunc_len); | ||
555 | req = ah_tmp_req(ahash, icv); | ||
556 | sg = ah_req_sg(ahash, req); | ||
557 | |||
558 | memcpy(work_iph, ip6h, hdr_len); | ||
559 | memcpy(auth_data, ah->auth_data, ahp->icv_trunc_len); | ||
560 | memset(ah->auth_data, 0, ahp->icv_trunc_len); | ||
561 | |||
365 | if (ipv6_clear_mutable_options(ip6h, hdr_len, XFRM_POLICY_IN)) | 562 | if (ipv6_clear_mutable_options(ip6h, hdr_len, XFRM_POLICY_IN)) |
366 | goto free_out; | 563 | goto out_free; |
564 | |||
367 | ip6h->priority = 0; | 565 | ip6h->priority = 0; |
368 | ip6h->flow_lbl[0] = 0; | 566 | ip6h->flow_lbl[0] = 0; |
369 | ip6h->flow_lbl[1] = 0; | 567 | ip6h->flow_lbl[1] = 0; |
370 | ip6h->flow_lbl[2] = 0; | 568 | ip6h->flow_lbl[2] = 0; |
371 | ip6h->hop_limit = 0; | 569 | ip6h->hop_limit = 0; |
372 | 570 | ||
373 | spin_lock(&x->lock); | 571 | sg_init_table(sg, nfrags); |
374 | { | 572 | skb_to_sgvec(skb, sg, 0, skb->len); |
375 | u8 auth_data[MAX_AH_AUTH_LEN]; | ||
376 | 573 | ||
377 | memcpy(auth_data, ah->auth_data, ahp->icv_trunc_len); | 574 | ahash_request_set_crypt(req, sg, icv, skb->len); |
378 | memset(ah->auth_data, 0, ahp->icv_trunc_len); | 575 | ahash_request_set_callback(req, 0, ah6_input_done, skb); |
379 | skb_push(skb, hdr_len); | 576 | |
380 | err = ah_mac_digest(ahp, skb, ah->auth_data); | 577 | AH_SKB_CB(skb)->tmp = work_iph; |
381 | if (err) | 578 | |
382 | goto unlock; | 579 | err = crypto_ahash_digest(req); |
383 | if (memcmp(ahp->work_icv, auth_data, ahp->icv_trunc_len)) | 580 | if (err) { |
384 | err = -EBADMSG; | 581 | if (err == -EINPROGRESS) |
582 | goto out; | ||
583 | |||
584 | if (err == -EBUSY) | ||
585 | err = NET_XMIT_DROP; | ||
586 | goto out_free; | ||
385 | } | 587 | } |
386 | unlock: | ||
387 | spin_unlock(&x->lock); | ||
388 | 588 | ||
589 | err = memcmp(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG: 0; | ||
389 | if (err) | 590 | if (err) |
390 | goto free_out; | 591 | goto out_free; |
391 | 592 | ||
392 | skb->network_header += ah_hlen; | 593 | skb->network_header += ah_hlen; |
393 | memcpy(skb_network_header(skb), tmp_hdr, hdr_len); | 594 | memcpy(skb_network_header(skb), work_iph, hdr_len); |
394 | skb->transport_header = skb->network_header; | 595 | skb->transport_header = skb->network_header; |
395 | __skb_pull(skb, ah_hlen + hdr_len); | 596 | __skb_pull(skb, ah_hlen + hdr_len); |
396 | 597 | ||
397 | kfree(tmp_hdr); | 598 | err = nexthdr; |
398 | 599 | ||
399 | return nexthdr; | 600 | out_free: |
400 | 601 | kfree(work_iph); | |
401 | free_out: | ||
402 | kfree(tmp_hdr); | ||
403 | out: | 602 | out: |
404 | return err; | 603 | return err; |
405 | } | 604 | } |
@@ -416,7 +615,7 @@ static void ah6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
416 | type != ICMPV6_PKT_TOOBIG) | 615 | type != ICMPV6_PKT_TOOBIG) |
417 | return; | 616 | return; |
418 | 617 | ||
419 | x = xfrm_state_lookup(net, (xfrm_address_t *)&iph->daddr, ah->spi, IPPROTO_AH, AF_INET6); | 618 | x = xfrm_state_lookup(net, skb->mark, (xfrm_address_t *)&iph->daddr, ah->spi, IPPROTO_AH, AF_INET6); |
420 | if (!x) | 619 | if (!x) |
421 | return; | 620 | return; |
422 | 621 | ||
@@ -430,7 +629,7 @@ static int ah6_init_state(struct xfrm_state *x) | |||
430 | { | 629 | { |
431 | struct ah_data *ahp = NULL; | 630 | struct ah_data *ahp = NULL; |
432 | struct xfrm_algo_desc *aalg_desc; | 631 | struct xfrm_algo_desc *aalg_desc; |
433 | struct crypto_hash *tfm; | 632 | struct crypto_ahash *ahash; |
434 | 633 | ||
435 | if (!x->aalg) | 634 | if (!x->aalg) |
436 | goto error; | 635 | goto error; |
@@ -442,12 +641,12 @@ static int ah6_init_state(struct xfrm_state *x) | |||
442 | if (ahp == NULL) | 641 | if (ahp == NULL) |
443 | return -ENOMEM; | 642 | return -ENOMEM; |
444 | 643 | ||
445 | tfm = crypto_alloc_hash(x->aalg->alg_name, 0, CRYPTO_ALG_ASYNC); | 644 | ahash = crypto_alloc_ahash(x->aalg->alg_name, 0, 0); |
446 | if (IS_ERR(tfm)) | 645 | if (IS_ERR(ahash)) |
447 | goto error; | 646 | goto error; |
448 | 647 | ||
449 | ahp->tfm = tfm; | 648 | ahp->ahash = ahash; |
450 | if (crypto_hash_setkey(tfm, x->aalg->alg_key, | 649 | if (crypto_ahash_setkey(ahash, x->aalg->alg_key, |
451 | (x->aalg->alg_key_len + 7) / 8)) | 650 | (x->aalg->alg_key_len + 7) / 8)) |
452 | goto error; | 651 | goto error; |
453 | 652 | ||
@@ -461,22 +660,18 @@ static int ah6_init_state(struct xfrm_state *x) | |||
461 | BUG_ON(!aalg_desc); | 660 | BUG_ON(!aalg_desc); |
462 | 661 | ||
463 | if (aalg_desc->uinfo.auth.icv_fullbits/8 != | 662 | if (aalg_desc->uinfo.auth.icv_fullbits/8 != |
464 | crypto_hash_digestsize(tfm)) { | 663 | crypto_ahash_digestsize(ahash)) { |
465 | printk(KERN_INFO "AH: %s digestsize %u != %hu\n", | 664 | printk(KERN_INFO "AH: %s digestsize %u != %hu\n", |
466 | x->aalg->alg_name, crypto_hash_digestsize(tfm), | 665 | x->aalg->alg_name, crypto_ahash_digestsize(ahash), |
467 | aalg_desc->uinfo.auth.icv_fullbits/8); | 666 | aalg_desc->uinfo.auth.icv_fullbits/8); |
468 | goto error; | 667 | goto error; |
469 | } | 668 | } |
470 | 669 | ||
471 | ahp->icv_full_len = aalg_desc->uinfo.auth.icv_fullbits/8; | 670 | ahp->icv_full_len = aalg_desc->uinfo.auth.icv_fullbits/8; |
472 | ahp->icv_trunc_len = aalg_desc->uinfo.auth.icv_truncbits/8; | 671 | ahp->icv_trunc_len = x->aalg->alg_trunc_len/8; |
473 | 672 | ||
474 | BUG_ON(ahp->icv_trunc_len > MAX_AH_AUTH_LEN); | 673 | BUG_ON(ahp->icv_trunc_len > MAX_AH_AUTH_LEN); |
475 | 674 | ||
476 | ahp->work_icv = kmalloc(ahp->icv_full_len, GFP_KERNEL); | ||
477 | if (!ahp->work_icv) | ||
478 | goto error; | ||
479 | |||
480 | x->props.header_len = XFRM_ALIGN8(sizeof(struct ip_auth_hdr) + | 675 | x->props.header_len = XFRM_ALIGN8(sizeof(struct ip_auth_hdr) + |
481 | ahp->icv_trunc_len); | 676 | ahp->icv_trunc_len); |
482 | switch (x->props.mode) { | 677 | switch (x->props.mode) { |
@@ -495,8 +690,7 @@ static int ah6_init_state(struct xfrm_state *x) | |||
495 | 690 | ||
496 | error: | 691 | error: |
497 | if (ahp) { | 692 | if (ahp) { |
498 | kfree(ahp->work_icv); | 693 | crypto_free_ahash(ahp->ahash); |
499 | crypto_free_hash(ahp->tfm); | ||
500 | kfree(ahp); | 694 | kfree(ahp); |
501 | } | 695 | } |
502 | return -EINVAL; | 696 | return -EINVAL; |
@@ -509,8 +703,7 @@ static void ah6_destroy(struct xfrm_state *x) | |||
509 | if (!ahp) | 703 | if (!ahp) |
510 | return; | 704 | return; |
511 | 705 | ||
512 | kfree(ahp->work_icv); | 706 | crypto_free_ahash(ahp->ahash); |
513 | crypto_free_hash(ahp->tfm); | ||
514 | kfree(ahp); | 707 | kfree(ahp); |
515 | } | 708 | } |
516 | 709 | ||
diff --git a/net/ipv6/anycast.c b/net/ipv6/anycast.c index 1ae58bec1de0..b5b07054508a 100644 --- a/net/ipv6/anycast.c +++ b/net/ipv6/anycast.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/init.h> | 29 | #include <linux/init.h> |
30 | #include <linux/proc_fs.h> | 30 | #include <linux/proc_fs.h> |
31 | #include <linux/seq_file.h> | 31 | #include <linux/seq_file.h> |
32 | #include <linux/slab.h> | ||
32 | 33 | ||
33 | #include <net/net_namespace.h> | 34 | #include <net/net_namespace.h> |
34 | #include <net/sock.h> | 35 | #include <net/sock.h> |
@@ -404,13 +405,13 @@ int ipv6_chk_acast_addr(struct net *net, struct net_device *dev, | |||
404 | 405 | ||
405 | if (dev) | 406 | if (dev) |
406 | return ipv6_chk_acast_dev(dev, addr); | 407 | return ipv6_chk_acast_dev(dev, addr); |
407 | read_lock(&dev_base_lock); | 408 | rcu_read_lock(); |
408 | for_each_netdev(net, dev) | 409 | for_each_netdev_rcu(net, dev) |
409 | if (ipv6_chk_acast_dev(dev, addr)) { | 410 | if (ipv6_chk_acast_dev(dev, addr)) { |
410 | found = 1; | 411 | found = 1; |
411 | break; | 412 | break; |
412 | } | 413 | } |
413 | read_unlock(&dev_base_lock); | 414 | rcu_read_unlock(); |
414 | return found; | 415 | return found; |
415 | } | 416 | } |
416 | 417 | ||
@@ -431,9 +432,9 @@ static inline struct ifacaddr6 *ac6_get_first(struct seq_file *seq) | |||
431 | struct net *net = seq_file_net(seq); | 432 | struct net *net = seq_file_net(seq); |
432 | 433 | ||
433 | state->idev = NULL; | 434 | state->idev = NULL; |
434 | for_each_netdev(net, state->dev) { | 435 | for_each_netdev_rcu(net, state->dev) { |
435 | struct inet6_dev *idev; | 436 | struct inet6_dev *idev; |
436 | idev = in6_dev_get(state->dev); | 437 | idev = __in6_dev_get(state->dev); |
437 | if (!idev) | 438 | if (!idev) |
438 | continue; | 439 | continue; |
439 | read_lock_bh(&idev->lock); | 440 | read_lock_bh(&idev->lock); |
@@ -443,7 +444,6 @@ static inline struct ifacaddr6 *ac6_get_first(struct seq_file *seq) | |||
443 | break; | 444 | break; |
444 | } | 445 | } |
445 | read_unlock_bh(&idev->lock); | 446 | read_unlock_bh(&idev->lock); |
446 | in6_dev_put(idev); | ||
447 | } | 447 | } |
448 | return im; | 448 | return im; |
449 | } | 449 | } |
@@ -454,16 +454,15 @@ static struct ifacaddr6 *ac6_get_next(struct seq_file *seq, struct ifacaddr6 *im | |||
454 | 454 | ||
455 | im = im->aca_next; | 455 | im = im->aca_next; |
456 | while (!im) { | 456 | while (!im) { |
457 | if (likely(state->idev != NULL)) { | 457 | if (likely(state->idev != NULL)) |
458 | read_unlock_bh(&state->idev->lock); | 458 | read_unlock_bh(&state->idev->lock); |
459 | in6_dev_put(state->idev); | 459 | |
460 | } | 460 | state->dev = next_net_device_rcu(state->dev); |
461 | state->dev = next_net_device(state->dev); | ||
462 | if (!state->dev) { | 461 | if (!state->dev) { |
463 | state->idev = NULL; | 462 | state->idev = NULL; |
464 | break; | 463 | break; |
465 | } | 464 | } |
466 | state->idev = in6_dev_get(state->dev); | 465 | state->idev = __in6_dev_get(state->dev); |
467 | if (!state->idev) | 466 | if (!state->idev) |
468 | continue; | 467 | continue; |
469 | read_lock_bh(&state->idev->lock); | 468 | read_lock_bh(&state->idev->lock); |
@@ -482,29 +481,30 @@ static struct ifacaddr6 *ac6_get_idx(struct seq_file *seq, loff_t pos) | |||
482 | } | 481 | } |
483 | 482 | ||
484 | static void *ac6_seq_start(struct seq_file *seq, loff_t *pos) | 483 | static void *ac6_seq_start(struct seq_file *seq, loff_t *pos) |
485 | __acquires(dev_base_lock) | 484 | __acquires(RCU) |
486 | { | 485 | { |
487 | read_lock(&dev_base_lock); | 486 | rcu_read_lock(); |
488 | return ac6_get_idx(seq, *pos); | 487 | return ac6_get_idx(seq, *pos); |
489 | } | 488 | } |
490 | 489 | ||
491 | static void *ac6_seq_next(struct seq_file *seq, void *v, loff_t *pos) | 490 | static void *ac6_seq_next(struct seq_file *seq, void *v, loff_t *pos) |
492 | { | 491 | { |
493 | struct ifacaddr6 *im; | 492 | struct ifacaddr6 *im = ac6_get_next(seq, v); |
494 | im = ac6_get_next(seq, v); | 493 | |
495 | ++*pos; | 494 | ++*pos; |
496 | return im; | 495 | return im; |
497 | } | 496 | } |
498 | 497 | ||
499 | static void ac6_seq_stop(struct seq_file *seq, void *v) | 498 | static void ac6_seq_stop(struct seq_file *seq, void *v) |
500 | __releases(dev_base_lock) | 499 | __releases(RCU) |
501 | { | 500 | { |
502 | struct ac6_iter_state *state = ac6_seq_private(seq); | 501 | struct ac6_iter_state *state = ac6_seq_private(seq); |
502 | |||
503 | if (likely(state->idev != NULL)) { | 503 | if (likely(state->idev != NULL)) { |
504 | read_unlock_bh(&state->idev->lock); | 504 | read_unlock_bh(&state->idev->lock); |
505 | in6_dev_put(state->idev); | 505 | state->idev = NULL; |
506 | } | 506 | } |
507 | read_unlock(&dev_base_lock); | 507 | rcu_read_unlock(); |
508 | } | 508 | } |
509 | 509 | ||
510 | static int ac6_seq_show(struct seq_file *seq, void *v) | 510 | static int ac6_seq_show(struct seq_file *seq, void *v) |
@@ -539,7 +539,7 @@ static const struct file_operations ac6_seq_fops = { | |||
539 | .release = seq_release_net, | 539 | .release = seq_release_net, |
540 | }; | 540 | }; |
541 | 541 | ||
542 | int ac6_proc_init(struct net *net) | 542 | int __net_init ac6_proc_init(struct net *net) |
543 | { | 543 | { |
544 | if (!proc_net_fops_create(net, "anycast6", S_IRUGO, &ac6_seq_fops)) | 544 | if (!proc_net_fops_create(net, "anycast6", S_IRUGO, &ac6_seq_fops)) |
545 | return -ENOMEM; | 545 | return -ENOMEM; |
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index e2bdc6d83a43..61573885e451 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/in6.h> | 21 | #include <linux/in6.h> |
22 | #include <linux/ipv6.h> | 22 | #include <linux/ipv6.h> |
23 | #include <linux/route.h> | 23 | #include <linux/route.h> |
24 | #include <linux/slab.h> | ||
24 | 25 | ||
25 | #include <net/ipv6.h> | 26 | #include <net/ipv6.h> |
26 | #include <net/ndisc.h> | 27 | #include <net/ndisc.h> |
@@ -98,17 +99,15 @@ ipv4_connected: | |||
98 | if (err) | 99 | if (err) |
99 | goto out; | 100 | goto out; |
100 | 101 | ||
101 | ipv6_addr_set(&np->daddr, 0, 0, htonl(0x0000ffff), inet->daddr); | 102 | ipv6_addr_set_v4mapped(inet->inet_daddr, &np->daddr); |
102 | 103 | ||
103 | if (ipv6_addr_any(&np->saddr)) { | 104 | if (ipv6_addr_any(&np->saddr)) |
104 | ipv6_addr_set(&np->saddr, 0, 0, htonl(0x0000ffff), | 105 | ipv6_addr_set_v4mapped(inet->inet_saddr, &np->saddr); |
105 | inet->saddr); | 106 | |
106 | } | 107 | if (ipv6_addr_any(&np->rcv_saddr)) |
108 | ipv6_addr_set_v4mapped(inet->inet_rcv_saddr, | ||
109 | &np->rcv_saddr); | ||
107 | 110 | ||
108 | if (ipv6_addr_any(&np->rcv_saddr)) { | ||
109 | ipv6_addr_set(&np->rcv_saddr, 0, 0, htonl(0x0000ffff), | ||
110 | inet->rcv_saddr); | ||
111 | } | ||
112 | goto out; | 111 | goto out; |
113 | } | 112 | } |
114 | 113 | ||
@@ -136,7 +135,7 @@ ipv4_connected: | |||
136 | ipv6_addr_copy(&np->daddr, daddr); | 135 | ipv6_addr_copy(&np->daddr, daddr); |
137 | np->flow_label = fl.fl6_flowlabel; | 136 | np->flow_label = fl.fl6_flowlabel; |
138 | 137 | ||
139 | inet->dport = usin->sin6_port; | 138 | inet->inet_dport = usin->sin6_port; |
140 | 139 | ||
141 | /* | 140 | /* |
142 | * Check for a route to destination an obtain the | 141 | * Check for a route to destination an obtain the |
@@ -147,8 +146,9 @@ ipv4_connected: | |||
147 | ipv6_addr_copy(&fl.fl6_dst, &np->daddr); | 146 | ipv6_addr_copy(&fl.fl6_dst, &np->daddr); |
148 | ipv6_addr_copy(&fl.fl6_src, &np->saddr); | 147 | ipv6_addr_copy(&fl.fl6_src, &np->saddr); |
149 | fl.oif = sk->sk_bound_dev_if; | 148 | fl.oif = sk->sk_bound_dev_if; |
150 | fl.fl_ip_dport = inet->dport; | 149 | fl.mark = sk->sk_mark; |
151 | fl.fl_ip_sport = inet->sport; | 150 | fl.fl_ip_dport = inet->inet_dport; |
151 | fl.fl_ip_sport = inet->inet_sport; | ||
152 | 152 | ||
153 | if (!fl.oif && (addr_type&IPV6_ADDR_MULTICAST)) | 153 | if (!fl.oif && (addr_type&IPV6_ADDR_MULTICAST)) |
154 | fl.oif = np->mcast_oif; | 154 | fl.oif = np->mcast_oif; |
@@ -190,7 +190,7 @@ ipv4_connected: | |||
190 | 190 | ||
191 | if (ipv6_addr_any(&np->rcv_saddr)) { | 191 | if (ipv6_addr_any(&np->rcv_saddr)) { |
192 | ipv6_addr_copy(&np->rcv_saddr, &fl.fl6_src); | 192 | ipv6_addr_copy(&np->rcv_saddr, &fl.fl6_src); |
193 | inet->rcv_saddr = LOOPBACK4_IPV6; | 193 | inet->inet_rcv_saddr = LOOPBACK4_IPV6; |
194 | } | 194 | } |
195 | 195 | ||
196 | ip6_dst_store(sk, dst, | 196 | ip6_dst_store(sk, dst, |
@@ -222,6 +222,8 @@ void ipv6_icmp_error(struct sock *sk, struct sk_buff *skb, int err, | |||
222 | if (!skb) | 222 | if (!skb) |
223 | return; | 223 | return; |
224 | 224 | ||
225 | skb->protocol = htons(ETH_P_IPV6); | ||
226 | |||
225 | serr = SKB_EXT_ERR(skb); | 227 | serr = SKB_EXT_ERR(skb); |
226 | serr->ee.ee_errno = err; | 228 | serr->ee.ee_errno = err; |
227 | serr->ee.ee_origin = SO_EE_ORIGIN_ICMP6; | 229 | serr->ee.ee_origin = SO_EE_ORIGIN_ICMP6; |
@@ -255,6 +257,8 @@ void ipv6_local_error(struct sock *sk, int err, struct flowi *fl, u32 info) | |||
255 | if (!skb) | 257 | if (!skb) |
256 | return; | 258 | return; |
257 | 259 | ||
260 | skb->protocol = htons(ETH_P_IPV6); | ||
261 | |||
258 | skb_put(skb, sizeof(struct ipv6hdr)); | 262 | skb_put(skb, sizeof(struct ipv6hdr)); |
259 | skb_reset_network_header(skb); | 263 | skb_reset_network_header(skb); |
260 | iph = ipv6_hdr(skb); | 264 | iph = ipv6_hdr(skb); |
@@ -319,7 +323,7 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len) | |||
319 | sin->sin6_flowinfo = 0; | 323 | sin->sin6_flowinfo = 0; |
320 | sin->sin6_port = serr->port; | 324 | sin->sin6_port = serr->port; |
321 | sin->sin6_scope_id = 0; | 325 | sin->sin6_scope_id = 0; |
322 | if (serr->ee.ee_origin == SO_EE_ORIGIN_ICMP6) { | 326 | if (skb->protocol == htons(ETH_P_IPV6)) { |
323 | ipv6_addr_copy(&sin->sin6_addr, | 327 | ipv6_addr_copy(&sin->sin6_addr, |
324 | (struct in6_addr *)(nh + serr->addr_offset)); | 328 | (struct in6_addr *)(nh + serr->addr_offset)); |
325 | if (np->sndflow) | 329 | if (np->sndflow) |
@@ -329,9 +333,8 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len) | |||
329 | if (ipv6_addr_type(&sin->sin6_addr) & IPV6_ADDR_LINKLOCAL) | 333 | if (ipv6_addr_type(&sin->sin6_addr) & IPV6_ADDR_LINKLOCAL) |
330 | sin->sin6_scope_id = IP6CB(skb)->iif; | 334 | sin->sin6_scope_id = IP6CB(skb)->iif; |
331 | } else { | 335 | } else { |
332 | ipv6_addr_set(&sin->sin6_addr, 0, 0, | 336 | ipv6_addr_set_v4mapped(*(__be32 *)(nh + serr->addr_offset), |
333 | htonl(0xffff), | 337 | &sin->sin6_addr); |
334 | *(__be32 *)(nh + serr->addr_offset)); | ||
335 | } | 338 | } |
336 | } | 339 | } |
337 | 340 | ||
@@ -342,7 +345,7 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len) | |||
342 | sin->sin6_family = AF_INET6; | 345 | sin->sin6_family = AF_INET6; |
343 | sin->sin6_flowinfo = 0; | 346 | sin->sin6_flowinfo = 0; |
344 | sin->sin6_scope_id = 0; | 347 | sin->sin6_scope_id = 0; |
345 | if (serr->ee.ee_origin == SO_EE_ORIGIN_ICMP6) { | 348 | if (skb->protocol == htons(ETH_P_IPV6)) { |
346 | ipv6_addr_copy(&sin->sin6_addr, &ipv6_hdr(skb)->saddr); | 349 | ipv6_addr_copy(&sin->sin6_addr, &ipv6_hdr(skb)->saddr); |
347 | if (np->rxopt.all) | 350 | if (np->rxopt.all) |
348 | datagram_recv_ctl(sk, msg, skb); | 351 | datagram_recv_ctl(sk, msg, skb); |
@@ -351,8 +354,8 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len) | |||
351 | } else { | 354 | } else { |
352 | struct inet_sock *inet = inet_sk(sk); | 355 | struct inet_sock *inet = inet_sk(sk); |
353 | 356 | ||
354 | ipv6_addr_set(&sin->sin6_addr, 0, 0, | 357 | ipv6_addr_set_v4mapped(ip_hdr(skb)->saddr, |
355 | htonl(0xffff), ip_hdr(skb)->saddr); | 358 | &sin->sin6_addr); |
356 | if (inet->cmsg_flags) | 359 | if (inet->cmsg_flags) |
357 | ip_cmsg_recv(msg, skb); | 360 | ip_cmsg_recv(msg, skb); |
358 | } | 361 | } |
@@ -539,12 +542,17 @@ int datagram_send_ctl(struct net *net, | |||
539 | 542 | ||
540 | addr_type = __ipv6_addr_type(&src_info->ipi6_addr); | 543 | addr_type = __ipv6_addr_type(&src_info->ipi6_addr); |
541 | 544 | ||
545 | rcu_read_lock(); | ||
542 | if (fl->oif) { | 546 | if (fl->oif) { |
543 | dev = dev_get_by_index(net, fl->oif); | 547 | dev = dev_get_by_index_rcu(net, fl->oif); |
544 | if (!dev) | 548 | if (!dev) { |
549 | rcu_read_unlock(); | ||
545 | return -ENODEV; | 550 | return -ENODEV; |
546 | } else if (addr_type & IPV6_ADDR_LINKLOCAL) | 551 | } |
552 | } else if (addr_type & IPV6_ADDR_LINKLOCAL) { | ||
553 | rcu_read_unlock(); | ||
547 | return -EINVAL; | 554 | return -EINVAL; |
555 | } | ||
548 | 556 | ||
549 | if (addr_type != IPV6_ADDR_ANY) { | 557 | if (addr_type != IPV6_ADDR_ANY) { |
550 | int strict = __ipv6_addr_src_scope(addr_type) <= IPV6_ADDR_SCOPE_LINKLOCAL; | 558 | int strict = __ipv6_addr_src_scope(addr_type) <= IPV6_ADDR_SCOPE_LINKLOCAL; |
@@ -555,8 +563,7 @@ int datagram_send_ctl(struct net *net, | |||
555 | ipv6_addr_copy(&fl->fl6_src, &src_info->ipi6_addr); | 563 | ipv6_addr_copy(&fl->fl6_src, &src_info->ipi6_addr); |
556 | } | 564 | } |
557 | 565 | ||
558 | if (dev) | 566 | rcu_read_unlock(); |
559 | dev_put(dev); | ||
560 | 567 | ||
561 | if (err) | 568 | if (err) |
562 | goto exit_f; | 569 | goto exit_f; |
diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c index af597c73ebe9..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", |
@@ -473,7 +473,7 @@ static int esp_init_authenc(struct xfrm_state *x) | |||
473 | } | 473 | } |
474 | 474 | ||
475 | err = crypto_aead_setauthsize( | 475 | err = crypto_aead_setauthsize( |
476 | aead, aalg_desc->uinfo.auth.icv_truncbits / 8); | 476 | aead, x->aalg->alg_trunc_len / 8); |
477 | if (err) | 477 | if (err) |
478 | goto free_key; | 478 | goto free_key; |
479 | } | 479 | } |
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c index df159fffe4bc..8a659f92d17a 100644 --- a/net/ipv6/exthdrs.c +++ b/net/ipv6/exthdrs.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/netdevice.h> | 29 | #include <linux/netdevice.h> |
30 | #include <linux/in6.h> | 30 | #include <linux/in6.h> |
31 | #include <linux/icmpv6.h> | 31 | #include <linux/icmpv6.h> |
32 | #include <linux/slab.h> | ||
32 | 33 | ||
33 | #include <net/dst.h> | 34 | #include <net/dst.h> |
34 | #include <net/sock.h> | 35 | #include <net/sock.h> |
@@ -481,7 +482,7 @@ looped_back: | |||
481 | IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)), | 482 | IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)), |
482 | IPSTATS_MIB_INHDRERRORS); | 483 | IPSTATS_MIB_INHDRERRORS); |
483 | icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT, | 484 | icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT, |
484 | 0, skb->dev); | 485 | 0); |
485 | kfree_skb(skb); | 486 | kfree_skb(skb); |
486 | return -1; | 487 | return -1; |
487 | } | 488 | } |
@@ -559,6 +560,11 @@ static inline struct inet6_dev *ipv6_skb_idev(struct sk_buff *skb) | |||
559 | return skb_dst(skb) ? ip6_dst_idev(skb_dst(skb)) : __in6_dev_get(skb->dev); | 560 | return skb_dst(skb) ? ip6_dst_idev(skb_dst(skb)) : __in6_dev_get(skb->dev); |
560 | } | 561 | } |
561 | 562 | ||
563 | static inline struct net *ipv6_skb_net(struct sk_buff *skb) | ||
564 | { | ||
565 | return skb_dst(skb) ? dev_net(skb_dst(skb)->dev) : dev_net(skb->dev); | ||
566 | } | ||
567 | |||
562 | /* Router Alert as of RFC 2711 */ | 568 | /* Router Alert as of RFC 2711 */ |
563 | 569 | ||
564 | static int ipv6_hop_ra(struct sk_buff *skb, int optoff) | 570 | static int ipv6_hop_ra(struct sk_buff *skb, int optoff) |
@@ -580,8 +586,8 @@ static int ipv6_hop_ra(struct sk_buff *skb, int optoff) | |||
580 | static int ipv6_hop_jumbo(struct sk_buff *skb, int optoff) | 586 | static int ipv6_hop_jumbo(struct sk_buff *skb, int optoff) |
581 | { | 587 | { |
582 | const unsigned char *nh = skb_network_header(skb); | 588 | const unsigned char *nh = skb_network_header(skb); |
589 | struct net *net = ipv6_skb_net(skb); | ||
583 | u32 pkt_len; | 590 | u32 pkt_len; |
584 | struct net *net = dev_net(skb_dst(skb)->dev); | ||
585 | 591 | ||
586 | if (nh[optoff + 1] != 4 || (optoff & 3) != 2) { | 592 | if (nh[optoff + 1] != 4 || (optoff & 3) != 2) { |
587 | LIMIT_NETDEBUG(KERN_DEBUG "ipv6_hop_jumbo: wrong jumbo opt length/alignment %d\n", | 593 | LIMIT_NETDEBUG(KERN_DEBUG "ipv6_hop_jumbo: wrong jumbo opt length/alignment %d\n", |
diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c index 00a7a5e4ac97..5e463c43fcc2 100644 --- a/net/ipv6/fib6_rules.c +++ b/net/ipv6/fib6_rules.c | |||
@@ -84,18 +84,11 @@ static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp, | |||
84 | if ((rule->flags & FIB_RULE_FIND_SADDR) && | 84 | if ((rule->flags & FIB_RULE_FIND_SADDR) && |
85 | r->src.plen && !(flags & RT6_LOOKUP_F_HAS_SADDR)) { | 85 | r->src.plen && !(flags & RT6_LOOKUP_F_HAS_SADDR)) { |
86 | struct in6_addr saddr; | 86 | struct in6_addr saddr; |
87 | unsigned int srcprefs = 0; | ||
88 | |||
89 | if (flags & RT6_LOOKUP_F_SRCPREF_TMP) | ||
90 | srcprefs |= IPV6_PREFER_SRC_TMP; | ||
91 | if (flags & RT6_LOOKUP_F_SRCPREF_PUBLIC) | ||
92 | srcprefs |= IPV6_PREFER_SRC_PUBLIC; | ||
93 | if (flags & RT6_LOOKUP_F_SRCPREF_COA) | ||
94 | srcprefs |= IPV6_PREFER_SRC_COA; | ||
95 | 87 | ||
96 | if (ipv6_dev_get_saddr(net, | 88 | if (ipv6_dev_get_saddr(net, |
97 | ip6_dst_idev(&rt->u.dst)->dev, | 89 | ip6_dst_idev(&rt->u.dst)->dev, |
98 | &flp->fl6_dst, srcprefs, | 90 | &flp->fl6_dst, |
91 | rt6_flags2srcprefs(flags), | ||
99 | &saddr)) | 92 | &saddr)) |
100 | goto again; | 93 | goto again; |
101 | if (!ipv6_prefix_equal(&saddr, &r->src.addr, | 94 | if (!ipv6_prefix_equal(&saddr, &r->src.addr, |
@@ -262,46 +255,38 @@ static struct fib_rules_ops fib6_rules_ops_template = { | |||
262 | .fro_net = &init_net, | 255 | .fro_net = &init_net, |
263 | }; | 256 | }; |
264 | 257 | ||
265 | static int fib6_rules_net_init(struct net *net) | 258 | static int __net_init fib6_rules_net_init(struct net *net) |
266 | { | 259 | { |
260 | struct fib_rules_ops *ops; | ||
267 | int err = -ENOMEM; | 261 | int err = -ENOMEM; |
268 | 262 | ||
269 | net->ipv6.fib6_rules_ops = kmemdup(&fib6_rules_ops_template, | 263 | ops = fib_rules_register(&fib6_rules_ops_template, net); |
270 | sizeof(*net->ipv6.fib6_rules_ops), | 264 | if (IS_ERR(ops)) |
271 | GFP_KERNEL); | 265 | return PTR_ERR(ops); |
272 | if (!net->ipv6.fib6_rules_ops) | 266 | net->ipv6.fib6_rules_ops = ops; |
273 | goto out; | ||
274 | 267 | ||
275 | net->ipv6.fib6_rules_ops->fro_net = net; | ||
276 | INIT_LIST_HEAD(&net->ipv6.fib6_rules_ops->rules_list); | ||
277 | 268 | ||
278 | err = fib_default_rule_add(net->ipv6.fib6_rules_ops, 0, | 269 | err = fib_default_rule_add(net->ipv6.fib6_rules_ops, 0, |
279 | RT6_TABLE_LOCAL, FIB_RULE_PERMANENT); | 270 | RT6_TABLE_LOCAL, 0); |
280 | if (err) | 271 | if (err) |
281 | goto out_fib6_rules_ops; | 272 | goto out_fib6_rules_ops; |
282 | 273 | ||
283 | err = fib_default_rule_add(net->ipv6.fib6_rules_ops, | 274 | err = fib_default_rule_add(net->ipv6.fib6_rules_ops, |
284 | 0x7FFE, RT6_TABLE_MAIN, 0); | 275 | 0x7FFE, RT6_TABLE_MAIN, 0); |
285 | if (err) | 276 | if (err) |
286 | goto out_fib6_default_rule_add; | 277 | goto out_fib6_rules_ops; |
287 | 278 | ||
288 | err = fib_rules_register(net->ipv6.fib6_rules_ops); | ||
289 | if (err) | ||
290 | goto out_fib6_default_rule_add; | ||
291 | out: | 279 | out: |
292 | return err; | 280 | return err; |
293 | 281 | ||
294 | out_fib6_default_rule_add: | ||
295 | fib_rules_cleanup_ops(net->ipv6.fib6_rules_ops); | ||
296 | out_fib6_rules_ops: | 282 | out_fib6_rules_ops: |
297 | kfree(net->ipv6.fib6_rules_ops); | 283 | fib_rules_unregister(ops); |
298 | goto out; | 284 | goto out; |
299 | } | 285 | } |
300 | 286 | ||
301 | static void fib6_rules_net_exit(struct net *net) | 287 | static void __net_exit fib6_rules_net_exit(struct net *net) |
302 | { | 288 | { |
303 | fib_rules_unregister(net->ipv6.fib6_rules_ops); | 289 | fib_rules_unregister(net->ipv6.fib6_rules_ops); |
304 | kfree(net->ipv6.fib6_rules_ops); | ||
305 | } | 290 | } |
306 | 291 | ||
307 | static struct pernet_operations fib6_rules_net_ops = { | 292 | static struct pernet_operations fib6_rules_net_ops = { |
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index f23ebbec0631..3330a4bd6157 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c | |||
@@ -40,6 +40,7 @@ | |||
40 | #include <linux/skbuff.h> | 40 | #include <linux/skbuff.h> |
41 | #include <linux/init.h> | 41 | #include <linux/init.h> |
42 | #include <linux/netfilter.h> | 42 | #include <linux/netfilter.h> |
43 | #include <linux/slab.h> | ||
43 | 44 | ||
44 | #ifdef CONFIG_SYSCTL | 45 | #ifdef CONFIG_SYSCTL |
45 | #include <linux/sysctl.h> | 46 | #include <linux/sysctl.h> |
@@ -67,11 +68,6 @@ | |||
67 | #include <asm/uaccess.h> | 68 | #include <asm/uaccess.h> |
68 | #include <asm/system.h> | 69 | #include <asm/system.h> |
69 | 70 | ||
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 | /* | 71 | /* |
76 | * The ICMP socket(s). This is the most convenient way to flow control | 72 | * 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 | 73 | * our ICMP output as well as maintain a clean interface throughout |
@@ -119,7 +115,7 @@ static __inline__ void icmpv6_xmit_unlock(struct sock *sk) | |||
119 | */ | 115 | */ |
120 | void icmpv6_param_prob(struct sk_buff *skb, u8 code, int pos) | 116 | void icmpv6_param_prob(struct sk_buff *skb, u8 code, int pos) |
121 | { | 117 | { |
122 | icmpv6_send(skb, ICMPV6_PARAMPROB, code, pos, skb->dev); | 118 | icmpv6_send(skb, ICMPV6_PARAMPROB, code, pos); |
123 | kfree_skb(skb); | 119 | kfree_skb(skb); |
124 | } | 120 | } |
125 | 121 | ||
@@ -305,8 +301,7 @@ static inline void mip6_addr_swap(struct sk_buff *skb) {} | |||
305 | /* | 301 | /* |
306 | * Send an ICMP message in response to a packet in error | 302 | * Send an ICMP message in response to a packet in error |
307 | */ | 303 | */ |
308 | void icmpv6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info, | 304 | void icmpv6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info) |
309 | struct net_device *dev) | ||
310 | { | 305 | { |
311 | struct net *net = dev_net(skb->dev); | 306 | struct net *net = dev_net(skb->dev); |
312 | struct inet6_dev *idev = NULL; | 307 | struct inet6_dev *idev = NULL; |
@@ -942,18 +937,16 @@ EXPORT_SYMBOL(icmpv6_err_convert); | |||
942 | #ifdef CONFIG_SYSCTL | 937 | #ifdef CONFIG_SYSCTL |
943 | ctl_table ipv6_icmp_table_template[] = { | 938 | ctl_table ipv6_icmp_table_template[] = { |
944 | { | 939 | { |
945 | .ctl_name = NET_IPV6_ICMP_RATELIMIT, | ||
946 | .procname = "ratelimit", | 940 | .procname = "ratelimit", |
947 | .data = &init_net.ipv6.sysctl.icmpv6_time, | 941 | .data = &init_net.ipv6.sysctl.icmpv6_time, |
948 | .maxlen = sizeof(int), | 942 | .maxlen = sizeof(int), |
949 | .mode = 0644, | 943 | .mode = 0644, |
950 | .proc_handler = proc_dointvec_ms_jiffies, | 944 | .proc_handler = proc_dointvec_ms_jiffies, |
951 | .strategy = sysctl_ms_jiffies | ||
952 | }, | 945 | }, |
953 | { .ctl_name = 0 }, | 946 | { }, |
954 | }; | 947 | }; |
955 | 948 | ||
956 | struct ctl_table *ipv6_icmp_sysctl_init(struct net *net) | 949 | struct ctl_table * __net_init ipv6_icmp_sysctl_init(struct net *net) |
957 | { | 950 | { |
958 | struct ctl_table *table; | 951 | struct ctl_table *table; |
959 | 952 | ||
diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c index cc4797dd8325..628db24bcf22 100644 --- a/net/ipv6/inet6_connection_sock.c +++ b/net/ipv6/inet6_connection_sock.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/in6.h> | 17 | #include <linux/in6.h> |
18 | #include <linux/ipv6.h> | 18 | #include <linux/ipv6.h> |
19 | #include <linux/jhash.h> | 19 | #include <linux/jhash.h> |
20 | #include <linux/slab.h> | ||
20 | 21 | ||
21 | #include <net/addrconf.h> | 22 | #include <net/addrconf.h> |
22 | #include <net/inet_connection_sock.h> | 23 | #include <net/inet_connection_sock.h> |
@@ -132,7 +133,7 @@ void inet6_csk_addr2sockaddr(struct sock *sk, struct sockaddr * uaddr) | |||
132 | 133 | ||
133 | sin6->sin6_family = AF_INET6; | 134 | sin6->sin6_family = AF_INET6; |
134 | ipv6_addr_copy(&sin6->sin6_addr, &np->daddr); | 135 | ipv6_addr_copy(&sin6->sin6_addr, &np->daddr); |
135 | sin6->sin6_port = inet_sk(sk)->dport; | 136 | sin6->sin6_port = inet_sk(sk)->inet_dport; |
136 | /* We do not store received flowlabel for TCP */ | 137 | /* We do not store received flowlabel for TCP */ |
137 | sin6->sin6_flowinfo = 0; | 138 | sin6->sin6_flowinfo = 0; |
138 | sin6->sin6_scope_id = 0; | 139 | sin6->sin6_scope_id = 0; |
@@ -168,8 +169,7 @@ struct dst_entry *__inet6_csk_dst_check(struct sock *sk, u32 cookie) | |||
168 | if (dst) { | 169 | if (dst) { |
169 | struct rt6_info *rt = (struct rt6_info *)dst; | 170 | struct rt6_info *rt = (struct rt6_info *)dst; |
170 | if (rt->rt6i_flow_cache_genid != atomic_read(&flow_cache_genid)) { | 171 | if (rt->rt6i_flow_cache_genid != atomic_read(&flow_cache_genid)) { |
171 | sk->sk_dst_cache = NULL; | 172 | __sk_dst_reset(sk); |
172 | dst_release(dst); | ||
173 | dst = NULL; | 173 | dst = NULL; |
174 | } | 174 | } |
175 | } | 175 | } |
@@ -194,8 +194,9 @@ int inet6_csk_xmit(struct sk_buff *skb, int ipfragok) | |||
194 | fl.fl6_flowlabel = np->flow_label; | 194 | fl.fl6_flowlabel = np->flow_label; |
195 | IP6_ECN_flow_xmit(sk, fl.fl6_flowlabel); | 195 | IP6_ECN_flow_xmit(sk, fl.fl6_flowlabel); |
196 | fl.oif = sk->sk_bound_dev_if; | 196 | fl.oif = sk->sk_bound_dev_if; |
197 | fl.fl_ip_sport = inet->sport; | 197 | fl.mark = sk->sk_mark; |
198 | fl.fl_ip_dport = inet->dport; | 198 | fl.fl_ip_sport = inet->inet_sport; |
199 | fl.fl_ip_dport = inet->inet_dport; | ||
199 | security_sk_classify_flow(sk, &fl); | 200 | security_sk_classify_flow(sk, &fl); |
200 | 201 | ||
201 | if (np->opt && np->opt->srcrt) { | 202 | if (np->opt && np->opt->srcrt) { |
diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c index 1bcc3431859e..633a6c266136 100644 --- a/net/ipv6/inet6_hashtables.c +++ b/net/ipv6/inet6_hashtables.c | |||
@@ -22,9 +22,10 @@ | |||
22 | #include <net/inet6_hashtables.h> | 22 | #include <net/inet6_hashtables.h> |
23 | #include <net/ip.h> | 23 | #include <net/ip.h> |
24 | 24 | ||
25 | void __inet6_hash(struct sock *sk) | 25 | int __inet6_hash(struct sock *sk, struct inet_timewait_sock *tw) |
26 | { | 26 | { |
27 | struct inet_hashinfo *hashinfo = sk->sk_prot->h.hashinfo; | 27 | struct inet_hashinfo *hashinfo = sk->sk_prot->h.hashinfo; |
28 | int twrefcnt = 0; | ||
28 | 29 | ||
29 | WARN_ON(!sk_unhashed(sk)); | 30 | WARN_ON(!sk_unhashed(sk)); |
30 | 31 | ||
@@ -45,10 +46,15 @@ void __inet6_hash(struct sock *sk) | |||
45 | lock = inet_ehash_lockp(hashinfo, hash); | 46 | lock = inet_ehash_lockp(hashinfo, hash); |
46 | spin_lock(lock); | 47 | spin_lock(lock); |
47 | __sk_nulls_add_node_rcu(sk, list); | 48 | __sk_nulls_add_node_rcu(sk, list); |
49 | if (tw) { | ||
50 | WARN_ON(sk->sk_hash != tw->tw_hash); | ||
51 | twrefcnt = inet_twsk_unhash(tw); | ||
52 | } | ||
48 | spin_unlock(lock); | 53 | spin_unlock(lock); |
49 | } | 54 | } |
50 | 55 | ||
51 | sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); | 56 | sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); |
57 | return twrefcnt; | ||
52 | } | 58 | } |
53 | EXPORT_SYMBOL(__inet6_hash); | 59 | EXPORT_SYMBOL(__inet6_hash); |
54 | 60 | ||
@@ -73,7 +79,7 @@ struct sock *__inet6_lookup_established(struct net *net, | |||
73 | * have wildcards anyways. | 79 | * have wildcards anyways. |
74 | */ | 80 | */ |
75 | unsigned int hash = inet6_ehashfn(net, daddr, hnum, saddr, sport); | 81 | unsigned int hash = inet6_ehashfn(net, daddr, hnum, saddr, sport); |
76 | unsigned int slot = hash & (hashinfo->ehash_size - 1); | 82 | unsigned int slot = hash & hashinfo->ehash_mask; |
77 | struct inet_ehash_bucket *head = &hashinfo->ehash[slot]; | 83 | struct inet_ehash_bucket *head = &hashinfo->ehash[slot]; |
78 | 84 | ||
79 | 85 | ||
@@ -125,7 +131,7 @@ static int inline compute_score(struct sock *sk, struct net *net, | |||
125 | { | 131 | { |
126 | int score = -1; | 132 | int score = -1; |
127 | 133 | ||
128 | if (net_eq(sock_net(sk), net) && inet_sk(sk)->num == hnum && | 134 | if (net_eq(sock_net(sk), net) && inet_sk(sk)->inet_num == hnum && |
129 | sk->sk_family == PF_INET6) { | 135 | sk->sk_family == PF_INET6) { |
130 | const struct ipv6_pinfo *np = inet6_sk(sk); | 136 | const struct ipv6_pinfo *np = inet6_sk(sk); |
131 | 137 | ||
@@ -214,15 +220,16 @@ static int __inet6_check_established(struct inet_timewait_death_row *death_row, | |||
214 | const struct in6_addr *daddr = &np->rcv_saddr; | 220 | const struct in6_addr *daddr = &np->rcv_saddr; |
215 | const struct in6_addr *saddr = &np->daddr; | 221 | const struct in6_addr *saddr = &np->daddr; |
216 | const int dif = sk->sk_bound_dev_if; | 222 | const int dif = sk->sk_bound_dev_if; |
217 | const __portpair ports = INET_COMBINED_PORTS(inet->dport, lport); | 223 | const __portpair ports = INET_COMBINED_PORTS(inet->inet_dport, lport); |
218 | struct net *net = sock_net(sk); | 224 | struct net *net = sock_net(sk); |
219 | const unsigned int hash = inet6_ehashfn(net, daddr, lport, saddr, | 225 | const unsigned int hash = inet6_ehashfn(net, daddr, lport, saddr, |
220 | inet->dport); | 226 | inet->inet_dport); |
221 | struct inet_ehash_bucket *head = inet_ehash_bucket(hinfo, hash); | 227 | struct inet_ehash_bucket *head = inet_ehash_bucket(hinfo, hash); |
222 | spinlock_t *lock = inet_ehash_lockp(hinfo, hash); | 228 | spinlock_t *lock = inet_ehash_lockp(hinfo, hash); |
223 | struct sock *sk2; | 229 | struct sock *sk2; |
224 | const struct hlist_nulls_node *node; | 230 | const struct hlist_nulls_node *node; |
225 | struct inet_timewait_sock *tw; | 231 | struct inet_timewait_sock *tw; |
232 | int twrefcnt = 0; | ||
226 | 233 | ||
227 | spin_lock(lock); | 234 | spin_lock(lock); |
228 | 235 | ||
@@ -248,21 +255,25 @@ static int __inet6_check_established(struct inet_timewait_death_row *death_row, | |||
248 | unique: | 255 | unique: |
249 | /* Must record num and sport now. Otherwise we will see | 256 | /* Must record num and sport now. Otherwise we will see |
250 | * in hash table socket with a funny identity. */ | 257 | * in hash table socket with a funny identity. */ |
251 | inet->num = lport; | 258 | inet->inet_num = lport; |
252 | inet->sport = htons(lport); | 259 | inet->inet_sport = htons(lport); |
260 | sk->sk_hash = hash; | ||
253 | WARN_ON(!sk_unhashed(sk)); | 261 | WARN_ON(!sk_unhashed(sk)); |
254 | __sk_nulls_add_node_rcu(sk, &head->chain); | 262 | __sk_nulls_add_node_rcu(sk, &head->chain); |
255 | sk->sk_hash = hash; | 263 | if (tw) { |
264 | twrefcnt = inet_twsk_unhash(tw); | ||
265 | NET_INC_STATS_BH(net, LINUX_MIB_TIMEWAITRECYCLED); | ||
266 | } | ||
256 | spin_unlock(lock); | 267 | spin_unlock(lock); |
268 | if (twrefcnt) | ||
269 | inet_twsk_put(tw); | ||
257 | sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); | 270 | sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); |
258 | 271 | ||
259 | if (twp != NULL) { | 272 | if (twp) { |
260 | *twp = tw; | 273 | *twp = tw; |
261 | NET_INC_STATS_BH(net, LINUX_MIB_TIMEWAITRECYCLED); | 274 | } else if (tw) { |
262 | } else if (tw != NULL) { | ||
263 | /* Silly. Should hash-dance instead... */ | 275 | /* Silly. Should hash-dance instead... */ |
264 | inet_twsk_deschedule(tw, death_row); | 276 | inet_twsk_deschedule(tw, death_row); |
265 | NET_INC_STATS_BH(net, LINUX_MIB_TIMEWAITRECYCLED); | ||
266 | 277 | ||
267 | inet_twsk_put(tw); | 278 | inet_twsk_put(tw); |
268 | } | 279 | } |
@@ -279,7 +290,7 @@ static inline u32 inet6_sk_port_offset(const struct sock *sk) | |||
279 | const struct ipv6_pinfo *np = inet6_sk(sk); | 290 | const struct ipv6_pinfo *np = inet6_sk(sk); |
280 | return secure_ipv6_port_ephemeral(np->rcv_saddr.s6_addr32, | 291 | return secure_ipv6_port_ephemeral(np->rcv_saddr.s6_addr32, |
281 | np->daddr.s6_addr32, | 292 | np->daddr.s6_addr32, |
282 | inet->dport); | 293 | inet->inet_dport); |
283 | } | 294 | } |
284 | 295 | ||
285 | int inet6_hash_connect(struct inet_timewait_death_row *death_row, | 296 | int inet6_hash_connect(struct inet_timewait_death_row *death_row, |
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 0e93ca56eb69..6b82e02158c6 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/in6.h> | 26 | #include <linux/in6.h> |
27 | #include <linux/init.h> | 27 | #include <linux/init.h> |
28 | #include <linux/list.h> | 28 | #include <linux/list.h> |
29 | #include <linux/slab.h> | ||
29 | 30 | ||
30 | #ifdef CONFIG_PROC_FS | 31 | #ifdef CONFIG_PROC_FS |
31 | #include <linux/proc_fs.h> | 32 | #include <linux/proc_fs.h> |
@@ -93,29 +94,20 @@ static __u32 rt_sernum; | |||
93 | 94 | ||
94 | static void fib6_gc_timer_cb(unsigned long arg); | 95 | static void fib6_gc_timer_cb(unsigned long arg); |
95 | 96 | ||
96 | static struct fib6_walker_t fib6_walker_list = { | 97 | static LIST_HEAD(fib6_walkers); |
97 | .prev = &fib6_walker_list, | 98 | #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 | 99 | ||
103 | static inline void fib6_walker_link(struct fib6_walker_t *w) | 100 | static inline void fib6_walker_link(struct fib6_walker_t *w) |
104 | { | 101 | { |
105 | write_lock_bh(&fib6_walker_lock); | 102 | write_lock_bh(&fib6_walker_lock); |
106 | w->next = fib6_walker_list.next; | 103 | 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); | 104 | write_unlock_bh(&fib6_walker_lock); |
111 | } | 105 | } |
112 | 106 | ||
113 | static inline void fib6_walker_unlink(struct fib6_walker_t *w) | 107 | static inline void fib6_walker_unlink(struct fib6_walker_t *w) |
114 | { | 108 | { |
115 | write_lock_bh(&fib6_walker_lock); | 109 | write_lock_bh(&fib6_walker_lock); |
116 | w->next->prev = w->prev; | 110 | list_del(&w->lh); |
117 | w->prev->next = w->next; | ||
118 | w->prev = w->next = w; | ||
119 | write_unlock_bh(&fib6_walker_lock); | 111 | write_unlock_bh(&fib6_walker_lock); |
120 | } | 112 | } |
121 | static __inline__ u32 fib6_new_sernum(void) | 113 | static __inline__ u32 fib6_new_sernum(void) |
@@ -239,7 +231,7 @@ struct fib6_table *fib6_get_table(struct net *net, u32 id) | |||
239 | return NULL; | 231 | return NULL; |
240 | } | 232 | } |
241 | 233 | ||
242 | static void fib6_tables_init(struct net *net) | 234 | static void __net_init fib6_tables_init(struct net *net) |
243 | { | 235 | { |
244 | fib6_link_table(net, net->ipv6.fib6_main_tbl); | 236 | fib6_link_table(net, net->ipv6.fib6_main_tbl); |
245 | fib6_link_table(net, net->ipv6.fib6_local_tbl); | 237 | fib6_link_table(net, net->ipv6.fib6_local_tbl); |
@@ -262,7 +254,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); | 254 | return (struct dst_entry *) lookup(net, net->ipv6.fib6_main_tbl, fl, flags); |
263 | } | 255 | } |
264 | 256 | ||
265 | static void fib6_tables_init(struct net *net) | 257 | static void __net_init fib6_tables_init(struct net *net) |
266 | { | 258 | { |
267 | fib6_link_table(net, net->ipv6.fib6_main_tbl); | 259 | fib6_link_table(net, net->ipv6.fib6_main_tbl); |
268 | } | 260 | } |
@@ -319,12 +311,26 @@ static int fib6_dump_table(struct fib6_table *table, struct sk_buff *skb, | |||
319 | w->root = &table->tb6_root; | 311 | w->root = &table->tb6_root; |
320 | 312 | ||
321 | if (cb->args[4] == 0) { | 313 | if (cb->args[4] == 0) { |
314 | w->count = 0; | ||
315 | w->skip = 0; | ||
316 | |||
322 | read_lock_bh(&table->tb6_lock); | 317 | read_lock_bh(&table->tb6_lock); |
323 | res = fib6_walk(w); | 318 | res = fib6_walk(w); |
324 | read_unlock_bh(&table->tb6_lock); | 319 | read_unlock_bh(&table->tb6_lock); |
325 | if (res > 0) | 320 | if (res > 0) { |
326 | cb->args[4] = 1; | 321 | cb->args[4] = 1; |
322 | cb->args[5] = w->root->fn_sernum; | ||
323 | } | ||
327 | } else { | 324 | } else { |
325 | if (cb->args[5] != w->root->fn_sernum) { | ||
326 | /* Begin at the root if the tree changed */ | ||
327 | cb->args[5] = w->root->fn_sernum; | ||
328 | w->state = FWS_INIT; | ||
329 | w->node = w->root; | ||
330 | w->skip = w->count; | ||
331 | } else | ||
332 | w->skip = 0; | ||
333 | |||
328 | read_lock_bh(&table->tb6_lock); | 334 | read_lock_bh(&table->tb6_lock); |
329 | res = fib6_walk_continue(w); | 335 | res = fib6_walk_continue(w); |
330 | read_unlock_bh(&table->tb6_lock); | 336 | read_unlock_bh(&table->tb6_lock); |
@@ -1250,9 +1256,18 @@ static int fib6_walk_continue(struct fib6_walker_t *w) | |||
1250 | w->leaf = fn->leaf; | 1256 | w->leaf = fn->leaf; |
1251 | case FWS_C: | 1257 | case FWS_C: |
1252 | if (w->leaf && fn->fn_flags&RTN_RTINFO) { | 1258 | if (w->leaf && fn->fn_flags&RTN_RTINFO) { |
1253 | int err = w->func(w); | 1259 | int err; |
1260 | |||
1261 | if (w->count < w->skip) { | ||
1262 | w->count++; | ||
1263 | continue; | ||
1264 | } | ||
1265 | |||
1266 | err = w->func(w); | ||
1254 | if (err) | 1267 | if (err) |
1255 | return err; | 1268 | return err; |
1269 | |||
1270 | w->count++; | ||
1256 | continue; | 1271 | continue; |
1257 | } | 1272 | } |
1258 | w->state = FWS_U; | 1273 | w->state = FWS_U; |
@@ -1346,6 +1361,8 @@ static void fib6_clean_tree(struct net *net, struct fib6_node *root, | |||
1346 | c.w.root = root; | 1361 | c.w.root = root; |
1347 | c.w.func = fib6_clean_node; | 1362 | c.w.func = fib6_clean_node; |
1348 | c.w.prune = prune; | 1363 | c.w.prune = prune; |
1364 | c.w.count = 0; | ||
1365 | c.w.skip = 0; | ||
1349 | c.func = func; | 1366 | c.func = func; |
1350 | c.arg = arg; | 1367 | c.arg = arg; |
1351 | c.net = net; | 1368 | c.net = net; |
@@ -1469,7 +1486,7 @@ static void fib6_gc_timer_cb(unsigned long arg) | |||
1469 | fib6_run_gc(0, (struct net *)arg); | 1486 | fib6_run_gc(0, (struct net *)arg); |
1470 | } | 1487 | } |
1471 | 1488 | ||
1472 | static int fib6_net_init(struct net *net) | 1489 | static int __net_init fib6_net_init(struct net *net) |
1473 | { | 1490 | { |
1474 | setup_timer(&net->ipv6.ip6_fib_timer, fib6_gc_timer_cb, (unsigned long)net); | 1491 | setup_timer(&net->ipv6.ip6_fib_timer, fib6_gc_timer_cb, (unsigned long)net); |
1475 | 1492 | ||
diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c index 7712578bdc66..14e23216eb28 100644 --- a/net/ipv6/ip6_flowlabel.c +++ b/net/ipv6/ip6_flowlabel.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/route.h> | 20 | #include <linux/route.h> |
21 | #include <linux/proc_fs.h> | 21 | #include <linux/proc_fs.h> |
22 | #include <linux/seq_file.h> | 22 | #include <linux/seq_file.h> |
23 | #include <linux/slab.h> | ||
23 | 24 | ||
24 | #include <net/net_namespace.h> | 25 | #include <net/net_namespace.h> |
25 | #include <net/sock.h> | 26 | #include <net/sock.h> |
@@ -67,7 +68,7 @@ static inline struct ip6_flowlabel *__fl_lookup(struct net *net, __be32 label) | |||
67 | struct ip6_flowlabel *fl; | 68 | struct ip6_flowlabel *fl; |
68 | 69 | ||
69 | for (fl=fl_ht[FL_HASH(label)]; fl; fl = fl->next) { | 70 | for (fl=fl_ht[FL_HASH(label)]; fl; fl = fl->next) { |
70 | if (fl->label == label && fl->fl_net == net) | 71 | if (fl->label == label && net_eq(fl->fl_net, net)) |
71 | return fl; | 72 | return fl; |
72 | } | 73 | } |
73 | return NULL; | 74 | return NULL; |
@@ -154,7 +155,7 @@ static void ip6_fl_gc(unsigned long dummy) | |||
154 | write_unlock(&ip6_fl_lock); | 155 | write_unlock(&ip6_fl_lock); |
155 | } | 156 | } |
156 | 157 | ||
157 | static void ip6_fl_purge(struct net *net) | 158 | static void __net_exit ip6_fl_purge(struct net *net) |
158 | { | 159 | { |
159 | int i; | 160 | int i; |
160 | 161 | ||
@@ -163,7 +164,8 @@ static void ip6_fl_purge(struct net *net) | |||
163 | struct ip6_flowlabel *fl, **flp; | 164 | struct ip6_flowlabel *fl, **flp; |
164 | flp = &fl_ht[i]; | 165 | flp = &fl_ht[i]; |
165 | while ((fl = *flp) != NULL) { | 166 | while ((fl = *flp) != NULL) { |
166 | if (fl->fl_net == net && atomic_read(&fl->users) == 0) { | 167 | if (net_eq(fl->fl_net, net) && |
168 | atomic_read(&fl->users) == 0) { | ||
167 | *flp = fl->next; | 169 | *flp = fl->next; |
168 | fl_free(fl); | 170 | fl_free(fl); |
169 | atomic_dec(&fl_size); | 171 | atomic_dec(&fl_size); |
@@ -377,8 +379,8 @@ fl_create(struct net *net, struct in6_flowlabel_req *freq, char __user *optval, | |||
377 | goto done; | 379 | goto done; |
378 | fl->share = freq->flr_share; | 380 | fl->share = freq->flr_share; |
379 | addr_type = ipv6_addr_type(&freq->flr_dst); | 381 | addr_type = ipv6_addr_type(&freq->flr_dst); |
380 | if ((addr_type&IPV6_ADDR_MAPPED) | 382 | if ((addr_type & IPV6_ADDR_MAPPED) || |
381 | || addr_type == IPV6_ADDR_ANY) { | 383 | addr_type == IPV6_ADDR_ANY) { |
382 | err = -EINVAL; | 384 | err = -EINVAL; |
383 | goto done; | 385 | goto done; |
384 | } | 386 | } |
@@ -421,8 +423,8 @@ static int mem_check(struct sock *sk) | |||
421 | 423 | ||
422 | if (room <= 0 || | 424 | if (room <= 0 || |
423 | ((count >= FL_MAX_PER_SOCK || | 425 | ((count >= FL_MAX_PER_SOCK || |
424 | (count > 0 && room < FL_MAX_SIZE/2) || room < FL_MAX_SIZE/4) | 426 | (count > 0 && room < FL_MAX_SIZE/2) || room < FL_MAX_SIZE/4) && |
425 | && !capable(CAP_NET_ADMIN))) | 427 | !capable(CAP_NET_ADMIN))) |
426 | return -ENOBUFS; | 428 | return -ENOBUFS; |
427 | 429 | ||
428 | return 0; | 430 | return 0; |
@@ -630,7 +632,7 @@ static struct ip6_flowlabel *ip6fl_get_first(struct seq_file *seq) | |||
630 | for (state->bucket = 0; state->bucket <= FL_HASH_MASK; ++state->bucket) { | 632 | for (state->bucket = 0; state->bucket <= FL_HASH_MASK; ++state->bucket) { |
631 | fl = fl_ht[state->bucket]; | 633 | fl = fl_ht[state->bucket]; |
632 | 634 | ||
633 | while (fl && fl->fl_net != net) | 635 | while (fl && !net_eq(fl->fl_net, net)) |
634 | fl = fl->next; | 636 | fl = fl->next; |
635 | if (fl) | 637 | if (fl) |
636 | break; | 638 | break; |
@@ -645,7 +647,7 @@ static struct ip6_flowlabel *ip6fl_get_next(struct seq_file *seq, struct ip6_flo | |||
645 | 647 | ||
646 | fl = fl->next; | 648 | fl = fl->next; |
647 | try_again: | 649 | try_again: |
648 | while (fl && fl->fl_net != net) | 650 | while (fl && !net_eq(fl->fl_net, net)) |
649 | fl = fl->next; | 651 | fl = fl->next; |
650 | 652 | ||
651 | while (!fl) { | 653 | while (!fl) { |
@@ -734,7 +736,7 @@ static const struct file_operations ip6fl_seq_fops = { | |||
734 | .release = seq_release_net, | 736 | .release = seq_release_net, |
735 | }; | 737 | }; |
736 | 738 | ||
737 | static int ip6_flowlabel_proc_init(struct net *net) | 739 | static int __net_init ip6_flowlabel_proc_init(struct net *net) |
738 | { | 740 | { |
739 | if (!proc_net_fops_create(net, "ip6_flowlabel", | 741 | if (!proc_net_fops_create(net, "ip6_flowlabel", |
740 | S_IRUGO, &ip6fl_seq_fops)) | 742 | S_IRUGO, &ip6fl_seq_fops)) |
@@ -742,7 +744,7 @@ static int ip6_flowlabel_proc_init(struct net *net) | |||
742 | return 0; | 744 | return 0; |
743 | } | 745 | } |
744 | 746 | ||
745 | static void ip6_flowlabel_proc_fini(struct net *net) | 747 | static void __net_exit ip6_flowlabel_proc_fini(struct net *net) |
746 | { | 748 | { |
747 | proc_net_remove(net, "ip6_flowlabel"); | 749 | proc_net_remove(net, "ip6_flowlabel"); |
748 | } | 750 | } |
@@ -753,11 +755,10 @@ static inline int ip6_flowlabel_proc_init(struct net *net) | |||
753 | } | 755 | } |
754 | static inline void ip6_flowlabel_proc_fini(struct net *net) | 756 | static inline void ip6_flowlabel_proc_fini(struct net *net) |
755 | { | 757 | { |
756 | return ; | ||
757 | } | 758 | } |
758 | #endif | 759 | #endif |
759 | 760 | ||
760 | static inline void ip6_flowlabel_net_exit(struct net *net) | 761 | static void __net_exit ip6_flowlabel_net_exit(struct net *net) |
761 | { | 762 | { |
762 | ip6_fl_purge(net); | 763 | ip6_fl_purge(net); |
763 | ip6_flowlabel_proc_fini(net); | 764 | ip6_flowlabel_proc_fini(net); |
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c index 237e2dba6e94..6aa7ee1295c2 100644 --- a/net/ipv6/ip6_input.c +++ b/net/ipv6/ip6_input.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/in6.h> | 28 | #include <linux/in6.h> |
29 | #include <linux/icmpv6.h> | 29 | #include <linux/icmpv6.h> |
30 | #include <linux/mroute6.h> | 30 | #include <linux/mroute6.h> |
31 | #include <linux/slab.h> | ||
31 | 32 | ||
32 | #include <linux/netfilter.h> | 33 | #include <linux/netfilter.h> |
33 | #include <linux/netfilter_ipv6.h> | 34 | #include <linux/netfilter_ipv6.h> |
@@ -216,8 +217,7 @@ resubmit: | |||
216 | IP6_INC_STATS_BH(net, idev, | 217 | IP6_INC_STATS_BH(net, idev, |
217 | IPSTATS_MIB_INUNKNOWNPROTOS); | 218 | IPSTATS_MIB_INUNKNOWNPROTOS); |
218 | icmpv6_send(skb, ICMPV6_PARAMPROB, | 219 | icmpv6_send(skb, ICMPV6_PARAMPROB, |
219 | ICMPV6_UNK_NEXTHDR, nhoff, | 220 | ICMPV6_UNK_NEXTHDR, nhoff); |
220 | skb->dev); | ||
221 | } | 221 | } |
222 | } else | 222 | } else |
223 | IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_INDELIVERS); | 223 | IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_INDELIVERS); |
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index cd48801a8d6f..75d5ef830097 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c | |||
@@ -37,6 +37,7 @@ | |||
37 | #include <linux/tcp.h> | 37 | #include <linux/tcp.h> |
38 | #include <linux/route.h> | 38 | #include <linux/route.h> |
39 | #include <linux/module.h> | 39 | #include <linux/module.h> |
40 | #include <linux/slab.h> | ||
40 | 41 | ||
41 | #include <linux/netfilter.h> | 42 | #include <linux/netfilter.h> |
42 | #include <linux/netfilter_ipv6.h> | 43 | #include <linux/netfilter_ipv6.h> |
@@ -107,7 +108,7 @@ static int ip6_dev_loopback_xmit(struct sk_buff *newskb) | |||
107 | newskb->ip_summed = CHECKSUM_UNNECESSARY; | 108 | newskb->ip_summed = CHECKSUM_UNNECESSARY; |
108 | WARN_ON(!skb_dst(newskb)); | 109 | WARN_ON(!skb_dst(newskb)); |
109 | 110 | ||
110 | netif_rx(newskb); | 111 | netif_rx_ni(newskb); |
111 | return 0; | 112 | return 0; |
112 | } | 113 | } |
113 | 114 | ||
@@ -121,10 +122,9 @@ static int ip6_output2(struct sk_buff *skb) | |||
121 | skb->dev = dev; | 122 | skb->dev = dev; |
122 | 123 | ||
123 | if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr)) { | 124 | if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr)) { |
124 | struct ipv6_pinfo* np = skb->sk ? inet6_sk(skb->sk) : NULL; | ||
125 | struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb)); | 125 | struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb)); |
126 | 126 | ||
127 | if (!(dev->flags & IFF_LOOPBACK) && (!np || np->mc_loop) && | 127 | if (!(dev->flags & IFF_LOOPBACK) && sk_mc_loop(skb->sk) && |
128 | ((mroute6_socket(dev_net(dev)) && | 128 | ((mroute6_socket(dev_net(dev)) && |
129 | !(IP6CB(skb)->flags & IP6SKB_FORWARDED)) || | 129 | !(IP6CB(skb)->flags & IP6SKB_FORWARDED)) || |
130 | ipv6_chk_mcast_addr(dev, &ipv6_hdr(skb)->daddr, | 130 | ipv6_chk_mcast_addr(dev, &ipv6_hdr(skb)->daddr, |
@@ -268,7 +268,7 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl, | |||
268 | if (net_ratelimit()) | 268 | if (net_ratelimit()) |
269 | printk(KERN_DEBUG "IPv6: sending pkt_too_big to self\n"); | 269 | printk(KERN_DEBUG "IPv6: sending pkt_too_big to self\n"); |
270 | skb->dev = dst->dev; | 270 | skb->dev = dst->dev; |
271 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev); | 271 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); |
272 | IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_FRAGFAILS); | 272 | IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_FRAGFAILS); |
273 | kfree_skb(skb); | 273 | kfree_skb(skb); |
274 | return -EMSGSIZE; | 274 | return -EMSGSIZE; |
@@ -403,6 +403,7 @@ int ip6_forward(struct sk_buff *skb) | |||
403 | struct ipv6hdr *hdr = ipv6_hdr(skb); | 403 | struct ipv6hdr *hdr = ipv6_hdr(skb); |
404 | struct inet6_skb_parm *opt = IP6CB(skb); | 404 | struct inet6_skb_parm *opt = IP6CB(skb); |
405 | struct net *net = dev_net(dst->dev); | 405 | struct net *net = dev_net(dst->dev); |
406 | u32 mtu; | ||
406 | 407 | ||
407 | if (net->ipv6.devconf_all->forwarding == 0) | 408 | if (net->ipv6.devconf_all->forwarding == 0) |
408 | goto error; | 409 | goto error; |
@@ -442,8 +443,7 @@ int ip6_forward(struct sk_buff *skb) | |||
442 | if (hdr->hop_limit <= 1) { | 443 | if (hdr->hop_limit <= 1) { |
443 | /* Force OUTPUT device used as source address */ | 444 | /* Force OUTPUT device used as source address */ |
444 | skb->dev = dst->dev; | 445 | skb->dev = dst->dev; |
445 | icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT, | 446 | icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT, 0); |
446 | 0, skb->dev); | ||
447 | IP6_INC_STATS_BH(net, | 447 | IP6_INC_STATS_BH(net, |
448 | ip6_dst_idev(dst), IPSTATS_MIB_INHDRERRORS); | 448 | ip6_dst_idev(dst), IPSTATS_MIB_INHDRERRORS); |
449 | 449 | ||
@@ -505,15 +505,19 @@ int ip6_forward(struct sk_buff *skb) | |||
505 | goto error; | 505 | goto error; |
506 | if (addrtype & IPV6_ADDR_LINKLOCAL) { | 506 | if (addrtype & IPV6_ADDR_LINKLOCAL) { |
507 | icmpv6_send(skb, ICMPV6_DEST_UNREACH, | 507 | icmpv6_send(skb, ICMPV6_DEST_UNREACH, |
508 | ICMPV6_NOT_NEIGHBOUR, 0, skb->dev); | 508 | ICMPV6_NOT_NEIGHBOUR, 0); |
509 | goto error; | 509 | goto error; |
510 | } | 510 | } |
511 | } | 511 | } |
512 | 512 | ||
513 | if (skb->len > dst_mtu(dst)) { | 513 | mtu = dst_mtu(dst); |
514 | if (mtu < IPV6_MIN_MTU) | ||
515 | mtu = IPV6_MIN_MTU; | ||
516 | |||
517 | if (skb->len > mtu) { | ||
514 | /* Again, force OUTPUT device used as source address */ | 518 | /* Again, force OUTPUT device used as source address */ |
515 | skb->dev = dst->dev; | 519 | skb->dev = dst->dev; |
516 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, dst_mtu(dst), skb->dev); | 520 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); |
517 | IP6_INC_STATS_BH(net, | 521 | IP6_INC_STATS_BH(net, |
518 | ip6_dst_idev(dst), IPSTATS_MIB_INTOOBIGERRORS); | 522 | ip6_dst_idev(dst), IPSTATS_MIB_INTOOBIGERRORS); |
519 | IP6_INC_STATS_BH(net, | 523 | IP6_INC_STATS_BH(net, |
@@ -623,12 +627,11 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) | |||
623 | mtu = ip6_skb_dst_mtu(skb); | 627 | mtu = ip6_skb_dst_mtu(skb); |
624 | 628 | ||
625 | /* We must not fragment if the socket is set to force MTU discovery | 629 | /* We must not fragment if the socket is set to force MTU discovery |
626 | * or if the skb it not generated by a local socket. (This last | 630 | * or if the skb it not generated by a local socket. |
627 | * check should be redundant, but it's free.) | ||
628 | */ | 631 | */ |
629 | if (!skb->local_df) { | 632 | if (!skb->local_df && skb->len > mtu) { |
630 | skb->dev = skb_dst(skb)->dev; | 633 | skb->dev = skb_dst(skb)->dev; |
631 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev); | 634 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); |
632 | IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), | 635 | IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), |
633 | IPSTATS_MIB_FRAGFAILS); | 636 | IPSTATS_MIB_FRAGFAILS); |
634 | kfree_skb(skb); | 637 | kfree_skb(skb); |
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index c595bbe1ed99..2599870747ec 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c | |||
@@ -37,6 +37,7 @@ | |||
37 | #include <linux/route.h> | 37 | #include <linux/route.h> |
38 | #include <linux/rtnetlink.h> | 38 | #include <linux/rtnetlink.h> |
39 | #include <linux/netfilter_ipv6.h> | 39 | #include <linux/netfilter_ipv6.h> |
40 | #include <linux/slab.h> | ||
40 | 41 | ||
41 | #include <asm/uaccess.h> | 42 | #include <asm/uaccess.h> |
42 | #include <asm/atomic.h> | 43 | #include <asm/atomic.h> |
@@ -74,11 +75,10 @@ MODULE_LICENSE("GPL"); | |||
74 | (addr)->s6_addr32[2] ^ (addr)->s6_addr32[3]) & \ | 75 | (addr)->s6_addr32[2] ^ (addr)->s6_addr32[3]) & \ |
75 | (HASH_SIZE - 1)) | 76 | (HASH_SIZE - 1)) |
76 | 77 | ||
77 | static void ip6_fb_tnl_dev_init(struct net_device *dev); | ||
78 | static void ip6_tnl_dev_init(struct net_device *dev); | 78 | static void ip6_tnl_dev_init(struct net_device *dev); |
79 | static void ip6_tnl_dev_setup(struct net_device *dev); | 79 | static void ip6_tnl_dev_setup(struct net_device *dev); |
80 | 80 | ||
81 | static int ip6_tnl_net_id; | 81 | static int ip6_tnl_net_id __read_mostly; |
82 | struct ip6_tnl_net { | 82 | struct ip6_tnl_net { |
83 | /* the IPv6 tunnel fallback device */ | 83 | /* the IPv6 tunnel fallback device */ |
84 | struct net_device *fb_tnl_dev; | 84 | struct net_device *fb_tnl_dev; |
@@ -88,8 +88,10 @@ struct ip6_tnl_net { | |||
88 | struct ip6_tnl **tnls[2]; | 88 | struct ip6_tnl **tnls[2]; |
89 | }; | 89 | }; |
90 | 90 | ||
91 | /* lock for the tunnel lists */ | 91 | /* |
92 | static DEFINE_RWLOCK(ip6_tnl_lock); | 92 | * Locking : hash tables are protected by RCU and a spinlock |
93 | */ | ||
94 | static DEFINE_SPINLOCK(ip6_tnl_lock); | ||
93 | 95 | ||
94 | static inline struct dst_entry *ip6_tnl_dst_check(struct ip6_tnl *t) | 96 | static inline struct dst_entry *ip6_tnl_dst_check(struct ip6_tnl *t) |
95 | { | 97 | { |
@@ -130,6 +132,9 @@ static inline void ip6_tnl_dst_store(struct ip6_tnl *t, struct dst_entry *dst) | |||
130 | * else %NULL | 132 | * else %NULL |
131 | **/ | 133 | **/ |
132 | 134 | ||
135 | #define for_each_ip6_tunnel_rcu(start) \ | ||
136 | for (t = rcu_dereference(start); t; t = rcu_dereference(t->next)) | ||
137 | |||
133 | static struct ip6_tnl * | 138 | static struct ip6_tnl * |
134 | ip6_tnl_lookup(struct net *net, struct in6_addr *remote, struct in6_addr *local) | 139 | ip6_tnl_lookup(struct net *net, struct in6_addr *remote, struct in6_addr *local) |
135 | { | 140 | { |
@@ -138,13 +143,14 @@ ip6_tnl_lookup(struct net *net, struct in6_addr *remote, struct in6_addr *local) | |||
138 | struct ip6_tnl *t; | 143 | struct ip6_tnl *t; |
139 | struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); | 144 | struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); |
140 | 145 | ||
141 | for (t = ip6n->tnls_r_l[h0 ^ h1]; t; t = t->next) { | 146 | for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[h0 ^ h1]) { |
142 | if (ipv6_addr_equal(local, &t->parms.laddr) && | 147 | if (ipv6_addr_equal(local, &t->parms.laddr) && |
143 | ipv6_addr_equal(remote, &t->parms.raddr) && | 148 | ipv6_addr_equal(remote, &t->parms.raddr) && |
144 | (t->dev->flags & IFF_UP)) | 149 | (t->dev->flags & IFF_UP)) |
145 | return t; | 150 | return t; |
146 | } | 151 | } |
147 | if ((t = ip6n->tnls_wc[0]) != NULL && (t->dev->flags & IFF_UP)) | 152 | t = rcu_dereference(ip6n->tnls_wc[0]); |
153 | if (t && (t->dev->flags & IFF_UP)) | ||
148 | return t; | 154 | return t; |
149 | 155 | ||
150 | return NULL; | 156 | return NULL; |
@@ -186,10 +192,10 @@ ip6_tnl_link(struct ip6_tnl_net *ip6n, struct ip6_tnl *t) | |||
186 | { | 192 | { |
187 | struct ip6_tnl **tp = ip6_tnl_bucket(ip6n, &t->parms); | 193 | struct ip6_tnl **tp = ip6_tnl_bucket(ip6n, &t->parms); |
188 | 194 | ||
195 | spin_lock_bh(&ip6_tnl_lock); | ||
189 | t->next = *tp; | 196 | t->next = *tp; |
190 | write_lock_bh(&ip6_tnl_lock); | 197 | rcu_assign_pointer(*tp, t); |
191 | *tp = t; | 198 | spin_unlock_bh(&ip6_tnl_lock); |
192 | write_unlock_bh(&ip6_tnl_lock); | ||
193 | } | 199 | } |
194 | 200 | ||
195 | /** | 201 | /** |
@@ -204,9 +210,9 @@ ip6_tnl_unlink(struct ip6_tnl_net *ip6n, struct ip6_tnl *t) | |||
204 | 210 | ||
205 | for (tp = ip6_tnl_bucket(ip6n, &t->parms); *tp; tp = &(*tp)->next) { | 211 | for (tp = ip6_tnl_bucket(ip6n, &t->parms); *tp; tp = &(*tp)->next) { |
206 | if (t == *tp) { | 212 | if (t == *tp) { |
207 | write_lock_bh(&ip6_tnl_lock); | 213 | spin_lock_bh(&ip6_tnl_lock); |
208 | *tp = t->next; | 214 | *tp = t->next; |
209 | write_unlock_bh(&ip6_tnl_lock); | 215 | spin_unlock_bh(&ip6_tnl_lock); |
210 | break; | 216 | break; |
211 | } | 217 | } |
212 | } | 218 | } |
@@ -313,9 +319,9 @@ ip6_tnl_dev_uninit(struct net_device *dev) | |||
313 | struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); | 319 | struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); |
314 | 320 | ||
315 | if (dev == ip6n->fb_tnl_dev) { | 321 | if (dev == ip6n->fb_tnl_dev) { |
316 | write_lock_bh(&ip6_tnl_lock); | 322 | spin_lock_bh(&ip6_tnl_lock); |
317 | ip6n->tnls_wc[0] = NULL; | 323 | ip6n->tnls_wc[0] = NULL; |
318 | write_unlock_bh(&ip6_tnl_lock); | 324 | spin_unlock_bh(&ip6_tnl_lock); |
319 | } else { | 325 | } else { |
320 | ip6_tnl_unlink(ip6n, t); | 326 | ip6_tnl_unlink(ip6n, t); |
321 | } | 327 | } |
@@ -409,7 +415,7 @@ ip6_tnl_err(struct sk_buff *skb, __u8 ipproto, struct inet6_skb_parm *opt, | |||
409 | in trouble since we might need the source address for further | 415 | in trouble since we might need the source address for further |
410 | processing of the error. */ | 416 | processing of the error. */ |
411 | 417 | ||
412 | read_lock(&ip6_tnl_lock); | 418 | rcu_read_lock(); |
413 | if ((t = ip6_tnl_lookup(dev_net(skb->dev), &ipv6h->daddr, | 419 | if ((t = ip6_tnl_lookup(dev_net(skb->dev), &ipv6h->daddr, |
414 | &ipv6h->saddr)) == NULL) | 420 | &ipv6h->saddr)) == NULL) |
415 | goto out; | 421 | goto out; |
@@ -482,7 +488,7 @@ ip6_tnl_err(struct sk_buff *skb, __u8 ipproto, struct inet6_skb_parm *opt, | |||
482 | *msg = rel_msg; | 488 | *msg = rel_msg; |
483 | 489 | ||
484 | out: | 490 | out: |
485 | read_unlock(&ip6_tnl_lock); | 491 | rcu_read_unlock(); |
486 | return err; | 492 | return err; |
487 | } | 493 | } |
488 | 494 | ||
@@ -617,7 +623,7 @@ ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
617 | if (rt && rt->rt6i_dev) | 623 | if (rt && rt->rt6i_dev) |
618 | skb2->dev = rt->rt6i_dev; | 624 | skb2->dev = rt->rt6i_dev; |
619 | 625 | ||
620 | icmpv6_send(skb2, rel_type, rel_code, rel_info, skb2->dev); | 626 | icmpv6_send(skb2, rel_type, rel_code, rel_info); |
621 | 627 | ||
622 | if (rt) | 628 | if (rt) |
623 | dst_release(&rt->u.dst); | 629 | dst_release(&rt->u.dst); |
@@ -652,6 +658,7 @@ static void ip6ip6_dscp_ecn_decapsulate(struct ip6_tnl *t, | |||
652 | IP6_ECN_set_ce(ipv6_hdr(skb)); | 658 | IP6_ECN_set_ce(ipv6_hdr(skb)); |
653 | } | 659 | } |
654 | 660 | ||
661 | /* called with rcu_read_lock() */ | ||
655 | static inline int ip6_tnl_rcv_ctl(struct ip6_tnl *t) | 662 | static inline int ip6_tnl_rcv_ctl(struct ip6_tnl *t) |
656 | { | 663 | { |
657 | struct ip6_tnl_parm *p = &t->parms; | 664 | struct ip6_tnl_parm *p = &t->parms; |
@@ -662,15 +669,13 @@ static inline int ip6_tnl_rcv_ctl(struct ip6_tnl *t) | |||
662 | struct net_device *ldev = NULL; | 669 | struct net_device *ldev = NULL; |
663 | 670 | ||
664 | if (p->link) | 671 | if (p->link) |
665 | ldev = dev_get_by_index(net, p->link); | 672 | ldev = dev_get_by_index_rcu(net, p->link); |
666 | 673 | ||
667 | if ((ipv6_addr_is_multicast(&p->laddr) || | 674 | if ((ipv6_addr_is_multicast(&p->laddr) || |
668 | likely(ipv6_chk_addr(net, &p->laddr, ldev, 0))) && | 675 | likely(ipv6_chk_addr(net, &p->laddr, ldev, 0))) && |
669 | likely(!ipv6_chk_addr(net, &p->raddr, NULL, 0))) | 676 | likely(!ipv6_chk_addr(net, &p->raddr, NULL, 0))) |
670 | ret = 1; | 677 | ret = 1; |
671 | 678 | ||
672 | if (ldev) | ||
673 | dev_put(ldev); | ||
674 | } | 679 | } |
675 | return ret; | 680 | return ret; |
676 | } | 681 | } |
@@ -693,23 +698,23 @@ static int ip6_tnl_rcv(struct sk_buff *skb, __u16 protocol, | |||
693 | struct ip6_tnl *t; | 698 | struct ip6_tnl *t; |
694 | struct ipv6hdr *ipv6h = ipv6_hdr(skb); | 699 | struct ipv6hdr *ipv6h = ipv6_hdr(skb); |
695 | 700 | ||
696 | read_lock(&ip6_tnl_lock); | 701 | rcu_read_lock(); |
697 | 702 | ||
698 | if ((t = ip6_tnl_lookup(dev_net(skb->dev), &ipv6h->saddr, | 703 | if ((t = ip6_tnl_lookup(dev_net(skb->dev), &ipv6h->saddr, |
699 | &ipv6h->daddr)) != NULL) { | 704 | &ipv6h->daddr)) != NULL) { |
700 | if (t->parms.proto != ipproto && t->parms.proto != 0) { | 705 | if (t->parms.proto != ipproto && t->parms.proto != 0) { |
701 | read_unlock(&ip6_tnl_lock); | 706 | rcu_read_unlock(); |
702 | goto discard; | 707 | goto discard; |
703 | } | 708 | } |
704 | 709 | ||
705 | if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) { | 710 | if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) { |
706 | read_unlock(&ip6_tnl_lock); | 711 | rcu_read_unlock(); |
707 | goto discard; | 712 | goto discard; |
708 | } | 713 | } |
709 | 714 | ||
710 | if (!ip6_tnl_rcv_ctl(t)) { | 715 | if (!ip6_tnl_rcv_ctl(t)) { |
711 | t->dev->stats.rx_dropped++; | 716 | t->dev->stats.rx_dropped++; |
712 | read_unlock(&ip6_tnl_lock); | 717 | rcu_read_unlock(); |
713 | goto discard; | 718 | goto discard; |
714 | } | 719 | } |
715 | secpath_reset(skb); | 720 | secpath_reset(skb); |
@@ -727,10 +732,10 @@ static int ip6_tnl_rcv(struct sk_buff *skb, __u16 protocol, | |||
727 | t->dev->stats.rx_packets++; | 732 | t->dev->stats.rx_packets++; |
728 | t->dev->stats.rx_bytes += skb->len; | 733 | t->dev->stats.rx_bytes += skb->len; |
729 | netif_rx(skb); | 734 | netif_rx(skb); |
730 | read_unlock(&ip6_tnl_lock); | 735 | rcu_read_unlock(); |
731 | return 0; | 736 | return 0; |
732 | } | 737 | } |
733 | read_unlock(&ip6_tnl_lock); | 738 | rcu_read_unlock(); |
734 | return 1; | 739 | return 1; |
735 | 740 | ||
736 | discard: | 741 | discard: |
@@ -798,8 +803,9 @@ static inline int ip6_tnl_xmit_ctl(struct ip6_tnl *t) | |||
798 | if (p->flags & IP6_TNL_F_CAP_XMIT) { | 803 | if (p->flags & IP6_TNL_F_CAP_XMIT) { |
799 | struct net_device *ldev = NULL; | 804 | struct net_device *ldev = NULL; |
800 | 805 | ||
806 | rcu_read_lock(); | ||
801 | if (p->link) | 807 | if (p->link) |
802 | ldev = dev_get_by_index(net, p->link); | 808 | ldev = dev_get_by_index_rcu(net, p->link); |
803 | 809 | ||
804 | if (unlikely(!ipv6_chk_addr(net, &p->laddr, ldev, 0))) | 810 | if (unlikely(!ipv6_chk_addr(net, &p->laddr, ldev, 0))) |
805 | printk(KERN_WARNING | 811 | printk(KERN_WARNING |
@@ -813,8 +819,7 @@ static inline int ip6_tnl_xmit_ctl(struct ip6_tnl *t) | |||
813 | p->name); | 819 | p->name); |
814 | else | 820 | else |
815 | ret = 1; | 821 | ret = 1; |
816 | if (ldev) | 822 | rcu_read_unlock(); |
817 | dev_put(ldev); | ||
818 | } | 823 | } |
819 | return ret; | 824 | return ret; |
820 | } | 825 | } |
@@ -1010,7 +1015,7 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev) | |||
1010 | tel = (struct ipv6_tlv_tnl_enc_lim *)&skb_network_header(skb)[offset]; | 1015 | tel = (struct ipv6_tlv_tnl_enc_lim *)&skb_network_header(skb)[offset]; |
1011 | if (tel->encap_limit == 0) { | 1016 | if (tel->encap_limit == 0) { |
1012 | icmpv6_send(skb, ICMPV6_PARAMPROB, | 1017 | icmpv6_send(skb, ICMPV6_PARAMPROB, |
1013 | ICMPV6_HDR_FIELD, offset + 2, skb->dev); | 1018 | ICMPV6_HDR_FIELD, offset + 2); |
1014 | return -1; | 1019 | return -1; |
1015 | } | 1020 | } |
1016 | encap_limit = tel->encap_limit - 1; | 1021 | encap_limit = tel->encap_limit - 1; |
@@ -1029,7 +1034,7 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev) | |||
1029 | err = ip6_tnl_xmit2(skb, dev, dsfield, &fl, encap_limit, &mtu); | 1034 | err = ip6_tnl_xmit2(skb, dev, dsfield, &fl, encap_limit, &mtu); |
1030 | if (err != 0) { | 1035 | if (err != 0) { |
1031 | if (err == -EMSGSIZE) | 1036 | if (err == -EMSGSIZE) |
1032 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, dev); | 1037 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); |
1033 | return -1; | 1038 | return -1; |
1034 | } | 1039 | } |
1035 | 1040 | ||
@@ -1359,7 +1364,7 @@ static void ip6_tnl_dev_init(struct net_device *dev) | |||
1359 | * Return: 0 | 1364 | * Return: 0 |
1360 | **/ | 1365 | **/ |
1361 | 1366 | ||
1362 | static void ip6_fb_tnl_dev_init(struct net_device *dev) | 1367 | static void __net_init ip6_fb_tnl_dev_init(struct net_device *dev) |
1363 | { | 1368 | { |
1364 | struct ip6_tnl *t = netdev_priv(dev); | 1369 | struct ip6_tnl *t = netdev_priv(dev); |
1365 | struct net *net = dev_net(dev); | 1370 | struct net *net = dev_net(dev); |
@@ -1383,33 +1388,29 @@ static struct xfrm6_tunnel ip6ip6_handler = { | |||
1383 | .priority = 1, | 1388 | .priority = 1, |
1384 | }; | 1389 | }; |
1385 | 1390 | ||
1386 | static void ip6_tnl_destroy_tunnels(struct ip6_tnl_net *ip6n) | 1391 | static void __net_exit ip6_tnl_destroy_tunnels(struct ip6_tnl_net *ip6n) |
1387 | { | 1392 | { |
1388 | int h; | 1393 | int h; |
1389 | struct ip6_tnl *t; | 1394 | struct ip6_tnl *t; |
1395 | LIST_HEAD(list); | ||
1390 | 1396 | ||
1391 | for (h = 0; h < HASH_SIZE; h++) { | 1397 | for (h = 0; h < HASH_SIZE; h++) { |
1392 | while ((t = ip6n->tnls_r_l[h]) != NULL) | 1398 | t = ip6n->tnls_r_l[h]; |
1393 | unregister_netdevice(t->dev); | 1399 | while (t != NULL) { |
1400 | unregister_netdevice_queue(t->dev, &list); | ||
1401 | t = t->next; | ||
1402 | } | ||
1394 | } | 1403 | } |
1395 | 1404 | ||
1396 | t = ip6n->tnls_wc[0]; | 1405 | t = ip6n->tnls_wc[0]; |
1397 | unregister_netdevice(t->dev); | 1406 | unregister_netdevice_queue(t->dev, &list); |
1407 | unregister_netdevice_many(&list); | ||
1398 | } | 1408 | } |
1399 | 1409 | ||
1400 | static int ip6_tnl_init_net(struct net *net) | 1410 | static int __net_init ip6_tnl_init_net(struct net *net) |
1401 | { | 1411 | { |
1412 | struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); | ||
1402 | int err; | 1413 | int err; |
1403 | struct ip6_tnl_net *ip6n; | ||
1404 | |||
1405 | err = -ENOMEM; | ||
1406 | ip6n = kzalloc(sizeof(struct ip6_tnl_net), GFP_KERNEL); | ||
1407 | if (ip6n == NULL) | ||
1408 | goto err_alloc; | ||
1409 | |||
1410 | err = net_assign_generic(net, ip6_tnl_net_id, ip6n); | ||
1411 | if (err < 0) | ||
1412 | goto err_assign; | ||
1413 | 1414 | ||
1414 | ip6n->tnls[0] = ip6n->tnls_wc; | 1415 | ip6n->tnls[0] = ip6n->tnls_wc; |
1415 | ip6n->tnls[1] = ip6n->tnls_r_l; | 1416 | ip6n->tnls[1] = ip6n->tnls_r_l; |
@@ -1432,27 +1433,23 @@ static int ip6_tnl_init_net(struct net *net) | |||
1432 | err_register: | 1433 | err_register: |
1433 | free_netdev(ip6n->fb_tnl_dev); | 1434 | free_netdev(ip6n->fb_tnl_dev); |
1434 | err_alloc_dev: | 1435 | err_alloc_dev: |
1435 | /* nothing */ | ||
1436 | err_assign: | ||
1437 | kfree(ip6n); | ||
1438 | err_alloc: | ||
1439 | return err; | 1436 | return err; |
1440 | } | 1437 | } |
1441 | 1438 | ||
1442 | static void ip6_tnl_exit_net(struct net *net) | 1439 | static void __net_exit ip6_tnl_exit_net(struct net *net) |
1443 | { | 1440 | { |
1444 | struct ip6_tnl_net *ip6n; | 1441 | struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); |
1445 | 1442 | ||
1446 | ip6n = net_generic(net, ip6_tnl_net_id); | ||
1447 | rtnl_lock(); | 1443 | rtnl_lock(); |
1448 | ip6_tnl_destroy_tunnels(ip6n); | 1444 | ip6_tnl_destroy_tunnels(ip6n); |
1449 | rtnl_unlock(); | 1445 | rtnl_unlock(); |
1450 | kfree(ip6n); | ||
1451 | } | 1446 | } |
1452 | 1447 | ||
1453 | static struct pernet_operations ip6_tnl_net_ops = { | 1448 | static struct pernet_operations ip6_tnl_net_ops = { |
1454 | .init = ip6_tnl_init_net, | 1449 | .init = ip6_tnl_init_net, |
1455 | .exit = ip6_tnl_exit_net, | 1450 | .exit = ip6_tnl_exit_net, |
1451 | .id = &ip6_tnl_net_id, | ||
1452 | .size = sizeof(struct ip6_tnl_net), | ||
1456 | }; | 1453 | }; |
1457 | 1454 | ||
1458 | /** | 1455 | /** |
@@ -1465,27 +1462,29 @@ static int __init ip6_tunnel_init(void) | |||
1465 | { | 1462 | { |
1466 | int err; | 1463 | int err; |
1467 | 1464 | ||
1468 | if (xfrm6_tunnel_register(&ip4ip6_handler, AF_INET)) { | 1465 | err = register_pernet_device(&ip6_tnl_net_ops); |
1466 | if (err < 0) | ||
1467 | goto out_pernet; | ||
1468 | |||
1469 | err = xfrm6_tunnel_register(&ip4ip6_handler, AF_INET); | ||
1470 | if (err < 0) { | ||
1469 | printk(KERN_ERR "ip6_tunnel init: can't register ip4ip6\n"); | 1471 | printk(KERN_ERR "ip6_tunnel init: can't register ip4ip6\n"); |
1470 | err = -EAGAIN; | 1472 | goto out_ip4ip6; |
1471 | goto out; | ||
1472 | } | 1473 | } |
1473 | 1474 | ||
1474 | if (xfrm6_tunnel_register(&ip6ip6_handler, AF_INET6)) { | 1475 | err = xfrm6_tunnel_register(&ip6ip6_handler, AF_INET6); |
1476 | if (err < 0) { | ||
1475 | printk(KERN_ERR "ip6_tunnel init: can't register ip6ip6\n"); | 1477 | printk(KERN_ERR "ip6_tunnel init: can't register ip6ip6\n"); |
1476 | err = -EAGAIN; | 1478 | goto out_ip6ip6; |
1477 | goto unreg_ip4ip6; | ||
1478 | } | 1479 | } |
1479 | 1480 | ||
1480 | err = register_pernet_gen_device(&ip6_tnl_net_id, &ip6_tnl_net_ops); | ||
1481 | if (err < 0) | ||
1482 | goto err_pernet; | ||
1483 | return 0; | 1481 | return 0; |
1484 | err_pernet: | 1482 | |
1485 | xfrm6_tunnel_deregister(&ip6ip6_handler, AF_INET6); | 1483 | out_ip6ip6: |
1486 | unreg_ip4ip6: | ||
1487 | xfrm6_tunnel_deregister(&ip4ip6_handler, AF_INET); | 1484 | xfrm6_tunnel_deregister(&ip4ip6_handler, AF_INET); |
1488 | out: | 1485 | out_ip4ip6: |
1486 | unregister_pernet_device(&ip6_tnl_net_ops); | ||
1487 | out_pernet: | ||
1489 | return err; | 1488 | return err; |
1490 | } | 1489 | } |
1491 | 1490 | ||
@@ -1501,7 +1500,7 @@ static void __exit ip6_tunnel_cleanup(void) | |||
1501 | if (xfrm6_tunnel_deregister(&ip6ip6_handler, AF_INET6)) | 1500 | if (xfrm6_tunnel_deregister(&ip6ip6_handler, AF_INET6)) |
1502 | printk(KERN_INFO "ip6_tunnel close: can't deregister ip6ip6\n"); | 1501 | printk(KERN_INFO "ip6_tunnel close: can't deregister ip6ip6\n"); |
1503 | 1502 | ||
1504 | unregister_pernet_gen_device(ip6_tnl_net_id, &ip6_tnl_net_ops); | 1503 | unregister_pernet_device(&ip6_tnl_net_ops); |
1505 | } | 1504 | } |
1506 | 1505 | ||
1507 | module_init(ip6_tunnel_init); | 1506 | module_init(ip6_tunnel_init); |
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 716153941fc4..3e333268db89 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <linux/proc_fs.h> | 33 | #include <linux/proc_fs.h> |
34 | #include <linux/seq_file.h> | 34 | #include <linux/seq_file.h> |
35 | #include <linux/init.h> | 35 | #include <linux/init.h> |
36 | #include <linux/slab.h> | ||
36 | #include <net/protocol.h> | 37 | #include <net/protocol.h> |
37 | #include <linux/skbuff.h> | 38 | #include <linux/skbuff.h> |
38 | #include <net/sock.h> | 39 | #include <net/sock.h> |
@@ -477,7 +478,7 @@ failure: | |||
477 | * Delete a VIF entry | 478 | * Delete a VIF entry |
478 | */ | 479 | */ |
479 | 480 | ||
480 | static int mif6_delete(struct net *net, int vifi) | 481 | static int mif6_delete(struct net *net, int vifi, struct list_head *head) |
481 | { | 482 | { |
482 | struct mif_device *v; | 483 | struct mif_device *v; |
483 | struct net_device *dev; | 484 | struct net_device *dev; |
@@ -519,7 +520,7 @@ static int mif6_delete(struct net *net, int vifi) | |||
519 | in6_dev->cnf.mc_forwarding--; | 520 | in6_dev->cnf.mc_forwarding--; |
520 | 521 | ||
521 | if (v->flags & MIFF_REGISTER) | 522 | if (v->flags & MIFF_REGISTER) |
522 | unregister_netdevice(dev); | 523 | unregister_netdevice_queue(dev, head); |
523 | 524 | ||
524 | dev_put(dev); | 525 | dev_put(dev); |
525 | return 0; | 526 | return 0; |
@@ -976,6 +977,7 @@ static int ip6mr_device_event(struct notifier_block *this, | |||
976 | struct net *net = dev_net(dev); | 977 | struct net *net = dev_net(dev); |
977 | struct mif_device *v; | 978 | struct mif_device *v; |
978 | int ct; | 979 | int ct; |
980 | LIST_HEAD(list); | ||
979 | 981 | ||
980 | if (event != NETDEV_UNREGISTER) | 982 | if (event != NETDEV_UNREGISTER) |
981 | return NOTIFY_DONE; | 983 | return NOTIFY_DONE; |
@@ -983,8 +985,10 @@ static int ip6mr_device_event(struct notifier_block *this, | |||
983 | v = &net->ipv6.vif6_table[0]; | 985 | v = &net->ipv6.vif6_table[0]; |
984 | for (ct = 0; ct < net->ipv6.maxvif; ct++, v++) { | 986 | for (ct = 0; ct < net->ipv6.maxvif; ct++, v++) { |
985 | if (v->dev == dev) | 987 | if (v->dev == dev) |
986 | mif6_delete(net, ct); | 988 | mif6_delete(net, ct, &list); |
987 | } | 989 | } |
990 | unregister_netdevice_many(&list); | ||
991 | |||
988 | return NOTIFY_DONE; | 992 | return NOTIFY_DONE; |
989 | } | 993 | } |
990 | 994 | ||
@@ -1110,6 +1114,9 @@ static int ip6mr_mfc_add(struct net *net, struct mf6cctl *mfc, int mrtsock) | |||
1110 | unsigned char ttls[MAXMIFS]; | 1114 | unsigned char ttls[MAXMIFS]; |
1111 | int i; | 1115 | int i; |
1112 | 1116 | ||
1117 | if (mfc->mf6cc_parent >= MAXMIFS) | ||
1118 | return -ENFILE; | ||
1119 | |||
1113 | memset(ttls, 255, MAXMIFS); | 1120 | memset(ttls, 255, MAXMIFS); |
1114 | for (i = 0; i < MAXMIFS; i++) { | 1121 | for (i = 0; i < MAXMIFS; i++) { |
1115 | if (IF_ISSET(i, &mfc->mf6cc_ifset)) | 1122 | if (IF_ISSET(i, &mfc->mf6cc_ifset)) |
@@ -1188,14 +1195,16 @@ static int ip6mr_mfc_add(struct net *net, struct mf6cctl *mfc, int mrtsock) | |||
1188 | static void mroute_clean_tables(struct net *net) | 1195 | static void mroute_clean_tables(struct net *net) |
1189 | { | 1196 | { |
1190 | int i; | 1197 | int i; |
1198 | LIST_HEAD(list); | ||
1191 | 1199 | ||
1192 | /* | 1200 | /* |
1193 | * Shut down all active vif entries | 1201 | * Shut down all active vif entries |
1194 | */ | 1202 | */ |
1195 | for (i = 0; i < net->ipv6.maxvif; i++) { | 1203 | for (i = 0; i < net->ipv6.maxvif; i++) { |
1196 | if (!(net->ipv6.vif6_table[i].flags & VIFF_STATIC)) | 1204 | if (!(net->ipv6.vif6_table[i].flags & VIFF_STATIC)) |
1197 | mif6_delete(net, i); | 1205 | mif6_delete(net, i, &list); |
1198 | } | 1206 | } |
1207 | unregister_netdevice_many(&list); | ||
1199 | 1208 | ||
1200 | /* | 1209 | /* |
1201 | * Wipe the cache | 1210 | * Wipe the cache |
@@ -1297,7 +1306,7 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns | |||
1297 | switch (optname) { | 1306 | switch (optname) { |
1298 | case MRT6_INIT: | 1307 | case MRT6_INIT: |
1299 | if (sk->sk_type != SOCK_RAW || | 1308 | if (sk->sk_type != SOCK_RAW || |
1300 | inet_sk(sk)->num != IPPROTO_ICMPV6) | 1309 | inet_sk(sk)->inet_num != IPPROTO_ICMPV6) |
1301 | return -EOPNOTSUPP; | 1310 | return -EOPNOTSUPP; |
1302 | if (optlen < sizeof(int)) | 1311 | if (optlen < sizeof(int)) |
1303 | return -EINVAL; | 1312 | return -EINVAL; |
@@ -1325,7 +1334,7 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns | |||
1325 | if (copy_from_user(&mifi, optval, sizeof(mifi_t))) | 1334 | if (copy_from_user(&mifi, optval, sizeof(mifi_t))) |
1326 | return -EFAULT; | 1335 | return -EFAULT; |
1327 | rtnl_lock(); | 1336 | rtnl_lock(); |
1328 | ret = mif6_delete(net, mifi); | 1337 | ret = mif6_delete(net, mifi, NULL); |
1329 | rtnl_unlock(); | 1338 | rtnl_unlock(); |
1330 | return ret; | 1339 | return ret; |
1331 | 1340 | ||
@@ -1687,17 +1696,20 @@ ip6mr_fill_mroute(struct sk_buff *skb, struct mfc6_cache *c, struct rtmsg *rtm) | |||
1687 | int ct; | 1696 | int ct; |
1688 | struct rtnexthop *nhp; | 1697 | struct rtnexthop *nhp; |
1689 | struct net *net = mfc6_net(c); | 1698 | struct net *net = mfc6_net(c); |
1690 | struct net_device *dev = net->ipv6.vif6_table[c->mf6c_parent].dev; | ||
1691 | u8 *b = skb_tail_pointer(skb); | 1699 | u8 *b = skb_tail_pointer(skb); |
1692 | struct rtattr *mp_head; | 1700 | struct rtattr *mp_head; |
1693 | 1701 | ||
1694 | if (dev) | 1702 | /* If cache is unresolved, don't try to parse IIF and OIF */ |
1695 | RTA_PUT(skb, RTA_IIF, 4, &dev->ifindex); | 1703 | if (c->mf6c_parent > MAXMIFS) |
1704 | return -ENOENT; | ||
1705 | |||
1706 | if (MIF_EXISTS(net, c->mf6c_parent)) | ||
1707 | RTA_PUT(skb, RTA_IIF, 4, &net->ipv6.vif6_table[c->mf6c_parent].dev->ifindex); | ||
1696 | 1708 | ||
1697 | mp_head = (struct rtattr *)skb_put(skb, RTA_LENGTH(0)); | 1709 | mp_head = (struct rtattr *)skb_put(skb, RTA_LENGTH(0)); |
1698 | 1710 | ||
1699 | for (ct = c->mfc_un.res.minvif; ct < c->mfc_un.res.maxvif; ct++) { | 1711 | for (ct = c->mfc_un.res.minvif; ct < c->mfc_un.res.maxvif; ct++) { |
1700 | if (c->mfc_un.res.ttls[ct] < 255) { | 1712 | if (MIF_EXISTS(net, ct) && c->mfc_un.res.ttls[ct] < 255) { |
1701 | if (skb_tailroom(skb) < RTA_ALIGN(RTA_ALIGN(sizeof(*nhp)) + 4)) | 1713 | if (skb_tailroom(skb) < RTA_ALIGN(RTA_ALIGN(sizeof(*nhp)) + 4)) |
1702 | goto rtattr_failure; | 1714 | goto rtattr_failure; |
1703 | nhp = (struct rtnexthop *)skb_put(skb, RTA_ALIGN(sizeof(*nhp))); | 1715 | nhp = (struct rtnexthop *)skb_put(skb, RTA_ALIGN(sizeof(*nhp))); |
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/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index 4f7aaf6996a3..33f60fca7aa7 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c | |||
@@ -36,6 +36,7 @@ | |||
36 | #include <linux/init.h> | 36 | #include <linux/init.h> |
37 | #include <linux/sysctl.h> | 37 | #include <linux/sysctl.h> |
38 | #include <linux/netfilter.h> | 38 | #include <linux/netfilter.h> |
39 | #include <linux/slab.h> | ||
39 | 40 | ||
40 | #include <net/sock.h> | 41 | #include <net/sock.h> |
41 | #include <net/snmp.h> | 42 | #include <net/snmp.h> |
@@ -64,7 +65,7 @@ int ip6_ra_control(struct sock *sk, int sel) | |||
64 | struct ip6_ra_chain *ra, *new_ra, **rap; | 65 | struct ip6_ra_chain *ra, *new_ra, **rap; |
65 | 66 | ||
66 | /* RA packet may be delivered ONLY to IPPROTO_RAW socket */ | 67 | /* RA packet may be delivered ONLY to IPPROTO_RAW socket */ |
67 | if (sk->sk_type != SOCK_RAW || inet_sk(sk)->num != IPPROTO_RAW) | 68 | if (sk->sk_type != SOCK_RAW || inet_sk(sk)->inet_num != IPPROTO_RAW) |
68 | return -ENOPROTOOPT; | 69 | return -ENOPROTOOPT; |
69 | 70 | ||
70 | new_ra = (sel>=0) ? kmalloc(sizeof(*new_ra), GFP_KERNEL) : NULL; | 71 | new_ra = (sel>=0) ? kmalloc(sizeof(*new_ra), GFP_KERNEL) : NULL; |
@@ -106,7 +107,7 @@ struct ipv6_txoptions *ipv6_update_options(struct sock *sk, | |||
106 | if (inet_sk(sk)->is_icsk) { | 107 | if (inet_sk(sk)->is_icsk) { |
107 | if (opt && | 108 | if (opt && |
108 | !((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE)) && | 109 | !((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE)) && |
109 | inet_sk(sk)->daddr != LOOPBACK4_IPV6) { | 110 | inet_sk(sk)->inet_daddr != LOOPBACK4_IPV6) { |
110 | struct inet_connection_sock *icsk = inet_csk(sk); | 111 | struct inet_connection_sock *icsk = inet_csk(sk); |
111 | icsk->icsk_ext_hdr_len = opt->opt_flen + opt->opt_nflen; | 112 | icsk->icsk_ext_hdr_len = opt->opt_flen + opt->opt_nflen; |
112 | icsk->icsk_sync_mss(sk, icsk->icsk_pmtu_cookie); | 113 | icsk->icsk_sync_mss(sk, icsk->icsk_pmtu_cookie); |
@@ -234,7 +235,7 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, | |||
234 | 235 | ||
235 | case IPV6_V6ONLY: | 236 | case IPV6_V6ONLY: |
236 | if (optlen < sizeof(int) || | 237 | if (optlen < sizeof(int) || |
237 | inet_sk(sk)->num) | 238 | inet_sk(sk)->inet_num) |
238 | goto e_inval; | 239 | goto e_inval; |
239 | np->ipv6only = valbool; | 240 | np->ipv6only = valbool; |
240 | retv = 0; | 241 | retv = 0; |
@@ -424,6 +425,7 @@ sticky_done: | |||
424 | 425 | ||
425 | fl.fl6_flowlabel = 0; | 426 | fl.fl6_flowlabel = 0; |
426 | fl.oif = sk->sk_bound_dev_if; | 427 | fl.oif = sk->sk_bound_dev_if; |
428 | fl.mark = sk->sk_mark; | ||
427 | 429 | ||
428 | if (optlen == 0) | 430 | if (optlen == 0) |
429 | goto update; | 431 | goto update; |
@@ -665,7 +667,7 @@ done: | |||
665 | case IPV6_MTU_DISCOVER: | 667 | case IPV6_MTU_DISCOVER: |
666 | if (optlen < sizeof(int)) | 668 | if (optlen < sizeof(int)) |
667 | goto e_inval; | 669 | goto e_inval; |
668 | if (val<0 || val>3) | 670 | if (val < IP_PMTUDISC_DONT || val > IP_PMTUDISC_PROBE) |
669 | goto e_inval; | 671 | goto e_inval; |
670 | np->pmtudisc = val; | 672 | np->pmtudisc = val; |
671 | retv = 0; | 673 | retv = 0; |
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index f9fcf690bd5d..c483ab9fd67b 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c | |||
@@ -43,6 +43,7 @@ | |||
43 | #include <linux/init.h> | 43 | #include <linux/init.h> |
44 | #include <linux/proc_fs.h> | 44 | #include <linux/proc_fs.h> |
45 | #include <linux/seq_file.h> | 45 | #include <linux/seq_file.h> |
46 | #include <linux/slab.h> | ||
46 | 47 | ||
47 | #include <linux/netfilter.h> | 48 | #include <linux/netfilter.h> |
48 | #include <linux/netfilter_ipv6.h> | 49 | #include <linux/netfilter_ipv6.h> |
@@ -793,10 +794,10 @@ static void mld_add_delrec(struct inet6_dev *idev, struct ifmcaddr6 *im) | |||
793 | } | 794 | } |
794 | spin_unlock_bh(&im->mca_lock); | 795 | spin_unlock_bh(&im->mca_lock); |
795 | 796 | ||
796 | write_lock_bh(&idev->mc_lock); | 797 | spin_lock_bh(&idev->mc_lock); |
797 | pmc->next = idev->mc_tomb; | 798 | pmc->next = idev->mc_tomb; |
798 | idev->mc_tomb = pmc; | 799 | idev->mc_tomb = pmc; |
799 | write_unlock_bh(&idev->mc_lock); | 800 | spin_unlock_bh(&idev->mc_lock); |
800 | } | 801 | } |
801 | 802 | ||
802 | static void mld_del_delrec(struct inet6_dev *idev, struct in6_addr *pmca) | 803 | static void mld_del_delrec(struct inet6_dev *idev, struct in6_addr *pmca) |
@@ -804,7 +805,7 @@ static void mld_del_delrec(struct inet6_dev *idev, struct in6_addr *pmca) | |||
804 | struct ifmcaddr6 *pmc, *pmc_prev; | 805 | struct ifmcaddr6 *pmc, *pmc_prev; |
805 | struct ip6_sf_list *psf, *psf_next; | 806 | struct ip6_sf_list *psf, *psf_next; |
806 | 807 | ||
807 | write_lock_bh(&idev->mc_lock); | 808 | spin_lock_bh(&idev->mc_lock); |
808 | pmc_prev = NULL; | 809 | pmc_prev = NULL; |
809 | for (pmc=idev->mc_tomb; pmc; pmc=pmc->next) { | 810 | for (pmc=idev->mc_tomb; pmc; pmc=pmc->next) { |
810 | if (ipv6_addr_equal(&pmc->mca_addr, pmca)) | 811 | if (ipv6_addr_equal(&pmc->mca_addr, pmca)) |
@@ -817,7 +818,8 @@ static void mld_del_delrec(struct inet6_dev *idev, struct in6_addr *pmca) | |||
817 | else | 818 | else |
818 | idev->mc_tomb = pmc->next; | 819 | idev->mc_tomb = pmc->next; |
819 | } | 820 | } |
820 | write_unlock_bh(&idev->mc_lock); | 821 | spin_unlock_bh(&idev->mc_lock); |
822 | |||
821 | if (pmc) { | 823 | if (pmc) { |
822 | for (psf=pmc->mca_tomb; psf; psf=psf_next) { | 824 | for (psf=pmc->mca_tomb; psf; psf=psf_next) { |
823 | psf_next = psf->sf_next; | 825 | psf_next = psf->sf_next; |
@@ -832,10 +834,10 @@ static void mld_clear_delrec(struct inet6_dev *idev) | |||
832 | { | 834 | { |
833 | struct ifmcaddr6 *pmc, *nextpmc; | 835 | struct ifmcaddr6 *pmc, *nextpmc; |
834 | 836 | ||
835 | write_lock_bh(&idev->mc_lock); | 837 | spin_lock_bh(&idev->mc_lock); |
836 | pmc = idev->mc_tomb; | 838 | pmc = idev->mc_tomb; |
837 | idev->mc_tomb = NULL; | 839 | idev->mc_tomb = NULL; |
838 | write_unlock_bh(&idev->mc_lock); | 840 | spin_unlock_bh(&idev->mc_lock); |
839 | 841 | ||
840 | for (; pmc; pmc = nextpmc) { | 842 | for (; pmc; pmc = nextpmc) { |
841 | nextpmc = pmc->next; | 843 | nextpmc = pmc->next; |
@@ -1696,7 +1698,7 @@ static void mld_send_cr(struct inet6_dev *idev) | |||
1696 | int type, dtype; | 1698 | int type, dtype; |
1697 | 1699 | ||
1698 | read_lock_bh(&idev->lock); | 1700 | read_lock_bh(&idev->lock); |
1699 | write_lock_bh(&idev->mc_lock); | 1701 | spin_lock(&idev->mc_lock); |
1700 | 1702 | ||
1701 | /* deleted MCA's */ | 1703 | /* deleted MCA's */ |
1702 | pmc_prev = NULL; | 1704 | pmc_prev = NULL; |
@@ -1730,7 +1732,7 @@ static void mld_send_cr(struct inet6_dev *idev) | |||
1730 | } else | 1732 | } else |
1731 | pmc_prev = pmc; | 1733 | pmc_prev = pmc; |
1732 | } | 1734 | } |
1733 | write_unlock_bh(&idev->mc_lock); | 1735 | spin_unlock(&idev->mc_lock); |
1734 | 1736 | ||
1735 | /* change recs */ | 1737 | /* change recs */ |
1736 | for (pmc=idev->mc_list; pmc; pmc=pmc->next) { | 1738 | for (pmc=idev->mc_list; pmc; pmc=pmc->next) { |
@@ -2311,7 +2313,7 @@ void ipv6_mc_up(struct inet6_dev *idev) | |||
2311 | void ipv6_mc_init_dev(struct inet6_dev *idev) | 2313 | void ipv6_mc_init_dev(struct inet6_dev *idev) |
2312 | { | 2314 | { |
2313 | write_lock_bh(&idev->lock); | 2315 | write_lock_bh(&idev->lock); |
2314 | rwlock_init(&idev->mc_lock); | 2316 | spin_lock_init(&idev->mc_lock); |
2315 | idev->mc_gq_running = 0; | 2317 | idev->mc_gq_running = 0; |
2316 | setup_timer(&idev->mc_gq_timer, mld_gq_timer_expire, | 2318 | setup_timer(&idev->mc_gq_timer, mld_gq_timer_expire, |
2317 | (unsigned long)idev); | 2319 | (unsigned long)idev); |
@@ -2375,9 +2377,9 @@ static inline struct ifmcaddr6 *igmp6_mc_get_first(struct seq_file *seq) | |||
2375 | struct net *net = seq_file_net(seq); | 2377 | struct net *net = seq_file_net(seq); |
2376 | 2378 | ||
2377 | state->idev = NULL; | 2379 | state->idev = NULL; |
2378 | for_each_netdev(net, state->dev) { | 2380 | for_each_netdev_rcu(net, state->dev) { |
2379 | struct inet6_dev *idev; | 2381 | struct inet6_dev *idev; |
2380 | idev = in6_dev_get(state->dev); | 2382 | idev = __in6_dev_get(state->dev); |
2381 | if (!idev) | 2383 | if (!idev) |
2382 | continue; | 2384 | continue; |
2383 | read_lock_bh(&idev->lock); | 2385 | read_lock_bh(&idev->lock); |
@@ -2387,7 +2389,6 @@ static inline struct ifmcaddr6 *igmp6_mc_get_first(struct seq_file *seq) | |||
2387 | break; | 2389 | break; |
2388 | } | 2390 | } |
2389 | read_unlock_bh(&idev->lock); | 2391 | read_unlock_bh(&idev->lock); |
2390 | in6_dev_put(idev); | ||
2391 | } | 2392 | } |
2392 | return im; | 2393 | return im; |
2393 | } | 2394 | } |
@@ -2398,16 +2399,15 @@ static struct ifmcaddr6 *igmp6_mc_get_next(struct seq_file *seq, struct ifmcaddr | |||
2398 | 2399 | ||
2399 | im = im->next; | 2400 | im = im->next; |
2400 | while (!im) { | 2401 | while (!im) { |
2401 | if (likely(state->idev != NULL)) { | 2402 | if (likely(state->idev != NULL)) |
2402 | read_unlock_bh(&state->idev->lock); | 2403 | read_unlock_bh(&state->idev->lock); |
2403 | in6_dev_put(state->idev); | 2404 | |
2404 | } | 2405 | state->dev = next_net_device_rcu(state->dev); |
2405 | state->dev = next_net_device(state->dev); | ||
2406 | if (!state->dev) { | 2406 | if (!state->dev) { |
2407 | state->idev = NULL; | 2407 | state->idev = NULL; |
2408 | break; | 2408 | break; |
2409 | } | 2409 | } |
2410 | state->idev = in6_dev_get(state->dev); | 2410 | state->idev = __in6_dev_get(state->dev); |
2411 | if (!state->idev) | 2411 | if (!state->idev) |
2412 | continue; | 2412 | continue; |
2413 | read_lock_bh(&state->idev->lock); | 2413 | read_lock_bh(&state->idev->lock); |
@@ -2426,31 +2426,31 @@ static struct ifmcaddr6 *igmp6_mc_get_idx(struct seq_file *seq, loff_t pos) | |||
2426 | } | 2426 | } |
2427 | 2427 | ||
2428 | static void *igmp6_mc_seq_start(struct seq_file *seq, loff_t *pos) | 2428 | static void *igmp6_mc_seq_start(struct seq_file *seq, loff_t *pos) |
2429 | __acquires(dev_base_lock) | 2429 | __acquires(RCU) |
2430 | { | 2430 | { |
2431 | read_lock(&dev_base_lock); | 2431 | rcu_read_lock(); |
2432 | return igmp6_mc_get_idx(seq, *pos); | 2432 | return igmp6_mc_get_idx(seq, *pos); |
2433 | } | 2433 | } |
2434 | 2434 | ||
2435 | static void *igmp6_mc_seq_next(struct seq_file *seq, void *v, loff_t *pos) | 2435 | static void *igmp6_mc_seq_next(struct seq_file *seq, void *v, loff_t *pos) |
2436 | { | 2436 | { |
2437 | struct ifmcaddr6 *im; | 2437 | struct ifmcaddr6 *im = igmp6_mc_get_next(seq, v); |
2438 | im = igmp6_mc_get_next(seq, v); | 2438 | |
2439 | ++*pos; | 2439 | ++*pos; |
2440 | return im; | 2440 | return im; |
2441 | } | 2441 | } |
2442 | 2442 | ||
2443 | static void igmp6_mc_seq_stop(struct seq_file *seq, void *v) | 2443 | static void igmp6_mc_seq_stop(struct seq_file *seq, void *v) |
2444 | __releases(dev_base_lock) | 2444 | __releases(RCU) |
2445 | { | 2445 | { |
2446 | struct igmp6_mc_iter_state *state = igmp6_mc_seq_private(seq); | 2446 | struct igmp6_mc_iter_state *state = igmp6_mc_seq_private(seq); |
2447 | |||
2447 | if (likely(state->idev != NULL)) { | 2448 | if (likely(state->idev != NULL)) { |
2448 | read_unlock_bh(&state->idev->lock); | 2449 | read_unlock_bh(&state->idev->lock); |
2449 | in6_dev_put(state->idev); | ||
2450 | state->idev = NULL; | 2450 | state->idev = NULL; |
2451 | } | 2451 | } |
2452 | state->dev = NULL; | 2452 | state->dev = NULL; |
2453 | read_unlock(&dev_base_lock); | 2453 | rcu_read_unlock(); |
2454 | } | 2454 | } |
2455 | 2455 | ||
2456 | static int igmp6_mc_seq_show(struct seq_file *seq, void *v) | 2456 | static int igmp6_mc_seq_show(struct seq_file *seq, void *v) |
@@ -2507,9 +2507,9 @@ static inline struct ip6_sf_list *igmp6_mcf_get_first(struct seq_file *seq) | |||
2507 | 2507 | ||
2508 | state->idev = NULL; | 2508 | state->idev = NULL; |
2509 | state->im = NULL; | 2509 | state->im = NULL; |
2510 | for_each_netdev(net, state->dev) { | 2510 | for_each_netdev_rcu(net, state->dev) { |
2511 | struct inet6_dev *idev; | 2511 | struct inet6_dev *idev; |
2512 | idev = in6_dev_get(state->dev); | 2512 | idev = __in6_dev_get(state->dev); |
2513 | if (unlikely(idev == NULL)) | 2513 | if (unlikely(idev == NULL)) |
2514 | continue; | 2514 | continue; |
2515 | read_lock_bh(&idev->lock); | 2515 | read_lock_bh(&idev->lock); |
@@ -2525,7 +2525,6 @@ static inline struct ip6_sf_list *igmp6_mcf_get_first(struct seq_file *seq) | |||
2525 | spin_unlock_bh(&im->mca_lock); | 2525 | spin_unlock_bh(&im->mca_lock); |
2526 | } | 2526 | } |
2527 | read_unlock_bh(&idev->lock); | 2527 | read_unlock_bh(&idev->lock); |
2528 | in6_dev_put(idev); | ||
2529 | } | 2528 | } |
2530 | return psf; | 2529 | return psf; |
2531 | } | 2530 | } |
@@ -2539,16 +2538,15 @@ static struct ip6_sf_list *igmp6_mcf_get_next(struct seq_file *seq, struct ip6_s | |||
2539 | spin_unlock_bh(&state->im->mca_lock); | 2538 | spin_unlock_bh(&state->im->mca_lock); |
2540 | state->im = state->im->next; | 2539 | state->im = state->im->next; |
2541 | while (!state->im) { | 2540 | while (!state->im) { |
2542 | if (likely(state->idev != NULL)) { | 2541 | if (likely(state->idev != NULL)) |
2543 | read_unlock_bh(&state->idev->lock); | 2542 | read_unlock_bh(&state->idev->lock); |
2544 | in6_dev_put(state->idev); | 2543 | |
2545 | } | 2544 | state->dev = next_net_device_rcu(state->dev); |
2546 | state->dev = next_net_device(state->dev); | ||
2547 | if (!state->dev) { | 2545 | if (!state->dev) { |
2548 | state->idev = NULL; | 2546 | state->idev = NULL; |
2549 | goto out; | 2547 | goto out; |
2550 | } | 2548 | } |
2551 | state->idev = in6_dev_get(state->dev); | 2549 | state->idev = __in6_dev_get(state->dev); |
2552 | if (!state->idev) | 2550 | if (!state->idev) |
2553 | continue; | 2551 | continue; |
2554 | read_lock_bh(&state->idev->lock); | 2552 | read_lock_bh(&state->idev->lock); |
@@ -2573,9 +2571,9 @@ static struct ip6_sf_list *igmp6_mcf_get_idx(struct seq_file *seq, loff_t pos) | |||
2573 | } | 2571 | } |
2574 | 2572 | ||
2575 | static void *igmp6_mcf_seq_start(struct seq_file *seq, loff_t *pos) | 2573 | static void *igmp6_mcf_seq_start(struct seq_file *seq, loff_t *pos) |
2576 | __acquires(dev_base_lock) | 2574 | __acquires(RCU) |
2577 | { | 2575 | { |
2578 | read_lock(&dev_base_lock); | 2576 | rcu_read_lock(); |
2579 | return *pos ? igmp6_mcf_get_idx(seq, *pos - 1) : SEQ_START_TOKEN; | 2577 | return *pos ? igmp6_mcf_get_idx(seq, *pos - 1) : SEQ_START_TOKEN; |
2580 | } | 2578 | } |
2581 | 2579 | ||
@@ -2591,7 +2589,7 @@ static void *igmp6_mcf_seq_next(struct seq_file *seq, void *v, loff_t *pos) | |||
2591 | } | 2589 | } |
2592 | 2590 | ||
2593 | static void igmp6_mcf_seq_stop(struct seq_file *seq, void *v) | 2591 | static void igmp6_mcf_seq_stop(struct seq_file *seq, void *v) |
2594 | __releases(dev_base_lock) | 2592 | __releases(RCU) |
2595 | { | 2593 | { |
2596 | struct igmp6_mcf_iter_state *state = igmp6_mcf_seq_private(seq); | 2594 | struct igmp6_mcf_iter_state *state = igmp6_mcf_seq_private(seq); |
2597 | if (likely(state->im != NULL)) { | 2595 | if (likely(state->im != NULL)) { |
@@ -2600,11 +2598,10 @@ static void igmp6_mcf_seq_stop(struct seq_file *seq, void *v) | |||
2600 | } | 2598 | } |
2601 | if (likely(state->idev != NULL)) { | 2599 | if (likely(state->idev != NULL)) { |
2602 | read_unlock_bh(&state->idev->lock); | 2600 | read_unlock_bh(&state->idev->lock); |
2603 | in6_dev_put(state->idev); | ||
2604 | state->idev = NULL; | 2601 | state->idev = NULL; |
2605 | } | 2602 | } |
2606 | state->dev = NULL; | 2603 | state->dev = NULL; |
2607 | read_unlock(&dev_base_lock); | 2604 | rcu_read_unlock(); |
2608 | } | 2605 | } |
2609 | 2606 | ||
2610 | static int igmp6_mcf_seq_show(struct seq_file *seq, void *v) | 2607 | static int igmp6_mcf_seq_show(struct seq_file *seq, void *v) |
@@ -2651,7 +2648,7 @@ static const struct file_operations igmp6_mcf_seq_fops = { | |||
2651 | .release = seq_release_net, | 2648 | .release = seq_release_net, |
2652 | }; | 2649 | }; |
2653 | 2650 | ||
2654 | static int igmp6_proc_init(struct net *net) | 2651 | static int __net_init igmp6_proc_init(struct net *net) |
2655 | { | 2652 | { |
2656 | int err; | 2653 | int err; |
2657 | 2654 | ||
@@ -2671,23 +2668,22 @@ out_proc_net_igmp6: | |||
2671 | goto out; | 2668 | goto out; |
2672 | } | 2669 | } |
2673 | 2670 | ||
2674 | static void igmp6_proc_exit(struct net *net) | 2671 | static void __net_exit igmp6_proc_exit(struct net *net) |
2675 | { | 2672 | { |
2676 | proc_net_remove(net, "mcfilter6"); | 2673 | proc_net_remove(net, "mcfilter6"); |
2677 | proc_net_remove(net, "igmp6"); | 2674 | proc_net_remove(net, "igmp6"); |
2678 | } | 2675 | } |
2679 | #else | 2676 | #else |
2680 | static int igmp6_proc_init(struct net *net) | 2677 | static inline int igmp6_proc_init(struct net *net) |
2681 | { | 2678 | { |
2682 | return 0; | 2679 | return 0; |
2683 | } | 2680 | } |
2684 | static void igmp6_proc_exit(struct net *net) | 2681 | static inline void igmp6_proc_exit(struct net *net) |
2685 | { | 2682 | { |
2686 | ; | ||
2687 | } | 2683 | } |
2688 | #endif | 2684 | #endif |
2689 | 2685 | ||
2690 | static int igmp6_net_init(struct net *net) | 2686 | static int __net_init igmp6_net_init(struct net *net) |
2691 | { | 2687 | { |
2692 | int err; | 2688 | int err; |
2693 | 2689 | ||
@@ -2713,7 +2709,7 @@ out_sock_create: | |||
2713 | goto out; | 2709 | goto out; |
2714 | } | 2710 | } |
2715 | 2711 | ||
2716 | static void igmp6_net_exit(struct net *net) | 2712 | static void __net_exit igmp6_net_exit(struct net *net) |
2717 | { | 2713 | { |
2718 | inet_ctl_sock_destroy(net->ipv6.igmp_sk); | 2714 | inet_ctl_sock_destroy(net->ipv6.igmp_sk); |
2719 | igmp6_proc_exit(net); | 2715 | 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 f74e4e2cdd06..da0a4d2adc69 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c | |||
@@ -59,6 +59,7 @@ | |||
59 | #include <linux/route.h> | 59 | #include <linux/route.h> |
60 | #include <linux/init.h> | 60 | #include <linux/init.h> |
61 | #include <linux/rcupdate.h> | 61 | #include <linux/rcupdate.h> |
62 | #include <linux/slab.h> | ||
62 | #ifdef CONFIG_SYSCTL | 63 | #ifdef CONFIG_SYSCTL |
63 | #include <linux/sysctl.h> | 64 | #include <linux/sysctl.h> |
64 | #endif | 65 | #endif |
@@ -598,6 +599,7 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, | |||
598 | icmp6h.icmp6_solicited = solicited; | 599 | icmp6h.icmp6_solicited = solicited; |
599 | icmp6h.icmp6_override = override; | 600 | icmp6h.icmp6_override = override; |
600 | 601 | ||
602 | inc_opt |= ifp->idev->cnf.force_tllao; | ||
601 | __ndisc_send(dev, neigh, daddr, src_addr, | 603 | __ndisc_send(dev, neigh, daddr, src_addr, |
602 | &icmp6h, solicited_addr, | 604 | &icmp6h, solicited_addr, |
603 | inc_opt ? ND_OPT_TARGET_LL_ADDR : 0); | 605 | inc_opt ? ND_OPT_TARGET_LL_ADDR : 0); |
@@ -1768,46 +1770,10 @@ int ndisc_ifinfo_sysctl_change(struct ctl_table *ctl, int write, void __user *bu | |||
1768 | return ret; | 1770 | return ret; |
1769 | } | 1771 | } |
1770 | 1772 | ||
1771 | int ndisc_ifinfo_sysctl_strategy(ctl_table *ctl, | ||
1772 | void __user *oldval, size_t __user *oldlenp, | ||
1773 | void __user *newval, size_t newlen) | ||
1774 | { | ||
1775 | struct net_device *dev = ctl->extra1; | ||
1776 | struct inet6_dev *idev; | ||
1777 | int ret; | ||
1778 | |||
1779 | if (ctl->ctl_name == NET_NEIGH_RETRANS_TIME || | ||
1780 | ctl->ctl_name == NET_NEIGH_REACHABLE_TIME) | ||
1781 | ndisc_warn_deprecated_sysctl(ctl, "procfs", dev ? dev->name : "default"); | ||
1782 | |||
1783 | switch (ctl->ctl_name) { | ||
1784 | case NET_NEIGH_REACHABLE_TIME: | ||
1785 | ret = sysctl_jiffies(ctl, oldval, oldlenp, newval, newlen); | ||
1786 | break; | ||
1787 | case NET_NEIGH_RETRANS_TIME_MS: | ||
1788 | case NET_NEIGH_REACHABLE_TIME_MS: | ||
1789 | ret = sysctl_ms_jiffies(ctl, oldval, oldlenp, newval, newlen); | ||
1790 | break; | ||
1791 | default: | ||
1792 | ret = 0; | ||
1793 | } | ||
1794 | |||
1795 | if (newval && newlen && ret > 0 && | ||
1796 | dev && (idev = in6_dev_get(dev)) != NULL) { | ||
1797 | if (ctl->ctl_name == NET_NEIGH_REACHABLE_TIME || | ||
1798 | ctl->ctl_name == NET_NEIGH_REACHABLE_TIME_MS) | ||
1799 | idev->nd_parms->reachable_time = neigh_rand_reach_time(idev->nd_parms->base_reachable_time); | ||
1800 | idev->tstamp = jiffies; | ||
1801 | inet6_ifinfo_notify(RTM_NEWLINK, idev); | ||
1802 | in6_dev_put(idev); | ||
1803 | } | ||
1804 | |||
1805 | return ret; | ||
1806 | } | ||
1807 | 1773 | ||
1808 | #endif | 1774 | #endif |
1809 | 1775 | ||
1810 | static int ndisc_net_init(struct net *net) | 1776 | static int __net_init ndisc_net_init(struct net *net) |
1811 | { | 1777 | { |
1812 | struct ipv6_pinfo *np; | 1778 | struct ipv6_pinfo *np; |
1813 | struct sock *sk; | 1779 | struct sock *sk; |
@@ -1832,7 +1798,7 @@ static int ndisc_net_init(struct net *net) | |||
1832 | return 0; | 1798 | return 0; |
1833 | } | 1799 | } |
1834 | 1800 | ||
1835 | static void ndisc_net_exit(struct net *net) | 1801 | static void __net_exit ndisc_net_exit(struct net *net) |
1836 | { | 1802 | { |
1837 | inet_ctl_sock_destroy(net->ipv6.ndisc_sk); | 1803 | inet_ctl_sock_destroy(net->ipv6.ndisc_sk); |
1838 | } | 1804 | } |
@@ -1855,10 +1821,8 @@ int __init ndisc_init(void) | |||
1855 | neigh_table_init(&nd_tbl); | 1821 | neigh_table_init(&nd_tbl); |
1856 | 1822 | ||
1857 | #ifdef CONFIG_SYSCTL | 1823 | #ifdef CONFIG_SYSCTL |
1858 | err = neigh_sysctl_register(NULL, &nd_tbl.parms, NET_IPV6, | 1824 | err = neigh_sysctl_register(NULL, &nd_tbl.parms, "ipv6", |
1859 | NET_IPV6_NEIGH, "ipv6", | 1825 | &ndisc_ifinfo_sysctl_change); |
1860 | &ndisc_ifinfo_sysctl_change, | ||
1861 | &ndisc_ifinfo_sysctl_strategy); | ||
1862 | if (err) | 1826 | if (err) |
1863 | goto out_unregister_pernet; | 1827 | goto out_unregister_pernet; |
1864 | #endif | 1828 | #endif |
diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c index 1cf3f0c6a959..6a68a74d14a3 100644 --- a/net/ipv6/netfilter/ip6_queue.c +++ b/net/ipv6/netfilter/ip6_queue.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <linux/proc_fs.h> | 25 | #include <linux/proc_fs.h> |
26 | #include <linux/seq_file.h> | 26 | #include <linux/seq_file.h> |
27 | #include <linux/mutex.h> | 27 | #include <linux/mutex.h> |
28 | #include <linux/slab.h> | ||
28 | #include <net/net_namespace.h> | 29 | #include <net/net_namespace.h> |
29 | #include <net/sock.h> | 30 | #include <net/sock.h> |
30 | #include <net/ipv6.h> | 31 | #include <net/ipv6.h> |
@@ -36,7 +37,6 @@ | |||
36 | 37 | ||
37 | #define IPQ_QMAX_DEFAULT 1024 | 38 | #define IPQ_QMAX_DEFAULT 1024 |
38 | #define IPQ_PROC_FS_NAME "ip6_queue" | 39 | #define IPQ_PROC_FS_NAME "ip6_queue" |
39 | #define NET_IPQ_QMAX 2088 | ||
40 | #define NET_IPQ_QMAX_NAME "ip6_queue_maxlen" | 40 | #define NET_IPQ_QMAX_NAME "ip6_queue_maxlen" |
41 | 41 | ||
42 | typedef int (*ipq_cmpfn)(struct nf_queue_entry *, unsigned long); | 42 | typedef int (*ipq_cmpfn)(struct nf_queue_entry *, unsigned long); |
@@ -499,10 +499,9 @@ ipq_rcv_nl_event(struct notifier_block *this, | |||
499 | { | 499 | { |
500 | struct netlink_notify *n = ptr; | 500 | struct netlink_notify *n = ptr; |
501 | 501 | ||
502 | if (event == NETLINK_URELEASE && | 502 | if (event == NETLINK_URELEASE && n->protocol == NETLINK_IP6_FW) { |
503 | n->protocol == NETLINK_IP6_FW && n->pid) { | ||
504 | write_lock_bh(&queue_lock); | 503 | write_lock_bh(&queue_lock); |
505 | if ((n->net == &init_net) && (n->pid == peer_pid)) | 504 | if ((net_eq(n->net, &init_net)) && (n->pid == peer_pid)) |
506 | __ipq_reset(); | 505 | __ipq_reset(); |
507 | write_unlock_bh(&queue_lock); | 506 | write_unlock_bh(&queue_lock); |
508 | } | 507 | } |
@@ -518,14 +517,13 @@ static struct ctl_table_header *ipq_sysctl_header; | |||
518 | 517 | ||
519 | static ctl_table ipq_table[] = { | 518 | static ctl_table ipq_table[] = { |
520 | { | 519 | { |
521 | .ctl_name = NET_IPQ_QMAX, | ||
522 | .procname = NET_IPQ_QMAX_NAME, | 520 | .procname = NET_IPQ_QMAX_NAME, |
523 | .data = &queue_maxlen, | 521 | .data = &queue_maxlen, |
524 | .maxlen = sizeof(queue_maxlen), | 522 | .maxlen = sizeof(queue_maxlen), |
525 | .mode = 0644, | 523 | .mode = 0644, |
526 | .proc_handler = proc_dointvec | 524 | .proc_handler = proc_dointvec |
527 | }, | 525 | }, |
528 | { .ctl_name = 0 } | 526 | { } |
529 | }; | 527 | }; |
530 | #endif | 528 | #endif |
531 | 529 | ||
@@ -625,7 +623,7 @@ cleanup_netlink_notifier: | |||
625 | static void __exit ip6_queue_fini(void) | 623 | static void __exit ip6_queue_fini(void) |
626 | { | 624 | { |
627 | nf_unregister_queue_handlers(&nfqh); | 625 | nf_unregister_queue_handlers(&nfqh); |
628 | synchronize_net(); | 626 | |
629 | ipq_flush(NULL, 0); | 627 | ipq_flush(NULL, 0); |
630 | 628 | ||
631 | #ifdef CONFIG_SYSCTL | 629 | #ifdef CONFIG_SYSCTL |
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index cc9f8ef303fd..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 |
@@ -105,9 +112,9 @@ ip6_packet_match(const struct sk_buff *skb, | |||
105 | #define FWINV(bool, invflg) ((bool) ^ !!(ip6info->invflags & (invflg))) | 112 | #define FWINV(bool, invflg) ((bool) ^ !!(ip6info->invflags & (invflg))) |
106 | 113 | ||
107 | if (FWINV(ipv6_masked_addr_cmp(&ipv6->saddr, &ip6info->smsk, | 114 | if (FWINV(ipv6_masked_addr_cmp(&ipv6->saddr, &ip6info->smsk, |
108 | &ip6info->src), IP6T_INV_SRCIP) | 115 | &ip6info->src), IP6T_INV_SRCIP) || |
109 | || FWINV(ipv6_masked_addr_cmp(&ipv6->daddr, &ip6info->dmsk, | 116 | FWINV(ipv6_masked_addr_cmp(&ipv6->daddr, &ip6info->dmsk, |
110 | &ip6info->dst), IP6T_INV_DSTIP)) { | 117 | &ip6info->dst), IP6T_INV_DSTIP)) { |
111 | dprintf("Source or dest mismatch.\n"); | 118 | dprintf("Source or dest mismatch.\n"); |
112 | /* | 119 | /* |
113 | dprintf("SRC: %u. Mask: %u. Target: %u.%s\n", ip->saddr, | 120 | dprintf("SRC: %u. Mask: %u. Target: %u.%s\n", ip->saddr, |
@@ -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 */ |
@@ -277,11 +290,11 @@ get_chainname_rulenum(struct ip6t_entry *s, struct ip6t_entry *e, | |||
277 | } else if (s == e) { | 290 | } else if (s == e) { |
278 | (*rulenum)++; | 291 | (*rulenum)++; |
279 | 292 | ||
280 | if (s->target_offset == sizeof(struct ip6t_entry) | 293 | if (s->target_offset == sizeof(struct ip6t_entry) && |
281 | && strcmp(t->target.u.kernel.target->name, | 294 | strcmp(t->target.u.kernel.target->name, |
282 | IP6T_STANDARD_TARGET) == 0 | 295 | IP6T_STANDARD_TARGET) == 0 && |
283 | && t->verdict < 0 | 296 | t->verdict < 0 && |
284 | && unconditional(&s->ipv6)) { | 297 | unconditional(&s->ipv6)) { |
285 | /* Tail of chains: STANDARD target (return/policy) */ | 298 | /* Tail of chains: STANDARD target (return/policy) */ |
286 | *comment = *chainname == hookname | 299 | *comment = *chainname == hookname |
287 | ? comments[NF_IP6_TRACE_COMMENT_POLICY] | 300 | ? comments[NF_IP6_TRACE_COMMENT_POLICY] |
@@ -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) || \ |
@@ -418,8 +437,8 @@ ip6t_do_table(struct sk_buff *skb, | |||
418 | back = get_entry(table_base, back->comefrom); | 437 | back = get_entry(table_base, back->comefrom); |
419 | continue; | 438 | continue; |
420 | } | 439 | } |
421 | if (table_base + v != ip6t_next_entry(e) | 440 | if (table_base + v != ip6t_next_entry(e) && |
422 | && !(e->ipv6.flags & IP6T_F_GOTO)) { | 441 | !(e->ipv6.flags & IP6T_F_GOTO)) { |
423 | /* Save old back ptr in next entry */ | 442 | /* Save old back ptr in next entry */ |
424 | struct ip6t_entry *next = ip6t_next_entry(e); | 443 | struct ip6t_entry *next = ip6t_next_entry(e); |
425 | next->comefrom = (void *)back - table_base; | 444 | next->comefrom = (void *)back - table_base; |
@@ -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)) { |
@@ -505,11 +524,11 @@ mark_source_chains(struct xt_table_info *newinfo, | |||
505 | e->comefrom |= ((1 << hook) | (1 << NF_INET_NUMHOOKS)); | 524 | e->comefrom |= ((1 << hook) | (1 << NF_INET_NUMHOOKS)); |
506 | 525 | ||
507 | /* Unconditional return/END. */ | 526 | /* Unconditional return/END. */ |
508 | if ((e->target_offset == sizeof(struct ip6t_entry) | 527 | if ((e->target_offset == sizeof(struct ip6t_entry) && |
509 | && (strcmp(t->target.u.user.name, | 528 | (strcmp(t->target.u.user.name, |
510 | IP6T_STANDARD_TARGET) == 0) | 529 | IP6T_STANDARD_TARGET) == 0) && |
511 | && t->verdict < 0 | 530 | t->verdict < 0 && |
512 | && unconditional(&e->ipv6)) || visited) { | 531 | unconditional(&e->ipv6)) || visited) { |
513 | unsigned int oldpos, size; | 532 | unsigned int oldpos, size; |
514 | 533 | ||
515 | if ((strcmp(t->target.u.user.name, | 534 | if ((strcmp(t->target.u.user.name, |
@@ -556,8 +575,8 @@ mark_source_chains(struct xt_table_info *newinfo, | |||
556 | int newpos = t->verdict; | 575 | int newpos = t->verdict; |
557 | 576 | ||
558 | if (strcmp(t->target.u.user.name, | 577 | if (strcmp(t->target.u.user.name, |
559 | IP6T_STANDARD_TARGET) == 0 | 578 | IP6T_STANDARD_TARGET) == 0 && |
560 | && newpos >= 0) { | 579 | newpos >= 0) { |
561 | if (newpos > newinfo->size - | 580 | if (newpos > newinfo->size - |
562 | sizeof(struct ip6t_entry)) { | 581 | sizeof(struct ip6t_entry)) { |
563 | duprintf("mark_source_chains: " | 582 | duprintf("mark_source_chains: " |
@@ -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,17 +778,16 @@ 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 | ||
770 | if ((unsigned long)e % __alignof__(struct ip6t_entry) != 0 | 789 | if ((unsigned long)e % __alignof__(struct ip6t_entry) != 0 || |
771 | || (unsigned char *)e + sizeof(struct ip6t_entry) >= limit) { | 790 | (unsigned char *)e + sizeof(struct ip6t_entry) >= limit) { |
772 | duprintf("Bad offset %p\n", e); | 791 | duprintf("Bad offset %p\n", e); |
773 | return -EINVAL; | 792 | return -EINVAL; |
774 | } | 793 | } |
@@ -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; |
@@ -1584,8 +1552,8 @@ check_compat_entry_size_and_hooks(struct compat_ip6t_entry *e, | |||
1584 | int ret, off, h; | 1552 | int ret, off, h; |
1585 | 1553 | ||
1586 | duprintf("check_compat_entry_size_and_hooks %p\n", e); | 1554 | duprintf("check_compat_entry_size_and_hooks %p\n", e); |
1587 | if ((unsigned long)e % __alignof__(struct compat_ip6t_entry) != 0 | 1555 | if ((unsigned long)e % __alignof__(struct compat_ip6t_entry) != 0 || |
1588 | || (unsigned char *)e + sizeof(struct compat_ip6t_entry) >= limit) { | 1556 | (unsigned char *)e + sizeof(struct compat_ip6t_entry) >= limit) { |
1589 | duprintf("Bad offset %p, limit = %p\n", e, limit); | 1557 | duprintf("Bad offset %p, limit = %p\n", e, limit); |
1590 | return -EINVAL; | 1558 | return -EINVAL; |
1591 | } | 1559 | } |
@@ -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_LOG.c b/net/ipv6/netfilter/ip6t_LOG.c index 7018cac4fddc..b285fdf19050 100644 --- a/net/ipv6/netfilter/ip6t_LOG.c +++ b/net/ipv6/netfilter/ip6t_LOG.c | |||
@@ -249,8 +249,8 @@ static void dump_packet(const struct nf_loginfo *info, | |||
249 | /* Max length: 11 "URGP=65535 " */ | 249 | /* Max length: 11 "URGP=65535 " */ |
250 | printk("URGP=%u ", ntohs(th->urg_ptr)); | 250 | printk("URGP=%u ", ntohs(th->urg_ptr)); |
251 | 251 | ||
252 | if ((logflags & IP6T_LOG_TCPOPT) | 252 | if ((logflags & IP6T_LOG_TCPOPT) && |
253 | && th->doff * 4 > sizeof(struct tcphdr)) { | 253 | th->doff * 4 > sizeof(struct tcphdr)) { |
254 | u_int8_t _opt[60 - sizeof(struct tcphdr)]; | 254 | u_int8_t _opt[60 - sizeof(struct tcphdr)]; |
255 | const u_int8_t *op; | 255 | const u_int8_t *op; |
256 | unsigned int i; | 256 | unsigned int i; |
diff --git a/net/ipv6/netfilter/ip6t_REJECT.c b/net/ipv6/netfilter/ip6t_REJECT.c index 5a7f00cd15ce..39b50c3768e8 100644 --- a/net/ipv6/netfilter/ip6t_REJECT.c +++ b/net/ipv6/netfilter/ip6t_REJECT.c | |||
@@ -15,6 +15,7 @@ | |||
15 | * 2 of the License, or (at your option) any later version. | 15 | * 2 of the License, or (at your option) any later version. |
16 | */ | 16 | */ |
17 | 17 | ||
18 | #include <linux/gfp.h> | ||
18 | #include <linux/module.h> | 19 | #include <linux/module.h> |
19 | #include <linux/skbuff.h> | 20 | #include <linux/skbuff.h> |
20 | #include <linux/icmpv6.h> | 21 | #include <linux/icmpv6.h> |
@@ -169,7 +170,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) | 170 | if (hooknum == NF_INET_LOCAL_OUT && skb_in->dev == NULL) |
170 | skb_in->dev = net->loopback_dev; | 171 | skb_in->dev = net->loopback_dev; |
171 | 172 | ||
172 | icmpv6_send(skb_in, ICMPV6_DEST_UNREACH, code, 0, NULL); | 173 | icmpv6_send(skb_in, ICMPV6_DEST_UNREACH, code, 0); |
173 | } | 174 | } |
174 | 175 | ||
175 | static unsigned int | 176 | static unsigned int |
@@ -223,8 +224,8 @@ static bool reject_tg6_check(const struct xt_tgchk_param *par) | |||
223 | return false; | 224 | return false; |
224 | } else if (rejinfo->with == IP6T_TCP_RESET) { | 225 | } else if (rejinfo->with == IP6T_TCP_RESET) { |
225 | /* Must specify that it's a TCP packet */ | 226 | /* Must specify that it's a TCP packet */ |
226 | if (e->ipv6.proto != IPPROTO_TCP | 227 | if (e->ipv6.proto != IPPROTO_TCP || |
227 | || (e->ipv6.invflags & XT_INV_PROTO)) { | 228 | (e->ipv6.invflags & XT_INV_PROTO)) { |
228 | printk("ip6t_REJECT: TCP_RESET illegal for non-tcp\n"); | 229 | printk("ip6t_REJECT: TCP_RESET illegal for non-tcp\n"); |
229 | return false; | 230 | return false; |
230 | } | 231 | } |
diff --git a/net/ipv6/netfilter/ip6t_ah.c b/net/ipv6/netfilter/ip6t_ah.c index 3a82f24746b9..ac0b7c629d78 100644 --- a/net/ipv6/netfilter/ip6t_ah.c +++ b/net/ipv6/netfilter/ip6t_ah.c | |||
@@ -77,17 +77,14 @@ static bool ah_mt6(const struct sk_buff *skb, const struct xt_match_param *par) | |||
77 | ahinfo->hdrres, ah->reserved, | 77 | ahinfo->hdrres, ah->reserved, |
78 | !(ahinfo->hdrres && ah->reserved)); | 78 | !(ahinfo->hdrres && ah->reserved)); |
79 | 79 | ||
80 | return (ah != NULL) | 80 | return (ah != NULL) && |
81 | && | 81 | spi_match(ahinfo->spis[0], ahinfo->spis[1], |
82 | spi_match(ahinfo->spis[0], ahinfo->spis[1], | 82 | ntohl(ah->spi), |
83 | ntohl(ah->spi), | 83 | !!(ahinfo->invflags & IP6T_AH_INV_SPI)) && |
84 | !!(ahinfo->invflags & IP6T_AH_INV_SPI)) | 84 | (!ahinfo->hdrlen || |
85 | && | 85 | (ahinfo->hdrlen == hdrlen) ^ |
86 | (!ahinfo->hdrlen || | 86 | !!(ahinfo->invflags & IP6T_AH_INV_LEN)) && |
87 | (ahinfo->hdrlen == hdrlen) ^ | 87 | !(ahinfo->hdrres && ah->reserved); |
88 | !!(ahinfo->invflags & IP6T_AH_INV_LEN)) | ||
89 | && | ||
90 | !(ahinfo->hdrres && ah->reserved); | ||
91 | } | 88 | } |
92 | 89 | ||
93 | static bool ah_mt6_check(const struct xt_mtchk_param *par) | 90 | static bool ah_mt6_check(const struct xt_mtchk_param *par) |
diff --git a/net/ipv6/netfilter/ip6t_frag.c b/net/ipv6/netfilter/ip6t_frag.c index 673aa0a5084e..7b91c2598ed5 100644 --- a/net/ipv6/netfilter/ip6t_frag.c +++ b/net/ipv6/netfilter/ip6t_frag.c | |||
@@ -70,41 +70,36 @@ frag_mt6(const struct sk_buff *skb, const struct xt_match_param *par) | |||
70 | pr_debug("res %02X %02X%04X %02X ", | 70 | pr_debug("res %02X %02X%04X %02X ", |
71 | fraginfo->flags & IP6T_FRAG_RES, fh->reserved, | 71 | fraginfo->flags & IP6T_FRAG_RES, fh->reserved, |
72 | ntohs(fh->frag_off) & 0x6, | 72 | ntohs(fh->frag_off) & 0x6, |
73 | !((fraginfo->flags & IP6T_FRAG_RES) | 73 | !((fraginfo->flags & IP6T_FRAG_RES) && |
74 | && (fh->reserved || (ntohs(fh->frag_off) & 0x06)))); | 74 | (fh->reserved || (ntohs(fh->frag_off) & 0x06)))); |
75 | pr_debug("first %02X %02X %02X ", | 75 | pr_debug("first %02X %02X %02X ", |
76 | fraginfo->flags & IP6T_FRAG_FST, | 76 | fraginfo->flags & IP6T_FRAG_FST, |
77 | ntohs(fh->frag_off) & ~0x7, | 77 | ntohs(fh->frag_off) & ~0x7, |
78 | !((fraginfo->flags & IP6T_FRAG_FST) | 78 | !((fraginfo->flags & IP6T_FRAG_FST) && |
79 | && (ntohs(fh->frag_off) & ~0x7))); | 79 | (ntohs(fh->frag_off) & ~0x7))); |
80 | pr_debug("mf %02X %02X %02X ", | 80 | pr_debug("mf %02X %02X %02X ", |
81 | fraginfo->flags & IP6T_FRAG_MF, | 81 | fraginfo->flags & IP6T_FRAG_MF, |
82 | ntohs(fh->frag_off) & IP6_MF, | 82 | ntohs(fh->frag_off) & IP6_MF, |
83 | !((fraginfo->flags & IP6T_FRAG_MF) | 83 | !((fraginfo->flags & IP6T_FRAG_MF) && |
84 | && !((ntohs(fh->frag_off) & IP6_MF)))); | 84 | !((ntohs(fh->frag_off) & IP6_MF)))); |
85 | pr_debug("last %02X %02X %02X\n", | 85 | pr_debug("last %02X %02X %02X\n", |
86 | fraginfo->flags & IP6T_FRAG_NMF, | 86 | fraginfo->flags & IP6T_FRAG_NMF, |
87 | ntohs(fh->frag_off) & IP6_MF, | 87 | ntohs(fh->frag_off) & IP6_MF, |
88 | !((fraginfo->flags & IP6T_FRAG_NMF) | 88 | !((fraginfo->flags & IP6T_FRAG_NMF) && |
89 | && (ntohs(fh->frag_off) & IP6_MF))); | 89 | (ntohs(fh->frag_off) & IP6_MF))); |
90 | 90 | ||
91 | return (fh != NULL) | 91 | return (fh != NULL) && |
92 | && | 92 | id_match(fraginfo->ids[0], fraginfo->ids[1], |
93 | id_match(fraginfo->ids[0], fraginfo->ids[1], | 93 | ntohl(fh->identification), |
94 | ntohl(fh->identification), | 94 | !!(fraginfo->invflags & IP6T_FRAG_INV_IDS)) && |
95 | !!(fraginfo->invflags & IP6T_FRAG_INV_IDS)) | 95 | !((fraginfo->flags & IP6T_FRAG_RES) && |
96 | && | 96 | (fh->reserved || (ntohs(fh->frag_off) & 0x6))) && |
97 | !((fraginfo->flags & IP6T_FRAG_RES) | 97 | !((fraginfo->flags & IP6T_FRAG_FST) && |
98 | && (fh->reserved || (ntohs(fh->frag_off) & 0x6))) | 98 | (ntohs(fh->frag_off) & ~0x7)) && |
99 | && | 99 | !((fraginfo->flags & IP6T_FRAG_MF) && |
100 | !((fraginfo->flags & IP6T_FRAG_FST) | 100 | !(ntohs(fh->frag_off) & IP6_MF)) && |
101 | && (ntohs(fh->frag_off) & ~0x7)) | 101 | !((fraginfo->flags & IP6T_FRAG_NMF) && |
102 | && | 102 | (ntohs(fh->frag_off) & IP6_MF)); |
103 | !((fraginfo->flags & IP6T_FRAG_MF) | ||
104 | && !(ntohs(fh->frag_off) & IP6_MF)) | ||
105 | && | ||
106 | !((fraginfo->flags & IP6T_FRAG_NMF) | ||
107 | && (ntohs(fh->frag_off) & IP6_MF)); | ||
108 | } | 103 | } |
109 | 104 | ||
110 | static bool frag_mt6_check(const struct xt_mtchk_param *par) | 105 | static bool frag_mt6_check(const struct xt_mtchk_param *par) |
diff --git a/net/ipv6/netfilter/ip6t_rt.c b/net/ipv6/netfilter/ip6t_rt.c index 356b8d6f6baa..b77307fc8743 100644 --- a/net/ipv6/netfilter/ip6t_rt.c +++ b/net/ipv6/netfilter/ip6t_rt.c | |||
@@ -92,16 +92,13 @@ static bool rt_mt6(const struct sk_buff *skb, const struct xt_match_param *par) | |||
92 | !((rtinfo->flags & IP6T_RT_RES) && | 92 | !((rtinfo->flags & IP6T_RT_RES) && |
93 | (((const struct rt0_hdr *)rh)->reserved))); | 93 | (((const struct rt0_hdr *)rh)->reserved))); |
94 | 94 | ||
95 | ret = (rh != NULL) | 95 | ret = (rh != NULL) && |
96 | && | ||
97 | (segsleft_match(rtinfo->segsleft[0], rtinfo->segsleft[1], | 96 | (segsleft_match(rtinfo->segsleft[0], rtinfo->segsleft[1], |
98 | rh->segments_left, | 97 | rh->segments_left, |
99 | !!(rtinfo->invflags & IP6T_RT_INV_SGS))) | 98 | !!(rtinfo->invflags & IP6T_RT_INV_SGS))) && |
100 | && | ||
101 | (!(rtinfo->flags & IP6T_RT_LEN) || | 99 | (!(rtinfo->flags & IP6T_RT_LEN) || |
102 | ((rtinfo->hdrlen == hdrlen) ^ | 100 | ((rtinfo->hdrlen == hdrlen) ^ |
103 | !!(rtinfo->invflags & IP6T_RT_INV_LEN))) | 101 | !!(rtinfo->invflags & IP6T_RT_INV_LEN))) && |
104 | && | ||
105 | (!(rtinfo->flags & IP6T_RT_TYP) || | 102 | (!(rtinfo->flags & IP6T_RT_TYP) || |
106 | ((rtinfo->rt_type == rh->type) ^ | 103 | ((rtinfo->rt_type == rh->type) ^ |
107 | !!(rtinfo->invflags & IP6T_RT_INV_TYP))); | 104 | !!(rtinfo->invflags & IP6T_RT_INV_TYP))); |
diff --git a/net/ipv6/netfilter/ip6table_filter.c b/net/ipv6/netfilter/ip6table_filter.c index 6f4383ad86f9..d6fc9aff3163 100644 --- a/net/ipv6/netfilter/ip6table_filter.c +++ b/net/ipv6/netfilter/ip6table_filter.c | |||
@@ -12,6 +12,7 @@ | |||
12 | #include <linux/module.h> | 12 | #include <linux/module.h> |
13 | #include <linux/moduleparam.h> | 13 | #include <linux/moduleparam.h> |
14 | #include <linux/netfilter_ipv6/ip6_tables.h> | 14 | #include <linux/netfilter_ipv6/ip6_tables.h> |
15 | #include <linux/slab.h> | ||
15 | 16 | ||
16 | MODULE_LICENSE("GPL"); | 17 | MODULE_LICENSE("GPL"); |
17 | MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>"); | 18 | MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>"); |
@@ -21,99 +22,26 @@ MODULE_DESCRIPTION("ip6tables filter table"); | |||
21 | (1 << NF_INET_FORWARD) | \ | 22 | (1 << NF_INET_FORWARD) | \ |
22 | (1 << NF_INET_LOCAL_OUT)) | 23 | (1 << NF_INET_LOCAL_OUT)) |
23 | 24 | ||
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 = { | 25 | static const struct xt_table packet_filter = { |
55 | .name = "filter", | 26 | .name = "filter", |
56 | .valid_hooks = FILTER_VALID_HOOKS, | 27 | .valid_hooks = FILTER_VALID_HOOKS, |
57 | .me = THIS_MODULE, | 28 | .me = THIS_MODULE, |
58 | .af = NFPROTO_IPV6, | 29 | .af = NFPROTO_IPV6, |
30 | .priority = NF_IP6_PRI_FILTER, | ||
59 | }; | 31 | }; |
60 | 32 | ||
61 | /* The work comes in here from netfilter.c. */ | 33 | /* The work comes in here from netfilter.c. */ |
62 | static unsigned int | 34 | static unsigned int |
63 | ip6t_in_hook(unsigned int hook, | 35 | ip6table_filter_hook(unsigned int hook, struct sk_buff *skb, |
64 | struct sk_buff *skb, | 36 | const struct net_device *in, const struct net_device *out, |
65 | const struct net_device *in, | 37 | 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 | { | 38 | { |
80 | #if 0 | 39 | 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 | 40 | ||
90 | return ip6t_do_table(skb, hook, in, out, | 41 | return ip6t_do_table(skb, hook, in, out, net->ipv6.ip6table_filter); |
91 | dev_net(out)->ipv6.ip6table_filter); | ||
92 | } | 42 | } |
93 | 43 | ||
94 | static struct nf_hook_ops ip6t_ops[] __read_mostly = { | 44 | 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 | 45 | ||
118 | /* Default to forward because I got too much mail already. */ | 46 | /* Default to forward because I got too much mail already. */ |
119 | static int forward = NF_ACCEPT; | 47 | static int forward = NF_ACCEPT; |
@@ -121,9 +49,18 @@ module_param(forward, bool, 0000); | |||
121 | 49 | ||
122 | static int __net_init ip6table_filter_net_init(struct net *net) | 50 | static int __net_init ip6table_filter_net_init(struct net *net) |
123 | { | 51 | { |
124 | /* Register table */ | 52 | struct ip6t_replace *repl; |
53 | |||
54 | repl = ip6t_alloc_initial_table(&packet_filter); | ||
55 | if (repl == NULL) | ||
56 | return -ENOMEM; | ||
57 | /* Entry 1 is the FORWARD hook */ | ||
58 | ((struct ip6t_standard *)repl->entries)[1].target.verdict = | ||
59 | -forward - 1; | ||
60 | |||
125 | net->ipv6.ip6table_filter = | 61 | net->ipv6.ip6table_filter = |
126 | ip6t_register_table(net, &packet_filter, &initial_table.repl); | 62 | ip6t_register_table(net, &packet_filter, repl); |
63 | kfree(repl); | ||
127 | if (IS_ERR(net->ipv6.ip6table_filter)) | 64 | if (IS_ERR(net->ipv6.ip6table_filter)) |
128 | return PTR_ERR(net->ipv6.ip6table_filter); | 65 | return PTR_ERR(net->ipv6.ip6table_filter); |
129 | return 0; | 66 | return 0; |
@@ -131,7 +68,7 @@ static int __net_init ip6table_filter_net_init(struct net *net) | |||
131 | 68 | ||
132 | static void __net_exit ip6table_filter_net_exit(struct net *net) | 69 | static void __net_exit ip6table_filter_net_exit(struct net *net) |
133 | { | 70 | { |
134 | ip6t_unregister_table(net->ipv6.ip6table_filter); | 71 | ip6t_unregister_table(net, net->ipv6.ip6table_filter); |
135 | } | 72 | } |
136 | 73 | ||
137 | static struct pernet_operations ip6table_filter_net_ops = { | 74 | static struct pernet_operations ip6table_filter_net_ops = { |
@@ -148,17 +85,16 @@ static int __init ip6table_filter_init(void) | |||
148 | return -EINVAL; | 85 | return -EINVAL; |
149 | } | 86 | } |
150 | 87 | ||
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); | 88 | ret = register_pernet_subsys(&ip6table_filter_net_ops); |
155 | if (ret < 0) | 89 | if (ret < 0) |
156 | return ret; | 90 | return ret; |
157 | 91 | ||
158 | /* Register hooks */ | 92 | /* Register hooks */ |
159 | ret = nf_register_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops)); | 93 | filter_ops = xt_hook_link(&packet_filter, ip6table_filter_hook); |
160 | if (ret < 0) | 94 | if (IS_ERR(filter_ops)) { |
95 | ret = PTR_ERR(filter_ops); | ||
161 | goto cleanup_table; | 96 | goto cleanup_table; |
97 | } | ||
162 | 98 | ||
163 | return ret; | 99 | return ret; |
164 | 100 | ||
@@ -169,7 +105,7 @@ static int __init ip6table_filter_init(void) | |||
169 | 105 | ||
170 | static void __exit ip6table_filter_fini(void) | 106 | static void __exit ip6table_filter_fini(void) |
171 | { | 107 | { |
172 | nf_unregister_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops)); | 108 | xt_hook_unlink(&packet_filter, filter_ops); |
173 | unregister_pernet_subsys(&ip6table_filter_net_ops); | 109 | unregister_pernet_subsys(&ip6table_filter_net_ops); |
174 | } | 110 | } |
175 | 111 | ||
diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c index 0ad91433ed61..6a102b57f356 100644 --- a/net/ipv6/netfilter/ip6table_mangle.c +++ b/net/ipv6/netfilter/ip6table_mangle.c | |||
@@ -10,6 +10,7 @@ | |||
10 | */ | 10 | */ |
11 | #include <linux/module.h> | 11 | #include <linux/module.h> |
12 | #include <linux/netfilter_ipv6/ip6_tables.h> | 12 | #include <linux/netfilter_ipv6/ip6_tables.h> |
13 | #include <linux/slab.h> | ||
13 | 14 | ||
14 | MODULE_LICENSE("GPL"); | 15 | MODULE_LICENSE("GPL"); |
15 | MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>"); | 16 | MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>"); |
@@ -21,80 +22,17 @@ MODULE_DESCRIPTION("ip6tables mangle table"); | |||
21 | (1 << NF_INET_LOCAL_OUT) | \ | 22 | (1 << NF_INET_LOCAL_OUT) | \ |
22 | (1 << NF_INET_POST_ROUTING)) | 23 | (1 << NF_INET_POST_ROUTING)) |
23 | 24 | ||
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 = { | 25 | static const struct xt_table packet_mangler = { |
61 | .name = "mangle", | 26 | .name = "mangle", |
62 | .valid_hooks = MANGLE_VALID_HOOKS, | 27 | .valid_hooks = MANGLE_VALID_HOOKS, |
63 | .me = THIS_MODULE, | 28 | .me = THIS_MODULE, |
64 | .af = NFPROTO_IPV6, | 29 | .af = NFPROTO_IPV6, |
30 | .priority = NF_IP6_PRI_MANGLE, | ||
65 | }; | 31 | }; |
66 | 32 | ||
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 | 33 | static unsigned int |
91 | ip6t_local_out_hook(unsigned int hook, | 34 | 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 | { | 35 | { |
97 | |||
98 | unsigned int ret; | 36 | unsigned int ret; |
99 | struct in6_addr saddr, daddr; | 37 | struct in6_addr saddr, daddr; |
100 | u_int8_t hop_limit; | 38 | u_int8_t hop_limit; |
@@ -102,8 +40,8 @@ ip6t_local_out_hook(unsigned int hook, | |||
102 | 40 | ||
103 | #if 0 | 41 | #if 0 |
104 | /* root is playing with raw sockets. */ | 42 | /* root is playing with raw sockets. */ |
105 | if (skb->len < sizeof(struct iphdr) | 43 | if (skb->len < sizeof(struct iphdr) || |
106 | || ip_hdrlen(skb) < sizeof(struct iphdr)) { | 44 | ip_hdrlen(skb) < sizeof(struct iphdr)) { |
107 | if (net_ratelimit()) | 45 | if (net_ratelimit()) |
108 | printk("ip6t_hook: happy cracking.\n"); | 46 | printk("ip6t_hook: happy cracking.\n"); |
109 | return NF_ACCEPT; | 47 | return NF_ACCEPT; |
@@ -119,62 +57,46 @@ ip6t_local_out_hook(unsigned int hook, | |||
119 | /* flowlabel and prio (includes version, which shouldn't change either */ | 57 | /* flowlabel and prio (includes version, which shouldn't change either */ |
120 | flowlabel = *((u_int32_t *)ipv6_hdr(skb)); | 58 | flowlabel = *((u_int32_t *)ipv6_hdr(skb)); |
121 | 59 | ||
122 | ret = ip6t_do_table(skb, hook, in, out, | 60 | ret = ip6t_do_table(skb, NF_INET_LOCAL_OUT, NULL, out, |
123 | dev_net(out)->ipv6.ip6table_mangle); | 61 | dev_net(out)->ipv6.ip6table_mangle); |
124 | 62 | ||
125 | if (ret != NF_DROP && ret != NF_STOLEN | 63 | if (ret != NF_DROP && ret != NF_STOLEN && |
126 | && (memcmp(&ipv6_hdr(skb)->saddr, &saddr, sizeof(saddr)) | 64 | (memcmp(&ipv6_hdr(skb)->saddr, &saddr, sizeof(saddr)) || |
127 | || memcmp(&ipv6_hdr(skb)->daddr, &daddr, sizeof(daddr)) | 65 | memcmp(&ipv6_hdr(skb)->daddr, &daddr, sizeof(daddr)) || |
128 | || skb->mark != mark | 66 | skb->mark != mark || |
129 | || ipv6_hdr(skb)->hop_limit != hop_limit)) | 67 | ipv6_hdr(skb)->hop_limit != hop_limit)) |
130 | return ip6_route_me_harder(skb) == 0 ? ret : NF_DROP; | 68 | return ip6_route_me_harder(skb) == 0 ? ret : NF_DROP; |
131 | 69 | ||
132 | return ret; | 70 | return ret; |
133 | } | 71 | } |
134 | 72 | ||
135 | static struct nf_hook_ops ip6t_ops[] __read_mostly = { | 73 | /* The work comes in here from netfilter.c. */ |
136 | { | 74 | static unsigned int |
137 | .hook = ip6t_in_hook, | 75 | ip6table_mangle_hook(unsigned int hook, struct sk_buff *skb, |
138 | .owner = THIS_MODULE, | 76 | const struct net_device *in, const struct net_device *out, |
139 | .pf = NFPROTO_IPV6, | 77 | int (*okfn)(struct sk_buff *)) |
140 | .hooknum = NF_INET_PRE_ROUTING, | 78 | { |
141 | .priority = NF_IP6_PRI_MANGLE, | 79 | if (hook == NF_INET_LOCAL_OUT) |
142 | }, | 80 | return ip6t_mangle_out(skb, out); |
143 | { | 81 | if (hook == NF_INET_POST_ROUTING) |
144 | .hook = ip6t_in_hook, | 82 | return ip6t_do_table(skb, hook, in, out, |
145 | .owner = THIS_MODULE, | 83 | dev_net(out)->ipv6.ip6table_mangle); |
146 | .pf = NFPROTO_IPV6, | 84 | /* INPUT/FORWARD */ |
147 | .hooknum = NF_INET_LOCAL_IN, | 85 | return ip6t_do_table(skb, hook, in, out, |
148 | .priority = NF_IP6_PRI_MANGLE, | 86 | dev_net(in)->ipv6.ip6table_mangle); |
149 | }, | 87 | } |
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 | 88 | ||
89 | static struct nf_hook_ops *mangle_ops __read_mostly; | ||
173 | static int __net_init ip6table_mangle_net_init(struct net *net) | 90 | static int __net_init ip6table_mangle_net_init(struct net *net) |
174 | { | 91 | { |
175 | /* Register table */ | 92 | struct ip6t_replace *repl; |
93 | |||
94 | repl = ip6t_alloc_initial_table(&packet_mangler); | ||
95 | if (repl == NULL) | ||
96 | return -ENOMEM; | ||
176 | net->ipv6.ip6table_mangle = | 97 | net->ipv6.ip6table_mangle = |
177 | ip6t_register_table(net, &packet_mangler, &initial_table.repl); | 98 | ip6t_register_table(net, &packet_mangler, repl); |
99 | kfree(repl); | ||
178 | if (IS_ERR(net->ipv6.ip6table_mangle)) | 100 | if (IS_ERR(net->ipv6.ip6table_mangle)) |
179 | return PTR_ERR(net->ipv6.ip6table_mangle); | 101 | return PTR_ERR(net->ipv6.ip6table_mangle); |
180 | return 0; | 102 | return 0; |
@@ -182,7 +104,7 @@ static int __net_init ip6table_mangle_net_init(struct net *net) | |||
182 | 104 | ||
183 | static void __net_exit ip6table_mangle_net_exit(struct net *net) | 105 | static void __net_exit ip6table_mangle_net_exit(struct net *net) |
184 | { | 106 | { |
185 | ip6t_unregister_table(net->ipv6.ip6table_mangle); | 107 | ip6t_unregister_table(net, net->ipv6.ip6table_mangle); |
186 | } | 108 | } |
187 | 109 | ||
188 | static struct pernet_operations ip6table_mangle_net_ops = { | 110 | static struct pernet_operations ip6table_mangle_net_ops = { |
@@ -199,9 +121,11 @@ static int __init ip6table_mangle_init(void) | |||
199 | return ret; | 121 | return ret; |
200 | 122 | ||
201 | /* Register hooks */ | 123 | /* Register hooks */ |
202 | ret = nf_register_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops)); | 124 | mangle_ops = xt_hook_link(&packet_mangler, ip6table_mangle_hook); |
203 | if (ret < 0) | 125 | if (IS_ERR(mangle_ops)) { |
126 | ret = PTR_ERR(mangle_ops); | ||
204 | goto cleanup_table; | 127 | goto cleanup_table; |
128 | } | ||
205 | 129 | ||
206 | return ret; | 130 | return ret; |
207 | 131 | ||
@@ -212,7 +136,7 @@ static int __init ip6table_mangle_init(void) | |||
212 | 136 | ||
213 | static void __exit ip6table_mangle_fini(void) | 137 | static void __exit ip6table_mangle_fini(void) |
214 | { | 138 | { |
215 | nf_unregister_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops)); | 139 | xt_hook_unlink(&packet_mangler, mangle_ops); |
216 | unregister_pernet_subsys(&ip6table_mangle_net_ops); | 140 | unregister_pernet_subsys(&ip6table_mangle_net_ops); |
217 | } | 141 | } |
218 | 142 | ||
diff --git a/net/ipv6/netfilter/ip6table_raw.c b/net/ipv6/netfilter/ip6table_raw.c index ed1a1180f3b3..5b9926a011bd 100644 --- a/net/ipv6/netfilter/ip6table_raw.c +++ b/net/ipv6/netfilter/ip6table_raw.c | |||
@@ -5,88 +5,41 @@ | |||
5 | */ | 5 | */ |
6 | #include <linux/module.h> | 6 | #include <linux/module.h> |
7 | #include <linux/netfilter_ipv6/ip6_tables.h> | 7 | #include <linux/netfilter_ipv6/ip6_tables.h> |
8 | #include <linux/slab.h> | ||
8 | 9 | ||
9 | #define RAW_VALID_HOOKS ((1 << NF_INET_PRE_ROUTING) | (1 << NF_INET_LOCAL_OUT)) | 10 | #define RAW_VALID_HOOKS ((1 << NF_INET_PRE_ROUTING) | (1 << NF_INET_LOCAL_OUT)) |
10 | 11 | ||
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 = { | 12 | static const struct xt_table packet_raw = { |
39 | .name = "raw", | 13 | .name = "raw", |
40 | .valid_hooks = RAW_VALID_HOOKS, | 14 | .valid_hooks = RAW_VALID_HOOKS, |
41 | .me = THIS_MODULE, | 15 | .me = THIS_MODULE, |
42 | .af = NFPROTO_IPV6, | 16 | .af = NFPROTO_IPV6, |
17 | .priority = NF_IP6_PRI_RAW, | ||
43 | }; | 18 | }; |
44 | 19 | ||
45 | /* The work comes in here from netfilter.c. */ | 20 | /* The work comes in here from netfilter.c. */ |
46 | static unsigned int | 21 | static unsigned int |
47 | ip6t_pre_routing_hook(unsigned int hook, | 22 | ip6table_raw_hook(unsigned int hook, struct sk_buff *skb, |
48 | struct sk_buff *skb, | 23 | const struct net_device *in, const struct net_device *out, |
49 | const struct net_device *in, | 24 | int (*okfn)(struct sk_buff *)) |
50 | const struct net_device *out, | ||
51 | int (*okfn)(struct sk_buff *)) | ||
52 | { | 25 | { |
53 | return ip6t_do_table(skb, hook, in, out, | 26 | const struct net *net = dev_net((in != NULL) ? in : out); |
54 | dev_net(in)->ipv6.ip6table_raw); | ||
55 | } | ||
56 | 27 | ||
57 | static unsigned int | 28 | 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 | } | 29 | } |
67 | 30 | ||
68 | static struct nf_hook_ops ip6t_ops[] __read_mostly = { | 31 | 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 | 32 | ||
85 | static int __net_init ip6table_raw_net_init(struct net *net) | 33 | static int __net_init ip6table_raw_net_init(struct net *net) |
86 | { | 34 | { |
87 | /* Register table */ | 35 | struct ip6t_replace *repl; |
36 | |||
37 | repl = ip6t_alloc_initial_table(&packet_raw); | ||
38 | if (repl == NULL) | ||
39 | return -ENOMEM; | ||
88 | net->ipv6.ip6table_raw = | 40 | net->ipv6.ip6table_raw = |
89 | ip6t_register_table(net, &packet_raw, &initial_table.repl); | 41 | ip6t_register_table(net, &packet_raw, repl); |
42 | kfree(repl); | ||
90 | if (IS_ERR(net->ipv6.ip6table_raw)) | 43 | if (IS_ERR(net->ipv6.ip6table_raw)) |
91 | return PTR_ERR(net->ipv6.ip6table_raw); | 44 | return PTR_ERR(net->ipv6.ip6table_raw); |
92 | return 0; | 45 | return 0; |
@@ -94,7 +47,7 @@ static int __net_init ip6table_raw_net_init(struct net *net) | |||
94 | 47 | ||
95 | static void __net_exit ip6table_raw_net_exit(struct net *net) | 48 | static void __net_exit ip6table_raw_net_exit(struct net *net) |
96 | { | 49 | { |
97 | ip6t_unregister_table(net->ipv6.ip6table_raw); | 50 | ip6t_unregister_table(net, net->ipv6.ip6table_raw); |
98 | } | 51 | } |
99 | 52 | ||
100 | static struct pernet_operations ip6table_raw_net_ops = { | 53 | static struct pernet_operations ip6table_raw_net_ops = { |
@@ -111,9 +64,11 @@ static int __init ip6table_raw_init(void) | |||
111 | return ret; | 64 | return ret; |
112 | 65 | ||
113 | /* Register hooks */ | 66 | /* Register hooks */ |
114 | ret = nf_register_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops)); | 67 | rawtable_ops = xt_hook_link(&packet_raw, ip6table_raw_hook); |
115 | if (ret < 0) | 68 | if (IS_ERR(rawtable_ops)) { |
69 | ret = PTR_ERR(rawtable_ops); | ||
116 | goto cleanup_table; | 70 | goto cleanup_table; |
71 | } | ||
117 | 72 | ||
118 | return ret; | 73 | return ret; |
119 | 74 | ||
@@ -124,7 +79,7 @@ static int __init ip6table_raw_init(void) | |||
124 | 79 | ||
125 | static void __exit ip6table_raw_fini(void) | 80 | static void __exit ip6table_raw_fini(void) |
126 | { | 81 | { |
127 | nf_unregister_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops)); | 82 | xt_hook_unlink(&packet_raw, rawtable_ops); |
128 | unregister_pernet_subsys(&ip6table_raw_net_ops); | 83 | unregister_pernet_subsys(&ip6table_raw_net_ops); |
129 | } | 84 | } |
130 | 85 | ||
diff --git a/net/ipv6/netfilter/ip6table_security.c b/net/ipv6/netfilter/ip6table_security.c index 41b444c60934..91aa2b4d83c9 100644 --- a/net/ipv6/netfilter/ip6table_security.c +++ b/net/ipv6/netfilter/ip6table_security.c | |||
@@ -17,6 +17,7 @@ | |||
17 | */ | 17 | */ |
18 | #include <linux/module.h> | 18 | #include <linux/module.h> |
19 | #include <linux/netfilter_ipv6/ip6_tables.h> | 19 | #include <linux/netfilter_ipv6/ip6_tables.h> |
20 | #include <linux/slab.h> | ||
20 | 21 | ||
21 | MODULE_LICENSE("GPL"); | 22 | MODULE_LICENSE("GPL"); |
22 | MODULE_AUTHOR("James Morris <jmorris <at> redhat.com>"); | 23 | MODULE_AUTHOR("James Morris <jmorris <at> redhat.com>"); |
@@ -26,106 +27,37 @@ MODULE_DESCRIPTION("ip6tables security table, for MAC rules"); | |||
26 | (1 << NF_INET_FORWARD) | \ | 27 | (1 << NF_INET_FORWARD) | \ |
27 | (1 << NF_INET_LOCAL_OUT) | 28 | (1 << NF_INET_LOCAL_OUT) |
28 | 29 | ||
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 = { | 30 | static const struct xt_table security_table = { |
60 | .name = "security", | 31 | .name = "security", |
61 | .valid_hooks = SECURITY_VALID_HOOKS, | 32 | .valid_hooks = SECURITY_VALID_HOOKS, |
62 | .me = THIS_MODULE, | 33 | .me = THIS_MODULE, |
63 | .af = NFPROTO_IPV6, | 34 | .af = NFPROTO_IPV6, |
35 | .priority = NF_IP6_PRI_SECURITY, | ||
64 | }; | 36 | }; |
65 | 37 | ||
66 | static unsigned int | 38 | static unsigned int |
67 | ip6t_local_in_hook(unsigned int hook, | 39 | ip6table_security_hook(unsigned int hook, struct sk_buff *skb, |
68 | struct sk_buff *skb, | 40 | const struct net_device *in, |
69 | const struct net_device *in, | 41 | const struct net_device *out, |
70 | const struct net_device *out, | 42 | 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 | { | 43 | { |
84 | return ip6t_do_table(skb, hook, in, out, | 44 | const struct net *net = dev_net((in != NULL) ? in : out); |
85 | dev_net(in)->ipv6.ip6table_security); | ||
86 | } | ||
87 | 45 | ||
88 | static unsigned int | 46 | 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 | } | 47 | } |
99 | 48 | ||
100 | static struct nf_hook_ops ip6t_ops[] __read_mostly = { | 49 | 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 | 50 | ||
124 | static int __net_init ip6table_security_net_init(struct net *net) | 51 | static int __net_init ip6table_security_net_init(struct net *net) |
125 | { | 52 | { |
126 | net->ipv6.ip6table_security = | 53 | struct ip6t_replace *repl; |
127 | ip6t_register_table(net, &security_table, &initial_table.repl); | ||
128 | 54 | ||
55 | repl = ip6t_alloc_initial_table(&security_table); | ||
56 | if (repl == NULL) | ||
57 | return -ENOMEM; | ||
58 | net->ipv6.ip6table_security = | ||
59 | ip6t_register_table(net, &security_table, repl); | ||
60 | kfree(repl); | ||
129 | if (IS_ERR(net->ipv6.ip6table_security)) | 61 | if (IS_ERR(net->ipv6.ip6table_security)) |
130 | return PTR_ERR(net->ipv6.ip6table_security); | 62 | return PTR_ERR(net->ipv6.ip6table_security); |
131 | 63 | ||
@@ -134,7 +66,7 @@ static int __net_init ip6table_security_net_init(struct net *net) | |||
134 | 66 | ||
135 | static void __net_exit ip6table_security_net_exit(struct net *net) | 67 | static void __net_exit ip6table_security_net_exit(struct net *net) |
136 | { | 68 | { |
137 | ip6t_unregister_table(net->ipv6.ip6table_security); | 69 | ip6t_unregister_table(net, net->ipv6.ip6table_security); |
138 | } | 70 | } |
139 | 71 | ||
140 | static struct pernet_operations ip6table_security_net_ops = { | 72 | static struct pernet_operations ip6table_security_net_ops = { |
@@ -150,9 +82,11 @@ static int __init ip6table_security_init(void) | |||
150 | if (ret < 0) | 82 | if (ret < 0) |
151 | return ret; | 83 | return ret; |
152 | 84 | ||
153 | ret = nf_register_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops)); | 85 | sectbl_ops = xt_hook_link(&security_table, ip6table_security_hook); |
154 | if (ret < 0) | 86 | if (IS_ERR(sectbl_ops)) { |
87 | ret = PTR_ERR(sectbl_ops); | ||
155 | goto cleanup_table; | 88 | goto cleanup_table; |
89 | } | ||
156 | 90 | ||
157 | return ret; | 91 | return ret; |
158 | 92 | ||
@@ -163,7 +97,7 @@ cleanup_table: | |||
163 | 97 | ||
164 | static void __exit ip6table_security_fini(void) | 98 | static void __exit ip6table_security_fini(void) |
165 | { | 99 | { |
166 | nf_unregister_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops)); | 100 | xt_hook_unlink(&security_table, sectbl_ops); |
167 | unregister_pernet_subsys(&ip6table_security_net_ops); | 101 | unregister_pernet_subsys(&ip6table_security_net_ops); |
168 | } | 102 | } |
169 | 103 | ||
diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c index 5f2ec208a8c3..996c3f41fecd 100644 --- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c +++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c | |||
@@ -20,12 +20,14 @@ | |||
20 | #include <net/ipv6.h> | 20 | #include <net/ipv6.h> |
21 | #include <net/inet_frag.h> | 21 | #include <net/inet_frag.h> |
22 | 22 | ||
23 | #include <linux/netfilter_bridge.h> | ||
23 | #include <linux/netfilter_ipv6.h> | 24 | #include <linux/netfilter_ipv6.h> |
24 | #include <net/netfilter/nf_conntrack.h> | 25 | #include <net/netfilter/nf_conntrack.h> |
25 | #include <net/netfilter/nf_conntrack_helper.h> | 26 | #include <net/netfilter/nf_conntrack_helper.h> |
26 | #include <net/netfilter/nf_conntrack_l4proto.h> | 27 | #include <net/netfilter/nf_conntrack_l4proto.h> |
27 | #include <net/netfilter/nf_conntrack_l3proto.h> | 28 | #include <net/netfilter/nf_conntrack_l3proto.h> |
28 | #include <net/netfilter/nf_conntrack_core.h> | 29 | #include <net/netfilter/nf_conntrack_core.h> |
30 | #include <net/netfilter/nf_conntrack_zones.h> | ||
29 | #include <net/netfilter/ipv6/nf_conntrack_ipv6.h> | 31 | #include <net/netfilter/ipv6/nf_conntrack_ipv6.h> |
30 | #include <net/netfilter/nf_log.h> | 32 | #include <net/netfilter/nf_log.h> |
31 | 33 | ||
@@ -187,6 +189,26 @@ out: | |||
187 | return nf_conntrack_confirm(skb); | 189 | return nf_conntrack_confirm(skb); |
188 | } | 190 | } |
189 | 191 | ||
192 | static enum ip6_defrag_users nf_ct6_defrag_user(unsigned int hooknum, | ||
193 | struct sk_buff *skb) | ||
194 | { | ||
195 | u16 zone = NF_CT_DEFAULT_ZONE; | ||
196 | |||
197 | if (skb->nfct) | ||
198 | zone = nf_ct_zone((struct nf_conn *)skb->nfct); | ||
199 | |||
200 | #ifdef CONFIG_BRIDGE_NETFILTER | ||
201 | if (skb->nf_bridge && | ||
202 | skb->nf_bridge->mask & BRNF_NF_BRIDGE_PREROUTING) | ||
203 | return IP6_DEFRAG_CONNTRACK_BRIDGE_IN + zone; | ||
204 | #endif | ||
205 | if (hooknum == NF_INET_PRE_ROUTING) | ||
206 | return IP6_DEFRAG_CONNTRACK_IN + zone; | ||
207 | else | ||
208 | return IP6_DEFRAG_CONNTRACK_OUT + zone; | ||
209 | |||
210 | } | ||
211 | |||
190 | static unsigned int ipv6_defrag(unsigned int hooknum, | 212 | static unsigned int ipv6_defrag(unsigned int hooknum, |
191 | struct sk_buff *skb, | 213 | struct sk_buff *skb, |
192 | const struct net_device *in, | 214 | const struct net_device *in, |
@@ -196,11 +218,10 @@ static unsigned int ipv6_defrag(unsigned int hooknum, | |||
196 | struct sk_buff *reasm; | 218 | struct sk_buff *reasm; |
197 | 219 | ||
198 | /* Previously seen (loopback)? */ | 220 | /* Previously seen (loopback)? */ |
199 | if (skb->nfct) | 221 | if (skb->nfct && !nf_ct_is_template((struct nf_conn *)skb->nfct)) |
200 | return NF_ACCEPT; | 222 | return NF_ACCEPT; |
201 | 223 | ||
202 | reasm = nf_ct_frag6_gather(skb); | 224 | reasm = nf_ct_frag6_gather(skb, nf_ct6_defrag_user(hooknum, skb)); |
203 | |||
204 | /* queued */ | 225 | /* queued */ |
205 | if (reasm == NULL) | 226 | if (reasm == NULL) |
206 | return NF_STOLEN; | 227 | return NF_STOLEN; |
diff --git a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c index 642dcb127bab..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) |
@@ -244,18 +247,18 @@ static const struct nla_policy icmpv6_nla_policy[CTA_PROTO_MAX+1] = { | |||
244 | static int icmpv6_nlattr_to_tuple(struct nlattr *tb[], | 247 | static int icmpv6_nlattr_to_tuple(struct nlattr *tb[], |
245 | struct nf_conntrack_tuple *tuple) | 248 | struct nf_conntrack_tuple *tuple) |
246 | { | 249 | { |
247 | if (!tb[CTA_PROTO_ICMPV6_TYPE] | 250 | if (!tb[CTA_PROTO_ICMPV6_TYPE] || |
248 | || !tb[CTA_PROTO_ICMPV6_CODE] | 251 | !tb[CTA_PROTO_ICMPV6_CODE] || |
249 | || !tb[CTA_PROTO_ICMPV6_ID]) | 252 | !tb[CTA_PROTO_ICMPV6_ID]) |
250 | return -EINVAL; | 253 | return -EINVAL; |
251 | 254 | ||
252 | tuple->dst.u.icmp.type = nla_get_u8(tb[CTA_PROTO_ICMPV6_TYPE]); | 255 | tuple->dst.u.icmp.type = nla_get_u8(tb[CTA_PROTO_ICMPV6_TYPE]); |
253 | tuple->dst.u.icmp.code = nla_get_u8(tb[CTA_PROTO_ICMPV6_CODE]); | 256 | tuple->dst.u.icmp.code = nla_get_u8(tb[CTA_PROTO_ICMPV6_CODE]); |
254 | tuple->src.u.icmp.id = nla_get_be16(tb[CTA_PROTO_ICMPV6_ID]); | 257 | tuple->src.u.icmp.id = nla_get_be16(tb[CTA_PROTO_ICMPV6_ID]); |
255 | 258 | ||
256 | if (tuple->dst.u.icmp.type < 128 | 259 | if (tuple->dst.u.icmp.type < 128 || |
257 | || tuple->dst.u.icmp.type - 128 >= sizeof(invmap) | 260 | tuple->dst.u.icmp.type - 128 >= sizeof(invmap) || |
258 | || !invmap[tuple->dst.u.icmp.type - 128]) | 261 | !invmap[tuple->dst.u.icmp.type - 128]) |
259 | return -EINVAL; | 262 | return -EINVAL; |
260 | 263 | ||
261 | return 0; | 264 | return 0; |
@@ -277,9 +280,7 @@ static struct ctl_table icmpv6_sysctl_table[] = { | |||
277 | .mode = 0644, | 280 | .mode = 0644, |
278 | .proc_handler = proc_dointvec_jiffies, | 281 | .proc_handler = proc_dointvec_jiffies, |
279 | }, | 282 | }, |
280 | { | 283 | { } |
281 | .ctl_name = 0 | ||
282 | } | ||
283 | }; | 284 | }; |
284 | #endif /* CONFIG_SYSCTL */ | 285 | #endif /* CONFIG_SYSCTL */ |
285 | 286 | ||
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c index f3aba255ad9f..dd5b9bd61c62 100644 --- a/net/ipv6/netfilter/nf_conntrack_reasm.c +++ b/net/ipv6/netfilter/nf_conntrack_reasm.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <linux/ipv6.h> | 27 | #include <linux/ipv6.h> |
28 | #include <linux/icmpv6.h> | 28 | #include <linux/icmpv6.h> |
29 | #include <linux/random.h> | 29 | #include <linux/random.h> |
30 | #include <linux/slab.h> | ||
30 | 31 | ||
31 | #include <net/sock.h> | 32 | #include <net/sock.h> |
32 | #include <net/snmp.h> | 33 | #include <net/snmp.h> |
@@ -45,9 +46,6 @@ | |||
45 | #include <linux/kernel.h> | 46 | #include <linux/kernel.h> |
46 | #include <linux/module.h> | 47 | #include <linux/module.h> |
47 | 48 | ||
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 | 49 | ||
52 | struct nf_ct_frag6_skb_cb | 50 | struct nf_ct_frag6_skb_cb |
53 | { | 51 | { |
@@ -63,6 +61,7 @@ struct nf_ct_frag6_queue | |||
63 | struct inet_frag_queue q; | 61 | struct inet_frag_queue q; |
64 | 62 | ||
65 | __be32 id; /* fragment id */ | 63 | __be32 id; /* fragment id */ |
64 | u32 user; | ||
66 | struct in6_addr saddr; | 65 | struct in6_addr saddr; |
67 | struct in6_addr daddr; | 66 | struct in6_addr daddr; |
68 | 67 | ||
@@ -83,7 +82,6 @@ struct ctl_table nf_ct_ipv6_sysctl_table[] = { | |||
83 | .proc_handler = proc_dointvec_jiffies, | 82 | .proc_handler = proc_dointvec_jiffies, |
84 | }, | 83 | }, |
85 | { | 84 | { |
86 | .ctl_name = NET_NF_CONNTRACK_FRAG6_LOW_THRESH, | ||
87 | .procname = "nf_conntrack_frag6_low_thresh", | 85 | .procname = "nf_conntrack_frag6_low_thresh", |
88 | .data = &nf_init_frags.low_thresh, | 86 | .data = &nf_init_frags.low_thresh, |
89 | .maxlen = sizeof(unsigned int), | 87 | .maxlen = sizeof(unsigned int), |
@@ -91,14 +89,13 @@ struct ctl_table nf_ct_ipv6_sysctl_table[] = { | |||
91 | .proc_handler = proc_dointvec, | 89 | .proc_handler = proc_dointvec, |
92 | }, | 90 | }, |
93 | { | 91 | { |
94 | .ctl_name = NET_NF_CONNTRACK_FRAG6_HIGH_THRESH, | ||
95 | .procname = "nf_conntrack_frag6_high_thresh", | 92 | .procname = "nf_conntrack_frag6_high_thresh", |
96 | .data = &nf_init_frags.high_thresh, | 93 | .data = &nf_init_frags.high_thresh, |
97 | .maxlen = sizeof(unsigned int), | 94 | .maxlen = sizeof(unsigned int), |
98 | .mode = 0644, | 95 | .mode = 0644, |
99 | .proc_handler = proc_dointvec, | 96 | .proc_handler = proc_dointvec, |
100 | }, | 97 | }, |
101 | { .ctl_name = 0 } | 98 | { } |
102 | }; | 99 | }; |
103 | #endif | 100 | #endif |
104 | 101 | ||
@@ -170,13 +167,14 @@ out: | |||
170 | /* Creation primitives. */ | 167 | /* Creation primitives. */ |
171 | 168 | ||
172 | static __inline__ struct nf_ct_frag6_queue * | 169 | static __inline__ struct nf_ct_frag6_queue * |
173 | fq_find(__be32 id, struct in6_addr *src, struct in6_addr *dst) | 170 | fq_find(__be32 id, u32 user, struct in6_addr *src, struct in6_addr *dst) |
174 | { | 171 | { |
175 | struct inet_frag_queue *q; | 172 | struct inet_frag_queue *q; |
176 | struct ip6_create_arg arg; | 173 | struct ip6_create_arg arg; |
177 | unsigned int hash; | 174 | unsigned int hash; |
178 | 175 | ||
179 | arg.id = id; | 176 | arg.id = id; |
177 | arg.user = user; | ||
180 | arg.src = src; | 178 | arg.src = src; |
181 | arg.dst = dst; | 179 | arg.dst = dst; |
182 | 180 | ||
@@ -472,7 +470,7 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev) | |||
472 | 470 | ||
473 | /* all original skbs are linked into the NFCT_FRAG6_CB(head).orig */ | 471 | /* all original skbs are linked into the NFCT_FRAG6_CB(head).orig */ |
474 | fp = skb_shinfo(head)->frag_list; | 472 | fp = skb_shinfo(head)->frag_list; |
475 | if (NFCT_FRAG6_CB(fp)->orig == NULL) | 473 | if (fp && NFCT_FRAG6_CB(fp)->orig == NULL) |
476 | /* at above code, head skb is divided into two skbs. */ | 474 | /* at above code, head skb is divided into two skbs. */ |
477 | fp = fp->next; | 475 | fp = fp->next; |
478 | 476 | ||
@@ -561,7 +559,7 @@ find_prev_fhdr(struct sk_buff *skb, u8 *prevhdrp, int *prevhoff, int *fhoff) | |||
561 | return 0; | 559 | return 0; |
562 | } | 560 | } |
563 | 561 | ||
564 | struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb) | 562 | struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb, u32 user) |
565 | { | 563 | { |
566 | struct sk_buff *clone; | 564 | struct sk_buff *clone; |
567 | struct net_device *dev = skb->dev; | 565 | struct net_device *dev = skb->dev; |
@@ -598,16 +596,10 @@ struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb) | |||
598 | hdr = ipv6_hdr(clone); | 596 | hdr = ipv6_hdr(clone); |
599 | fhdr = (struct frag_hdr *)skb_transport_header(clone); | 597 | fhdr = (struct frag_hdr *)skb_transport_header(clone); |
600 | 598 | ||
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) | 599 | if (atomic_read(&nf_init_frags.mem) > nf_init_frags.high_thresh) |
608 | nf_ct_frag6_evictor(); | 600 | nf_ct_frag6_evictor(); |
609 | 601 | ||
610 | fq = fq_find(fhdr->identification, &hdr->saddr, &hdr->daddr); | 602 | fq = fq_find(fhdr->identification, user, &hdr->saddr, &hdr->daddr); |
611 | if (fq == NULL) { | 603 | if (fq == NULL) { |
612 | pr_debug("Can't find and can't create new queue\n"); | 604 | pr_debug("Can't find and can't create new queue\n"); |
613 | goto ret_orig; | 605 | goto ret_orig; |
@@ -670,8 +662,8 @@ int nf_ct_frag6_init(void) | |||
670 | nf_frags.frag_expire = nf_ct_frag6_expire; | 662 | nf_frags.frag_expire = nf_ct_frag6_expire; |
671 | nf_frags.secret_interval = 10 * 60 * HZ; | 663 | nf_frags.secret_interval = 10 * 60 * HZ; |
672 | nf_init_frags.timeout = IPV6_FRAG_TIMEOUT; | 664 | nf_init_frags.timeout = IPV6_FRAG_TIMEOUT; |
673 | nf_init_frags.high_thresh = 256 * 1024; | 665 | nf_init_frags.high_thresh = IPV6_FRAG_HIGH_THRESH; |
674 | nf_init_frags.low_thresh = 192 * 1024; | 666 | nf_init_frags.low_thresh = IPV6_FRAG_LOW_THRESH; |
675 | inet_frags_init_net(&nf_init_frags); | 667 | inet_frags_init_net(&nf_init_frags); |
676 | inet_frags_init(&nf_frags); | 668 | inet_frags_init(&nf_frags); |
677 | 669 | ||
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 4f24570b0869..8763b1a0814a 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/errno.h> | 21 | #include <linux/errno.h> |
22 | #include <linux/types.h> | 22 | #include <linux/types.h> |
23 | #include <linux/socket.h> | 23 | #include <linux/socket.h> |
24 | #include <linux/slab.h> | ||
24 | #include <linux/sockios.h> | 25 | #include <linux/sockios.h> |
25 | #include <linux/net.h> | 26 | #include <linux/net.h> |
26 | #include <linux/in6.h> | 27 | #include <linux/in6.h> |
@@ -72,7 +73,7 @@ static struct sock *__raw_v6_lookup(struct net *net, struct sock *sk, | |||
72 | int is_multicast = ipv6_addr_is_multicast(loc_addr); | 73 | int is_multicast = ipv6_addr_is_multicast(loc_addr); |
73 | 74 | ||
74 | sk_for_each_from(sk, node) | 75 | sk_for_each_from(sk, node) |
75 | if (inet_sk(sk)->num == num) { | 76 | if (inet_sk(sk)->inet_num == num) { |
76 | struct ipv6_pinfo *np = inet6_sk(sk); | 77 | struct ipv6_pinfo *np = inet6_sk(sk); |
77 | 78 | ||
78 | if (!net_eq(sock_net(sk), net)) | 79 | if (!net_eq(sock_net(sk), net)) |
@@ -249,7 +250,7 @@ static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) | |||
249 | 250 | ||
250 | /* Raw sockets are IPv6 only */ | 251 | /* Raw sockets are IPv6 only */ |
251 | if (addr_type == IPV6_ADDR_MAPPED) | 252 | if (addr_type == IPV6_ADDR_MAPPED) |
252 | return(-EADDRNOTAVAIL); | 253 | return -EADDRNOTAVAIL; |
253 | 254 | ||
254 | lock_sock(sk); | 255 | lock_sock(sk); |
255 | 256 | ||
@@ -257,6 +258,7 @@ static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) | |||
257 | if (sk->sk_state != TCP_CLOSE) | 258 | if (sk->sk_state != TCP_CLOSE) |
258 | goto out; | 259 | goto out; |
259 | 260 | ||
261 | rcu_read_lock(); | ||
260 | /* Check if the address belongs to the host. */ | 262 | /* Check if the address belongs to the host. */ |
261 | if (addr_type != IPV6_ADDR_ANY) { | 263 | if (addr_type != IPV6_ADDR_ANY) { |
262 | struct net_device *dev = NULL; | 264 | struct net_device *dev = NULL; |
@@ -272,13 +274,13 @@ static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) | |||
272 | 274 | ||
273 | /* Binding to link-local address requires an interface */ | 275 | /* Binding to link-local address requires an interface */ |
274 | if (!sk->sk_bound_dev_if) | 276 | if (!sk->sk_bound_dev_if) |
275 | goto out; | 277 | goto out_unlock; |
276 | 278 | ||
277 | dev = dev_get_by_index(sock_net(sk), sk->sk_bound_dev_if); | 279 | err = -ENODEV; |
278 | if (!dev) { | 280 | dev = dev_get_by_index_rcu(sock_net(sk), |
279 | err = -ENODEV; | 281 | sk->sk_bound_dev_if); |
280 | goto out; | 282 | if (!dev) |
281 | } | 283 | goto out_unlock; |
282 | } | 284 | } |
283 | 285 | ||
284 | /* ipv4 addr of the socket is invalid. Only the | 286 | /* ipv4 addr of the socket is invalid. Only the |
@@ -289,20 +291,18 @@ static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) | |||
289 | err = -EADDRNOTAVAIL; | 291 | err = -EADDRNOTAVAIL; |
290 | if (!ipv6_chk_addr(sock_net(sk), &addr->sin6_addr, | 292 | if (!ipv6_chk_addr(sock_net(sk), &addr->sin6_addr, |
291 | dev, 0)) { | 293 | dev, 0)) { |
292 | if (dev) | 294 | goto out_unlock; |
293 | dev_put(dev); | ||
294 | goto out; | ||
295 | } | 295 | } |
296 | } | 296 | } |
297 | if (dev) | ||
298 | dev_put(dev); | ||
299 | } | 297 | } |
300 | 298 | ||
301 | inet->rcv_saddr = inet->saddr = v4addr; | 299 | inet->inet_rcv_saddr = inet->inet_saddr = v4addr; |
302 | ipv6_addr_copy(&np->rcv_saddr, &addr->sin6_addr); | 300 | ipv6_addr_copy(&np->rcv_saddr, &addr->sin6_addr); |
303 | if (!(addr_type & IPV6_ADDR_MULTICAST)) | 301 | if (!(addr_type & IPV6_ADDR_MULTICAST)) |
304 | ipv6_addr_copy(&np->saddr, &addr->sin6_addr); | 302 | ipv6_addr_copy(&np->saddr, &addr->sin6_addr); |
305 | err = 0; | 303 | err = 0; |
304 | out_unlock: | ||
305 | rcu_read_unlock(); | ||
306 | out: | 306 | out: |
307 | release_sock(sk); | 307 | release_sock(sk); |
308 | return err; | 308 | return err; |
@@ -381,8 +381,7 @@ static inline int rawv6_rcv_skb(struct sock * sk, struct sk_buff * skb) | |||
381 | } | 381 | } |
382 | 382 | ||
383 | /* Charge it to the socket. */ | 383 | /* Charge it to the socket. */ |
384 | if (sock_queue_rcv_skb(sk,skb)<0) { | 384 | if (sock_queue_rcv_skb(sk, skb) < 0) { |
385 | atomic_inc(&sk->sk_drops); | ||
386 | kfree_skb(skb); | 385 | kfree_skb(skb); |
387 | return NET_RX_DROP; | 386 | return NET_RX_DROP; |
388 | } | 387 | } |
@@ -416,14 +415,14 @@ int rawv6_rcv(struct sock *sk, struct sk_buff *skb) | |||
416 | skb_network_header_len(skb)); | 415 | skb_network_header_len(skb)); |
417 | if (!csum_ipv6_magic(&ipv6_hdr(skb)->saddr, | 416 | if (!csum_ipv6_magic(&ipv6_hdr(skb)->saddr, |
418 | &ipv6_hdr(skb)->daddr, | 417 | &ipv6_hdr(skb)->daddr, |
419 | skb->len, inet->num, skb->csum)) | 418 | skb->len, inet->inet_num, skb->csum)) |
420 | skb->ip_summed = CHECKSUM_UNNECESSARY; | 419 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
421 | } | 420 | } |
422 | if (!skb_csum_unnecessary(skb)) | 421 | if (!skb_csum_unnecessary(skb)) |
423 | skb->csum = ~csum_unfold(csum_ipv6_magic(&ipv6_hdr(skb)->saddr, | 422 | skb->csum = ~csum_unfold(csum_ipv6_magic(&ipv6_hdr(skb)->saddr, |
424 | &ipv6_hdr(skb)->daddr, | 423 | &ipv6_hdr(skb)->daddr, |
425 | skb->len, | 424 | skb->len, |
426 | inet->num, 0)); | 425 | inet->inet_num, 0)); |
427 | 426 | ||
428 | if (inet->hdrincl) { | 427 | if (inet->hdrincl) { |
429 | if (skb_checksum_complete(skb)) { | 428 | if (skb_checksum_complete(skb)) { |
@@ -497,7 +496,7 @@ static int rawv6_recvmsg(struct kiocb *iocb, struct sock *sk, | |||
497 | sin6->sin6_scope_id = IP6CB(skb)->iif; | 496 | sin6->sin6_scope_id = IP6CB(skb)->iif; |
498 | } | 497 | } |
499 | 498 | ||
500 | sock_recv_timestamp(msg, sk, skb); | 499 | sock_recv_ts_and_drops(msg, sk, skb); |
501 | 500 | ||
502 | if (np->rxopt.all) | 501 | if (np->rxopt.all) |
503 | datagram_recv_ctl(sk, msg, skb); | 502 | datagram_recv_ctl(sk, msg, skb); |
@@ -518,7 +517,6 @@ csum_copy_err: | |||
518 | as some normal condition. | 517 | as some normal condition. |
519 | */ | 518 | */ |
520 | err = (flags&MSG_DONTWAIT) ? -EAGAIN : -EHOSTUNREACH; | 519 | err = (flags&MSG_DONTWAIT) ? -EAGAIN : -EHOSTUNREACH; |
521 | atomic_inc(&sk->sk_drops); | ||
522 | goto out; | 520 | goto out; |
523 | } | 521 | } |
524 | 522 | ||
@@ -766,8 +764,8 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
766 | proto = ntohs(sin6->sin6_port); | 764 | proto = ntohs(sin6->sin6_port); |
767 | 765 | ||
768 | if (!proto) | 766 | if (!proto) |
769 | proto = inet->num; | 767 | proto = inet->inet_num; |
770 | else if (proto != inet->num) | 768 | else if (proto != inet->inet_num) |
771 | return(-EINVAL); | 769 | return(-EINVAL); |
772 | 770 | ||
773 | if (proto > 255) | 771 | if (proto > 255) |
@@ -800,7 +798,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
800 | if (sk->sk_state != TCP_ESTABLISHED) | 798 | if (sk->sk_state != TCP_ESTABLISHED) |
801 | return -EDESTADDRREQ; | 799 | return -EDESTADDRREQ; |
802 | 800 | ||
803 | proto = inet->num; | 801 | proto = inet->inet_num; |
804 | daddr = &np->daddr; | 802 | daddr = &np->daddr; |
805 | fl.fl6_flowlabel = np->flow_label; | 803 | fl.fl6_flowlabel = np->flow_label; |
806 | } | 804 | } |
@@ -967,7 +965,7 @@ static int do_rawv6_setsockopt(struct sock *sk, int level, int optname, | |||
967 | 965 | ||
968 | switch (optname) { | 966 | switch (optname) { |
969 | case IPV6_CHECKSUM: | 967 | case IPV6_CHECKSUM: |
970 | if (inet_sk(sk)->num == IPPROTO_ICMPV6 && | 968 | if (inet_sk(sk)->inet_num == IPPROTO_ICMPV6 && |
971 | level == IPPROTO_IPV6) { | 969 | level == IPPROTO_IPV6) { |
972 | /* | 970 | /* |
973 | * RFC3542 tells that IPV6_CHECKSUM socket | 971 | * RFC3542 tells that IPV6_CHECKSUM socket |
@@ -1007,7 +1005,7 @@ static int rawv6_setsockopt(struct sock *sk, int level, int optname, | |||
1007 | break; | 1005 | break; |
1008 | 1006 | ||
1009 | case SOL_ICMPV6: | 1007 | case SOL_ICMPV6: |
1010 | if (inet_sk(sk)->num != IPPROTO_ICMPV6) | 1008 | if (inet_sk(sk)->inet_num != IPPROTO_ICMPV6) |
1011 | return -EOPNOTSUPP; | 1009 | return -EOPNOTSUPP; |
1012 | return rawv6_seticmpfilter(sk, level, optname, optval, | 1010 | return rawv6_seticmpfilter(sk, level, optname, optval, |
1013 | optlen); | 1011 | optlen); |
@@ -1030,7 +1028,7 @@ static int compat_rawv6_setsockopt(struct sock *sk, int level, int optname, | |||
1030 | case SOL_RAW: | 1028 | case SOL_RAW: |
1031 | break; | 1029 | break; |
1032 | case SOL_ICMPV6: | 1030 | case SOL_ICMPV6: |
1033 | if (inet_sk(sk)->num != IPPROTO_ICMPV6) | 1031 | if (inet_sk(sk)->inet_num != IPPROTO_ICMPV6) |
1034 | return -EOPNOTSUPP; | 1032 | return -EOPNOTSUPP; |
1035 | return rawv6_seticmpfilter(sk, level, optname, optval, optlen); | 1033 | return rawv6_seticmpfilter(sk, level, optname, optval, optlen); |
1036 | case SOL_IPV6: | 1034 | case SOL_IPV6: |
@@ -1087,7 +1085,7 @@ static int rawv6_getsockopt(struct sock *sk, int level, int optname, | |||
1087 | break; | 1085 | break; |
1088 | 1086 | ||
1089 | case SOL_ICMPV6: | 1087 | case SOL_ICMPV6: |
1090 | if (inet_sk(sk)->num != IPPROTO_ICMPV6) | 1088 | if (inet_sk(sk)->inet_num != IPPROTO_ICMPV6) |
1091 | return -EOPNOTSUPP; | 1089 | return -EOPNOTSUPP; |
1092 | return rawv6_geticmpfilter(sk, level, optname, optval, | 1090 | return rawv6_geticmpfilter(sk, level, optname, optval, |
1093 | optlen); | 1091 | optlen); |
@@ -1110,7 +1108,7 @@ static int compat_rawv6_getsockopt(struct sock *sk, int level, int optname, | |||
1110 | case SOL_RAW: | 1108 | case SOL_RAW: |
1111 | break; | 1109 | break; |
1112 | case SOL_ICMPV6: | 1110 | case SOL_ICMPV6: |
1113 | if (inet_sk(sk)->num != IPPROTO_ICMPV6) | 1111 | if (inet_sk(sk)->inet_num != IPPROTO_ICMPV6) |
1114 | return -EOPNOTSUPP; | 1112 | return -EOPNOTSUPP; |
1115 | return rawv6_geticmpfilter(sk, level, optname, optval, optlen); | 1113 | return rawv6_geticmpfilter(sk, level, optname, optval, optlen); |
1116 | case SOL_IPV6: | 1114 | case SOL_IPV6: |
@@ -1157,7 +1155,7 @@ static int rawv6_ioctl(struct sock *sk, int cmd, unsigned long arg) | |||
1157 | 1155 | ||
1158 | static void rawv6_close(struct sock *sk, long timeout) | 1156 | static void rawv6_close(struct sock *sk, long timeout) |
1159 | { | 1157 | { |
1160 | if (inet_sk(sk)->num == IPPROTO_RAW) | 1158 | if (inet_sk(sk)->inet_num == IPPROTO_RAW) |
1161 | ip6_ra_control(sk, -1); | 1159 | ip6_ra_control(sk, -1); |
1162 | ip6mr_sk_done(sk); | 1160 | ip6mr_sk_done(sk); |
1163 | sk_common_release(sk); | 1161 | sk_common_release(sk); |
@@ -1176,7 +1174,7 @@ static int rawv6_init_sk(struct sock *sk) | |||
1176 | { | 1174 | { |
1177 | struct raw6_sock *rp = raw6_sk(sk); | 1175 | struct raw6_sock *rp = raw6_sk(sk); |
1178 | 1176 | ||
1179 | switch (inet_sk(sk)->num) { | 1177 | switch (inet_sk(sk)->inet_num) { |
1180 | case IPPROTO_ICMPV6: | 1178 | case IPPROTO_ICMPV6: |
1181 | rp->checksum = 1; | 1179 | rp->checksum = 1; |
1182 | rp->offset = 2; | 1180 | rp->offset = 2; |
@@ -1226,7 +1224,7 @@ static void raw6_sock_seq_show(struct seq_file *seq, struct sock *sp, int i) | |||
1226 | dest = &np->daddr; | 1224 | dest = &np->daddr; |
1227 | src = &np->rcv_saddr; | 1225 | src = &np->rcv_saddr; |
1228 | destp = 0; | 1226 | destp = 0; |
1229 | srcp = inet_sk(sp)->num; | 1227 | srcp = inet_sk(sp)->inet_num; |
1230 | seq_printf(seq, | 1228 | seq_printf(seq, |
1231 | "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X " | 1229 | "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X " |
1232 | "%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %d\n", | 1230 | "%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %d\n", |
@@ -1278,7 +1276,7 @@ static const struct file_operations raw6_seq_fops = { | |||
1278 | .release = seq_release_net, | 1276 | .release = seq_release_net, |
1279 | }; | 1277 | }; |
1280 | 1278 | ||
1281 | static int raw6_init_net(struct net *net) | 1279 | static int __net_init raw6_init_net(struct net *net) |
1282 | { | 1280 | { |
1283 | if (!proc_net_fops_create(net, "raw6", S_IRUGO, &raw6_seq_fops)) | 1281 | if (!proc_net_fops_create(net, "raw6", S_IRUGO, &raw6_seq_fops)) |
1284 | return -ENOMEM; | 1282 | return -ENOMEM; |
@@ -1286,7 +1284,7 @@ static int raw6_init_net(struct net *net) | |||
1286 | return 0; | 1284 | return 0; |
1287 | } | 1285 | } |
1288 | 1286 | ||
1289 | static void raw6_exit_net(struct net *net) | 1287 | static void __net_exit raw6_exit_net(struct net *net) |
1290 | { | 1288 | { |
1291 | proc_net_remove(net, "raw6"); | 1289 | proc_net_remove(net, "raw6"); |
1292 | } | 1290 | } |
@@ -1338,7 +1336,6 @@ static struct inet_protosw rawv6_protosw = { | |||
1338 | .protocol = IPPROTO_IP, /* wild card */ | 1336 | .protocol = IPPROTO_IP, /* wild card */ |
1339 | .prot = &rawv6_prot, | 1337 | .prot = &rawv6_prot, |
1340 | .ops = &inet6_sockraw_ops, | 1338 | .ops = &inet6_sockraw_ops, |
1341 | .capability = CAP_NET_RAW, | ||
1342 | .no_check = UDP_CSUM_DEFAULT, | 1339 | .no_check = UDP_CSUM_DEFAULT, |
1343 | .flags = INET_PROTOSW_REUSE, | 1340 | .flags = INET_PROTOSW_REUSE, |
1344 | }; | 1341 | }; |
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index da5bd0ed83df..6d4292ff5854 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c | |||
@@ -41,6 +41,7 @@ | |||
41 | #include <linux/random.h> | 41 | #include <linux/random.h> |
42 | #include <linux/jhash.h> | 42 | #include <linux/jhash.h> |
43 | #include <linux/skbuff.h> | 43 | #include <linux/skbuff.h> |
44 | #include <linux/slab.h> | ||
44 | 45 | ||
45 | #include <net/sock.h> | 46 | #include <net/sock.h> |
46 | #include <net/snmp.h> | 47 | #include <net/snmp.h> |
@@ -72,6 +73,7 @@ struct frag_queue | |||
72 | struct inet_frag_queue q; | 73 | struct inet_frag_queue q; |
73 | 74 | ||
74 | __be32 id; /* fragment id */ | 75 | __be32 id; /* fragment id */ |
76 | u32 user; | ||
75 | struct in6_addr saddr; | 77 | struct in6_addr saddr; |
76 | struct in6_addr daddr; | 78 | struct in6_addr daddr; |
77 | 79 | ||
@@ -141,7 +143,7 @@ int ip6_frag_match(struct inet_frag_queue *q, void *a) | |||
141 | struct ip6_create_arg *arg = a; | 143 | struct ip6_create_arg *arg = a; |
142 | 144 | ||
143 | fq = container_of(q, struct frag_queue, q); | 145 | fq = container_of(q, struct frag_queue, q); |
144 | return (fq->id == arg->id && | 146 | return (fq->id == arg->id && fq->user == arg->user && |
145 | ipv6_addr_equal(&fq->saddr, arg->src) && | 147 | ipv6_addr_equal(&fq->saddr, arg->src) && |
146 | ipv6_addr_equal(&fq->daddr, arg->dst)); | 148 | ipv6_addr_equal(&fq->daddr, arg->dst)); |
147 | } | 149 | } |
@@ -163,6 +165,7 @@ void ip6_frag_init(struct inet_frag_queue *q, void *a) | |||
163 | struct ip6_create_arg *arg = a; | 165 | struct ip6_create_arg *arg = a; |
164 | 166 | ||
165 | fq->id = arg->id; | 167 | fq->id = arg->id; |
168 | fq->user = arg->user; | ||
166 | ipv6_addr_copy(&fq->saddr, arg->src); | 169 | ipv6_addr_copy(&fq->saddr, arg->src); |
167 | ipv6_addr_copy(&fq->daddr, arg->dst); | 170 | ipv6_addr_copy(&fq->daddr, arg->dst); |
168 | } | 171 | } |
@@ -208,18 +211,17 @@ static void ip6_frag_expire(unsigned long data) | |||
208 | fq_kill(fq); | 211 | fq_kill(fq); |
209 | 212 | ||
210 | net = container_of(fq->q.net, struct net, ipv6.frags); | 213 | net = container_of(fq->q.net, struct net, ipv6.frags); |
211 | dev = dev_get_by_index(net, fq->iif); | 214 | rcu_read_lock(); |
215 | dev = dev_get_by_index_rcu(net, fq->iif); | ||
212 | if (!dev) | 216 | if (!dev) |
213 | goto out; | 217 | goto out_rcu_unlock; |
214 | 218 | ||
215 | rcu_read_lock(); | ||
216 | IP6_INC_STATS_BH(net, __in6_dev_get(dev), IPSTATS_MIB_REASMTIMEOUT); | 219 | IP6_INC_STATS_BH(net, __in6_dev_get(dev), IPSTATS_MIB_REASMTIMEOUT); |
217 | IP6_INC_STATS_BH(net, __in6_dev_get(dev), IPSTATS_MIB_REASMFAILS); | 220 | IP6_INC_STATS_BH(net, __in6_dev_get(dev), IPSTATS_MIB_REASMFAILS); |
218 | rcu_read_unlock(); | ||
219 | 221 | ||
220 | /* Don't send error if the first segment did not arrive. */ | 222 | /* Don't send error if the first segment did not arrive. */ |
221 | if (!(fq->q.last_in & INET_FRAG_FIRST_IN) || !fq->q.fragments) | 223 | if (!(fq->q.last_in & INET_FRAG_FIRST_IN) || !fq->q.fragments) |
222 | goto out; | 224 | goto out_rcu_unlock; |
223 | 225 | ||
224 | /* | 226 | /* |
225 | But use as source device on which LAST ARRIVED | 227 | But use as source device on which LAST ARRIVED |
@@ -227,23 +229,23 @@ static void ip6_frag_expire(unsigned long data) | |||
227 | pointer directly, device might already disappeared. | 229 | pointer directly, device might already disappeared. |
228 | */ | 230 | */ |
229 | fq->q.fragments->dev = dev; | 231 | fq->q.fragments->dev = dev; |
230 | icmpv6_send(fq->q.fragments, ICMPV6_TIME_EXCEED, ICMPV6_EXC_FRAGTIME, 0, dev); | 232 | icmpv6_send(fq->q.fragments, ICMPV6_TIME_EXCEED, ICMPV6_EXC_FRAGTIME, 0); |
233 | out_rcu_unlock: | ||
234 | rcu_read_unlock(); | ||
231 | out: | 235 | out: |
232 | if (dev) | ||
233 | dev_put(dev); | ||
234 | spin_unlock(&fq->q.lock); | 236 | spin_unlock(&fq->q.lock); |
235 | fq_put(fq); | 237 | fq_put(fq); |
236 | } | 238 | } |
237 | 239 | ||
238 | static __inline__ struct frag_queue * | 240 | static __inline__ struct frag_queue * |
239 | fq_find(struct net *net, __be32 id, struct in6_addr *src, struct in6_addr *dst, | 241 | fq_find(struct net *net, __be32 id, struct in6_addr *src, struct in6_addr *dst) |
240 | struct inet6_dev *idev) | ||
241 | { | 242 | { |
242 | struct inet_frag_queue *q; | 243 | struct inet_frag_queue *q; |
243 | struct ip6_create_arg arg; | 244 | struct ip6_create_arg arg; |
244 | unsigned int hash; | 245 | unsigned int hash; |
245 | 246 | ||
246 | arg.id = id; | 247 | arg.id = id; |
248 | arg.user = IP6_DEFRAG_LOCAL_DELIVER; | ||
247 | arg.src = src; | 249 | arg.src = src; |
248 | arg.dst = dst; | 250 | arg.dst = dst; |
249 | 251 | ||
@@ -252,13 +254,9 @@ fq_find(struct net *net, __be32 id, struct in6_addr *src, struct in6_addr *dst, | |||
252 | 254 | ||
253 | q = inet_frag_find(&net->ipv6.frags, &ip6_frags, &arg, hash); | 255 | q = inet_frag_find(&net->ipv6.frags, &ip6_frags, &arg, hash); |
254 | if (q == NULL) | 256 | if (q == NULL) |
255 | goto oom; | 257 | return NULL; |
256 | 258 | ||
257 | return container_of(q, struct frag_queue, q); | 259 | return container_of(q, struct frag_queue, q); |
258 | |||
259 | oom: | ||
260 | IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_REASMFAILS); | ||
261 | return NULL; | ||
262 | } | 260 | } |
263 | 261 | ||
264 | static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, | 262 | static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, |
@@ -604,8 +602,8 @@ static int ipv6_frag_rcv(struct sk_buff *skb) | |||
604 | if (atomic_read(&net->ipv6.frags.mem) > net->ipv6.frags.high_thresh) | 602 | if (atomic_read(&net->ipv6.frags.mem) > net->ipv6.frags.high_thresh) |
605 | ip6_evictor(net, ip6_dst_idev(skb_dst(skb))); | 603 | ip6_evictor(net, ip6_dst_idev(skb_dst(skb))); |
606 | 604 | ||
607 | if ((fq = fq_find(net, fhdr->identification, &hdr->saddr, &hdr->daddr, | 605 | fq = fq_find(net, fhdr->identification, &hdr->saddr, &hdr->daddr); |
608 | ip6_dst_idev(skb_dst(skb)))) != NULL) { | 606 | if (fq != NULL) { |
609 | int ret; | 607 | int ret; |
610 | 608 | ||
611 | spin_lock(&fq->q.lock); | 609 | spin_lock(&fq->q.lock); |
@@ -636,7 +634,6 @@ static const struct inet6_protocol frag_protocol = | |||
636 | #ifdef CONFIG_SYSCTL | 634 | #ifdef CONFIG_SYSCTL |
637 | static struct ctl_table ip6_frags_ns_ctl_table[] = { | 635 | static struct ctl_table ip6_frags_ns_ctl_table[] = { |
638 | { | 636 | { |
639 | .ctl_name = NET_IPV6_IP6FRAG_HIGH_THRESH, | ||
640 | .procname = "ip6frag_high_thresh", | 637 | .procname = "ip6frag_high_thresh", |
641 | .data = &init_net.ipv6.frags.high_thresh, | 638 | .data = &init_net.ipv6.frags.high_thresh, |
642 | .maxlen = sizeof(int), | 639 | .maxlen = sizeof(int), |
@@ -644,7 +641,6 @@ static struct ctl_table ip6_frags_ns_ctl_table[] = { | |||
644 | .proc_handler = proc_dointvec | 641 | .proc_handler = proc_dointvec |
645 | }, | 642 | }, |
646 | { | 643 | { |
647 | .ctl_name = NET_IPV6_IP6FRAG_LOW_THRESH, | ||
648 | .procname = "ip6frag_low_thresh", | 644 | .procname = "ip6frag_low_thresh", |
649 | .data = &init_net.ipv6.frags.low_thresh, | 645 | .data = &init_net.ipv6.frags.low_thresh, |
650 | .maxlen = sizeof(int), | 646 | .maxlen = sizeof(int), |
@@ -652,37 +648,33 @@ static struct ctl_table ip6_frags_ns_ctl_table[] = { | |||
652 | .proc_handler = proc_dointvec | 648 | .proc_handler = proc_dointvec |
653 | }, | 649 | }, |
654 | { | 650 | { |
655 | .ctl_name = NET_IPV6_IP6FRAG_TIME, | ||
656 | .procname = "ip6frag_time", | 651 | .procname = "ip6frag_time", |
657 | .data = &init_net.ipv6.frags.timeout, | 652 | .data = &init_net.ipv6.frags.timeout, |
658 | .maxlen = sizeof(int), | 653 | .maxlen = sizeof(int), |
659 | .mode = 0644, | 654 | .mode = 0644, |
660 | .proc_handler = proc_dointvec_jiffies, | 655 | .proc_handler = proc_dointvec_jiffies, |
661 | .strategy = sysctl_jiffies, | ||
662 | }, | 656 | }, |
663 | { } | 657 | { } |
664 | }; | 658 | }; |
665 | 659 | ||
666 | static struct ctl_table ip6_frags_ctl_table[] = { | 660 | static struct ctl_table ip6_frags_ctl_table[] = { |
667 | { | 661 | { |
668 | .ctl_name = NET_IPV6_IP6FRAG_SECRET_INTERVAL, | ||
669 | .procname = "ip6frag_secret_interval", | 662 | .procname = "ip6frag_secret_interval", |
670 | .data = &ip6_frags.secret_interval, | 663 | .data = &ip6_frags.secret_interval, |
671 | .maxlen = sizeof(int), | 664 | .maxlen = sizeof(int), |
672 | .mode = 0644, | 665 | .mode = 0644, |
673 | .proc_handler = proc_dointvec_jiffies, | 666 | .proc_handler = proc_dointvec_jiffies, |
674 | .strategy = sysctl_jiffies | ||
675 | }, | 667 | }, |
676 | { } | 668 | { } |
677 | }; | 669 | }; |
678 | 670 | ||
679 | static int ip6_frags_ns_sysctl_register(struct net *net) | 671 | static int __net_init ip6_frags_ns_sysctl_register(struct net *net) |
680 | { | 672 | { |
681 | struct ctl_table *table; | 673 | struct ctl_table *table; |
682 | struct ctl_table_header *hdr; | 674 | struct ctl_table_header *hdr; |
683 | 675 | ||
684 | table = ip6_frags_ns_ctl_table; | 676 | table = ip6_frags_ns_ctl_table; |
685 | if (net != &init_net) { | 677 | if (!net_eq(net, &init_net)) { |
686 | table = kmemdup(table, sizeof(ip6_frags_ns_ctl_table), GFP_KERNEL); | 678 | table = kmemdup(table, sizeof(ip6_frags_ns_ctl_table), GFP_KERNEL); |
687 | if (table == NULL) | 679 | if (table == NULL) |
688 | goto err_alloc; | 680 | goto err_alloc; |
@@ -700,19 +692,20 @@ static int ip6_frags_ns_sysctl_register(struct net *net) | |||
700 | return 0; | 692 | return 0; |
701 | 693 | ||
702 | err_reg: | 694 | err_reg: |
703 | if (net != &init_net) | 695 | if (!net_eq(net, &init_net)) |
704 | kfree(table); | 696 | kfree(table); |
705 | err_alloc: | 697 | err_alloc: |
706 | return -ENOMEM; | 698 | return -ENOMEM; |
707 | } | 699 | } |
708 | 700 | ||
709 | static void ip6_frags_ns_sysctl_unregister(struct net *net) | 701 | static void __net_exit ip6_frags_ns_sysctl_unregister(struct net *net) |
710 | { | 702 | { |
711 | struct ctl_table *table; | 703 | struct ctl_table *table; |
712 | 704 | ||
713 | table = net->ipv6.sysctl.frags_hdr->ctl_table_arg; | 705 | table = net->ipv6.sysctl.frags_hdr->ctl_table_arg; |
714 | unregister_net_sysctl_table(net->ipv6.sysctl.frags_hdr); | 706 | unregister_net_sysctl_table(net->ipv6.sysctl.frags_hdr); |
715 | kfree(table); | 707 | if (!net_eq(net, &init_net)) |
708 | kfree(table); | ||
716 | } | 709 | } |
717 | 710 | ||
718 | static struct ctl_table_header *ip6_ctl_header; | 711 | static struct ctl_table_header *ip6_ctl_header; |
@@ -748,10 +741,10 @@ static inline void ip6_frags_sysctl_unregister(void) | |||
748 | } | 741 | } |
749 | #endif | 742 | #endif |
750 | 743 | ||
751 | static int ipv6_frags_init_net(struct net *net) | 744 | static int __net_init ipv6_frags_init_net(struct net *net) |
752 | { | 745 | { |
753 | net->ipv6.frags.high_thresh = 256 * 1024; | 746 | net->ipv6.frags.high_thresh = IPV6_FRAG_HIGH_THRESH; |
754 | net->ipv6.frags.low_thresh = 192 * 1024; | 747 | net->ipv6.frags.low_thresh = IPV6_FRAG_LOW_THRESH; |
755 | net->ipv6.frags.timeout = IPV6_FRAG_TIMEOUT; | 748 | net->ipv6.frags.timeout = IPV6_FRAG_TIMEOUT; |
756 | 749 | ||
757 | inet_frags_init_net(&net->ipv6.frags); | 750 | inet_frags_init_net(&net->ipv6.frags); |
@@ -759,7 +752,7 @@ static int ipv6_frags_init_net(struct net *net) | |||
759 | return ip6_frags_ns_sysctl_register(net); | 752 | return ip6_frags_ns_sysctl_register(net); |
760 | } | 753 | } |
761 | 754 | ||
762 | static void ipv6_frags_exit_net(struct net *net) | 755 | static void __net_exit ipv6_frags_exit_net(struct net *net) |
763 | { | 756 | { |
764 | ip6_frags_ns_sysctl_unregister(net); | 757 | ip6_frags_ns_sysctl_unregister(net); |
765 | inet_frags_exit_net(&net->ipv6.frags, &ip6_frags); | 758 | inet_frags_exit_net(&net->ipv6.frags, &ip6_frags); |
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index d6fe7646a8ff..05ebd7833043 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
@@ -40,6 +40,7 @@ | |||
40 | #include <linux/proc_fs.h> | 40 | #include <linux/proc_fs.h> |
41 | #include <linux/seq_file.h> | 41 | #include <linux/seq_file.h> |
42 | #include <linux/nsproxy.h> | 42 | #include <linux/nsproxy.h> |
43 | #include <linux/slab.h> | ||
43 | #include <net/net_namespace.h> | 44 | #include <net/net_namespace.h> |
44 | #include <net/snmp.h> | 45 | #include <net/snmp.h> |
45 | #include <net/ipv6.h> | 46 | #include <net/ipv6.h> |
@@ -814,20 +815,13 @@ struct dst_entry * ip6_route_output(struct net *net, struct sock *sk, | |||
814 | { | 815 | { |
815 | int flags = 0; | 816 | int flags = 0; |
816 | 817 | ||
817 | if (rt6_need_strict(&fl->fl6_dst)) | 818 | if (fl->oif || rt6_need_strict(&fl->fl6_dst)) |
818 | flags |= RT6_LOOKUP_F_IFACE; | 819 | flags |= RT6_LOOKUP_F_IFACE; |
819 | 820 | ||
820 | if (!ipv6_addr_any(&fl->fl6_src)) | 821 | if (!ipv6_addr_any(&fl->fl6_src)) |
821 | flags |= RT6_LOOKUP_F_HAS_SADDR; | 822 | flags |= RT6_LOOKUP_F_HAS_SADDR; |
822 | else if (sk) { | 823 | else if (sk) |
823 | unsigned int prefs = inet6_sk(sk)->srcprefs; | 824 | flags |= rt6_srcprefs2flags(inet6_sk(sk)->srcprefs); |
824 | if (prefs & IPV6_PREFER_SRC_TMP) | ||
825 | flags |= RT6_LOOKUP_F_SRCPREF_TMP; | ||
826 | if (prefs & IPV6_PREFER_SRC_PUBLIC) | ||
827 | flags |= RT6_LOOKUP_F_SRCPREF_PUBLIC; | ||
828 | if (prefs & IPV6_PREFER_SRC_COA) | ||
829 | flags |= RT6_LOOKUP_F_SRCPREF_COA; | ||
830 | } | ||
831 | 825 | ||
832 | return fib6_rule_lookup(net, fl, flags, ip6_pol_route_output); | 826 | return fib6_rule_lookup(net, fl, flags, ip6_pol_route_output); |
833 | } | 827 | } |
@@ -886,7 +880,7 @@ static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie) | |||
886 | 880 | ||
887 | rt = (struct rt6_info *) dst; | 881 | rt = (struct rt6_info *) dst; |
888 | 882 | ||
889 | if (rt && rt->rt6i_node && (rt->rt6i_node->fn_sernum == cookie)) | 883 | if (rt->rt6i_node && (rt->rt6i_node->fn_sernum == cookie)) |
890 | return dst; | 884 | return dst; |
891 | 885 | ||
892 | return NULL; | 886 | return NULL; |
@@ -897,19 +891,24 @@ static struct dst_entry *ip6_negative_advice(struct dst_entry *dst) | |||
897 | struct rt6_info *rt = (struct rt6_info *) dst; | 891 | struct rt6_info *rt = (struct rt6_info *) dst; |
898 | 892 | ||
899 | if (rt) { | 893 | if (rt) { |
900 | if (rt->rt6i_flags & RTF_CACHE) | 894 | if (rt->rt6i_flags & RTF_CACHE) { |
901 | ip6_del_rt(rt); | 895 | if (rt6_check_expired(rt)) { |
902 | else | 896 | ip6_del_rt(rt); |
897 | dst = NULL; | ||
898 | } | ||
899 | } else { | ||
903 | dst_release(dst); | 900 | dst_release(dst); |
901 | dst = NULL; | ||
902 | } | ||
904 | } | 903 | } |
905 | return NULL; | 904 | return dst; |
906 | } | 905 | } |
907 | 906 | ||
908 | static void ip6_link_failure(struct sk_buff *skb) | 907 | static void ip6_link_failure(struct sk_buff *skb) |
909 | { | 908 | { |
910 | struct rt6_info *rt; | 909 | struct rt6_info *rt; |
911 | 910 | ||
912 | icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0, skb->dev); | 911 | icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0); |
913 | 912 | ||
914 | rt = (struct rt6_info *) skb_dst(skb); | 913 | rt = (struct rt6_info *) skb_dst(skb); |
915 | if (rt) { | 914 | if (rt) { |
@@ -1471,9 +1470,10 @@ static struct rt6_info *ip6_route_redirect(struct in6_addr *dest, | |||
1471 | }, | 1470 | }, |
1472 | }, | 1471 | }, |
1473 | }, | 1472 | }, |
1474 | .gateway = *gateway, | ||
1475 | }; | 1473 | }; |
1476 | 1474 | ||
1475 | ipv6_addr_copy(&rdfl.gateway, gateway); | ||
1476 | |||
1477 | if (rt6_need_strict(dest)) | 1477 | if (rt6_need_strict(dest)) |
1478 | flags |= RT6_LOOKUP_F_IFACE; | 1478 | flags |= RT6_LOOKUP_F_IFACE; |
1479 | 1479 | ||
@@ -1872,7 +1872,7 @@ static int ip6_pkt_drop(struct sk_buff *skb, u8 code, int ipstats_mib_noroutes) | |||
1872 | switch (ipstats_mib_noroutes) { | 1872 | switch (ipstats_mib_noroutes) { |
1873 | case IPSTATS_MIB_INNOROUTES: | 1873 | case IPSTATS_MIB_INNOROUTES: |
1874 | type = ipv6_addr_type(&ipv6_hdr(skb)->daddr); | 1874 | type = ipv6_addr_type(&ipv6_hdr(skb)->daddr); |
1875 | if (type == IPV6_ADDR_ANY || type == IPV6_ADDR_RESERVED) { | 1875 | if (type == IPV6_ADDR_ANY) { |
1876 | IP6_INC_STATS(dev_net(dst->dev), ip6_dst_idev(dst), | 1876 | IP6_INC_STATS(dev_net(dst->dev), ip6_dst_idev(dst), |
1877 | IPSTATS_MIB_INADDRERRORS); | 1877 | IPSTATS_MIB_INADDRERRORS); |
1878 | break; | 1878 | break; |
@@ -1883,7 +1883,7 @@ static int ip6_pkt_drop(struct sk_buff *skb, u8 code, int ipstats_mib_noroutes) | |||
1883 | ipstats_mib_noroutes); | 1883 | ipstats_mib_noroutes); |
1884 | break; | 1884 | break; |
1885 | } | 1885 | } |
1886 | icmpv6_send(skb, ICMPV6_DEST_UNREACH, code, 0, skb->dev); | 1886 | icmpv6_send(skb, ICMPV6_DEST_UNREACH, code, 0); |
1887 | kfree_skb(skb); | 1887 | kfree_skb(skb); |
1888 | return 0; | 1888 | return 0; |
1889 | } | 1889 | } |
@@ -2546,7 +2546,6 @@ ctl_table ipv6_route_table_template[] = { | |||
2546 | .proc_handler = ipv6_sysctl_rtcache_flush | 2546 | .proc_handler = ipv6_sysctl_rtcache_flush |
2547 | }, | 2547 | }, |
2548 | { | 2548 | { |
2549 | .ctl_name = NET_IPV6_ROUTE_GC_THRESH, | ||
2550 | .procname = "gc_thresh", | 2549 | .procname = "gc_thresh", |
2551 | .data = &ip6_dst_ops_template.gc_thresh, | 2550 | .data = &ip6_dst_ops_template.gc_thresh, |
2552 | .maxlen = sizeof(int), | 2551 | .maxlen = sizeof(int), |
@@ -2554,7 +2553,6 @@ ctl_table ipv6_route_table_template[] = { | |||
2554 | .proc_handler = proc_dointvec, | 2553 | .proc_handler = proc_dointvec, |
2555 | }, | 2554 | }, |
2556 | { | 2555 | { |
2557 | .ctl_name = NET_IPV6_ROUTE_MAX_SIZE, | ||
2558 | .procname = "max_size", | 2556 | .procname = "max_size", |
2559 | .data = &init_net.ipv6.sysctl.ip6_rt_max_size, | 2557 | .data = &init_net.ipv6.sysctl.ip6_rt_max_size, |
2560 | .maxlen = sizeof(int), | 2558 | .maxlen = sizeof(int), |
@@ -2562,72 +2560,58 @@ ctl_table ipv6_route_table_template[] = { | |||
2562 | .proc_handler = proc_dointvec, | 2560 | .proc_handler = proc_dointvec, |
2563 | }, | 2561 | }, |
2564 | { | 2562 | { |
2565 | .ctl_name = NET_IPV6_ROUTE_GC_MIN_INTERVAL, | ||
2566 | .procname = "gc_min_interval", | 2563 | .procname = "gc_min_interval", |
2567 | .data = &init_net.ipv6.sysctl.ip6_rt_gc_min_interval, | 2564 | .data = &init_net.ipv6.sysctl.ip6_rt_gc_min_interval, |
2568 | .maxlen = sizeof(int), | 2565 | .maxlen = sizeof(int), |
2569 | .mode = 0644, | 2566 | .mode = 0644, |
2570 | .proc_handler = proc_dointvec_jiffies, | 2567 | .proc_handler = proc_dointvec_jiffies, |
2571 | .strategy = sysctl_jiffies, | ||
2572 | }, | 2568 | }, |
2573 | { | 2569 | { |
2574 | .ctl_name = NET_IPV6_ROUTE_GC_TIMEOUT, | ||
2575 | .procname = "gc_timeout", | 2570 | .procname = "gc_timeout", |
2576 | .data = &init_net.ipv6.sysctl.ip6_rt_gc_timeout, | 2571 | .data = &init_net.ipv6.sysctl.ip6_rt_gc_timeout, |
2577 | .maxlen = sizeof(int), | 2572 | .maxlen = sizeof(int), |
2578 | .mode = 0644, | 2573 | .mode = 0644, |
2579 | .proc_handler = proc_dointvec_jiffies, | 2574 | .proc_handler = proc_dointvec_jiffies, |
2580 | .strategy = sysctl_jiffies, | ||
2581 | }, | 2575 | }, |
2582 | { | 2576 | { |
2583 | .ctl_name = NET_IPV6_ROUTE_GC_INTERVAL, | ||
2584 | .procname = "gc_interval", | 2577 | .procname = "gc_interval", |
2585 | .data = &init_net.ipv6.sysctl.ip6_rt_gc_interval, | 2578 | .data = &init_net.ipv6.sysctl.ip6_rt_gc_interval, |
2586 | .maxlen = sizeof(int), | 2579 | .maxlen = sizeof(int), |
2587 | .mode = 0644, | 2580 | .mode = 0644, |
2588 | .proc_handler = proc_dointvec_jiffies, | 2581 | .proc_handler = proc_dointvec_jiffies, |
2589 | .strategy = sysctl_jiffies, | ||
2590 | }, | 2582 | }, |
2591 | { | 2583 | { |
2592 | .ctl_name = NET_IPV6_ROUTE_GC_ELASTICITY, | ||
2593 | .procname = "gc_elasticity", | 2584 | .procname = "gc_elasticity", |
2594 | .data = &init_net.ipv6.sysctl.ip6_rt_gc_elasticity, | 2585 | .data = &init_net.ipv6.sysctl.ip6_rt_gc_elasticity, |
2595 | .maxlen = sizeof(int), | 2586 | .maxlen = sizeof(int), |
2596 | .mode = 0644, | 2587 | .mode = 0644, |
2597 | .proc_handler = proc_dointvec_jiffies, | 2588 | .proc_handler = proc_dointvec_jiffies, |
2598 | .strategy = sysctl_jiffies, | ||
2599 | }, | 2589 | }, |
2600 | { | 2590 | { |
2601 | .ctl_name = NET_IPV6_ROUTE_MTU_EXPIRES, | ||
2602 | .procname = "mtu_expires", | 2591 | .procname = "mtu_expires", |
2603 | .data = &init_net.ipv6.sysctl.ip6_rt_mtu_expires, | 2592 | .data = &init_net.ipv6.sysctl.ip6_rt_mtu_expires, |
2604 | .maxlen = sizeof(int), | 2593 | .maxlen = sizeof(int), |
2605 | .mode = 0644, | 2594 | .mode = 0644, |
2606 | .proc_handler = proc_dointvec_jiffies, | 2595 | .proc_handler = proc_dointvec_jiffies, |
2607 | .strategy = sysctl_jiffies, | ||
2608 | }, | 2596 | }, |
2609 | { | 2597 | { |
2610 | .ctl_name = NET_IPV6_ROUTE_MIN_ADVMSS, | ||
2611 | .procname = "min_adv_mss", | 2598 | .procname = "min_adv_mss", |
2612 | .data = &init_net.ipv6.sysctl.ip6_rt_min_advmss, | 2599 | .data = &init_net.ipv6.sysctl.ip6_rt_min_advmss, |
2613 | .maxlen = sizeof(int), | 2600 | .maxlen = sizeof(int), |
2614 | .mode = 0644, | 2601 | .mode = 0644, |
2615 | .proc_handler = proc_dointvec_jiffies, | 2602 | .proc_handler = proc_dointvec_jiffies, |
2616 | .strategy = sysctl_jiffies, | ||
2617 | }, | 2603 | }, |
2618 | { | 2604 | { |
2619 | .ctl_name = NET_IPV6_ROUTE_GC_MIN_INTERVAL_MS, | ||
2620 | .procname = "gc_min_interval_ms", | 2605 | .procname = "gc_min_interval_ms", |
2621 | .data = &init_net.ipv6.sysctl.ip6_rt_gc_min_interval, | 2606 | .data = &init_net.ipv6.sysctl.ip6_rt_gc_min_interval, |
2622 | .maxlen = sizeof(int), | 2607 | .maxlen = sizeof(int), |
2623 | .mode = 0644, | 2608 | .mode = 0644, |
2624 | .proc_handler = proc_dointvec_ms_jiffies, | 2609 | .proc_handler = proc_dointvec_ms_jiffies, |
2625 | .strategy = sysctl_ms_jiffies, | ||
2626 | }, | 2610 | }, |
2627 | { .ctl_name = 0 } | 2611 | { } |
2628 | }; | 2612 | }; |
2629 | 2613 | ||
2630 | struct ctl_table *ipv6_route_sysctl_init(struct net *net) | 2614 | struct ctl_table * __net_init ipv6_route_sysctl_init(struct net *net) |
2631 | { | 2615 | { |
2632 | struct ctl_table *table; | 2616 | struct ctl_table *table; |
2633 | 2617 | ||
@@ -2645,13 +2629,14 @@ struct ctl_table *ipv6_route_sysctl_init(struct net *net) | |||
2645 | table[6].data = &net->ipv6.sysctl.ip6_rt_gc_elasticity; | 2629 | table[6].data = &net->ipv6.sysctl.ip6_rt_gc_elasticity; |
2646 | table[7].data = &net->ipv6.sysctl.ip6_rt_mtu_expires; | 2630 | table[7].data = &net->ipv6.sysctl.ip6_rt_mtu_expires; |
2647 | table[8].data = &net->ipv6.sysctl.ip6_rt_min_advmss; | 2631 | table[8].data = &net->ipv6.sysctl.ip6_rt_min_advmss; |
2632 | table[9].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval; | ||
2648 | } | 2633 | } |
2649 | 2634 | ||
2650 | return table; | 2635 | return table; |
2651 | } | 2636 | } |
2652 | #endif | 2637 | #endif |
2653 | 2638 | ||
2654 | static int ip6_route_net_init(struct net *net) | 2639 | static int __net_init ip6_route_net_init(struct net *net) |
2655 | { | 2640 | { |
2656 | int ret = -ENOMEM; | 2641 | int ret = -ENOMEM; |
2657 | 2642 | ||
@@ -2716,7 +2701,7 @@ out_ip6_dst_ops: | |||
2716 | goto out; | 2701 | goto out; |
2717 | } | 2702 | } |
2718 | 2703 | ||
2719 | static void ip6_route_net_exit(struct net *net) | 2704 | static void __net_exit ip6_route_net_exit(struct net *net) |
2720 | { | 2705 | { |
2721 | #ifdef CONFIG_PROC_FS | 2706 | #ifdef CONFIG_PROC_FS |
2722 | proc_net_remove(net, "ipv6_route"); | 2707 | proc_net_remove(net, "ipv6_route"); |
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index dbd19a78ca73..5abae10cd884 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/netdevice.h> | 28 | #include <linux/netdevice.h> |
29 | #include <linux/if_arp.h> | 29 | #include <linux/if_arp.h> |
30 | #include <linux/icmp.h> | 30 | #include <linux/icmp.h> |
31 | #include <linux/slab.h> | ||
31 | #include <asm/uaccess.h> | 32 | #include <asm/uaccess.h> |
32 | #include <linux/init.h> | 33 | #include <linux/init.h> |
33 | #include <linux/netfilter_ipv4.h> | 34 | #include <linux/netfilter_ipv4.h> |
@@ -62,11 +63,10 @@ | |||
62 | #define HASH_SIZE 16 | 63 | #define HASH_SIZE 16 |
63 | #define HASH(addr) (((__force u32)addr^((__force u32)addr>>4))&0xF) | 64 | #define HASH(addr) (((__force u32)addr^((__force u32)addr>>4))&0xF) |
64 | 65 | ||
65 | static void ipip6_fb_tunnel_init(struct net_device *dev); | ||
66 | static void ipip6_tunnel_init(struct net_device *dev); | 66 | static void ipip6_tunnel_init(struct net_device *dev); |
67 | static void ipip6_tunnel_setup(struct net_device *dev); | 67 | static void ipip6_tunnel_setup(struct net_device *dev); |
68 | 68 | ||
69 | static int sit_net_id; | 69 | static int sit_net_id __read_mostly; |
70 | struct sit_net { | 70 | struct sit_net { |
71 | struct ip_tunnel *tunnels_r_l[HASH_SIZE]; | 71 | struct ip_tunnel *tunnels_r_l[HASH_SIZE]; |
72 | struct ip_tunnel *tunnels_r[HASH_SIZE]; | 72 | struct ip_tunnel *tunnels_r[HASH_SIZE]; |
@@ -77,8 +77,17 @@ struct sit_net { | |||
77 | struct net_device *fb_tunnel_dev; | 77 | struct net_device *fb_tunnel_dev; |
78 | }; | 78 | }; |
79 | 79 | ||
80 | static DEFINE_RWLOCK(ipip6_lock); | 80 | /* |
81 | * Locking : hash tables are protected by RCU and a spinlock | ||
82 | */ | ||
83 | static DEFINE_SPINLOCK(ipip6_lock); | ||
84 | |||
85 | #define for_each_ip_tunnel_rcu(start) \ | ||
86 | for (t = rcu_dereference(start); t; t = rcu_dereference(t->next)) | ||
81 | 87 | ||
88 | /* | ||
89 | * Must be invoked with rcu_read_lock | ||
90 | */ | ||
82 | static struct ip_tunnel * ipip6_tunnel_lookup(struct net *net, | 91 | static struct ip_tunnel * ipip6_tunnel_lookup(struct net *net, |
83 | struct net_device *dev, __be32 remote, __be32 local) | 92 | struct net_device *dev, __be32 remote, __be32 local) |
84 | { | 93 | { |
@@ -87,26 +96,26 @@ static struct ip_tunnel * ipip6_tunnel_lookup(struct net *net, | |||
87 | struct ip_tunnel *t; | 96 | struct ip_tunnel *t; |
88 | struct sit_net *sitn = net_generic(net, sit_net_id); | 97 | struct sit_net *sitn = net_generic(net, sit_net_id); |
89 | 98 | ||
90 | for (t = sitn->tunnels_r_l[h0^h1]; t; t = t->next) { | 99 | for_each_ip_tunnel_rcu(sitn->tunnels_r_l[h0 ^ h1]) { |
91 | if (local == t->parms.iph.saddr && | 100 | if (local == t->parms.iph.saddr && |
92 | remote == t->parms.iph.daddr && | 101 | remote == t->parms.iph.daddr && |
93 | (!dev || !t->parms.link || dev->iflink == t->parms.link) && | 102 | (!dev || !t->parms.link || dev->iflink == t->parms.link) && |
94 | (t->dev->flags & IFF_UP)) | 103 | (t->dev->flags & IFF_UP)) |
95 | return t; | 104 | return t; |
96 | } | 105 | } |
97 | for (t = sitn->tunnels_r[h0]; t; t = t->next) { | 106 | for_each_ip_tunnel_rcu(sitn->tunnels_r[h0]) { |
98 | if (remote == t->parms.iph.daddr && | 107 | if (remote == t->parms.iph.daddr && |
99 | (!dev || !t->parms.link || dev->iflink == t->parms.link) && | 108 | (!dev || !t->parms.link || dev->iflink == t->parms.link) && |
100 | (t->dev->flags & IFF_UP)) | 109 | (t->dev->flags & IFF_UP)) |
101 | return t; | 110 | return t; |
102 | } | 111 | } |
103 | for (t = sitn->tunnels_l[h1]; t; t = t->next) { | 112 | for_each_ip_tunnel_rcu(sitn->tunnels_l[h1]) { |
104 | if (local == t->parms.iph.saddr && | 113 | if (local == t->parms.iph.saddr && |
105 | (!dev || !t->parms.link || dev->iflink == t->parms.link) && | 114 | (!dev || !t->parms.link || dev->iflink == t->parms.link) && |
106 | (t->dev->flags & IFF_UP)) | 115 | (t->dev->flags & IFF_UP)) |
107 | return t; | 116 | return t; |
108 | } | 117 | } |
109 | t = sitn->tunnels_wc[0]; | 118 | t = rcu_dereference(sitn->tunnels_wc[0]); |
110 | if ((t != NULL) && (t->dev->flags & IFF_UP)) | 119 | if ((t != NULL) && (t->dev->flags & IFF_UP)) |
111 | return t; | 120 | return t; |
112 | return NULL; | 121 | return NULL; |
@@ -143,9 +152,9 @@ static void ipip6_tunnel_unlink(struct sit_net *sitn, struct ip_tunnel *t) | |||
143 | 152 | ||
144 | for (tp = ipip6_bucket(sitn, t); *tp; tp = &(*tp)->next) { | 153 | for (tp = ipip6_bucket(sitn, t); *tp; tp = &(*tp)->next) { |
145 | if (t == *tp) { | 154 | if (t == *tp) { |
146 | write_lock_bh(&ipip6_lock); | 155 | spin_lock_bh(&ipip6_lock); |
147 | *tp = t->next; | 156 | *tp = t->next; |
148 | write_unlock_bh(&ipip6_lock); | 157 | spin_unlock_bh(&ipip6_lock); |
149 | break; | 158 | break; |
150 | } | 159 | } |
151 | } | 160 | } |
@@ -155,10 +164,27 @@ static void ipip6_tunnel_link(struct sit_net *sitn, struct ip_tunnel *t) | |||
155 | { | 164 | { |
156 | struct ip_tunnel **tp = ipip6_bucket(sitn, t); | 165 | struct ip_tunnel **tp = ipip6_bucket(sitn, t); |
157 | 166 | ||
167 | spin_lock_bh(&ipip6_lock); | ||
158 | t->next = *tp; | 168 | t->next = *tp; |
159 | write_lock_bh(&ipip6_lock); | 169 | rcu_assign_pointer(*tp, t); |
160 | *tp = t; | 170 | spin_unlock_bh(&ipip6_lock); |
161 | write_unlock_bh(&ipip6_lock); | 171 | } |
172 | |||
173 | static void ipip6_tunnel_clone_6rd(struct net_device *dev, struct sit_net *sitn) | ||
174 | { | ||
175 | #ifdef CONFIG_IPV6_SIT_6RD | ||
176 | struct ip_tunnel *t = netdev_priv(dev); | ||
177 | |||
178 | if (t->dev == sitn->fb_tunnel_dev) { | ||
179 | ipv6_addr_set(&t->ip6rd.prefix, htonl(0x20020000), 0, 0, 0); | ||
180 | t->ip6rd.relay_prefix = 0; | ||
181 | t->ip6rd.prefixlen = 16; | ||
182 | t->ip6rd.relay_prefixlen = 0; | ||
183 | } else { | ||
184 | struct ip_tunnel *t0 = netdev_priv(sitn->fb_tunnel_dev); | ||
185 | memcpy(&t->ip6rd, &t0->ip6rd, sizeof(t->ip6rd)); | ||
186 | } | ||
187 | #endif | ||
162 | } | 188 | } |
163 | 189 | ||
164 | static struct ip_tunnel * ipip6_tunnel_locate(struct net *net, | 190 | static struct ip_tunnel * ipip6_tunnel_locate(struct net *net, |
@@ -204,6 +230,7 @@ static struct ip_tunnel * ipip6_tunnel_locate(struct net *net, | |||
204 | 230 | ||
205 | nt->parms = *parms; | 231 | nt->parms = *parms; |
206 | ipip6_tunnel_init(dev); | 232 | ipip6_tunnel_init(dev); |
233 | ipip6_tunnel_clone_6rd(dev, sitn); | ||
207 | 234 | ||
208 | if (parms->i_flags & SIT_ISATAP) | 235 | if (parms->i_flags & SIT_ISATAP) |
209 | dev->priv_flags |= IFF_ISATAP; | 236 | dev->priv_flags |= IFF_ISATAP; |
@@ -222,15 +249,22 @@ failed: | |||
222 | return NULL; | 249 | return NULL; |
223 | } | 250 | } |
224 | 251 | ||
252 | static DEFINE_SPINLOCK(ipip6_prl_lock); | ||
253 | |||
254 | #define for_each_prl_rcu(start) \ | ||
255 | for (prl = rcu_dereference(start); \ | ||
256 | prl; \ | ||
257 | prl = rcu_dereference(prl->next)) | ||
258 | |||
225 | static struct ip_tunnel_prl_entry * | 259 | static struct ip_tunnel_prl_entry * |
226 | __ipip6_tunnel_locate_prl(struct ip_tunnel *t, __be32 addr) | 260 | __ipip6_tunnel_locate_prl(struct ip_tunnel *t, __be32 addr) |
227 | { | 261 | { |
228 | struct ip_tunnel_prl_entry *p = (struct ip_tunnel_prl_entry *)NULL; | 262 | struct ip_tunnel_prl_entry *prl; |
229 | 263 | ||
230 | for (p = t->prl; p; p = p->next) | 264 | for_each_prl_rcu(t->prl) |
231 | if (p->addr == addr) | 265 | if (prl->addr == addr) |
232 | break; | 266 | break; |
233 | return p; | 267 | return prl; |
234 | 268 | ||
235 | } | 269 | } |
236 | 270 | ||
@@ -255,7 +289,7 @@ static int ipip6_tunnel_get_prl(struct ip_tunnel *t, | |||
255 | kcalloc(cmax, sizeof(*kp), GFP_KERNEL) : | 289 | kcalloc(cmax, sizeof(*kp), GFP_KERNEL) : |
256 | NULL; | 290 | NULL; |
257 | 291 | ||
258 | read_lock(&ipip6_lock); | 292 | rcu_read_lock(); |
259 | 293 | ||
260 | ca = t->prl_count < cmax ? t->prl_count : cmax; | 294 | ca = t->prl_count < cmax ? t->prl_count : cmax; |
261 | 295 | ||
@@ -273,7 +307,7 @@ static int ipip6_tunnel_get_prl(struct ip_tunnel *t, | |||
273 | } | 307 | } |
274 | 308 | ||
275 | c = 0; | 309 | c = 0; |
276 | for (prl = t->prl; prl; prl = prl->next) { | 310 | for_each_prl_rcu(t->prl) { |
277 | if (c >= cmax) | 311 | if (c >= cmax) |
278 | break; | 312 | break; |
279 | if (kprl.addr != htonl(INADDR_ANY) && prl->addr != kprl.addr) | 313 | if (kprl.addr != htonl(INADDR_ANY) && prl->addr != kprl.addr) |
@@ -285,7 +319,7 @@ static int ipip6_tunnel_get_prl(struct ip_tunnel *t, | |||
285 | break; | 319 | break; |
286 | } | 320 | } |
287 | out: | 321 | out: |
288 | read_unlock(&ipip6_lock); | 322 | rcu_read_unlock(); |
289 | 323 | ||
290 | len = sizeof(*kp) * c; | 324 | len = sizeof(*kp) * c; |
291 | ret = 0; | 325 | ret = 0; |
@@ -306,12 +340,14 @@ ipip6_tunnel_add_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a, int chg) | |||
306 | if (a->addr == htonl(INADDR_ANY)) | 340 | if (a->addr == htonl(INADDR_ANY)) |
307 | return -EINVAL; | 341 | return -EINVAL; |
308 | 342 | ||
309 | write_lock(&ipip6_lock); | 343 | spin_lock(&ipip6_prl_lock); |
310 | 344 | ||
311 | for (p = t->prl; p; p = p->next) { | 345 | for (p = t->prl; p; p = p->next) { |
312 | if (p->addr == a->addr) { | 346 | if (p->addr == a->addr) { |
313 | if (chg) | 347 | if (chg) { |
314 | goto update; | 348 | p->flags = a->flags; |
349 | goto out; | ||
350 | } | ||
315 | err = -EEXIST; | 351 | err = -EEXIST; |
316 | goto out; | 352 | goto out; |
317 | } | 353 | } |
@@ -329,45 +365,61 @@ ipip6_tunnel_add_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a, int chg) | |||
329 | } | 365 | } |
330 | 366 | ||
331 | p->next = t->prl; | 367 | p->next = t->prl; |
332 | t->prl = p; | ||
333 | t->prl_count++; | ||
334 | update: | ||
335 | p->addr = a->addr; | 368 | p->addr = a->addr; |
336 | p->flags = a->flags; | 369 | p->flags = a->flags; |
370 | t->prl_count++; | ||
371 | rcu_assign_pointer(t->prl, p); | ||
337 | out: | 372 | out: |
338 | write_unlock(&ipip6_lock); | 373 | spin_unlock(&ipip6_prl_lock); |
339 | return err; | 374 | return err; |
340 | } | 375 | } |
341 | 376 | ||
377 | static void prl_entry_destroy_rcu(struct rcu_head *head) | ||
378 | { | ||
379 | kfree(container_of(head, struct ip_tunnel_prl_entry, rcu_head)); | ||
380 | } | ||
381 | |||
382 | static void prl_list_destroy_rcu(struct rcu_head *head) | ||
383 | { | ||
384 | struct ip_tunnel_prl_entry *p, *n; | ||
385 | |||
386 | p = container_of(head, struct ip_tunnel_prl_entry, rcu_head); | ||
387 | do { | ||
388 | n = p->next; | ||
389 | kfree(p); | ||
390 | p = n; | ||
391 | } while (p); | ||
392 | } | ||
393 | |||
342 | static int | 394 | static int |
343 | ipip6_tunnel_del_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a) | 395 | ipip6_tunnel_del_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a) |
344 | { | 396 | { |
345 | struct ip_tunnel_prl_entry *x, **p; | 397 | struct ip_tunnel_prl_entry *x, **p; |
346 | int err = 0; | 398 | int err = 0; |
347 | 399 | ||
348 | write_lock(&ipip6_lock); | 400 | spin_lock(&ipip6_prl_lock); |
349 | 401 | ||
350 | if (a && a->addr != htonl(INADDR_ANY)) { | 402 | if (a && a->addr != htonl(INADDR_ANY)) { |
351 | for (p = &t->prl; *p; p = &(*p)->next) { | 403 | for (p = &t->prl; *p; p = &(*p)->next) { |
352 | if ((*p)->addr == a->addr) { | 404 | if ((*p)->addr == a->addr) { |
353 | x = *p; | 405 | x = *p; |
354 | *p = x->next; | 406 | *p = x->next; |
355 | kfree(x); | 407 | call_rcu(&x->rcu_head, prl_entry_destroy_rcu); |
356 | t->prl_count--; | 408 | t->prl_count--; |
357 | goto out; | 409 | goto out; |
358 | } | 410 | } |
359 | } | 411 | } |
360 | err = -ENXIO; | 412 | err = -ENXIO; |
361 | } else { | 413 | } else { |
362 | while (t->prl) { | 414 | if (t->prl) { |
415 | t->prl_count = 0; | ||
363 | x = t->prl; | 416 | x = t->prl; |
364 | t->prl = t->prl->next; | 417 | call_rcu(&x->rcu_head, prl_list_destroy_rcu); |
365 | kfree(x); | 418 | t->prl = NULL; |
366 | t->prl_count--; | ||
367 | } | 419 | } |
368 | } | 420 | } |
369 | out: | 421 | out: |
370 | write_unlock(&ipip6_lock); | 422 | spin_unlock(&ipip6_prl_lock); |
371 | return err; | 423 | return err; |
372 | } | 424 | } |
373 | 425 | ||
@@ -377,7 +429,7 @@ isatap_chksrc(struct sk_buff *skb, struct iphdr *iph, struct ip_tunnel *t) | |||
377 | struct ip_tunnel_prl_entry *p; | 429 | struct ip_tunnel_prl_entry *p; |
378 | int ok = 1; | 430 | int ok = 1; |
379 | 431 | ||
380 | read_lock(&ipip6_lock); | 432 | rcu_read_lock(); |
381 | p = __ipip6_tunnel_locate_prl(t, iph->saddr); | 433 | p = __ipip6_tunnel_locate_prl(t, iph->saddr); |
382 | if (p) { | 434 | if (p) { |
383 | if (p->flags & PRL_DEFAULT) | 435 | if (p->flags & PRL_DEFAULT) |
@@ -393,7 +445,7 @@ isatap_chksrc(struct sk_buff *skb, struct iphdr *iph, struct ip_tunnel *t) | |||
393 | else | 445 | else |
394 | ok = 0; | 446 | ok = 0; |
395 | } | 447 | } |
396 | read_unlock(&ipip6_lock); | 448 | rcu_read_unlock(); |
397 | return ok; | 449 | return ok; |
398 | } | 450 | } |
399 | 451 | ||
@@ -403,9 +455,9 @@ static void ipip6_tunnel_uninit(struct net_device *dev) | |||
403 | struct sit_net *sitn = net_generic(net, sit_net_id); | 455 | struct sit_net *sitn = net_generic(net, sit_net_id); |
404 | 456 | ||
405 | if (dev == sitn->fb_tunnel_dev) { | 457 | if (dev == sitn->fb_tunnel_dev) { |
406 | write_lock_bh(&ipip6_lock); | 458 | spin_lock_bh(&ipip6_lock); |
407 | sitn->tunnels_wc[0] = NULL; | 459 | sitn->tunnels_wc[0] = NULL; |
408 | write_unlock_bh(&ipip6_lock); | 460 | spin_unlock_bh(&ipip6_lock); |
409 | dev_put(dev); | 461 | dev_put(dev); |
410 | } else { | 462 | } else { |
411 | ipip6_tunnel_unlink(sitn, netdev_priv(dev)); | 463 | ipip6_tunnel_unlink(sitn, netdev_priv(dev)); |
@@ -458,7 +510,7 @@ static int ipip6_err(struct sk_buff *skb, u32 info) | |||
458 | 510 | ||
459 | err = -ENOENT; | 511 | err = -ENOENT; |
460 | 512 | ||
461 | read_lock(&ipip6_lock); | 513 | rcu_read_lock(); |
462 | t = ipip6_tunnel_lookup(dev_net(skb->dev), | 514 | t = ipip6_tunnel_lookup(dev_net(skb->dev), |
463 | skb->dev, | 515 | skb->dev, |
464 | iph->daddr, | 516 | iph->daddr, |
@@ -476,7 +528,7 @@ static int ipip6_err(struct sk_buff *skb, u32 info) | |||
476 | t->err_count = 1; | 528 | t->err_count = 1; |
477 | t->err_time = jiffies; | 529 | t->err_time = jiffies; |
478 | out: | 530 | out: |
479 | read_unlock(&ipip6_lock); | 531 | rcu_read_unlock(); |
480 | return err; | 532 | return err; |
481 | } | 533 | } |
482 | 534 | ||
@@ -496,7 +548,7 @@ static int ipip6_rcv(struct sk_buff *skb) | |||
496 | 548 | ||
497 | iph = ip_hdr(skb); | 549 | iph = ip_hdr(skb); |
498 | 550 | ||
499 | read_lock(&ipip6_lock); | 551 | rcu_read_lock(); |
500 | tunnel = ipip6_tunnel_lookup(dev_net(skb->dev), skb->dev, | 552 | tunnel = ipip6_tunnel_lookup(dev_net(skb->dev), skb->dev, |
501 | iph->saddr, iph->daddr); | 553 | iph->saddr, iph->daddr); |
502 | if (tunnel != NULL) { | 554 | if (tunnel != NULL) { |
@@ -510,7 +562,7 @@ static int ipip6_rcv(struct sk_buff *skb) | |||
510 | if ((tunnel->dev->priv_flags & IFF_ISATAP) && | 562 | if ((tunnel->dev->priv_flags & IFF_ISATAP) && |
511 | !isatap_chksrc(skb, iph, tunnel)) { | 563 | !isatap_chksrc(skb, iph, tunnel)) { |
512 | tunnel->dev->stats.rx_errors++; | 564 | tunnel->dev->stats.rx_errors++; |
513 | read_unlock(&ipip6_lock); | 565 | rcu_read_unlock(); |
514 | kfree_skb(skb); | 566 | kfree_skb(skb); |
515 | return 0; | 567 | return 0; |
516 | } | 568 | } |
@@ -521,28 +573,52 @@ static int ipip6_rcv(struct sk_buff *skb) | |||
521 | nf_reset(skb); | 573 | nf_reset(skb); |
522 | ipip6_ecn_decapsulate(iph, skb); | 574 | ipip6_ecn_decapsulate(iph, skb); |
523 | netif_rx(skb); | 575 | netif_rx(skb); |
524 | read_unlock(&ipip6_lock); | 576 | rcu_read_unlock(); |
525 | return 0; | 577 | return 0; |
526 | } | 578 | } |
527 | 579 | ||
528 | icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); | 580 | icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); |
529 | read_unlock(&ipip6_lock); | 581 | rcu_read_unlock(); |
530 | out: | 582 | out: |
531 | kfree_skb(skb); | 583 | kfree_skb(skb); |
532 | return 0; | 584 | return 0; |
533 | } | 585 | } |
534 | 586 | ||
535 | /* Returns the embedded IPv4 address if the IPv6 address | 587 | /* |
536 | comes from 6to4 (RFC 3056) addr space */ | 588 | * Returns the embedded IPv4 address if the IPv6 address |
537 | 589 | * comes from 6rd / 6to4 (RFC 3056) addr space. | |
538 | static inline __be32 try_6to4(struct in6_addr *v6dst) | 590 | */ |
591 | static inline | ||
592 | __be32 try_6rd(struct in6_addr *v6dst, struct ip_tunnel *tunnel) | ||
539 | { | 593 | { |
540 | __be32 dst = 0; | 594 | __be32 dst = 0; |
541 | 595 | ||
596 | #ifdef CONFIG_IPV6_SIT_6RD | ||
597 | if (ipv6_prefix_equal(v6dst, &tunnel->ip6rd.prefix, | ||
598 | tunnel->ip6rd.prefixlen)) { | ||
599 | unsigned pbw0, pbi0; | ||
600 | int pbi1; | ||
601 | u32 d; | ||
602 | |||
603 | pbw0 = tunnel->ip6rd.prefixlen >> 5; | ||
604 | pbi0 = tunnel->ip6rd.prefixlen & 0x1f; | ||
605 | |||
606 | d = (ntohl(v6dst->s6_addr32[pbw0]) << pbi0) >> | ||
607 | tunnel->ip6rd.relay_prefixlen; | ||
608 | |||
609 | pbi1 = pbi0 - tunnel->ip6rd.relay_prefixlen; | ||
610 | if (pbi1 > 0) | ||
611 | d |= ntohl(v6dst->s6_addr32[pbw0 + 1]) >> | ||
612 | (32 - pbi1); | ||
613 | |||
614 | dst = tunnel->ip6rd.relay_prefix | htonl(d); | ||
615 | } | ||
616 | #else | ||
542 | if (v6dst->s6_addr16[0] == htons(0x2002)) { | 617 | if (v6dst->s6_addr16[0] == htons(0x2002)) { |
543 | /* 6to4 v6 addr has 16 bits prefix, 32 v4addr, 16 SLA, ... */ | 618 | /* 6to4 v6 addr has 16 bits prefix, 32 v4addr, 16 SLA, ... */ |
544 | memcpy(&dst, &v6dst->s6_addr16[1], 4); | 619 | memcpy(&dst, &v6dst->s6_addr16[1], 4); |
545 | } | 620 | } |
621 | #endif | ||
546 | return dst; | 622 | return dst; |
547 | } | 623 | } |
548 | 624 | ||
@@ -555,10 +631,12 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, | |||
555 | struct net_device *dev) | 631 | struct net_device *dev) |
556 | { | 632 | { |
557 | struct ip_tunnel *tunnel = netdev_priv(dev); | 633 | struct ip_tunnel *tunnel = netdev_priv(dev); |
558 | struct net_device_stats *stats = &tunnel->dev->stats; | 634 | struct net_device_stats *stats = &dev->stats; |
635 | struct netdev_queue *txq = netdev_get_tx_queue(dev, 0); | ||
559 | struct iphdr *tiph = &tunnel->parms.iph; | 636 | struct iphdr *tiph = &tunnel->parms.iph; |
560 | struct ipv6hdr *iph6 = ipv6_hdr(skb); | 637 | struct ipv6hdr *iph6 = ipv6_hdr(skb); |
561 | u8 tos = tunnel->parms.iph.tos; | 638 | u8 tos = tunnel->parms.iph.tos; |
639 | __be16 df = tiph->frag_off; | ||
562 | struct rtable *rt; /* Route to the other host */ | 640 | struct rtable *rt; /* Route to the other host */ |
563 | struct net_device *tdev; /* Device to other host */ | 641 | struct net_device *tdev; /* Device to other host */ |
564 | struct iphdr *iph; /* Our new IP header */ | 642 | struct iphdr *iph; /* Our new IP header */ |
@@ -595,7 +673,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, | |||
595 | } | 673 | } |
596 | 674 | ||
597 | if (!dst) | 675 | if (!dst) |
598 | dst = try_6to4(&iph6->daddr); | 676 | dst = try_6rd(&iph6->daddr, tunnel); |
599 | 677 | ||
600 | if (!dst) { | 678 | if (!dst) { |
601 | struct neighbour *neigh = NULL; | 679 | struct neighbour *neigh = NULL; |
@@ -648,25 +726,28 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, | |||
648 | goto tx_error; | 726 | goto tx_error; |
649 | } | 727 | } |
650 | 728 | ||
651 | if (tiph->frag_off) | 729 | if (df) { |
652 | mtu = dst_mtu(&rt->u.dst) - sizeof(struct iphdr); | 730 | mtu = dst_mtu(&rt->u.dst) - sizeof(struct iphdr); |
653 | else | ||
654 | mtu = skb_dst(skb) ? dst_mtu(skb_dst(skb)) : dev->mtu; | ||
655 | 731 | ||
656 | if (mtu < 68) { | 732 | if (mtu < 68) { |
657 | stats->collisions++; | 733 | stats->collisions++; |
658 | ip_rt_put(rt); | 734 | ip_rt_put(rt); |
659 | goto tx_error; | 735 | goto tx_error; |
660 | } | 736 | } |
661 | if (mtu < IPV6_MIN_MTU) | ||
662 | mtu = IPV6_MIN_MTU; | ||
663 | if (tunnel->parms.iph.daddr && skb_dst(skb)) | ||
664 | skb_dst(skb)->ops->update_pmtu(skb_dst(skb), mtu); | ||
665 | 737 | ||
666 | if (skb->len > mtu) { | 738 | if (mtu < IPV6_MIN_MTU) { |
667 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, dev); | 739 | mtu = IPV6_MIN_MTU; |
668 | ip_rt_put(rt); | 740 | df = 0; |
669 | goto tx_error; | 741 | } |
742 | |||
743 | if (tunnel->parms.iph.daddr && skb_dst(skb)) | ||
744 | skb_dst(skb)->ops->update_pmtu(skb_dst(skb), mtu); | ||
745 | |||
746 | if (skb->len > mtu) { | ||
747 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); | ||
748 | ip_rt_put(rt); | ||
749 | goto tx_error; | ||
750 | } | ||
670 | } | 751 | } |
671 | 752 | ||
672 | if (tunnel->err_count > 0) { | 753 | if (tunnel->err_count > 0) { |
@@ -688,7 +769,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, | |||
688 | struct sk_buff *new_skb = skb_realloc_headroom(skb, max_headroom); | 769 | struct sk_buff *new_skb = skb_realloc_headroom(skb, max_headroom); |
689 | if (!new_skb) { | 770 | if (!new_skb) { |
690 | ip_rt_put(rt); | 771 | ip_rt_put(rt); |
691 | stats->tx_dropped++; | 772 | txq->tx_dropped++; |
692 | dev_kfree_skb(skb); | 773 | dev_kfree_skb(skb); |
693 | return NETDEV_TX_OK; | 774 | return NETDEV_TX_OK; |
694 | } | 775 | } |
@@ -714,11 +795,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, | |||
714 | iph = ip_hdr(skb); | 795 | iph = ip_hdr(skb); |
715 | iph->version = 4; | 796 | iph->version = 4; |
716 | iph->ihl = sizeof(struct iphdr)>>2; | 797 | iph->ihl = sizeof(struct iphdr)>>2; |
717 | if (mtu > IPV6_MIN_MTU) | 798 | iph->frag_off = df; |
718 | iph->frag_off = tiph->frag_off; | ||
719 | else | ||
720 | iph->frag_off = 0; | ||
721 | |||
722 | iph->protocol = IPPROTO_IPV6; | 799 | iph->protocol = IPPROTO_IPV6; |
723 | iph->tos = INET_ECN_encapsulate(tos, ipv6_get_dsfield(iph6)); | 800 | iph->tos = INET_ECN_encapsulate(tos, ipv6_get_dsfield(iph6)); |
724 | iph->daddr = rt->rt_dst; | 801 | iph->daddr = rt->rt_dst; |
@@ -785,9 +862,15 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) | |||
785 | struct ip_tunnel *t; | 862 | struct ip_tunnel *t; |
786 | struct net *net = dev_net(dev); | 863 | struct net *net = dev_net(dev); |
787 | struct sit_net *sitn = net_generic(net, sit_net_id); | 864 | struct sit_net *sitn = net_generic(net, sit_net_id); |
865 | #ifdef CONFIG_IPV6_SIT_6RD | ||
866 | struct ip_tunnel_6rd ip6rd; | ||
867 | #endif | ||
788 | 868 | ||
789 | switch (cmd) { | 869 | switch (cmd) { |
790 | case SIOCGETTUNNEL: | 870 | case SIOCGETTUNNEL: |
871 | #ifdef CONFIG_IPV6_SIT_6RD | ||
872 | case SIOCGET6RD: | ||
873 | #endif | ||
791 | t = NULL; | 874 | t = NULL; |
792 | if (dev == sitn->fb_tunnel_dev) { | 875 | if (dev == sitn->fb_tunnel_dev) { |
793 | if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) { | 876 | if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) { |
@@ -798,9 +881,25 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) | |||
798 | } | 881 | } |
799 | if (t == NULL) | 882 | if (t == NULL) |
800 | t = netdev_priv(dev); | 883 | t = netdev_priv(dev); |
801 | memcpy(&p, &t->parms, sizeof(p)); | 884 | |
802 | if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p))) | 885 | err = -EFAULT; |
803 | err = -EFAULT; | 886 | if (cmd == SIOCGETTUNNEL) { |
887 | memcpy(&p, &t->parms, sizeof(p)); | ||
888 | if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, | ||
889 | sizeof(p))) | ||
890 | goto done; | ||
891 | #ifdef CONFIG_IPV6_SIT_6RD | ||
892 | } else { | ||
893 | ipv6_addr_copy(&ip6rd.prefix, &t->ip6rd.prefix); | ||
894 | ip6rd.relay_prefix = t->ip6rd.relay_prefix; | ||
895 | ip6rd.prefixlen = t->ip6rd.prefixlen; | ||
896 | ip6rd.relay_prefixlen = t->ip6rd.relay_prefixlen; | ||
897 | if (copy_to_user(ifr->ifr_ifru.ifru_data, &ip6rd, | ||
898 | sizeof(ip6rd))) | ||
899 | goto done; | ||
900 | #endif | ||
901 | } | ||
902 | err = 0; | ||
804 | break; | 903 | break; |
805 | 904 | ||
806 | case SIOCADDTUNNEL: | 905 | case SIOCADDTUNNEL: |
@@ -921,6 +1020,54 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) | |||
921 | netdev_state_change(dev); | 1020 | netdev_state_change(dev); |
922 | break; | 1021 | break; |
923 | 1022 | ||
1023 | #ifdef CONFIG_IPV6_SIT_6RD | ||
1024 | case SIOCADD6RD: | ||
1025 | case SIOCCHG6RD: | ||
1026 | case SIOCDEL6RD: | ||
1027 | err = -EPERM; | ||
1028 | if (!capable(CAP_NET_ADMIN)) | ||
1029 | goto done; | ||
1030 | |||
1031 | err = -EFAULT; | ||
1032 | if (copy_from_user(&ip6rd, ifr->ifr_ifru.ifru_data, | ||
1033 | sizeof(ip6rd))) | ||
1034 | goto done; | ||
1035 | |||
1036 | t = netdev_priv(dev); | ||
1037 | |||
1038 | if (cmd != SIOCDEL6RD) { | ||
1039 | struct in6_addr prefix; | ||
1040 | __be32 relay_prefix; | ||
1041 | |||
1042 | err = -EINVAL; | ||
1043 | if (ip6rd.relay_prefixlen > 32 || | ||
1044 | ip6rd.prefixlen + (32 - ip6rd.relay_prefixlen) > 64) | ||
1045 | goto done; | ||
1046 | |||
1047 | ipv6_addr_prefix(&prefix, &ip6rd.prefix, | ||
1048 | ip6rd.prefixlen); | ||
1049 | if (!ipv6_addr_equal(&prefix, &ip6rd.prefix)) | ||
1050 | goto done; | ||
1051 | if (ip6rd.relay_prefixlen) | ||
1052 | relay_prefix = ip6rd.relay_prefix & | ||
1053 | htonl(0xffffffffUL << | ||
1054 | (32 - ip6rd.relay_prefixlen)); | ||
1055 | else | ||
1056 | relay_prefix = 0; | ||
1057 | if (relay_prefix != ip6rd.relay_prefix) | ||
1058 | goto done; | ||
1059 | |||
1060 | ipv6_addr_copy(&t->ip6rd.prefix, &prefix); | ||
1061 | t->ip6rd.relay_prefix = relay_prefix; | ||
1062 | t->ip6rd.prefixlen = ip6rd.prefixlen; | ||
1063 | t->ip6rd.relay_prefixlen = ip6rd.relay_prefixlen; | ||
1064 | } else | ||
1065 | ipip6_tunnel_clone_6rd(dev, sitn); | ||
1066 | |||
1067 | err = 0; | ||
1068 | break; | ||
1069 | #endif | ||
1070 | |||
924 | default: | 1071 | default: |
925 | err = -EINVAL; | 1072 | err = -EINVAL; |
926 | } | 1073 | } |
@@ -972,7 +1119,7 @@ static void ipip6_tunnel_init(struct net_device *dev) | |||
972 | ipip6_tunnel_bind_dev(dev); | 1119 | ipip6_tunnel_bind_dev(dev); |
973 | } | 1120 | } |
974 | 1121 | ||
975 | static void ipip6_fb_tunnel_init(struct net_device *dev) | 1122 | static void __net_init ipip6_fb_tunnel_init(struct net_device *dev) |
976 | { | 1123 | { |
977 | struct ip_tunnel *tunnel = netdev_priv(dev); | 1124 | struct ip_tunnel *tunnel = netdev_priv(dev); |
978 | struct iphdr *iph = &tunnel->parms.iph; | 1125 | struct iphdr *iph = &tunnel->parms.iph; |
@@ -997,33 +1144,27 @@ static struct xfrm_tunnel sit_handler = { | |||
997 | .priority = 1, | 1144 | .priority = 1, |
998 | }; | 1145 | }; |
999 | 1146 | ||
1000 | static void sit_destroy_tunnels(struct sit_net *sitn) | 1147 | static void __net_exit sit_destroy_tunnels(struct sit_net *sitn, struct list_head *head) |
1001 | { | 1148 | { |
1002 | int prio; | 1149 | int prio; |
1003 | 1150 | ||
1004 | for (prio = 1; prio < 4; prio++) { | 1151 | for (prio = 1; prio < 4; prio++) { |
1005 | int h; | 1152 | int h; |
1006 | for (h = 0; h < HASH_SIZE; h++) { | 1153 | for (h = 0; h < HASH_SIZE; h++) { |
1007 | struct ip_tunnel *t; | 1154 | struct ip_tunnel *t = sitn->tunnels[prio][h]; |
1008 | while ((t = sitn->tunnels[prio][h]) != NULL) | 1155 | |
1009 | unregister_netdevice(t->dev); | 1156 | while (t != NULL) { |
1157 | unregister_netdevice_queue(t->dev, head); | ||
1158 | t = t->next; | ||
1159 | } | ||
1010 | } | 1160 | } |
1011 | } | 1161 | } |
1012 | } | 1162 | } |
1013 | 1163 | ||
1014 | static int sit_init_net(struct net *net) | 1164 | static int __net_init sit_init_net(struct net *net) |
1015 | { | 1165 | { |
1166 | struct sit_net *sitn = net_generic(net, sit_net_id); | ||
1016 | int err; | 1167 | int err; |
1017 | struct sit_net *sitn; | ||
1018 | |||
1019 | err = -ENOMEM; | ||
1020 | sitn = kzalloc(sizeof(struct sit_net), GFP_KERNEL); | ||
1021 | if (sitn == NULL) | ||
1022 | goto err_alloc; | ||
1023 | |||
1024 | err = net_assign_generic(net, sit_net_id, sitn); | ||
1025 | if (err < 0) | ||
1026 | goto err_assign; | ||
1027 | 1168 | ||
1028 | sitn->tunnels[0] = sitn->tunnels_wc; | 1169 | sitn->tunnels[0] = sitn->tunnels_wc; |
1029 | sitn->tunnels[1] = sitn->tunnels_l; | 1170 | sitn->tunnels[1] = sitn->tunnels_l; |
@@ -1039,6 +1180,7 @@ static int sit_init_net(struct net *net) | |||
1039 | dev_net_set(sitn->fb_tunnel_dev, net); | 1180 | dev_net_set(sitn->fb_tunnel_dev, net); |
1040 | 1181 | ||
1041 | ipip6_fb_tunnel_init(sitn->fb_tunnel_dev); | 1182 | ipip6_fb_tunnel_init(sitn->fb_tunnel_dev); |
1183 | ipip6_tunnel_clone_6rd(sitn->fb_tunnel_dev, sitn); | ||
1042 | 1184 | ||
1043 | if ((err = register_netdev(sitn->fb_tunnel_dev))) | 1185 | if ((err = register_netdev(sitn->fb_tunnel_dev))) |
1044 | goto err_reg_dev; | 1186 | goto err_reg_dev; |
@@ -1049,35 +1191,34 @@ err_reg_dev: | |||
1049 | dev_put(sitn->fb_tunnel_dev); | 1191 | dev_put(sitn->fb_tunnel_dev); |
1050 | free_netdev(sitn->fb_tunnel_dev); | 1192 | free_netdev(sitn->fb_tunnel_dev); |
1051 | err_alloc_dev: | 1193 | err_alloc_dev: |
1052 | /* nothing */ | ||
1053 | err_assign: | ||
1054 | kfree(sitn); | ||
1055 | err_alloc: | ||
1056 | return err; | 1194 | return err; |
1057 | } | 1195 | } |
1058 | 1196 | ||
1059 | static void sit_exit_net(struct net *net) | 1197 | static void __net_exit sit_exit_net(struct net *net) |
1060 | { | 1198 | { |
1061 | struct sit_net *sitn; | 1199 | struct sit_net *sitn = net_generic(net, sit_net_id); |
1200 | LIST_HEAD(list); | ||
1062 | 1201 | ||
1063 | sitn = net_generic(net, sit_net_id); | ||
1064 | rtnl_lock(); | 1202 | rtnl_lock(); |
1065 | sit_destroy_tunnels(sitn); | 1203 | sit_destroy_tunnels(sitn, &list); |
1066 | unregister_netdevice(sitn->fb_tunnel_dev); | 1204 | unregister_netdevice_queue(sitn->fb_tunnel_dev, &list); |
1205 | unregister_netdevice_many(&list); | ||
1067 | rtnl_unlock(); | 1206 | rtnl_unlock(); |
1068 | kfree(sitn); | ||
1069 | } | 1207 | } |
1070 | 1208 | ||
1071 | static struct pernet_operations sit_net_ops = { | 1209 | static struct pernet_operations sit_net_ops = { |
1072 | .init = sit_init_net, | 1210 | .init = sit_init_net, |
1073 | .exit = sit_exit_net, | 1211 | .exit = sit_exit_net, |
1212 | .id = &sit_net_id, | ||
1213 | .size = sizeof(struct sit_net), | ||
1074 | }; | 1214 | }; |
1075 | 1215 | ||
1076 | static void __exit sit_cleanup(void) | 1216 | static void __exit sit_cleanup(void) |
1077 | { | 1217 | { |
1078 | xfrm4_tunnel_deregister(&sit_handler, AF_INET6); | 1218 | xfrm4_tunnel_deregister(&sit_handler, AF_INET6); |
1079 | 1219 | ||
1080 | unregister_pernet_gen_device(sit_net_id, &sit_net_ops); | 1220 | unregister_pernet_device(&sit_net_ops); |
1221 | rcu_barrier(); /* Wait for completion of call_rcu()'s */ | ||
1081 | } | 1222 | } |
1082 | 1223 | ||
1083 | static int __init sit_init(void) | 1224 | static int __init sit_init(void) |
@@ -1086,15 +1227,14 @@ static int __init sit_init(void) | |||
1086 | 1227 | ||
1087 | printk(KERN_INFO "IPv6 over IPv4 tunneling driver\n"); | 1228 | printk(KERN_INFO "IPv6 over IPv4 tunneling driver\n"); |
1088 | 1229 | ||
1089 | if (xfrm4_tunnel_register(&sit_handler, AF_INET6) < 0) { | 1230 | err = register_pernet_device(&sit_net_ops); |
1231 | if (err < 0) | ||
1232 | return err; | ||
1233 | err = xfrm4_tunnel_register(&sit_handler, AF_INET6); | ||
1234 | if (err < 0) { | ||
1235 | unregister_pernet_device(&sit_net_ops); | ||
1090 | printk(KERN_INFO "sit init: Can't add protocol\n"); | 1236 | printk(KERN_INFO "sit init: Can't add protocol\n"); |
1091 | return -EAGAIN; | ||
1092 | } | 1237 | } |
1093 | |||
1094 | err = register_pernet_gen_device(&sit_net_id, &sit_net_ops); | ||
1095 | if (err < 0) | ||
1096 | xfrm4_tunnel_deregister(&sit_handler, AF_INET6); | ||
1097 | |||
1098 | return err; | 1238 | return err; |
1099 | } | 1239 | } |
1100 | 1240 | ||
diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c index 6b6ae913b5d4..34d1f0690d7e 100644 --- a/net/ipv6/syncookies.c +++ b/net/ipv6/syncookies.c | |||
@@ -159,6 +159,8 @@ static inline int cookie_check(struct sk_buff *skb, __u32 cookie) | |||
159 | 159 | ||
160 | struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) | 160 | struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) |
161 | { | 161 | { |
162 | struct tcp_options_received tcp_opt; | ||
163 | u8 *hash_location; | ||
162 | struct inet_request_sock *ireq; | 164 | struct inet_request_sock *ireq; |
163 | struct inet6_request_sock *ireq6; | 165 | struct inet6_request_sock *ireq6; |
164 | struct tcp_request_sock *treq; | 166 | struct tcp_request_sock *treq; |
@@ -171,7 +173,6 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) | |||
171 | int mss; | 173 | int mss; |
172 | struct dst_entry *dst; | 174 | struct dst_entry *dst; |
173 | __u8 rcv_wscale; | 175 | __u8 rcv_wscale; |
174 | struct tcp_options_received tcp_opt; | ||
175 | 176 | ||
176 | if (!sysctl_tcp_syncookies || !th->ack) | 177 | if (!sysctl_tcp_syncookies || !th->ack) |
177 | goto out; | 178 | goto out; |
@@ -186,7 +187,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) | |||
186 | 187 | ||
187 | /* check for timestamp cookie support */ | 188 | /* check for timestamp cookie support */ |
188 | memset(&tcp_opt, 0, sizeof(tcp_opt)); | 189 | memset(&tcp_opt, 0, sizeof(tcp_opt)); |
189 | tcp_parse_options(skb, &tcp_opt, 0); | 190 | tcp_parse_options(skb, &tcp_opt, &hash_location, 0); |
190 | 191 | ||
191 | if (tcp_opt.saw_tstamp) | 192 | if (tcp_opt.saw_tstamp) |
192 | cookie_check_timestamp(&tcp_opt); | 193 | cookie_check_timestamp(&tcp_opt); |
@@ -252,8 +253,9 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) | |||
252 | } | 253 | } |
253 | ipv6_addr_copy(&fl.fl6_src, &ireq6->loc_addr); | 254 | ipv6_addr_copy(&fl.fl6_src, &ireq6->loc_addr); |
254 | fl.oif = sk->sk_bound_dev_if; | 255 | fl.oif = sk->sk_bound_dev_if; |
256 | fl.mark = sk->sk_mark; | ||
255 | fl.fl_ip_dport = inet_rsk(req)->rmt_port; | 257 | fl.fl_ip_dport = inet_rsk(req)->rmt_port; |
256 | fl.fl_ip_sport = inet_sk(sk)->sport; | 258 | fl.fl_ip_sport = inet_sk(sk)->inet_sport; |
257 | security_req_classify_flow(req, &fl); | 259 | security_req_classify_flow(req, &fl); |
258 | if (ip6_dst_lookup(sk, &dst, &fl)) | 260 | if (ip6_dst_lookup(sk, &dst, &fl)) |
259 | goto out_free; | 261 | goto out_free; |
@@ -267,7 +269,8 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) | |||
267 | req->window_clamp = tp->window_clamp ? :dst_metric(dst, RTAX_WINDOW); | 269 | req->window_clamp = tp->window_clamp ? :dst_metric(dst, RTAX_WINDOW); |
268 | tcp_select_initial_window(tcp_full_space(sk), req->mss, | 270 | tcp_select_initial_window(tcp_full_space(sk), req->mss, |
269 | &req->rcv_wnd, &req->window_clamp, | 271 | &req->rcv_wnd, &req->window_clamp, |
270 | ireq->wscale_ok, &rcv_wscale); | 272 | ireq->wscale_ok, &rcv_wscale, |
273 | dst_metric(dst, RTAX_INITRWND)); | ||
271 | 274 | ||
272 | ireq->rcv_wscale = rcv_wscale; | 275 | ireq->rcv_wscale = rcv_wscale; |
273 | 276 | ||
diff --git a/net/ipv6/sysctl_net_ipv6.c b/net/ipv6/sysctl_net_ipv6.c index 0dc6a4e5ed4a..fa1d8f4e0051 100644 --- a/net/ipv6/sysctl_net_ipv6.c +++ b/net/ipv6/sysctl_net_ipv6.c | |||
@@ -9,6 +9,7 @@ | |||
9 | #include <linux/sysctl.h> | 9 | #include <linux/sysctl.h> |
10 | #include <linux/in6.h> | 10 | #include <linux/in6.h> |
11 | #include <linux/ipv6.h> | 11 | #include <linux/ipv6.h> |
12 | #include <linux/slab.h> | ||
12 | #include <net/ndisc.h> | 13 | #include <net/ndisc.h> |
13 | #include <net/ipv6.h> | 14 | #include <net/ipv6.h> |
14 | #include <net/addrconf.h> | 15 | #include <net/addrconf.h> |
@@ -16,50 +17,46 @@ | |||
16 | 17 | ||
17 | static ctl_table ipv6_table_template[] = { | 18 | static ctl_table ipv6_table_template[] = { |
18 | { | 19 | { |
19 | .ctl_name = NET_IPV6_ROUTE, | ||
20 | .procname = "route", | 20 | .procname = "route", |
21 | .maxlen = 0, | 21 | .maxlen = 0, |
22 | .mode = 0555, | 22 | .mode = 0555, |
23 | .child = ipv6_route_table_template | 23 | .child = ipv6_route_table_template |
24 | }, | 24 | }, |
25 | { | 25 | { |
26 | .ctl_name = NET_IPV6_ICMP, | ||
27 | .procname = "icmp", | 26 | .procname = "icmp", |
28 | .maxlen = 0, | 27 | .maxlen = 0, |
29 | .mode = 0555, | 28 | .mode = 0555, |
30 | .child = ipv6_icmp_table_template | 29 | .child = ipv6_icmp_table_template |
31 | }, | 30 | }, |
32 | { | 31 | { |
33 | .ctl_name = NET_IPV6_BINDV6ONLY, | ||
34 | .procname = "bindv6only", | 32 | .procname = "bindv6only", |
35 | .data = &init_net.ipv6.sysctl.bindv6only, | 33 | .data = &init_net.ipv6.sysctl.bindv6only, |
36 | .maxlen = sizeof(int), | 34 | .maxlen = sizeof(int), |
37 | .mode = 0644, | 35 | .mode = 0644, |
38 | .proc_handler = proc_dointvec | 36 | .proc_handler = proc_dointvec |
39 | }, | 37 | }, |
40 | { .ctl_name = 0 } | 38 | { } |
41 | }; | 39 | }; |
42 | 40 | ||
43 | static ctl_table ipv6_rotable[] = { | 41 | static ctl_table ipv6_rotable[] = { |
44 | { | 42 | { |
45 | .ctl_name = NET_IPV6_MLD_MAX_MSF, | ||
46 | .procname = "mld_max_msf", | 43 | .procname = "mld_max_msf", |
47 | .data = &sysctl_mld_max_msf, | 44 | .data = &sysctl_mld_max_msf, |
48 | .maxlen = sizeof(int), | 45 | .maxlen = sizeof(int), |
49 | .mode = 0644, | 46 | .mode = 0644, |
50 | .proc_handler = proc_dointvec | 47 | .proc_handler = proc_dointvec |
51 | }, | 48 | }, |
52 | { .ctl_name = 0 } | 49 | { } |
53 | }; | 50 | }; |
54 | 51 | ||
55 | struct ctl_path net_ipv6_ctl_path[] = { | 52 | struct ctl_path net_ipv6_ctl_path[] = { |
56 | { .procname = "net", .ctl_name = CTL_NET, }, | 53 | { .procname = "net", }, |
57 | { .procname = "ipv6", .ctl_name = NET_IPV6, }, | 54 | { .procname = "ipv6", }, |
58 | { }, | 55 | { }, |
59 | }; | 56 | }; |
60 | EXPORT_SYMBOL_GPL(net_ipv6_ctl_path); | 57 | EXPORT_SYMBOL_GPL(net_ipv6_ctl_path); |
61 | 58 | ||
62 | static int ipv6_sysctl_net_init(struct net *net) | 59 | static int __net_init ipv6_sysctl_net_init(struct net *net) |
63 | { | 60 | { |
64 | struct ctl_table *ipv6_table; | 61 | struct ctl_table *ipv6_table; |
65 | struct ctl_table *ipv6_route_table; | 62 | struct ctl_table *ipv6_route_table; |
@@ -102,7 +99,7 @@ out_ipv6_table: | |||
102 | goto out; | 99 | goto out; |
103 | } | 100 | } |
104 | 101 | ||
105 | static void ipv6_sysctl_net_exit(struct net *net) | 102 | static void __net_exit ipv6_sysctl_net_exit(struct net *net) |
106 | { | 103 | { |
107 | struct ctl_table *ipv6_table; | 104 | struct ctl_table *ipv6_table; |
108 | struct ctl_table *ipv6_route_table; | 105 | struct ctl_table *ipv6_route_table; |
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 21d100b68b19..075f540ec197 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c | |||
@@ -38,6 +38,7 @@ | |||
38 | #include <linux/jhash.h> | 38 | #include <linux/jhash.h> |
39 | #include <linux/ipsec.h> | 39 | #include <linux/ipsec.h> |
40 | #include <linux/times.h> | 40 | #include <linux/times.h> |
41 | #include <linux/slab.h> | ||
41 | 42 | ||
42 | #include <linux/ipv6.h> | 43 | #include <linux/ipv6.h> |
43 | #include <linux/icmpv6.h> | 44 | #include <linux/icmpv6.h> |
@@ -96,7 +97,7 @@ static void tcp_v6_hash(struct sock *sk) | |||
96 | return; | 97 | return; |
97 | } | 98 | } |
98 | local_bh_disable(); | 99 | local_bh_disable(); |
99 | __inet6_hash(sk); | 100 | __inet6_hash(sk, NULL); |
100 | local_bh_enable(); | 101 | local_bh_enable(); |
101 | } | 102 | } |
102 | } | 103 | } |
@@ -226,10 +227,9 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, | |||
226 | #endif | 227 | #endif |
227 | goto failure; | 228 | goto failure; |
228 | } else { | 229 | } else { |
229 | ipv6_addr_set(&np->saddr, 0, 0, htonl(0x0000FFFF), | 230 | ipv6_addr_set_v4mapped(inet->inet_saddr, &np->saddr); |
230 | inet->saddr); | 231 | ipv6_addr_set_v4mapped(inet->inet_rcv_saddr, |
231 | ipv6_addr_set(&np->rcv_saddr, 0, 0, htonl(0x0000FFFF), | 232 | &np->rcv_saddr); |
232 | inet->rcv_saddr); | ||
233 | } | 233 | } |
234 | 234 | ||
235 | return err; | 235 | return err; |
@@ -243,8 +243,9 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, | |||
243 | ipv6_addr_copy(&fl.fl6_src, | 243 | ipv6_addr_copy(&fl.fl6_src, |
244 | (saddr ? saddr : &np->saddr)); | 244 | (saddr ? saddr : &np->saddr)); |
245 | fl.oif = sk->sk_bound_dev_if; | 245 | fl.oif = sk->sk_bound_dev_if; |
246 | fl.mark = sk->sk_mark; | ||
246 | fl.fl_ip_dport = usin->sin6_port; | 247 | fl.fl_ip_dport = usin->sin6_port; |
247 | fl.fl_ip_sport = inet->sport; | 248 | fl.fl_ip_sport = inet->inet_sport; |
248 | 249 | ||
249 | if (np->opt && np->opt->srcrt) { | 250 | if (np->opt && np->opt->srcrt) { |
250 | struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt; | 251 | struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt; |
@@ -276,7 +277,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, | |||
276 | 277 | ||
277 | /* set the source address */ | 278 | /* set the source address */ |
278 | ipv6_addr_copy(&np->saddr, saddr); | 279 | ipv6_addr_copy(&np->saddr, saddr); |
279 | inet->rcv_saddr = LOOPBACK4_IPV6; | 280 | inet->inet_rcv_saddr = LOOPBACK4_IPV6; |
280 | 281 | ||
281 | sk->sk_gso_type = SKB_GSO_TCPV6; | 282 | sk->sk_gso_type = SKB_GSO_TCPV6; |
282 | __ip6_dst_store(sk, dst, NULL, NULL); | 283 | __ip6_dst_store(sk, dst, NULL, NULL); |
@@ -288,7 +289,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, | |||
288 | 289 | ||
289 | tp->rx_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr); | 290 | tp->rx_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr); |
290 | 291 | ||
291 | inet->dport = usin->sin6_port; | 292 | inet->inet_dport = usin->sin6_port; |
292 | 293 | ||
293 | tcp_set_state(sk, TCP_SYN_SENT); | 294 | tcp_set_state(sk, TCP_SYN_SENT); |
294 | err = inet6_hash_connect(&tcp_death_row, sk); | 295 | err = inet6_hash_connect(&tcp_death_row, sk); |
@@ -298,8 +299,8 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, | |||
298 | if (!tp->write_seq) | 299 | if (!tp->write_seq) |
299 | tp->write_seq = secure_tcpv6_sequence_number(np->saddr.s6_addr32, | 300 | tp->write_seq = secure_tcpv6_sequence_number(np->saddr.s6_addr32, |
300 | np->daddr.s6_addr32, | 301 | np->daddr.s6_addr32, |
301 | inet->sport, | 302 | inet->inet_sport, |
302 | inet->dport); | 303 | inet->inet_dport); |
303 | 304 | ||
304 | err = tcp_connect(sk); | 305 | err = tcp_connect(sk); |
305 | if (err) | 306 | if (err) |
@@ -311,7 +312,7 @@ late_failure: | |||
311 | tcp_set_state(sk, TCP_CLOSE); | 312 | tcp_set_state(sk, TCP_CLOSE); |
312 | __sk_dst_reset(sk); | 313 | __sk_dst_reset(sk); |
313 | failure: | 314 | failure: |
314 | inet->dport = 0; | 315 | inet->inet_dport = 0; |
315 | sk->sk_route_caps = 0; | 316 | sk->sk_route_caps = 0; |
316 | return err; | 317 | return err; |
317 | } | 318 | } |
@@ -383,8 +384,9 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
383 | ipv6_addr_copy(&fl.fl6_dst, &np->daddr); | 384 | ipv6_addr_copy(&fl.fl6_dst, &np->daddr); |
384 | ipv6_addr_copy(&fl.fl6_src, &np->saddr); | 385 | ipv6_addr_copy(&fl.fl6_src, &np->saddr); |
385 | fl.oif = sk->sk_bound_dev_if; | 386 | fl.oif = sk->sk_bound_dev_if; |
386 | fl.fl_ip_dport = inet->dport; | 387 | fl.mark = sk->sk_mark; |
387 | fl.fl_ip_sport = inet->sport; | 388 | fl.fl_ip_dport = inet->inet_dport; |
389 | fl.fl_ip_sport = inet->inet_sport; | ||
388 | security_skb_classify_flow(skb, &fl); | 390 | security_skb_classify_flow(skb, &fl); |
389 | 391 | ||
390 | if ((err = ip6_dst_lookup(sk, &dst, &fl))) { | 392 | if ((err = ip6_dst_lookup(sk, &dst, &fl))) { |
@@ -460,7 +462,8 @@ out: | |||
460 | } | 462 | } |
461 | 463 | ||
462 | 464 | ||
463 | static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req) | 465 | static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req, |
466 | struct request_values *rvp) | ||
464 | { | 467 | { |
465 | struct inet6_request_sock *treq = inet6_rsk(req); | 468 | struct inet6_request_sock *treq = inet6_rsk(req); |
466 | struct ipv6_pinfo *np = inet6_sk(sk); | 469 | struct ipv6_pinfo *np = inet6_sk(sk); |
@@ -477,6 +480,7 @@ static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req) | |||
477 | ipv6_addr_copy(&fl.fl6_src, &treq->loc_addr); | 480 | ipv6_addr_copy(&fl.fl6_src, &treq->loc_addr); |
478 | fl.fl6_flowlabel = 0; | 481 | fl.fl6_flowlabel = 0; |
479 | fl.oif = treq->iif; | 482 | fl.oif = treq->iif; |
483 | fl.mark = sk->sk_mark; | ||
480 | fl.fl_ip_dport = inet_rsk(req)->rmt_port; | 484 | fl.fl_ip_dport = inet_rsk(req)->rmt_port; |
481 | fl.fl_ip_sport = inet_rsk(req)->loc_port; | 485 | fl.fl_ip_sport = inet_rsk(req)->loc_port; |
482 | security_req_classify_flow(req, &fl); | 486 | security_req_classify_flow(req, &fl); |
@@ -497,7 +501,7 @@ static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req) | |||
497 | if ((err = xfrm_lookup(sock_net(sk), &dst, &fl, sk, 0)) < 0) | 501 | if ((err = xfrm_lookup(sock_net(sk), &dst, &fl, sk, 0)) < 0) |
498 | goto done; | 502 | goto done; |
499 | 503 | ||
500 | skb = tcp_make_synack(sk, dst, req); | 504 | skb = tcp_make_synack(sk, dst, req, rvp); |
501 | if (skb) { | 505 | if (skb) { |
502 | struct tcphdr *th = tcp_hdr(skb); | 506 | struct tcphdr *th = tcp_hdr(skb); |
503 | 507 | ||
@@ -517,6 +521,13 @@ done: | |||
517 | return err; | 521 | return err; |
518 | } | 522 | } |
519 | 523 | ||
524 | static int tcp_v6_rtx_synack(struct sock *sk, struct request_sock *req, | ||
525 | struct request_values *rvp) | ||
526 | { | ||
527 | TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_RETRANSSEGS); | ||
528 | return tcp_v6_send_synack(sk, req, rvp); | ||
529 | } | ||
530 | |||
520 | static inline void syn_flood_warning(struct sk_buff *skb) | 531 | static inline void syn_flood_warning(struct sk_buff *skb) |
521 | { | 532 | { |
522 | #ifdef CONFIG_SYN_COOKIES | 533 | #ifdef CONFIG_SYN_COOKIES |
@@ -873,7 +884,7 @@ static int tcp_v6_inbound_md5_hash (struct sock *sk, struct sk_buff *skb) | |||
873 | 884 | ||
874 | if (genhash || memcmp(hash_location, newhash, 16) != 0) { | 885 | if (genhash || memcmp(hash_location, newhash, 16) != 0) { |
875 | if (net_ratelimit()) { | 886 | if (net_ratelimit()) { |
876 | printk(KERN_INFO "MD5 Hash %s for (%pI6, %u)->(%pI6, %u)\n", | 887 | printk(KERN_INFO "MD5 Hash %s for [%pI6c]:%u->[%pI6c]:%u\n", |
877 | genhash ? "failed" : "mismatch", | 888 | genhash ? "failed" : "mismatch", |
878 | &ip6h->saddr, ntohs(th->source), | 889 | &ip6h->saddr, ntohs(th->source), |
879 | &ip6h->daddr, ntohs(th->dest)); | 890 | &ip6h->daddr, ntohs(th->dest)); |
@@ -887,10 +898,11 @@ static int tcp_v6_inbound_md5_hash (struct sock *sk, struct sk_buff *skb) | |||
887 | struct request_sock_ops tcp6_request_sock_ops __read_mostly = { | 898 | struct request_sock_ops tcp6_request_sock_ops __read_mostly = { |
888 | .family = AF_INET6, | 899 | .family = AF_INET6, |
889 | .obj_size = sizeof(struct tcp6_request_sock), | 900 | .obj_size = sizeof(struct tcp6_request_sock), |
890 | .rtx_syn_ack = tcp_v6_send_synack, | 901 | .rtx_syn_ack = tcp_v6_rtx_synack, |
891 | .send_ack = tcp_v6_reqsk_send_ack, | 902 | .send_ack = tcp_v6_reqsk_send_ack, |
892 | .destructor = tcp_v6_reqsk_destructor, | 903 | .destructor = tcp_v6_reqsk_destructor, |
893 | .send_reset = tcp_v6_send_reset | 904 | .send_reset = tcp_v6_send_reset, |
905 | .syn_ack_timeout = tcp_syn_ack_timeout, | ||
894 | }; | 906 | }; |
895 | 907 | ||
896 | #ifdef CONFIG_TCP_MD5SIG | 908 | #ifdef CONFIG_TCP_MD5SIG |
@@ -1003,7 +1015,7 @@ static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win, | |||
1003 | skb_reserve(buff, MAX_HEADER + sizeof(struct ipv6hdr) + tot_len); | 1015 | skb_reserve(buff, MAX_HEADER + sizeof(struct ipv6hdr) + tot_len); |
1004 | 1016 | ||
1005 | t1 = (struct tcphdr *) skb_push(buff, tot_len); | 1017 | t1 = (struct tcphdr *) skb_push(buff, tot_len); |
1006 | skb_reset_transport_header(skb); | 1018 | skb_reset_transport_header(buff); |
1007 | 1019 | ||
1008 | /* Swap the send and the receive. */ | 1020 | /* Swap the send and the receive. */ |
1009 | memset(t1, 0, sizeof(*t1)); | 1021 | memset(t1, 0, sizeof(*t1)); |
@@ -1159,11 +1171,13 @@ static struct sock *tcp_v6_hnd_req(struct sock *sk,struct sk_buff *skb) | |||
1159 | */ | 1171 | */ |
1160 | static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) | 1172 | static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) |
1161 | { | 1173 | { |
1174 | struct tcp_extend_values tmp_ext; | ||
1175 | struct tcp_options_received tmp_opt; | ||
1176 | u8 *hash_location; | ||
1177 | struct request_sock *req; | ||
1162 | struct inet6_request_sock *treq; | 1178 | struct inet6_request_sock *treq; |
1163 | struct ipv6_pinfo *np = inet6_sk(sk); | 1179 | struct ipv6_pinfo *np = inet6_sk(sk); |
1164 | struct tcp_options_received tmp_opt; | ||
1165 | struct tcp_sock *tp = tcp_sk(sk); | 1180 | struct tcp_sock *tp = tcp_sk(sk); |
1166 | struct request_sock *req = NULL; | ||
1167 | __u32 isn = TCP_SKB_CB(skb)->when; | 1181 | __u32 isn = TCP_SKB_CB(skb)->when; |
1168 | #ifdef CONFIG_SYN_COOKIES | 1182 | #ifdef CONFIG_SYN_COOKIES |
1169 | int want_cookie = 0; | 1183 | int want_cookie = 0; |
@@ -1202,8 +1216,52 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) | |||
1202 | tcp_clear_options(&tmp_opt); | 1216 | tcp_clear_options(&tmp_opt); |
1203 | tmp_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr); | 1217 | tmp_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr); |
1204 | tmp_opt.user_mss = tp->rx_opt.user_mss; | 1218 | tmp_opt.user_mss = tp->rx_opt.user_mss; |
1219 | tcp_parse_options(skb, &tmp_opt, &hash_location, 0); | ||
1220 | |||
1221 | if (tmp_opt.cookie_plus > 0 && | ||
1222 | tmp_opt.saw_tstamp && | ||
1223 | !tp->rx_opt.cookie_out_never && | ||
1224 | (sysctl_tcp_cookie_size > 0 || | ||
1225 | (tp->cookie_values != NULL && | ||
1226 | tp->cookie_values->cookie_desired > 0))) { | ||
1227 | u8 *c; | ||
1228 | u32 *d; | ||
1229 | u32 *mess = &tmp_ext.cookie_bakery[COOKIE_DIGEST_WORDS]; | ||
1230 | int l = tmp_opt.cookie_plus - TCPOLEN_COOKIE_BASE; | ||
1231 | |||
1232 | if (tcp_cookie_generator(&tmp_ext.cookie_bakery[0]) != 0) | ||
1233 | goto drop_and_free; | ||
1234 | |||
1235 | /* Secret recipe starts with IP addresses */ | ||
1236 | d = &ipv6_hdr(skb)->daddr.s6_addr32[0]; | ||
1237 | *mess++ ^= *d++; | ||
1238 | *mess++ ^= *d++; | ||
1239 | *mess++ ^= *d++; | ||
1240 | *mess++ ^= *d++; | ||
1241 | d = &ipv6_hdr(skb)->saddr.s6_addr32[0]; | ||
1242 | *mess++ ^= *d++; | ||
1243 | *mess++ ^= *d++; | ||
1244 | *mess++ ^= *d++; | ||
1245 | *mess++ ^= *d++; | ||
1246 | |||
1247 | /* plus variable length Initiator Cookie */ | ||
1248 | c = (u8 *)mess; | ||
1249 | while (l-- > 0) | ||
1250 | *c++ ^= *hash_location++; | ||
1205 | 1251 | ||
1206 | tcp_parse_options(skb, &tmp_opt, 0); | 1252 | #ifdef CONFIG_SYN_COOKIES |
1253 | want_cookie = 0; /* not our kind of cookie */ | ||
1254 | #endif | ||
1255 | tmp_ext.cookie_out_never = 0; /* false */ | ||
1256 | tmp_ext.cookie_plus = tmp_opt.cookie_plus; | ||
1257 | } else if (!tp->rx_opt.cookie_in_always) { | ||
1258 | /* redundant indications, but ensure initialization. */ | ||
1259 | tmp_ext.cookie_out_never = 1; /* true */ | ||
1260 | tmp_ext.cookie_plus = 0; | ||
1261 | } else { | ||
1262 | goto drop_and_free; | ||
1263 | } | ||
1264 | tmp_ext.cookie_in_always = tp->rx_opt.cookie_in_always; | ||
1207 | 1265 | ||
1208 | if (want_cookie && !tmp_opt.saw_tstamp) | 1266 | if (want_cookie && !tmp_opt.saw_tstamp) |
1209 | tcp_clear_options(&tmp_opt); | 1267 | tcp_clear_options(&tmp_opt); |
@@ -1236,23 +1294,21 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) | |||
1236 | 1294 | ||
1237 | isn = tcp_v6_init_sequence(skb); | 1295 | isn = tcp_v6_init_sequence(skb); |
1238 | } | 1296 | } |
1239 | |||
1240 | tcp_rsk(req)->snt_isn = isn; | 1297 | tcp_rsk(req)->snt_isn = isn; |
1241 | 1298 | ||
1242 | security_inet_conn_request(sk, skb, req); | 1299 | security_inet_conn_request(sk, skb, req); |
1243 | 1300 | ||
1244 | if (tcp_v6_send_synack(sk, req)) | 1301 | if (tcp_v6_send_synack(sk, req, |
1245 | goto drop; | 1302 | (struct request_values *)&tmp_ext) || |
1303 | want_cookie) | ||
1304 | goto drop_and_free; | ||
1246 | 1305 | ||
1247 | if (!want_cookie) { | 1306 | inet6_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT); |
1248 | inet6_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT); | 1307 | return 0; |
1249 | return 0; | ||
1250 | } | ||
1251 | 1308 | ||
1309 | drop_and_free: | ||
1310 | reqsk_free(req); | ||
1252 | drop: | 1311 | drop: |
1253 | if (req) | ||
1254 | reqsk_free(req); | ||
1255 | |||
1256 | return 0; /* don't send reset */ | 1312 | return 0; /* don't send reset */ |
1257 | } | 1313 | } |
1258 | 1314 | ||
@@ -1290,11 +1346,9 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, | |||
1290 | 1346 | ||
1291 | memcpy(newnp, np, sizeof(struct ipv6_pinfo)); | 1347 | memcpy(newnp, np, sizeof(struct ipv6_pinfo)); |
1292 | 1348 | ||
1293 | ipv6_addr_set(&newnp->daddr, 0, 0, htonl(0x0000FFFF), | 1349 | ipv6_addr_set_v4mapped(newinet->inet_daddr, &newnp->daddr); |
1294 | newinet->daddr); | ||
1295 | 1350 | ||
1296 | ipv6_addr_set(&newnp->saddr, 0, 0, htonl(0x0000FFFF), | 1351 | ipv6_addr_set_v4mapped(newinet->inet_saddr, &newnp->saddr); |
1297 | newinet->saddr); | ||
1298 | 1352 | ||
1299 | ipv6_addr_copy(&newnp->rcv_saddr, &newnp->saddr); | 1353 | ipv6_addr_copy(&newnp->rcv_saddr, &newnp->saddr); |
1300 | 1354 | ||
@@ -1345,6 +1399,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, | |||
1345 | } | 1399 | } |
1346 | ipv6_addr_copy(&fl.fl6_src, &treq->loc_addr); | 1400 | ipv6_addr_copy(&fl.fl6_src, &treq->loc_addr); |
1347 | fl.oif = sk->sk_bound_dev_if; | 1401 | fl.oif = sk->sk_bound_dev_if; |
1402 | fl.mark = sk->sk_mark; | ||
1348 | fl.fl_ip_dport = inet_rsk(req)->rmt_port; | 1403 | fl.fl_ip_dport = inet_rsk(req)->rmt_port; |
1349 | fl.fl_ip_sport = inet_rsk(req)->loc_port; | 1404 | fl.fl_ip_sport = inet_rsk(req)->loc_port; |
1350 | security_req_classify_flow(req, &fl); | 1405 | security_req_classify_flow(req, &fl); |
@@ -1431,7 +1486,8 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, | |||
1431 | newtp->advmss = dst_metric(dst, RTAX_ADVMSS); | 1486 | newtp->advmss = dst_metric(dst, RTAX_ADVMSS); |
1432 | tcp_initialize_rcv_mss(newsk); | 1487 | tcp_initialize_rcv_mss(newsk); |
1433 | 1488 | ||
1434 | newinet->daddr = newinet->saddr = newinet->rcv_saddr = LOOPBACK4_IPV6; | 1489 | newinet->inet_daddr = newinet->inet_saddr = LOOPBACK4_IPV6; |
1490 | newinet->inet_rcv_saddr = LOOPBACK4_IPV6; | ||
1435 | 1491 | ||
1436 | #ifdef CONFIG_TCP_MD5SIG | 1492 | #ifdef CONFIG_TCP_MD5SIG |
1437 | /* Copy over the MD5 key from the original socket */ | 1493 | /* Copy over the MD5 key from the original socket */ |
@@ -1448,7 +1504,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, | |||
1448 | } | 1504 | } |
1449 | #endif | 1505 | #endif |
1450 | 1506 | ||
1451 | __inet6_hash(newsk); | 1507 | __inet6_hash(newsk, NULL); |
1452 | __inet_inherit_port(sk, newsk); | 1508 | __inet_inherit_port(sk, newsk); |
1453 | 1509 | ||
1454 | return newsk; | 1510 | return newsk; |
@@ -1685,8 +1741,11 @@ process: | |||
1685 | if (!tcp_prequeue(sk, skb)) | 1741 | if (!tcp_prequeue(sk, skb)) |
1686 | ret = tcp_v6_do_rcv(sk, skb); | 1742 | ret = tcp_v6_do_rcv(sk, skb); |
1687 | } | 1743 | } |
1688 | } else | 1744 | } else if (unlikely(sk_add_backlog(sk, skb))) { |
1689 | sk_add_backlog(sk, skb); | 1745 | bh_unlock_sock(sk); |
1746 | NET_INC_STATS_BH(net, LINUX_MIB_TCPBACKLOGDROP); | ||
1747 | goto discard_and_relse; | ||
1748 | } | ||
1690 | bh_unlock_sock(sk); | 1749 | bh_unlock_sock(sk); |
1691 | 1750 | ||
1692 | sock_put(sk); | 1751 | sock_put(sk); |
@@ -1848,7 +1907,7 @@ static int tcp_v6_init_sock(struct sock *sk) | |||
1848 | */ | 1907 | */ |
1849 | tp->snd_ssthresh = TCP_INFINITE_SSTHRESH; | 1908 | tp->snd_ssthresh = TCP_INFINITE_SSTHRESH; |
1850 | tp->snd_cwnd_clamp = ~0; | 1909 | tp->snd_cwnd_clamp = ~0; |
1851 | tp->mss_cache = 536; | 1910 | tp->mss_cache = TCP_MSS_DEFAULT; |
1852 | 1911 | ||
1853 | tp->reordering = sysctl_tcp_reordering; | 1912 | tp->reordering = sysctl_tcp_reordering; |
1854 | 1913 | ||
@@ -1864,6 +1923,19 @@ static int tcp_v6_init_sock(struct sock *sk) | |||
1864 | tp->af_specific = &tcp_sock_ipv6_specific; | 1923 | tp->af_specific = &tcp_sock_ipv6_specific; |
1865 | #endif | 1924 | #endif |
1866 | 1925 | ||
1926 | /* TCP Cookie Transactions */ | ||
1927 | if (sysctl_tcp_cookie_size > 0) { | ||
1928 | /* Default, cookies without s_data_payload. */ | ||
1929 | tp->cookie_values = | ||
1930 | kzalloc(sizeof(*tp->cookie_values), | ||
1931 | sk->sk_allocation); | ||
1932 | if (tp->cookie_values != NULL) | ||
1933 | kref_init(&tp->cookie_values->kref); | ||
1934 | } | ||
1935 | /* Presumed zeroed, in order of appearance: | ||
1936 | * cookie_in_always, cookie_out_never, | ||
1937 | * s_data_constant, s_data_in, s_data_out | ||
1938 | */ | ||
1867 | sk->sk_sndbuf = sysctl_tcp_wmem[1]; | 1939 | sk->sk_sndbuf = sysctl_tcp_wmem[1]; |
1868 | sk->sk_rcvbuf = sysctl_tcp_rmem[1]; | 1940 | sk->sk_rcvbuf = sysctl_tcp_rmem[1]; |
1869 | 1941 | ||
@@ -1931,8 +2003,8 @@ static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i) | |||
1931 | 2003 | ||
1932 | dest = &np->daddr; | 2004 | dest = &np->daddr; |
1933 | src = &np->rcv_saddr; | 2005 | src = &np->rcv_saddr; |
1934 | destp = ntohs(inet->dport); | 2006 | destp = ntohs(inet->inet_dport); |
1935 | srcp = ntohs(inet->sport); | 2007 | srcp = ntohs(inet->inet_sport); |
1936 | 2008 | ||
1937 | if (icsk->icsk_pending == ICSK_TIME_RETRANS) { | 2009 | if (icsk->icsk_pending == ICSK_TIME_RETRANS) { |
1938 | timer_active = 1; | 2010 | timer_active = 1; |
@@ -2045,7 +2117,7 @@ static struct tcp_seq_afinfo tcp6_seq_afinfo = { | |||
2045 | }, | 2117 | }, |
2046 | }; | 2118 | }; |
2047 | 2119 | ||
2048 | int tcp6_proc_init(struct net *net) | 2120 | int __net_init tcp6_proc_init(struct net *net) |
2049 | { | 2121 | { |
2050 | return tcp_proc_register(net, &tcp6_seq_afinfo); | 2122 | return tcp_proc_register(net, &tcp6_seq_afinfo); |
2051 | } | 2123 | } |
@@ -2109,27 +2181,31 @@ static struct inet_protosw tcpv6_protosw = { | |||
2109 | .protocol = IPPROTO_TCP, | 2181 | .protocol = IPPROTO_TCP, |
2110 | .prot = &tcpv6_prot, | 2182 | .prot = &tcpv6_prot, |
2111 | .ops = &inet6_stream_ops, | 2183 | .ops = &inet6_stream_ops, |
2112 | .capability = -1, | ||
2113 | .no_check = 0, | 2184 | .no_check = 0, |
2114 | .flags = INET_PROTOSW_PERMANENT | | 2185 | .flags = INET_PROTOSW_PERMANENT | |
2115 | INET_PROTOSW_ICSK, | 2186 | INET_PROTOSW_ICSK, |
2116 | }; | 2187 | }; |
2117 | 2188 | ||
2118 | static int tcpv6_net_init(struct net *net) | 2189 | static int __net_init tcpv6_net_init(struct net *net) |
2119 | { | 2190 | { |
2120 | return inet_ctl_sock_create(&net->ipv6.tcp_sk, PF_INET6, | 2191 | return inet_ctl_sock_create(&net->ipv6.tcp_sk, PF_INET6, |
2121 | SOCK_RAW, IPPROTO_TCP, net); | 2192 | SOCK_RAW, IPPROTO_TCP, net); |
2122 | } | 2193 | } |
2123 | 2194 | ||
2124 | static void tcpv6_net_exit(struct net *net) | 2195 | static void __net_exit tcpv6_net_exit(struct net *net) |
2125 | { | 2196 | { |
2126 | inet_ctl_sock_destroy(net->ipv6.tcp_sk); | 2197 | inet_ctl_sock_destroy(net->ipv6.tcp_sk); |
2127 | inet_twsk_purge(net, &tcp_hashinfo, &tcp_death_row, AF_INET6); | 2198 | } |
2199 | |||
2200 | static void __net_exit tcpv6_net_exit_batch(struct list_head *net_exit_list) | ||
2201 | { | ||
2202 | inet_twsk_purge(&tcp_hashinfo, &tcp_death_row, AF_INET6); | ||
2128 | } | 2203 | } |
2129 | 2204 | ||
2130 | static struct pernet_operations tcpv6_net_ops = { | 2205 | static struct pernet_operations tcpv6_net_ops = { |
2131 | .init = tcpv6_net_init, | 2206 | .init = tcpv6_net_init, |
2132 | .exit = tcpv6_net_exit, | 2207 | .exit = tcpv6_net_exit, |
2208 | .exit_batch = tcpv6_net_exit_batch, | ||
2133 | }; | 2209 | }; |
2134 | 2210 | ||
2135 | int __init tcpv6_init(void) | 2211 | int __init tcpv6_init(void) |
diff --git a/net/ipv6/tunnel6.c b/net/ipv6/tunnel6.c index 51e2832d13a6..fc3c86a47452 100644 --- a/net/ipv6/tunnel6.c +++ b/net/ipv6/tunnel6.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <linux/mutex.h> | 25 | #include <linux/mutex.h> |
26 | #include <linux/netdevice.h> | 26 | #include <linux/netdevice.h> |
27 | #include <linux/skbuff.h> | 27 | #include <linux/skbuff.h> |
28 | #include <linux/slab.h> | ||
28 | #include <net/ipv6.h> | 29 | #include <net/ipv6.h> |
29 | #include <net/protocol.h> | 30 | #include <net/protocol.h> |
30 | #include <net/xfrm.h> | 31 | #include <net/xfrm.h> |
@@ -98,7 +99,7 @@ static int tunnel6_rcv(struct sk_buff *skb) | |||
98 | if (!handler->handler(skb)) | 99 | if (!handler->handler(skb)) |
99 | return 0; | 100 | return 0; |
100 | 101 | ||
101 | icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0, skb->dev); | 102 | icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0); |
102 | 103 | ||
103 | drop: | 104 | drop: |
104 | kfree_skb(skb); | 105 | kfree_skb(skb); |
@@ -116,7 +117,7 @@ static int tunnel46_rcv(struct sk_buff *skb) | |||
116 | if (!handler->handler(skb)) | 117 | if (!handler->handler(skb)) |
117 | return 0; | 118 | return 0; |
118 | 119 | ||
119 | icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0, skb->dev); | 120 | icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0); |
120 | 121 | ||
121 | drop: | 122 | drop: |
122 | kfree_skb(skb); | 123 | kfree_skb(skb); |
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index cf538ed5ef6a..90824852f598 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include <linux/init.h> | 34 | #include <linux/init.h> |
35 | #include <linux/module.h> | 35 | #include <linux/module.h> |
36 | #include <linux/skbuff.h> | 36 | #include <linux/skbuff.h> |
37 | #include <linux/slab.h> | ||
37 | #include <asm/uaccess.h> | 38 | #include <asm/uaccess.h> |
38 | 39 | ||
39 | #include <net/ndisc.h> | 40 | #include <net/ndisc.h> |
@@ -53,7 +54,7 @@ int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2) | |||
53 | { | 54 | { |
54 | const struct in6_addr *sk_rcv_saddr6 = &inet6_sk(sk)->rcv_saddr; | 55 | const struct in6_addr *sk_rcv_saddr6 = &inet6_sk(sk)->rcv_saddr; |
55 | const struct in6_addr *sk2_rcv_saddr6 = inet6_rcv_saddr(sk2); | 56 | const struct in6_addr *sk2_rcv_saddr6 = inet6_rcv_saddr(sk2); |
56 | __be32 sk_rcv_saddr = inet_sk(sk)->rcv_saddr; | 57 | __be32 sk1_rcv_saddr = inet_sk(sk)->inet_rcv_saddr; |
57 | __be32 sk2_rcv_saddr = inet_rcv_saddr(sk2); | 58 | __be32 sk2_rcv_saddr = inet_rcv_saddr(sk2); |
58 | int sk_ipv6only = ipv6_only_sock(sk); | 59 | int sk_ipv6only = ipv6_only_sock(sk); |
59 | int sk2_ipv6only = inet_v6_ipv6only(sk2); | 60 | int sk2_ipv6only = inet_v6_ipv6only(sk2); |
@@ -63,8 +64,8 @@ int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2) | |||
63 | /* if both are mapped, treat as IPv4 */ | 64 | /* if both are mapped, treat as IPv4 */ |
64 | if (addr_type == IPV6_ADDR_MAPPED && addr_type2 == IPV6_ADDR_MAPPED) | 65 | if (addr_type == IPV6_ADDR_MAPPED && addr_type2 == IPV6_ADDR_MAPPED) |
65 | return (!sk2_ipv6only && | 66 | return (!sk2_ipv6only && |
66 | (!sk_rcv_saddr || !sk2_rcv_saddr || | 67 | (!sk1_rcv_saddr || !sk2_rcv_saddr || |
67 | sk_rcv_saddr == sk2_rcv_saddr)); | 68 | sk1_rcv_saddr == sk2_rcv_saddr)); |
68 | 69 | ||
69 | if (addr_type2 == IPV6_ADDR_ANY && | 70 | if (addr_type2 == IPV6_ADDR_ANY && |
70 | !(sk2_ipv6only && addr_type == IPV6_ADDR_MAPPED)) | 71 | !(sk2_ipv6only && addr_type == IPV6_ADDR_MAPPED)) |
@@ -81,9 +82,33 @@ int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2) | |||
81 | return 0; | 82 | return 0; |
82 | } | 83 | } |
83 | 84 | ||
85 | static unsigned int udp6_portaddr_hash(struct net *net, | ||
86 | const struct in6_addr *addr6, | ||
87 | unsigned int port) | ||
88 | { | ||
89 | unsigned int hash, mix = net_hash_mix(net); | ||
90 | |||
91 | if (ipv6_addr_any(addr6)) | ||
92 | hash = jhash_1word(0, mix); | ||
93 | else if (ipv6_addr_v4mapped(addr6)) | ||
94 | hash = jhash_1word(addr6->s6_addr32[3], mix); | ||
95 | else | ||
96 | hash = jhash2(addr6->s6_addr32, 4, mix); | ||
97 | |||
98 | return hash ^ port; | ||
99 | } | ||
100 | |||
101 | |||
84 | int udp_v6_get_port(struct sock *sk, unsigned short snum) | 102 | int udp_v6_get_port(struct sock *sk, unsigned short snum) |
85 | { | 103 | { |
86 | return udp_lib_get_port(sk, snum, ipv6_rcv_saddr_equal); | 104 | unsigned int hash2_nulladdr = |
105 | udp6_portaddr_hash(sock_net(sk), &in6addr_any, snum); | ||
106 | unsigned int hash2_partial = | ||
107 | udp6_portaddr_hash(sock_net(sk), &inet6_sk(sk)->rcv_saddr, 0); | ||
108 | |||
109 | /* precompute partial secondary hash */ | ||
110 | udp_sk(sk)->udp_portaddr_hash = hash2_partial; | ||
111 | return udp_lib_get_port(sk, snum, ipv6_rcv_saddr_equal, hash2_nulladdr); | ||
87 | } | 112 | } |
88 | 113 | ||
89 | static inline int compute_score(struct sock *sk, struct net *net, | 114 | static inline int compute_score(struct sock *sk, struct net *net, |
@@ -94,14 +119,14 @@ static inline int compute_score(struct sock *sk, struct net *net, | |||
94 | { | 119 | { |
95 | int score = -1; | 120 | int score = -1; |
96 | 121 | ||
97 | if (net_eq(sock_net(sk), net) && sk->sk_hash == hnum && | 122 | if (net_eq(sock_net(sk), net) && udp_sk(sk)->udp_port_hash == hnum && |
98 | sk->sk_family == PF_INET6) { | 123 | sk->sk_family == PF_INET6) { |
99 | struct ipv6_pinfo *np = inet6_sk(sk); | 124 | struct ipv6_pinfo *np = inet6_sk(sk); |
100 | struct inet_sock *inet = inet_sk(sk); | 125 | struct inet_sock *inet = inet_sk(sk); |
101 | 126 | ||
102 | score = 0; | 127 | score = 0; |
103 | if (inet->dport) { | 128 | if (inet->inet_dport) { |
104 | if (inet->dport != sport) | 129 | if (inet->inet_dport != sport) |
105 | return -1; | 130 | return -1; |
106 | score++; | 131 | score++; |
107 | } | 132 | } |
@@ -124,6 +149,86 @@ static inline int compute_score(struct sock *sk, struct net *net, | |||
124 | return score; | 149 | return score; |
125 | } | 150 | } |
126 | 151 | ||
152 | #define SCORE2_MAX (1 + 1 + 1) | ||
153 | static inline int compute_score2(struct sock *sk, struct net *net, | ||
154 | const struct in6_addr *saddr, __be16 sport, | ||
155 | const struct in6_addr *daddr, unsigned short hnum, | ||
156 | int dif) | ||
157 | { | ||
158 | int score = -1; | ||
159 | |||
160 | if (net_eq(sock_net(sk), net) && udp_sk(sk)->udp_port_hash == hnum && | ||
161 | sk->sk_family == PF_INET6) { | ||
162 | struct ipv6_pinfo *np = inet6_sk(sk); | ||
163 | struct inet_sock *inet = inet_sk(sk); | ||
164 | |||
165 | if (!ipv6_addr_equal(&np->rcv_saddr, daddr)) | ||
166 | return -1; | ||
167 | score = 0; | ||
168 | if (inet->inet_dport) { | ||
169 | if (inet->inet_dport != sport) | ||
170 | return -1; | ||
171 | score++; | ||
172 | } | ||
173 | if (!ipv6_addr_any(&np->daddr)) { | ||
174 | if (!ipv6_addr_equal(&np->daddr, saddr)) | ||
175 | return -1; | ||
176 | score++; | ||
177 | } | ||
178 | if (sk->sk_bound_dev_if) { | ||
179 | if (sk->sk_bound_dev_if != dif) | ||
180 | return -1; | ||
181 | score++; | ||
182 | } | ||
183 | } | ||
184 | return score; | ||
185 | } | ||
186 | |||
187 | |||
188 | /* called with read_rcu_lock() */ | ||
189 | static struct sock *udp6_lib_lookup2(struct net *net, | ||
190 | const struct in6_addr *saddr, __be16 sport, | ||
191 | const struct in6_addr *daddr, unsigned int hnum, int dif, | ||
192 | struct udp_hslot *hslot2, unsigned int slot2) | ||
193 | { | ||
194 | struct sock *sk, *result; | ||
195 | struct hlist_nulls_node *node; | ||
196 | int score, badness; | ||
197 | |||
198 | begin: | ||
199 | result = NULL; | ||
200 | badness = -1; | ||
201 | udp_portaddr_for_each_entry_rcu(sk, node, &hslot2->head) { | ||
202 | score = compute_score2(sk, net, saddr, sport, | ||
203 | daddr, hnum, dif); | ||
204 | if (score > badness) { | ||
205 | result = sk; | ||
206 | badness = score; | ||
207 | if (score == SCORE2_MAX) | ||
208 | goto exact_match; | ||
209 | } | ||
210 | } | ||
211 | /* | ||
212 | * if the nulls value we got at the end of this lookup is | ||
213 | * not the expected one, we must restart lookup. | ||
214 | * We probably met an item that was moved to another chain. | ||
215 | */ | ||
216 | if (get_nulls_value(node) != slot2) | ||
217 | goto begin; | ||
218 | |||
219 | if (result) { | ||
220 | exact_match: | ||
221 | if (unlikely(!atomic_inc_not_zero(&result->sk_refcnt))) | ||
222 | result = NULL; | ||
223 | else if (unlikely(compute_score2(result, net, saddr, sport, | ||
224 | daddr, hnum, dif) < badness)) { | ||
225 | sock_put(result); | ||
226 | goto begin; | ||
227 | } | ||
228 | } | ||
229 | return result; | ||
230 | } | ||
231 | |||
127 | static struct sock *__udp6_lib_lookup(struct net *net, | 232 | static struct sock *__udp6_lib_lookup(struct net *net, |
128 | struct in6_addr *saddr, __be16 sport, | 233 | struct in6_addr *saddr, __be16 sport, |
129 | struct in6_addr *daddr, __be16 dport, | 234 | struct in6_addr *daddr, __be16 dport, |
@@ -132,11 +237,35 @@ static struct sock *__udp6_lib_lookup(struct net *net, | |||
132 | struct sock *sk, *result; | 237 | struct sock *sk, *result; |
133 | struct hlist_nulls_node *node; | 238 | struct hlist_nulls_node *node; |
134 | unsigned short hnum = ntohs(dport); | 239 | unsigned short hnum = ntohs(dport); |
135 | unsigned int hash = udp_hashfn(net, hnum); | 240 | unsigned int hash2, slot2, slot = udp_hashfn(net, hnum, udptable->mask); |
136 | struct udp_hslot *hslot = &udptable->hash[hash]; | 241 | struct udp_hslot *hslot2, *hslot = &udptable->hash[slot]; |
137 | int score, badness; | 242 | int score, badness; |
138 | 243 | ||
139 | rcu_read_lock(); | 244 | rcu_read_lock(); |
245 | if (hslot->count > 10) { | ||
246 | hash2 = udp6_portaddr_hash(net, daddr, hnum); | ||
247 | slot2 = hash2 & udptable->mask; | ||
248 | hslot2 = &udptable->hash2[slot2]; | ||
249 | if (hslot->count < hslot2->count) | ||
250 | goto begin; | ||
251 | |||
252 | result = udp6_lib_lookup2(net, saddr, sport, | ||
253 | daddr, hnum, dif, | ||
254 | hslot2, slot2); | ||
255 | if (!result) { | ||
256 | hash2 = udp6_portaddr_hash(net, &in6addr_any, hnum); | ||
257 | slot2 = hash2 & udptable->mask; | ||
258 | hslot2 = &udptable->hash2[slot2]; | ||
259 | if (hslot->count < hslot2->count) | ||
260 | goto begin; | ||
261 | |||
262 | result = udp6_lib_lookup2(net, saddr, sport, | ||
263 | &in6addr_any, hnum, dif, | ||
264 | hslot2, slot2); | ||
265 | } | ||
266 | rcu_read_unlock(); | ||
267 | return result; | ||
268 | } | ||
140 | begin: | 269 | begin: |
141 | result = NULL; | 270 | result = NULL; |
142 | badness = -1; | 271 | badness = -1; |
@@ -152,7 +281,7 @@ begin: | |||
152 | * not the expected one, we must restart lookup. | 281 | * not the expected one, we must restart lookup. |
153 | * We probably met an item that was moved to another chain. | 282 | * We probably met an item that was moved to another chain. |
154 | */ | 283 | */ |
155 | if (get_nulls_value(node) != hash) | 284 | if (get_nulls_value(node) != slot) |
156 | goto begin; | 285 | goto begin; |
157 | 286 | ||
158 | if (result) { | 287 | if (result) { |
@@ -194,7 +323,7 @@ int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk, | |||
194 | struct ipv6_pinfo *np = inet6_sk(sk); | 323 | struct ipv6_pinfo *np = inet6_sk(sk); |
195 | struct inet_sock *inet = inet_sk(sk); | 324 | struct inet_sock *inet = inet_sk(sk); |
196 | struct sk_buff *skb; | 325 | struct sk_buff *skb; |
197 | unsigned int ulen, copied; | 326 | unsigned int ulen; |
198 | int peeked; | 327 | int peeked; |
199 | int err; | 328 | int err; |
200 | int is_udplite = IS_UDPLITE(sk); | 329 | int is_udplite = IS_UDPLITE(sk); |
@@ -213,10 +342,9 @@ try_again: | |||
213 | goto out; | 342 | goto out; |
214 | 343 | ||
215 | ulen = skb->len - sizeof(struct udphdr); | 344 | ulen = skb->len - sizeof(struct udphdr); |
216 | copied = len; | 345 | if (len > ulen) |
217 | if (copied > ulen) | 346 | len = ulen; |
218 | copied = ulen; | 347 | else if (len < ulen) |
219 | else if (copied < ulen) | ||
220 | msg->msg_flags |= MSG_TRUNC; | 348 | msg->msg_flags |= MSG_TRUNC; |
221 | 349 | ||
222 | is_udp4 = (skb->protocol == htons(ETH_P_IP)); | 350 | is_udp4 = (skb->protocol == htons(ETH_P_IP)); |
@@ -227,14 +355,14 @@ try_again: | |||
227 | * coverage checksum (UDP-Lite), do it before the copy. | 355 | * coverage checksum (UDP-Lite), do it before the copy. |
228 | */ | 356 | */ |
229 | 357 | ||
230 | if (copied < ulen || UDP_SKB_CB(skb)->partial_cov) { | 358 | if (len < ulen || UDP_SKB_CB(skb)->partial_cov) { |
231 | if (udp_lib_checksum_complete(skb)) | 359 | if (udp_lib_checksum_complete(skb)) |
232 | goto csum_copy_err; | 360 | goto csum_copy_err; |
233 | } | 361 | } |
234 | 362 | ||
235 | if (skb_csum_unnecessary(skb)) | 363 | if (skb_csum_unnecessary(skb)) |
236 | err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), | 364 | err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), |
237 | msg->msg_iov, copied ); | 365 | msg->msg_iov,len); |
238 | else { | 366 | else { |
239 | err = skb_copy_and_csum_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov); | 367 | err = skb_copy_and_csum_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov); |
240 | if (err == -EINVAL) | 368 | if (err == -EINVAL) |
@@ -252,7 +380,7 @@ try_again: | |||
252 | UDP_MIB_INDATAGRAMS, is_udplite); | 380 | UDP_MIB_INDATAGRAMS, is_udplite); |
253 | } | 381 | } |
254 | 382 | ||
255 | sock_recv_timestamp(msg, sk, skb); | 383 | sock_recv_ts_and_drops(msg, sk, skb); |
256 | 384 | ||
257 | /* Copy the address. */ | 385 | /* Copy the address. */ |
258 | if (msg->msg_name) { | 386 | if (msg->msg_name) { |
@@ -265,8 +393,8 @@ try_again: | |||
265 | sin6->sin6_scope_id = 0; | 393 | sin6->sin6_scope_id = 0; |
266 | 394 | ||
267 | if (is_udp4) | 395 | if (is_udp4) |
268 | ipv6_addr_set(&sin6->sin6_addr, 0, 0, | 396 | ipv6_addr_set_v4mapped(ip_hdr(skb)->saddr, |
269 | htonl(0xffff), ip_hdr(skb)->saddr); | 397 | &sin6->sin6_addr); |
270 | else { | 398 | else { |
271 | ipv6_addr_copy(&sin6->sin6_addr, | 399 | ipv6_addr_copy(&sin6->sin6_addr, |
272 | &ipv6_hdr(skb)->saddr); | 400 | &ipv6_hdr(skb)->saddr); |
@@ -283,7 +411,7 @@ try_again: | |||
283 | datagram_recv_ctl(sk, msg, skb); | 411 | datagram_recv_ctl(sk, msg, skb); |
284 | } | 412 | } |
285 | 413 | ||
286 | err = copied; | 414 | err = len; |
287 | if (flags & MSG_TRUNC) | 415 | if (flags & MSG_TRUNC) |
288 | err = ulen; | 416 | err = ulen; |
289 | 417 | ||
@@ -383,18 +511,18 @@ int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) | |||
383 | goto drop; | 511 | goto drop; |
384 | } | 512 | } |
385 | 513 | ||
386 | if ((rc = sock_queue_rcv_skb(sk,skb)) < 0) { | 514 | if ((rc = sock_queue_rcv_skb(sk, skb)) < 0) { |
387 | /* Note that an ENOMEM error is charged twice */ | 515 | /* Note that an ENOMEM error is charged twice */ |
388 | if (rc == -ENOMEM) { | 516 | if (rc == -ENOMEM) |
389 | UDP6_INC_STATS_BH(sock_net(sk), | 517 | UDP6_INC_STATS_BH(sock_net(sk), |
390 | UDP_MIB_RCVBUFERRORS, is_udplite); | 518 | UDP_MIB_RCVBUFERRORS, is_udplite); |
391 | atomic_inc(&sk->sk_drops); | 519 | goto drop_no_sk_drops_inc; |
392 | } | ||
393 | goto drop; | ||
394 | } | 520 | } |
395 | 521 | ||
396 | return 0; | 522 | return 0; |
397 | drop: | 523 | drop: |
524 | atomic_inc(&sk->sk_drops); | ||
525 | drop_no_sk_drops_inc: | ||
398 | UDP6_INC_STATS_BH(sock_net(sk), UDP_MIB_INERRORS, is_udplite); | 526 | UDP6_INC_STATS_BH(sock_net(sk), UDP_MIB_INERRORS, is_udplite); |
399 | kfree_skb(skb); | 527 | kfree_skb(skb); |
400 | return -1; | 528 | return -1; |
@@ -415,10 +543,11 @@ static struct sock *udp_v6_mcast_next(struct net *net, struct sock *sk, | |||
415 | if (!net_eq(sock_net(s), net)) | 543 | if (!net_eq(sock_net(s), net)) |
416 | continue; | 544 | continue; |
417 | 545 | ||
418 | if (s->sk_hash == num && s->sk_family == PF_INET6) { | 546 | if (udp_sk(s)->udp_port_hash == num && |
547 | s->sk_family == PF_INET6) { | ||
419 | struct ipv6_pinfo *np = inet6_sk(s); | 548 | struct ipv6_pinfo *np = inet6_sk(s); |
420 | if (inet->dport) { | 549 | if (inet->inet_dport) { |
421 | if (inet->dport != rmt_port) | 550 | if (inet->inet_dport != rmt_port) |
422 | continue; | 551 | continue; |
423 | } | 552 | } |
424 | if (!ipv6_addr_any(&np->daddr) && | 553 | if (!ipv6_addr_any(&np->daddr) && |
@@ -440,6 +569,37 @@ static struct sock *udp_v6_mcast_next(struct net *net, struct sock *sk, | |||
440 | return NULL; | 569 | return NULL; |
441 | } | 570 | } |
442 | 571 | ||
572 | static void flush_stack(struct sock **stack, unsigned int count, | ||
573 | struct sk_buff *skb, unsigned int final) | ||
574 | { | ||
575 | unsigned int i; | ||
576 | struct sock *sk; | ||
577 | struct sk_buff *skb1; | ||
578 | |||
579 | for (i = 0; i < count; i++) { | ||
580 | skb1 = (i == final) ? skb : skb_clone(skb, GFP_ATOMIC); | ||
581 | |||
582 | sk = stack[i]; | ||
583 | if (skb1) { | ||
584 | bh_lock_sock(sk); | ||
585 | if (!sock_owned_by_user(sk)) | ||
586 | udpv6_queue_rcv_skb(sk, skb1); | ||
587 | else if (sk_add_backlog(sk, skb1)) { | ||
588 | kfree_skb(skb1); | ||
589 | bh_unlock_sock(sk); | ||
590 | goto drop; | ||
591 | } | ||
592 | bh_unlock_sock(sk); | ||
593 | continue; | ||
594 | } | ||
595 | drop: | ||
596 | atomic_inc(&sk->sk_drops); | ||
597 | UDP6_INC_STATS_BH(sock_net(sk), | ||
598 | UDP_MIB_RCVBUFERRORS, IS_UDPLITE(sk)); | ||
599 | UDP6_INC_STATS_BH(sock_net(sk), | ||
600 | UDP_MIB_INERRORS, IS_UDPLITE(sk)); | ||
601 | } | ||
602 | } | ||
443 | /* | 603 | /* |
444 | * Note: called only from the BH handler context, | 604 | * Note: called only from the BH handler context, |
445 | * so we don't need to lock the hashes. | 605 | * so we don't need to lock the hashes. |
@@ -448,41 +608,43 @@ static int __udp6_lib_mcast_deliver(struct net *net, struct sk_buff *skb, | |||
448 | struct in6_addr *saddr, struct in6_addr *daddr, | 608 | struct in6_addr *saddr, struct in6_addr *daddr, |
449 | struct udp_table *udptable) | 609 | struct udp_table *udptable) |
450 | { | 610 | { |
451 | struct sock *sk, *sk2; | 611 | struct sock *sk, *stack[256 / sizeof(struct sock *)]; |
452 | const struct udphdr *uh = udp_hdr(skb); | 612 | const struct udphdr *uh = udp_hdr(skb); |
453 | struct udp_hslot *hslot = &udptable->hash[udp_hashfn(net, ntohs(uh->dest))]; | 613 | struct udp_hslot *hslot = udp_hashslot(udptable, net, ntohs(uh->dest)); |
454 | int dif; | 614 | int dif; |
615 | unsigned int i, count = 0; | ||
455 | 616 | ||
456 | spin_lock(&hslot->lock); | 617 | spin_lock(&hslot->lock); |
457 | sk = sk_nulls_head(&hslot->head); | 618 | sk = sk_nulls_head(&hslot->head); |
458 | dif = inet6_iif(skb); | 619 | dif = inet6_iif(skb); |
459 | sk = udp_v6_mcast_next(net, sk, uh->dest, daddr, uh->source, saddr, dif); | 620 | sk = udp_v6_mcast_next(net, sk, uh->dest, daddr, uh->source, saddr, dif); |
460 | if (!sk) { | 621 | while (sk) { |
461 | kfree_skb(skb); | 622 | stack[count++] = sk; |
462 | goto out; | 623 | sk = udp_v6_mcast_next(net, sk_nulls_next(sk), uh->dest, daddr, |
463 | } | 624 | uh->source, saddr, dif); |
464 | 625 | if (unlikely(count == ARRAY_SIZE(stack))) { | |
465 | sk2 = sk; | 626 | if (!sk) |
466 | while ((sk2 = udp_v6_mcast_next(net, sk_nulls_next(sk2), uh->dest, daddr, | 627 | break; |
467 | uh->source, saddr, dif))) { | 628 | flush_stack(stack, count, skb, ~0); |
468 | struct sk_buff *buff = skb_clone(skb, GFP_ATOMIC); | 629 | count = 0; |
469 | if (buff) { | ||
470 | bh_lock_sock(sk2); | ||
471 | if (!sock_owned_by_user(sk2)) | ||
472 | udpv6_queue_rcv_skb(sk2, buff); | ||
473 | else | ||
474 | sk_add_backlog(sk2, buff); | ||
475 | bh_unlock_sock(sk2); | ||
476 | } | 630 | } |
477 | } | 631 | } |
478 | bh_lock_sock(sk); | 632 | /* |
479 | if (!sock_owned_by_user(sk)) | 633 | * before releasing the lock, we must take reference on sockets |
480 | udpv6_queue_rcv_skb(sk, skb); | 634 | */ |
481 | else | 635 | for (i = 0; i < count; i++) |
482 | sk_add_backlog(sk, skb); | 636 | sock_hold(stack[i]); |
483 | bh_unlock_sock(sk); | 637 | |
484 | out: | ||
485 | spin_unlock(&hslot->lock); | 638 | spin_unlock(&hslot->lock); |
639 | |||
640 | if (count) { | ||
641 | flush_stack(stack, count, skb, count - 1); | ||
642 | |||
643 | for (i = 0; i < count; i++) | ||
644 | sock_put(stack[i]); | ||
645 | } else { | ||
646 | kfree_skb(skb); | ||
647 | } | ||
486 | return 0; | 648 | return 0; |
487 | } | 649 | } |
488 | 650 | ||
@@ -523,12 +685,11 @@ static inline int udp6_csum_init(struct sk_buff *skb, struct udphdr *uh, | |||
523 | int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable, | 685 | int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable, |
524 | int proto) | 686 | int proto) |
525 | { | 687 | { |
688 | struct net *net = dev_net(skb->dev); | ||
526 | struct sock *sk; | 689 | struct sock *sk; |
527 | struct udphdr *uh; | 690 | struct udphdr *uh; |
528 | struct net_device *dev = skb->dev; | ||
529 | struct in6_addr *saddr, *daddr; | 691 | struct in6_addr *saddr, *daddr; |
530 | u32 ulen = 0; | 692 | u32 ulen = 0; |
531 | struct net *net = dev_net(skb->dev); | ||
532 | 693 | ||
533 | if (!pskb_may_pull(skb, sizeof(struct udphdr))) | 694 | if (!pskb_may_pull(skb, sizeof(struct udphdr))) |
534 | goto short_packet; | 695 | goto short_packet; |
@@ -587,7 +748,7 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable, | |||
587 | UDP6_INC_STATS_BH(net, UDP_MIB_NOPORTS, | 748 | UDP6_INC_STATS_BH(net, UDP_MIB_NOPORTS, |
588 | proto == IPPROTO_UDPLITE); | 749 | proto == IPPROTO_UDPLITE); |
589 | 750 | ||
590 | icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0, dev); | 751 | icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0); |
591 | 752 | ||
592 | kfree_skb(skb); | 753 | kfree_skb(skb); |
593 | return 0; | 754 | return 0; |
@@ -598,8 +759,12 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable, | |||
598 | bh_lock_sock(sk); | 759 | bh_lock_sock(sk); |
599 | if (!sock_owned_by_user(sk)) | 760 | if (!sock_owned_by_user(sk)) |
600 | udpv6_queue_rcv_skb(sk, skb); | 761 | udpv6_queue_rcv_skb(sk, skb); |
601 | else | 762 | else if (sk_add_backlog(sk, skb)) { |
602 | sk_add_backlog(sk, skb); | 763 | atomic_inc(&sk->sk_drops); |
764 | bh_unlock_sock(sk); | ||
765 | sock_put(sk); | ||
766 | goto discard; | ||
767 | } | ||
603 | bh_unlock_sock(sk); | 768 | bh_unlock_sock(sk); |
604 | sock_put(sk); | 769 | sock_put(sk); |
605 | return 0; | 770 | return 0; |
@@ -792,7 +957,7 @@ int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
792 | if (ipv6_addr_v4mapped(daddr)) { | 957 | if (ipv6_addr_v4mapped(daddr)) { |
793 | struct sockaddr_in sin; | 958 | struct sockaddr_in sin; |
794 | sin.sin_family = AF_INET; | 959 | sin.sin_family = AF_INET; |
795 | sin.sin_port = sin6 ? sin6->sin6_port : inet->dport; | 960 | sin.sin_port = sin6 ? sin6->sin6_port : inet->inet_dport; |
796 | sin.sin_addr.s_addr = daddr->s6_addr32[3]; | 961 | sin.sin_addr.s_addr = daddr->s6_addr32[3]; |
797 | msg->msg_name = &sin; | 962 | msg->msg_name = &sin; |
798 | msg->msg_namelen = sizeof(sin); | 963 | msg->msg_namelen = sizeof(sin); |
@@ -865,7 +1030,7 @@ do_udp_sendmsg: | |||
865 | if (sk->sk_state != TCP_ESTABLISHED) | 1030 | if (sk->sk_state != TCP_ESTABLISHED) |
866 | return -EDESTADDRREQ; | 1031 | return -EDESTADDRREQ; |
867 | 1032 | ||
868 | fl.fl_ip_dport = inet->dport; | 1033 | fl.fl_ip_dport = inet->inet_dport; |
869 | daddr = &np->daddr; | 1034 | daddr = &np->daddr; |
870 | fl.fl6_flowlabel = np->flow_label; | 1035 | fl.fl6_flowlabel = np->flow_label; |
871 | connected = 1; | 1036 | connected = 1; |
@@ -877,6 +1042,8 @@ do_udp_sendmsg: | |||
877 | if (!fl.oif) | 1042 | if (!fl.oif) |
878 | fl.oif = np->sticky_pktinfo.ipi6_ifindex; | 1043 | fl.oif = np->sticky_pktinfo.ipi6_ifindex; |
879 | 1044 | ||
1045 | fl.mark = sk->sk_mark; | ||
1046 | |||
880 | if (msg->msg_controllen) { | 1047 | if (msg->msg_controllen) { |
881 | opt = &opt_space; | 1048 | opt = &opt_space; |
882 | memset(opt, 0, sizeof(struct ipv6_txoptions)); | 1049 | memset(opt, 0, sizeof(struct ipv6_txoptions)); |
@@ -909,7 +1076,7 @@ do_udp_sendmsg: | |||
909 | fl.fl6_dst.s6_addr[15] = 0x1; /* :: means loopback (BSD'ism) */ | 1076 | fl.fl6_dst.s6_addr[15] = 0x1; /* :: means loopback (BSD'ism) */ |
910 | if (ipv6_addr_any(&fl.fl6_src) && !ipv6_addr_any(&np->saddr)) | 1077 | if (ipv6_addr_any(&fl.fl6_src) && !ipv6_addr_any(&np->saddr)) |
911 | ipv6_addr_copy(&fl.fl6_src, &np->saddr); | 1078 | ipv6_addr_copy(&fl.fl6_src, &np->saddr); |
912 | fl.fl_ip_sport = inet->sport; | 1079 | fl.fl_ip_sport = inet->inet_sport; |
913 | 1080 | ||
914 | /* merge ip6_build_xmit from ip6_output */ | 1081 | /* merge ip6_build_xmit from ip6_output */ |
915 | if (opt && opt->srcrt) { | 1082 | if (opt && opt->srcrt) { |
@@ -1190,10 +1357,10 @@ static void udp6_sock_seq_show(struct seq_file *seq, struct sock *sp, int bucket | |||
1190 | 1357 | ||
1191 | dest = &np->daddr; | 1358 | dest = &np->daddr; |
1192 | src = &np->rcv_saddr; | 1359 | src = &np->rcv_saddr; |
1193 | destp = ntohs(inet->dport); | 1360 | destp = ntohs(inet->inet_dport); |
1194 | srcp = ntohs(inet->sport); | 1361 | srcp = ntohs(inet->inet_sport); |
1195 | seq_printf(seq, | 1362 | seq_printf(seq, |
1196 | "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X " | 1363 | "%5d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X " |
1197 | "%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %d\n", | 1364 | "%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %d\n", |
1198 | bucket, | 1365 | bucket, |
1199 | src->s6_addr32[0], src->s6_addr32[1], | 1366 | src->s6_addr32[0], src->s6_addr32[1], |
@@ -1236,7 +1403,7 @@ static struct udp_seq_afinfo udp6_seq_afinfo = { | |||
1236 | }, | 1403 | }, |
1237 | }; | 1404 | }; |
1238 | 1405 | ||
1239 | int udp6_proc_init(struct net *net) | 1406 | int __net_init udp6_proc_init(struct net *net) |
1240 | { | 1407 | { |
1241 | return udp_proc_register(net, &udp6_seq_afinfo); | 1408 | return udp_proc_register(net, &udp6_seq_afinfo); |
1242 | } | 1409 | } |
@@ -1282,7 +1449,6 @@ static struct inet_protosw udpv6_protosw = { | |||
1282 | .protocol = IPPROTO_UDP, | 1449 | .protocol = IPPROTO_UDP, |
1283 | .prot = &udpv6_prot, | 1450 | .prot = &udpv6_prot, |
1284 | .ops = &inet6_dgram_ops, | 1451 | .ops = &inet6_dgram_ops, |
1285 | .capability =-1, | ||
1286 | .no_check = UDP_CSUM_DEFAULT, | 1452 | .no_check = UDP_CSUM_DEFAULT, |
1287 | .flags = INET_PROTOSW_PERMANENT, | 1453 | .flags = INET_PROTOSW_PERMANENT, |
1288 | }; | 1454 | }; |
diff --git a/net/ipv6/udplite.c b/net/ipv6/udplite.c index d737a27ee010..5f48fadc27f7 100644 --- a/net/ipv6/udplite.c +++ b/net/ipv6/udplite.c | |||
@@ -62,7 +62,6 @@ static struct inet_protosw udplite6_protosw = { | |||
62 | .protocol = IPPROTO_UDPLITE, | 62 | .protocol = IPPROTO_UDPLITE, |
63 | .prot = &udplitev6_prot, | 63 | .prot = &udplitev6_prot, |
64 | .ops = &inet6_dgram_ops, | 64 | .ops = &inet6_dgram_ops, |
65 | .capability = -1, | ||
66 | .no_check = 0, | 65 | .no_check = 0, |
67 | .flags = INET_PROTOSW_PERMANENT, | 66 | .flags = INET_PROTOSW_PERMANENT, |
68 | }; | 67 | }; |
@@ -105,12 +104,12 @@ static struct udp_seq_afinfo udplite6_seq_afinfo = { | |||
105 | }, | 104 | }, |
106 | }; | 105 | }; |
107 | 106 | ||
108 | static int udplite6_proc_init_net(struct net *net) | 107 | static int __net_init udplite6_proc_init_net(struct net *net) |
109 | { | 108 | { |
110 | return udp_proc_register(net, &udplite6_seq_afinfo); | 109 | return udp_proc_register(net, &udplite6_seq_afinfo); |
111 | } | 110 | } |
112 | 111 | ||
113 | static void udplite6_proc_exit_net(struct net *net) | 112 | static void __net_exit udplite6_proc_exit_net(struct net *net) |
114 | { | 113 | { |
115 | udp_proc_unregister(net, &udplite6_seq_afinfo); | 114 | udp_proc_unregister(net, &udplite6_seq_afinfo); |
116 | } | 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_mode_tunnel.c b/net/ipv6/xfrm6_mode_tunnel.c index 3927832227b9..b809812c8d30 100644 --- a/net/ipv6/xfrm6_mode_tunnel.c +++ b/net/ipv6/xfrm6_mode_tunnel.c | |||
@@ -5,6 +5,7 @@ | |||
5 | * Copyright (c) 2004-2006 Herbert Xu <herbert@gondor.apana.org.au> | 5 | * Copyright (c) 2004-2006 Herbert Xu <herbert@gondor.apana.org.au> |
6 | */ | 6 | */ |
7 | 7 | ||
8 | #include <linux/gfp.h> | ||
8 | #include <linux/init.h> | 9 | #include <linux/init.h> |
9 | #include <linux/kernel.h> | 10 | #include <linux/kernel.h> |
10 | #include <linux/module.h> | 11 | #include <linux/module.h> |
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_policy.c b/net/ipv6/xfrm6_policy.c index 8ec3d45cd1d9..00bf7c962b7e 100644 --- a/net/ipv6/xfrm6_policy.c +++ b/net/ipv6/xfrm6_policy.c | |||
@@ -24,7 +24,6 @@ | |||
24 | #include <net/mip6.h> | 24 | #include <net/mip6.h> |
25 | #endif | 25 | #endif |
26 | 26 | ||
27 | static struct dst_ops xfrm6_dst_ops; | ||
28 | static struct xfrm_policy_afinfo xfrm6_policy_afinfo; | 27 | static struct xfrm_policy_afinfo xfrm6_policy_afinfo; |
29 | 28 | ||
30 | static struct dst_entry *xfrm6_dst_lookup(struct net *net, int tos, | 29 | static struct dst_entry *xfrm6_dst_lookup(struct net *net, int tos, |
@@ -117,14 +116,15 @@ static int xfrm6_init_path(struct xfrm_dst *path, struct dst_entry *dst, | |||
117 | return 0; | 116 | return 0; |
118 | } | 117 | } |
119 | 118 | ||
120 | static int xfrm6_fill_dst(struct xfrm_dst *xdst, struct net_device *dev) | 119 | static int xfrm6_fill_dst(struct xfrm_dst *xdst, struct net_device *dev, |
120 | struct flowi *fl) | ||
121 | { | 121 | { |
122 | struct rt6_info *rt = (struct rt6_info*)xdst->route; | 122 | struct rt6_info *rt = (struct rt6_info*)xdst->route; |
123 | 123 | ||
124 | xdst->u.dst.dev = dev; | 124 | xdst->u.dst.dev = dev; |
125 | dev_hold(dev); | 125 | dev_hold(dev); |
126 | 126 | ||
127 | xdst->u.rt6.rt6i_idev = in6_dev_get(rt->u.dst.dev); | 127 | xdst->u.rt6.rt6i_idev = in6_dev_get(dev); |
128 | if (!xdst->u.rt6.rt6i_idev) | 128 | if (!xdst->u.rt6.rt6i_idev) |
129 | return -ENODEV; | 129 | return -ENODEV; |
130 | 130 | ||
@@ -224,8 +224,10 @@ _decode_session6(struct sk_buff *skb, struct flowi *fl, int reverse) | |||
224 | 224 | ||
225 | static inline int xfrm6_garbage_collect(struct dst_ops *ops) | 225 | static inline int xfrm6_garbage_collect(struct dst_ops *ops) |
226 | { | 226 | { |
227 | xfrm6_policy_afinfo.garbage_collect(&init_net); | 227 | struct net *net = container_of(ops, struct net, xfrm.xfrm6_dst_ops); |
228 | return (atomic_read(&xfrm6_dst_ops.entries) > xfrm6_dst_ops.gc_thresh*2); | 228 | |
229 | xfrm6_policy_afinfo.garbage_collect(net); | ||
230 | return (atomic_read(&ops->entries) > ops->gc_thresh * 2); | ||
229 | } | 231 | } |
230 | 232 | ||
231 | static void xfrm6_update_pmtu(struct dst_entry *dst, u32 mtu) | 233 | static void xfrm6_update_pmtu(struct dst_entry *dst, u32 mtu) |
@@ -309,9 +311,8 @@ static void xfrm6_policy_fini(void) | |||
309 | #ifdef CONFIG_SYSCTL | 311 | #ifdef CONFIG_SYSCTL |
310 | static struct ctl_table xfrm6_policy_table[] = { | 312 | static struct ctl_table xfrm6_policy_table[] = { |
311 | { | 313 | { |
312 | .ctl_name = CTL_UNNUMBERED, | ||
313 | .procname = "xfrm6_gc_thresh", | 314 | .procname = "xfrm6_gc_thresh", |
314 | .data = &xfrm6_dst_ops.gc_thresh, | 315 | .data = &init_net.xfrm.xfrm6_dst_ops.gc_thresh, |
315 | .maxlen = sizeof(int), | 316 | .maxlen = sizeof(int), |
316 | .mode = 0644, | 317 | .mode = 0644, |
317 | .proc_handler = proc_dointvec, | 318 | .proc_handler = proc_dointvec, |
@@ -327,13 +328,6 @@ int __init xfrm6_init(void) | |||
327 | int ret; | 328 | int ret; |
328 | unsigned int gc_thresh; | 329 | unsigned int gc_thresh; |
329 | 330 | ||
330 | ret = xfrm6_policy_init(); | ||
331 | if (ret) | ||
332 | goto out; | ||
333 | |||
334 | ret = xfrm6_state_init(); | ||
335 | if (ret) | ||
336 | goto out_policy; | ||
337 | /* | 331 | /* |
338 | * We need a good default value for the xfrm6 gc threshold. | 332 | * We need a good default value for the xfrm6 gc threshold. |
339 | * In ipv4 we set it to the route hash table size * 8, which | 333 | * In ipv4 we set it to the route hash table size * 8, which |
@@ -347,6 +341,15 @@ int __init xfrm6_init(void) | |||
347 | */ | 341 | */ |
348 | gc_thresh = FIB6_TABLE_HASHSZ * 8; | 342 | gc_thresh = FIB6_TABLE_HASHSZ * 8; |
349 | xfrm6_dst_ops.gc_thresh = (gc_thresh < 1024) ? 1024 : gc_thresh; | 343 | xfrm6_dst_ops.gc_thresh = (gc_thresh < 1024) ? 1024 : gc_thresh; |
344 | |||
345 | ret = xfrm6_policy_init(); | ||
346 | if (ret) | ||
347 | goto out; | ||
348 | |||
349 | ret = xfrm6_state_init(); | ||
350 | if (ret) | ||
351 | goto out_policy; | ||
352 | |||
350 | #ifdef CONFIG_SYSCTL | 353 | #ifdef CONFIG_SYSCTL |
351 | sysctl_hdr = register_net_sysctl_table(&init_net, net_ipv6_ctl_path, | 354 | sysctl_hdr = register_net_sysctl_table(&init_net, net_ipv6_ctl_path, |
352 | xfrm6_policy_table); | 355 | xfrm6_policy_table); |
diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c index 81a95c00e503..2ce3a8278f26 100644 --- a/net/ipv6/xfrm6_tunnel.c +++ b/net/ipv6/xfrm6_tunnel.c | |||
@@ -23,41 +23,51 @@ | |||
23 | */ | 23 | */ |
24 | #include <linux/module.h> | 24 | #include <linux/module.h> |
25 | #include <linux/xfrm.h> | 25 | #include <linux/xfrm.h> |
26 | #include <linux/list.h> | 26 | #include <linux/slab.h> |
27 | #include <linux/rculist.h> | ||
27 | #include <net/ip.h> | 28 | #include <net/ip.h> |
28 | #include <net/xfrm.h> | 29 | #include <net/xfrm.h> |
29 | #include <net/ipv6.h> | 30 | #include <net/ipv6.h> |
30 | #include <linux/ipv6.h> | 31 | #include <linux/ipv6.h> |
31 | #include <linux/icmpv6.h> | 32 | #include <linux/icmpv6.h> |
32 | #include <linux/mutex.h> | 33 | #include <linux/mutex.h> |
34 | #include <net/netns/generic.h> | ||
35 | |||
36 | #define XFRM6_TUNNEL_SPI_BYADDR_HSIZE 256 | ||
37 | #define XFRM6_TUNNEL_SPI_BYSPI_HSIZE 256 | ||
38 | |||
39 | #define XFRM6_TUNNEL_SPI_MIN 1 | ||
40 | #define XFRM6_TUNNEL_SPI_MAX 0xffffffff | ||
41 | |||
42 | struct xfrm6_tunnel_net { | ||
43 | struct hlist_head spi_byaddr[XFRM6_TUNNEL_SPI_BYADDR_HSIZE]; | ||
44 | struct hlist_head spi_byspi[XFRM6_TUNNEL_SPI_BYSPI_HSIZE]; | ||
45 | u32 spi; | ||
46 | }; | ||
47 | |||
48 | static int xfrm6_tunnel_net_id __read_mostly; | ||
49 | static inline struct xfrm6_tunnel_net *xfrm6_tunnel_pernet(struct net *net) | ||
50 | { | ||
51 | return net_generic(net, xfrm6_tunnel_net_id); | ||
52 | } | ||
33 | 53 | ||
34 | /* | 54 | /* |
35 | * xfrm_tunnel_spi things are for allocating unique id ("spi") | 55 | * xfrm_tunnel_spi things are for allocating unique id ("spi") |
36 | * per xfrm_address_t. | 56 | * per xfrm_address_t. |
37 | */ | 57 | */ |
38 | struct xfrm6_tunnel_spi { | 58 | struct xfrm6_tunnel_spi { |
39 | struct hlist_node list_byaddr; | 59 | struct hlist_node list_byaddr; |
40 | struct hlist_node list_byspi; | 60 | struct hlist_node list_byspi; |
41 | xfrm_address_t addr; | 61 | xfrm_address_t addr; |
42 | u32 spi; | 62 | u32 spi; |
43 | atomic_t refcnt; | 63 | atomic_t refcnt; |
64 | struct rcu_head rcu_head; | ||
44 | }; | 65 | }; |
45 | 66 | ||
46 | static DEFINE_RWLOCK(xfrm6_tunnel_spi_lock); | 67 | static DEFINE_SPINLOCK(xfrm6_tunnel_spi_lock); |
47 | |||
48 | static u32 xfrm6_tunnel_spi; | ||
49 | |||
50 | #define XFRM6_TUNNEL_SPI_MIN 1 | ||
51 | #define XFRM6_TUNNEL_SPI_MAX 0xffffffff | ||
52 | 68 | ||
53 | static struct kmem_cache *xfrm6_tunnel_spi_kmem __read_mostly; | 69 | static struct kmem_cache *xfrm6_tunnel_spi_kmem __read_mostly; |
54 | 70 | ||
55 | #define XFRM6_TUNNEL_SPI_BYADDR_HSIZE 256 | ||
56 | #define XFRM6_TUNNEL_SPI_BYSPI_HSIZE 256 | ||
57 | |||
58 | static struct hlist_head xfrm6_tunnel_spi_byaddr[XFRM6_TUNNEL_SPI_BYADDR_HSIZE]; | ||
59 | static struct hlist_head xfrm6_tunnel_spi_byspi[XFRM6_TUNNEL_SPI_BYSPI_HSIZE]; | ||
60 | |||
61 | static inline unsigned xfrm6_tunnel_spi_hash_byaddr(xfrm_address_t *addr) | 71 | static inline unsigned xfrm6_tunnel_spi_hash_byaddr(xfrm_address_t *addr) |
62 | { | 72 | { |
63 | unsigned h; | 73 | unsigned h; |
@@ -75,49 +85,14 @@ static inline unsigned xfrm6_tunnel_spi_hash_byspi(u32 spi) | |||
75 | return spi % XFRM6_TUNNEL_SPI_BYSPI_HSIZE; | 85 | return spi % XFRM6_TUNNEL_SPI_BYSPI_HSIZE; |
76 | } | 86 | } |
77 | 87 | ||
78 | 88 | static struct xfrm6_tunnel_spi *__xfrm6_tunnel_spi_lookup(struct net *net, xfrm_address_t *saddr) | |
79 | static int xfrm6_tunnel_spi_init(void) | ||
80 | { | ||
81 | int i; | ||
82 | |||
83 | xfrm6_tunnel_spi = 0; | ||
84 | xfrm6_tunnel_spi_kmem = kmem_cache_create("xfrm6_tunnel_spi", | ||
85 | sizeof(struct xfrm6_tunnel_spi), | ||
86 | 0, SLAB_HWCACHE_ALIGN, | ||
87 | NULL); | ||
88 | if (!xfrm6_tunnel_spi_kmem) | ||
89 | return -ENOMEM; | ||
90 | |||
91 | for (i = 0; i < XFRM6_TUNNEL_SPI_BYADDR_HSIZE; i++) | ||
92 | INIT_HLIST_HEAD(&xfrm6_tunnel_spi_byaddr[i]); | ||
93 | for (i = 0; i < XFRM6_TUNNEL_SPI_BYSPI_HSIZE; i++) | ||
94 | INIT_HLIST_HEAD(&xfrm6_tunnel_spi_byspi[i]); | ||
95 | return 0; | ||
96 | } | ||
97 | |||
98 | static void xfrm6_tunnel_spi_fini(void) | ||
99 | { | ||
100 | int i; | ||
101 | |||
102 | for (i = 0; i < XFRM6_TUNNEL_SPI_BYADDR_HSIZE; i++) { | ||
103 | if (!hlist_empty(&xfrm6_tunnel_spi_byaddr[i])) | ||
104 | return; | ||
105 | } | ||
106 | for (i = 0; i < XFRM6_TUNNEL_SPI_BYSPI_HSIZE; i++) { | ||
107 | if (!hlist_empty(&xfrm6_tunnel_spi_byspi[i])) | ||
108 | return; | ||
109 | } | ||
110 | kmem_cache_destroy(xfrm6_tunnel_spi_kmem); | ||
111 | xfrm6_tunnel_spi_kmem = NULL; | ||
112 | } | ||
113 | |||
114 | static struct xfrm6_tunnel_spi *__xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr) | ||
115 | { | 89 | { |
90 | struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net); | ||
116 | struct xfrm6_tunnel_spi *x6spi; | 91 | struct xfrm6_tunnel_spi *x6spi; |
117 | struct hlist_node *pos; | 92 | struct hlist_node *pos; |
118 | 93 | ||
119 | hlist_for_each_entry(x6spi, pos, | 94 | hlist_for_each_entry_rcu(x6spi, pos, |
120 | &xfrm6_tunnel_spi_byaddr[xfrm6_tunnel_spi_hash_byaddr(saddr)], | 95 | &xfrm6_tn->spi_byaddr[xfrm6_tunnel_spi_hash_byaddr(saddr)], |
121 | list_byaddr) { | 96 | list_byaddr) { |
122 | if (memcmp(&x6spi->addr, saddr, sizeof(x6spi->addr)) == 0) | 97 | if (memcmp(&x6spi->addr, saddr, sizeof(x6spi->addr)) == 0) |
123 | return x6spi; | 98 | return x6spi; |
@@ -126,28 +101,29 @@ static struct xfrm6_tunnel_spi *__xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr) | |||
126 | return NULL; | 101 | return NULL; |
127 | } | 102 | } |
128 | 103 | ||
129 | __be32 xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr) | 104 | __be32 xfrm6_tunnel_spi_lookup(struct net *net, xfrm_address_t *saddr) |
130 | { | 105 | { |
131 | struct xfrm6_tunnel_spi *x6spi; | 106 | struct xfrm6_tunnel_spi *x6spi; |
132 | u32 spi; | 107 | u32 spi; |
133 | 108 | ||
134 | read_lock_bh(&xfrm6_tunnel_spi_lock); | 109 | rcu_read_lock_bh(); |
135 | x6spi = __xfrm6_tunnel_spi_lookup(saddr); | 110 | x6spi = __xfrm6_tunnel_spi_lookup(net, saddr); |
136 | spi = x6spi ? x6spi->spi : 0; | 111 | spi = x6spi ? x6spi->spi : 0; |
137 | read_unlock_bh(&xfrm6_tunnel_spi_lock); | 112 | rcu_read_unlock_bh(); |
138 | return htonl(spi); | 113 | return htonl(spi); |
139 | } | 114 | } |
140 | 115 | ||
141 | EXPORT_SYMBOL(xfrm6_tunnel_spi_lookup); | 116 | EXPORT_SYMBOL(xfrm6_tunnel_spi_lookup); |
142 | 117 | ||
143 | static int __xfrm6_tunnel_spi_check(u32 spi) | 118 | static int __xfrm6_tunnel_spi_check(struct net *net, u32 spi) |
144 | { | 119 | { |
120 | struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net); | ||
145 | struct xfrm6_tunnel_spi *x6spi; | 121 | struct xfrm6_tunnel_spi *x6spi; |
146 | int index = xfrm6_tunnel_spi_hash_byspi(spi); | 122 | int index = xfrm6_tunnel_spi_hash_byspi(spi); |
147 | struct hlist_node *pos; | 123 | struct hlist_node *pos; |
148 | 124 | ||
149 | hlist_for_each_entry(x6spi, pos, | 125 | hlist_for_each_entry(x6spi, pos, |
150 | &xfrm6_tunnel_spi_byspi[index], | 126 | &xfrm6_tn->spi_byspi[index], |
151 | list_byspi) { | 127 | list_byspi) { |
152 | if (x6spi->spi == spi) | 128 | if (x6spi->spi == spi) |
153 | return -1; | 129 | return -1; |
@@ -155,32 +131,33 @@ static int __xfrm6_tunnel_spi_check(u32 spi) | |||
155 | return index; | 131 | return index; |
156 | } | 132 | } |
157 | 133 | ||
158 | static u32 __xfrm6_tunnel_alloc_spi(xfrm_address_t *saddr) | 134 | static u32 __xfrm6_tunnel_alloc_spi(struct net *net, xfrm_address_t *saddr) |
159 | { | 135 | { |
136 | struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net); | ||
160 | u32 spi; | 137 | u32 spi; |
161 | struct xfrm6_tunnel_spi *x6spi; | 138 | struct xfrm6_tunnel_spi *x6spi; |
162 | int index; | 139 | int index; |
163 | 140 | ||
164 | if (xfrm6_tunnel_spi < XFRM6_TUNNEL_SPI_MIN || | 141 | if (xfrm6_tn->spi < XFRM6_TUNNEL_SPI_MIN || |
165 | xfrm6_tunnel_spi >= XFRM6_TUNNEL_SPI_MAX) | 142 | xfrm6_tn->spi >= XFRM6_TUNNEL_SPI_MAX) |
166 | xfrm6_tunnel_spi = XFRM6_TUNNEL_SPI_MIN; | 143 | xfrm6_tn->spi = XFRM6_TUNNEL_SPI_MIN; |
167 | else | 144 | else |
168 | xfrm6_tunnel_spi++; | 145 | xfrm6_tn->spi++; |
169 | 146 | ||
170 | for (spi = xfrm6_tunnel_spi; spi <= XFRM6_TUNNEL_SPI_MAX; spi++) { | 147 | for (spi = xfrm6_tn->spi; spi <= XFRM6_TUNNEL_SPI_MAX; spi++) { |
171 | index = __xfrm6_tunnel_spi_check(spi); | 148 | index = __xfrm6_tunnel_spi_check(net, spi); |
172 | if (index >= 0) | 149 | if (index >= 0) |
173 | goto alloc_spi; | 150 | goto alloc_spi; |
174 | } | 151 | } |
175 | for (spi = XFRM6_TUNNEL_SPI_MIN; spi < xfrm6_tunnel_spi; spi++) { | 152 | for (spi = XFRM6_TUNNEL_SPI_MIN; spi < xfrm6_tn->spi; spi++) { |
176 | index = __xfrm6_tunnel_spi_check(spi); | 153 | index = __xfrm6_tunnel_spi_check(net, spi); |
177 | if (index >= 0) | 154 | if (index >= 0) |
178 | goto alloc_spi; | 155 | goto alloc_spi; |
179 | } | 156 | } |
180 | spi = 0; | 157 | spi = 0; |
181 | goto out; | 158 | goto out; |
182 | alloc_spi: | 159 | alloc_spi: |
183 | xfrm6_tunnel_spi = spi; | 160 | xfrm6_tn->spi = spi; |
184 | x6spi = kmem_cache_alloc(xfrm6_tunnel_spi_kmem, GFP_ATOMIC); | 161 | x6spi = kmem_cache_alloc(xfrm6_tunnel_spi_kmem, GFP_ATOMIC); |
185 | if (!x6spi) | 162 | if (!x6spi) |
186 | goto out; | 163 | goto out; |
@@ -189,54 +166,61 @@ alloc_spi: | |||
189 | x6spi->spi = spi; | 166 | x6spi->spi = spi; |
190 | atomic_set(&x6spi->refcnt, 1); | 167 | atomic_set(&x6spi->refcnt, 1); |
191 | 168 | ||
192 | hlist_add_head(&x6spi->list_byspi, &xfrm6_tunnel_spi_byspi[index]); | 169 | hlist_add_head_rcu(&x6spi->list_byspi, &xfrm6_tn->spi_byspi[index]); |
193 | 170 | ||
194 | index = xfrm6_tunnel_spi_hash_byaddr(saddr); | 171 | index = xfrm6_tunnel_spi_hash_byaddr(saddr); |
195 | hlist_add_head(&x6spi->list_byaddr, &xfrm6_tunnel_spi_byaddr[index]); | 172 | hlist_add_head_rcu(&x6spi->list_byaddr, &xfrm6_tn->spi_byaddr[index]); |
196 | out: | 173 | out: |
197 | return spi; | 174 | return spi; |
198 | } | 175 | } |
199 | 176 | ||
200 | __be32 xfrm6_tunnel_alloc_spi(xfrm_address_t *saddr) | 177 | __be32 xfrm6_tunnel_alloc_spi(struct net *net, xfrm_address_t *saddr) |
201 | { | 178 | { |
202 | struct xfrm6_tunnel_spi *x6spi; | 179 | struct xfrm6_tunnel_spi *x6spi; |
203 | u32 spi; | 180 | u32 spi; |
204 | 181 | ||
205 | write_lock_bh(&xfrm6_tunnel_spi_lock); | 182 | spin_lock_bh(&xfrm6_tunnel_spi_lock); |
206 | x6spi = __xfrm6_tunnel_spi_lookup(saddr); | 183 | x6spi = __xfrm6_tunnel_spi_lookup(net, saddr); |
207 | if (x6spi) { | 184 | if (x6spi) { |
208 | atomic_inc(&x6spi->refcnt); | 185 | atomic_inc(&x6spi->refcnt); |
209 | spi = x6spi->spi; | 186 | spi = x6spi->spi; |
210 | } else | 187 | } else |
211 | spi = __xfrm6_tunnel_alloc_spi(saddr); | 188 | spi = __xfrm6_tunnel_alloc_spi(net, saddr); |
212 | write_unlock_bh(&xfrm6_tunnel_spi_lock); | 189 | spin_unlock_bh(&xfrm6_tunnel_spi_lock); |
213 | 190 | ||
214 | return htonl(spi); | 191 | return htonl(spi); |
215 | } | 192 | } |
216 | 193 | ||
217 | EXPORT_SYMBOL(xfrm6_tunnel_alloc_spi); | 194 | EXPORT_SYMBOL(xfrm6_tunnel_alloc_spi); |
218 | 195 | ||
219 | void xfrm6_tunnel_free_spi(xfrm_address_t *saddr) | 196 | static void x6spi_destroy_rcu(struct rcu_head *head) |
197 | { | ||
198 | kmem_cache_free(xfrm6_tunnel_spi_kmem, | ||
199 | container_of(head, struct xfrm6_tunnel_spi, rcu_head)); | ||
200 | } | ||
201 | |||
202 | void xfrm6_tunnel_free_spi(struct net *net, xfrm_address_t *saddr) | ||
220 | { | 203 | { |
204 | struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net); | ||
221 | struct xfrm6_tunnel_spi *x6spi; | 205 | struct xfrm6_tunnel_spi *x6spi; |
222 | struct hlist_node *pos, *n; | 206 | struct hlist_node *pos, *n; |
223 | 207 | ||
224 | write_lock_bh(&xfrm6_tunnel_spi_lock); | 208 | spin_lock_bh(&xfrm6_tunnel_spi_lock); |
225 | 209 | ||
226 | hlist_for_each_entry_safe(x6spi, pos, n, | 210 | hlist_for_each_entry_safe(x6spi, pos, n, |
227 | &xfrm6_tunnel_spi_byaddr[xfrm6_tunnel_spi_hash_byaddr(saddr)], | 211 | &xfrm6_tn->spi_byaddr[xfrm6_tunnel_spi_hash_byaddr(saddr)], |
228 | list_byaddr) | 212 | list_byaddr) |
229 | { | 213 | { |
230 | if (memcmp(&x6spi->addr, saddr, sizeof(x6spi->addr)) == 0) { | 214 | if (memcmp(&x6spi->addr, saddr, sizeof(x6spi->addr)) == 0) { |
231 | if (atomic_dec_and_test(&x6spi->refcnt)) { | 215 | if (atomic_dec_and_test(&x6spi->refcnt)) { |
232 | hlist_del(&x6spi->list_byaddr); | 216 | hlist_del_rcu(&x6spi->list_byaddr); |
233 | hlist_del(&x6spi->list_byspi); | 217 | hlist_del_rcu(&x6spi->list_byspi); |
234 | kmem_cache_free(xfrm6_tunnel_spi_kmem, x6spi); | 218 | call_rcu(&x6spi->rcu_head, x6spi_destroy_rcu); |
235 | break; | 219 | break; |
236 | } | 220 | } |
237 | } | 221 | } |
238 | } | 222 | } |
239 | write_unlock_bh(&xfrm6_tunnel_spi_lock); | 223 | spin_unlock_bh(&xfrm6_tunnel_spi_lock); |
240 | } | 224 | } |
241 | 225 | ||
242 | EXPORT_SYMBOL(xfrm6_tunnel_free_spi); | 226 | EXPORT_SYMBOL(xfrm6_tunnel_free_spi); |
@@ -254,10 +238,11 @@ static int xfrm6_tunnel_input(struct xfrm_state *x, struct sk_buff *skb) | |||
254 | 238 | ||
255 | static int xfrm6_tunnel_rcv(struct sk_buff *skb) | 239 | static int xfrm6_tunnel_rcv(struct sk_buff *skb) |
256 | { | 240 | { |
241 | struct net *net = dev_net(skb->dev); | ||
257 | struct ipv6hdr *iph = ipv6_hdr(skb); | 242 | struct ipv6hdr *iph = ipv6_hdr(skb); |
258 | __be32 spi; | 243 | __be32 spi; |
259 | 244 | ||
260 | spi = xfrm6_tunnel_spi_lookup((xfrm_address_t *)&iph->saddr); | 245 | spi = xfrm6_tunnel_spi_lookup(net, (xfrm_address_t *)&iph->saddr); |
261 | return xfrm6_rcv_spi(skb, IPPROTO_IPV6, spi) > 0 ? : 0; | 246 | return xfrm6_rcv_spi(skb, IPPROTO_IPV6, spi) > 0 ? : 0; |
262 | } | 247 | } |
263 | 248 | ||
@@ -317,7 +302,9 @@ static int xfrm6_tunnel_init_state(struct xfrm_state *x) | |||
317 | 302 | ||
318 | static void xfrm6_tunnel_destroy(struct xfrm_state *x) | 303 | static void xfrm6_tunnel_destroy(struct xfrm_state *x) |
319 | { | 304 | { |
320 | xfrm6_tunnel_free_spi((xfrm_address_t *)&x->props.saddr); | 305 | struct net *net = xs_net(x); |
306 | |||
307 | xfrm6_tunnel_free_spi(net, (xfrm_address_t *)&x->props.saddr); | ||
321 | } | 308 | } |
322 | 309 | ||
323 | static const struct xfrm_type xfrm6_tunnel_type = { | 310 | static const struct xfrm_type xfrm6_tunnel_type = { |
@@ -342,34 +329,73 @@ static struct xfrm6_tunnel xfrm46_tunnel_handler = { | |||
342 | .priority = 2, | 329 | .priority = 2, |
343 | }; | 330 | }; |
344 | 331 | ||
332 | static int __net_init xfrm6_tunnel_net_init(struct net *net) | ||
333 | { | ||
334 | struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net); | ||
335 | unsigned int i; | ||
336 | |||
337 | for (i = 0; i < XFRM6_TUNNEL_SPI_BYADDR_HSIZE; i++) | ||
338 | INIT_HLIST_HEAD(&xfrm6_tn->spi_byaddr[i]); | ||
339 | for (i = 0; i < XFRM6_TUNNEL_SPI_BYSPI_HSIZE; i++) | ||
340 | INIT_HLIST_HEAD(&xfrm6_tn->spi_byspi[i]); | ||
341 | xfrm6_tn->spi = 0; | ||
342 | |||
343 | return 0; | ||
344 | } | ||
345 | |||
346 | static void __net_exit xfrm6_tunnel_net_exit(struct net *net) | ||
347 | { | ||
348 | } | ||
349 | |||
350 | static struct pernet_operations xfrm6_tunnel_net_ops = { | ||
351 | .init = xfrm6_tunnel_net_init, | ||
352 | .exit = xfrm6_tunnel_net_exit, | ||
353 | .id = &xfrm6_tunnel_net_id, | ||
354 | .size = sizeof(struct xfrm6_tunnel_net), | ||
355 | }; | ||
356 | |||
345 | static int __init xfrm6_tunnel_init(void) | 357 | static int __init xfrm6_tunnel_init(void) |
346 | { | 358 | { |
347 | if (xfrm_register_type(&xfrm6_tunnel_type, AF_INET6) < 0) | 359 | int rv; |
348 | goto err; | 360 | |
349 | if (xfrm6_tunnel_register(&xfrm6_tunnel_handler, AF_INET6)) | 361 | xfrm6_tunnel_spi_kmem = kmem_cache_create("xfrm6_tunnel_spi", |
350 | goto unreg; | 362 | sizeof(struct xfrm6_tunnel_spi), |
351 | if (xfrm6_tunnel_register(&xfrm46_tunnel_handler, AF_INET)) | 363 | 0, SLAB_HWCACHE_ALIGN, |
352 | goto dereg6; | 364 | NULL); |
353 | if (xfrm6_tunnel_spi_init() < 0) | 365 | if (!xfrm6_tunnel_spi_kmem) |
354 | goto dereg46; | 366 | return -ENOMEM; |
367 | rv = register_pernet_subsys(&xfrm6_tunnel_net_ops); | ||
368 | if (rv < 0) | ||
369 | goto out_pernet; | ||
370 | rv = xfrm_register_type(&xfrm6_tunnel_type, AF_INET6); | ||
371 | if (rv < 0) | ||
372 | goto out_type; | ||
373 | rv = xfrm6_tunnel_register(&xfrm6_tunnel_handler, AF_INET6); | ||
374 | if (rv < 0) | ||
375 | goto out_xfrm6; | ||
376 | rv = xfrm6_tunnel_register(&xfrm46_tunnel_handler, AF_INET); | ||
377 | if (rv < 0) | ||
378 | goto out_xfrm46; | ||
355 | return 0; | 379 | return 0; |
356 | 380 | ||
357 | dereg46: | 381 | out_xfrm46: |
358 | xfrm6_tunnel_deregister(&xfrm46_tunnel_handler, AF_INET); | ||
359 | dereg6: | ||
360 | xfrm6_tunnel_deregister(&xfrm6_tunnel_handler, AF_INET6); | 382 | xfrm6_tunnel_deregister(&xfrm6_tunnel_handler, AF_INET6); |
361 | unreg: | 383 | out_xfrm6: |
362 | xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6); | 384 | xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6); |
363 | err: | 385 | out_type: |
364 | return -EAGAIN; | 386 | unregister_pernet_subsys(&xfrm6_tunnel_net_ops); |
387 | out_pernet: | ||
388 | kmem_cache_destroy(xfrm6_tunnel_spi_kmem); | ||
389 | return rv; | ||
365 | } | 390 | } |
366 | 391 | ||
367 | static void __exit xfrm6_tunnel_fini(void) | 392 | static void __exit xfrm6_tunnel_fini(void) |
368 | { | 393 | { |
369 | xfrm6_tunnel_spi_fini(); | ||
370 | xfrm6_tunnel_deregister(&xfrm46_tunnel_handler, AF_INET); | 394 | xfrm6_tunnel_deregister(&xfrm46_tunnel_handler, AF_INET); |
371 | xfrm6_tunnel_deregister(&xfrm6_tunnel_handler, AF_INET6); | 395 | xfrm6_tunnel_deregister(&xfrm6_tunnel_handler, AF_INET6); |
372 | xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6); | 396 | xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6); |
397 | unregister_pernet_subsys(&xfrm6_tunnel_net_ops); | ||
398 | kmem_cache_destroy(xfrm6_tunnel_spi_kmem); | ||
373 | } | 399 | } |
374 | 400 | ||
375 | module_init(xfrm6_tunnel_init); | 401 | module_init(xfrm6_tunnel_init); |