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); |
