diff options
Diffstat (limited to 'net/ipv6')
56 files changed, 1504 insertions, 1040 deletions
diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile index 2fe68364bb20..2e8c06108ab9 100644 --- a/net/ipv6/Makefile +++ b/net/ipv6/Makefile | |||
@@ -45,3 +45,7 @@ obj-y += addrconf_core.o exthdrs_core.o ip6_checksum.o ip6_icmp.o | |||
45 | obj-$(CONFIG_INET) += output_core.o protocol.o $(ipv6-offload) | 45 | obj-$(CONFIG_INET) += output_core.o protocol.o $(ipv6-offload) |
46 | 46 | ||
47 | obj-$(subst m,y,$(CONFIG_IPV6)) += inet6_hashtables.o | 47 | obj-$(subst m,y,$(CONFIG_IPV6)) += inet6_hashtables.o |
48 | |||
49 | ifneq ($(CONFIG_IPV6),) | ||
50 | obj-$(CONFIG_NET_UDP_TUNNEL) += ip6_udp_tunnel.o | ||
51 | endif | ||
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 3e118dfddd02..725c763270a0 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
@@ -180,7 +180,7 @@ static struct ipv6_devconf ipv6_devconf __read_mostly = { | |||
180 | .rtr_solicits = MAX_RTR_SOLICITATIONS, | 180 | .rtr_solicits = MAX_RTR_SOLICITATIONS, |
181 | .rtr_solicit_interval = RTR_SOLICITATION_INTERVAL, | 181 | .rtr_solicit_interval = RTR_SOLICITATION_INTERVAL, |
182 | .rtr_solicit_delay = MAX_RTR_SOLICITATION_DELAY, | 182 | .rtr_solicit_delay = MAX_RTR_SOLICITATION_DELAY, |
183 | .use_tempaddr = 0, | 183 | .use_tempaddr = 0, |
184 | .temp_valid_lft = TEMP_VALID_LIFETIME, | 184 | .temp_valid_lft = TEMP_VALID_LIFETIME, |
185 | .temp_prefered_lft = TEMP_PREFERRED_LIFETIME, | 185 | .temp_prefered_lft = TEMP_PREFERRED_LIFETIME, |
186 | .regen_max_retry = REGEN_MAX_RETRY, | 186 | .regen_max_retry = REGEN_MAX_RETRY, |
@@ -1105,8 +1105,8 @@ retry: | |||
1105 | spin_unlock_bh(&ifp->lock); | 1105 | spin_unlock_bh(&ifp->lock); |
1106 | 1106 | ||
1107 | regen_advance = idev->cnf.regen_max_retry * | 1107 | regen_advance = idev->cnf.regen_max_retry * |
1108 | idev->cnf.dad_transmits * | 1108 | idev->cnf.dad_transmits * |
1109 | NEIGH_VAR(idev->nd_parms, RETRANS_TIME) / HZ; | 1109 | NEIGH_VAR(idev->nd_parms, RETRANS_TIME) / HZ; |
1110 | write_unlock_bh(&idev->lock); | 1110 | write_unlock_bh(&idev->lock); |
1111 | 1111 | ||
1112 | /* A temporary address is created only if this calculated Preferred | 1112 | /* A temporary address is created only if this calculated Preferred |
@@ -1725,7 +1725,7 @@ static void addrconf_join_anycast(struct inet6_ifaddr *ifp) | |||
1725 | ipv6_addr_prefix(&addr, &ifp->addr, ifp->prefix_len); | 1725 | ipv6_addr_prefix(&addr, &ifp->addr, ifp->prefix_len); |
1726 | if (ipv6_addr_any(&addr)) | 1726 | if (ipv6_addr_any(&addr)) |
1727 | return; | 1727 | return; |
1728 | ipv6_dev_ac_inc(ifp->idev->dev, &addr); | 1728 | __ipv6_dev_ac_inc(ifp->idev, &addr); |
1729 | } | 1729 | } |
1730 | 1730 | ||
1731 | /* caller must hold RTNL */ | 1731 | /* caller must hold RTNL */ |
@@ -2844,6 +2844,9 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, | |||
2844 | if (dev->flags & IFF_SLAVE) | 2844 | if (dev->flags & IFF_SLAVE) |
2845 | break; | 2845 | break; |
2846 | 2846 | ||
2847 | if (idev && idev->cnf.disable_ipv6) | ||
2848 | break; | ||
2849 | |||
2847 | if (event == NETDEV_UP) { | 2850 | if (event == NETDEV_UP) { |
2848 | if (!addrconf_qdisc_ok(dev)) { | 2851 | if (!addrconf_qdisc_ok(dev)) { |
2849 | /* device is not ready yet. */ | 2852 | /* device is not ready yet. */ |
@@ -3030,7 +3033,7 @@ static int addrconf_ifdown(struct net_device *dev, int how) | |||
3030 | struct hlist_head *h = &inet6_addr_lst[i]; | 3033 | struct hlist_head *h = &inet6_addr_lst[i]; |
3031 | 3034 | ||
3032 | spin_lock_bh(&addrconf_hash_lock); | 3035 | spin_lock_bh(&addrconf_hash_lock); |
3033 | restart: | 3036 | restart: |
3034 | hlist_for_each_entry_rcu(ifa, h, addr_lst) { | 3037 | hlist_for_each_entry_rcu(ifa, h, addr_lst) { |
3035 | if (ifa->idev == idev) { | 3038 | if (ifa->idev == idev) { |
3036 | hlist_del_init_rcu(&ifa->addr_lst); | 3039 | hlist_del_init_rcu(&ifa->addr_lst); |
@@ -3544,8 +3547,8 @@ static void __net_exit if6_proc_net_exit(struct net *net) | |||
3544 | } | 3547 | } |
3545 | 3548 | ||
3546 | static struct pernet_operations if6_proc_net_ops = { | 3549 | static struct pernet_operations if6_proc_net_ops = { |
3547 | .init = if6_proc_net_init, | 3550 | .init = if6_proc_net_init, |
3548 | .exit = if6_proc_net_exit, | 3551 | .exit = if6_proc_net_exit, |
3549 | }; | 3552 | }; |
3550 | 3553 | ||
3551 | int __init if6_proc_init(void) | 3554 | int __init if6_proc_init(void) |
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 2daa3a133e49..e8c4400f23e9 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c | |||
@@ -7,15 +7,15 @@ | |||
7 | * | 7 | * |
8 | * Adapted from linux/net/ipv4/af_inet.c | 8 | * Adapted from linux/net/ipv4/af_inet.c |
9 | * | 9 | * |
10 | * Fixes: | 10 | * Fixes: |
11 | * piggy, Karl Knutson : Socket protocol table | 11 | * piggy, Karl Knutson : Socket protocol table |
12 | * Hideaki YOSHIFUJI : sin6_scope_id support | 12 | * Hideaki YOSHIFUJI : sin6_scope_id support |
13 | * Arnaldo Melo : check proc_net_create return, cleanups | 13 | * Arnaldo Melo : check proc_net_create return, cleanups |
14 | * | 14 | * |
15 | * This program is free software; you can redistribute it and/or | 15 | * This program is free software; you can redistribute it and/or |
16 | * modify it under the terms of the GNU General Public License | 16 | * modify it under the terms of the GNU General Public License |
17 | * as published by the Free Software Foundation; either version | 17 | * as published by the Free Software Foundation; either version |
18 | * 2 of the License, or (at your option) any later version. | 18 | * 2 of the License, or (at your option) any later version. |
19 | */ | 19 | */ |
20 | 20 | ||
21 | #define pr_fmt(fmt) "IPv6: " fmt | 21 | #define pr_fmt(fmt) "IPv6: " fmt |
@@ -302,7 +302,7 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) | |||
302 | /* Reproduce AF_INET checks to make the bindings consistent */ | 302 | /* Reproduce AF_INET checks to make the bindings consistent */ |
303 | v4addr = addr->sin6_addr.s6_addr32[3]; | 303 | v4addr = addr->sin6_addr.s6_addr32[3]; |
304 | chk_addr_ret = inet_addr_type(net, v4addr); | 304 | chk_addr_ret = inet_addr_type(net, v4addr); |
305 | if (!sysctl_ip_nonlocal_bind && | 305 | if (!net->ipv4.sysctl_ip_nonlocal_bind && |
306 | !(inet->freebind || inet->transparent) && | 306 | !(inet->freebind || inet->transparent) && |
307 | v4addr != htonl(INADDR_ANY) && | 307 | v4addr != htonl(INADDR_ANY) && |
308 | chk_addr_ret != RTN_LOCAL && | 308 | chk_addr_ret != RTN_LOCAL && |
@@ -672,10 +672,10 @@ int inet6_sk_rebuild_header(struct sock *sk) | |||
672 | } | 672 | } |
673 | EXPORT_SYMBOL_GPL(inet6_sk_rebuild_header); | 673 | EXPORT_SYMBOL_GPL(inet6_sk_rebuild_header); |
674 | 674 | ||
675 | bool ipv6_opt_accepted(const struct sock *sk, const struct sk_buff *skb) | 675 | bool ipv6_opt_accepted(const struct sock *sk, const struct sk_buff *skb, |
676 | const struct inet6_skb_parm *opt) | ||
676 | { | 677 | { |
677 | const struct ipv6_pinfo *np = inet6_sk(sk); | 678 | const struct ipv6_pinfo *np = inet6_sk(sk); |
678 | const struct inet6_skb_parm *opt = IP6CB(skb); | ||
679 | 679 | ||
680 | if (np->rxopt.all) { | 680 | if (np->rxopt.all) { |
681 | if ((opt->hop && (np->rxopt.bits.hopopts || | 681 | if ((opt->hop && (np->rxopt.bits.hopopts || |
@@ -766,7 +766,7 @@ static int __net_init inet6_net_init(struct net *net) | |||
766 | net->ipv6.sysctl.icmpv6_time = 1*HZ; | 766 | net->ipv6.sysctl.icmpv6_time = 1*HZ; |
767 | net->ipv6.sysctl.flowlabel_consistency = 1; | 767 | net->ipv6.sysctl.flowlabel_consistency = 1; |
768 | net->ipv6.sysctl.auto_flowlabels = 0; | 768 | net->ipv6.sysctl.auto_flowlabels = 0; |
769 | atomic_set(&net->ipv6.rt_genid, 0); | 769 | atomic_set(&net->ipv6.fib6_sernum, 1); |
770 | 770 | ||
771 | err = ipv6_init_mibs(net); | 771 | err = ipv6_init_mibs(net); |
772 | if (err) | 772 | if (err) |
diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c index 72a4930bdc0a..6d16eb0e0c7f 100644 --- a/net/ipv6/ah6.c +++ b/net/ipv6/ah6.c | |||
@@ -17,10 +17,10 @@ | |||
17 | * Authors | 17 | * Authors |
18 | * | 18 | * |
19 | * Mitsuru KANDA @USAGI : IPv6 Support | 19 | * Mitsuru KANDA @USAGI : IPv6 Support |
20 | * Kazunori MIYAZAWA @USAGI : | 20 | * Kazunori MIYAZAWA @USAGI : |
21 | * Kunihiro Ishiguro <kunihiro@ipinfusion.com> | 21 | * Kunihiro Ishiguro <kunihiro@ipinfusion.com> |
22 | * | 22 | * |
23 | * This file is derived from net/ipv4/ah.c. | 23 | * This file is derived from net/ipv4/ah.c. |
24 | */ | 24 | */ |
25 | 25 | ||
26 | #define pr_fmt(fmt) "IPv6: " fmt | 26 | #define pr_fmt(fmt) "IPv6: " fmt |
@@ -284,7 +284,7 @@ static int ipv6_clear_mutable_options(struct ipv6hdr *iph, int len, int dir) | |||
284 | ipv6_rearrange_rthdr(iph, exthdr.rth); | 284 | ipv6_rearrange_rthdr(iph, exthdr.rth); |
285 | break; | 285 | break; |
286 | 286 | ||
287 | default : | 287 | default: |
288 | return 0; | 288 | return 0; |
289 | } | 289 | } |
290 | 290 | ||
@@ -478,7 +478,7 @@ static void ah6_input_done(struct crypto_async_request *base, int err) | |||
478 | auth_data = ah_tmp_auth(work_iph, hdr_len); | 478 | auth_data = ah_tmp_auth(work_iph, hdr_len); |
479 | icv = ah_tmp_icv(ahp->ahash, auth_data, ahp->icv_trunc_len); | 479 | icv = ah_tmp_icv(ahp->ahash, auth_data, ahp->icv_trunc_len); |
480 | 480 | ||
481 | err = memcmp(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG: 0; | 481 | err = memcmp(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG : 0; |
482 | if (err) | 482 | if (err) |
483 | goto out; | 483 | goto out; |
484 | 484 | ||
@@ -622,7 +622,7 @@ static int ah6_input(struct xfrm_state *x, struct sk_buff *skb) | |||
622 | goto out_free; | 622 | goto out_free; |
623 | } | 623 | } |
624 | 624 | ||
625 | err = memcmp(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG: 0; | 625 | err = memcmp(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG : 0; |
626 | if (err) | 626 | if (err) |
627 | goto out_free; | 627 | goto out_free; |
628 | 628 | ||
@@ -647,8 +647,8 @@ static int ah6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
647 | u8 type, u8 code, int offset, __be32 info) | 647 | u8 type, u8 code, int offset, __be32 info) |
648 | { | 648 | { |
649 | struct net *net = dev_net(skb->dev); | 649 | struct net *net = dev_net(skb->dev); |
650 | struct ipv6hdr *iph = (struct ipv6hdr*)skb->data; | 650 | struct ipv6hdr *iph = (struct ipv6hdr *)skb->data; |
651 | struct ip_auth_hdr *ah = (struct ip_auth_hdr*)(skb->data+offset); | 651 | struct ip_auth_hdr *ah = (struct ip_auth_hdr *)(skb->data+offset); |
652 | struct xfrm_state *x; | 652 | struct xfrm_state *x; |
653 | 653 | ||
654 | if (type != ICMPV6_PKT_TOOBIG && | 654 | if (type != ICMPV6_PKT_TOOBIG && |
@@ -713,8 +713,6 @@ static int ah6_init_state(struct xfrm_state *x) | |||
713 | ahp->icv_full_len = aalg_desc->uinfo.auth.icv_fullbits/8; | 713 | ahp->icv_full_len = aalg_desc->uinfo.auth.icv_fullbits/8; |
714 | ahp->icv_trunc_len = x->aalg->alg_trunc_len/8; | 714 | ahp->icv_trunc_len = x->aalg->alg_trunc_len/8; |
715 | 715 | ||
716 | BUG_ON(ahp->icv_trunc_len > MAX_AH_AUTH_LEN); | ||
717 | |||
718 | x->props.header_len = XFRM_ALIGN8(sizeof(struct ip_auth_hdr) + | 716 | x->props.header_len = XFRM_ALIGN8(sizeof(struct ip_auth_hdr) + |
719 | ahp->icv_trunc_len); | 717 | ahp->icv_trunc_len); |
720 | switch (x->props.mode) { | 718 | switch (x->props.mode) { |
@@ -755,11 +753,10 @@ static int ah6_rcv_cb(struct sk_buff *skb, int err) | |||
755 | return 0; | 753 | return 0; |
756 | } | 754 | } |
757 | 755 | ||
758 | static const struct xfrm_type ah6_type = | 756 | static const struct xfrm_type ah6_type = { |
759 | { | ||
760 | .description = "AH6", | 757 | .description = "AH6", |
761 | .owner = THIS_MODULE, | 758 | .owner = THIS_MODULE, |
762 | .proto = IPPROTO_AH, | 759 | .proto = IPPROTO_AH, |
763 | .flags = XFRM_TYPE_REPLAY_PROT, | 760 | .flags = XFRM_TYPE_REPLAY_PROT, |
764 | .init_state = ah6_init_state, | 761 | .init_state = ah6_init_state, |
765 | .destructor = ah6_destroy, | 762 | .destructor = ah6_destroy, |
diff --git a/net/ipv6/anycast.c b/net/ipv6/anycast.c index 9a386842fd62..f5e319a8d4e2 100644 --- a/net/ipv6/anycast.c +++ b/net/ipv6/anycast.c | |||
@@ -46,10 +46,6 @@ | |||
46 | 46 | ||
47 | static int ipv6_dev_ac_dec(struct net_device *dev, const struct in6_addr *addr); | 47 | static int ipv6_dev_ac_dec(struct net_device *dev, const struct in6_addr *addr); |
48 | 48 | ||
49 | /* Big ac list lock for all the sockets */ | ||
50 | static DEFINE_SPINLOCK(ipv6_sk_ac_lock); | ||
51 | |||
52 | |||
53 | /* | 49 | /* |
54 | * socket join an anycast group | 50 | * socket join an anycast group |
55 | */ | 51 | */ |
@@ -78,7 +74,6 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, const struct in6_addr *addr) | |||
78 | pac->acl_addr = *addr; | 74 | pac->acl_addr = *addr; |
79 | 75 | ||
80 | rtnl_lock(); | 76 | rtnl_lock(); |
81 | rcu_read_lock(); | ||
82 | if (ifindex == 0) { | 77 | if (ifindex == 0) { |
83 | struct rt6_info *rt; | 78 | struct rt6_info *rt; |
84 | 79 | ||
@@ -91,11 +86,11 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, const struct in6_addr *addr) | |||
91 | goto error; | 86 | goto error; |
92 | } else { | 87 | } else { |
93 | /* router, no matching interface: just pick one */ | 88 | /* router, no matching interface: just pick one */ |
94 | dev = dev_get_by_flags_rcu(net, IFF_UP, | 89 | dev = __dev_get_by_flags(net, IFF_UP, |
95 | IFF_UP | IFF_LOOPBACK); | 90 | IFF_UP | IFF_LOOPBACK); |
96 | } | 91 | } |
97 | } else | 92 | } else |
98 | dev = dev_get_by_index_rcu(net, ifindex); | 93 | dev = __dev_get_by_index(net, ifindex); |
99 | 94 | ||
100 | if (dev == NULL) { | 95 | if (dev == NULL) { |
101 | err = -ENODEV; | 96 | err = -ENODEV; |
@@ -127,17 +122,14 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, const struct in6_addr *addr) | |||
127 | goto error; | 122 | goto error; |
128 | } | 123 | } |
129 | 124 | ||
130 | err = ipv6_dev_ac_inc(dev, addr); | 125 | err = __ipv6_dev_ac_inc(idev, addr); |
131 | if (!err) { | 126 | if (!err) { |
132 | spin_lock_bh(&ipv6_sk_ac_lock); | ||
133 | pac->acl_next = np->ipv6_ac_list; | 127 | pac->acl_next = np->ipv6_ac_list; |
134 | np->ipv6_ac_list = pac; | 128 | np->ipv6_ac_list = pac; |
135 | spin_unlock_bh(&ipv6_sk_ac_lock); | ||
136 | pac = NULL; | 129 | pac = NULL; |
137 | } | 130 | } |
138 | 131 | ||
139 | error: | 132 | error: |
140 | rcu_read_unlock(); | ||
141 | rtnl_unlock(); | 133 | rtnl_unlock(); |
142 | if (pac) | 134 | if (pac) |
143 | sock_kfree_s(sk, pac, sizeof(*pac)); | 135 | sock_kfree_s(sk, pac, sizeof(*pac)); |
@@ -154,7 +146,7 @@ int ipv6_sock_ac_drop(struct sock *sk, int ifindex, const struct in6_addr *addr) | |||
154 | struct ipv6_ac_socklist *pac, *prev_pac; | 146 | struct ipv6_ac_socklist *pac, *prev_pac; |
155 | struct net *net = sock_net(sk); | 147 | struct net *net = sock_net(sk); |
156 | 148 | ||
157 | spin_lock_bh(&ipv6_sk_ac_lock); | 149 | rtnl_lock(); |
158 | prev_pac = NULL; | 150 | prev_pac = NULL; |
159 | for (pac = np->ipv6_ac_list; pac; pac = pac->acl_next) { | 151 | for (pac = np->ipv6_ac_list; pac; pac = pac->acl_next) { |
160 | if ((ifindex == 0 || pac->acl_ifindex == ifindex) && | 152 | if ((ifindex == 0 || pac->acl_ifindex == ifindex) && |
@@ -163,7 +155,7 @@ int ipv6_sock_ac_drop(struct sock *sk, int ifindex, const struct in6_addr *addr) | |||
163 | prev_pac = pac; | 155 | prev_pac = pac; |
164 | } | 156 | } |
165 | if (!pac) { | 157 | if (!pac) { |
166 | spin_unlock_bh(&ipv6_sk_ac_lock); | 158 | rtnl_unlock(); |
167 | return -ENOENT; | 159 | return -ENOENT; |
168 | } | 160 | } |
169 | if (prev_pac) | 161 | if (prev_pac) |
@@ -171,14 +163,9 @@ int ipv6_sock_ac_drop(struct sock *sk, int ifindex, const struct in6_addr *addr) | |||
171 | else | 163 | else |
172 | np->ipv6_ac_list = pac->acl_next; | 164 | np->ipv6_ac_list = pac->acl_next; |
173 | 165 | ||
174 | spin_unlock_bh(&ipv6_sk_ac_lock); | 166 | dev = __dev_get_by_index(net, pac->acl_ifindex); |
175 | |||
176 | rtnl_lock(); | ||
177 | rcu_read_lock(); | ||
178 | dev = dev_get_by_index_rcu(net, pac->acl_ifindex); | ||
179 | if (dev) | 167 | if (dev) |
180 | ipv6_dev_ac_dec(dev, &pac->acl_addr); | 168 | ipv6_dev_ac_dec(dev, &pac->acl_addr); |
181 | rcu_read_unlock(); | ||
182 | rtnl_unlock(); | 169 | rtnl_unlock(); |
183 | 170 | ||
184 | sock_kfree_s(sk, pac, sizeof(*pac)); | 171 | sock_kfree_s(sk, pac, sizeof(*pac)); |
@@ -196,19 +183,16 @@ void ipv6_sock_ac_close(struct sock *sk) | |||
196 | if (!np->ipv6_ac_list) | 183 | if (!np->ipv6_ac_list) |
197 | return; | 184 | return; |
198 | 185 | ||
199 | spin_lock_bh(&ipv6_sk_ac_lock); | 186 | rtnl_lock(); |
200 | pac = np->ipv6_ac_list; | 187 | pac = np->ipv6_ac_list; |
201 | np->ipv6_ac_list = NULL; | 188 | np->ipv6_ac_list = NULL; |
202 | spin_unlock_bh(&ipv6_sk_ac_lock); | ||
203 | 189 | ||
204 | prev_index = 0; | 190 | prev_index = 0; |
205 | rtnl_lock(); | ||
206 | rcu_read_lock(); | ||
207 | while (pac) { | 191 | while (pac) { |
208 | struct ipv6_ac_socklist *next = pac->acl_next; | 192 | struct ipv6_ac_socklist *next = pac->acl_next; |
209 | 193 | ||
210 | if (pac->acl_ifindex != prev_index) { | 194 | if (pac->acl_ifindex != prev_index) { |
211 | dev = dev_get_by_index_rcu(net, pac->acl_ifindex); | 195 | dev = __dev_get_by_index(net, pac->acl_ifindex); |
212 | prev_index = pac->acl_ifindex; | 196 | prev_index = pac->acl_ifindex; |
213 | } | 197 | } |
214 | if (dev) | 198 | if (dev) |
@@ -216,10 +200,14 @@ void ipv6_sock_ac_close(struct sock *sk) | |||
216 | sock_kfree_s(sk, pac, sizeof(*pac)); | 200 | sock_kfree_s(sk, pac, sizeof(*pac)); |
217 | pac = next; | 201 | pac = next; |
218 | } | 202 | } |
219 | rcu_read_unlock(); | ||
220 | rtnl_unlock(); | 203 | rtnl_unlock(); |
221 | } | 204 | } |
222 | 205 | ||
206 | static void aca_get(struct ifacaddr6 *aca) | ||
207 | { | ||
208 | atomic_inc(&aca->aca_refcnt); | ||
209 | } | ||
210 | |||
223 | static void aca_put(struct ifacaddr6 *ac) | 211 | static void aca_put(struct ifacaddr6 *ac) |
224 | { | 212 | { |
225 | if (atomic_dec_and_test(&ac->aca_refcnt)) { | 213 | if (atomic_dec_and_test(&ac->aca_refcnt)) { |
@@ -229,23 +217,40 @@ static void aca_put(struct ifacaddr6 *ac) | |||
229 | } | 217 | } |
230 | } | 218 | } |
231 | 219 | ||
220 | static struct ifacaddr6 *aca_alloc(struct rt6_info *rt, | ||
221 | const struct in6_addr *addr) | ||
222 | { | ||
223 | struct inet6_dev *idev = rt->rt6i_idev; | ||
224 | struct ifacaddr6 *aca; | ||
225 | |||
226 | aca = kzalloc(sizeof(*aca), GFP_ATOMIC); | ||
227 | if (aca == NULL) | ||
228 | return NULL; | ||
229 | |||
230 | aca->aca_addr = *addr; | ||
231 | in6_dev_hold(idev); | ||
232 | aca->aca_idev = idev; | ||
233 | aca->aca_rt = rt; | ||
234 | aca->aca_users = 1; | ||
235 | /* aca_tstamp should be updated upon changes */ | ||
236 | aca->aca_cstamp = aca->aca_tstamp = jiffies; | ||
237 | atomic_set(&aca->aca_refcnt, 1); | ||
238 | spin_lock_init(&aca->aca_lock); | ||
239 | |||
240 | return aca; | ||
241 | } | ||
242 | |||
232 | /* | 243 | /* |
233 | * device anycast group inc (add if not found) | 244 | * device anycast group inc (add if not found) |
234 | */ | 245 | */ |
235 | int ipv6_dev_ac_inc(struct net_device *dev, const struct in6_addr *addr) | 246 | int __ipv6_dev_ac_inc(struct inet6_dev *idev, const struct in6_addr *addr) |
236 | { | 247 | { |
237 | struct ifacaddr6 *aca; | 248 | struct ifacaddr6 *aca; |
238 | struct inet6_dev *idev; | ||
239 | struct rt6_info *rt; | 249 | struct rt6_info *rt; |
240 | int err; | 250 | int err; |
241 | 251 | ||
242 | ASSERT_RTNL(); | 252 | ASSERT_RTNL(); |
243 | 253 | ||
244 | idev = in6_dev_get(dev); | ||
245 | |||
246 | if (idev == NULL) | ||
247 | return -EINVAL; | ||
248 | |||
249 | write_lock_bh(&idev->lock); | 254 | write_lock_bh(&idev->lock); |
250 | if (idev->dead) { | 255 | if (idev->dead) { |
251 | err = -ENODEV; | 256 | err = -ENODEV; |
@@ -260,46 +265,35 @@ int ipv6_dev_ac_inc(struct net_device *dev, const struct in6_addr *addr) | |||
260 | } | 265 | } |
261 | } | 266 | } |
262 | 267 | ||
263 | /* | ||
264 | * not found: create a new one. | ||
265 | */ | ||
266 | |||
267 | aca = kzalloc(sizeof(struct ifacaddr6), GFP_ATOMIC); | ||
268 | |||
269 | if (aca == NULL) { | ||
270 | err = -ENOMEM; | ||
271 | goto out; | ||
272 | } | ||
273 | |||
274 | rt = addrconf_dst_alloc(idev, addr, true); | 268 | rt = addrconf_dst_alloc(idev, addr, true); |
275 | if (IS_ERR(rt)) { | 269 | if (IS_ERR(rt)) { |
276 | kfree(aca); | ||
277 | err = PTR_ERR(rt); | 270 | err = PTR_ERR(rt); |
278 | goto out; | 271 | goto out; |
279 | } | 272 | } |
280 | 273 | aca = aca_alloc(rt, addr); | |
281 | aca->aca_addr = *addr; | 274 | if (aca == NULL) { |
282 | aca->aca_idev = idev; | 275 | ip6_rt_put(rt); |
283 | aca->aca_rt = rt; | 276 | err = -ENOMEM; |
284 | aca->aca_users = 1; | 277 | goto out; |
285 | /* aca_tstamp should be updated upon changes */ | 278 | } |
286 | aca->aca_cstamp = aca->aca_tstamp = jiffies; | ||
287 | atomic_set(&aca->aca_refcnt, 2); | ||
288 | spin_lock_init(&aca->aca_lock); | ||
289 | 279 | ||
290 | aca->aca_next = idev->ac_list; | 280 | aca->aca_next = idev->ac_list; |
291 | idev->ac_list = aca; | 281 | idev->ac_list = aca; |
282 | |||
283 | /* Hold this for addrconf_join_solict() below before we unlock, | ||
284 | * it is already exposed via idev->ac_list. | ||
285 | */ | ||
286 | aca_get(aca); | ||
292 | write_unlock_bh(&idev->lock); | 287 | write_unlock_bh(&idev->lock); |
293 | 288 | ||
294 | ip6_ins_rt(rt); | 289 | ip6_ins_rt(rt); |
295 | 290 | ||
296 | addrconf_join_solict(dev, &aca->aca_addr); | 291 | addrconf_join_solict(idev->dev, &aca->aca_addr); |
297 | 292 | ||
298 | aca_put(aca); | 293 | aca_put(aca); |
299 | return 0; | 294 | return 0; |
300 | out: | 295 | out: |
301 | write_unlock_bh(&idev->lock); | 296 | write_unlock_bh(&idev->lock); |
302 | in6_dev_put(idev); | ||
303 | return err; | 297 | return err; |
304 | } | 298 | } |
305 | 299 | ||
@@ -341,7 +335,7 @@ int __ipv6_dev_ac_dec(struct inet6_dev *idev, const struct in6_addr *addr) | |||
341 | return 0; | 335 | return 0; |
342 | } | 336 | } |
343 | 337 | ||
344 | /* called with rcu_read_lock() */ | 338 | /* called with rtnl_lock() */ |
345 | static int ipv6_dev_ac_dec(struct net_device *dev, const struct in6_addr *addr) | 339 | static int ipv6_dev_ac_dec(struct net_device *dev, const struct in6_addr *addr) |
346 | { | 340 | { |
347 | struct inet6_dev *idev = __in6_dev_get(dev); | 341 | struct inet6_dev *idev = __in6_dev_get(dev); |
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index 2753319524f1..2cdc38338be3 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c | |||
@@ -43,13 +43,13 @@ static bool ipv6_mapped_addr_any(const struct in6_addr *a) | |||
43 | int ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) | 43 | int ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) |
44 | { | 44 | { |
45 | struct sockaddr_in6 *usin = (struct sockaddr_in6 *) uaddr; | 45 | struct sockaddr_in6 *usin = (struct sockaddr_in6 *) uaddr; |
46 | struct inet_sock *inet = inet_sk(sk); | 46 | struct inet_sock *inet = inet_sk(sk); |
47 | struct ipv6_pinfo *np = inet6_sk(sk); | 47 | struct ipv6_pinfo *np = inet6_sk(sk); |
48 | struct in6_addr *daddr, *final_p, final; | 48 | struct in6_addr *daddr, *final_p, final; |
49 | struct dst_entry *dst; | 49 | struct dst_entry *dst; |
50 | struct flowi6 fl6; | 50 | struct flowi6 fl6; |
51 | struct ip6_flowlabel *flowlabel = NULL; | 51 | struct ip6_flowlabel *flowlabel = NULL; |
52 | struct ipv6_txoptions *opt; | 52 | struct ipv6_txoptions *opt; |
53 | int addr_type; | 53 | int addr_type; |
54 | int err; | 54 | int err; |
55 | 55 | ||
@@ -332,7 +332,7 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len) | |||
332 | { | 332 | { |
333 | struct ipv6_pinfo *np = inet6_sk(sk); | 333 | struct ipv6_pinfo *np = inet6_sk(sk); |
334 | struct sock_exterr_skb *serr; | 334 | struct sock_exterr_skb *serr; |
335 | struct sk_buff *skb, *skb2; | 335 | struct sk_buff *skb; |
336 | DECLARE_SOCKADDR(struct sockaddr_in6 *, sin, msg->msg_name); | 336 | DECLARE_SOCKADDR(struct sockaddr_in6 *, sin, msg->msg_name); |
337 | struct { | 337 | struct { |
338 | struct sock_extended_err ee; | 338 | struct sock_extended_err ee; |
@@ -342,7 +342,7 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len) | |||
342 | int copied; | 342 | int copied; |
343 | 343 | ||
344 | err = -EAGAIN; | 344 | err = -EAGAIN; |
345 | skb = skb_dequeue(&sk->sk_error_queue); | 345 | skb = sock_dequeue_err_skb(sk); |
346 | if (skb == NULL) | 346 | if (skb == NULL) |
347 | goto out; | 347 | goto out; |
348 | 348 | ||
@@ -415,17 +415,6 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len) | |||
415 | msg->msg_flags |= MSG_ERRQUEUE; | 415 | msg->msg_flags |= MSG_ERRQUEUE; |
416 | err = copied; | 416 | err = copied; |
417 | 417 | ||
418 | /* Reset and regenerate socket error */ | ||
419 | spin_lock_bh(&sk->sk_error_queue.lock); | ||
420 | sk->sk_err = 0; | ||
421 | if ((skb2 = skb_peek(&sk->sk_error_queue)) != NULL) { | ||
422 | sk->sk_err = SKB_EXT_ERR(skb2)->ee.ee_errno; | ||
423 | spin_unlock_bh(&sk->sk_error_queue.lock); | ||
424 | sk->sk_error_report(sk); | ||
425 | } else { | ||
426 | spin_unlock_bh(&sk->sk_error_queue.lock); | ||
427 | } | ||
428 | |||
429 | out_free_skb: | 418 | out_free_skb: |
430 | kfree_skb(skb); | 419 | kfree_skb(skb); |
431 | out: | 420 | out: |
diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c index d15da1377149..83fc3a385a26 100644 --- a/net/ipv6/esp6.c +++ b/net/ipv6/esp6.c | |||
@@ -17,10 +17,10 @@ | |||
17 | * Authors | 17 | * Authors |
18 | * | 18 | * |
19 | * Mitsuru KANDA @USAGI : IPv6 Support | 19 | * Mitsuru KANDA @USAGI : IPv6 Support |
20 | * Kazunori MIYAZAWA @USAGI : | 20 | * Kazunori MIYAZAWA @USAGI : |
21 | * Kunihiro Ishiguro <kunihiro@ipinfusion.com> | 21 | * Kunihiro Ishiguro <kunihiro@ipinfusion.com> |
22 | * | 22 | * |
23 | * This file is derived from net/ipv4/esp.c | 23 | * This file is derived from net/ipv4/esp.c |
24 | */ | 24 | */ |
25 | 25 | ||
26 | #define pr_fmt(fmt) "IPv6: " fmt | 26 | #define pr_fmt(fmt) "IPv6: " fmt |
@@ -598,7 +598,7 @@ static int esp6_init_state(struct xfrm_state *x) | |||
598 | case XFRM_MODE_BEET: | 598 | case XFRM_MODE_BEET: |
599 | if (x->sel.family != AF_INET6) | 599 | if (x->sel.family != AF_INET6) |
600 | x->props.header_len += IPV4_BEET_PHMAXLEN + | 600 | x->props.header_len += IPV4_BEET_PHMAXLEN + |
601 | (sizeof(struct ipv6hdr) - sizeof(struct iphdr)); | 601 | (sizeof(struct ipv6hdr) - sizeof(struct iphdr)); |
602 | break; | 602 | break; |
603 | case XFRM_MODE_TRANSPORT: | 603 | case XFRM_MODE_TRANSPORT: |
604 | break; | 604 | break; |
@@ -621,11 +621,10 @@ static int esp6_rcv_cb(struct sk_buff *skb, int err) | |||
621 | return 0; | 621 | return 0; |
622 | } | 622 | } |
623 | 623 | ||
624 | static const struct xfrm_type esp6_type = | 624 | static const struct xfrm_type esp6_type = { |
625 | { | ||
626 | .description = "ESP6", | 625 | .description = "ESP6", |
627 | .owner = THIS_MODULE, | 626 | .owner = THIS_MODULE, |
628 | .proto = IPPROTO_ESP, | 627 | .proto = IPPROTO_ESP, |
629 | .flags = XFRM_TYPE_REPLAY_PROT, | 628 | .flags = XFRM_TYPE_REPLAY_PROT, |
630 | .init_state = esp6_init_state, | 629 | .init_state = esp6_init_state, |
631 | .destructor = esp6_destroy, | 630 | .destructor = esp6_destroy, |
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c index 8d67900aa003..bfde361b6134 100644 --- a/net/ipv6/exthdrs.c +++ b/net/ipv6/exthdrs.c | |||
@@ -142,7 +142,7 @@ static bool ip6_parse_tlv(const struct tlvtype_proc *procs, struct sk_buff *skb) | |||
142 | default: /* Other TLV code so scan list */ | 142 | default: /* Other TLV code so scan list */ |
143 | if (optlen > len) | 143 | if (optlen > len) |
144 | goto bad; | 144 | goto bad; |
145 | for (curr=procs; curr->type >= 0; curr++) { | 145 | for (curr = procs; curr->type >= 0; curr++) { |
146 | if (curr->type == nh[off]) { | 146 | if (curr->type == nh[off]) { |
147 | /* type specific length/alignment | 147 | /* type specific length/alignment |
148 | checks will be performed in the | 148 | checks will be performed in the |
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 06ba3e58320b..97ae70077a4f 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c | |||
@@ -170,11 +170,11 @@ static bool is_ineligible(const struct sk_buff *skb) | |||
170 | /* | 170 | /* |
171 | * Check the ICMP output rate limit | 171 | * Check the ICMP output rate limit |
172 | */ | 172 | */ |
173 | static inline bool icmpv6_xrlim_allow(struct sock *sk, u8 type, | 173 | static bool icmpv6_xrlim_allow(struct sock *sk, u8 type, |
174 | struct flowi6 *fl6) | 174 | struct flowi6 *fl6) |
175 | { | 175 | { |
176 | struct dst_entry *dst; | ||
177 | struct net *net = sock_net(sk); | 176 | struct net *net = sock_net(sk); |
177 | struct dst_entry *dst; | ||
178 | bool res = false; | 178 | bool res = false; |
179 | 179 | ||
180 | /* Informational messages are not limited. */ | 180 | /* Informational messages are not limited. */ |
@@ -199,16 +199,20 @@ static inline bool icmpv6_xrlim_allow(struct sock *sk, u8 type, | |||
199 | } else { | 199 | } else { |
200 | struct rt6_info *rt = (struct rt6_info *)dst; | 200 | struct rt6_info *rt = (struct rt6_info *)dst; |
201 | int tmo = net->ipv6.sysctl.icmpv6_time; | 201 | int tmo = net->ipv6.sysctl.icmpv6_time; |
202 | struct inet_peer *peer; | ||
203 | 202 | ||
204 | /* Give more bandwidth to wider prefixes. */ | 203 | /* Give more bandwidth to wider prefixes. */ |
205 | if (rt->rt6i_dst.plen < 128) | 204 | if (rt->rt6i_dst.plen < 128) |
206 | tmo >>= ((128 - rt->rt6i_dst.plen)>>5); | 205 | tmo >>= ((128 - rt->rt6i_dst.plen)>>5); |
207 | 206 | ||
208 | peer = inet_getpeer_v6(net->ipv6.peers, &rt->rt6i_dst.addr, 1); | 207 | if (icmp_global_allow()) { |
209 | res = inet_peer_xrlim_allow(peer, tmo); | 208 | struct inet_peer *peer; |
210 | if (peer) | 209 | |
211 | inet_putpeer(peer); | 210 | peer = inet_getpeer_v6(net->ipv6.peers, |
211 | &rt->rt6i_dst.addr, 1); | ||
212 | res = inet_peer_xrlim_allow(peer, tmo); | ||
213 | if (peer) | ||
214 | inet_putpeer(peer); | ||
215 | } | ||
212 | } | 216 | } |
213 | dst_release(dst); | 217 | dst_release(dst); |
214 | return res; | 218 | return res; |
@@ -503,7 +507,7 @@ static void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info) | |||
503 | msg.type = type; | 507 | msg.type = type; |
504 | 508 | ||
505 | len = skb->len - msg.offset; | 509 | len = skb->len - msg.offset; |
506 | len = min_t(unsigned int, len, IPV6_MIN_MTU - sizeof(struct ipv6hdr) -sizeof(struct icmp6hdr)); | 510 | len = min_t(unsigned int, len, IPV6_MIN_MTU - sizeof(struct ipv6hdr) - sizeof(struct icmp6hdr)); |
507 | if (len < 0) { | 511 | if (len < 0) { |
508 | LIMIT_NETDEBUG(KERN_DEBUG "icmp: len problem\n"); | 512 | LIMIT_NETDEBUG(KERN_DEBUG "icmp: len problem\n"); |
509 | goto out_dst_release; | 513 | goto out_dst_release; |
@@ -636,7 +640,7 @@ void icmpv6_notify(struct sk_buff *skb, u8 type, u8 code, __be32 info) | |||
636 | /* now skip over extension headers */ | 640 | /* now skip over extension headers */ |
637 | inner_offset = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), | 641 | inner_offset = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), |
638 | &nexthdr, &frag_off); | 642 | &nexthdr, &frag_off); |
639 | if (inner_offset<0) | 643 | if (inner_offset < 0) |
640 | goto out; | 644 | goto out; |
641 | } else { | 645 | } else { |
642 | inner_offset = sizeof(struct ipv6hdr); | 646 | inner_offset = sizeof(struct ipv6hdr); |
@@ -773,12 +777,12 @@ static int icmpv6_rcv(struct sk_buff *skb) | |||
773 | break; | 777 | break; |
774 | 778 | ||
775 | default: | 779 | default: |
776 | LIMIT_NETDEBUG(KERN_DEBUG "icmpv6: msg of unknown type\n"); | ||
777 | |||
778 | /* informational */ | 780 | /* informational */ |
779 | if (type & ICMPV6_INFOMSG_MASK) | 781 | if (type & ICMPV6_INFOMSG_MASK) |
780 | break; | 782 | break; |
781 | 783 | ||
784 | LIMIT_NETDEBUG(KERN_DEBUG "icmpv6: msg of unknown type\n"); | ||
785 | |||
782 | /* | 786 | /* |
783 | * error of unknown type. | 787 | * error of unknown type. |
784 | * must pass to upper level | 788 | * must pass to upper level |
@@ -808,7 +812,7 @@ void icmpv6_flow_init(struct sock *sk, struct flowi6 *fl6, | |||
808 | memset(fl6, 0, sizeof(*fl6)); | 812 | memset(fl6, 0, sizeof(*fl6)); |
809 | fl6->saddr = *saddr; | 813 | fl6->saddr = *saddr; |
810 | fl6->daddr = *daddr; | 814 | fl6->daddr = *daddr; |
811 | fl6->flowi6_proto = IPPROTO_ICMPV6; | 815 | fl6->flowi6_proto = IPPROTO_ICMPV6; |
812 | fl6->fl6_icmp_type = type; | 816 | fl6->fl6_icmp_type = type; |
813 | fl6->fl6_icmp_code = 0; | 817 | fl6->fl6_icmp_code = 0; |
814 | fl6->flowi6_oif = oif; | 818 | fl6->flowi6_oif = oif; |
@@ -875,8 +879,8 @@ static void __net_exit icmpv6_sk_exit(struct net *net) | |||
875 | } | 879 | } |
876 | 880 | ||
877 | static struct pernet_operations icmpv6_sk_ops = { | 881 | static struct pernet_operations icmpv6_sk_ops = { |
878 | .init = icmpv6_sk_init, | 882 | .init = icmpv6_sk_init, |
879 | .exit = icmpv6_sk_exit, | 883 | .exit = icmpv6_sk_exit, |
880 | }; | 884 | }; |
881 | 885 | ||
882 | int __init icmpv6_init(void) | 886 | int __init icmpv6_init(void) |
diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c index a245e5ddffbd..29b32206e494 100644 --- a/net/ipv6/inet6_connection_sock.c +++ b/net/ipv6/inet6_connection_sock.c | |||
@@ -63,7 +63,6 @@ int inet6_csk_bind_conflict(const struct sock *sk, | |||
63 | 63 | ||
64 | return sk2 != NULL; | 64 | return sk2 != NULL; |
65 | } | 65 | } |
66 | |||
67 | EXPORT_SYMBOL_GPL(inet6_csk_bind_conflict); | 66 | EXPORT_SYMBOL_GPL(inet6_csk_bind_conflict); |
68 | 67 | ||
69 | struct dst_entry *inet6_csk_route_req(struct sock *sk, | 68 | struct dst_entry *inet6_csk_route_req(struct sock *sk, |
@@ -144,7 +143,6 @@ struct request_sock *inet6_csk_search_req(const struct sock *sk, | |||
144 | 143 | ||
145 | return NULL; | 144 | return NULL; |
146 | } | 145 | } |
147 | |||
148 | EXPORT_SYMBOL_GPL(inet6_csk_search_req); | 146 | EXPORT_SYMBOL_GPL(inet6_csk_search_req); |
149 | 147 | ||
150 | void inet6_csk_reqsk_queue_hash_add(struct sock *sk, | 148 | void inet6_csk_reqsk_queue_hash_add(struct sock *sk, |
@@ -160,10 +158,9 @@ void inet6_csk_reqsk_queue_hash_add(struct sock *sk, | |||
160 | reqsk_queue_hash_req(&icsk->icsk_accept_queue, h, req, timeout); | 158 | reqsk_queue_hash_req(&icsk->icsk_accept_queue, h, req, timeout); |
161 | inet_csk_reqsk_queue_added(sk, timeout); | 159 | inet_csk_reqsk_queue_added(sk, timeout); |
162 | } | 160 | } |
163 | |||
164 | EXPORT_SYMBOL_GPL(inet6_csk_reqsk_queue_hash_add); | 161 | EXPORT_SYMBOL_GPL(inet6_csk_reqsk_queue_hash_add); |
165 | 162 | ||
166 | void inet6_csk_addr2sockaddr(struct sock *sk, struct sockaddr * uaddr) | 163 | void inet6_csk_addr2sockaddr(struct sock *sk, struct sockaddr *uaddr) |
167 | { | 164 | { |
168 | struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) uaddr; | 165 | struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) uaddr; |
169 | 166 | ||
@@ -175,7 +172,6 @@ void inet6_csk_addr2sockaddr(struct sock *sk, struct sockaddr * uaddr) | |||
175 | sin6->sin6_scope_id = ipv6_iface_scope_id(&sin6->sin6_addr, | 172 | sin6->sin6_scope_id = ipv6_iface_scope_id(&sin6->sin6_addr, |
176 | sk->sk_bound_dev_if); | 173 | sk->sk_bound_dev_if); |
177 | } | 174 | } |
178 | |||
179 | EXPORT_SYMBOL_GPL(inet6_csk_addr2sockaddr); | 175 | EXPORT_SYMBOL_GPL(inet6_csk_addr2sockaddr); |
180 | 176 | ||
181 | static inline | 177 | static inline |
diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c index 262e13c02ec2..051dffb49c90 100644 --- a/net/ipv6/inet6_hashtables.c +++ b/net/ipv6/inet6_hashtables.c | |||
@@ -6,7 +6,7 @@ | |||
6 | * Generic INET6 transport hashtables | 6 | * Generic INET6 transport hashtables |
7 | * | 7 | * |
8 | * Authors: Lotsa people, from code originally in tcp, generalised here | 8 | * Authors: Lotsa people, from code originally in tcp, generalised here |
9 | * by Arnaldo Carvalho de Melo <acme@mandriva.com> | 9 | * by Arnaldo Carvalho de Melo <acme@mandriva.com> |
10 | * | 10 | * |
11 | * This program is free software; you can redistribute it and/or | 11 | * This program is free software; you can redistribute it and/or |
12 | * modify it under the terms of the GNU General Public License | 12 | * modify it under the terms of the GNU General Public License |
@@ -198,7 +198,7 @@ begin: | |||
198 | } | 198 | } |
199 | } else if (score == hiscore && reuseport) { | 199 | } else if (score == hiscore && reuseport) { |
200 | matches++; | 200 | matches++; |
201 | if (((u64)phash * matches) >> 32 == 0) | 201 | if (reciprocal_scale(phash, matches) == 0) |
202 | result = sk; | 202 | result = sk; |
203 | phash = next_pseudo_random32(phash); | 203 | phash = next_pseudo_random32(phash); |
204 | } | 204 | } |
@@ -222,7 +222,6 @@ begin: | |||
222 | rcu_read_unlock(); | 222 | rcu_read_unlock(); |
223 | return result; | 223 | return result; |
224 | } | 224 | } |
225 | |||
226 | EXPORT_SYMBOL_GPL(inet6_lookup_listener); | 225 | EXPORT_SYMBOL_GPL(inet6_lookup_listener); |
227 | 226 | ||
228 | struct sock *inet6_lookup(struct net *net, struct inet_hashinfo *hashinfo, | 227 | struct sock *inet6_lookup(struct net *net, struct inet_hashinfo *hashinfo, |
@@ -238,7 +237,6 @@ struct sock *inet6_lookup(struct net *net, struct inet_hashinfo *hashinfo, | |||
238 | 237 | ||
239 | return sk; | 238 | return sk; |
240 | } | 239 | } |
241 | |||
242 | EXPORT_SYMBOL_GPL(inet6_lookup); | 240 | EXPORT_SYMBOL_GPL(inet6_lookup); |
243 | 241 | ||
244 | static int __inet6_check_established(struct inet_timewait_death_row *death_row, | 242 | static int __inet6_check_established(struct inet_timewait_death_row *death_row, |
@@ -324,5 +322,4 @@ int inet6_hash_connect(struct inet_timewait_death_row *death_row, | |||
324 | return __inet_hash_connect(death_row, sk, inet6_sk_port_offset(sk), | 322 | return __inet_hash_connect(death_row, sk, inet6_sk_port_offset(sk), |
325 | __inet6_check_established, __inet6_hash); | 323 | __inet6_check_established, __inet6_hash); |
326 | } | 324 | } |
327 | |||
328 | EXPORT_SYMBOL_GPL(inet6_hash_connect); | 325 | EXPORT_SYMBOL_GPL(inet6_hash_connect); |
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 97b9fa8de377..b2d1838897c9 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c | |||
@@ -46,20 +46,11 @@ | |||
46 | 46 | ||
47 | static struct kmem_cache *fib6_node_kmem __read_mostly; | 47 | static struct kmem_cache *fib6_node_kmem __read_mostly; |
48 | 48 | ||
49 | enum fib_walk_state_t { | 49 | struct fib6_cleaner { |
50 | #ifdef CONFIG_IPV6_SUBTREES | 50 | struct fib6_walker w; |
51 | FWS_S, | ||
52 | #endif | ||
53 | FWS_L, | ||
54 | FWS_R, | ||
55 | FWS_C, | ||
56 | FWS_U | ||
57 | }; | ||
58 | |||
59 | struct fib6_cleaner_t { | ||
60 | struct fib6_walker_t w; | ||
61 | struct net *net; | 51 | struct net *net; |
62 | int (*func)(struct rt6_info *, void *arg); | 52 | int (*func)(struct rt6_info *, void *arg); |
53 | int sernum; | ||
63 | void *arg; | 54 | void *arg; |
64 | }; | 55 | }; |
65 | 56 | ||
@@ -74,8 +65,8 @@ static DEFINE_RWLOCK(fib6_walker_lock); | |||
74 | static void fib6_prune_clones(struct net *net, struct fib6_node *fn); | 65 | static void fib6_prune_clones(struct net *net, struct fib6_node *fn); |
75 | static struct rt6_info *fib6_find_prefix(struct net *net, struct fib6_node *fn); | 66 | static struct rt6_info *fib6_find_prefix(struct net *net, struct fib6_node *fn); |
76 | static struct fib6_node *fib6_repair_tree(struct net *net, struct fib6_node *fn); | 67 | static struct fib6_node *fib6_repair_tree(struct net *net, struct fib6_node *fn); |
77 | static int fib6_walk(struct fib6_walker_t *w); | 68 | static int fib6_walk(struct fib6_walker *w); |
78 | static int fib6_walk_continue(struct fib6_walker_t *w); | 69 | static int fib6_walk_continue(struct fib6_walker *w); |
79 | 70 | ||
80 | /* | 71 | /* |
81 | * A routing update causes an increase of the serial number on the | 72 | * A routing update causes an increase of the serial number on the |
@@ -84,34 +75,41 @@ static int fib6_walk_continue(struct fib6_walker_t *w); | |||
84 | * result of redirects, path MTU changes, etc. | 75 | * result of redirects, path MTU changes, etc. |
85 | */ | 76 | */ |
86 | 77 | ||
87 | static __u32 rt_sernum; | ||
88 | |||
89 | static void fib6_gc_timer_cb(unsigned long arg); | 78 | static void fib6_gc_timer_cb(unsigned long arg); |
90 | 79 | ||
91 | static LIST_HEAD(fib6_walkers); | 80 | static LIST_HEAD(fib6_walkers); |
92 | #define FOR_WALKERS(w) list_for_each_entry(w, &fib6_walkers, lh) | 81 | #define FOR_WALKERS(w) list_for_each_entry(w, &fib6_walkers, lh) |
93 | 82 | ||
94 | static inline void fib6_walker_link(struct fib6_walker_t *w) | 83 | static void fib6_walker_link(struct fib6_walker *w) |
95 | { | 84 | { |
96 | write_lock_bh(&fib6_walker_lock); | 85 | write_lock_bh(&fib6_walker_lock); |
97 | list_add(&w->lh, &fib6_walkers); | 86 | list_add(&w->lh, &fib6_walkers); |
98 | write_unlock_bh(&fib6_walker_lock); | 87 | write_unlock_bh(&fib6_walker_lock); |
99 | } | 88 | } |
100 | 89 | ||
101 | static inline void fib6_walker_unlink(struct fib6_walker_t *w) | 90 | static void fib6_walker_unlink(struct fib6_walker *w) |
102 | { | 91 | { |
103 | write_lock_bh(&fib6_walker_lock); | 92 | write_lock_bh(&fib6_walker_lock); |
104 | list_del(&w->lh); | 93 | list_del(&w->lh); |
105 | write_unlock_bh(&fib6_walker_lock); | 94 | write_unlock_bh(&fib6_walker_lock); |
106 | } | 95 | } |
107 | static __inline__ u32 fib6_new_sernum(void) | 96 | |
97 | static int fib6_new_sernum(struct net *net) | ||
108 | { | 98 | { |
109 | u32 n = ++rt_sernum; | 99 | int new, old; |
110 | if ((__s32)n <= 0) | 100 | |
111 | rt_sernum = n = 1; | 101 | do { |
112 | return n; | 102 | old = atomic_read(&net->ipv6.fib6_sernum); |
103 | new = old < INT_MAX ? old + 1 : 1; | ||
104 | } while (atomic_cmpxchg(&net->ipv6.fib6_sernum, | ||
105 | old, new) != old); | ||
106 | return new; | ||
113 | } | 107 | } |
114 | 108 | ||
109 | enum { | ||
110 | FIB6_NO_SERNUM_CHANGE = 0, | ||
111 | }; | ||
112 | |||
115 | /* | 113 | /* |
116 | * Auxiliary address test functions for the radix tree. | 114 | * Auxiliary address test functions for the radix tree. |
117 | * | 115 | * |
@@ -128,7 +126,7 @@ static __inline__ u32 fib6_new_sernum(void) | |||
128 | # define BITOP_BE32_SWIZZLE 0 | 126 | # define BITOP_BE32_SWIZZLE 0 |
129 | #endif | 127 | #endif |
130 | 128 | ||
131 | static __inline__ __be32 addr_bit_set(const void *token, int fn_bit) | 129 | static __be32 addr_bit_set(const void *token, int fn_bit) |
132 | { | 130 | { |
133 | const __be32 *addr = token; | 131 | const __be32 *addr = token; |
134 | /* | 132 | /* |
@@ -142,7 +140,7 @@ static __inline__ __be32 addr_bit_set(const void *token, int fn_bit) | |||
142 | addr[fn_bit >> 5]; | 140 | addr[fn_bit >> 5]; |
143 | } | 141 | } |
144 | 142 | ||
145 | static __inline__ struct fib6_node *node_alloc(void) | 143 | static struct fib6_node *node_alloc(void) |
146 | { | 144 | { |
147 | struct fib6_node *fn; | 145 | struct fib6_node *fn; |
148 | 146 | ||
@@ -151,12 +149,12 @@ static __inline__ struct fib6_node *node_alloc(void) | |||
151 | return fn; | 149 | return fn; |
152 | } | 150 | } |
153 | 151 | ||
154 | static __inline__ void node_free(struct fib6_node *fn) | 152 | static void node_free(struct fib6_node *fn) |
155 | { | 153 | { |
156 | kmem_cache_free(fib6_node_kmem, fn); | 154 | kmem_cache_free(fib6_node_kmem, fn); |
157 | } | 155 | } |
158 | 156 | ||
159 | static __inline__ void rt6_release(struct rt6_info *rt) | 157 | static void rt6_release(struct rt6_info *rt) |
160 | { | 158 | { |
161 | if (atomic_dec_and_test(&rt->rt6i_ref)) | 159 | if (atomic_dec_and_test(&rt->rt6i_ref)) |
162 | dst_free(&rt->dst); | 160 | dst_free(&rt->dst); |
@@ -267,7 +265,7 @@ static void __net_init fib6_tables_init(struct net *net) | |||
267 | 265 | ||
268 | #endif | 266 | #endif |
269 | 267 | ||
270 | static int fib6_dump_node(struct fib6_walker_t *w) | 268 | static int fib6_dump_node(struct fib6_walker *w) |
271 | { | 269 | { |
272 | int res; | 270 | int res; |
273 | struct rt6_info *rt; | 271 | struct rt6_info *rt; |
@@ -287,7 +285,7 @@ static int fib6_dump_node(struct fib6_walker_t *w) | |||
287 | 285 | ||
288 | static void fib6_dump_end(struct netlink_callback *cb) | 286 | static void fib6_dump_end(struct netlink_callback *cb) |
289 | { | 287 | { |
290 | struct fib6_walker_t *w = (void *)cb->args[2]; | 288 | struct fib6_walker *w = (void *)cb->args[2]; |
291 | 289 | ||
292 | if (w) { | 290 | if (w) { |
293 | if (cb->args[4]) { | 291 | if (cb->args[4]) { |
@@ -310,7 +308,7 @@ static int fib6_dump_done(struct netlink_callback *cb) | |||
310 | static int fib6_dump_table(struct fib6_table *table, struct sk_buff *skb, | 308 | static int fib6_dump_table(struct fib6_table *table, struct sk_buff *skb, |
311 | struct netlink_callback *cb) | 309 | struct netlink_callback *cb) |
312 | { | 310 | { |
313 | struct fib6_walker_t *w; | 311 | struct fib6_walker *w; |
314 | int res; | 312 | int res; |
315 | 313 | ||
316 | w = (void *)cb->args[2]; | 314 | w = (void *)cb->args[2]; |
@@ -355,7 +353,7 @@ static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) | |||
355 | unsigned int h, s_h; | 353 | unsigned int h, s_h; |
356 | unsigned int e = 0, s_e; | 354 | unsigned int e = 0, s_e; |
357 | struct rt6_rtnl_dump_arg arg; | 355 | struct rt6_rtnl_dump_arg arg; |
358 | struct fib6_walker_t *w; | 356 | struct fib6_walker *w; |
359 | struct fib6_table *tb; | 357 | struct fib6_table *tb; |
360 | struct hlist_head *head; | 358 | struct hlist_head *head; |
361 | int res = 0; | 359 | int res = 0; |
@@ -423,14 +421,13 @@ out: | |||
423 | static struct fib6_node *fib6_add_1(struct fib6_node *root, | 421 | static struct fib6_node *fib6_add_1(struct fib6_node *root, |
424 | struct in6_addr *addr, int plen, | 422 | struct in6_addr *addr, int plen, |
425 | int offset, int allow_create, | 423 | int offset, int allow_create, |
426 | int replace_required) | 424 | int replace_required, int sernum) |
427 | { | 425 | { |
428 | struct fib6_node *fn, *in, *ln; | 426 | struct fib6_node *fn, *in, *ln; |
429 | struct fib6_node *pn = NULL; | 427 | struct fib6_node *pn = NULL; |
430 | struct rt6key *key; | 428 | struct rt6key *key; |
431 | int bit; | 429 | int bit; |
432 | __be32 dir = 0; | 430 | __be32 dir = 0; |
433 | __u32 sernum = fib6_new_sernum(); | ||
434 | 431 | ||
435 | RT6_TRACE("fib6_add_1\n"); | 432 | RT6_TRACE("fib6_add_1\n"); |
436 | 433 | ||
@@ -627,7 +624,7 @@ insert_above: | |||
627 | return ln; | 624 | return ln; |
628 | } | 625 | } |
629 | 626 | ||
630 | static inline bool rt6_qualify_for_ecmp(struct rt6_info *rt) | 627 | static bool rt6_qualify_for_ecmp(struct rt6_info *rt) |
631 | { | 628 | { |
632 | return (rt->rt6i_flags & (RTF_GATEWAY|RTF_ADDRCONF|RTF_DYNAMIC)) == | 629 | return (rt->rt6i_flags & (RTF_GATEWAY|RTF_ADDRCONF|RTF_DYNAMIC)) == |
633 | RTF_GATEWAY; | 630 | RTF_GATEWAY; |
@@ -820,7 +817,7 @@ add: | |||
820 | return 0; | 817 | return 0; |
821 | } | 818 | } |
822 | 819 | ||
823 | static __inline__ void fib6_start_gc(struct net *net, struct rt6_info *rt) | 820 | static void fib6_start_gc(struct net *net, struct rt6_info *rt) |
824 | { | 821 | { |
825 | if (!timer_pending(&net->ipv6.ip6_fib_timer) && | 822 | if (!timer_pending(&net->ipv6.ip6_fib_timer) && |
826 | (rt->rt6i_flags & (RTF_EXPIRES | RTF_CACHE))) | 823 | (rt->rt6i_flags & (RTF_EXPIRES | RTF_CACHE))) |
@@ -848,6 +845,7 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nl_info *info, | |||
848 | int err = -ENOMEM; | 845 | int err = -ENOMEM; |
849 | int allow_create = 1; | 846 | int allow_create = 1; |
850 | int replace_required = 0; | 847 | int replace_required = 0; |
848 | int sernum = fib6_new_sernum(info->nl_net); | ||
851 | 849 | ||
852 | if (info->nlh) { | 850 | if (info->nlh) { |
853 | if (!(info->nlh->nlmsg_flags & NLM_F_CREATE)) | 851 | if (!(info->nlh->nlmsg_flags & NLM_F_CREATE)) |
@@ -860,7 +858,7 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nl_info *info, | |||
860 | 858 | ||
861 | fn = fib6_add_1(root, &rt->rt6i_dst.addr, rt->rt6i_dst.plen, | 859 | fn = fib6_add_1(root, &rt->rt6i_dst.addr, rt->rt6i_dst.plen, |
862 | offsetof(struct rt6_info, rt6i_dst), allow_create, | 860 | offsetof(struct rt6_info, rt6i_dst), allow_create, |
863 | replace_required); | 861 | replace_required, sernum); |
864 | if (IS_ERR(fn)) { | 862 | if (IS_ERR(fn)) { |
865 | err = PTR_ERR(fn); | 863 | err = PTR_ERR(fn); |
866 | fn = NULL; | 864 | fn = NULL; |
@@ -894,14 +892,14 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nl_info *info, | |||
894 | sfn->leaf = info->nl_net->ipv6.ip6_null_entry; | 892 | sfn->leaf = info->nl_net->ipv6.ip6_null_entry; |
895 | atomic_inc(&info->nl_net->ipv6.ip6_null_entry->rt6i_ref); | 893 | atomic_inc(&info->nl_net->ipv6.ip6_null_entry->rt6i_ref); |
896 | sfn->fn_flags = RTN_ROOT; | 894 | sfn->fn_flags = RTN_ROOT; |
897 | sfn->fn_sernum = fib6_new_sernum(); | 895 | sfn->fn_sernum = sernum; |
898 | 896 | ||
899 | /* Now add the first leaf node to new subtree */ | 897 | /* Now add the first leaf node to new subtree */ |
900 | 898 | ||
901 | sn = fib6_add_1(sfn, &rt->rt6i_src.addr, | 899 | sn = fib6_add_1(sfn, &rt->rt6i_src.addr, |
902 | rt->rt6i_src.plen, | 900 | rt->rt6i_src.plen, |
903 | offsetof(struct rt6_info, rt6i_src), | 901 | offsetof(struct rt6_info, rt6i_src), |
904 | allow_create, replace_required); | 902 | allow_create, replace_required, sernum); |
905 | 903 | ||
906 | if (IS_ERR(sn)) { | 904 | if (IS_ERR(sn)) { |
907 | /* If it is failed, discard just allocated | 905 | /* If it is failed, discard just allocated |
@@ -920,7 +918,7 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nl_info *info, | |||
920 | sn = fib6_add_1(fn->subtree, &rt->rt6i_src.addr, | 918 | sn = fib6_add_1(fn->subtree, &rt->rt6i_src.addr, |
921 | rt->rt6i_src.plen, | 919 | rt->rt6i_src.plen, |
922 | offsetof(struct rt6_info, rt6i_src), | 920 | offsetof(struct rt6_info, rt6i_src), |
923 | allow_create, replace_required); | 921 | allow_create, replace_required, sernum); |
924 | 922 | ||
925 | if (IS_ERR(sn)) { | 923 | if (IS_ERR(sn)) { |
926 | err = PTR_ERR(sn); | 924 | err = PTR_ERR(sn); |
@@ -1174,7 +1172,7 @@ static struct fib6_node *fib6_repair_tree(struct net *net, | |||
1174 | int children; | 1172 | int children; |
1175 | int nstate; | 1173 | int nstate; |
1176 | struct fib6_node *child, *pn; | 1174 | struct fib6_node *child, *pn; |
1177 | struct fib6_walker_t *w; | 1175 | struct fib6_walker *w; |
1178 | int iter = 0; | 1176 | int iter = 0; |
1179 | 1177 | ||
1180 | for (;;) { | 1178 | for (;;) { |
@@ -1276,7 +1274,7 @@ static struct fib6_node *fib6_repair_tree(struct net *net, | |||
1276 | static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp, | 1274 | static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp, |
1277 | struct nl_info *info) | 1275 | struct nl_info *info) |
1278 | { | 1276 | { |
1279 | struct fib6_walker_t *w; | 1277 | struct fib6_walker *w; |
1280 | struct rt6_info *rt = *rtp; | 1278 | struct rt6_info *rt = *rtp; |
1281 | struct net *net = info->nl_net; | 1279 | struct net *net = info->nl_net; |
1282 | 1280 | ||
@@ -1414,7 +1412,7 @@ int fib6_del(struct rt6_info *rt, struct nl_info *info) | |||
1414 | * <0 -> walk is terminated by an error. | 1412 | * <0 -> walk is terminated by an error. |
1415 | */ | 1413 | */ |
1416 | 1414 | ||
1417 | static int fib6_walk_continue(struct fib6_walker_t *w) | 1415 | static int fib6_walk_continue(struct fib6_walker *w) |
1418 | { | 1416 | { |
1419 | struct fib6_node *fn, *pn; | 1417 | struct fib6_node *fn, *pn; |
1420 | 1418 | ||
@@ -1498,7 +1496,7 @@ skip: | |||
1498 | } | 1496 | } |
1499 | } | 1497 | } |
1500 | 1498 | ||
1501 | static int fib6_walk(struct fib6_walker_t *w) | 1499 | static int fib6_walk(struct fib6_walker *w) |
1502 | { | 1500 | { |
1503 | int res; | 1501 | int res; |
1504 | 1502 | ||
@@ -1512,15 +1510,25 @@ static int fib6_walk(struct fib6_walker_t *w) | |||
1512 | return res; | 1510 | return res; |
1513 | } | 1511 | } |
1514 | 1512 | ||
1515 | static int fib6_clean_node(struct fib6_walker_t *w) | 1513 | static int fib6_clean_node(struct fib6_walker *w) |
1516 | { | 1514 | { |
1517 | int res; | 1515 | int res; |
1518 | struct rt6_info *rt; | 1516 | struct rt6_info *rt; |
1519 | struct fib6_cleaner_t *c = container_of(w, struct fib6_cleaner_t, w); | 1517 | struct fib6_cleaner *c = container_of(w, struct fib6_cleaner, w); |
1520 | struct nl_info info = { | 1518 | struct nl_info info = { |
1521 | .nl_net = c->net, | 1519 | .nl_net = c->net, |
1522 | }; | 1520 | }; |
1523 | 1521 | ||
1522 | if (c->sernum != FIB6_NO_SERNUM_CHANGE && | ||
1523 | w->node->fn_sernum != c->sernum) | ||
1524 | w->node->fn_sernum = c->sernum; | ||
1525 | |||
1526 | if (!c->func) { | ||
1527 | WARN_ON_ONCE(c->sernum == FIB6_NO_SERNUM_CHANGE); | ||
1528 | w->leaf = NULL; | ||
1529 | return 0; | ||
1530 | } | ||
1531 | |||
1524 | for (rt = w->leaf; rt; rt = rt->dst.rt6_next) { | 1532 | for (rt = w->leaf; rt; rt = rt->dst.rt6_next) { |
1525 | res = c->func(rt, c->arg); | 1533 | res = c->func(rt, c->arg); |
1526 | if (res < 0) { | 1534 | if (res < 0) { |
@@ -1554,9 +1562,9 @@ static int fib6_clean_node(struct fib6_walker_t *w) | |||
1554 | 1562 | ||
1555 | static void fib6_clean_tree(struct net *net, struct fib6_node *root, | 1563 | static void fib6_clean_tree(struct net *net, struct fib6_node *root, |
1556 | int (*func)(struct rt6_info *, void *arg), | 1564 | int (*func)(struct rt6_info *, void *arg), |
1557 | int prune, void *arg) | 1565 | bool prune, int sernum, void *arg) |
1558 | { | 1566 | { |
1559 | struct fib6_cleaner_t c; | 1567 | struct fib6_cleaner c; |
1560 | 1568 | ||
1561 | c.w.root = root; | 1569 | c.w.root = root; |
1562 | c.w.func = fib6_clean_node; | 1570 | c.w.func = fib6_clean_node; |
@@ -1564,14 +1572,16 @@ static void fib6_clean_tree(struct net *net, struct fib6_node *root, | |||
1564 | c.w.count = 0; | 1572 | c.w.count = 0; |
1565 | c.w.skip = 0; | 1573 | c.w.skip = 0; |
1566 | c.func = func; | 1574 | c.func = func; |
1575 | c.sernum = sernum; | ||
1567 | c.arg = arg; | 1576 | c.arg = arg; |
1568 | c.net = net; | 1577 | c.net = net; |
1569 | 1578 | ||
1570 | fib6_walk(&c.w); | 1579 | fib6_walk(&c.w); |
1571 | } | 1580 | } |
1572 | 1581 | ||
1573 | void fib6_clean_all(struct net *net, int (*func)(struct rt6_info *, void *arg), | 1582 | static void __fib6_clean_all(struct net *net, |
1574 | void *arg) | 1583 | int (*func)(struct rt6_info *, void *), |
1584 | int sernum, void *arg) | ||
1575 | { | 1585 | { |
1576 | struct fib6_table *table; | 1586 | struct fib6_table *table; |
1577 | struct hlist_head *head; | 1587 | struct hlist_head *head; |
@@ -1583,13 +1593,19 @@ void fib6_clean_all(struct net *net, int (*func)(struct rt6_info *, void *arg), | |||
1583 | hlist_for_each_entry_rcu(table, head, tb6_hlist) { | 1593 | hlist_for_each_entry_rcu(table, head, tb6_hlist) { |
1584 | write_lock_bh(&table->tb6_lock); | 1594 | write_lock_bh(&table->tb6_lock); |
1585 | fib6_clean_tree(net, &table->tb6_root, | 1595 | fib6_clean_tree(net, &table->tb6_root, |
1586 | func, 0, arg); | 1596 | func, false, sernum, arg); |
1587 | write_unlock_bh(&table->tb6_lock); | 1597 | write_unlock_bh(&table->tb6_lock); |
1588 | } | 1598 | } |
1589 | } | 1599 | } |
1590 | rcu_read_unlock(); | 1600 | rcu_read_unlock(); |
1591 | } | 1601 | } |
1592 | 1602 | ||
1603 | void fib6_clean_all(struct net *net, int (*func)(struct rt6_info *, void *), | ||
1604 | void *arg) | ||
1605 | { | ||
1606 | __fib6_clean_all(net, func, FIB6_NO_SERNUM_CHANGE, arg); | ||
1607 | } | ||
1608 | |||
1593 | static int fib6_prune_clone(struct rt6_info *rt, void *arg) | 1609 | static int fib6_prune_clone(struct rt6_info *rt, void *arg) |
1594 | { | 1610 | { |
1595 | if (rt->rt6i_flags & RTF_CACHE) { | 1611 | if (rt->rt6i_flags & RTF_CACHE) { |
@@ -1602,25 +1618,15 @@ static int fib6_prune_clone(struct rt6_info *rt, void *arg) | |||
1602 | 1618 | ||
1603 | static void fib6_prune_clones(struct net *net, struct fib6_node *fn) | 1619 | static void fib6_prune_clones(struct net *net, struct fib6_node *fn) |
1604 | { | 1620 | { |
1605 | fib6_clean_tree(net, fn, fib6_prune_clone, 1, NULL); | 1621 | fib6_clean_tree(net, fn, fib6_prune_clone, true, |
1606 | } | 1622 | FIB6_NO_SERNUM_CHANGE, NULL); |
1607 | |||
1608 | static int fib6_update_sernum(struct rt6_info *rt, void *arg) | ||
1609 | { | ||
1610 | __u32 sernum = *(__u32 *)arg; | ||
1611 | |||
1612 | if (rt->rt6i_node && | ||
1613 | rt->rt6i_node->fn_sernum != sernum) | ||
1614 | rt->rt6i_node->fn_sernum = sernum; | ||
1615 | |||
1616 | return 0; | ||
1617 | } | 1623 | } |
1618 | 1624 | ||
1619 | static void fib6_flush_trees(struct net *net) | 1625 | static void fib6_flush_trees(struct net *net) |
1620 | { | 1626 | { |
1621 | __u32 new_sernum = fib6_new_sernum(); | 1627 | int new_sernum = fib6_new_sernum(net); |
1622 | 1628 | ||
1623 | fib6_clean_all(net, fib6_update_sernum, &new_sernum); | 1629 | __fib6_clean_all(net, NULL, new_sernum, NULL); |
1624 | } | 1630 | } |
1625 | 1631 | ||
1626 | /* | 1632 | /* |
@@ -1828,10 +1834,10 @@ void fib6_gc_cleanup(void) | |||
1828 | 1834 | ||
1829 | struct ipv6_route_iter { | 1835 | struct ipv6_route_iter { |
1830 | struct seq_net_private p; | 1836 | struct seq_net_private p; |
1831 | struct fib6_walker_t w; | 1837 | struct fib6_walker w; |
1832 | loff_t skip; | 1838 | loff_t skip; |
1833 | struct fib6_table *tbl; | 1839 | struct fib6_table *tbl; |
1834 | __u32 sernum; | 1840 | int sernum; |
1835 | }; | 1841 | }; |
1836 | 1842 | ||
1837 | static int ipv6_route_seq_show(struct seq_file *seq, void *v) | 1843 | static int ipv6_route_seq_show(struct seq_file *seq, void *v) |
@@ -1859,7 +1865,7 @@ static int ipv6_route_seq_show(struct seq_file *seq, void *v) | |||
1859 | return 0; | 1865 | return 0; |
1860 | } | 1866 | } |
1861 | 1867 | ||
1862 | static int ipv6_route_yield(struct fib6_walker_t *w) | 1868 | static int ipv6_route_yield(struct fib6_walker *w) |
1863 | { | 1869 | { |
1864 | struct ipv6_route_iter *iter = w->args; | 1870 | struct ipv6_route_iter *iter = w->args; |
1865 | 1871 | ||
@@ -1980,7 +1986,7 @@ static void *ipv6_route_seq_start(struct seq_file *seq, loff_t *pos) | |||
1980 | 1986 | ||
1981 | static bool ipv6_route_iter_active(struct ipv6_route_iter *iter) | 1987 | static bool ipv6_route_iter_active(struct ipv6_route_iter *iter) |
1982 | { | 1988 | { |
1983 | struct fib6_walker_t *w = &iter->w; | 1989 | struct fib6_walker *w = &iter->w; |
1984 | return w->node && !(w->state == FWS_U && w->node == w->root); | 1990 | return w->node && !(w->state == FWS_U && w->node == w->root); |
1985 | } | 1991 | } |
1986 | 1992 | ||
diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c index 4052694c6f2c..3dd7d4ebd7cd 100644 --- a/net/ipv6/ip6_flowlabel.c +++ b/net/ipv6/ip6_flowlabel.c | |||
@@ -136,7 +136,7 @@ static void ip6_fl_gc(unsigned long dummy) | |||
136 | 136 | ||
137 | spin_lock(&ip6_fl_lock); | 137 | spin_lock(&ip6_fl_lock); |
138 | 138 | ||
139 | for (i=0; i<=FL_HASH_MASK; i++) { | 139 | for (i = 0; i <= FL_HASH_MASK; i++) { |
140 | struct ip6_flowlabel *fl; | 140 | struct ip6_flowlabel *fl; |
141 | struct ip6_flowlabel __rcu **flp; | 141 | struct ip6_flowlabel __rcu **flp; |
142 | 142 | ||
@@ -239,7 +239,7 @@ static struct ip6_flowlabel *fl_intern(struct net *net, | |||
239 | 239 | ||
240 | /* Socket flowlabel lists */ | 240 | /* Socket flowlabel lists */ |
241 | 241 | ||
242 | struct ip6_flowlabel * fl6_sock_lookup(struct sock *sk, __be32 label) | 242 | struct ip6_flowlabel *fl6_sock_lookup(struct sock *sk, __be32 label) |
243 | { | 243 | { |
244 | struct ipv6_fl_socklist *sfl; | 244 | struct ipv6_fl_socklist *sfl; |
245 | struct ipv6_pinfo *np = inet6_sk(sk); | 245 | struct ipv6_pinfo *np = inet6_sk(sk); |
@@ -259,7 +259,6 @@ struct ip6_flowlabel * fl6_sock_lookup(struct sock *sk, __be32 label) | |||
259 | rcu_read_unlock_bh(); | 259 | rcu_read_unlock_bh(); |
260 | return NULL; | 260 | return NULL; |
261 | } | 261 | } |
262 | |||
263 | EXPORT_SYMBOL_GPL(fl6_sock_lookup); | 262 | EXPORT_SYMBOL_GPL(fl6_sock_lookup); |
264 | 263 | ||
265 | void fl6_free_socklist(struct sock *sk) | 264 | void fl6_free_socklist(struct sock *sk) |
@@ -293,11 +292,11 @@ void fl6_free_socklist(struct sock *sk) | |||
293 | following rthdr. | 292 | following rthdr. |
294 | */ | 293 | */ |
295 | 294 | ||
296 | struct ipv6_txoptions *fl6_merge_options(struct ipv6_txoptions * opt_space, | 295 | struct ipv6_txoptions *fl6_merge_options(struct ipv6_txoptions *opt_space, |
297 | struct ip6_flowlabel * fl, | 296 | struct ip6_flowlabel *fl, |
298 | struct ipv6_txoptions * fopt) | 297 | struct ipv6_txoptions *fopt) |
299 | { | 298 | { |
300 | struct ipv6_txoptions * fl_opt = fl->opt; | 299 | struct ipv6_txoptions *fl_opt = fl->opt; |
301 | 300 | ||
302 | if (fopt == NULL || fopt->opt_flen == 0) | 301 | if (fopt == NULL || fopt->opt_flen == 0) |
303 | return fl_opt; | 302 | return fl_opt; |
@@ -388,7 +387,7 @@ fl_create(struct net *net, struct sock *sk, struct in6_flowlabel_req *freq, | |||
388 | goto done; | 387 | goto done; |
389 | 388 | ||
390 | msg.msg_controllen = olen; | 389 | msg.msg_controllen = olen; |
391 | msg.msg_control = (void*)(fl->opt+1); | 390 | msg.msg_control = (void *)(fl->opt+1); |
392 | memset(&flowi6, 0, sizeof(flowi6)); | 391 | memset(&flowi6, 0, sizeof(flowi6)); |
393 | 392 | ||
394 | err = ip6_datagram_send_ctl(net, sk, &msg, &flowi6, fl->opt, | 393 | err = ip6_datagram_send_ctl(net, sk, &msg, &flowi6, fl->opt, |
@@ -517,7 +516,7 @@ int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen) | |||
517 | struct net *net = sock_net(sk); | 516 | struct net *net = sock_net(sk); |
518 | struct ipv6_pinfo *np = inet6_sk(sk); | 517 | struct ipv6_pinfo *np = inet6_sk(sk); |
519 | struct in6_flowlabel_req freq; | 518 | struct in6_flowlabel_req freq; |
520 | struct ipv6_fl_socklist *sfl1=NULL; | 519 | struct ipv6_fl_socklist *sfl1 = NULL; |
521 | struct ipv6_fl_socklist *sfl; | 520 | struct ipv6_fl_socklist *sfl; |
522 | struct ipv6_fl_socklist __rcu **sflp; | 521 | struct ipv6_fl_socklist __rcu **sflp; |
523 | struct ip6_flowlabel *fl, *fl1 = NULL; | 522 | struct ip6_flowlabel *fl, *fl1 = NULL; |
@@ -542,7 +541,7 @@ int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen) | |||
542 | } | 541 | } |
543 | spin_lock_bh(&ip6_sk_fl_lock); | 542 | spin_lock_bh(&ip6_sk_fl_lock); |
544 | for (sflp = &np->ipv6_fl_list; | 543 | for (sflp = &np->ipv6_fl_list; |
545 | (sfl = rcu_dereference(*sflp))!=NULL; | 544 | (sfl = rcu_dereference(*sflp)) != NULL; |
546 | sflp = &sfl->next) { | 545 | sflp = &sfl->next) { |
547 | if (sfl->fl->label == freq.flr_label) { | 546 | if (sfl->fl->label == freq.flr_label) { |
548 | if (freq.flr_label == (np->flow_label&IPV6_FLOWLABEL_MASK)) | 547 | if (freq.flr_label == (np->flow_label&IPV6_FLOWLABEL_MASK)) |
diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index 97299d76c1b0..12c3c8ef3849 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c | |||
@@ -618,6 +618,7 @@ static netdev_tx_t ip6gre_xmit2(struct sk_buff *skb, | |||
618 | int err = -1; | 618 | int err = -1; |
619 | u8 proto; | 619 | u8 proto; |
620 | struct sk_buff *new_skb; | 620 | struct sk_buff *new_skb; |
621 | __be16 protocol; | ||
621 | 622 | ||
622 | if (dev->type == ARPHRD_ETHER) | 623 | if (dev->type == ARPHRD_ETHER) |
623 | IPCB(skb)->flags = 0; | 624 | IPCB(skb)->flags = 0; |
@@ -734,8 +735,9 @@ static netdev_tx_t ip6gre_xmit2(struct sk_buff *skb, | |||
734 | ipv6h->daddr = fl6->daddr; | 735 | ipv6h->daddr = fl6->daddr; |
735 | 736 | ||
736 | ((__be16 *)(ipv6h + 1))[0] = tunnel->parms.o_flags; | 737 | ((__be16 *)(ipv6h + 1))[0] = tunnel->parms.o_flags; |
737 | ((__be16 *)(ipv6h + 1))[1] = (dev->type == ARPHRD_ETHER) ? | 738 | protocol = (dev->type == ARPHRD_ETHER) ? |
738 | htons(ETH_P_TEB) : skb->protocol; | 739 | htons(ETH_P_TEB) : skb->protocol; |
740 | ((__be16 *)(ipv6h + 1))[1] = protocol; | ||
739 | 741 | ||
740 | if (tunnel->parms.o_flags&(GRE_KEY|GRE_CSUM|GRE_SEQ)) { | 742 | if (tunnel->parms.o_flags&(GRE_KEY|GRE_CSUM|GRE_SEQ)) { |
741 | __be32 *ptr = (__be32 *)(((u8 *)ipv6h) + tunnel->hlen - 4); | 743 | __be32 *ptr = (__be32 *)(((u8 *)ipv6h) + tunnel->hlen - 4); |
@@ -756,6 +758,8 @@ static netdev_tx_t ip6gre_xmit2(struct sk_buff *skb, | |||
756 | } | 758 | } |
757 | } | 759 | } |
758 | 760 | ||
761 | skb_set_inner_protocol(skb, protocol); | ||
762 | |||
759 | ip6tunnel_xmit(skb, dev); | 763 | ip6tunnel_xmit(skb, dev); |
760 | if (ndst) | 764 | if (ndst) |
761 | ip6_tnl_dst_store(tunnel, ndst); | 765 | ip6_tnl_dst_store(tunnel, ndst); |
@@ -1238,7 +1242,7 @@ static void ip6gre_tunnel_setup(struct net_device *dev) | |||
1238 | dev->flags |= IFF_NOARP; | 1242 | dev->flags |= IFF_NOARP; |
1239 | dev->iflink = 0; | 1243 | dev->iflink = 0; |
1240 | dev->addr_len = sizeof(struct in6_addr); | 1244 | dev->addr_len = sizeof(struct in6_addr); |
1241 | dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; | 1245 | netif_keep_dst(dev); |
1242 | } | 1246 | } |
1243 | 1247 | ||
1244 | static int ip6gre_tunnel_init(struct net_device *dev) | 1248 | static int ip6gre_tunnel_init(struct net_device *dev) |
diff --git a/net/ipv6/ip6_icmp.c b/net/ipv6/ip6_icmp.c index 4578e23834f7..14dacc544c3e 100644 --- a/net/ipv6/ip6_icmp.c +++ b/net/ipv6/ip6_icmp.c | |||
@@ -13,7 +13,7 @@ static ip6_icmp_send_t __rcu *ip6_icmp_send; | |||
13 | int inet6_register_icmp_sender(ip6_icmp_send_t *fn) | 13 | int inet6_register_icmp_sender(ip6_icmp_send_t *fn) |
14 | { | 14 | { |
15 | return (cmpxchg((ip6_icmp_send_t **)&ip6_icmp_send, NULL, fn) == NULL) ? | 15 | return (cmpxchg((ip6_icmp_send_t **)&ip6_icmp_send, NULL, fn) == NULL) ? |
16 | 0 : -EBUSY; | 16 | 0 : -EBUSY; |
17 | } | 17 | } |
18 | EXPORT_SYMBOL(inet6_register_icmp_sender); | 18 | EXPORT_SYMBOL(inet6_register_icmp_sender); |
19 | 19 | ||
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c index 51d54dc376f3..a3084ab5df6c 100644 --- a/net/ipv6/ip6_input.c +++ b/net/ipv6/ip6_input.c | |||
@@ -15,8 +15,8 @@ | |||
15 | */ | 15 | */ |
16 | /* Changes | 16 | /* Changes |
17 | * | 17 | * |
18 | * Mitsuru KANDA @USAGI and | 18 | * Mitsuru KANDA @USAGI and |
19 | * YOSHIFUJI Hideaki @USAGI: Remove ipv6_parse_exthdrs(). | 19 | * YOSHIFUJI Hideaki @USAGI: Remove ipv6_parse_exthdrs(). |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <linux/errno.h> | 22 | #include <linux/errno.h> |
@@ -65,7 +65,7 @@ int ip6_rcv_finish(struct sk_buff *skb) | |||
65 | int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) | 65 | int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) |
66 | { | 66 | { |
67 | const struct ipv6hdr *hdr; | 67 | const struct ipv6hdr *hdr; |
68 | u32 pkt_len; | 68 | u32 pkt_len; |
69 | struct inet6_dev *idev; | 69 | struct inet6_dev *idev; |
70 | struct net *net = dev_net(skb->dev); | 70 | struct net *net = dev_net(skb->dev); |
71 | 71 | ||
diff --git a/net/ipv6/ip6_offload.c b/net/ipv6/ip6_offload.c index 65eda2a8af48..9034f76ae013 100644 --- a/net/ipv6/ip6_offload.c +++ b/net/ipv6/ip6_offload.c | |||
@@ -53,31 +53,6 @@ static int ipv6_gso_pull_exthdrs(struct sk_buff *skb, int proto) | |||
53 | return proto; | 53 | return proto; |
54 | } | 54 | } |
55 | 55 | ||
56 | static int ipv6_gso_send_check(struct sk_buff *skb) | ||
57 | { | ||
58 | const struct ipv6hdr *ipv6h; | ||
59 | const struct net_offload *ops; | ||
60 | int err = -EINVAL; | ||
61 | |||
62 | if (unlikely(!pskb_may_pull(skb, sizeof(*ipv6h)))) | ||
63 | goto out; | ||
64 | |||
65 | ipv6h = ipv6_hdr(skb); | ||
66 | __skb_pull(skb, sizeof(*ipv6h)); | ||
67 | err = -EPROTONOSUPPORT; | ||
68 | |||
69 | ops = rcu_dereference(inet6_offloads[ | ||
70 | ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr)]); | ||
71 | |||
72 | if (likely(ops && ops->callbacks.gso_send_check)) { | ||
73 | skb_reset_transport_header(skb); | ||
74 | err = ops->callbacks.gso_send_check(skb); | ||
75 | } | ||
76 | |||
77 | out: | ||
78 | return err; | ||
79 | } | ||
80 | |||
81 | static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, | 56 | static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, |
82 | netdev_features_t features) | 57 | netdev_features_t features) |
83 | { | 58 | { |
@@ -244,7 +219,7 @@ static struct sk_buff **ipv6_gro_receive(struct sk_buff **head, | |||
244 | continue; | 219 | continue; |
245 | 220 | ||
246 | iph2 = (struct ipv6hdr *)(p->data + off); | 221 | iph2 = (struct ipv6hdr *)(p->data + off); |
247 | first_word = *(__be32 *)iph ^ *(__be32 *)iph2 ; | 222 | first_word = *(__be32 *)iph ^ *(__be32 *)iph2; |
248 | 223 | ||
249 | /* All fields must match except length and Traffic Class. | 224 | /* All fields must match except length and Traffic Class. |
250 | * XXX skbs on the gro_list have all been parsed and pulled | 225 | * XXX skbs on the gro_list have all been parsed and pulled |
@@ -261,6 +236,9 @@ static struct sk_buff **ipv6_gro_receive(struct sk_buff **head, | |||
261 | /* flush if Traffic Class fields are different */ | 236 | /* flush if Traffic Class fields are different */ |
262 | NAPI_GRO_CB(p)->flush |= !!(first_word & htonl(0x0FF00000)); | 237 | NAPI_GRO_CB(p)->flush |= !!(first_word & htonl(0x0FF00000)); |
263 | NAPI_GRO_CB(p)->flush |= flush; | 238 | NAPI_GRO_CB(p)->flush |= flush; |
239 | |||
240 | /* Clear flush_id, there's really no concept of ID in IPv6. */ | ||
241 | NAPI_GRO_CB(p)->flush_id = 0; | ||
264 | } | 242 | } |
265 | 243 | ||
266 | NAPI_GRO_CB(skb)->flush |= flush; | 244 | NAPI_GRO_CB(skb)->flush |= flush; |
@@ -303,7 +281,6 @@ out_unlock: | |||
303 | static struct packet_offload ipv6_packet_offload __read_mostly = { | 281 | static struct packet_offload ipv6_packet_offload __read_mostly = { |
304 | .type = cpu_to_be16(ETH_P_IPV6), | 282 | .type = cpu_to_be16(ETH_P_IPV6), |
305 | .callbacks = { | 283 | .callbacks = { |
306 | .gso_send_check = ipv6_gso_send_check, | ||
307 | .gso_segment = ipv6_gso_segment, | 284 | .gso_segment = ipv6_gso_segment, |
308 | .gro_receive = ipv6_gro_receive, | 285 | .gro_receive = ipv6_gro_receive, |
309 | .gro_complete = ipv6_gro_complete, | 286 | .gro_complete = ipv6_gro_complete, |
@@ -312,8 +289,9 @@ static struct packet_offload ipv6_packet_offload __read_mostly = { | |||
312 | 289 | ||
313 | static const struct net_offload sit_offload = { | 290 | static const struct net_offload sit_offload = { |
314 | .callbacks = { | 291 | .callbacks = { |
315 | .gso_send_check = ipv6_gso_send_check, | ||
316 | .gso_segment = ipv6_gso_segment, | 292 | .gso_segment = ipv6_gso_segment, |
293 | .gro_receive = ipv6_gro_receive, | ||
294 | .gro_complete = ipv6_gro_complete, | ||
317 | }, | 295 | }, |
318 | }; | 296 | }; |
319 | 297 | ||
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 0a3448b2888f..8e950c250ada 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c | |||
@@ -20,7 +20,7 @@ | |||
20 | * etc. | 20 | * etc. |
21 | * | 21 | * |
22 | * H. von Brand : Added missing #include <linux/string.h> | 22 | * H. von Brand : Added missing #include <linux/string.h> |
23 | * Imran Patel : frag id should be in NBO | 23 | * Imran Patel : frag id should be in NBO |
24 | * Kazunori MIYAZAWA @USAGI | 24 | * Kazunori MIYAZAWA @USAGI |
25 | * : add ip6_append_data and related functions | 25 | * : add ip6_append_data and related functions |
26 | * for datagram xmit | 26 | * for datagram xmit |
@@ -233,7 +233,6 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6, | |||
233 | kfree_skb(skb); | 233 | kfree_skb(skb); |
234 | return -EMSGSIZE; | 234 | return -EMSGSIZE; |
235 | } | 235 | } |
236 | |||
237 | EXPORT_SYMBOL(ip6_xmit); | 236 | EXPORT_SYMBOL(ip6_xmit); |
238 | 237 | ||
239 | static int ip6_call_ra_chain(struct sk_buff *skb, int sel) | 238 | static int ip6_call_ra_chain(struct sk_buff *skb, int sel) |
@@ -555,14 +554,14 @@ static void ipv6_select_ident(struct frag_hdr *fhdr, struct rt6_info *rt) | |||
555 | int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) | 554 | int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) |
556 | { | 555 | { |
557 | struct sk_buff *frag; | 556 | struct sk_buff *frag; |
558 | struct rt6_info *rt = (struct rt6_info*)skb_dst(skb); | 557 | struct rt6_info *rt = (struct rt6_info *)skb_dst(skb); |
559 | struct ipv6_pinfo *np = skb->sk ? inet6_sk(skb->sk) : NULL; | 558 | struct ipv6_pinfo *np = skb->sk ? inet6_sk(skb->sk) : NULL; |
560 | struct ipv6hdr *tmp_hdr; | 559 | struct ipv6hdr *tmp_hdr; |
561 | struct frag_hdr *fh; | 560 | struct frag_hdr *fh; |
562 | unsigned int mtu, hlen, left, len; | 561 | unsigned int mtu, hlen, left, len; |
563 | int hroom, troom; | 562 | int hroom, troom; |
564 | __be32 frag_id = 0; | 563 | __be32 frag_id = 0; |
565 | int ptr, offset = 0, err=0; | 564 | int ptr, offset = 0, err = 0; |
566 | u8 *prevhdr, nexthdr = 0; | 565 | u8 *prevhdr, nexthdr = 0; |
567 | struct net *net = dev_net(skb_dst(skb)->dev); | 566 | struct net *net = dev_net(skb_dst(skb)->dev); |
568 | 567 | ||
@@ -637,7 +636,7 @@ int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) | |||
637 | } | 636 | } |
638 | 637 | ||
639 | __skb_pull(skb, hlen); | 638 | __skb_pull(skb, hlen); |
640 | fh = (struct frag_hdr*)__skb_push(skb, sizeof(struct frag_hdr)); | 639 | fh = (struct frag_hdr *)__skb_push(skb, sizeof(struct frag_hdr)); |
641 | __skb_push(skb, hlen); | 640 | __skb_push(skb, hlen); |
642 | skb_reset_network_header(skb); | 641 | skb_reset_network_header(skb); |
643 | memcpy(skb_network_header(skb), tmp_hdr, hlen); | 642 | memcpy(skb_network_header(skb), tmp_hdr, hlen); |
@@ -662,7 +661,7 @@ int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) | |||
662 | if (frag) { | 661 | if (frag) { |
663 | frag->ip_summed = CHECKSUM_NONE; | 662 | frag->ip_summed = CHECKSUM_NONE; |
664 | skb_reset_transport_header(frag); | 663 | skb_reset_transport_header(frag); |
665 | fh = (struct frag_hdr*)__skb_push(frag, sizeof(struct frag_hdr)); | 664 | fh = (struct frag_hdr *)__skb_push(frag, sizeof(struct frag_hdr)); |
666 | __skb_push(frag, hlen); | 665 | __skb_push(frag, hlen); |
667 | skb_reset_network_header(frag); | 666 | skb_reset_network_header(frag); |
668 | memcpy(skb_network_header(frag), tmp_hdr, | 667 | memcpy(skb_network_header(frag), tmp_hdr, |
@@ -681,7 +680,7 @@ int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) | |||
681 | } | 680 | } |
682 | 681 | ||
683 | err = output(skb); | 682 | err = output(skb); |
684 | if(!err) | 683 | if (!err) |
685 | IP6_INC_STATS(net, ip6_dst_idev(&rt->dst), | 684 | IP6_INC_STATS(net, ip6_dst_idev(&rt->dst), |
686 | IPSTATS_MIB_FRAGCREATES); | 685 | IPSTATS_MIB_FRAGCREATES); |
687 | 686 | ||
@@ -702,11 +701,7 @@ int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) | |||
702 | return 0; | 701 | return 0; |
703 | } | 702 | } |
704 | 703 | ||
705 | while (frag) { | 704 | kfree_skb_list(frag); |
706 | skb = frag->next; | ||
707 | kfree_skb(frag); | ||
708 | frag = skb; | ||
709 | } | ||
710 | 705 | ||
711 | IP6_INC_STATS(net, ip6_dst_idev(&rt->dst), | 706 | IP6_INC_STATS(net, ip6_dst_idev(&rt->dst), |
712 | IPSTATS_MIB_FRAGFAILS); | 707 | IPSTATS_MIB_FRAGFAILS); |
@@ -742,7 +737,7 @@ slow_path: | |||
742 | /* | 737 | /* |
743 | * Keep copying data until we run out. | 738 | * Keep copying data until we run out. |
744 | */ | 739 | */ |
745 | while(left > 0) { | 740 | while (left > 0) { |
746 | len = left; | 741 | len = left; |
747 | /* IF: it doesn't fit, use 'mtu' - the data space left */ | 742 | /* IF: it doesn't fit, use 'mtu' - the data space left */ |
748 | if (len > mtu) | 743 | if (len > mtu) |
@@ -865,7 +860,7 @@ static struct dst_entry *ip6_sk_dst_check(struct sock *sk, | |||
865 | /* Yes, checking route validity in not connected | 860 | /* Yes, checking route validity in not connected |
866 | * case is not very simple. Take into account, | 861 | * case is not very simple. Take into account, |
867 | * that we do not support routing by source, TOS, | 862 | * that we do not support routing by source, TOS, |
868 | * and MSG_DONTROUTE --ANK (980726) | 863 | * and MSG_DONTROUTE --ANK (980726) |
869 | * | 864 | * |
870 | * 1. ip6_rt_check(): If route was host route, | 865 | * 1. ip6_rt_check(): If route was host route, |
871 | * check that cached destination is current. | 866 | * check that cached destination is current. |
@@ -1049,7 +1044,7 @@ static inline int ip6_ufo_append_data(struct sock *sk, | |||
1049 | int getfrag(void *from, char *to, int offset, int len, | 1044 | int getfrag(void *from, char *to, int offset, int len, |
1050 | int odd, struct sk_buff *skb), | 1045 | int odd, struct sk_buff *skb), |
1051 | void *from, int length, int hh_len, int fragheaderlen, | 1046 | void *from, int length, int hh_len, int fragheaderlen, |
1052 | int transhdrlen, int mtu,unsigned int flags, | 1047 | int transhdrlen, int mtu, unsigned int flags, |
1053 | struct rt6_info *rt) | 1048 | struct rt6_info *rt) |
1054 | 1049 | ||
1055 | { | 1050 | { |
@@ -1072,7 +1067,7 @@ static inline int ip6_ufo_append_data(struct sock *sk, | |||
1072 | skb_reserve(skb, hh_len); | 1067 | skb_reserve(skb, hh_len); |
1073 | 1068 | ||
1074 | /* create space for UDP/IP header */ | 1069 | /* create space for UDP/IP header */ |
1075 | skb_put(skb,fragheaderlen + transhdrlen); | 1070 | skb_put(skb, fragheaderlen + transhdrlen); |
1076 | 1071 | ||
1077 | /* initialize network header pointer */ | 1072 | /* initialize network header pointer */ |
1078 | skb_reset_network_header(skb); | 1073 | skb_reset_network_header(skb); |
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 69a84b464009..9409887fb664 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c | |||
@@ -412,12 +412,12 @@ __u16 ip6_tnl_parse_tlv_enc_lim(struct sk_buff *skb, __u8 *raw) | |||
412 | { | 412 | { |
413 | const struct ipv6hdr *ipv6h = (const struct ipv6hdr *) raw; | 413 | const struct ipv6hdr *ipv6h = (const struct ipv6hdr *) raw; |
414 | __u8 nexthdr = ipv6h->nexthdr; | 414 | __u8 nexthdr = ipv6h->nexthdr; |
415 | __u16 off = sizeof (*ipv6h); | 415 | __u16 off = sizeof(*ipv6h); |
416 | 416 | ||
417 | while (ipv6_ext_hdr(nexthdr) && nexthdr != NEXTHDR_NONE) { | 417 | while (ipv6_ext_hdr(nexthdr) && nexthdr != NEXTHDR_NONE) { |
418 | __u16 optlen = 0; | 418 | __u16 optlen = 0; |
419 | struct ipv6_opt_hdr *hdr; | 419 | struct ipv6_opt_hdr *hdr; |
420 | if (raw + off + sizeof (*hdr) > skb->data && | 420 | if (raw + off + sizeof(*hdr) > skb->data && |
421 | !pskb_may_pull(skb, raw - skb->data + off + sizeof (*hdr))) | 421 | !pskb_may_pull(skb, raw - skb->data + off + sizeof (*hdr))) |
422 | break; | 422 | break; |
423 | 423 | ||
@@ -534,7 +534,7 @@ ip6_tnl_err(struct sk_buff *skb, __u8 ipproto, struct inet6_skb_parm *opt, | |||
534 | mtu = IPV6_MIN_MTU; | 534 | mtu = IPV6_MIN_MTU; |
535 | t->dev->mtu = mtu; | 535 | t->dev->mtu = mtu; |
536 | 536 | ||
537 | if ((len = sizeof (*ipv6h) + ntohs(ipv6h->payload_len)) > mtu) { | 537 | if ((len = sizeof(*ipv6h) + ntohs(ipv6h->payload_len)) > mtu) { |
538 | rel_type = ICMPV6_PKT_TOOBIG; | 538 | rel_type = ICMPV6_PKT_TOOBIG; |
539 | rel_code = 0; | 539 | rel_code = 0; |
540 | rel_info = mtu; | 540 | rel_info = mtu; |
@@ -995,7 +995,7 @@ static int ip6_tnl_xmit2(struct sk_buff *skb, | |||
995 | t->parms.name); | 995 | t->parms.name); |
996 | goto tx_err_dst_release; | 996 | goto tx_err_dst_release; |
997 | } | 997 | } |
998 | mtu = dst_mtu(dst) - sizeof (*ipv6h); | 998 | mtu = dst_mtu(dst) - sizeof(*ipv6h); |
999 | if (encap_limit >= 0) { | 999 | if (encap_limit >= 0) { |
1000 | max_headroom += 8; | 1000 | max_headroom += 8; |
1001 | mtu -= 8; | 1001 | mtu -= 8; |
@@ -1087,7 +1087,7 @@ ip4ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev) | |||
1087 | if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT)) | 1087 | if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT)) |
1088 | encap_limit = t->parms.encap_limit; | 1088 | encap_limit = t->parms.encap_limit; |
1089 | 1089 | ||
1090 | memcpy(&fl6, &t->fl.u.ip6, sizeof (fl6)); | 1090 | memcpy(&fl6, &t->fl.u.ip6, sizeof(fl6)); |
1091 | fl6.flowi6_proto = IPPROTO_IPIP; | 1091 | fl6.flowi6_proto = IPPROTO_IPIP; |
1092 | 1092 | ||
1093 | dsfield = ipv4_get_dsfield(iph); | 1093 | dsfield = ipv4_get_dsfield(iph); |
@@ -1139,7 +1139,7 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev) | |||
1139 | } else if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT)) | 1139 | } else if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT)) |
1140 | encap_limit = t->parms.encap_limit; | 1140 | encap_limit = t->parms.encap_limit; |
1141 | 1141 | ||
1142 | memcpy(&fl6, &t->fl.u.ip6, sizeof (fl6)); | 1142 | memcpy(&fl6, &t->fl.u.ip6, sizeof(fl6)); |
1143 | fl6.flowi6_proto = IPPROTO_IPV6; | 1143 | fl6.flowi6_proto = IPPROTO_IPV6; |
1144 | 1144 | ||
1145 | dsfield = ipv6_get_dsfield(ipv6h); | 1145 | dsfield = ipv6_get_dsfield(ipv6h); |
@@ -1233,11 +1233,11 @@ static void ip6_tnl_link_config(struct ip6_tnl *t) | |||
1233 | 1233 | ||
1234 | if (rt->dst.dev) { | 1234 | if (rt->dst.dev) { |
1235 | dev->hard_header_len = rt->dst.dev->hard_header_len + | 1235 | dev->hard_header_len = rt->dst.dev->hard_header_len + |
1236 | sizeof (struct ipv6hdr); | 1236 | sizeof(struct ipv6hdr); |
1237 | 1237 | ||
1238 | dev->mtu = rt->dst.dev->mtu - sizeof (struct ipv6hdr); | 1238 | dev->mtu = rt->dst.dev->mtu - sizeof(struct ipv6hdr); |
1239 | if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT)) | 1239 | if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT)) |
1240 | dev->mtu-=8; | 1240 | dev->mtu -= 8; |
1241 | 1241 | ||
1242 | if (dev->mtu < IPV6_MIN_MTU) | 1242 | if (dev->mtu < IPV6_MIN_MTU) |
1243 | dev->mtu = IPV6_MIN_MTU; | 1243 | dev->mtu = IPV6_MIN_MTU; |
@@ -1354,7 +1354,7 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | |||
1354 | switch (cmd) { | 1354 | switch (cmd) { |
1355 | case SIOCGETTUNNEL: | 1355 | case SIOCGETTUNNEL: |
1356 | if (dev == ip6n->fb_tnl_dev) { | 1356 | if (dev == ip6n->fb_tnl_dev) { |
1357 | if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof (p))) { | 1357 | if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) { |
1358 | err = -EFAULT; | 1358 | err = -EFAULT; |
1359 | break; | 1359 | break; |
1360 | } | 1360 | } |
@@ -1366,7 +1366,7 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | |||
1366 | memset(&p, 0, sizeof(p)); | 1366 | memset(&p, 0, sizeof(p)); |
1367 | } | 1367 | } |
1368 | ip6_tnl_parm_to_user(&p, &t->parms); | 1368 | ip6_tnl_parm_to_user(&p, &t->parms); |
1369 | if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof (p))) { | 1369 | if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p))) { |
1370 | err = -EFAULT; | 1370 | err = -EFAULT; |
1371 | } | 1371 | } |
1372 | break; | 1372 | break; |
@@ -1376,7 +1376,7 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | |||
1376 | if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) | 1376 | if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) |
1377 | break; | 1377 | break; |
1378 | err = -EFAULT; | 1378 | err = -EFAULT; |
1379 | if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof (p))) | 1379 | if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) |
1380 | break; | 1380 | break; |
1381 | err = -EINVAL; | 1381 | err = -EINVAL; |
1382 | if (p.proto != IPPROTO_IPV6 && p.proto != IPPROTO_IPIP && | 1382 | if (p.proto != IPPROTO_IPV6 && p.proto != IPPROTO_IPIP && |
@@ -1411,7 +1411,7 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | |||
1411 | 1411 | ||
1412 | if (dev == ip6n->fb_tnl_dev) { | 1412 | if (dev == ip6n->fb_tnl_dev) { |
1413 | err = -EFAULT; | 1413 | err = -EFAULT; |
1414 | if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof (p))) | 1414 | if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) |
1415 | break; | 1415 | break; |
1416 | err = -ENOENT; | 1416 | err = -ENOENT; |
1417 | ip6_tnl_parm_from_user(&p1, &p); | 1417 | ip6_tnl_parm_from_user(&p1, &p); |
@@ -1486,14 +1486,14 @@ static void ip6_tnl_dev_setup(struct net_device *dev) | |||
1486 | dev->destructor = ip6_dev_free; | 1486 | dev->destructor = ip6_dev_free; |
1487 | 1487 | ||
1488 | dev->type = ARPHRD_TUNNEL6; | 1488 | dev->type = ARPHRD_TUNNEL6; |
1489 | dev->hard_header_len = LL_MAX_HEADER + sizeof (struct ipv6hdr); | 1489 | dev->hard_header_len = LL_MAX_HEADER + sizeof(struct ipv6hdr); |
1490 | dev->mtu = ETH_DATA_LEN - sizeof (struct ipv6hdr); | 1490 | dev->mtu = ETH_DATA_LEN - sizeof(struct ipv6hdr); |
1491 | t = netdev_priv(dev); | 1491 | t = netdev_priv(dev); |
1492 | if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT)) | 1492 | if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT)) |
1493 | dev->mtu-=8; | 1493 | dev->mtu -= 8; |
1494 | dev->flags |= IFF_NOARP; | 1494 | dev->flags |= IFF_NOARP; |
1495 | dev->addr_len = sizeof(struct in6_addr); | 1495 | dev->addr_len = sizeof(struct in6_addr); |
1496 | dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; | 1496 | netif_keep_dst(dev); |
1497 | /* This perm addr will be used as interface identifier by IPv6 */ | 1497 | /* This perm addr will be used as interface identifier by IPv6 */ |
1498 | dev->addr_assign_type = NET_ADDR_RANDOM; | 1498 | dev->addr_assign_type = NET_ADDR_RANDOM; |
1499 | eth_random_addr(dev->perm_addr); | 1499 | eth_random_addr(dev->perm_addr); |
diff --git a/net/ipv6/ip6_udp_tunnel.c b/net/ipv6/ip6_udp_tunnel.c new file mode 100644 index 000000000000..b04ed72c4542 --- /dev/null +++ b/net/ipv6/ip6_udp_tunnel.c | |||
@@ -0,0 +1,107 @@ | |||
1 | #include <linux/module.h> | ||
2 | #include <linux/errno.h> | ||
3 | #include <linux/socket.h> | ||
4 | #include <linux/udp.h> | ||
5 | #include <linux/types.h> | ||
6 | #include <linux/kernel.h> | ||
7 | #include <linux/in6.h> | ||
8 | #include <net/udp.h> | ||
9 | #include <net/udp_tunnel.h> | ||
10 | #include <net/net_namespace.h> | ||
11 | #include <net/netns/generic.h> | ||
12 | #include <net/ip6_tunnel.h> | ||
13 | #include <net/ip6_checksum.h> | ||
14 | |||
15 | int udp_sock_create6(struct net *net, struct udp_port_cfg *cfg, | ||
16 | struct socket **sockp) | ||
17 | { | ||
18 | struct sockaddr_in6 udp6_addr; | ||
19 | int err; | ||
20 | struct socket *sock = NULL; | ||
21 | |||
22 | err = sock_create_kern(AF_INET6, SOCK_DGRAM, 0, &sock); | ||
23 | if (err < 0) | ||
24 | goto error; | ||
25 | |||
26 | sk_change_net(sock->sk, net); | ||
27 | |||
28 | udp6_addr.sin6_family = AF_INET6; | ||
29 | memcpy(&udp6_addr.sin6_addr, &cfg->local_ip6, | ||
30 | sizeof(udp6_addr.sin6_addr)); | ||
31 | udp6_addr.sin6_port = cfg->local_udp_port; | ||
32 | err = kernel_bind(sock, (struct sockaddr *)&udp6_addr, | ||
33 | sizeof(udp6_addr)); | ||
34 | if (err < 0) | ||
35 | goto error; | ||
36 | |||
37 | if (cfg->peer_udp_port) { | ||
38 | udp6_addr.sin6_family = AF_INET6; | ||
39 | memcpy(&udp6_addr.sin6_addr, &cfg->peer_ip6, | ||
40 | sizeof(udp6_addr.sin6_addr)); | ||
41 | udp6_addr.sin6_port = cfg->peer_udp_port; | ||
42 | err = kernel_connect(sock, | ||
43 | (struct sockaddr *)&udp6_addr, | ||
44 | sizeof(udp6_addr), 0); | ||
45 | } | ||
46 | if (err < 0) | ||
47 | goto error; | ||
48 | |||
49 | udp_set_no_check6_tx(sock->sk, !cfg->use_udp6_tx_checksums); | ||
50 | udp_set_no_check6_rx(sock->sk, !cfg->use_udp6_rx_checksums); | ||
51 | |||
52 | *sockp = sock; | ||
53 | return 0; | ||
54 | |||
55 | error: | ||
56 | if (sock) { | ||
57 | kernel_sock_shutdown(sock, SHUT_RDWR); | ||
58 | sk_release_kernel(sock->sk); | ||
59 | } | ||
60 | *sockp = NULL; | ||
61 | return err; | ||
62 | } | ||
63 | EXPORT_SYMBOL_GPL(udp_sock_create6); | ||
64 | |||
65 | int udp_tunnel6_xmit_skb(struct socket *sock, struct dst_entry *dst, | ||
66 | struct sk_buff *skb, struct net_device *dev, | ||
67 | struct in6_addr *saddr, struct in6_addr *daddr, | ||
68 | __u8 prio, __u8 ttl, __be16 src_port, __be16 dst_port) | ||
69 | { | ||
70 | struct udphdr *uh; | ||
71 | struct ipv6hdr *ip6h; | ||
72 | struct sock *sk = sock->sk; | ||
73 | |||
74 | __skb_push(skb, sizeof(*uh)); | ||
75 | skb_reset_transport_header(skb); | ||
76 | uh = udp_hdr(skb); | ||
77 | |||
78 | uh->dest = dst_port; | ||
79 | uh->source = src_port; | ||
80 | |||
81 | uh->len = htons(skb->len); | ||
82 | uh->check = 0; | ||
83 | |||
84 | memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); | ||
85 | IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED | ||
86 | | IPSKB_REROUTED); | ||
87 | skb_dst_set(skb, dst); | ||
88 | |||
89 | udp6_set_csum(udp_get_no_check6_tx(sk), skb, &inet6_sk(sk)->saddr, | ||
90 | &sk->sk_v6_daddr, skb->len); | ||
91 | |||
92 | __skb_push(skb, sizeof(*ip6h)); | ||
93 | skb_reset_network_header(skb); | ||
94 | ip6h = ipv6_hdr(skb); | ||
95 | ip6_flow_hdr(ip6h, prio, htonl(0)); | ||
96 | ip6h->payload_len = htons(skb->len); | ||
97 | ip6h->nexthdr = IPPROTO_UDP; | ||
98 | ip6h->hop_limit = ttl; | ||
99 | ip6h->daddr = *daddr; | ||
100 | ip6h->saddr = *saddr; | ||
101 | |||
102 | ip6tunnel_xmit(skb, dev); | ||
103 | return 0; | ||
104 | } | ||
105 | EXPORT_SYMBOL_GPL(udp_tunnel6_xmit_skb); | ||
106 | |||
107 | MODULE_LICENSE("GPL"); | ||
diff --git a/net/ipv6/ip6_vti.c b/net/ipv6/ip6_vti.c index 5833a2244467..d440bb585524 100644 --- a/net/ipv6/ip6_vti.c +++ b/net/ipv6/ip6_vti.c | |||
@@ -807,7 +807,7 @@ static void vti6_dev_setup(struct net_device *dev) | |||
807 | dev->mtu = ETH_DATA_LEN; | 807 | dev->mtu = ETH_DATA_LEN; |
808 | dev->flags |= IFF_NOARP; | 808 | dev->flags |= IFF_NOARP; |
809 | dev->addr_len = sizeof(struct in6_addr); | 809 | dev->addr_len = sizeof(struct in6_addr); |
810 | dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; | 810 | netif_keep_dst(dev); |
811 | } | 811 | } |
812 | 812 | ||
813 | /** | 813 | /** |
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index f9a3fd320d1d..0171f08325c3 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c | |||
@@ -845,7 +845,7 @@ static void ip6mr_destroy_unres(struct mr6_table *mrt, struct mfc6_cache *c) | |||
845 | 845 | ||
846 | atomic_dec(&mrt->cache_resolve_queue_len); | 846 | atomic_dec(&mrt->cache_resolve_queue_len); |
847 | 847 | ||
848 | while((skb = skb_dequeue(&c->mfc_un.unres.unresolved)) != NULL) { | 848 | while ((skb = skb_dequeue(&c->mfc_un.unres.unresolved)) != NULL) { |
849 | if (ipv6_hdr(skb)->version == 0) { | 849 | if (ipv6_hdr(skb)->version == 0) { |
850 | struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct ipv6hdr)); | 850 | struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct ipv6hdr)); |
851 | nlh->nlmsg_type = NLMSG_ERROR; | 851 | nlh->nlmsg_type = NLMSG_ERROR; |
@@ -1103,7 +1103,7 @@ static void ip6mr_cache_resolve(struct net *net, struct mr6_table *mrt, | |||
1103 | * Play the pending entries through our router | 1103 | * Play the pending entries through our router |
1104 | */ | 1104 | */ |
1105 | 1105 | ||
1106 | while((skb = __skb_dequeue(&uc->mfc_un.unres.unresolved))) { | 1106 | while ((skb = __skb_dequeue(&uc->mfc_un.unres.unresolved))) { |
1107 | if (ipv6_hdr(skb)->version == 0) { | 1107 | if (ipv6_hdr(skb)->version == 0) { |
1108 | struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct ipv6hdr)); | 1108 | struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct ipv6hdr)); |
1109 | 1109 | ||
diff --git a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c index d1c793cffcb5..1b9316e1386a 100644 --- a/net/ipv6/ipcomp6.c +++ b/net/ipv6/ipcomp6.c | |||
@@ -181,8 +181,7 @@ static int ipcomp6_rcv_cb(struct sk_buff *skb, int err) | |||
181 | return 0; | 181 | return 0; |
182 | } | 182 | } |
183 | 183 | ||
184 | static const struct xfrm_type ipcomp6_type = | 184 | static const struct xfrm_type ipcomp6_type = { |
185 | { | ||
186 | .description = "IPCOMP6", | 185 | .description = "IPCOMP6", |
187 | .owner = THIS_MODULE, | 186 | .owner = THIS_MODULE, |
188 | .proto = IPPROTO_COMP, | 187 | .proto = IPPROTO_COMP, |
@@ -193,8 +192,7 @@ static const struct xfrm_type ipcomp6_type = | |||
193 | .hdr_offset = xfrm6_find_1stfragopt, | 192 | .hdr_offset = xfrm6_find_1stfragopt, |
194 | }; | 193 | }; |
195 | 194 | ||
196 | static struct xfrm6_protocol ipcomp6_protocol = | 195 | static struct xfrm6_protocol ipcomp6_protocol = { |
197 | { | ||
198 | .handler = xfrm6_rcv, | 196 | .handler = xfrm6_rcv, |
199 | .cb_handler = ipcomp6_rcv_cb, | 197 | .cb_handler = ipcomp6_rcv_cb, |
200 | .err_handler = ipcomp6_err, | 198 | .err_handler = ipcomp6_err, |
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index 0c289982796d..e1a9583bb419 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c | |||
@@ -66,12 +66,12 @@ int ip6_ra_control(struct sock *sk, int sel) | |||
66 | if (sk->sk_type != SOCK_RAW || inet_sk(sk)->inet_num != IPPROTO_RAW) | 66 | if (sk->sk_type != SOCK_RAW || inet_sk(sk)->inet_num != IPPROTO_RAW) |
67 | return -ENOPROTOOPT; | 67 | return -ENOPROTOOPT; |
68 | 68 | ||
69 | new_ra = (sel>=0) ? kmalloc(sizeof(*new_ra), GFP_KERNEL) : NULL; | 69 | new_ra = (sel >= 0) ? kmalloc(sizeof(*new_ra), GFP_KERNEL) : NULL; |
70 | 70 | ||
71 | write_lock_bh(&ip6_ra_lock); | 71 | write_lock_bh(&ip6_ra_lock); |
72 | for (rap = &ip6_ra_chain; (ra=*rap) != NULL; rap = &ra->next) { | 72 | for (rap = &ip6_ra_chain; (ra = *rap) != NULL; rap = &ra->next) { |
73 | if (ra->sk == sk) { | 73 | if (ra->sk == sk) { |
74 | if (sel>=0) { | 74 | if (sel >= 0) { |
75 | write_unlock_bh(&ip6_ra_lock); | 75 | write_unlock_bh(&ip6_ra_lock); |
76 | kfree(new_ra); | 76 | kfree(new_ra); |
77 | return -EADDRINUSE; | 77 | return -EADDRINUSE; |
@@ -130,7 +130,7 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, | |||
130 | int retv = -ENOPROTOOPT; | 130 | int retv = -ENOPROTOOPT; |
131 | 131 | ||
132 | if (optval == NULL) | 132 | if (optval == NULL) |
133 | val=0; | 133 | val = 0; |
134 | else { | 134 | else { |
135 | if (optlen >= sizeof(int)) { | 135 | if (optlen >= sizeof(int)) { |
136 | if (get_user(val, (int __user *) optval)) | 136 | if (get_user(val, (int __user *) optval)) |
@@ -139,7 +139,7 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, | |||
139 | val = 0; | 139 | val = 0; |
140 | } | 140 | } |
141 | 141 | ||
142 | valbool = (val!=0); | 142 | valbool = (val != 0); |
143 | 143 | ||
144 | if (ip6_mroute_opt(optname)) | 144 | if (ip6_mroute_opt(optname)) |
145 | return ip6_mroute_setsockopt(sk, optname, optval, optlen); | 145 | return ip6_mroute_setsockopt(sk, optname, optval, optlen); |
@@ -474,7 +474,7 @@ sticky_done: | |||
474 | goto done; | 474 | goto done; |
475 | 475 | ||
476 | msg.msg_controllen = optlen; | 476 | msg.msg_controllen = optlen; |
477 | msg.msg_control = (void*)(opt+1); | 477 | msg.msg_control = (void *)(opt+1); |
478 | 478 | ||
479 | retv = ip6_datagram_send_ctl(net, sk, &msg, &fl6, opt, &junk, | 479 | retv = ip6_datagram_send_ctl(net, sk, &msg, &fl6, opt, &junk, |
480 | &junk, &junk); | 480 | &junk, &junk); |
@@ -687,7 +687,7 @@ done: | |||
687 | retv = -ENOBUFS; | 687 | retv = -ENOBUFS; |
688 | break; | 688 | break; |
689 | } | 689 | } |
690 | gsf = kmalloc(optlen,GFP_KERNEL); | 690 | gsf = kmalloc(optlen, GFP_KERNEL); |
691 | if (!gsf) { | 691 | if (!gsf) { |
692 | retv = -ENOBUFS; | 692 | retv = -ENOBUFS; |
693 | break; | 693 | break; |
@@ -873,7 +873,6 @@ int ipv6_setsockopt(struct sock *sk, int level, int optname, | |||
873 | #endif | 873 | #endif |
874 | return err; | 874 | return err; |
875 | } | 875 | } |
876 | |||
877 | EXPORT_SYMBOL(ipv6_setsockopt); | 876 | EXPORT_SYMBOL(ipv6_setsockopt); |
878 | 877 | ||
879 | #ifdef CONFIG_COMPAT | 878 | #ifdef CONFIG_COMPAT |
@@ -909,7 +908,6 @@ int compat_ipv6_setsockopt(struct sock *sk, int level, int optname, | |||
909 | #endif | 908 | #endif |
910 | return err; | 909 | return err; |
911 | } | 910 | } |
912 | |||
913 | EXPORT_SYMBOL(compat_ipv6_setsockopt); | 911 | EXPORT_SYMBOL(compat_ipv6_setsockopt); |
914 | #endif | 912 | #endif |
915 | 913 | ||
@@ -921,7 +919,7 @@ static int ipv6_getsockopt_sticky(struct sock *sk, struct ipv6_txoptions *opt, | |||
921 | if (!opt) | 919 | if (!opt) |
922 | return 0; | 920 | return 0; |
923 | 921 | ||
924 | switch(optname) { | 922 | switch (optname) { |
925 | case IPV6_HOPOPTS: | 923 | case IPV6_HOPOPTS: |
926 | hdr = opt->hopopt; | 924 | hdr = opt->hopopt; |
927 | break; | 925 | break; |
@@ -1284,9 +1282,9 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, | |||
1284 | return -ENOPROTOOPT; | 1282 | return -ENOPROTOOPT; |
1285 | } | 1283 | } |
1286 | len = min_t(unsigned int, sizeof(int), len); | 1284 | len = min_t(unsigned int, sizeof(int), len); |
1287 | if(put_user(len, optlen)) | 1285 | if (put_user(len, optlen)) |
1288 | return -EFAULT; | 1286 | return -EFAULT; |
1289 | if(copy_to_user(optval,&val,len)) | 1287 | if (copy_to_user(optval, &val, len)) |
1290 | return -EFAULT; | 1288 | return -EFAULT; |
1291 | return 0; | 1289 | return 0; |
1292 | } | 1290 | } |
@@ -1299,7 +1297,7 @@ int ipv6_getsockopt(struct sock *sk, int level, int optname, | |||
1299 | if (level == SOL_IP && sk->sk_type != SOCK_RAW) | 1297 | if (level == SOL_IP && sk->sk_type != SOCK_RAW) |
1300 | return udp_prot.getsockopt(sk, level, optname, optval, optlen); | 1298 | return udp_prot.getsockopt(sk, level, optname, optval, optlen); |
1301 | 1299 | ||
1302 | if(level != SOL_IPV6) | 1300 | if (level != SOL_IPV6) |
1303 | return -ENOPROTOOPT; | 1301 | return -ENOPROTOOPT; |
1304 | 1302 | ||
1305 | err = do_ipv6_getsockopt(sk, level, optname, optval, optlen, 0); | 1303 | err = do_ipv6_getsockopt(sk, level, optname, optval, optlen, 0); |
@@ -1321,7 +1319,6 @@ int ipv6_getsockopt(struct sock *sk, int level, int optname, | |||
1321 | #endif | 1319 | #endif |
1322 | return err; | 1320 | return err; |
1323 | } | 1321 | } |
1324 | |||
1325 | EXPORT_SYMBOL(ipv6_getsockopt); | 1322 | EXPORT_SYMBOL(ipv6_getsockopt); |
1326 | 1323 | ||
1327 | #ifdef CONFIG_COMPAT | 1324 | #ifdef CONFIG_COMPAT |
@@ -1364,7 +1361,6 @@ int compat_ipv6_getsockopt(struct sock *sk, int level, int optname, | |||
1364 | #endif | 1361 | #endif |
1365 | return err; | 1362 | return err; |
1366 | } | 1363 | } |
1367 | |||
1368 | EXPORT_SYMBOL(compat_ipv6_getsockopt); | 1364 | EXPORT_SYMBOL(compat_ipv6_getsockopt); |
1369 | #endif | 1365 | #endif |
1370 | 1366 | ||
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index a23b655a7627..9648de2b6745 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c | |||
@@ -64,15 +64,6 @@ | |||
64 | 64 | ||
65 | #include <net/ip6_checksum.h> | 65 | #include <net/ip6_checksum.h> |
66 | 66 | ||
67 | /* Set to 3 to get tracing... */ | ||
68 | #define MCAST_DEBUG 2 | ||
69 | |||
70 | #if MCAST_DEBUG >= 3 | ||
71 | #define MDBG(x) printk x | ||
72 | #else | ||
73 | #define MDBG(x) | ||
74 | #endif | ||
75 | |||
76 | /* Ensure that we have struct in6_addr aligned on 32bit word. */ | 67 | /* Ensure that we have struct in6_addr aligned on 32bit word. */ |
77 | static void *__mld2_query_bugs[] __attribute__((__unused__)) = { | 68 | static void *__mld2_query_bugs[] __attribute__((__unused__)) = { |
78 | BUILD_BUG_ON_NULL(offsetof(struct mld2_query, mld2q_srcs) % 4), | 69 | BUILD_BUG_ON_NULL(offsetof(struct mld2_query, mld2q_srcs) % 4), |
@@ -82,9 +73,6 @@ static void *__mld2_query_bugs[] __attribute__((__unused__)) = { | |||
82 | 73 | ||
83 | static struct in6_addr mld2_all_mcr = MLD2_ALL_MCR_INIT; | 74 | static struct in6_addr mld2_all_mcr = MLD2_ALL_MCR_INIT; |
84 | 75 | ||
85 | /* Big mc list lock for all the sockets */ | ||
86 | static DEFINE_SPINLOCK(ipv6_sk_mc_lock); | ||
87 | |||
88 | static void igmp6_join_group(struct ifmcaddr6 *ma); | 76 | static void igmp6_join_group(struct ifmcaddr6 *ma); |
89 | static void igmp6_leave_group(struct ifmcaddr6 *ma); | 77 | static void igmp6_leave_group(struct ifmcaddr6 *ma); |
90 | static void igmp6_timer_handler(unsigned long data); | 78 | static void igmp6_timer_handler(unsigned long data); |
@@ -121,6 +109,7 @@ static int ip6_mc_leave_src(struct sock *sk, struct ipv6_mc_socklist *iml, | |||
121 | #define IPV6_MLD_MAX_MSF 64 | 109 | #define IPV6_MLD_MAX_MSF 64 |
122 | 110 | ||
123 | int sysctl_mld_max_msf __read_mostly = IPV6_MLD_MAX_MSF; | 111 | int sysctl_mld_max_msf __read_mostly = IPV6_MLD_MAX_MSF; |
112 | int sysctl_mld_qrv __read_mostly = MLD_QRV_DEFAULT; | ||
124 | 113 | ||
125 | /* | 114 | /* |
126 | * socket join on multicast group | 115 | * socket join on multicast group |
@@ -173,7 +162,6 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr) | |||
173 | mc_lst->addr = *addr; | 162 | mc_lst->addr = *addr; |
174 | 163 | ||
175 | rtnl_lock(); | 164 | rtnl_lock(); |
176 | rcu_read_lock(); | ||
177 | if (ifindex == 0) { | 165 | if (ifindex == 0) { |
178 | struct rt6_info *rt; | 166 | struct rt6_info *rt; |
179 | rt = rt6_lookup(net, addr, NULL, 0, 0); | 167 | rt = rt6_lookup(net, addr, NULL, 0, 0); |
@@ -182,10 +170,9 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr) | |||
182 | ip6_rt_put(rt); | 170 | ip6_rt_put(rt); |
183 | } | 171 | } |
184 | } else | 172 | } else |
185 | dev = dev_get_by_index_rcu(net, ifindex); | 173 | dev = __dev_get_by_index(net, ifindex); |
186 | 174 | ||
187 | if (dev == NULL) { | 175 | if (dev == NULL) { |
188 | rcu_read_unlock(); | ||
189 | rtnl_unlock(); | 176 | rtnl_unlock(); |
190 | sock_kfree_s(sk, mc_lst, sizeof(*mc_lst)); | 177 | sock_kfree_s(sk, mc_lst, sizeof(*mc_lst)); |
191 | return -ENODEV; | 178 | return -ENODEV; |
@@ -203,18 +190,14 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr) | |||
203 | err = ipv6_dev_mc_inc(dev, addr); | 190 | err = ipv6_dev_mc_inc(dev, addr); |
204 | 191 | ||
205 | if (err) { | 192 | if (err) { |
206 | rcu_read_unlock(); | ||
207 | rtnl_unlock(); | 193 | rtnl_unlock(); |
208 | sock_kfree_s(sk, mc_lst, sizeof(*mc_lst)); | 194 | sock_kfree_s(sk, mc_lst, sizeof(*mc_lst)); |
209 | return err; | 195 | return err; |
210 | } | 196 | } |
211 | 197 | ||
212 | spin_lock(&ipv6_sk_mc_lock); | ||
213 | mc_lst->next = np->ipv6_mc_list; | 198 | mc_lst->next = np->ipv6_mc_list; |
214 | rcu_assign_pointer(np->ipv6_mc_list, mc_lst); | 199 | rcu_assign_pointer(np->ipv6_mc_list, mc_lst); |
215 | spin_unlock(&ipv6_sk_mc_lock); | ||
216 | 200 | ||
217 | rcu_read_unlock(); | ||
218 | rtnl_unlock(); | 201 | rtnl_unlock(); |
219 | 202 | ||
220 | return 0; | 203 | return 0; |
@@ -234,20 +217,16 @@ int ipv6_sock_mc_drop(struct sock *sk, int ifindex, const struct in6_addr *addr) | |||
234 | return -EINVAL; | 217 | return -EINVAL; |
235 | 218 | ||
236 | rtnl_lock(); | 219 | rtnl_lock(); |
237 | spin_lock(&ipv6_sk_mc_lock); | ||
238 | for (lnk = &np->ipv6_mc_list; | 220 | for (lnk = &np->ipv6_mc_list; |
239 | (mc_lst = rcu_dereference_protected(*lnk, | 221 | (mc_lst = rtnl_dereference(*lnk)) != NULL; |
240 | lockdep_is_held(&ipv6_sk_mc_lock))) !=NULL ; | ||
241 | lnk = &mc_lst->next) { | 222 | lnk = &mc_lst->next) { |
242 | if ((ifindex == 0 || mc_lst->ifindex == ifindex) && | 223 | if ((ifindex == 0 || mc_lst->ifindex == ifindex) && |
243 | ipv6_addr_equal(&mc_lst->addr, addr)) { | 224 | ipv6_addr_equal(&mc_lst->addr, addr)) { |
244 | struct net_device *dev; | 225 | struct net_device *dev; |
245 | 226 | ||
246 | *lnk = mc_lst->next; | 227 | *lnk = mc_lst->next; |
247 | spin_unlock(&ipv6_sk_mc_lock); | ||
248 | 228 | ||
249 | rcu_read_lock(); | 229 | dev = __dev_get_by_index(net, mc_lst->ifindex); |
250 | dev = dev_get_by_index_rcu(net, mc_lst->ifindex); | ||
251 | if (dev != NULL) { | 230 | if (dev != NULL) { |
252 | struct inet6_dev *idev = __in6_dev_get(dev); | 231 | struct inet6_dev *idev = __in6_dev_get(dev); |
253 | 232 | ||
@@ -256,7 +235,6 @@ int ipv6_sock_mc_drop(struct sock *sk, int ifindex, const struct in6_addr *addr) | |||
256 | __ipv6_dev_mc_dec(idev, &mc_lst->addr); | 235 | __ipv6_dev_mc_dec(idev, &mc_lst->addr); |
257 | } else | 236 | } else |
258 | (void) ip6_mc_leave_src(sk, mc_lst, NULL); | 237 | (void) ip6_mc_leave_src(sk, mc_lst, NULL); |
259 | rcu_read_unlock(); | ||
260 | rtnl_unlock(); | 238 | rtnl_unlock(); |
261 | 239 | ||
262 | atomic_sub(sizeof(*mc_lst), &sk->sk_omem_alloc); | 240 | atomic_sub(sizeof(*mc_lst), &sk->sk_omem_alloc); |
@@ -264,7 +242,6 @@ int ipv6_sock_mc_drop(struct sock *sk, int ifindex, const struct in6_addr *addr) | |||
264 | return 0; | 242 | return 0; |
265 | } | 243 | } |
266 | } | 244 | } |
267 | spin_unlock(&ipv6_sk_mc_lock); | ||
268 | rtnl_unlock(); | 245 | rtnl_unlock(); |
269 | 246 | ||
270 | return -EADDRNOTAVAIL; | 247 | return -EADDRNOTAVAIL; |
@@ -311,16 +288,12 @@ void ipv6_sock_mc_close(struct sock *sk) | |||
311 | return; | 288 | return; |
312 | 289 | ||
313 | rtnl_lock(); | 290 | rtnl_lock(); |
314 | spin_lock(&ipv6_sk_mc_lock); | 291 | while ((mc_lst = rtnl_dereference(np->ipv6_mc_list)) != NULL) { |
315 | while ((mc_lst = rcu_dereference_protected(np->ipv6_mc_list, | ||
316 | lockdep_is_held(&ipv6_sk_mc_lock))) != NULL) { | ||
317 | struct net_device *dev; | 292 | struct net_device *dev; |
318 | 293 | ||
319 | np->ipv6_mc_list = mc_lst->next; | 294 | np->ipv6_mc_list = mc_lst->next; |
320 | spin_unlock(&ipv6_sk_mc_lock); | ||
321 | 295 | ||
322 | rcu_read_lock(); | 296 | dev = __dev_get_by_index(net, mc_lst->ifindex); |
323 | dev = dev_get_by_index_rcu(net, mc_lst->ifindex); | ||
324 | if (dev) { | 297 | if (dev) { |
325 | struct inet6_dev *idev = __in6_dev_get(dev); | 298 | struct inet6_dev *idev = __in6_dev_get(dev); |
326 | 299 | ||
@@ -329,14 +302,11 @@ void ipv6_sock_mc_close(struct sock *sk) | |||
329 | __ipv6_dev_mc_dec(idev, &mc_lst->addr); | 302 | __ipv6_dev_mc_dec(idev, &mc_lst->addr); |
330 | } else | 303 | } else |
331 | (void) ip6_mc_leave_src(sk, mc_lst, NULL); | 304 | (void) ip6_mc_leave_src(sk, mc_lst, NULL); |
332 | rcu_read_unlock(); | ||
333 | 305 | ||
334 | atomic_sub(sizeof(*mc_lst), &sk->sk_omem_alloc); | 306 | atomic_sub(sizeof(*mc_lst), &sk->sk_omem_alloc); |
335 | kfree_rcu(mc_lst, rcu); | 307 | kfree_rcu(mc_lst, rcu); |
336 | 308 | ||
337 | spin_lock(&ipv6_sk_mc_lock); | ||
338 | } | 309 | } |
339 | spin_unlock(&ipv6_sk_mc_lock); | ||
340 | rtnl_unlock(); | 310 | rtnl_unlock(); |
341 | } | 311 | } |
342 | 312 | ||
@@ -400,7 +370,7 @@ int ip6_mc_source(int add, int omode, struct sock *sk, | |||
400 | if (!psl) | 370 | if (!psl) |
401 | goto done; /* err = -EADDRNOTAVAIL */ | 371 | goto done; /* err = -EADDRNOTAVAIL */ |
402 | rv = !0; | 372 | rv = !0; |
403 | for (i=0; i<psl->sl_count; i++) { | 373 | for (i = 0; i < psl->sl_count; i++) { |
404 | rv = !ipv6_addr_equal(&psl->sl_addr[i], source); | 374 | rv = !ipv6_addr_equal(&psl->sl_addr[i], source); |
405 | if (rv == 0) | 375 | if (rv == 0) |
406 | break; | 376 | break; |
@@ -417,7 +387,7 @@ int ip6_mc_source(int add, int omode, struct sock *sk, | |||
417 | /* update the interface filter */ | 387 | /* update the interface filter */ |
418 | ip6_mc_del_src(idev, group, omode, 1, source, 1); | 388 | ip6_mc_del_src(idev, group, omode, 1, source, 1); |
419 | 389 | ||
420 | for (j=i+1; j<psl->sl_count; j++) | 390 | for (j = i+1; j < psl->sl_count; j++) |
421 | psl->sl_addr[j-1] = psl->sl_addr[j]; | 391 | psl->sl_addr[j-1] = psl->sl_addr[j]; |
422 | psl->sl_count--; | 392 | psl->sl_count--; |
423 | err = 0; | 393 | err = 0; |
@@ -443,19 +413,19 @@ int ip6_mc_source(int add, int omode, struct sock *sk, | |||
443 | newpsl->sl_max = count; | 413 | newpsl->sl_max = count; |
444 | newpsl->sl_count = count - IP6_SFBLOCK; | 414 | newpsl->sl_count = count - IP6_SFBLOCK; |
445 | if (psl) { | 415 | if (psl) { |
446 | for (i=0; i<psl->sl_count; i++) | 416 | for (i = 0; i < psl->sl_count; i++) |
447 | newpsl->sl_addr[i] = psl->sl_addr[i]; | 417 | newpsl->sl_addr[i] = psl->sl_addr[i]; |
448 | sock_kfree_s(sk, psl, IP6_SFLSIZE(psl->sl_max)); | 418 | sock_kfree_s(sk, psl, IP6_SFLSIZE(psl->sl_max)); |
449 | } | 419 | } |
450 | pmc->sflist = psl = newpsl; | 420 | pmc->sflist = psl = newpsl; |
451 | } | 421 | } |
452 | rv = 1; /* > 0 for insert logic below if sl_count is 0 */ | 422 | rv = 1; /* > 0 for insert logic below if sl_count is 0 */ |
453 | for (i=0; i<psl->sl_count; i++) { | 423 | for (i = 0; i < psl->sl_count; i++) { |
454 | rv = !ipv6_addr_equal(&psl->sl_addr[i], source); | 424 | rv = !ipv6_addr_equal(&psl->sl_addr[i], source); |
455 | if (rv == 0) /* There is an error in the address. */ | 425 | if (rv == 0) /* There is an error in the address. */ |
456 | goto done; | 426 | goto done; |
457 | } | 427 | } |
458 | for (j=psl->sl_count-1; j>=i; j--) | 428 | for (j = psl->sl_count-1; j >= i; j--) |
459 | psl->sl_addr[j+1] = psl->sl_addr[j]; | 429 | psl->sl_addr[j+1] = psl->sl_addr[j]; |
460 | psl->sl_addr[i] = *source; | 430 | psl->sl_addr[i] = *source; |
461 | psl->sl_count++; | 431 | psl->sl_count++; |
@@ -524,7 +494,7 @@ int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf) | |||
524 | goto done; | 494 | goto done; |
525 | } | 495 | } |
526 | newpsl->sl_max = newpsl->sl_count = gsf->gf_numsrc; | 496 | newpsl->sl_max = newpsl->sl_count = gsf->gf_numsrc; |
527 | for (i=0; i<newpsl->sl_count; ++i) { | 497 | for (i = 0; i < newpsl->sl_count; ++i) { |
528 | struct sockaddr_in6 *psin6; | 498 | struct sockaddr_in6 *psin6; |
529 | 499 | ||
530 | psin6 = (struct sockaddr_in6 *)&gsf->gf_slist[i]; | 500 | psin6 = (struct sockaddr_in6 *)&gsf->gf_slist[i]; |
@@ -586,9 +556,8 @@ int ip6_mc_msfget(struct sock *sk, struct group_filter *gsf, | |||
586 | } | 556 | } |
587 | 557 | ||
588 | err = -EADDRNOTAVAIL; | 558 | err = -EADDRNOTAVAIL; |
589 | /* | 559 | /* changes to the ipv6_mc_list require the socket lock and |
590 | * changes to the ipv6_mc_list require the socket lock and | 560 | * rtnl lock. We have the socket lock and rcu read lock, |
591 | * a read lock on ip6_sk_mc_lock. We have the socket lock, | ||
592 | * so reading the list is safe. | 561 | * so reading the list is safe. |
593 | */ | 562 | */ |
594 | 563 | ||
@@ -612,11 +581,10 @@ int ip6_mc_msfget(struct sock *sk, struct group_filter *gsf, | |||
612 | copy_to_user(optval, gsf, GROUP_FILTER_SIZE(0))) { | 581 | copy_to_user(optval, gsf, GROUP_FILTER_SIZE(0))) { |
613 | return -EFAULT; | 582 | return -EFAULT; |
614 | } | 583 | } |
615 | /* changes to psl require the socket lock, a read lock on | 584 | /* changes to psl require the socket lock, and a write lock |
616 | * on ipv6_sk_mc_lock and a write lock on pmc->sflock. We | 585 | * on pmc->sflock. We have the socket lock so reading here is safe. |
617 | * have the socket lock, so reading here is safe. | ||
618 | */ | 586 | */ |
619 | for (i=0; i<copycount; i++) { | 587 | for (i = 0; i < copycount; i++) { |
620 | struct sockaddr_in6 *psin6; | 588 | struct sockaddr_in6 *psin6; |
621 | struct sockaddr_storage ss; | 589 | struct sockaddr_storage ss; |
622 | 590 | ||
@@ -658,7 +626,7 @@ bool inet6_mc_check(struct sock *sk, const struct in6_addr *mc_addr, | |||
658 | } else { | 626 | } else { |
659 | int i; | 627 | int i; |
660 | 628 | ||
661 | for (i=0; i<psl->sl_count; i++) { | 629 | for (i = 0; i < psl->sl_count; i++) { |
662 | if (ipv6_addr_equal(&psl->sl_addr[i], src_addr)) | 630 | if (ipv6_addr_equal(&psl->sl_addr[i], src_addr)) |
663 | break; | 631 | break; |
664 | } | 632 | } |
@@ -673,14 +641,6 @@ bool inet6_mc_check(struct sock *sk, const struct in6_addr *mc_addr, | |||
673 | return rv; | 641 | return rv; |
674 | } | 642 | } |
675 | 643 | ||
676 | static void ma_put(struct ifmcaddr6 *mc) | ||
677 | { | ||
678 | if (atomic_dec_and_test(&mc->mca_refcnt)) { | ||
679 | in6_dev_put(mc->idev); | ||
680 | kfree(mc); | ||
681 | } | ||
682 | } | ||
683 | |||
684 | static void igmp6_group_added(struct ifmcaddr6 *mc) | 644 | static void igmp6_group_added(struct ifmcaddr6 *mc) |
685 | { | 645 | { |
686 | struct net_device *dev = mc->idev->dev; | 646 | struct net_device *dev = mc->idev->dev; |
@@ -772,7 +732,7 @@ static void mld_add_delrec(struct inet6_dev *idev, struct ifmcaddr6 *im) | |||
772 | pmc->mca_tomb = im->mca_tomb; | 732 | pmc->mca_tomb = im->mca_tomb; |
773 | pmc->mca_sources = im->mca_sources; | 733 | pmc->mca_sources = im->mca_sources; |
774 | im->mca_tomb = im->mca_sources = NULL; | 734 | im->mca_tomb = im->mca_sources = NULL; |
775 | for (psf=pmc->mca_sources; psf; psf=psf->sf_next) | 735 | for (psf = pmc->mca_sources; psf; psf = psf->sf_next) |
776 | psf->sf_crcount = pmc->mca_crcount; | 736 | psf->sf_crcount = pmc->mca_crcount; |
777 | } | 737 | } |
778 | spin_unlock_bh(&im->mca_lock); | 738 | spin_unlock_bh(&im->mca_lock); |
@@ -790,7 +750,7 @@ static void mld_del_delrec(struct inet6_dev *idev, const struct in6_addr *pmca) | |||
790 | 750 | ||
791 | spin_lock_bh(&idev->mc_lock); | 751 | spin_lock_bh(&idev->mc_lock); |
792 | pmc_prev = NULL; | 752 | pmc_prev = NULL; |
793 | for (pmc=idev->mc_tomb; pmc; pmc=pmc->next) { | 753 | for (pmc = idev->mc_tomb; pmc; pmc = pmc->next) { |
794 | if (ipv6_addr_equal(&pmc->mca_addr, pmca)) | 754 | if (ipv6_addr_equal(&pmc->mca_addr, pmca)) |
795 | break; | 755 | break; |
796 | pmc_prev = pmc; | 756 | pmc_prev = pmc; |
@@ -804,7 +764,7 @@ static void mld_del_delrec(struct inet6_dev *idev, const struct in6_addr *pmca) | |||
804 | spin_unlock_bh(&idev->mc_lock); | 764 | spin_unlock_bh(&idev->mc_lock); |
805 | 765 | ||
806 | if (pmc) { | 766 | if (pmc) { |
807 | for (psf=pmc->mca_tomb; psf; psf=psf_next) { | 767 | for (psf = pmc->mca_tomb; psf; psf = psf_next) { |
808 | psf_next = psf->sf_next; | 768 | psf_next = psf->sf_next; |
809 | kfree(psf); | 769 | kfree(psf); |
810 | } | 770 | } |
@@ -831,14 +791,14 @@ static void mld_clear_delrec(struct inet6_dev *idev) | |||
831 | 791 | ||
832 | /* clear dead sources, too */ | 792 | /* clear dead sources, too */ |
833 | read_lock_bh(&idev->lock); | 793 | read_lock_bh(&idev->lock); |
834 | for (pmc=idev->mc_list; pmc; pmc=pmc->next) { | 794 | for (pmc = idev->mc_list; pmc; pmc = pmc->next) { |
835 | struct ip6_sf_list *psf, *psf_next; | 795 | struct ip6_sf_list *psf, *psf_next; |
836 | 796 | ||
837 | spin_lock_bh(&pmc->mca_lock); | 797 | spin_lock_bh(&pmc->mca_lock); |
838 | psf = pmc->mca_tomb; | 798 | psf = pmc->mca_tomb; |
839 | pmc->mca_tomb = NULL; | 799 | pmc->mca_tomb = NULL; |
840 | spin_unlock_bh(&pmc->mca_lock); | 800 | spin_unlock_bh(&pmc->mca_lock); |
841 | for (; psf; psf=psf_next) { | 801 | for (; psf; psf = psf_next) { |
842 | psf_next = psf->sf_next; | 802 | psf_next = psf->sf_next; |
843 | kfree(psf); | 803 | kfree(psf); |
844 | } | 804 | } |
@@ -846,6 +806,48 @@ static void mld_clear_delrec(struct inet6_dev *idev) | |||
846 | read_unlock_bh(&idev->lock); | 806 | read_unlock_bh(&idev->lock); |
847 | } | 807 | } |
848 | 808 | ||
809 | static void mca_get(struct ifmcaddr6 *mc) | ||
810 | { | ||
811 | atomic_inc(&mc->mca_refcnt); | ||
812 | } | ||
813 | |||
814 | static void ma_put(struct ifmcaddr6 *mc) | ||
815 | { | ||
816 | if (atomic_dec_and_test(&mc->mca_refcnt)) { | ||
817 | in6_dev_put(mc->idev); | ||
818 | kfree(mc); | ||
819 | } | ||
820 | } | ||
821 | |||
822 | static struct ifmcaddr6 *mca_alloc(struct inet6_dev *idev, | ||
823 | const struct in6_addr *addr) | ||
824 | { | ||
825 | struct ifmcaddr6 *mc; | ||
826 | |||
827 | mc = kzalloc(sizeof(*mc), GFP_ATOMIC); | ||
828 | if (mc == NULL) | ||
829 | return NULL; | ||
830 | |||
831 | setup_timer(&mc->mca_timer, igmp6_timer_handler, (unsigned long)mc); | ||
832 | |||
833 | mc->mca_addr = *addr; | ||
834 | mc->idev = idev; /* reference taken by caller */ | ||
835 | mc->mca_users = 1; | ||
836 | /* mca_stamp should be updated upon changes */ | ||
837 | mc->mca_cstamp = mc->mca_tstamp = jiffies; | ||
838 | atomic_set(&mc->mca_refcnt, 1); | ||
839 | spin_lock_init(&mc->mca_lock); | ||
840 | |||
841 | /* initial mode is (EX, empty) */ | ||
842 | mc->mca_sfmode = MCAST_EXCLUDE; | ||
843 | mc->mca_sfcount[MCAST_EXCLUDE] = 1; | ||
844 | |||
845 | if (ipv6_addr_is_ll_all_nodes(&mc->mca_addr) || | ||
846 | IPV6_ADDR_MC_SCOPE(&mc->mca_addr) < IPV6_ADDR_SCOPE_LINKLOCAL) | ||
847 | mc->mca_flags |= MAF_NOREPORT; | ||
848 | |||
849 | return mc; | ||
850 | } | ||
849 | 851 | ||
850 | /* | 852 | /* |
851 | * device multicast group inc (add if not found) | 853 | * device multicast group inc (add if not found) |
@@ -881,38 +883,20 @@ int ipv6_dev_mc_inc(struct net_device *dev, const struct in6_addr *addr) | |||
881 | } | 883 | } |
882 | } | 884 | } |
883 | 885 | ||
884 | /* | 886 | mc = mca_alloc(idev, addr); |
885 | * not found: create a new one. | 887 | if (!mc) { |
886 | */ | ||
887 | |||
888 | mc = kzalloc(sizeof(struct ifmcaddr6), GFP_ATOMIC); | ||
889 | |||
890 | if (mc == NULL) { | ||
891 | write_unlock_bh(&idev->lock); | 888 | write_unlock_bh(&idev->lock); |
892 | in6_dev_put(idev); | 889 | in6_dev_put(idev); |
893 | return -ENOMEM; | 890 | return -ENOMEM; |
894 | } | 891 | } |
895 | 892 | ||
896 | setup_timer(&mc->mca_timer, igmp6_timer_handler, (unsigned long)mc); | ||
897 | |||
898 | mc->mca_addr = *addr; | ||
899 | mc->idev = idev; /* (reference taken) */ | ||
900 | mc->mca_users = 1; | ||
901 | /* mca_stamp should be updated upon changes */ | ||
902 | mc->mca_cstamp = mc->mca_tstamp = jiffies; | ||
903 | atomic_set(&mc->mca_refcnt, 2); | ||
904 | spin_lock_init(&mc->mca_lock); | ||
905 | |||
906 | /* initial mode is (EX, empty) */ | ||
907 | mc->mca_sfmode = MCAST_EXCLUDE; | ||
908 | mc->mca_sfcount[MCAST_EXCLUDE] = 1; | ||
909 | |||
910 | if (ipv6_addr_is_ll_all_nodes(&mc->mca_addr) || | ||
911 | IPV6_ADDR_MC_SCOPE(&mc->mca_addr) < IPV6_ADDR_SCOPE_LINKLOCAL) | ||
912 | mc->mca_flags |= MAF_NOREPORT; | ||
913 | |||
914 | mc->next = idev->mc_list; | 893 | mc->next = idev->mc_list; |
915 | idev->mc_list = mc; | 894 | idev->mc_list = mc; |
895 | |||
896 | /* Hold this for the code below before we unlock, | ||
897 | * it is already exposed via idev->mc_list. | ||
898 | */ | ||
899 | mca_get(mc); | ||
916 | write_unlock_bh(&idev->lock); | 900 | write_unlock_bh(&idev->lock); |
917 | 901 | ||
918 | mld_del_delrec(idev, &mc->mca_addr); | 902 | mld_del_delrec(idev, &mc->mca_addr); |
@@ -931,7 +915,7 @@ int __ipv6_dev_mc_dec(struct inet6_dev *idev, const struct in6_addr *addr) | |||
931 | ASSERT_RTNL(); | 915 | ASSERT_RTNL(); |
932 | 916 | ||
933 | write_lock_bh(&idev->lock); | 917 | write_lock_bh(&idev->lock); |
934 | for (map = &idev->mc_list; (ma=*map) != NULL; map = &ma->next) { | 918 | for (map = &idev->mc_list; (ma = *map) != NULL; map = &ma->next) { |
935 | if (ipv6_addr_equal(&ma->mca_addr, addr)) { | 919 | if (ipv6_addr_equal(&ma->mca_addr, addr)) { |
936 | if (--ma->mca_users == 0) { | 920 | if (--ma->mca_users == 0) { |
937 | *map = ma->next; | 921 | *map = ma->next; |
@@ -956,7 +940,7 @@ int ipv6_dev_mc_dec(struct net_device *dev, const struct in6_addr *addr) | |||
956 | struct inet6_dev *idev; | 940 | struct inet6_dev *idev; |
957 | int err; | 941 | int err; |
958 | 942 | ||
959 | rcu_read_lock(); | 943 | ASSERT_RTNL(); |
960 | 944 | ||
961 | idev = __in6_dev_get(dev); | 945 | idev = __in6_dev_get(dev); |
962 | if (!idev) | 946 | if (!idev) |
@@ -964,7 +948,6 @@ int ipv6_dev_mc_dec(struct net_device *dev, const struct in6_addr *addr) | |||
964 | else | 948 | else |
965 | err = __ipv6_dev_mc_dec(idev, addr); | 949 | err = __ipv6_dev_mc_dec(idev, addr); |
966 | 950 | ||
967 | rcu_read_unlock(); | ||
968 | return err; | 951 | return err; |
969 | } | 952 | } |
970 | 953 | ||
@@ -982,7 +965,7 @@ bool ipv6_chk_mcast_addr(struct net_device *dev, const struct in6_addr *group, | |||
982 | idev = __in6_dev_get(dev); | 965 | idev = __in6_dev_get(dev); |
983 | if (idev) { | 966 | if (idev) { |
984 | read_lock_bh(&idev->lock); | 967 | read_lock_bh(&idev->lock); |
985 | for (mc = idev->mc_list; mc; mc=mc->next) { | 968 | for (mc = idev->mc_list; mc; mc = mc->next) { |
986 | if (ipv6_addr_equal(&mc->mca_addr, group)) | 969 | if (ipv6_addr_equal(&mc->mca_addr, group)) |
987 | break; | 970 | break; |
988 | } | 971 | } |
@@ -991,7 +974,7 @@ bool ipv6_chk_mcast_addr(struct net_device *dev, const struct in6_addr *group, | |||
991 | struct ip6_sf_list *psf; | 974 | struct ip6_sf_list *psf; |
992 | 975 | ||
993 | spin_lock_bh(&mc->mca_lock); | 976 | spin_lock_bh(&mc->mca_lock); |
994 | for (psf=mc->mca_sources;psf;psf=psf->sf_next) { | 977 | for (psf = mc->mca_sources; psf; psf = psf->sf_next) { |
995 | if (ipv6_addr_equal(&psf->sf_addr, src_addr)) | 978 | if (ipv6_addr_equal(&psf->sf_addr, src_addr)) |
996 | break; | 979 | break; |
997 | } | 980 | } |
@@ -1000,7 +983,7 @@ bool ipv6_chk_mcast_addr(struct net_device *dev, const struct in6_addr *group, | |||
1000 | psf->sf_count[MCAST_EXCLUDE] != | 983 | psf->sf_count[MCAST_EXCLUDE] != |
1001 | mc->mca_sfcount[MCAST_EXCLUDE]; | 984 | mc->mca_sfcount[MCAST_EXCLUDE]; |
1002 | else | 985 | else |
1003 | rv = mc->mca_sfcount[MCAST_EXCLUDE] !=0; | 986 | rv = mc->mca_sfcount[MCAST_EXCLUDE] != 0; |
1004 | spin_unlock_bh(&mc->mca_lock); | 987 | spin_unlock_bh(&mc->mca_lock); |
1005 | } else | 988 | } else |
1006 | rv = true; /* don't filter unspecified source */ | 989 | rv = true; /* don't filter unspecified source */ |
@@ -1091,10 +1074,10 @@ static bool mld_xmarksources(struct ifmcaddr6 *pmc, int nsrcs, | |||
1091 | int i, scount; | 1074 | int i, scount; |
1092 | 1075 | ||
1093 | scount = 0; | 1076 | scount = 0; |
1094 | for (psf=pmc->mca_sources; psf; psf=psf->sf_next) { | 1077 | for (psf = pmc->mca_sources; psf; psf = psf->sf_next) { |
1095 | if (scount == nsrcs) | 1078 | if (scount == nsrcs) |
1096 | break; | 1079 | break; |
1097 | for (i=0; i<nsrcs; i++) { | 1080 | for (i = 0; i < nsrcs; i++) { |
1098 | /* skip inactive filters */ | 1081 | /* skip inactive filters */ |
1099 | if (psf->sf_count[MCAST_INCLUDE] || | 1082 | if (psf->sf_count[MCAST_INCLUDE] || |
1100 | pmc->mca_sfcount[MCAST_EXCLUDE] != | 1083 | pmc->mca_sfcount[MCAST_EXCLUDE] != |
@@ -1124,10 +1107,10 @@ static bool mld_marksources(struct ifmcaddr6 *pmc, int nsrcs, | |||
1124 | /* mark INCLUDE-mode sources */ | 1107 | /* mark INCLUDE-mode sources */ |
1125 | 1108 | ||
1126 | scount = 0; | 1109 | scount = 0; |
1127 | for (psf=pmc->mca_sources; psf; psf=psf->sf_next) { | 1110 | for (psf = pmc->mca_sources; psf; psf = psf->sf_next) { |
1128 | if (scount == nsrcs) | 1111 | if (scount == nsrcs) |
1129 | break; | 1112 | break; |
1130 | for (i=0; i<nsrcs; i++) { | 1113 | for (i = 0; i < nsrcs; i++) { |
1131 | if (ipv6_addr_equal(&srcs[i], &psf->sf_addr)) { | 1114 | if (ipv6_addr_equal(&srcs[i], &psf->sf_addr)) { |
1132 | psf->sf_gsresp = 1; | 1115 | psf->sf_gsresp = 1; |
1133 | scount++; | 1116 | scount++; |
@@ -1205,15 +1188,16 @@ static void mld_update_qrv(struct inet6_dev *idev, | |||
1205 | * and SHOULD NOT be one. Catch this here if we ever run | 1188 | * and SHOULD NOT be one. Catch this here if we ever run |
1206 | * into such a case in future. | 1189 | * into such a case in future. |
1207 | */ | 1190 | */ |
1191 | const int min_qrv = min(MLD_QRV_DEFAULT, sysctl_mld_qrv); | ||
1208 | WARN_ON(idev->mc_qrv == 0); | 1192 | WARN_ON(idev->mc_qrv == 0); |
1209 | 1193 | ||
1210 | if (mlh2->mld2q_qrv > 0) | 1194 | if (mlh2->mld2q_qrv > 0) |
1211 | idev->mc_qrv = mlh2->mld2q_qrv; | 1195 | idev->mc_qrv = mlh2->mld2q_qrv; |
1212 | 1196 | ||
1213 | if (unlikely(idev->mc_qrv < 2)) { | 1197 | if (unlikely(idev->mc_qrv < min_qrv)) { |
1214 | net_warn_ratelimited("IPv6: MLD: clamping QRV from %u to %u!\n", | 1198 | net_warn_ratelimited("IPv6: MLD: clamping QRV from %u to %u!\n", |
1215 | idev->mc_qrv, MLD_QRV_DEFAULT); | 1199 | idev->mc_qrv, min_qrv); |
1216 | idev->mc_qrv = MLD_QRV_DEFAULT; | 1200 | idev->mc_qrv = min_qrv; |
1217 | } | 1201 | } |
1218 | } | 1202 | } |
1219 | 1203 | ||
@@ -1253,7 +1237,7 @@ static void mld_update_qri(struct inet6_dev *idev, | |||
1253 | } | 1237 | } |
1254 | 1238 | ||
1255 | static int mld_process_v1(struct inet6_dev *idev, struct mld_msg *mld, | 1239 | static int mld_process_v1(struct inet6_dev *idev, struct mld_msg *mld, |
1256 | unsigned long *max_delay) | 1240 | unsigned long *max_delay, bool v1_query) |
1257 | { | 1241 | { |
1258 | unsigned long mldv1_md; | 1242 | unsigned long mldv1_md; |
1259 | 1243 | ||
@@ -1261,11 +1245,32 @@ static int mld_process_v1(struct inet6_dev *idev, struct mld_msg *mld, | |||
1261 | if (mld_in_v2_mode_only(idev)) | 1245 | if (mld_in_v2_mode_only(idev)) |
1262 | return -EINVAL; | 1246 | return -EINVAL; |
1263 | 1247 | ||
1264 | /* MLDv1 router present */ | ||
1265 | mldv1_md = ntohs(mld->mld_maxdelay); | 1248 | mldv1_md = ntohs(mld->mld_maxdelay); |
1249 | |||
1250 | /* When in MLDv1 fallback and a MLDv2 router start-up being | ||
1251 | * unaware of current MLDv1 operation, the MRC == MRD mapping | ||
1252 | * only works when the exponential algorithm is not being | ||
1253 | * used (as MLDv1 is unaware of such things). | ||
1254 | * | ||
1255 | * According to the RFC author, the MLDv2 implementations | ||
1256 | * he's aware of all use a MRC < 32768 on start up queries. | ||
1257 | * | ||
1258 | * Thus, should we *ever* encounter something else larger | ||
1259 | * than that, just assume the maximum possible within our | ||
1260 | * reach. | ||
1261 | */ | ||
1262 | if (!v1_query) | ||
1263 | mldv1_md = min(mldv1_md, MLDV1_MRD_MAX_COMPAT); | ||
1264 | |||
1266 | *max_delay = max(msecs_to_jiffies(mldv1_md), 1UL); | 1265 | *max_delay = max(msecs_to_jiffies(mldv1_md), 1UL); |
1267 | 1266 | ||
1268 | mld_set_v1_mode(idev); | 1267 | /* MLDv1 router present: we need to go into v1 mode *only* |
1268 | * when an MLDv1 query is received as per section 9.12. of | ||
1269 | * RFC3810! And we know from RFC2710 section 3.7 that MLDv1 | ||
1270 | * queries MUST be of exactly 24 octets. | ||
1271 | */ | ||
1272 | if (v1_query) | ||
1273 | mld_set_v1_mode(idev); | ||
1269 | 1274 | ||
1270 | /* cancel MLDv2 report timer */ | 1275 | /* cancel MLDv2 report timer */ |
1271 | mld_gq_stop_timer(idev); | 1276 | mld_gq_stop_timer(idev); |
@@ -1280,10 +1285,6 @@ static int mld_process_v1(struct inet6_dev *idev, struct mld_msg *mld, | |||
1280 | static int mld_process_v2(struct inet6_dev *idev, struct mld2_query *mld, | 1285 | static int mld_process_v2(struct inet6_dev *idev, struct mld2_query *mld, |
1281 | unsigned long *max_delay) | 1286 | unsigned long *max_delay) |
1282 | { | 1287 | { |
1283 | /* hosts need to stay in MLDv1 mode, discard MLDv2 queries */ | ||
1284 | if (mld_in_v1_mode(idev)) | ||
1285 | return -EINVAL; | ||
1286 | |||
1287 | *max_delay = max(msecs_to_jiffies(mldv2_mrc(mld)), 1UL); | 1288 | *max_delay = max(msecs_to_jiffies(mldv2_mrc(mld)), 1UL); |
1288 | 1289 | ||
1289 | mld_update_qrv(idev, mld); | 1290 | mld_update_qrv(idev, mld); |
@@ -1340,8 +1341,11 @@ int igmp6_event_query(struct sk_buff *skb) | |||
1340 | !(group_type&IPV6_ADDR_MULTICAST)) | 1341 | !(group_type&IPV6_ADDR_MULTICAST)) |
1341 | return -EINVAL; | 1342 | return -EINVAL; |
1342 | 1343 | ||
1343 | if (len == MLD_V1_QUERY_LEN) { | 1344 | if (len < MLD_V1_QUERY_LEN) { |
1344 | err = mld_process_v1(idev, mld, &max_delay); | 1345 | return -EINVAL; |
1346 | } else if (len == MLD_V1_QUERY_LEN || mld_in_v1_mode(idev)) { | ||
1347 | err = mld_process_v1(idev, mld, &max_delay, | ||
1348 | len == MLD_V1_QUERY_LEN); | ||
1345 | if (err < 0) | 1349 | if (err < 0) |
1346 | return err; | 1350 | return err; |
1347 | } else if (len >= MLD_V2_QUERY_LEN_MIN) { | 1351 | } else if (len >= MLD_V2_QUERY_LEN_MIN) { |
@@ -1373,18 +1377,19 @@ int igmp6_event_query(struct sk_buff *skb) | |||
1373 | mlh2 = (struct mld2_query *)skb_transport_header(skb); | 1377 | mlh2 = (struct mld2_query *)skb_transport_header(skb); |
1374 | mark = 1; | 1378 | mark = 1; |
1375 | } | 1379 | } |
1376 | } else | 1380 | } else { |
1377 | return -EINVAL; | 1381 | return -EINVAL; |
1382 | } | ||
1378 | 1383 | ||
1379 | read_lock_bh(&idev->lock); | 1384 | read_lock_bh(&idev->lock); |
1380 | if (group_type == IPV6_ADDR_ANY) { | 1385 | if (group_type == IPV6_ADDR_ANY) { |
1381 | for (ma = idev->mc_list; ma; ma=ma->next) { | 1386 | for (ma = idev->mc_list; ma; ma = ma->next) { |
1382 | spin_lock_bh(&ma->mca_lock); | 1387 | spin_lock_bh(&ma->mca_lock); |
1383 | igmp6_group_queried(ma, max_delay); | 1388 | igmp6_group_queried(ma, max_delay); |
1384 | spin_unlock_bh(&ma->mca_lock); | 1389 | spin_unlock_bh(&ma->mca_lock); |
1385 | } | 1390 | } |
1386 | } else { | 1391 | } else { |
1387 | for (ma = idev->mc_list; ma; ma=ma->next) { | 1392 | for (ma = idev->mc_list; ma; ma = ma->next) { |
1388 | if (!ipv6_addr_equal(group, &ma->mca_addr)) | 1393 | if (!ipv6_addr_equal(group, &ma->mca_addr)) |
1389 | continue; | 1394 | continue; |
1390 | spin_lock_bh(&ma->mca_lock); | 1395 | spin_lock_bh(&ma->mca_lock); |
@@ -1448,7 +1453,7 @@ int igmp6_event_report(struct sk_buff *skb) | |||
1448 | */ | 1453 | */ |
1449 | 1454 | ||
1450 | read_lock_bh(&idev->lock); | 1455 | read_lock_bh(&idev->lock); |
1451 | for (ma = idev->mc_list; ma; ma=ma->next) { | 1456 | for (ma = idev->mc_list; ma; ma = ma->next) { |
1452 | if (ipv6_addr_equal(&ma->mca_addr, &mld->mld_mca)) { | 1457 | if (ipv6_addr_equal(&ma->mca_addr, &mld->mld_mca)) { |
1453 | spin_lock(&ma->mca_lock); | 1458 | spin_lock(&ma->mca_lock); |
1454 | if (del_timer(&ma->mca_timer)) | 1459 | if (del_timer(&ma->mca_timer)) |
@@ -1512,7 +1517,7 @@ mld_scount(struct ifmcaddr6 *pmc, int type, int gdeleted, int sdeleted) | |||
1512 | struct ip6_sf_list *psf; | 1517 | struct ip6_sf_list *psf; |
1513 | int scount = 0; | 1518 | int scount = 0; |
1514 | 1519 | ||
1515 | for (psf=pmc->mca_sources; psf; psf=psf->sf_next) { | 1520 | for (psf = pmc->mca_sources; psf; psf = psf->sf_next) { |
1516 | if (!is_in(pmc, psf, type, gdeleted, sdeleted)) | 1521 | if (!is_in(pmc, psf, type, gdeleted, sdeleted)) |
1517 | continue; | 1522 | continue; |
1518 | scount++; | 1523 | scount++; |
@@ -1726,7 +1731,7 @@ static struct sk_buff *add_grec(struct sk_buff *skb, struct ifmcaddr6 *pmc, | |||
1726 | } | 1731 | } |
1727 | first = 1; | 1732 | first = 1; |
1728 | psf_prev = NULL; | 1733 | psf_prev = NULL; |
1729 | for (psf=*psf_list; psf; psf=psf_next) { | 1734 | for (psf = *psf_list; psf; psf = psf_next) { |
1730 | struct in6_addr *psrc; | 1735 | struct in6_addr *psrc; |
1731 | 1736 | ||
1732 | psf_next = psf->sf_next; | 1737 | psf_next = psf->sf_next; |
@@ -1805,7 +1810,7 @@ static void mld_send_report(struct inet6_dev *idev, struct ifmcaddr6 *pmc) | |||
1805 | 1810 | ||
1806 | read_lock_bh(&idev->lock); | 1811 | read_lock_bh(&idev->lock); |
1807 | if (!pmc) { | 1812 | if (!pmc) { |
1808 | for (pmc=idev->mc_list; pmc; pmc=pmc->next) { | 1813 | for (pmc = idev->mc_list; pmc; pmc = pmc->next) { |
1809 | if (pmc->mca_flags & MAF_NOREPORT) | 1814 | if (pmc->mca_flags & MAF_NOREPORT) |
1810 | continue; | 1815 | continue; |
1811 | spin_lock_bh(&pmc->mca_lock); | 1816 | spin_lock_bh(&pmc->mca_lock); |
@@ -1838,7 +1843,7 @@ static void mld_clear_zeros(struct ip6_sf_list **ppsf) | |||
1838 | struct ip6_sf_list *psf_prev, *psf_next, *psf; | 1843 | struct ip6_sf_list *psf_prev, *psf_next, *psf; |
1839 | 1844 | ||
1840 | psf_prev = NULL; | 1845 | psf_prev = NULL; |
1841 | for (psf=*ppsf; psf; psf = psf_next) { | 1846 | for (psf = *ppsf; psf; psf = psf_next) { |
1842 | psf_next = psf->sf_next; | 1847 | psf_next = psf->sf_next; |
1843 | if (psf->sf_crcount == 0) { | 1848 | if (psf->sf_crcount == 0) { |
1844 | if (psf_prev) | 1849 | if (psf_prev) |
@@ -1862,7 +1867,7 @@ static void mld_send_cr(struct inet6_dev *idev) | |||
1862 | 1867 | ||
1863 | /* deleted MCA's */ | 1868 | /* deleted MCA's */ |
1864 | pmc_prev = NULL; | 1869 | pmc_prev = NULL; |
1865 | for (pmc=idev->mc_tomb; pmc; pmc=pmc_next) { | 1870 | for (pmc = idev->mc_tomb; pmc; pmc = pmc_next) { |
1866 | pmc_next = pmc->next; | 1871 | pmc_next = pmc->next; |
1867 | if (pmc->mca_sfmode == MCAST_INCLUDE) { | 1872 | if (pmc->mca_sfmode == MCAST_INCLUDE) { |
1868 | type = MLD2_BLOCK_OLD_SOURCES; | 1873 | type = MLD2_BLOCK_OLD_SOURCES; |
@@ -1895,7 +1900,7 @@ static void mld_send_cr(struct inet6_dev *idev) | |||
1895 | spin_unlock(&idev->mc_lock); | 1900 | spin_unlock(&idev->mc_lock); |
1896 | 1901 | ||
1897 | /* change recs */ | 1902 | /* change recs */ |
1898 | for (pmc=idev->mc_list; pmc; pmc=pmc->next) { | 1903 | for (pmc = idev->mc_list; pmc; pmc = pmc->next) { |
1899 | spin_lock_bh(&pmc->mca_lock); | 1904 | spin_lock_bh(&pmc->mca_lock); |
1900 | if (pmc->mca_sfcount[MCAST_EXCLUDE]) { | 1905 | if (pmc->mca_sfcount[MCAST_EXCLUDE]) { |
1901 | type = MLD2_BLOCK_OLD_SOURCES; | 1906 | type = MLD2_BLOCK_OLD_SOURCES; |
@@ -2032,7 +2037,7 @@ static void mld_send_initial_cr(struct inet6_dev *idev) | |||
2032 | 2037 | ||
2033 | skb = NULL; | 2038 | skb = NULL; |
2034 | read_lock_bh(&idev->lock); | 2039 | read_lock_bh(&idev->lock); |
2035 | for (pmc=idev->mc_list; pmc; pmc=pmc->next) { | 2040 | for (pmc = idev->mc_list; pmc; pmc = pmc->next) { |
2036 | spin_lock_bh(&pmc->mca_lock); | 2041 | spin_lock_bh(&pmc->mca_lock); |
2037 | if (pmc->mca_sfcount[MCAST_EXCLUDE]) | 2042 | if (pmc->mca_sfcount[MCAST_EXCLUDE]) |
2038 | type = MLD2_CHANGE_TO_EXCLUDE; | 2043 | type = MLD2_CHANGE_TO_EXCLUDE; |
@@ -2077,7 +2082,7 @@ static int ip6_mc_del1_src(struct ifmcaddr6 *pmc, int sfmode, | |||
2077 | int rv = 0; | 2082 | int rv = 0; |
2078 | 2083 | ||
2079 | psf_prev = NULL; | 2084 | psf_prev = NULL; |
2080 | for (psf=pmc->mca_sources; psf; psf=psf->sf_next) { | 2085 | for (psf = pmc->mca_sources; psf; psf = psf->sf_next) { |
2081 | if (ipv6_addr_equal(&psf->sf_addr, psfsrc)) | 2086 | if (ipv6_addr_equal(&psf->sf_addr, psfsrc)) |
2082 | break; | 2087 | break; |
2083 | psf_prev = psf; | 2088 | psf_prev = psf; |
@@ -2118,7 +2123,7 @@ static int ip6_mc_del_src(struct inet6_dev *idev, const struct in6_addr *pmca, | |||
2118 | if (!idev) | 2123 | if (!idev) |
2119 | return -ENODEV; | 2124 | return -ENODEV; |
2120 | read_lock_bh(&idev->lock); | 2125 | read_lock_bh(&idev->lock); |
2121 | for (pmc=idev->mc_list; pmc; pmc=pmc->next) { | 2126 | for (pmc = idev->mc_list; pmc; pmc = pmc->next) { |
2122 | if (ipv6_addr_equal(pmca, &pmc->mca_addr)) | 2127 | if (ipv6_addr_equal(pmca, &pmc->mca_addr)) |
2123 | break; | 2128 | break; |
2124 | } | 2129 | } |
@@ -2138,7 +2143,7 @@ static int ip6_mc_del_src(struct inet6_dev *idev, const struct in6_addr *pmca, | |||
2138 | pmc->mca_sfcount[sfmode]--; | 2143 | pmc->mca_sfcount[sfmode]--; |
2139 | } | 2144 | } |
2140 | err = 0; | 2145 | err = 0; |
2141 | for (i=0; i<sfcount; i++) { | 2146 | for (i = 0; i < sfcount; i++) { |
2142 | int rv = ip6_mc_del1_src(pmc, sfmode, &psfsrc[i]); | 2147 | int rv = ip6_mc_del1_src(pmc, sfmode, &psfsrc[i]); |
2143 | 2148 | ||
2144 | changerec |= rv > 0; | 2149 | changerec |= rv > 0; |
@@ -2154,7 +2159,7 @@ static int ip6_mc_del_src(struct inet6_dev *idev, const struct in6_addr *pmca, | |||
2154 | pmc->mca_sfmode = MCAST_INCLUDE; | 2159 | pmc->mca_sfmode = MCAST_INCLUDE; |
2155 | pmc->mca_crcount = idev->mc_qrv; | 2160 | pmc->mca_crcount = idev->mc_qrv; |
2156 | idev->mc_ifc_count = pmc->mca_crcount; | 2161 | idev->mc_ifc_count = pmc->mca_crcount; |
2157 | for (psf=pmc->mca_sources; psf; psf = psf->sf_next) | 2162 | for (psf = pmc->mca_sources; psf; psf = psf->sf_next) |
2158 | psf->sf_crcount = 0; | 2163 | psf->sf_crcount = 0; |
2159 | mld_ifc_event(pmc->idev); | 2164 | mld_ifc_event(pmc->idev); |
2160 | } else if (sf_setstate(pmc) || changerec) | 2165 | } else if (sf_setstate(pmc) || changerec) |
@@ -2173,7 +2178,7 @@ static int ip6_mc_add1_src(struct ifmcaddr6 *pmc, int sfmode, | |||
2173 | struct ip6_sf_list *psf, *psf_prev; | 2178 | struct ip6_sf_list *psf, *psf_prev; |
2174 | 2179 | ||
2175 | psf_prev = NULL; | 2180 | psf_prev = NULL; |
2176 | for (psf=pmc->mca_sources; psf; psf=psf->sf_next) { | 2181 | for (psf = pmc->mca_sources; psf; psf = psf->sf_next) { |
2177 | if (ipv6_addr_equal(&psf->sf_addr, psfsrc)) | 2182 | if (ipv6_addr_equal(&psf->sf_addr, psfsrc)) |
2178 | break; | 2183 | break; |
2179 | psf_prev = psf; | 2184 | psf_prev = psf; |
@@ -2198,7 +2203,7 @@ static void sf_markstate(struct ifmcaddr6 *pmc) | |||
2198 | struct ip6_sf_list *psf; | 2203 | struct ip6_sf_list *psf; |
2199 | int mca_xcount = pmc->mca_sfcount[MCAST_EXCLUDE]; | 2204 | int mca_xcount = pmc->mca_sfcount[MCAST_EXCLUDE]; |
2200 | 2205 | ||
2201 | for (psf=pmc->mca_sources; psf; psf=psf->sf_next) | 2206 | for (psf = pmc->mca_sources; psf; psf = psf->sf_next) |
2202 | if (pmc->mca_sfcount[MCAST_EXCLUDE]) { | 2207 | if (pmc->mca_sfcount[MCAST_EXCLUDE]) { |
2203 | psf->sf_oldin = mca_xcount == | 2208 | psf->sf_oldin = mca_xcount == |
2204 | psf->sf_count[MCAST_EXCLUDE] && | 2209 | psf->sf_count[MCAST_EXCLUDE] && |
@@ -2215,7 +2220,7 @@ static int sf_setstate(struct ifmcaddr6 *pmc) | |||
2215 | int new_in, rv; | 2220 | int new_in, rv; |
2216 | 2221 | ||
2217 | rv = 0; | 2222 | rv = 0; |
2218 | for (psf=pmc->mca_sources; psf; psf=psf->sf_next) { | 2223 | for (psf = pmc->mca_sources; psf; psf = psf->sf_next) { |
2219 | if (pmc->mca_sfcount[MCAST_EXCLUDE]) { | 2224 | if (pmc->mca_sfcount[MCAST_EXCLUDE]) { |
2220 | new_in = mca_xcount == psf->sf_count[MCAST_EXCLUDE] && | 2225 | new_in = mca_xcount == psf->sf_count[MCAST_EXCLUDE] && |
2221 | !psf->sf_count[MCAST_INCLUDE]; | 2226 | !psf->sf_count[MCAST_INCLUDE]; |
@@ -2225,8 +2230,8 @@ static int sf_setstate(struct ifmcaddr6 *pmc) | |||
2225 | if (!psf->sf_oldin) { | 2230 | if (!psf->sf_oldin) { |
2226 | struct ip6_sf_list *prev = NULL; | 2231 | struct ip6_sf_list *prev = NULL; |
2227 | 2232 | ||
2228 | for (dpsf=pmc->mca_tomb; dpsf; | 2233 | for (dpsf = pmc->mca_tomb; dpsf; |
2229 | dpsf=dpsf->sf_next) { | 2234 | dpsf = dpsf->sf_next) { |
2230 | if (ipv6_addr_equal(&dpsf->sf_addr, | 2235 | if (ipv6_addr_equal(&dpsf->sf_addr, |
2231 | &psf->sf_addr)) | 2236 | &psf->sf_addr)) |
2232 | break; | 2237 | break; |
@@ -2248,7 +2253,7 @@ static int sf_setstate(struct ifmcaddr6 *pmc) | |||
2248 | * add or update "delete" records if an active filter | 2253 | * add or update "delete" records if an active filter |
2249 | * is now inactive | 2254 | * is now inactive |
2250 | */ | 2255 | */ |
2251 | for (dpsf=pmc->mca_tomb; dpsf; dpsf=dpsf->sf_next) | 2256 | for (dpsf = pmc->mca_tomb; dpsf; dpsf = dpsf->sf_next) |
2252 | if (ipv6_addr_equal(&dpsf->sf_addr, | 2257 | if (ipv6_addr_equal(&dpsf->sf_addr, |
2253 | &psf->sf_addr)) | 2258 | &psf->sf_addr)) |
2254 | break; | 2259 | break; |
@@ -2282,7 +2287,7 @@ static int ip6_mc_add_src(struct inet6_dev *idev, const struct in6_addr *pmca, | |||
2282 | if (!idev) | 2287 | if (!idev) |
2283 | return -ENODEV; | 2288 | return -ENODEV; |
2284 | read_lock_bh(&idev->lock); | 2289 | read_lock_bh(&idev->lock); |
2285 | for (pmc=idev->mc_list; pmc; pmc=pmc->next) { | 2290 | for (pmc = idev->mc_list; pmc; pmc = pmc->next) { |
2286 | if (ipv6_addr_equal(pmca, &pmc->mca_addr)) | 2291 | if (ipv6_addr_equal(pmca, &pmc->mca_addr)) |
2287 | break; | 2292 | break; |
2288 | } | 2293 | } |
@@ -2298,7 +2303,7 @@ static int ip6_mc_add_src(struct inet6_dev *idev, const struct in6_addr *pmca, | |||
2298 | if (!delta) | 2303 | if (!delta) |
2299 | pmc->mca_sfcount[sfmode]++; | 2304 | pmc->mca_sfcount[sfmode]++; |
2300 | err = 0; | 2305 | err = 0; |
2301 | for (i=0; i<sfcount; i++) { | 2306 | for (i = 0; i < sfcount; i++) { |
2302 | err = ip6_mc_add1_src(pmc, sfmode, &psfsrc[i]); | 2307 | err = ip6_mc_add1_src(pmc, sfmode, &psfsrc[i]); |
2303 | if (err) | 2308 | if (err) |
2304 | break; | 2309 | break; |
@@ -2308,7 +2313,7 @@ static int ip6_mc_add_src(struct inet6_dev *idev, const struct in6_addr *pmca, | |||
2308 | 2313 | ||
2309 | if (!delta) | 2314 | if (!delta) |
2310 | pmc->mca_sfcount[sfmode]--; | 2315 | pmc->mca_sfcount[sfmode]--; |
2311 | for (j=0; j<i; j++) | 2316 | for (j = 0; j < i; j++) |
2312 | ip6_mc_del1_src(pmc, sfmode, &psfsrc[j]); | 2317 | ip6_mc_del1_src(pmc, sfmode, &psfsrc[j]); |
2313 | } else if (isexclude != (pmc->mca_sfcount[MCAST_EXCLUDE] != 0)) { | 2318 | } else if (isexclude != (pmc->mca_sfcount[MCAST_EXCLUDE] != 0)) { |
2314 | struct ip6_sf_list *psf; | 2319 | struct ip6_sf_list *psf; |
@@ -2322,7 +2327,7 @@ static int ip6_mc_add_src(struct inet6_dev *idev, const struct in6_addr *pmca, | |||
2322 | 2327 | ||
2323 | pmc->mca_crcount = idev->mc_qrv; | 2328 | pmc->mca_crcount = idev->mc_qrv; |
2324 | idev->mc_ifc_count = pmc->mca_crcount; | 2329 | idev->mc_ifc_count = pmc->mca_crcount; |
2325 | for (psf=pmc->mca_sources; psf; psf = psf->sf_next) | 2330 | for (psf = pmc->mca_sources; psf; psf = psf->sf_next) |
2326 | psf->sf_crcount = 0; | 2331 | psf->sf_crcount = 0; |
2327 | mld_ifc_event(idev); | 2332 | mld_ifc_event(idev); |
2328 | } else if (sf_setstate(pmc)) | 2333 | } else if (sf_setstate(pmc)) |
@@ -2336,12 +2341,12 @@ static void ip6_mc_clear_src(struct ifmcaddr6 *pmc) | |||
2336 | { | 2341 | { |
2337 | struct ip6_sf_list *psf, *nextpsf; | 2342 | struct ip6_sf_list *psf, *nextpsf; |
2338 | 2343 | ||
2339 | for (psf=pmc->mca_tomb; psf; psf=nextpsf) { | 2344 | for (psf = pmc->mca_tomb; psf; psf = nextpsf) { |
2340 | nextpsf = psf->sf_next; | 2345 | nextpsf = psf->sf_next; |
2341 | kfree(psf); | 2346 | kfree(psf); |
2342 | } | 2347 | } |
2343 | pmc->mca_tomb = NULL; | 2348 | pmc->mca_tomb = NULL; |
2344 | for (psf=pmc->mca_sources; psf; psf=nextpsf) { | 2349 | for (psf = pmc->mca_sources; psf; psf = nextpsf) { |
2345 | nextpsf = psf->sf_next; | 2350 | nextpsf = psf->sf_next; |
2346 | kfree(psf); | 2351 | kfree(psf); |
2347 | } | 2352 | } |
@@ -2380,7 +2385,7 @@ static int ip6_mc_leave_src(struct sock *sk, struct ipv6_mc_socklist *iml, | |||
2380 | { | 2385 | { |
2381 | int err; | 2386 | int err; |
2382 | 2387 | ||
2383 | /* callers have the socket lock and a write lock on ipv6_sk_mc_lock, | 2388 | /* callers have the socket lock and rtnl lock |
2384 | * so no other readers or writers of iml or its sflist | 2389 | * so no other readers or writers of iml or its sflist |
2385 | */ | 2390 | */ |
2386 | if (!iml->sflist) { | 2391 | if (!iml->sflist) { |
@@ -2485,13 +2490,21 @@ void ipv6_mc_down(struct inet6_dev *idev) | |||
2485 | mld_gq_stop_timer(idev); | 2490 | mld_gq_stop_timer(idev); |
2486 | mld_dad_stop_timer(idev); | 2491 | mld_dad_stop_timer(idev); |
2487 | 2492 | ||
2488 | for (i = idev->mc_list; i; i=i->next) | 2493 | for (i = idev->mc_list; i; i = i->next) |
2489 | igmp6_group_dropped(i); | 2494 | igmp6_group_dropped(i); |
2490 | read_unlock_bh(&idev->lock); | 2495 | read_unlock_bh(&idev->lock); |
2491 | 2496 | ||
2492 | mld_clear_delrec(idev); | 2497 | mld_clear_delrec(idev); |
2493 | } | 2498 | } |
2494 | 2499 | ||
2500 | static void ipv6_mc_reset(struct inet6_dev *idev) | ||
2501 | { | ||
2502 | idev->mc_qrv = sysctl_mld_qrv; | ||
2503 | idev->mc_qi = MLD_QI_DEFAULT; | ||
2504 | idev->mc_qri = MLD_QRI_DEFAULT; | ||
2505 | idev->mc_v1_seen = 0; | ||
2506 | idev->mc_maxdelay = unsolicited_report_interval(idev); | ||
2507 | } | ||
2495 | 2508 | ||
2496 | /* Device going up */ | 2509 | /* Device going up */ |
2497 | 2510 | ||
@@ -2502,7 +2515,8 @@ void ipv6_mc_up(struct inet6_dev *idev) | |||
2502 | /* Install multicast list, except for all-nodes (already installed) */ | 2515 | /* Install multicast list, except for all-nodes (already installed) */ |
2503 | 2516 | ||
2504 | read_lock_bh(&idev->lock); | 2517 | read_lock_bh(&idev->lock); |
2505 | for (i = idev->mc_list; i; i=i->next) | 2518 | ipv6_mc_reset(idev); |
2519 | for (i = idev->mc_list; i; i = i->next) | ||
2506 | igmp6_group_added(i); | 2520 | igmp6_group_added(i); |
2507 | read_unlock_bh(&idev->lock); | 2521 | read_unlock_bh(&idev->lock); |
2508 | } | 2522 | } |
@@ -2522,13 +2536,7 @@ void ipv6_mc_init_dev(struct inet6_dev *idev) | |||
2522 | (unsigned long)idev); | 2536 | (unsigned long)idev); |
2523 | setup_timer(&idev->mc_dad_timer, mld_dad_timer_expire, | 2537 | setup_timer(&idev->mc_dad_timer, mld_dad_timer_expire, |
2524 | (unsigned long)idev); | 2538 | (unsigned long)idev); |
2525 | 2539 | ipv6_mc_reset(idev); | |
2526 | idev->mc_qrv = MLD_QRV_DEFAULT; | ||
2527 | idev->mc_qi = MLD_QI_DEFAULT; | ||
2528 | idev->mc_qri = MLD_QRI_DEFAULT; | ||
2529 | |||
2530 | idev->mc_maxdelay = unsolicited_report_interval(idev); | ||
2531 | idev->mc_v1_seen = 0; | ||
2532 | write_unlock_bh(&idev->lock); | 2540 | write_unlock_bh(&idev->lock); |
2533 | } | 2541 | } |
2534 | 2542 | ||
diff --git a/net/ipv6/mip6.c b/net/ipv6/mip6.c index db9b6cbc9db3..f61429d391d3 100644 --- a/net/ipv6/mip6.c +++ b/net/ipv6/mip6.c | |||
@@ -336,11 +336,10 @@ static void mip6_destopt_destroy(struct xfrm_state *x) | |||
336 | { | 336 | { |
337 | } | 337 | } |
338 | 338 | ||
339 | static const struct xfrm_type mip6_destopt_type = | 339 | static const struct xfrm_type mip6_destopt_type = { |
340 | { | ||
341 | .description = "MIP6DESTOPT", | 340 | .description = "MIP6DESTOPT", |
342 | .owner = THIS_MODULE, | 341 | .owner = THIS_MODULE, |
343 | .proto = IPPROTO_DSTOPTS, | 342 | .proto = IPPROTO_DSTOPTS, |
344 | .flags = XFRM_TYPE_NON_FRAGMENT | XFRM_TYPE_LOCAL_COADDR, | 343 | .flags = XFRM_TYPE_NON_FRAGMENT | XFRM_TYPE_LOCAL_COADDR, |
345 | .init_state = mip6_destopt_init_state, | 344 | .init_state = mip6_destopt_init_state, |
346 | .destructor = mip6_destopt_destroy, | 345 | .destructor = mip6_destopt_destroy, |
@@ -469,11 +468,10 @@ static void mip6_rthdr_destroy(struct xfrm_state *x) | |||
469 | { | 468 | { |
470 | } | 469 | } |
471 | 470 | ||
472 | static const struct xfrm_type mip6_rthdr_type = | 471 | static const struct xfrm_type mip6_rthdr_type = { |
473 | { | ||
474 | .description = "MIP6RT", | 472 | .description = "MIP6RT", |
475 | .owner = THIS_MODULE, | 473 | .owner = THIS_MODULE, |
476 | .proto = IPPROTO_ROUTING, | 474 | .proto = IPPROTO_ROUTING, |
477 | .flags = XFRM_TYPE_NON_FRAGMENT | XFRM_TYPE_REMOTE_COADDR, | 475 | .flags = XFRM_TYPE_NON_FRAGMENT | XFRM_TYPE_REMOTE_COADDR, |
478 | .init_state = mip6_rthdr_init_state, | 476 | .init_state = mip6_rthdr_init_state, |
479 | .destructor = mip6_rthdr_destroy, | 477 | .destructor = mip6_rthdr_destroy, |
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 339078f95d1b..4cb45c1079a2 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c | |||
@@ -175,7 +175,7 @@ static struct nd_opt_hdr *ndisc_next_option(struct nd_opt_hdr *cur, | |||
175 | type = cur->nd_opt_type; | 175 | type = cur->nd_opt_type; |
176 | do { | 176 | do { |
177 | cur = ((void *)cur) + (cur->nd_opt_len << 3); | 177 | cur = ((void *)cur) + (cur->nd_opt_len << 3); |
178 | } while(cur < end && cur->nd_opt_type != type); | 178 | } while (cur < end && cur->nd_opt_type != type); |
179 | return cur <= end && cur->nd_opt_type == type ? cur : NULL; | 179 | return cur <= end && cur->nd_opt_type == type ? cur : NULL; |
180 | } | 180 | } |
181 | 181 | ||
@@ -192,7 +192,7 @@ static struct nd_opt_hdr *ndisc_next_useropt(struct nd_opt_hdr *cur, | |||
192 | return NULL; | 192 | return NULL; |
193 | do { | 193 | do { |
194 | cur = ((void *)cur) + (cur->nd_opt_len << 3); | 194 | cur = ((void *)cur) + (cur->nd_opt_len << 3); |
195 | } while(cur < end && !ndisc_is_useropt(cur)); | 195 | } while (cur < end && !ndisc_is_useropt(cur)); |
196 | return cur <= end && ndisc_is_useropt(cur) ? cur : NULL; | 196 | return cur <= end && ndisc_is_useropt(cur) ? cur : NULL; |
197 | } | 197 | } |
198 | 198 | ||
@@ -284,7 +284,6 @@ int ndisc_mc_map(const struct in6_addr *addr, char *buf, struct net_device *dev, | |||
284 | } | 284 | } |
285 | return -EINVAL; | 285 | return -EINVAL; |
286 | } | 286 | } |
287 | |||
288 | EXPORT_SYMBOL(ndisc_mc_map); | 287 | EXPORT_SYMBOL(ndisc_mc_map); |
289 | 288 | ||
290 | static u32 ndisc_hash(const void *pkey, | 289 | static u32 ndisc_hash(const void *pkey, |
@@ -296,7 +295,7 @@ static u32 ndisc_hash(const void *pkey, | |||
296 | 295 | ||
297 | static int ndisc_constructor(struct neighbour *neigh) | 296 | static int ndisc_constructor(struct neighbour *neigh) |
298 | { | 297 | { |
299 | struct in6_addr *addr = (struct in6_addr*)&neigh->primary_key; | 298 | struct in6_addr *addr = (struct in6_addr *)&neigh->primary_key; |
300 | struct net_device *dev = neigh->dev; | 299 | struct net_device *dev = neigh->dev; |
301 | struct inet6_dev *in6_dev; | 300 | struct inet6_dev *in6_dev; |
302 | struct neigh_parms *parms; | 301 | struct neigh_parms *parms; |
@@ -344,7 +343,7 @@ static int ndisc_constructor(struct neighbour *neigh) | |||
344 | 343 | ||
345 | static int pndisc_constructor(struct pneigh_entry *n) | 344 | static int pndisc_constructor(struct pneigh_entry *n) |
346 | { | 345 | { |
347 | struct in6_addr *addr = (struct in6_addr*)&n->key; | 346 | struct in6_addr *addr = (struct in6_addr *)&n->key; |
348 | struct in6_addr maddr; | 347 | struct in6_addr maddr; |
349 | struct net_device *dev = n->dev; | 348 | struct net_device *dev = n->dev; |
350 | 349 | ||
@@ -357,7 +356,7 @@ static int pndisc_constructor(struct pneigh_entry *n) | |||
357 | 356 | ||
358 | static void pndisc_destructor(struct pneigh_entry *n) | 357 | static void pndisc_destructor(struct pneigh_entry *n) |
359 | { | 358 | { |
360 | struct in6_addr *addr = (struct in6_addr*)&n->key; | 359 | struct in6_addr *addr = (struct in6_addr *)&n->key; |
361 | struct in6_addr maddr; | 360 | struct in6_addr maddr; |
362 | struct net_device *dev = n->dev; | 361 | struct net_device *dev = n->dev; |
363 | 362 | ||
@@ -1065,7 +1064,7 @@ static void ndisc_router_discovery(struct sk_buff *skb) | |||
1065 | int optlen; | 1064 | int optlen; |
1066 | unsigned int pref = 0; | 1065 | unsigned int pref = 0; |
1067 | 1066 | ||
1068 | __u8 * opt = (__u8 *)(ra_msg + 1); | 1067 | __u8 *opt = (__u8 *)(ra_msg + 1); |
1069 | 1068 | ||
1070 | optlen = (skb_tail_pointer(skb) - skb_transport_header(skb)) - | 1069 | optlen = (skb_tail_pointer(skb) - skb_transport_header(skb)) - |
1071 | sizeof(struct ra_msg); | 1070 | sizeof(struct ra_msg); |
@@ -1319,7 +1318,7 @@ skip_linkparms: | |||
1319 | continue; | 1318 | continue; |
1320 | if (ri->prefix_len > in6_dev->cnf.accept_ra_rt_info_max_plen) | 1319 | if (ri->prefix_len > in6_dev->cnf.accept_ra_rt_info_max_plen) |
1321 | continue; | 1320 | continue; |
1322 | rt6_route_rcv(skb->dev, (u8*)p, (p->nd_opt_len) << 3, | 1321 | rt6_route_rcv(skb->dev, (u8 *)p, (p->nd_opt_len) << 3, |
1323 | &ipv6_hdr(skb)->saddr); | 1322 | &ipv6_hdr(skb)->saddr); |
1324 | } | 1323 | } |
1325 | } | 1324 | } |
@@ -1352,7 +1351,7 @@ skip_routeinfo: | |||
1352 | __be32 n; | 1351 | __be32 n; |
1353 | u32 mtu; | 1352 | u32 mtu; |
1354 | 1353 | ||
1355 | memcpy(&n, ((u8*)(ndopts.nd_opts_mtu+1))+2, sizeof(mtu)); | 1354 | memcpy(&n, ((u8 *)(ndopts.nd_opts_mtu+1))+2, sizeof(mtu)); |
1356 | mtu = ntohl(n); | 1355 | mtu = ntohl(n); |
1357 | 1356 | ||
1358 | if (mtu < IPV6_MIN_MTU || mtu > skb->dev->mtu) { | 1357 | if (mtu < IPV6_MIN_MTU || mtu > skb->dev->mtu) { |
diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig index 2812816aabdc..6af874fc187f 100644 --- a/net/ipv6/netfilter/Kconfig +++ b/net/ipv6/netfilter/Kconfig | |||
@@ -40,18 +40,13 @@ config NFT_CHAIN_ROUTE_IPV6 | |||
40 | fields such as the source, destination, flowlabel, hop-limit and | 40 | fields such as the source, destination, flowlabel, hop-limit and |
41 | the packet mark. | 41 | the packet mark. |
42 | 42 | ||
43 | config NFT_CHAIN_NAT_IPV6 | 43 | config NF_REJECT_IPV6 |
44 | depends on NF_TABLES_IPV6 | 44 | tristate "IPv6 packet rejection" |
45 | depends on NF_NAT_IPV6 && NFT_NAT | 45 | default m if NETFILTER_ADVANCED=n |
46 | tristate "IPv6 nf_tables nat chain support" | ||
47 | help | ||
48 | This option enables the "nat" chain for IPv6 in nf_tables. This | ||
49 | chain type is used to perform Network Address Translation (NAT) | ||
50 | packet transformations such as the source, destination address and | ||
51 | source and destination ports. | ||
52 | 46 | ||
53 | config NFT_REJECT_IPV6 | 47 | config NFT_REJECT_IPV6 |
54 | depends on NF_TABLES_IPV6 | 48 | depends on NF_TABLES_IPV6 |
49 | select NF_REJECT_IPV6 | ||
55 | default NFT_REJECT | 50 | default NFT_REJECT |
56 | tristate | 51 | tristate |
57 | 52 | ||
@@ -70,6 +65,34 @@ config NF_NAT_IPV6 | |||
70 | forms of full Network Address Port Translation. This can be | 65 | forms of full Network Address Port Translation. This can be |
71 | controlled by iptables or nft. | 66 | controlled by iptables or nft. |
72 | 67 | ||
68 | if NF_NAT_IPV6 | ||
69 | |||
70 | config NFT_CHAIN_NAT_IPV6 | ||
71 | depends on NF_TABLES_IPV6 | ||
72 | tristate "IPv6 nf_tables nat chain support" | ||
73 | help | ||
74 | This option enables the "nat" chain for IPv6 in nf_tables. This | ||
75 | chain type is used to perform Network Address Translation (NAT) | ||
76 | packet transformations such as the source, destination address and | ||
77 | source and destination ports. | ||
78 | |||
79 | config NF_NAT_MASQUERADE_IPV6 | ||
80 | tristate "IPv6 masquerade support" | ||
81 | help | ||
82 | This is the kernel functionality to provide NAT in the masquerade | ||
83 | flavour (automatic source address selection) for IPv6. | ||
84 | |||
85 | config NFT_MASQ_IPV6 | ||
86 | tristate "IPv6 masquerade support for nf_tables" | ||
87 | depends on NF_TABLES_IPV6 | ||
88 | depends on NFT_MASQ | ||
89 | select NF_NAT_MASQUERADE_IPV6 | ||
90 | help | ||
91 | This is the expression that provides IPv4 masquerading support for | ||
92 | nf_tables. | ||
93 | |||
94 | endif # NF_NAT_IPV6 | ||
95 | |||
73 | config IP6_NF_IPTABLES | 96 | config IP6_NF_IPTABLES |
74 | tristate "IP6 tables support (required for filtering)" | 97 | tristate "IP6 tables support (required for filtering)" |
75 | depends on INET && IPV6 | 98 | depends on INET && IPV6 |
@@ -190,6 +213,7 @@ config IP6_NF_FILTER | |||
190 | config IP6_NF_TARGET_REJECT | 213 | config IP6_NF_TARGET_REJECT |
191 | tristate "REJECT target support" | 214 | tristate "REJECT target support" |
192 | depends on IP6_NF_FILTER | 215 | depends on IP6_NF_FILTER |
216 | select NF_REJECT_IPV6 | ||
193 | default m if NETFILTER_ADVANCED=n | 217 | default m if NETFILTER_ADVANCED=n |
194 | help | 218 | help |
195 | The REJECT target allows a filtering rule to specify that an ICMPv6 | 219 | The REJECT target allows a filtering rule to specify that an ICMPv6 |
@@ -260,6 +284,7 @@ if IP6_NF_NAT | |||
260 | 284 | ||
261 | config IP6_NF_TARGET_MASQUERADE | 285 | config IP6_NF_TARGET_MASQUERADE |
262 | tristate "MASQUERADE target support" | 286 | tristate "MASQUERADE target support" |
287 | select NF_NAT_MASQUERADE_IPV6 | ||
263 | help | 288 | help |
264 | Masquerading is a special case of NAT: all outgoing connections are | 289 | Masquerading is a special case of NAT: all outgoing connections are |
265 | changed to seem to come from a particular interface's address, and | 290 | changed to seem to come from a particular interface's address, and |
diff --git a/net/ipv6/netfilter/Makefile b/net/ipv6/netfilter/Makefile index c3d3286db4bb..fbb25f01143c 100644 --- a/net/ipv6/netfilter/Makefile +++ b/net/ipv6/netfilter/Makefile | |||
@@ -18,6 +18,7 @@ obj-$(CONFIG_NF_CONNTRACK_IPV6) += nf_conntrack_ipv6.o | |||
18 | 18 | ||
19 | nf_nat_ipv6-y := nf_nat_l3proto_ipv6.o nf_nat_proto_icmpv6.o | 19 | nf_nat_ipv6-y := nf_nat_l3proto_ipv6.o nf_nat_proto_icmpv6.o |
20 | obj-$(CONFIG_NF_NAT_IPV6) += nf_nat_ipv6.o | 20 | obj-$(CONFIG_NF_NAT_IPV6) += nf_nat_ipv6.o |
21 | obj-$(CONFIG_NF_NAT_MASQUERADE_IPV6) += nf_nat_masquerade_ipv6.o | ||
21 | 22 | ||
22 | # defrag | 23 | # defrag |
23 | nf_defrag_ipv6-y := nf_defrag_ipv6_hooks.o nf_conntrack_reasm.o | 24 | nf_defrag_ipv6-y := nf_defrag_ipv6_hooks.o nf_conntrack_reasm.o |
@@ -26,11 +27,15 @@ obj-$(CONFIG_NF_DEFRAG_IPV6) += nf_defrag_ipv6.o | |||
26 | # logging | 27 | # logging |
27 | obj-$(CONFIG_NF_LOG_IPV6) += nf_log_ipv6.o | 28 | obj-$(CONFIG_NF_LOG_IPV6) += nf_log_ipv6.o |
28 | 29 | ||
30 | # reject | ||
31 | obj-$(CONFIG_NF_REJECT_IPV6) += nf_reject_ipv6.o | ||
32 | |||
29 | # nf_tables | 33 | # nf_tables |
30 | obj-$(CONFIG_NF_TABLES_IPV6) += nf_tables_ipv6.o | 34 | obj-$(CONFIG_NF_TABLES_IPV6) += nf_tables_ipv6.o |
31 | obj-$(CONFIG_NFT_CHAIN_ROUTE_IPV6) += nft_chain_route_ipv6.o | 35 | obj-$(CONFIG_NFT_CHAIN_ROUTE_IPV6) += nft_chain_route_ipv6.o |
32 | obj-$(CONFIG_NFT_CHAIN_NAT_IPV6) += nft_chain_nat_ipv6.o | 36 | obj-$(CONFIG_NFT_CHAIN_NAT_IPV6) += nft_chain_nat_ipv6.o |
33 | obj-$(CONFIG_NFT_REJECT_IPV6) += nft_reject_ipv6.o | 37 | obj-$(CONFIG_NFT_REJECT_IPV6) += nft_reject_ipv6.o |
38 | obj-$(CONFIG_NFT_MASQ_IPV6) += nft_masq_ipv6.o | ||
34 | 39 | ||
35 | # matches | 40 | # matches |
36 | obj-$(CONFIG_IP6_NF_MATCH_AH) += ip6t_ah.o | 41 | obj-$(CONFIG_IP6_NF_MATCH_AH) += ip6t_ah.o |
diff --git a/net/ipv6/netfilter/ip6t_MASQUERADE.c b/net/ipv6/netfilter/ip6t_MASQUERADE.c index 3e4e92d5e157..7f9f45d829d2 100644 --- a/net/ipv6/netfilter/ip6t_MASQUERADE.c +++ b/net/ipv6/netfilter/ip6t_MASQUERADE.c | |||
@@ -19,33 +19,12 @@ | |||
19 | #include <net/netfilter/nf_nat.h> | 19 | #include <net/netfilter/nf_nat.h> |
20 | #include <net/addrconf.h> | 20 | #include <net/addrconf.h> |
21 | #include <net/ipv6.h> | 21 | #include <net/ipv6.h> |
22 | #include <net/netfilter/ipv6/nf_nat_masquerade.h> | ||
22 | 23 | ||
23 | static unsigned int | 24 | static unsigned int |
24 | masquerade_tg6(struct sk_buff *skb, const struct xt_action_param *par) | 25 | masquerade_tg6(struct sk_buff *skb, const struct xt_action_param *par) |
25 | { | 26 | { |
26 | const struct nf_nat_range *range = par->targinfo; | 27 | return nf_nat_masquerade_ipv6(skb, par->targinfo, par->out); |
27 | enum ip_conntrack_info ctinfo; | ||
28 | struct in6_addr src; | ||
29 | struct nf_conn *ct; | ||
30 | struct nf_nat_range newrange; | ||
31 | |||
32 | ct = nf_ct_get(skb, &ctinfo); | ||
33 | NF_CT_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED || | ||
34 | ctinfo == IP_CT_RELATED_REPLY)); | ||
35 | |||
36 | if (ipv6_dev_get_saddr(dev_net(par->out), par->out, | ||
37 | &ipv6_hdr(skb)->daddr, 0, &src) < 0) | ||
38 | return NF_DROP; | ||
39 | |||
40 | nfct_nat(ct)->masq_index = par->out->ifindex; | ||
41 | |||
42 | newrange.flags = range->flags | NF_NAT_RANGE_MAP_IPS; | ||
43 | newrange.min_addr.in6 = src; | ||
44 | newrange.max_addr.in6 = src; | ||
45 | newrange.min_proto = range->min_proto; | ||
46 | newrange.max_proto = range->max_proto; | ||
47 | |||
48 | return nf_nat_setup_info(ct, &newrange, NF_NAT_MANIP_SRC); | ||
49 | } | 28 | } |
50 | 29 | ||
51 | static int masquerade_tg6_checkentry(const struct xt_tgchk_param *par) | 30 | static int masquerade_tg6_checkentry(const struct xt_tgchk_param *par) |
@@ -57,48 +36,6 @@ static int masquerade_tg6_checkentry(const struct xt_tgchk_param *par) | |||
57 | return 0; | 36 | return 0; |
58 | } | 37 | } |
59 | 38 | ||
60 | static int device_cmp(struct nf_conn *ct, void *ifindex) | ||
61 | { | ||
62 | const struct nf_conn_nat *nat = nfct_nat(ct); | ||
63 | |||
64 | if (!nat) | ||
65 | return 0; | ||
66 | if (nf_ct_l3num(ct) != NFPROTO_IPV6) | ||
67 | return 0; | ||
68 | return nat->masq_index == (int)(long)ifindex; | ||
69 | } | ||
70 | |||
71 | static int masq_device_event(struct notifier_block *this, | ||
72 | unsigned long event, void *ptr) | ||
73 | { | ||
74 | const struct net_device *dev = netdev_notifier_info_to_dev(ptr); | ||
75 | struct net *net = dev_net(dev); | ||
76 | |||
77 | if (event == NETDEV_DOWN) | ||
78 | nf_ct_iterate_cleanup(net, device_cmp, | ||
79 | (void *)(long)dev->ifindex, 0, 0); | ||
80 | |||
81 | return NOTIFY_DONE; | ||
82 | } | ||
83 | |||
84 | static struct notifier_block masq_dev_notifier = { | ||
85 | .notifier_call = masq_device_event, | ||
86 | }; | ||
87 | |||
88 | static int masq_inet_event(struct notifier_block *this, | ||
89 | unsigned long event, void *ptr) | ||
90 | { | ||
91 | struct inet6_ifaddr *ifa = ptr; | ||
92 | struct netdev_notifier_info info; | ||
93 | |||
94 | netdev_notifier_info_init(&info, ifa->idev->dev); | ||
95 | return masq_device_event(this, event, &info); | ||
96 | } | ||
97 | |||
98 | static struct notifier_block masq_inet_notifier = { | ||
99 | .notifier_call = masq_inet_event, | ||
100 | }; | ||
101 | |||
102 | static struct xt_target masquerade_tg6_reg __read_mostly = { | 39 | static struct xt_target masquerade_tg6_reg __read_mostly = { |
103 | .name = "MASQUERADE", | 40 | .name = "MASQUERADE", |
104 | .family = NFPROTO_IPV6, | 41 | .family = NFPROTO_IPV6, |
@@ -115,17 +52,14 @@ static int __init masquerade_tg6_init(void) | |||
115 | int err; | 52 | int err; |
116 | 53 | ||
117 | err = xt_register_target(&masquerade_tg6_reg); | 54 | err = xt_register_target(&masquerade_tg6_reg); |
118 | if (err == 0) { | 55 | if (err == 0) |
119 | register_netdevice_notifier(&masq_dev_notifier); | 56 | nf_nat_masquerade_ipv6_register_notifier(); |
120 | register_inet6addr_notifier(&masq_inet_notifier); | ||
121 | } | ||
122 | 57 | ||
123 | return err; | 58 | return err; |
124 | } | 59 | } |
125 | static void __exit masquerade_tg6_exit(void) | 60 | static void __exit masquerade_tg6_exit(void) |
126 | { | 61 | { |
127 | unregister_inet6addr_notifier(&masq_inet_notifier); | 62 | nf_nat_masquerade_ipv6_unregister_notifier(); |
128 | unregister_netdevice_notifier(&masq_dev_notifier); | ||
129 | xt_unregister_target(&masquerade_tg6_reg); | 63 | xt_unregister_target(&masquerade_tg6_reg); |
130 | } | 64 | } |
131 | 65 | ||
diff --git a/net/ipv6/netfilter/ip6table_nat.c b/net/ipv6/netfilter/ip6table_nat.c index 387d8b8fc18d..b0634ac996b7 100644 --- a/net/ipv6/netfilter/ip6table_nat.c +++ b/net/ipv6/netfilter/ip6table_nat.c | |||
@@ -30,222 +30,57 @@ static const struct xt_table nf_nat_ipv6_table = { | |||
30 | .af = NFPROTO_IPV6, | 30 | .af = NFPROTO_IPV6, |
31 | }; | 31 | }; |
32 | 32 | ||
33 | static unsigned int alloc_null_binding(struct nf_conn *ct, unsigned int hooknum) | 33 | static unsigned int ip6table_nat_do_chain(const struct nf_hook_ops *ops, |
34 | { | 34 | struct sk_buff *skb, |
35 | /* Force range to this IP; let proto decide mapping for | 35 | const struct net_device *in, |
36 | * per-proto parts (hence not IP_NAT_RANGE_PROTO_SPECIFIED). | 36 | const struct net_device *out, |
37 | */ | 37 | struct nf_conn *ct) |
38 | struct nf_nat_range range; | ||
39 | |||
40 | range.flags = 0; | ||
41 | pr_debug("Allocating NULL binding for %p (%pI6)\n", ct, | ||
42 | HOOK2MANIP(hooknum) == NF_NAT_MANIP_SRC ? | ||
43 | &ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip6 : | ||
44 | &ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip6); | ||
45 | |||
46 | return nf_nat_setup_info(ct, &range, HOOK2MANIP(hooknum)); | ||
47 | } | ||
48 | |||
49 | static unsigned int nf_nat_rule_find(struct sk_buff *skb, unsigned int hooknum, | ||
50 | const struct net_device *in, | ||
51 | const struct net_device *out, | ||
52 | struct nf_conn *ct) | ||
53 | { | 38 | { |
54 | struct net *net = nf_ct_net(ct); | 39 | struct net *net = nf_ct_net(ct); |
55 | unsigned int ret; | ||
56 | 40 | ||
57 | ret = ip6t_do_table(skb, hooknum, in, out, net->ipv6.ip6table_nat); | 41 | return ip6t_do_table(skb, ops->hooknum, in, out, net->ipv6.ip6table_nat); |
58 | if (ret == NF_ACCEPT) { | ||
59 | if (!nf_nat_initialized(ct, HOOK2MANIP(hooknum))) | ||
60 | ret = alloc_null_binding(ct, hooknum); | ||
61 | } | ||
62 | return ret; | ||
63 | } | 42 | } |
64 | 43 | ||
65 | static unsigned int | 44 | static unsigned int ip6table_nat_fn(const struct nf_hook_ops *ops, |
66 | nf_nat_ipv6_fn(const struct nf_hook_ops *ops, | 45 | struct sk_buff *skb, |
67 | struct sk_buff *skb, | 46 | const struct net_device *in, |
68 | const struct net_device *in, | 47 | const struct net_device *out, |
69 | const struct net_device *out, | 48 | int (*okfn)(struct sk_buff *)) |
70 | int (*okfn)(struct sk_buff *)) | ||
71 | { | 49 | { |
72 | struct nf_conn *ct; | 50 | return nf_nat_ipv6_fn(ops, skb, in, out, ip6table_nat_do_chain); |
73 | enum ip_conntrack_info ctinfo; | ||
74 | struct nf_conn_nat *nat; | ||
75 | enum nf_nat_manip_type maniptype = HOOK2MANIP(ops->hooknum); | ||
76 | __be16 frag_off; | ||
77 | int hdrlen; | ||
78 | u8 nexthdr; | ||
79 | |||
80 | ct = nf_ct_get(skb, &ctinfo); | ||
81 | /* Can't track? It's not due to stress, or conntrack would | ||
82 | * have dropped it. Hence it's the user's responsibilty to | ||
83 | * packet filter it out, or implement conntrack/NAT for that | ||
84 | * protocol. 8) --RR | ||
85 | */ | ||
86 | if (!ct) | ||
87 | return NF_ACCEPT; | ||
88 | |||
89 | /* Don't try to NAT if this packet is not conntracked */ | ||
90 | if (nf_ct_is_untracked(ct)) | ||
91 | return NF_ACCEPT; | ||
92 | |||
93 | nat = nf_ct_nat_ext_add(ct); | ||
94 | if (nat == NULL) | ||
95 | return NF_ACCEPT; | ||
96 | |||
97 | switch (ctinfo) { | ||
98 | case IP_CT_RELATED: | ||
99 | case IP_CT_RELATED_REPLY: | ||
100 | nexthdr = ipv6_hdr(skb)->nexthdr; | ||
101 | hdrlen = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), | ||
102 | &nexthdr, &frag_off); | ||
103 | |||
104 | if (hdrlen >= 0 && nexthdr == IPPROTO_ICMPV6) { | ||
105 | if (!nf_nat_icmpv6_reply_translation(skb, ct, ctinfo, | ||
106 | ops->hooknum, | ||
107 | hdrlen)) | ||
108 | return NF_DROP; | ||
109 | else | ||
110 | return NF_ACCEPT; | ||
111 | } | ||
112 | /* Fall thru... (Only ICMPs can be IP_CT_IS_REPLY) */ | ||
113 | case IP_CT_NEW: | ||
114 | /* Seen it before? This can happen for loopback, retrans, | ||
115 | * or local packets. | ||
116 | */ | ||
117 | if (!nf_nat_initialized(ct, maniptype)) { | ||
118 | unsigned int ret; | ||
119 | |||
120 | ret = nf_nat_rule_find(skb, ops->hooknum, in, out, ct); | ||
121 | if (ret != NF_ACCEPT) | ||
122 | return ret; | ||
123 | } else { | ||
124 | pr_debug("Already setup manip %s for ct %p\n", | ||
125 | maniptype == NF_NAT_MANIP_SRC ? "SRC" : "DST", | ||
126 | ct); | ||
127 | if (nf_nat_oif_changed(ops->hooknum, ctinfo, nat, out)) | ||
128 | goto oif_changed; | ||
129 | } | ||
130 | break; | ||
131 | |||
132 | default: | ||
133 | /* ESTABLISHED */ | ||
134 | NF_CT_ASSERT(ctinfo == IP_CT_ESTABLISHED || | ||
135 | ctinfo == IP_CT_ESTABLISHED_REPLY); | ||
136 | if (nf_nat_oif_changed(ops->hooknum, ctinfo, nat, out)) | ||
137 | goto oif_changed; | ||
138 | } | ||
139 | |||
140 | return nf_nat_packet(ct, ctinfo, ops->hooknum, skb); | ||
141 | |||
142 | oif_changed: | ||
143 | nf_ct_kill_acct(ct, ctinfo, skb); | ||
144 | return NF_DROP; | ||
145 | } | 51 | } |
146 | 52 | ||
147 | static unsigned int | 53 | static unsigned int ip6table_nat_in(const struct nf_hook_ops *ops, |
148 | nf_nat_ipv6_in(const struct nf_hook_ops *ops, | 54 | struct sk_buff *skb, |
149 | struct sk_buff *skb, | 55 | const struct net_device *in, |
150 | const struct net_device *in, | 56 | const struct net_device *out, |
151 | const struct net_device *out, | 57 | int (*okfn)(struct sk_buff *)) |
152 | int (*okfn)(struct sk_buff *)) | ||
153 | { | 58 | { |
154 | unsigned int ret; | 59 | return nf_nat_ipv6_in(ops, skb, in, out, ip6table_nat_do_chain); |
155 | struct in6_addr daddr = ipv6_hdr(skb)->daddr; | ||
156 | |||
157 | ret = nf_nat_ipv6_fn(ops, skb, in, out, okfn); | ||
158 | if (ret != NF_DROP && ret != NF_STOLEN && | ||
159 | ipv6_addr_cmp(&daddr, &ipv6_hdr(skb)->daddr)) | ||
160 | skb_dst_drop(skb); | ||
161 | |||
162 | return ret; | ||
163 | } | 60 | } |
164 | 61 | ||
165 | static unsigned int | 62 | static unsigned int ip6table_nat_out(const struct nf_hook_ops *ops, |
166 | nf_nat_ipv6_out(const struct nf_hook_ops *ops, | 63 | struct sk_buff *skb, |
167 | struct sk_buff *skb, | 64 | const struct net_device *in, |
168 | const struct net_device *in, | 65 | const struct net_device *out, |
169 | const struct net_device *out, | 66 | int (*okfn)(struct sk_buff *)) |
170 | int (*okfn)(struct sk_buff *)) | ||
171 | { | 67 | { |
172 | #ifdef CONFIG_XFRM | 68 | return nf_nat_ipv6_out(ops, skb, in, out, ip6table_nat_do_chain); |
173 | const struct nf_conn *ct; | ||
174 | enum ip_conntrack_info ctinfo; | ||
175 | int err; | ||
176 | #endif | ||
177 | unsigned int ret; | ||
178 | |||
179 | /* root is playing with raw sockets. */ | ||
180 | if (skb->len < sizeof(struct ipv6hdr)) | ||
181 | return NF_ACCEPT; | ||
182 | |||
183 | ret = nf_nat_ipv6_fn(ops, skb, in, out, okfn); | ||
184 | #ifdef CONFIG_XFRM | ||
185 | if (ret != NF_DROP && ret != NF_STOLEN && | ||
186 | !(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) && | ||
187 | (ct = nf_ct_get(skb, &ctinfo)) != NULL) { | ||
188 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); | ||
189 | |||
190 | if (!nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.src.u3, | ||
191 | &ct->tuplehash[!dir].tuple.dst.u3) || | ||
192 | (ct->tuplehash[dir].tuple.dst.protonum != IPPROTO_ICMPV6 && | ||
193 | ct->tuplehash[dir].tuple.src.u.all != | ||
194 | ct->tuplehash[!dir].tuple.dst.u.all)) { | ||
195 | err = nf_xfrm_me_harder(skb, AF_INET6); | ||
196 | if (err < 0) | ||
197 | ret = NF_DROP_ERR(err); | ||
198 | } | ||
199 | } | ||
200 | #endif | ||
201 | return ret; | ||
202 | } | 69 | } |
203 | 70 | ||
204 | static unsigned int | 71 | static unsigned int ip6table_nat_local_fn(const struct nf_hook_ops *ops, |
205 | nf_nat_ipv6_local_fn(const struct nf_hook_ops *ops, | 72 | struct sk_buff *skb, |
206 | struct sk_buff *skb, | 73 | const struct net_device *in, |
207 | const struct net_device *in, | 74 | const struct net_device *out, |
208 | const struct net_device *out, | 75 | int (*okfn)(struct sk_buff *)) |
209 | int (*okfn)(struct sk_buff *)) | ||
210 | { | 76 | { |
211 | const struct nf_conn *ct; | 77 | return nf_nat_ipv6_local_fn(ops, skb, in, out, ip6table_nat_do_chain); |
212 | enum ip_conntrack_info ctinfo; | ||
213 | unsigned int ret; | ||
214 | int err; | ||
215 | |||
216 | /* root is playing with raw sockets. */ | ||
217 | if (skb->len < sizeof(struct ipv6hdr)) | ||
218 | return NF_ACCEPT; | ||
219 | |||
220 | ret = nf_nat_ipv6_fn(ops, skb, in, out, okfn); | ||
221 | if (ret != NF_DROP && ret != NF_STOLEN && | ||
222 | (ct = nf_ct_get(skb, &ctinfo)) != NULL) { | ||
223 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); | ||
224 | |||
225 | if (!nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.dst.u3, | ||
226 | &ct->tuplehash[!dir].tuple.src.u3)) { | ||
227 | err = ip6_route_me_harder(skb); | ||
228 | if (err < 0) | ||
229 | ret = NF_DROP_ERR(err); | ||
230 | } | ||
231 | #ifdef CONFIG_XFRM | ||
232 | else if (!(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) && | ||
233 | ct->tuplehash[dir].tuple.dst.protonum != IPPROTO_ICMPV6 && | ||
234 | ct->tuplehash[dir].tuple.dst.u.all != | ||
235 | ct->tuplehash[!dir].tuple.src.u.all) { | ||
236 | err = nf_xfrm_me_harder(skb, AF_INET6); | ||
237 | if (err < 0) | ||
238 | ret = NF_DROP_ERR(err); | ||
239 | } | ||
240 | #endif | ||
241 | } | ||
242 | return ret; | ||
243 | } | 78 | } |
244 | 79 | ||
245 | static struct nf_hook_ops nf_nat_ipv6_ops[] __read_mostly = { | 80 | static struct nf_hook_ops nf_nat_ipv6_ops[] __read_mostly = { |
246 | /* Before packet filtering, change destination */ | 81 | /* Before packet filtering, change destination */ |
247 | { | 82 | { |
248 | .hook = nf_nat_ipv6_in, | 83 | .hook = ip6table_nat_in, |
249 | .owner = THIS_MODULE, | 84 | .owner = THIS_MODULE, |
250 | .pf = NFPROTO_IPV6, | 85 | .pf = NFPROTO_IPV6, |
251 | .hooknum = NF_INET_PRE_ROUTING, | 86 | .hooknum = NF_INET_PRE_ROUTING, |
@@ -253,7 +88,7 @@ static struct nf_hook_ops nf_nat_ipv6_ops[] __read_mostly = { | |||
253 | }, | 88 | }, |
254 | /* After packet filtering, change source */ | 89 | /* After packet filtering, change source */ |
255 | { | 90 | { |
256 | .hook = nf_nat_ipv6_out, | 91 | .hook = ip6table_nat_out, |
257 | .owner = THIS_MODULE, | 92 | .owner = THIS_MODULE, |
258 | .pf = NFPROTO_IPV6, | 93 | .pf = NFPROTO_IPV6, |
259 | .hooknum = NF_INET_POST_ROUTING, | 94 | .hooknum = NF_INET_POST_ROUTING, |
@@ -261,7 +96,7 @@ static struct nf_hook_ops nf_nat_ipv6_ops[] __read_mostly = { | |||
261 | }, | 96 | }, |
262 | /* Before packet filtering, change destination */ | 97 | /* Before packet filtering, change destination */ |
263 | { | 98 | { |
264 | .hook = nf_nat_ipv6_local_fn, | 99 | .hook = ip6table_nat_local_fn, |
265 | .owner = THIS_MODULE, | 100 | .owner = THIS_MODULE, |
266 | .pf = NFPROTO_IPV6, | 101 | .pf = NFPROTO_IPV6, |
267 | .hooknum = NF_INET_LOCAL_OUT, | 102 | .hooknum = NF_INET_LOCAL_OUT, |
@@ -269,7 +104,7 @@ static struct nf_hook_ops nf_nat_ipv6_ops[] __read_mostly = { | |||
269 | }, | 104 | }, |
270 | /* After packet filtering, change source */ | 105 | /* After packet filtering, change source */ |
271 | { | 106 | { |
272 | .hook = nf_nat_ipv6_fn, | 107 | .hook = ip6table_nat_fn, |
273 | .owner = THIS_MODULE, | 108 | .owner = THIS_MODULE, |
274 | .pf = NFPROTO_IPV6, | 109 | .pf = NFPROTO_IPV6, |
275 | .hooknum = NF_INET_LOCAL_IN, | 110 | .hooknum = NF_INET_LOCAL_IN, |
diff --git a/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c b/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c index 7b9a748c6bac..e70382e4dfb5 100644 --- a/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c +++ b/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c | |||
@@ -40,7 +40,7 @@ static enum ip6_defrag_users nf_ct6_defrag_user(unsigned int hooknum, | |||
40 | zone = nf_ct_zone((struct nf_conn *)skb->nfct); | 40 | zone = nf_ct_zone((struct nf_conn *)skb->nfct); |
41 | #endif | 41 | #endif |
42 | 42 | ||
43 | #ifdef CONFIG_BRIDGE_NETFILTER | 43 | #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) |
44 | if (skb->nf_bridge && | 44 | if (skb->nf_bridge && |
45 | skb->nf_bridge->mask & BRNF_NF_BRIDGE_PREROUTING) | 45 | skb->nf_bridge->mask & BRNF_NF_BRIDGE_PREROUTING) |
46 | return IP6_DEFRAG_CONNTRACK_BRIDGE_IN + zone; | 46 | return IP6_DEFRAG_CONNTRACK_BRIDGE_IN + zone; |
diff --git a/net/ipv6/netfilter/nf_nat_l3proto_ipv6.c b/net/ipv6/netfilter/nf_nat_l3proto_ipv6.c index fc8e49b2ff3e..c5812e1c1ffb 100644 --- a/net/ipv6/netfilter/nf_nat_l3proto_ipv6.c +++ b/net/ipv6/netfilter/nf_nat_l3proto_ipv6.c | |||
@@ -261,6 +261,205 @@ int nf_nat_icmpv6_reply_translation(struct sk_buff *skb, | |||
261 | } | 261 | } |
262 | EXPORT_SYMBOL_GPL(nf_nat_icmpv6_reply_translation); | 262 | EXPORT_SYMBOL_GPL(nf_nat_icmpv6_reply_translation); |
263 | 263 | ||
264 | unsigned int | ||
265 | nf_nat_ipv6_fn(const struct nf_hook_ops *ops, struct sk_buff *skb, | ||
266 | const struct net_device *in, const struct net_device *out, | ||
267 | unsigned int (*do_chain)(const struct nf_hook_ops *ops, | ||
268 | struct sk_buff *skb, | ||
269 | const struct net_device *in, | ||
270 | const struct net_device *out, | ||
271 | struct nf_conn *ct)) | ||
272 | { | ||
273 | struct nf_conn *ct; | ||
274 | enum ip_conntrack_info ctinfo; | ||
275 | struct nf_conn_nat *nat; | ||
276 | enum nf_nat_manip_type maniptype = HOOK2MANIP(ops->hooknum); | ||
277 | __be16 frag_off; | ||
278 | int hdrlen; | ||
279 | u8 nexthdr; | ||
280 | |||
281 | ct = nf_ct_get(skb, &ctinfo); | ||
282 | /* Can't track? It's not due to stress, or conntrack would | ||
283 | * have dropped it. Hence it's the user's responsibilty to | ||
284 | * packet filter it out, or implement conntrack/NAT for that | ||
285 | * protocol. 8) --RR | ||
286 | */ | ||
287 | if (!ct) | ||
288 | return NF_ACCEPT; | ||
289 | |||
290 | /* Don't try to NAT if this packet is not conntracked */ | ||
291 | if (nf_ct_is_untracked(ct)) | ||
292 | return NF_ACCEPT; | ||
293 | |||
294 | nat = nf_ct_nat_ext_add(ct); | ||
295 | if (nat == NULL) | ||
296 | return NF_ACCEPT; | ||
297 | |||
298 | switch (ctinfo) { | ||
299 | case IP_CT_RELATED: | ||
300 | case IP_CT_RELATED_REPLY: | ||
301 | nexthdr = ipv6_hdr(skb)->nexthdr; | ||
302 | hdrlen = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), | ||
303 | &nexthdr, &frag_off); | ||
304 | |||
305 | if (hdrlen >= 0 && nexthdr == IPPROTO_ICMPV6) { | ||
306 | if (!nf_nat_icmpv6_reply_translation(skb, ct, ctinfo, | ||
307 | ops->hooknum, | ||
308 | hdrlen)) | ||
309 | return NF_DROP; | ||
310 | else | ||
311 | return NF_ACCEPT; | ||
312 | } | ||
313 | /* Fall thru... (Only ICMPs can be IP_CT_IS_REPLY) */ | ||
314 | case IP_CT_NEW: | ||
315 | /* Seen it before? This can happen for loopback, retrans, | ||
316 | * or local packets. | ||
317 | */ | ||
318 | if (!nf_nat_initialized(ct, maniptype)) { | ||
319 | unsigned int ret; | ||
320 | |||
321 | ret = do_chain(ops, skb, in, out, ct); | ||
322 | if (ret != NF_ACCEPT) | ||
323 | return ret; | ||
324 | |||
325 | if (nf_nat_initialized(ct, HOOK2MANIP(ops->hooknum))) | ||
326 | break; | ||
327 | |||
328 | ret = nf_nat_alloc_null_binding(ct, ops->hooknum); | ||
329 | if (ret != NF_ACCEPT) | ||
330 | return ret; | ||
331 | } else { | ||
332 | pr_debug("Already setup manip %s for ct %p\n", | ||
333 | maniptype == NF_NAT_MANIP_SRC ? "SRC" : "DST", | ||
334 | ct); | ||
335 | if (nf_nat_oif_changed(ops->hooknum, ctinfo, nat, out)) | ||
336 | goto oif_changed; | ||
337 | } | ||
338 | break; | ||
339 | |||
340 | default: | ||
341 | /* ESTABLISHED */ | ||
342 | NF_CT_ASSERT(ctinfo == IP_CT_ESTABLISHED || | ||
343 | ctinfo == IP_CT_ESTABLISHED_REPLY); | ||
344 | if (nf_nat_oif_changed(ops->hooknum, ctinfo, nat, out)) | ||
345 | goto oif_changed; | ||
346 | } | ||
347 | |||
348 | return nf_nat_packet(ct, ctinfo, ops->hooknum, skb); | ||
349 | |||
350 | oif_changed: | ||
351 | nf_ct_kill_acct(ct, ctinfo, skb); | ||
352 | return NF_DROP; | ||
353 | } | ||
354 | EXPORT_SYMBOL_GPL(nf_nat_ipv6_fn); | ||
355 | |||
356 | unsigned int | ||
357 | nf_nat_ipv6_in(const struct nf_hook_ops *ops, struct sk_buff *skb, | ||
358 | const struct net_device *in, const struct net_device *out, | ||
359 | unsigned int (*do_chain)(const struct nf_hook_ops *ops, | ||
360 | struct sk_buff *skb, | ||
361 | const struct net_device *in, | ||
362 | const struct net_device *out, | ||
363 | struct nf_conn *ct)) | ||
364 | { | ||
365 | unsigned int ret; | ||
366 | struct in6_addr daddr = ipv6_hdr(skb)->daddr; | ||
367 | |||
368 | ret = nf_nat_ipv6_fn(ops, skb, in, out, do_chain); | ||
369 | if (ret != NF_DROP && ret != NF_STOLEN && | ||
370 | ipv6_addr_cmp(&daddr, &ipv6_hdr(skb)->daddr)) | ||
371 | skb_dst_drop(skb); | ||
372 | |||
373 | return ret; | ||
374 | } | ||
375 | EXPORT_SYMBOL_GPL(nf_nat_ipv6_in); | ||
376 | |||
377 | unsigned int | ||
378 | nf_nat_ipv6_out(const struct nf_hook_ops *ops, struct sk_buff *skb, | ||
379 | const struct net_device *in, const struct net_device *out, | ||
380 | unsigned int (*do_chain)(const struct nf_hook_ops *ops, | ||
381 | struct sk_buff *skb, | ||
382 | const struct net_device *in, | ||
383 | const struct net_device *out, | ||
384 | struct nf_conn *ct)) | ||
385 | { | ||
386 | #ifdef CONFIG_XFRM | ||
387 | const struct nf_conn *ct; | ||
388 | enum ip_conntrack_info ctinfo; | ||
389 | int err; | ||
390 | #endif | ||
391 | unsigned int ret; | ||
392 | |||
393 | /* root is playing with raw sockets. */ | ||
394 | if (skb->len < sizeof(struct ipv6hdr)) | ||
395 | return NF_ACCEPT; | ||
396 | |||
397 | ret = nf_nat_ipv6_fn(ops, skb, in, out, do_chain); | ||
398 | #ifdef CONFIG_XFRM | ||
399 | if (ret != NF_DROP && ret != NF_STOLEN && | ||
400 | !(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) && | ||
401 | (ct = nf_ct_get(skb, &ctinfo)) != NULL) { | ||
402 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); | ||
403 | |||
404 | if (!nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.src.u3, | ||
405 | &ct->tuplehash[!dir].tuple.dst.u3) || | ||
406 | (ct->tuplehash[dir].tuple.dst.protonum != IPPROTO_ICMPV6 && | ||
407 | ct->tuplehash[dir].tuple.src.u.all != | ||
408 | ct->tuplehash[!dir].tuple.dst.u.all)) { | ||
409 | err = nf_xfrm_me_harder(skb, AF_INET6); | ||
410 | if (err < 0) | ||
411 | ret = NF_DROP_ERR(err); | ||
412 | } | ||
413 | } | ||
414 | #endif | ||
415 | return ret; | ||
416 | } | ||
417 | EXPORT_SYMBOL_GPL(nf_nat_ipv6_out); | ||
418 | |||
419 | unsigned int | ||
420 | nf_nat_ipv6_local_fn(const struct nf_hook_ops *ops, struct sk_buff *skb, | ||
421 | const struct net_device *in, const struct net_device *out, | ||
422 | unsigned int (*do_chain)(const struct nf_hook_ops *ops, | ||
423 | struct sk_buff *skb, | ||
424 | const struct net_device *in, | ||
425 | const struct net_device *out, | ||
426 | struct nf_conn *ct)) | ||
427 | { | ||
428 | const struct nf_conn *ct; | ||
429 | enum ip_conntrack_info ctinfo; | ||
430 | unsigned int ret; | ||
431 | int err; | ||
432 | |||
433 | /* root is playing with raw sockets. */ | ||
434 | if (skb->len < sizeof(struct ipv6hdr)) | ||
435 | return NF_ACCEPT; | ||
436 | |||
437 | ret = nf_nat_ipv6_fn(ops, skb, in, out, do_chain); | ||
438 | if (ret != NF_DROP && ret != NF_STOLEN && | ||
439 | (ct = nf_ct_get(skb, &ctinfo)) != NULL) { | ||
440 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); | ||
441 | |||
442 | if (!nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.dst.u3, | ||
443 | &ct->tuplehash[!dir].tuple.src.u3)) { | ||
444 | err = ip6_route_me_harder(skb); | ||
445 | if (err < 0) | ||
446 | ret = NF_DROP_ERR(err); | ||
447 | } | ||
448 | #ifdef CONFIG_XFRM | ||
449 | else if (!(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) && | ||
450 | ct->tuplehash[dir].tuple.dst.protonum != IPPROTO_ICMPV6 && | ||
451 | ct->tuplehash[dir].tuple.dst.u.all != | ||
452 | ct->tuplehash[!dir].tuple.src.u.all) { | ||
453 | err = nf_xfrm_me_harder(skb, AF_INET6); | ||
454 | if (err < 0) | ||
455 | ret = NF_DROP_ERR(err); | ||
456 | } | ||
457 | #endif | ||
458 | } | ||
459 | return ret; | ||
460 | } | ||
461 | EXPORT_SYMBOL_GPL(nf_nat_ipv6_local_fn); | ||
462 | |||
264 | static int __init nf_nat_l3proto_ipv6_init(void) | 463 | static int __init nf_nat_l3proto_ipv6_init(void) |
265 | { | 464 | { |
266 | int err; | 465 | int err; |
diff --git a/net/ipv6/netfilter/nf_nat_masquerade_ipv6.c b/net/ipv6/netfilter/nf_nat_masquerade_ipv6.c new file mode 100644 index 000000000000..7745609665cd --- /dev/null +++ b/net/ipv6/netfilter/nf_nat_masquerade_ipv6.c | |||
@@ -0,0 +1,120 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2011 Patrick McHardy <kaber@trash.net> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | * | ||
8 | * Based on Rusty Russell's IPv6 MASQUERADE target. Development of IPv6 | ||
9 | * NAT funded by Astaro. | ||
10 | */ | ||
11 | |||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/atomic.h> | ||
15 | #include <linux/netdevice.h> | ||
16 | #include <linux/ipv6.h> | ||
17 | #include <linux/netfilter.h> | ||
18 | #include <linux/netfilter_ipv6.h> | ||
19 | #include <net/netfilter/nf_nat.h> | ||
20 | #include <net/addrconf.h> | ||
21 | #include <net/ipv6.h> | ||
22 | #include <net/netfilter/ipv6/nf_nat_masquerade.h> | ||
23 | |||
24 | unsigned int | ||
25 | nf_nat_masquerade_ipv6(struct sk_buff *skb, const struct nf_nat_range *range, | ||
26 | const struct net_device *out) | ||
27 | { | ||
28 | enum ip_conntrack_info ctinfo; | ||
29 | struct in6_addr src; | ||
30 | struct nf_conn *ct; | ||
31 | struct nf_nat_range newrange; | ||
32 | |||
33 | ct = nf_ct_get(skb, &ctinfo); | ||
34 | NF_CT_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED || | ||
35 | ctinfo == IP_CT_RELATED_REPLY)); | ||
36 | |||
37 | if (ipv6_dev_get_saddr(dev_net(out), out, | ||
38 | &ipv6_hdr(skb)->daddr, 0, &src) < 0) | ||
39 | return NF_DROP; | ||
40 | |||
41 | nfct_nat(ct)->masq_index = out->ifindex; | ||
42 | |||
43 | newrange.flags = range->flags | NF_NAT_RANGE_MAP_IPS; | ||
44 | newrange.min_addr.in6 = src; | ||
45 | newrange.max_addr.in6 = src; | ||
46 | newrange.min_proto = range->min_proto; | ||
47 | newrange.max_proto = range->max_proto; | ||
48 | |||
49 | return nf_nat_setup_info(ct, &newrange, NF_NAT_MANIP_SRC); | ||
50 | } | ||
51 | EXPORT_SYMBOL_GPL(nf_nat_masquerade_ipv6); | ||
52 | |||
53 | static int device_cmp(struct nf_conn *ct, void *ifindex) | ||
54 | { | ||
55 | const struct nf_conn_nat *nat = nfct_nat(ct); | ||
56 | |||
57 | if (!nat) | ||
58 | return 0; | ||
59 | if (nf_ct_l3num(ct) != NFPROTO_IPV6) | ||
60 | return 0; | ||
61 | return nat->masq_index == (int)(long)ifindex; | ||
62 | } | ||
63 | |||
64 | static int masq_device_event(struct notifier_block *this, | ||
65 | unsigned long event, void *ptr) | ||
66 | { | ||
67 | const struct net_device *dev = netdev_notifier_info_to_dev(ptr); | ||
68 | struct net *net = dev_net(dev); | ||
69 | |||
70 | if (event == NETDEV_DOWN) | ||
71 | nf_ct_iterate_cleanup(net, device_cmp, | ||
72 | (void *)(long)dev->ifindex, 0, 0); | ||
73 | |||
74 | return NOTIFY_DONE; | ||
75 | } | ||
76 | |||
77 | static struct notifier_block masq_dev_notifier = { | ||
78 | .notifier_call = masq_device_event, | ||
79 | }; | ||
80 | |||
81 | static int masq_inet_event(struct notifier_block *this, | ||
82 | unsigned long event, void *ptr) | ||
83 | { | ||
84 | struct inet6_ifaddr *ifa = ptr; | ||
85 | struct netdev_notifier_info info; | ||
86 | |||
87 | netdev_notifier_info_init(&info, ifa->idev->dev); | ||
88 | return masq_device_event(this, event, &info); | ||
89 | } | ||
90 | |||
91 | static struct notifier_block masq_inet_notifier = { | ||
92 | .notifier_call = masq_inet_event, | ||
93 | }; | ||
94 | |||
95 | static atomic_t masquerade_notifier_refcount = ATOMIC_INIT(0); | ||
96 | |||
97 | void nf_nat_masquerade_ipv6_register_notifier(void) | ||
98 | { | ||
99 | /* check if the notifier is already set */ | ||
100 | if (atomic_inc_return(&masquerade_notifier_refcount) > 1) | ||
101 | return; | ||
102 | |||
103 | register_netdevice_notifier(&masq_dev_notifier); | ||
104 | register_inet6addr_notifier(&masq_inet_notifier); | ||
105 | } | ||
106 | EXPORT_SYMBOL_GPL(nf_nat_masquerade_ipv6_register_notifier); | ||
107 | |||
108 | void nf_nat_masquerade_ipv6_unregister_notifier(void) | ||
109 | { | ||
110 | /* check if the notifier still has clients */ | ||
111 | if (atomic_dec_return(&masquerade_notifier_refcount) > 0) | ||
112 | return; | ||
113 | |||
114 | unregister_inet6addr_notifier(&masq_inet_notifier); | ||
115 | unregister_netdevice_notifier(&masq_dev_notifier); | ||
116 | } | ||
117 | EXPORT_SYMBOL_GPL(nf_nat_masquerade_ipv6_unregister_notifier); | ||
118 | |||
119 | MODULE_LICENSE("GPL"); | ||
120 | MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>"); | ||
diff --git a/net/ipv6/netfilter/nf_reject_ipv6.c b/net/ipv6/netfilter/nf_reject_ipv6.c new file mode 100644 index 000000000000..5f5f0438d74d --- /dev/null +++ b/net/ipv6/netfilter/nf_reject_ipv6.c | |||
@@ -0,0 +1,163 @@ | |||
1 | /* (C) 1999-2001 Paul `Rusty' Russell | ||
2 | * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | #include <net/ipv6.h> | ||
9 | #include <net/ip6_route.h> | ||
10 | #include <net/ip6_fib.h> | ||
11 | #include <net/ip6_checksum.h> | ||
12 | #include <linux/netfilter_ipv6.h> | ||
13 | |||
14 | void nf_send_reset6(struct net *net, struct sk_buff *oldskb, int hook) | ||
15 | { | ||
16 | struct sk_buff *nskb; | ||
17 | struct tcphdr otcph, *tcph; | ||
18 | unsigned int otcplen, hh_len; | ||
19 | int tcphoff, needs_ack; | ||
20 | const struct ipv6hdr *oip6h = ipv6_hdr(oldskb); | ||
21 | struct ipv6hdr *ip6h; | ||
22 | #define DEFAULT_TOS_VALUE 0x0U | ||
23 | const __u8 tclass = DEFAULT_TOS_VALUE; | ||
24 | struct dst_entry *dst = NULL; | ||
25 | u8 proto; | ||
26 | __be16 frag_off; | ||
27 | struct flowi6 fl6; | ||
28 | |||
29 | if ((!(ipv6_addr_type(&oip6h->saddr) & IPV6_ADDR_UNICAST)) || | ||
30 | (!(ipv6_addr_type(&oip6h->daddr) & IPV6_ADDR_UNICAST))) { | ||
31 | pr_debug("addr is not unicast.\n"); | ||
32 | return; | ||
33 | } | ||
34 | |||
35 | proto = oip6h->nexthdr; | ||
36 | tcphoff = ipv6_skip_exthdr(oldskb, ((u8*)(oip6h+1) - oldskb->data), &proto, &frag_off); | ||
37 | |||
38 | if ((tcphoff < 0) || (tcphoff > oldskb->len)) { | ||
39 | pr_debug("Cannot get TCP header.\n"); | ||
40 | return; | ||
41 | } | ||
42 | |||
43 | otcplen = oldskb->len - tcphoff; | ||
44 | |||
45 | /* IP header checks: fragment, too short. */ | ||
46 | if (proto != IPPROTO_TCP || otcplen < sizeof(struct tcphdr)) { | ||
47 | pr_debug("proto(%d) != IPPROTO_TCP, " | ||
48 | "or too short. otcplen = %d\n", | ||
49 | proto, otcplen); | ||
50 | return; | ||
51 | } | ||
52 | |||
53 | if (skb_copy_bits(oldskb, tcphoff, &otcph, sizeof(struct tcphdr))) | ||
54 | BUG(); | ||
55 | |||
56 | /* No RST for RST. */ | ||
57 | if (otcph.rst) { | ||
58 | pr_debug("RST is set\n"); | ||
59 | return; | ||
60 | } | ||
61 | |||
62 | /* Check checksum. */ | ||
63 | if (nf_ip6_checksum(oldskb, hook, tcphoff, IPPROTO_TCP)) { | ||
64 | pr_debug("TCP checksum is invalid\n"); | ||
65 | return; | ||
66 | } | ||
67 | |||
68 | memset(&fl6, 0, sizeof(fl6)); | ||
69 | fl6.flowi6_proto = IPPROTO_TCP; | ||
70 | fl6.saddr = oip6h->daddr; | ||
71 | fl6.daddr = oip6h->saddr; | ||
72 | fl6.fl6_sport = otcph.dest; | ||
73 | fl6.fl6_dport = otcph.source; | ||
74 | security_skb_classify_flow(oldskb, flowi6_to_flowi(&fl6)); | ||
75 | dst = ip6_route_output(net, NULL, &fl6); | ||
76 | if (dst == NULL || dst->error) { | ||
77 | dst_release(dst); | ||
78 | return; | ||
79 | } | ||
80 | dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), NULL, 0); | ||
81 | if (IS_ERR(dst)) | ||
82 | return; | ||
83 | |||
84 | hh_len = (dst->dev->hard_header_len + 15)&~15; | ||
85 | nskb = alloc_skb(hh_len + 15 + dst->header_len + sizeof(struct ipv6hdr) | ||
86 | + sizeof(struct tcphdr) + dst->trailer_len, | ||
87 | GFP_ATOMIC); | ||
88 | |||
89 | if (!nskb) { | ||
90 | net_dbg_ratelimited("cannot alloc skb\n"); | ||
91 | dst_release(dst); | ||
92 | return; | ||
93 | } | ||
94 | |||
95 | skb_dst_set(nskb, dst); | ||
96 | |||
97 | skb_reserve(nskb, hh_len + dst->header_len); | ||
98 | |||
99 | skb_put(nskb, sizeof(struct ipv6hdr)); | ||
100 | skb_reset_network_header(nskb); | ||
101 | ip6h = ipv6_hdr(nskb); | ||
102 | ip6_flow_hdr(ip6h, tclass, 0); | ||
103 | ip6h->hop_limit = ip6_dst_hoplimit(dst); | ||
104 | ip6h->nexthdr = IPPROTO_TCP; | ||
105 | ip6h->saddr = oip6h->daddr; | ||
106 | ip6h->daddr = oip6h->saddr; | ||
107 | |||
108 | skb_reset_transport_header(nskb); | ||
109 | tcph = (struct tcphdr *)skb_put(nskb, sizeof(struct tcphdr)); | ||
110 | /* Truncate to length (no data) */ | ||
111 | tcph->doff = sizeof(struct tcphdr)/4; | ||
112 | tcph->source = otcph.dest; | ||
113 | tcph->dest = otcph.source; | ||
114 | |||
115 | if (otcph.ack) { | ||
116 | needs_ack = 0; | ||
117 | tcph->seq = otcph.ack_seq; | ||
118 | tcph->ack_seq = 0; | ||
119 | } else { | ||
120 | needs_ack = 1; | ||
121 | tcph->ack_seq = htonl(ntohl(otcph.seq) + otcph.syn + otcph.fin | ||
122 | + otcplen - (otcph.doff<<2)); | ||
123 | tcph->seq = 0; | ||
124 | } | ||
125 | |||
126 | /* Reset flags */ | ||
127 | ((u_int8_t *)tcph)[13] = 0; | ||
128 | tcph->rst = 1; | ||
129 | tcph->ack = needs_ack; | ||
130 | tcph->window = 0; | ||
131 | tcph->urg_ptr = 0; | ||
132 | tcph->check = 0; | ||
133 | |||
134 | /* Adjust TCP checksum */ | ||
135 | tcph->check = csum_ipv6_magic(&ipv6_hdr(nskb)->saddr, | ||
136 | &ipv6_hdr(nskb)->daddr, | ||
137 | sizeof(struct tcphdr), IPPROTO_TCP, | ||
138 | csum_partial(tcph, | ||
139 | sizeof(struct tcphdr), 0)); | ||
140 | |||
141 | nf_ct_attach(nskb, oldskb); | ||
142 | |||
143 | #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) | ||
144 | /* If we use ip6_local_out for bridged traffic, the MAC source on | ||
145 | * the RST will be ours, instead of the destination's. This confuses | ||
146 | * some routers/firewalls, and they drop the packet. So we need to | ||
147 | * build the eth header using the original destination's MAC as the | ||
148 | * source, and send the RST packet directly. | ||
149 | */ | ||
150 | if (oldskb->nf_bridge) { | ||
151 | struct ethhdr *oeth = eth_hdr(oldskb); | ||
152 | nskb->dev = oldskb->nf_bridge->physindev; | ||
153 | nskb->protocol = htons(ETH_P_IPV6); | ||
154 | ip6h->payload_len = htons(sizeof(struct tcphdr)); | ||
155 | if (dev_hard_header(nskb, nskb->dev, ntohs(nskb->protocol), | ||
156 | oeth->h_source, oeth->h_dest, nskb->len) < 0) | ||
157 | return; | ||
158 | dev_queue_xmit(nskb); | ||
159 | } else | ||
160 | #endif | ||
161 | ip6_local_out(nskb); | ||
162 | } | ||
163 | EXPORT_SYMBOL_GPL(nf_send_reset6); | ||
diff --git a/net/ipv6/netfilter/nft_chain_nat_ipv6.c b/net/ipv6/netfilter/nft_chain_nat_ipv6.c index d189fcb437fe..1c4b75dd425b 100644 --- a/net/ipv6/netfilter/nft_chain_nat_ipv6.c +++ b/net/ipv6/netfilter/nft_chain_nat_ipv6.c | |||
@@ -24,144 +24,53 @@ | |||
24 | #include <net/netfilter/nf_nat_l3proto.h> | 24 | #include <net/netfilter/nf_nat_l3proto.h> |
25 | #include <net/ipv6.h> | 25 | #include <net/ipv6.h> |
26 | 26 | ||
27 | /* | 27 | static unsigned int nft_nat_do_chain(const struct nf_hook_ops *ops, |
28 | * IPv6 NAT chains | 28 | struct sk_buff *skb, |
29 | */ | 29 | const struct net_device *in, |
30 | 30 | const struct net_device *out, | |
31 | static unsigned int nf_nat_ipv6_fn(const struct nf_hook_ops *ops, | 31 | struct nf_conn *ct) |
32 | struct sk_buff *skb, | ||
33 | const struct net_device *in, | ||
34 | const struct net_device *out, | ||
35 | int (*okfn)(struct sk_buff *)) | ||
36 | { | 32 | { |
37 | enum ip_conntrack_info ctinfo; | ||
38 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); | ||
39 | struct nf_conn_nat *nat; | ||
40 | enum nf_nat_manip_type maniptype = HOOK2MANIP(ops->hooknum); | ||
41 | __be16 frag_off; | ||
42 | int hdrlen; | ||
43 | u8 nexthdr; | ||
44 | struct nft_pktinfo pkt; | 33 | struct nft_pktinfo pkt; |
45 | unsigned int ret; | ||
46 | |||
47 | if (ct == NULL || nf_ct_is_untracked(ct)) | ||
48 | return NF_ACCEPT; | ||
49 | |||
50 | nat = nf_ct_nat_ext_add(ct); | ||
51 | if (nat == NULL) | ||
52 | return NF_ACCEPT; | ||
53 | |||
54 | switch (ctinfo) { | ||
55 | case IP_CT_RELATED: | ||
56 | case IP_CT_RELATED + IP_CT_IS_REPLY: | ||
57 | nexthdr = ipv6_hdr(skb)->nexthdr; | ||
58 | hdrlen = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), | ||
59 | &nexthdr, &frag_off); | ||
60 | |||
61 | if (hdrlen >= 0 && nexthdr == IPPROTO_ICMPV6) { | ||
62 | if (!nf_nat_icmpv6_reply_translation(skb, ct, ctinfo, | ||
63 | ops->hooknum, | ||
64 | hdrlen)) | ||
65 | return NF_DROP; | ||
66 | else | ||
67 | return NF_ACCEPT; | ||
68 | } | ||
69 | /* Fall through */ | ||
70 | case IP_CT_NEW: | ||
71 | if (nf_nat_initialized(ct, maniptype)) | ||
72 | break; | ||
73 | |||
74 | nft_set_pktinfo_ipv6(&pkt, ops, skb, in, out); | ||
75 | 34 | ||
76 | ret = nft_do_chain(&pkt, ops); | 35 | nft_set_pktinfo_ipv6(&pkt, ops, skb, in, out); |
77 | if (ret != NF_ACCEPT) | ||
78 | return ret; | ||
79 | if (!nf_nat_initialized(ct, maniptype)) { | ||
80 | ret = nf_nat_alloc_null_binding(ct, ops->hooknum); | ||
81 | if (ret != NF_ACCEPT) | ||
82 | return ret; | ||
83 | } | ||
84 | default: | ||
85 | break; | ||
86 | } | ||
87 | 36 | ||
88 | return nf_nat_packet(ct, ctinfo, ops->hooknum, skb); | 37 | return nft_do_chain(&pkt, ops); |
89 | } | 38 | } |
90 | 39 | ||
91 | static unsigned int nf_nat_ipv6_prerouting(const struct nf_hook_ops *ops, | 40 | static unsigned int nft_nat_ipv6_fn(const struct nf_hook_ops *ops, |
92 | struct sk_buff *skb, | 41 | struct sk_buff *skb, |
93 | const struct net_device *in, | 42 | const struct net_device *in, |
94 | const struct net_device *out, | 43 | const struct net_device *out, |
95 | int (*okfn)(struct sk_buff *)) | 44 | int (*okfn)(struct sk_buff *)) |
96 | { | 45 | { |
97 | struct in6_addr daddr = ipv6_hdr(skb)->daddr; | 46 | return nf_nat_ipv6_fn(ops, skb, in, out, nft_nat_do_chain); |
98 | unsigned int ret; | ||
99 | |||
100 | ret = nf_nat_ipv6_fn(ops, skb, in, out, okfn); | ||
101 | if (ret != NF_DROP && ret != NF_STOLEN && | ||
102 | ipv6_addr_cmp(&daddr, &ipv6_hdr(skb)->daddr)) | ||
103 | skb_dst_drop(skb); | ||
104 | |||
105 | return ret; | ||
106 | } | 47 | } |
107 | 48 | ||
108 | static unsigned int nf_nat_ipv6_postrouting(const struct nf_hook_ops *ops, | 49 | static unsigned int nft_nat_ipv6_in(const struct nf_hook_ops *ops, |
109 | struct sk_buff *skb, | 50 | struct sk_buff *skb, |
110 | const struct net_device *in, | 51 | const struct net_device *in, |
111 | const struct net_device *out, | 52 | const struct net_device *out, |
112 | int (*okfn)(struct sk_buff *)) | 53 | int (*okfn)(struct sk_buff *)) |
113 | { | 54 | { |
114 | enum ip_conntrack_info ctinfo __maybe_unused; | 55 | return nf_nat_ipv6_in(ops, skb, in, out, nft_nat_do_chain); |
115 | const struct nf_conn *ct __maybe_unused; | ||
116 | unsigned int ret; | ||
117 | |||
118 | ret = nf_nat_ipv6_fn(ops, skb, in, out, okfn); | ||
119 | #ifdef CONFIG_XFRM | ||
120 | if (ret != NF_DROP && ret != NF_STOLEN && | ||
121 | !(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) && | ||
122 | (ct = nf_ct_get(skb, &ctinfo)) != NULL) { | ||
123 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); | ||
124 | |||
125 | if (!nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.src.u3, | ||
126 | &ct->tuplehash[!dir].tuple.dst.u3) || | ||
127 | (ct->tuplehash[dir].tuple.src.u.all != | ||
128 | ct->tuplehash[!dir].tuple.dst.u.all)) | ||
129 | if (nf_xfrm_me_harder(skb, AF_INET6) < 0) | ||
130 | ret = NF_DROP; | ||
131 | } | ||
132 | #endif | ||
133 | return ret; | ||
134 | } | 56 | } |
135 | 57 | ||
136 | static unsigned int nf_nat_ipv6_output(const struct nf_hook_ops *ops, | 58 | static unsigned int nft_nat_ipv6_out(const struct nf_hook_ops *ops, |
137 | struct sk_buff *skb, | 59 | struct sk_buff *skb, |
138 | const struct net_device *in, | 60 | const struct net_device *in, |
139 | const struct net_device *out, | 61 | const struct net_device *out, |
140 | int (*okfn)(struct sk_buff *)) | 62 | int (*okfn)(struct sk_buff *)) |
141 | { | 63 | { |
142 | enum ip_conntrack_info ctinfo; | 64 | return nf_nat_ipv6_out(ops, skb, in, out, nft_nat_do_chain); |
143 | const struct nf_conn *ct; | 65 | } |
144 | unsigned int ret; | ||
145 | |||
146 | ret = nf_nat_ipv6_fn(ops, skb, in, out, okfn); | ||
147 | if (ret != NF_DROP && ret != NF_STOLEN && | ||
148 | (ct = nf_ct_get(skb, &ctinfo)) != NULL) { | ||
149 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); | ||
150 | 66 | ||
151 | if (!nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.dst.u3, | 67 | static unsigned int nft_nat_ipv6_local_fn(const struct nf_hook_ops *ops, |
152 | &ct->tuplehash[!dir].tuple.src.u3)) { | 68 | struct sk_buff *skb, |
153 | if (ip6_route_me_harder(skb)) | 69 | const struct net_device *in, |
154 | ret = NF_DROP; | 70 | const struct net_device *out, |
155 | } | 71 | int (*okfn)(struct sk_buff *)) |
156 | #ifdef CONFIG_XFRM | 72 | { |
157 | else if (!(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) && | 73 | return nf_nat_ipv6_local_fn(ops, skb, in, out, nft_nat_do_chain); |
158 | ct->tuplehash[dir].tuple.dst.u.all != | ||
159 | ct->tuplehash[!dir].tuple.src.u.all) | ||
160 | if (nf_xfrm_me_harder(skb, AF_INET6)) | ||
161 | ret = NF_DROP; | ||
162 | #endif | ||
163 | } | ||
164 | return ret; | ||
165 | } | 74 | } |
166 | 75 | ||
167 | static const struct nf_chain_type nft_chain_nat_ipv6 = { | 76 | static const struct nf_chain_type nft_chain_nat_ipv6 = { |
@@ -174,10 +83,10 @@ static const struct nf_chain_type nft_chain_nat_ipv6 = { | |||
174 | (1 << NF_INET_LOCAL_OUT) | | 83 | (1 << NF_INET_LOCAL_OUT) | |
175 | (1 << NF_INET_LOCAL_IN), | 84 | (1 << NF_INET_LOCAL_IN), |
176 | .hooks = { | 85 | .hooks = { |
177 | [NF_INET_PRE_ROUTING] = nf_nat_ipv6_prerouting, | 86 | [NF_INET_PRE_ROUTING] = nft_nat_ipv6_in, |
178 | [NF_INET_POST_ROUTING] = nf_nat_ipv6_postrouting, | 87 | [NF_INET_POST_ROUTING] = nft_nat_ipv6_out, |
179 | [NF_INET_LOCAL_OUT] = nf_nat_ipv6_output, | 88 | [NF_INET_LOCAL_OUT] = nft_nat_ipv6_local_fn, |
180 | [NF_INET_LOCAL_IN] = nf_nat_ipv6_fn, | 89 | [NF_INET_LOCAL_IN] = nft_nat_ipv6_fn, |
181 | }, | 90 | }, |
182 | }; | 91 | }; |
183 | 92 | ||
diff --git a/net/ipv6/netfilter/nft_masq_ipv6.c b/net/ipv6/netfilter/nft_masq_ipv6.c new file mode 100644 index 000000000000..556262f40761 --- /dev/null +++ b/net/ipv6/netfilter/nft_masq_ipv6.c | |||
@@ -0,0 +1,77 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2014 Arturo Borrero Gonzalez <arturo.borrero.glez@gmail.com> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | #include <linux/kernel.h> | ||
10 | #include <linux/init.h> | ||
11 | #include <linux/module.h> | ||
12 | #include <linux/netlink.h> | ||
13 | #include <linux/netfilter.h> | ||
14 | #include <linux/netfilter/nf_tables.h> | ||
15 | #include <net/netfilter/nf_tables.h> | ||
16 | #include <net/netfilter/nf_nat.h> | ||
17 | #include <net/netfilter/nft_masq.h> | ||
18 | #include <net/netfilter/ipv6/nf_nat_masquerade.h> | ||
19 | |||
20 | static void nft_masq_ipv6_eval(const struct nft_expr *expr, | ||
21 | struct nft_data data[NFT_REG_MAX + 1], | ||
22 | const struct nft_pktinfo *pkt) | ||
23 | { | ||
24 | struct nft_masq *priv = nft_expr_priv(expr); | ||
25 | struct nf_nat_range range; | ||
26 | unsigned int verdict; | ||
27 | |||
28 | range.flags = priv->flags; | ||
29 | |||
30 | verdict = nf_nat_masquerade_ipv6(pkt->skb, &range, pkt->out); | ||
31 | |||
32 | data[NFT_REG_VERDICT].verdict = verdict; | ||
33 | } | ||
34 | |||
35 | static struct nft_expr_type nft_masq_ipv6_type; | ||
36 | static const struct nft_expr_ops nft_masq_ipv6_ops = { | ||
37 | .type = &nft_masq_ipv6_type, | ||
38 | .size = NFT_EXPR_SIZE(sizeof(struct nft_masq)), | ||
39 | .eval = nft_masq_ipv6_eval, | ||
40 | .init = nft_masq_init, | ||
41 | .dump = nft_masq_dump, | ||
42 | }; | ||
43 | |||
44 | static struct nft_expr_type nft_masq_ipv6_type __read_mostly = { | ||
45 | .family = NFPROTO_IPV6, | ||
46 | .name = "masq", | ||
47 | .ops = &nft_masq_ipv6_ops, | ||
48 | .policy = nft_masq_policy, | ||
49 | .maxattr = NFTA_MASQ_MAX, | ||
50 | .owner = THIS_MODULE, | ||
51 | }; | ||
52 | |||
53 | static int __init nft_masq_ipv6_module_init(void) | ||
54 | { | ||
55 | int ret; | ||
56 | |||
57 | ret = nft_register_expr(&nft_masq_ipv6_type); | ||
58 | if (ret < 0) | ||
59 | return ret; | ||
60 | |||
61 | nf_nat_masquerade_ipv6_register_notifier(); | ||
62 | |||
63 | return ret; | ||
64 | } | ||
65 | |||
66 | static void __exit nft_masq_ipv6_module_exit(void) | ||
67 | { | ||
68 | nft_unregister_expr(&nft_masq_ipv6_type); | ||
69 | nf_nat_masquerade_ipv6_unregister_notifier(); | ||
70 | } | ||
71 | |||
72 | module_init(nft_masq_ipv6_module_init); | ||
73 | module_exit(nft_masq_ipv6_module_exit); | ||
74 | |||
75 | MODULE_LICENSE("GPL"); | ||
76 | MODULE_AUTHOR("Arturo Borrero Gonzalez <arturo.borrero.glez@gmail.com>"); | ||
77 | MODULE_ALIAS_NFT_AF_EXPR(AF_INET6, "masq"); | ||
diff --git a/net/ipv6/output_core.c b/net/ipv6/output_core.c index 5ec867e4a8b7..fc24c390af05 100644 --- a/net/ipv6/output_core.c +++ b/net/ipv6/output_core.c | |||
@@ -35,7 +35,7 @@ int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr) | |||
35 | if (found_rhdr) | 35 | if (found_rhdr) |
36 | return offset; | 36 | return offset; |
37 | break; | 37 | break; |
38 | default : | 38 | default: |
39 | return offset; | 39 | return offset; |
40 | } | 40 | } |
41 | 41 | ||
diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c index 2d6f860e5c1e..1752cd0b4882 100644 --- a/net/ipv6/proc.c +++ b/net/ipv6/proc.c | |||
@@ -8,7 +8,7 @@ | |||
8 | * except it reports the sockets in the INET6 address family. | 8 | * except it reports the sockets in the INET6 address family. |
9 | * | 9 | * |
10 | * Authors: David S. Miller (davem@caip.rutgers.edu) | 10 | * Authors: David S. Miller (davem@caip.rutgers.edu) |
11 | * YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> | 11 | * YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> |
12 | * | 12 | * |
13 | * This program is free software; you can redistribute it and/or | 13 | * This program is free software; you can redistribute it and/or |
14 | * modify it under the terms of the GNU General Public License | 14 | * modify it under the terms of the GNU General Public License |
diff --git a/net/ipv6/protocol.c b/net/ipv6/protocol.c index e048cf1bb6a2..e3770abe688a 100644 --- a/net/ipv6/protocol.c +++ b/net/ipv6/protocol.c | |||
@@ -51,6 +51,7 @@ EXPORT_SYMBOL(inet6_del_protocol); | |||
51 | #endif | 51 | #endif |
52 | 52 | ||
53 | const struct net_offload __rcu *inet6_offloads[MAX_INET_PROTOS] __read_mostly; | 53 | const struct net_offload __rcu *inet6_offloads[MAX_INET_PROTOS] __read_mostly; |
54 | EXPORT_SYMBOL(inet6_offloads); | ||
54 | 55 | ||
55 | int inet6_add_offload(const struct net_offload *prot, unsigned char protocol) | 56 | int inet6_add_offload(const struct net_offload *prot, unsigned char protocol) |
56 | { | 57 | { |
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 39d44226e402..896af8807979 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c | |||
@@ -889,7 +889,7 @@ back_from_confirm: | |||
889 | else { | 889 | else { |
890 | lock_sock(sk); | 890 | lock_sock(sk); |
891 | err = ip6_append_data(sk, ip_generic_getfrag, msg->msg_iov, | 891 | err = ip6_append_data(sk, ip_generic_getfrag, msg->msg_iov, |
892 | len, 0, hlimit, tclass, opt, &fl6, (struct rt6_info*)dst, | 892 | len, 0, hlimit, tclass, opt, &fl6, (struct rt6_info *)dst, |
893 | msg->msg_flags, dontfrag); | 893 | msg->msg_flags, dontfrag); |
894 | 894 | ||
895 | if (err) | 895 | if (err) |
@@ -902,7 +902,7 @@ done: | |||
902 | dst_release(dst); | 902 | dst_release(dst); |
903 | out: | 903 | out: |
904 | fl6_sock_release(flowlabel); | 904 | fl6_sock_release(flowlabel); |
905 | return err<0?err:len; | 905 | return err < 0 ? err : len; |
906 | do_confirm: | 906 | do_confirm: |
907 | dst_confirm(dst); | 907 | dst_confirm(dst); |
908 | if (!(msg->msg_flags & MSG_PROBE) || len) | 908 | if (!(msg->msg_flags & MSG_PROBE) || len) |
@@ -1045,7 +1045,7 @@ static int do_rawv6_getsockopt(struct sock *sk, int level, int optname, | |||
1045 | struct raw6_sock *rp = raw6_sk(sk); | 1045 | struct raw6_sock *rp = raw6_sk(sk); |
1046 | int val, len; | 1046 | int val, len; |
1047 | 1047 | ||
1048 | if (get_user(len,optlen)) | 1048 | if (get_user(len, optlen)) |
1049 | return -EFAULT; | 1049 | return -EFAULT; |
1050 | 1050 | ||
1051 | switch (optname) { | 1051 | switch (optname) { |
@@ -1069,7 +1069,7 @@ static int do_rawv6_getsockopt(struct sock *sk, int level, int optname, | |||
1069 | 1069 | ||
1070 | if (put_user(len, optlen)) | 1070 | if (put_user(len, optlen)) |
1071 | return -EFAULT; | 1071 | return -EFAULT; |
1072 | if (copy_to_user(optval,&val,len)) | 1072 | if (copy_to_user(optval, &val, len)) |
1073 | return -EFAULT; | 1073 | return -EFAULT; |
1074 | return 0; | 1074 | return 0; |
1075 | } | 1075 | } |
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index c6557d9f7808..1a157ca2ebc1 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c | |||
@@ -62,13 +62,12 @@ | |||
62 | 62 | ||
63 | static const char ip6_frag_cache_name[] = "ip6-frags"; | 63 | static const char ip6_frag_cache_name[] = "ip6-frags"; |
64 | 64 | ||
65 | struct ip6frag_skb_cb | 65 | struct ip6frag_skb_cb { |
66 | { | ||
67 | struct inet6_skb_parm h; | 66 | struct inet6_skb_parm h; |
68 | int offset; | 67 | int offset; |
69 | }; | 68 | }; |
70 | 69 | ||
71 | #define FRAG6_CB(skb) ((struct ip6frag_skb_cb*)((skb)->cb)) | 70 | #define FRAG6_CB(skb) ((struct ip6frag_skb_cb *)((skb)->cb)) |
72 | 71 | ||
73 | static inline u8 ip6_frag_ecn(const struct ipv6hdr *ipv6h) | 72 | static inline u8 ip6_frag_ecn(const struct ipv6hdr *ipv6h) |
74 | { | 73 | { |
@@ -289,7 +288,7 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, | |||
289 | goto found; | 288 | goto found; |
290 | } | 289 | } |
291 | prev = NULL; | 290 | prev = NULL; |
292 | for(next = fq->q.fragments; next != NULL; next = next->next) { | 291 | for (next = fq->q.fragments; next != NULL; next = next->next) { |
293 | if (FRAG6_CB(next)->offset >= offset) | 292 | if (FRAG6_CB(next)->offset >= offset) |
294 | break; /* bingo! */ | 293 | break; /* bingo! */ |
295 | prev = next; | 294 | prev = next; |
@@ -529,7 +528,7 @@ static int ipv6_frag_rcv(struct sk_buff *skb) | |||
529 | IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_REASMREQDS); | 528 | IP6_INC_STATS_BH(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_REASMREQDS); |
530 | 529 | ||
531 | /* Jumbo payload inhibits frag. header */ | 530 | /* Jumbo payload inhibits frag. header */ |
532 | if (hdr->payload_len==0) | 531 | if (hdr->payload_len == 0) |
533 | goto fail_hdr; | 532 | goto fail_hdr; |
534 | 533 | ||
535 | if (!pskb_may_pull(skb, (skb_transport_offset(skb) + | 534 | if (!pskb_may_pull(skb, (skb_transport_offset(skb) + |
@@ -575,8 +574,7 @@ fail_hdr: | |||
575 | return -1; | 574 | return -1; |
576 | } | 575 | } |
577 | 576 | ||
578 | static const struct inet6_protocol frag_protocol = | 577 | static const struct inet6_protocol frag_protocol = { |
579 | { | ||
580 | .handler = ipv6_frag_rcv, | 578 | .handler = ipv6_frag_rcv, |
581 | .flags = INET6_PROTO_NOPOLICY, | 579 | .flags = INET6_PROTO_NOPOLICY, |
582 | }; | 580 | }; |
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index bafde82324c5..a318dd89b6d9 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
@@ -812,7 +812,7 @@ out: | |||
812 | 812 | ||
813 | } | 813 | } |
814 | 814 | ||
815 | struct dst_entry * ip6_route_lookup(struct net *net, struct flowi6 *fl6, | 815 | struct dst_entry *ip6_route_lookup(struct net *net, struct flowi6 *fl6, |
816 | int flags) | 816 | int flags) |
817 | { | 817 | { |
818 | return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_lookup); | 818 | return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_lookup); |
@@ -842,7 +842,6 @@ struct rt6_info *rt6_lookup(struct net *net, const struct in6_addr *daddr, | |||
842 | 842 | ||
843 | return NULL; | 843 | return NULL; |
844 | } | 844 | } |
845 | |||
846 | EXPORT_SYMBOL(rt6_lookup); | 845 | EXPORT_SYMBOL(rt6_lookup); |
847 | 846 | ||
848 | /* ip6_ins_rt is called with FREE table->tb6_lock. | 847 | /* ip6_ins_rt is called with FREE table->tb6_lock. |
@@ -1023,7 +1022,7 @@ static struct rt6_info *ip6_pol_route_output(struct net *net, struct fib6_table | |||
1023 | return ip6_pol_route(net, table, fl6->flowi6_oif, fl6, flags); | 1022 | return ip6_pol_route(net, table, fl6->flowi6_oif, fl6, flags); |
1024 | } | 1023 | } |
1025 | 1024 | ||
1026 | struct dst_entry * ip6_route_output(struct net *net, const struct sock *sk, | 1025 | struct dst_entry *ip6_route_output(struct net *net, const struct sock *sk, |
1027 | struct flowi6 *fl6) | 1026 | struct flowi6 *fl6) |
1028 | { | 1027 | { |
1029 | int flags = 0; | 1028 | int flags = 0; |
@@ -1040,7 +1039,6 @@ struct dst_entry * ip6_route_output(struct net *net, const struct sock *sk, | |||
1040 | 1039 | ||
1041 | return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_output); | 1040 | return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_output); |
1042 | } | 1041 | } |
1043 | |||
1044 | EXPORT_SYMBOL(ip6_route_output); | 1042 | EXPORT_SYMBOL(ip6_route_output); |
1045 | 1043 | ||
1046 | struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_orig) | 1044 | struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_orig) |
@@ -1145,7 +1143,7 @@ static void ip6_link_failure(struct sk_buff *skb) | |||
1145 | static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk, | 1143 | static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk, |
1146 | struct sk_buff *skb, u32 mtu) | 1144 | struct sk_buff *skb, u32 mtu) |
1147 | { | 1145 | { |
1148 | struct rt6_info *rt6 = (struct rt6_info*)dst; | 1146 | struct rt6_info *rt6 = (struct rt6_info *)dst; |
1149 | 1147 | ||
1150 | dst_confirm(dst); | 1148 | dst_confirm(dst); |
1151 | if (mtu < dst_mtu(dst) && rt6->rt6i_dst.plen == 128) { | 1149 | if (mtu < dst_mtu(dst) && rt6->rt6i_dst.plen == 128) { |
@@ -1920,7 +1918,7 @@ static struct rt6_info *rt6_get_route_info(struct net *net, | |||
1920 | return NULL; | 1918 | return NULL; |
1921 | 1919 | ||
1922 | read_lock_bh(&table->tb6_lock); | 1920 | read_lock_bh(&table->tb6_lock); |
1923 | fn = fib6_locate(&table->tb6_root, prefix ,prefixlen, NULL, 0); | 1921 | fn = fib6_locate(&table->tb6_root, prefix, prefixlen, NULL, 0); |
1924 | if (!fn) | 1922 | if (!fn) |
1925 | goto out; | 1923 | goto out; |
1926 | 1924 | ||
@@ -1979,7 +1977,7 @@ struct rt6_info *rt6_get_dflt_router(const struct in6_addr *addr, struct net_dev | |||
1979 | return NULL; | 1977 | return NULL; |
1980 | 1978 | ||
1981 | read_lock_bh(&table->tb6_lock); | 1979 | read_lock_bh(&table->tb6_lock); |
1982 | for (rt = table->tb6_root.leaf; rt; rt=rt->dst.rt6_next) { | 1980 | for (rt = table->tb6_root.leaf; rt; rt = rt->dst.rt6_next) { |
1983 | if (dev == rt->dst.dev && | 1981 | if (dev == rt->dst.dev && |
1984 | ((rt->rt6i_flags & (RTF_ADDRCONF | RTF_DEFAULT)) == (RTF_ADDRCONF | RTF_DEFAULT)) && | 1982 | ((rt->rt6i_flags & (RTF_ADDRCONF | RTF_DEFAULT)) == (RTF_ADDRCONF | RTF_DEFAULT)) && |
1985 | ipv6_addr_equal(&rt->rt6i_gateway, addr)) | 1983 | ipv6_addr_equal(&rt->rt6i_gateway, addr)) |
@@ -2064,7 +2062,7 @@ int ipv6_route_ioctl(struct net *net, unsigned int cmd, void __user *arg) | |||
2064 | struct in6_rtmsg rtmsg; | 2062 | struct in6_rtmsg rtmsg; |
2065 | int err; | 2063 | int err; |
2066 | 2064 | ||
2067 | switch(cmd) { | 2065 | switch (cmd) { |
2068 | case SIOCADDRT: /* Add a route */ | 2066 | case SIOCADDRT: /* Add a route */ |
2069 | case SIOCDELRT: /* Delete a route */ | 2067 | case SIOCDELRT: /* Delete a route */ |
2070 | if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) | 2068 | if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) |
@@ -2187,7 +2185,7 @@ int ip6_route_get_saddr(struct net *net, | |||
2187 | unsigned int prefs, | 2185 | unsigned int prefs, |
2188 | struct in6_addr *saddr) | 2186 | struct in6_addr *saddr) |
2189 | { | 2187 | { |
2190 | struct inet6_dev *idev = ip6_dst_idev((struct dst_entry*)rt); | 2188 | struct inet6_dev *idev = ip6_dst_idev((struct dst_entry *)rt); |
2191 | int err = 0; | 2189 | int err = 0; |
2192 | if (rt->rt6i_prefsrc.plen) | 2190 | if (rt->rt6i_prefsrc.plen) |
2193 | *saddr = rt->rt6i_prefsrc.addr; | 2191 | *saddr = rt->rt6i_prefsrc.addr; |
@@ -2482,7 +2480,7 @@ beginning: | |||
2482 | return last_err; | 2480 | return last_err; |
2483 | } | 2481 | } |
2484 | 2482 | ||
2485 | static int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh) | 2483 | static int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh) |
2486 | { | 2484 | { |
2487 | struct fib6_config cfg; | 2485 | struct fib6_config cfg; |
2488 | int err; | 2486 | int err; |
@@ -2497,7 +2495,7 @@ static int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh) | |||
2497 | return ip6_route_del(&cfg); | 2495 | return ip6_route_del(&cfg); |
2498 | } | 2496 | } |
2499 | 2497 | ||
2500 | static int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh) | 2498 | static int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh) |
2501 | { | 2499 | { |
2502 | struct fib6_config cfg; | 2500 | struct fib6_config cfg; |
2503 | int err; | 2501 | int err; |
@@ -2689,7 +2687,7 @@ int rt6_dump_route(struct rt6_info *rt, void *p_arg) | |||
2689 | prefix, 0, NLM_F_MULTI); | 2687 | prefix, 0, NLM_F_MULTI); |
2690 | } | 2688 | } |
2691 | 2689 | ||
2692 | static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh) | 2690 | static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh) |
2693 | { | 2691 | { |
2694 | struct net *net = sock_net(in_skb->sk); | 2692 | struct net *net = sock_net(in_skb->sk); |
2695 | struct nlattr *tb[RTA_MAX+1]; | 2693 | struct nlattr *tb[RTA_MAX+1]; |
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 6163f851dc01..6eab37cf5345 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c | |||
@@ -812,9 +812,9 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, | |||
812 | const struct ipv6hdr *iph6 = ipv6_hdr(skb); | 812 | const struct ipv6hdr *iph6 = ipv6_hdr(skb); |
813 | u8 tos = tunnel->parms.iph.tos; | 813 | u8 tos = tunnel->parms.iph.tos; |
814 | __be16 df = tiph->frag_off; | 814 | __be16 df = tiph->frag_off; |
815 | struct rtable *rt; /* Route to the other host */ | 815 | struct rtable *rt; /* Route to the other host */ |
816 | struct net_device *tdev; /* Device to other host */ | 816 | struct net_device *tdev; /* Device to other host */ |
817 | unsigned int max_headroom; /* The extra header space needed */ | 817 | unsigned int max_headroom; /* The extra header space needed */ |
818 | __be32 dst = tiph->daddr; | 818 | __be32 dst = tiph->daddr; |
819 | struct flowi4 fl4; | 819 | struct flowi4 fl4; |
820 | int mtu; | 820 | int mtu; |
@@ -822,6 +822,8 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, | |||
822 | int addr_type; | 822 | int addr_type; |
823 | u8 ttl; | 823 | u8 ttl; |
824 | int err; | 824 | int err; |
825 | u8 protocol = IPPROTO_IPV6; | ||
826 | int t_hlen = tunnel->hlen + sizeof(struct iphdr); | ||
825 | 827 | ||
826 | if (skb->protocol != htons(ETH_P_IPV6)) | 828 | if (skb->protocol != htons(ETH_P_IPV6)) |
827 | goto tx_error; | 829 | goto tx_error; |
@@ -911,8 +913,14 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, | |||
911 | goto tx_error; | 913 | goto tx_error; |
912 | } | 914 | } |
913 | 915 | ||
916 | skb = iptunnel_handle_offloads(skb, false, SKB_GSO_SIT); | ||
917 | if (IS_ERR(skb)) { | ||
918 | ip_rt_put(rt); | ||
919 | goto out; | ||
920 | } | ||
921 | |||
914 | if (df) { | 922 | if (df) { |
915 | mtu = dst_mtu(&rt->dst) - sizeof(struct iphdr); | 923 | mtu = dst_mtu(&rt->dst) - t_hlen; |
916 | 924 | ||
917 | if (mtu < 68) { | 925 | if (mtu < 68) { |
918 | dev->stats.collisions++; | 926 | dev->stats.collisions++; |
@@ -947,7 +955,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, | |||
947 | /* | 955 | /* |
948 | * Okay, now see if we can stuff it in the buffer as-is. | 956 | * Okay, now see if we can stuff it in the buffer as-is. |
949 | */ | 957 | */ |
950 | max_headroom = LL_RESERVED_SPACE(tdev)+sizeof(struct iphdr); | 958 | max_headroom = LL_RESERVED_SPACE(tdev) + t_hlen; |
951 | 959 | ||
952 | if (skb_headroom(skb) < max_headroom || skb_shared(skb) || | 960 | if (skb_headroom(skb) < max_headroom || skb_shared(skb) || |
953 | (skb_cloned(skb) && !skb_clone_writable(skb, 0))) { | 961 | (skb_cloned(skb) && !skb_clone_writable(skb, 0))) { |
@@ -969,14 +977,15 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, | |||
969 | ttl = iph6->hop_limit; | 977 | ttl = iph6->hop_limit; |
970 | tos = INET_ECN_encapsulate(tos, ipv6_get_dsfield(iph6)); | 978 | tos = INET_ECN_encapsulate(tos, ipv6_get_dsfield(iph6)); |
971 | 979 | ||
972 | skb = iptunnel_handle_offloads(skb, false, SKB_GSO_SIT); | 980 | if (ip_tunnel_encap(skb, tunnel, &protocol, &fl4) < 0) { |
973 | if (IS_ERR(skb)) { | ||
974 | ip_rt_put(rt); | 981 | ip_rt_put(rt); |
975 | goto out; | 982 | goto tx_error; |
976 | } | 983 | } |
977 | 984 | ||
985 | skb_set_inner_ipproto(skb, IPPROTO_IPV6); | ||
986 | |||
978 | err = iptunnel_xmit(skb->sk, rt, skb, fl4.saddr, fl4.daddr, | 987 | err = iptunnel_xmit(skb->sk, rt, skb, fl4.saddr, fl4.daddr, |
979 | IPPROTO_IPV6, tos, ttl, df, | 988 | protocol, tos, ttl, df, |
980 | !net_eq(tunnel->net, dev_net(dev))); | 989 | !net_eq(tunnel->net, dev_net(dev))); |
981 | iptunnel_xmit_stats(err, &dev->stats, dev->tstats); | 990 | iptunnel_xmit_stats(err, &dev->stats, dev->tstats); |
982 | return NETDEV_TX_OK; | 991 | return NETDEV_TX_OK; |
@@ -999,6 +1008,8 @@ static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) | |||
999 | if (IS_ERR(skb)) | 1008 | if (IS_ERR(skb)) |
1000 | goto out; | 1009 | goto out; |
1001 | 1010 | ||
1011 | skb_set_inner_ipproto(skb, IPPROTO_IPIP); | ||
1012 | |||
1002 | ip_tunnel_xmit(skb, dev, tiph, IPPROTO_IPIP); | 1013 | ip_tunnel_xmit(skb, dev, tiph, IPPROTO_IPIP); |
1003 | return NETDEV_TX_OK; | 1014 | return NETDEV_TX_OK; |
1004 | out: | 1015 | out: |
@@ -1059,8 +1070,10 @@ static void ipip6_tunnel_bind_dev(struct net_device *dev) | |||
1059 | tdev = __dev_get_by_index(tunnel->net, tunnel->parms.link); | 1070 | tdev = __dev_get_by_index(tunnel->net, tunnel->parms.link); |
1060 | 1071 | ||
1061 | if (tdev) { | 1072 | if (tdev) { |
1073 | int t_hlen = tunnel->hlen + sizeof(struct iphdr); | ||
1074 | |||
1062 | dev->hard_header_len = tdev->hard_header_len + sizeof(struct iphdr); | 1075 | dev->hard_header_len = tdev->hard_header_len + sizeof(struct iphdr); |
1063 | dev->mtu = tdev->mtu - sizeof(struct iphdr); | 1076 | dev->mtu = tdev->mtu - t_hlen; |
1064 | if (dev->mtu < IPV6_MIN_MTU) | 1077 | if (dev->mtu < IPV6_MIN_MTU) |
1065 | dev->mtu = IPV6_MIN_MTU; | 1078 | dev->mtu = IPV6_MIN_MTU; |
1066 | } | 1079 | } |
@@ -1123,7 +1136,7 @@ static int ipip6_tunnel_update_6rd(struct ip_tunnel *t, | |||
1123 | #endif | 1136 | #endif |
1124 | 1137 | ||
1125 | static int | 1138 | static int |
1126 | ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) | 1139 | ipip6_tunnel_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) |
1127 | { | 1140 | { |
1128 | int err = 0; | 1141 | int err = 0; |
1129 | struct ip_tunnel_parm p; | 1142 | struct ip_tunnel_parm p; |
@@ -1307,7 +1320,10 @@ done: | |||
1307 | 1320 | ||
1308 | static int ipip6_tunnel_change_mtu(struct net_device *dev, int new_mtu) | 1321 | static int ipip6_tunnel_change_mtu(struct net_device *dev, int new_mtu) |
1309 | { | 1322 | { |
1310 | if (new_mtu < IPV6_MIN_MTU || new_mtu > 0xFFF8 - sizeof(struct iphdr)) | 1323 | struct ip_tunnel *tunnel = netdev_priv(dev); |
1324 | int t_hlen = tunnel->hlen + sizeof(struct iphdr); | ||
1325 | |||
1326 | if (new_mtu < IPV6_MIN_MTU || new_mtu > 0xFFF8 - t_hlen) | ||
1311 | return -EINVAL; | 1327 | return -EINVAL; |
1312 | dev->mtu = new_mtu; | 1328 | dev->mtu = new_mtu; |
1313 | return 0; | 1329 | return 0; |
@@ -1338,14 +1354,17 @@ static void ipip6_dev_free(struct net_device *dev) | |||
1338 | 1354 | ||
1339 | static void ipip6_tunnel_setup(struct net_device *dev) | 1355 | static void ipip6_tunnel_setup(struct net_device *dev) |
1340 | { | 1356 | { |
1357 | struct ip_tunnel *tunnel = netdev_priv(dev); | ||
1358 | int t_hlen = tunnel->hlen + sizeof(struct iphdr); | ||
1359 | |||
1341 | dev->netdev_ops = &ipip6_netdev_ops; | 1360 | dev->netdev_ops = &ipip6_netdev_ops; |
1342 | dev->destructor = ipip6_dev_free; | 1361 | dev->destructor = ipip6_dev_free; |
1343 | 1362 | ||
1344 | dev->type = ARPHRD_SIT; | 1363 | dev->type = ARPHRD_SIT; |
1345 | dev->hard_header_len = LL_MAX_HEADER + sizeof(struct iphdr); | 1364 | dev->hard_header_len = LL_MAX_HEADER + t_hlen; |
1346 | dev->mtu = ETH_DATA_LEN - sizeof(struct iphdr); | 1365 | dev->mtu = ETH_DATA_LEN - t_hlen; |
1347 | dev->flags = IFF_NOARP; | 1366 | dev->flags = IFF_NOARP; |
1348 | dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; | 1367 | netif_keep_dst(dev); |
1349 | dev->iflink = 0; | 1368 | dev->iflink = 0; |
1350 | dev->addr_len = 4; | 1369 | dev->addr_len = 4; |
1351 | dev->features |= NETIF_F_LLTX; | 1370 | dev->features |= NETIF_F_LLTX; |
@@ -1466,6 +1485,40 @@ static void ipip6_netlink_parms(struct nlattr *data[], | |||
1466 | 1485 | ||
1467 | } | 1486 | } |
1468 | 1487 | ||
1488 | /* This function returns true when ENCAP attributes are present in the nl msg */ | ||
1489 | static bool ipip6_netlink_encap_parms(struct nlattr *data[], | ||
1490 | struct ip_tunnel_encap *ipencap) | ||
1491 | { | ||
1492 | bool ret = false; | ||
1493 | |||
1494 | memset(ipencap, 0, sizeof(*ipencap)); | ||
1495 | |||
1496 | if (!data) | ||
1497 | return ret; | ||
1498 | |||
1499 | if (data[IFLA_IPTUN_ENCAP_TYPE]) { | ||
1500 | ret = true; | ||
1501 | ipencap->type = nla_get_u16(data[IFLA_IPTUN_ENCAP_TYPE]); | ||
1502 | } | ||
1503 | |||
1504 | if (data[IFLA_IPTUN_ENCAP_FLAGS]) { | ||
1505 | ret = true; | ||
1506 | ipencap->flags = nla_get_u16(data[IFLA_IPTUN_ENCAP_FLAGS]); | ||
1507 | } | ||
1508 | |||
1509 | if (data[IFLA_IPTUN_ENCAP_SPORT]) { | ||
1510 | ret = true; | ||
1511 | ipencap->sport = nla_get_u16(data[IFLA_IPTUN_ENCAP_SPORT]); | ||
1512 | } | ||
1513 | |||
1514 | if (data[IFLA_IPTUN_ENCAP_DPORT]) { | ||
1515 | ret = true; | ||
1516 | ipencap->dport = nla_get_u16(data[IFLA_IPTUN_ENCAP_DPORT]); | ||
1517 | } | ||
1518 | |||
1519 | return ret; | ||
1520 | } | ||
1521 | |||
1469 | #ifdef CONFIG_IPV6_SIT_6RD | 1522 | #ifdef CONFIG_IPV6_SIT_6RD |
1470 | /* This function returns true when 6RD attributes are present in the nl msg */ | 1523 | /* This function returns true when 6RD attributes are present in the nl msg */ |
1471 | static bool ipip6_netlink_6rd_parms(struct nlattr *data[], | 1524 | static bool ipip6_netlink_6rd_parms(struct nlattr *data[], |
@@ -1509,12 +1562,20 @@ static int ipip6_newlink(struct net *src_net, struct net_device *dev, | |||
1509 | { | 1562 | { |
1510 | struct net *net = dev_net(dev); | 1563 | struct net *net = dev_net(dev); |
1511 | struct ip_tunnel *nt; | 1564 | struct ip_tunnel *nt; |
1565 | struct ip_tunnel_encap ipencap; | ||
1512 | #ifdef CONFIG_IPV6_SIT_6RD | 1566 | #ifdef CONFIG_IPV6_SIT_6RD |
1513 | struct ip_tunnel_6rd ip6rd; | 1567 | struct ip_tunnel_6rd ip6rd; |
1514 | #endif | 1568 | #endif |
1515 | int err; | 1569 | int err; |
1516 | 1570 | ||
1517 | nt = netdev_priv(dev); | 1571 | nt = netdev_priv(dev); |
1572 | |||
1573 | if (ipip6_netlink_encap_parms(data, &ipencap)) { | ||
1574 | err = ip_tunnel_encap_setup(nt, &ipencap); | ||
1575 | if (err < 0) | ||
1576 | return err; | ||
1577 | } | ||
1578 | |||
1518 | ipip6_netlink_parms(data, &nt->parms); | 1579 | ipip6_netlink_parms(data, &nt->parms); |
1519 | 1580 | ||
1520 | if (ipip6_tunnel_locate(net, &nt->parms, 0)) | 1581 | if (ipip6_tunnel_locate(net, &nt->parms, 0)) |
@@ -1537,15 +1598,23 @@ static int ipip6_changelink(struct net_device *dev, struct nlattr *tb[], | |||
1537 | { | 1598 | { |
1538 | struct ip_tunnel *t = netdev_priv(dev); | 1599 | struct ip_tunnel *t = netdev_priv(dev); |
1539 | struct ip_tunnel_parm p; | 1600 | struct ip_tunnel_parm p; |
1601 | struct ip_tunnel_encap ipencap; | ||
1540 | struct net *net = t->net; | 1602 | struct net *net = t->net; |
1541 | struct sit_net *sitn = net_generic(net, sit_net_id); | 1603 | struct sit_net *sitn = net_generic(net, sit_net_id); |
1542 | #ifdef CONFIG_IPV6_SIT_6RD | 1604 | #ifdef CONFIG_IPV6_SIT_6RD |
1543 | struct ip_tunnel_6rd ip6rd; | 1605 | struct ip_tunnel_6rd ip6rd; |
1544 | #endif | 1606 | #endif |
1607 | int err; | ||
1545 | 1608 | ||
1546 | if (dev == sitn->fb_tunnel_dev) | 1609 | if (dev == sitn->fb_tunnel_dev) |
1547 | return -EINVAL; | 1610 | return -EINVAL; |
1548 | 1611 | ||
1612 | if (ipip6_netlink_encap_parms(data, &ipencap)) { | ||
1613 | err = ip_tunnel_encap_setup(t, &ipencap); | ||
1614 | if (err < 0) | ||
1615 | return err; | ||
1616 | } | ||
1617 | |||
1549 | ipip6_netlink_parms(data, &p); | 1618 | ipip6_netlink_parms(data, &p); |
1550 | 1619 | ||
1551 | if (((dev->flags & IFF_POINTOPOINT) && !p.iph.daddr) || | 1620 | if (((dev->flags & IFF_POINTOPOINT) && !p.iph.daddr) || |
@@ -1599,6 +1668,14 @@ static size_t ipip6_get_size(const struct net_device *dev) | |||
1599 | /* IFLA_IPTUN_6RD_RELAY_PREFIXLEN */ | 1668 | /* IFLA_IPTUN_6RD_RELAY_PREFIXLEN */ |
1600 | nla_total_size(2) + | 1669 | nla_total_size(2) + |
1601 | #endif | 1670 | #endif |
1671 | /* IFLA_IPTUN_ENCAP_TYPE */ | ||
1672 | nla_total_size(2) + | ||
1673 | /* IFLA_IPTUN_ENCAP_FLAGS */ | ||
1674 | nla_total_size(2) + | ||
1675 | /* IFLA_IPTUN_ENCAP_SPORT */ | ||
1676 | nla_total_size(2) + | ||
1677 | /* IFLA_IPTUN_ENCAP_DPORT */ | ||
1678 | nla_total_size(2) + | ||
1602 | 0; | 1679 | 0; |
1603 | } | 1680 | } |
1604 | 1681 | ||
@@ -1630,6 +1707,16 @@ static int ipip6_fill_info(struct sk_buff *skb, const struct net_device *dev) | |||
1630 | goto nla_put_failure; | 1707 | goto nla_put_failure; |
1631 | #endif | 1708 | #endif |
1632 | 1709 | ||
1710 | if (nla_put_u16(skb, IFLA_IPTUN_ENCAP_TYPE, | ||
1711 | tunnel->encap.type) || | ||
1712 | nla_put_u16(skb, IFLA_IPTUN_ENCAP_SPORT, | ||
1713 | tunnel->encap.sport) || | ||
1714 | nla_put_u16(skb, IFLA_IPTUN_ENCAP_DPORT, | ||
1715 | tunnel->encap.dport) || | ||
1716 | nla_put_u16(skb, IFLA_IPTUN_ENCAP_FLAGS, | ||
1717 | tunnel->encap.dport)) | ||
1718 | goto nla_put_failure; | ||
1719 | |||
1633 | return 0; | 1720 | return 0; |
1634 | 1721 | ||
1635 | nla_put_failure: | 1722 | nla_put_failure: |
@@ -1651,6 +1738,10 @@ static const struct nla_policy ipip6_policy[IFLA_IPTUN_MAX + 1] = { | |||
1651 | [IFLA_IPTUN_6RD_PREFIXLEN] = { .type = NLA_U16 }, | 1738 | [IFLA_IPTUN_6RD_PREFIXLEN] = { .type = NLA_U16 }, |
1652 | [IFLA_IPTUN_6RD_RELAY_PREFIXLEN] = { .type = NLA_U16 }, | 1739 | [IFLA_IPTUN_6RD_RELAY_PREFIXLEN] = { .type = NLA_U16 }, |
1653 | #endif | 1740 | #endif |
1741 | [IFLA_IPTUN_ENCAP_TYPE] = { .type = NLA_U16 }, | ||
1742 | [IFLA_IPTUN_ENCAP_FLAGS] = { .type = NLA_U16 }, | ||
1743 | [IFLA_IPTUN_ENCAP_SPORT] = { .type = NLA_U16 }, | ||
1744 | [IFLA_IPTUN_ENCAP_DPORT] = { .type = NLA_U16 }, | ||
1654 | }; | 1745 | }; |
1655 | 1746 | ||
1656 | static void ipip6_dellink(struct net_device *dev, struct list_head *head) | 1747 | static void ipip6_dellink(struct net_device *dev, struct list_head *head) |
diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c index 83cea1d39466..9a2838e93cc5 100644 --- a/net/ipv6/syncookies.c +++ b/net/ipv6/syncookies.c | |||
@@ -24,7 +24,7 @@ | |||
24 | #define COOKIEBITS 24 /* Upper bits store count */ | 24 | #define COOKIEBITS 24 /* Upper bits store count */ |
25 | #define COOKIEMASK (((__u32)1 << COOKIEBITS) - 1) | 25 | #define COOKIEMASK (((__u32)1 << COOKIEBITS) - 1) |
26 | 26 | ||
27 | static u32 syncookie6_secret[2][16-4+SHA_DIGEST_WORDS]; | 27 | static u32 syncookie6_secret[2][16-4+SHA_DIGEST_WORDS] __read_mostly; |
28 | 28 | ||
29 | /* RFC 2460, Section 8.3: | 29 | /* RFC 2460, Section 8.3: |
30 | * [ipv6 tcp] MSS must be computed as the maximum packet size minus 60 [..] | 30 | * [ipv6 tcp] MSS must be computed as the maximum packet size minus 60 [..] |
@@ -203,7 +203,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) | |||
203 | ireq->ir_num = ntohs(th->dest); | 203 | ireq->ir_num = ntohs(th->dest); |
204 | ireq->ir_v6_rmt_addr = ipv6_hdr(skb)->saddr; | 204 | ireq->ir_v6_rmt_addr = ipv6_hdr(skb)->saddr; |
205 | ireq->ir_v6_loc_addr = ipv6_hdr(skb)->daddr; | 205 | ireq->ir_v6_loc_addr = ipv6_hdr(skb)->daddr; |
206 | if (ipv6_opt_accepted(sk, skb) || | 206 | if (ipv6_opt_accepted(sk, skb, &TCP_SKB_CB(skb)->header.h6) || |
207 | np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo || | 207 | np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo || |
208 | np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) { | 208 | np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) { |
209 | atomic_inc(&skb->users); | 209 | atomic_inc(&skb->users); |
diff --git a/net/ipv6/sysctl_net_ipv6.c b/net/ipv6/sysctl_net_ipv6.c index 0c56c93619e0..c5c10fafcfe2 100644 --- a/net/ipv6/sysctl_net_ipv6.c +++ b/net/ipv6/sysctl_net_ipv6.c | |||
@@ -16,6 +16,8 @@ | |||
16 | #include <net/addrconf.h> | 16 | #include <net/addrconf.h> |
17 | #include <net/inet_frag.h> | 17 | #include <net/inet_frag.h> |
18 | 18 | ||
19 | static int one = 1; | ||
20 | |||
19 | static struct ctl_table ipv6_table_template[] = { | 21 | static struct ctl_table ipv6_table_template[] = { |
20 | { | 22 | { |
21 | .procname = "bindv6only", | 23 | .procname = "bindv6only", |
@@ -63,6 +65,14 @@ static struct ctl_table ipv6_rotable[] = { | |||
63 | .mode = 0644, | 65 | .mode = 0644, |
64 | .proc_handler = proc_dointvec | 66 | .proc_handler = proc_dointvec |
65 | }, | 67 | }, |
68 | { | ||
69 | .procname = "mld_qrv", | ||
70 | .data = &sysctl_mld_qrv, | ||
71 | .maxlen = sizeof(int), | ||
72 | .mode = 0644, | ||
73 | .proc_handler = proc_dointvec_minmax, | ||
74 | .extra1 = &one | ||
75 | }, | ||
66 | { } | 76 | { } |
67 | }; | 77 | }; |
68 | 78 | ||
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 29964c3d363c..132bac137aed 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c | |||
@@ -93,13 +93,16 @@ static struct tcp_md5sig_key *tcp_v6_md5_do_lookup(struct sock *sk, | |||
93 | static void inet6_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb) | 93 | static void inet6_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb) |
94 | { | 94 | { |
95 | struct dst_entry *dst = skb_dst(skb); | 95 | struct dst_entry *dst = skb_dst(skb); |
96 | const struct rt6_info *rt = (const struct rt6_info *)dst; | ||
97 | 96 | ||
98 | dst_hold(dst); | 97 | if (dst) { |
99 | sk->sk_rx_dst = dst; | 98 | const struct rt6_info *rt = (const struct rt6_info *)dst; |
100 | inet_sk(sk)->rx_dst_ifindex = skb->skb_iif; | 99 | |
101 | if (rt->rt6i_node) | 100 | dst_hold(dst); |
102 | inet6_sk(sk)->rx_dst_cookie = rt->rt6i_node->fn_sernum; | 101 | sk->sk_rx_dst = dst; |
102 | inet_sk(sk)->rx_dst_ifindex = skb->skb_iif; | ||
103 | if (rt->rt6i_node) | ||
104 | inet6_sk(sk)->rx_dst_cookie = rt->rt6i_node->fn_sernum; | ||
105 | } | ||
103 | } | 106 | } |
104 | 107 | ||
105 | static void tcp_v6_hash(struct sock *sk) | 108 | static void tcp_v6_hash(struct sock *sk) |
@@ -738,8 +741,9 @@ static void tcp_v6_init_req(struct request_sock *req, struct sock *sk, | |||
738 | ipv6_addr_type(&ireq->ir_v6_rmt_addr) & IPV6_ADDR_LINKLOCAL) | 741 | ipv6_addr_type(&ireq->ir_v6_rmt_addr) & IPV6_ADDR_LINKLOCAL) |
739 | ireq->ir_iif = inet6_iif(skb); | 742 | ireq->ir_iif = inet6_iif(skb); |
740 | 743 | ||
741 | if (!TCP_SKB_CB(skb)->when && | 744 | if (!TCP_SKB_CB(skb)->tcp_tw_isn && |
742 | (ipv6_opt_accepted(sk, skb) || np->rxopt.bits.rxinfo || | 745 | (ipv6_opt_accepted(sk, skb, &TCP_SKB_CB(skb)->header.h6) || |
746 | np->rxopt.bits.rxinfo || | ||
743 | np->rxopt.bits.rxoinfo || np->rxopt.bits.rxhlim || | 747 | np->rxopt.bits.rxoinfo || np->rxopt.bits.rxhlim || |
744 | np->rxopt.bits.rxohlim || np->repflow)) { | 748 | np->rxopt.bits.rxohlim || np->repflow)) { |
745 | atomic_inc(&skb->users); | 749 | atomic_inc(&skb->users); |
@@ -1364,7 +1368,7 @@ ipv6_pktoptions: | |||
1364 | np->rcv_flowinfo = ip6_flowinfo(ipv6_hdr(opt_skb)); | 1368 | np->rcv_flowinfo = ip6_flowinfo(ipv6_hdr(opt_skb)); |
1365 | if (np->repflow) | 1369 | if (np->repflow) |
1366 | np->flow_label = ip6_flowlabel(ipv6_hdr(opt_skb)); | 1370 | np->flow_label = ip6_flowlabel(ipv6_hdr(opt_skb)); |
1367 | if (ipv6_opt_accepted(sk, opt_skb)) { | 1371 | if (ipv6_opt_accepted(sk, opt_skb, &TCP_SKB_CB(opt_skb)->header.h6)) { |
1368 | skb_set_owner_r(opt_skb, sk); | 1372 | skb_set_owner_r(opt_skb, sk); |
1369 | opt_skb = xchg(&np->pktoptions, opt_skb); | 1373 | opt_skb = xchg(&np->pktoptions, opt_skb); |
1370 | } else { | 1374 | } else { |
@@ -1408,11 +1412,19 @@ static int tcp_v6_rcv(struct sk_buff *skb) | |||
1408 | 1412 | ||
1409 | th = tcp_hdr(skb); | 1413 | th = tcp_hdr(skb); |
1410 | hdr = ipv6_hdr(skb); | 1414 | hdr = ipv6_hdr(skb); |
1415 | /* This is tricky : We move IPCB at its correct location into TCP_SKB_CB() | ||
1416 | * barrier() makes sure compiler wont play fool^Waliasing games. | ||
1417 | */ | ||
1418 | memmove(&TCP_SKB_CB(skb)->header.h6, IP6CB(skb), | ||
1419 | sizeof(struct inet6_skb_parm)); | ||
1420 | barrier(); | ||
1421 | |||
1411 | TCP_SKB_CB(skb)->seq = ntohl(th->seq); | 1422 | TCP_SKB_CB(skb)->seq = ntohl(th->seq); |
1412 | TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin + | 1423 | TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin + |
1413 | skb->len - th->doff*4); | 1424 | skb->len - th->doff*4); |
1414 | TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq); | 1425 | TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq); |
1415 | TCP_SKB_CB(skb)->when = 0; | 1426 | TCP_SKB_CB(skb)->tcp_flags = tcp_flag_byte(th); |
1427 | TCP_SKB_CB(skb)->tcp_tw_isn = 0; | ||
1416 | TCP_SKB_CB(skb)->ip_dsfield = ipv6_get_dsfield(hdr); | 1428 | TCP_SKB_CB(skb)->ip_dsfield = ipv6_get_dsfield(hdr); |
1417 | TCP_SKB_CB(skb)->sacked = 0; | 1429 | TCP_SKB_CB(skb)->sacked = 0; |
1418 | 1430 | ||
diff --git a/net/ipv6/tcpv6_offload.c b/net/ipv6/tcpv6_offload.c index 01b0ff9a0c2c..c1ab77105b4c 100644 --- a/net/ipv6/tcpv6_offload.c +++ b/net/ipv6/tcpv6_offload.c | |||
@@ -15,54 +15,17 @@ | |||
15 | #include <net/ip6_checksum.h> | 15 | #include <net/ip6_checksum.h> |
16 | #include "ip6_offload.h" | 16 | #include "ip6_offload.h" |
17 | 17 | ||
18 | static int tcp_v6_gso_send_check(struct sk_buff *skb) | ||
19 | { | ||
20 | const struct ipv6hdr *ipv6h; | ||
21 | struct tcphdr *th; | ||
22 | |||
23 | if (!pskb_may_pull(skb, sizeof(*th))) | ||
24 | return -EINVAL; | ||
25 | |||
26 | ipv6h = ipv6_hdr(skb); | ||
27 | th = tcp_hdr(skb); | ||
28 | |||
29 | th->check = 0; | ||
30 | skb->ip_summed = CHECKSUM_PARTIAL; | ||
31 | __tcp_v6_send_check(skb, &ipv6h->saddr, &ipv6h->daddr); | ||
32 | return 0; | ||
33 | } | ||
34 | |||
35 | static struct sk_buff **tcp6_gro_receive(struct sk_buff **head, | 18 | static struct sk_buff **tcp6_gro_receive(struct sk_buff **head, |
36 | struct sk_buff *skb) | 19 | struct sk_buff *skb) |
37 | { | 20 | { |
38 | const struct ipv6hdr *iph = skb_gro_network_header(skb); | ||
39 | __wsum wsum; | ||
40 | |||
41 | /* Don't bother verifying checksum if we're going to flush anyway. */ | 21 | /* Don't bother verifying checksum if we're going to flush anyway. */ |
42 | if (NAPI_GRO_CB(skb)->flush) | 22 | if (!NAPI_GRO_CB(skb)->flush && |
43 | goto skip_csum; | 23 | skb_gro_checksum_validate(skb, IPPROTO_TCP, |
44 | 24 | ip6_gro_compute_pseudo)) { | |
45 | wsum = NAPI_GRO_CB(skb)->csum; | ||
46 | |||
47 | switch (skb->ip_summed) { | ||
48 | case CHECKSUM_NONE: | ||
49 | wsum = skb_checksum(skb, skb_gro_offset(skb), skb_gro_len(skb), | ||
50 | wsum); | ||
51 | |||
52 | /* fall through */ | ||
53 | |||
54 | case CHECKSUM_COMPLETE: | ||
55 | if (!tcp_v6_check(skb_gro_len(skb), &iph->saddr, &iph->daddr, | ||
56 | wsum)) { | ||
57 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
58 | break; | ||
59 | } | ||
60 | |||
61 | NAPI_GRO_CB(skb)->flush = 1; | 25 | NAPI_GRO_CB(skb)->flush = 1; |
62 | return NULL; | 26 | return NULL; |
63 | } | 27 | } |
64 | 28 | ||
65 | skip_csum: | ||
66 | return tcp_gro_receive(head, skb); | 29 | return tcp_gro_receive(head, skb); |
67 | } | 30 | } |
68 | 31 | ||
@@ -78,10 +41,32 @@ static int tcp6_gro_complete(struct sk_buff *skb, int thoff) | |||
78 | return tcp_gro_complete(skb); | 41 | return tcp_gro_complete(skb); |
79 | } | 42 | } |
80 | 43 | ||
44 | struct sk_buff *tcp6_gso_segment(struct sk_buff *skb, | ||
45 | netdev_features_t features) | ||
46 | { | ||
47 | struct tcphdr *th; | ||
48 | |||
49 | if (!pskb_may_pull(skb, sizeof(*th))) | ||
50 | return ERR_PTR(-EINVAL); | ||
51 | |||
52 | if (unlikely(skb->ip_summed != CHECKSUM_PARTIAL)) { | ||
53 | const struct ipv6hdr *ipv6h = ipv6_hdr(skb); | ||
54 | struct tcphdr *th = tcp_hdr(skb); | ||
55 | |||
56 | /* Set up pseudo header, usually expect stack to have done | ||
57 | * this. | ||
58 | */ | ||
59 | |||
60 | th->check = 0; | ||
61 | skb->ip_summed = CHECKSUM_PARTIAL; | ||
62 | __tcp_v6_send_check(skb, &ipv6h->saddr, &ipv6h->daddr); | ||
63 | } | ||
64 | |||
65 | return tcp_gso_segment(skb, features); | ||
66 | } | ||
81 | static const struct net_offload tcpv6_offload = { | 67 | static const struct net_offload tcpv6_offload = { |
82 | .callbacks = { | 68 | .callbacks = { |
83 | .gso_send_check = tcp_v6_gso_send_check, | 69 | .gso_segment = tcp6_gso_segment, |
84 | .gso_segment = tcp_gso_segment, | ||
85 | .gro_receive = tcp6_gro_receive, | 70 | .gro_receive = tcp6_gro_receive, |
86 | .gro_complete = tcp6_gro_complete, | 71 | .gro_complete = tcp6_gro_complete, |
87 | }, | 72 | }, |
diff --git a/net/ipv6/tunnel6.c b/net/ipv6/tunnel6.c index 2c4e4c5c7614..3c758007b327 100644 --- a/net/ipv6/tunnel6.c +++ b/net/ipv6/tunnel6.c | |||
@@ -15,7 +15,7 @@ | |||
15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. | 15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
16 | * | 16 | * |
17 | * Authors Mitsuru KANDA <mk@linux-ipv6.org> | 17 | * Authors Mitsuru KANDA <mk@linux-ipv6.org> |
18 | * YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> | 18 | * YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> |
19 | */ | 19 | */ |
20 | 20 | ||
21 | #define pr_fmt(fmt) "IPv6: " fmt | 21 | #define pr_fmt(fmt) "IPv6: " fmt |
@@ -64,7 +64,6 @@ err: | |||
64 | 64 | ||
65 | return ret; | 65 | return ret; |
66 | } | 66 | } |
67 | |||
68 | EXPORT_SYMBOL(xfrm6_tunnel_register); | 67 | EXPORT_SYMBOL(xfrm6_tunnel_register); |
69 | 68 | ||
70 | int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler, unsigned short family) | 69 | int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler, unsigned short family) |
@@ -92,7 +91,6 @@ int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler, unsigned short family) | |||
92 | 91 | ||
93 | return ret; | 92 | return ret; |
94 | } | 93 | } |
95 | |||
96 | EXPORT_SYMBOL(xfrm6_tunnel_deregister); | 94 | EXPORT_SYMBOL(xfrm6_tunnel_deregister); |
97 | 95 | ||
98 | #define for_each_tunnel_rcu(head, handler) \ | 96 | #define for_each_tunnel_rcu(head, handler) \ |
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 4836af8f582d..f6ba535b6feb 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c | |||
@@ -243,7 +243,7 @@ begin: | |||
243 | goto exact_match; | 243 | goto exact_match; |
244 | } else if (score == badness && reuseport) { | 244 | } else if (score == badness && reuseport) { |
245 | matches++; | 245 | matches++; |
246 | if (((u64)hash * matches) >> 32 == 0) | 246 | if (reciprocal_scale(hash, matches) == 0) |
247 | result = sk; | 247 | result = sk; |
248 | hash = next_pseudo_random32(hash); | 248 | hash = next_pseudo_random32(hash); |
249 | } | 249 | } |
@@ -323,7 +323,7 @@ begin: | |||
323 | } | 323 | } |
324 | } else if (score == badness && reuseport) { | 324 | } else if (score == badness && reuseport) { |
325 | matches++; | 325 | matches++; |
326 | if (((u64)hash * matches) >> 32 == 0) | 326 | if (reciprocal_scale(hash, matches) == 0) |
327 | result = sk; | 327 | result = sk; |
328 | hash = next_pseudo_random32(hash); | 328 | hash = next_pseudo_random32(hash); |
329 | } | 329 | } |
@@ -373,8 +373,8 @@ EXPORT_SYMBOL_GPL(udp6_lib_lookup); | |||
373 | 373 | ||
374 | 374 | ||
375 | /* | 375 | /* |
376 | * This should be easy, if there is something there we | 376 | * This should be easy, if there is something there we |
377 | * return it, otherwise we block. | 377 | * return it, otherwise we block. |
378 | */ | 378 | */ |
379 | 379 | ||
380 | int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk, | 380 | int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk, |
@@ -530,7 +530,7 @@ void __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
530 | const struct ipv6hdr *hdr = (const struct ipv6hdr *)skb->data; | 530 | const struct ipv6hdr *hdr = (const struct ipv6hdr *)skb->data; |
531 | const struct in6_addr *saddr = &hdr->saddr; | 531 | const struct in6_addr *saddr = &hdr->saddr; |
532 | const struct in6_addr *daddr = &hdr->daddr; | 532 | const struct in6_addr *daddr = &hdr->daddr; |
533 | struct udphdr *uh = (struct udphdr*)(skb->data+offset); | 533 | struct udphdr *uh = (struct udphdr *)(skb->data+offset); |
534 | struct sock *sk; | 534 | struct sock *sk; |
535 | int err; | 535 | int err; |
536 | struct net *net = dev_net(skb->dev); | 536 | struct net *net = dev_net(skb->dev); |
@@ -596,7 +596,7 @@ static int __udpv6_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) | |||
596 | 596 | ||
597 | static __inline__ void udpv6_err(struct sk_buff *skb, | 597 | static __inline__ void udpv6_err(struct sk_buff *skb, |
598 | struct inet6_skb_parm *opt, u8 type, | 598 | struct inet6_skb_parm *opt, u8 type, |
599 | u8 code, int offset, __be32 info ) | 599 | u8 code, int offset, __be32 info) |
600 | { | 600 | { |
601 | __udp6_lib_err(skb, opt, type, code, offset, info, &udp_table); | 601 | __udp6_lib_err(skb, opt, type, code, offset, info, &udp_table); |
602 | } | 602 | } |
@@ -891,6 +891,10 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable, | |||
891 | goto csum_error; | 891 | goto csum_error; |
892 | } | 892 | } |
893 | 893 | ||
894 | if (udp_sk(sk)->convert_csum && uh->check && !IS_UDPLITE(sk)) | ||
895 | skb_checksum_try_convert(skb, IPPROTO_UDP, uh->check, | ||
896 | ip6_compute_pseudo); | ||
897 | |||
894 | ret = udpv6_queue_rcv_skb(sk, skb); | 898 | ret = udpv6_queue_rcv_skb(sk, skb); |
895 | sock_put(sk); | 899 | sock_put(sk); |
896 | 900 | ||
@@ -960,10 +964,10 @@ static void udp_v6_flush_pending_frames(struct sock *sk) | |||
960 | } | 964 | } |
961 | 965 | ||
962 | /** | 966 | /** |
963 | * udp6_hwcsum_outgoing - handle outgoing HW checksumming | 967 | * udp6_hwcsum_outgoing - handle outgoing HW checksumming |
964 | * @sk: socket we are sending on | 968 | * @sk: socket we are sending on |
965 | * @skb: sk_buff containing the filled-in UDP header | 969 | * @skb: sk_buff containing the filled-in UDP header |
966 | * (checksum field must be zeroed out) | 970 | * (checksum field must be zeroed out) |
967 | */ | 971 | */ |
968 | static void udp6_hwcsum_outgoing(struct sock *sk, struct sk_buff *skb, | 972 | static void udp6_hwcsum_outgoing(struct sock *sk, struct sk_buff *skb, |
969 | const struct in6_addr *saddr, | 973 | const struct in6_addr *saddr, |
@@ -1294,7 +1298,7 @@ do_append_data: | |||
1294 | getfrag = is_udplite ? udplite_getfrag : ip_generic_getfrag; | 1298 | getfrag = is_udplite ? udplite_getfrag : ip_generic_getfrag; |
1295 | err = ip6_append_data(sk, getfrag, msg->msg_iov, ulen, | 1299 | err = ip6_append_data(sk, getfrag, msg->msg_iov, ulen, |
1296 | sizeof(struct udphdr), hlimit, tclass, opt, &fl6, | 1300 | sizeof(struct udphdr), hlimit, tclass, opt, &fl6, |
1297 | (struct rt6_info*)dst, | 1301 | (struct rt6_info *)dst, |
1298 | corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags, dontfrag); | 1302 | corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags, dontfrag); |
1299 | if (err) | 1303 | if (err) |
1300 | udp_v6_flush_pending_frames(sk); | 1304 | udp_v6_flush_pending_frames(sk); |
diff --git a/net/ipv6/udp_offload.c b/net/ipv6/udp_offload.c index 0ae3d98f83e0..6b8f543f6ac6 100644 --- a/net/ipv6/udp_offload.c +++ b/net/ipv6/udp_offload.c | |||
@@ -10,34 +10,13 @@ | |||
10 | * UDPv6 GSO support | 10 | * UDPv6 GSO support |
11 | */ | 11 | */ |
12 | #include <linux/skbuff.h> | 12 | #include <linux/skbuff.h> |
13 | #include <linux/netdevice.h> | ||
13 | #include <net/protocol.h> | 14 | #include <net/protocol.h> |
14 | #include <net/ipv6.h> | 15 | #include <net/ipv6.h> |
15 | #include <net/udp.h> | 16 | #include <net/udp.h> |
16 | #include <net/ip6_checksum.h> | 17 | #include <net/ip6_checksum.h> |
17 | #include "ip6_offload.h" | 18 | #include "ip6_offload.h" |
18 | 19 | ||
19 | static int udp6_ufo_send_check(struct sk_buff *skb) | ||
20 | { | ||
21 | const struct ipv6hdr *ipv6h; | ||
22 | struct udphdr *uh; | ||
23 | |||
24 | if (!pskb_may_pull(skb, sizeof(*uh))) | ||
25 | return -EINVAL; | ||
26 | |||
27 | if (likely(!skb->encapsulation)) { | ||
28 | ipv6h = ipv6_hdr(skb); | ||
29 | uh = udp_hdr(skb); | ||
30 | |||
31 | uh->check = ~csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr, skb->len, | ||
32 | IPPROTO_UDP, 0); | ||
33 | skb->csum_start = skb_transport_header(skb) - skb->head; | ||
34 | skb->csum_offset = offsetof(struct udphdr, check); | ||
35 | skb->ip_summed = CHECKSUM_PARTIAL; | ||
36 | } | ||
37 | |||
38 | return 0; | ||
39 | } | ||
40 | |||
41 | static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb, | 20 | static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb, |
42 | netdev_features_t features) | 21 | netdev_features_t features) |
43 | { | 22 | { |
@@ -48,7 +27,6 @@ static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb, | |||
48 | u8 *packet_start, *prevhdr; | 27 | u8 *packet_start, *prevhdr; |
49 | u8 nexthdr; | 28 | u8 nexthdr; |
50 | u8 frag_hdr_sz = sizeof(struct frag_hdr); | 29 | u8 frag_hdr_sz = sizeof(struct frag_hdr); |
51 | int offset; | ||
52 | __wsum csum; | 30 | __wsum csum; |
53 | int tnl_hlen; | 31 | int tnl_hlen; |
54 | 32 | ||
@@ -80,15 +58,29 @@ static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb, | |||
80 | 58 | ||
81 | if (skb->encapsulation && skb_shinfo(skb)->gso_type & | 59 | if (skb->encapsulation && skb_shinfo(skb)->gso_type & |
82 | (SKB_GSO_UDP_TUNNEL|SKB_GSO_UDP_TUNNEL_CSUM)) | 60 | (SKB_GSO_UDP_TUNNEL|SKB_GSO_UDP_TUNNEL_CSUM)) |
83 | segs = skb_udp_tunnel_segment(skb, features); | 61 | segs = skb_udp_tunnel_segment(skb, features, true); |
84 | else { | 62 | else { |
63 | const struct ipv6hdr *ipv6h; | ||
64 | struct udphdr *uh; | ||
65 | |||
66 | if (!pskb_may_pull(skb, sizeof(struct udphdr))) | ||
67 | goto out; | ||
68 | |||
85 | /* Do software UFO. Complete and fill in the UDP checksum as HW cannot | 69 | /* Do software UFO. Complete and fill in the UDP checksum as HW cannot |
86 | * do checksum of UDP packets sent as multiple IP fragments. | 70 | * do checksum of UDP packets sent as multiple IP fragments. |
87 | */ | 71 | */ |
88 | offset = skb_checksum_start_offset(skb); | 72 | |
89 | csum = skb_checksum(skb, offset, skb->len - offset, 0); | 73 | uh = udp_hdr(skb); |
90 | offset += skb->csum_offset; | 74 | ipv6h = ipv6_hdr(skb); |
91 | *(__sum16 *)(skb->data + offset) = csum_fold(csum); | 75 | |
76 | uh->check = 0; | ||
77 | csum = skb_checksum(skb, 0, skb->len, 0); | ||
78 | uh->check = udp_v6_check(skb->len, &ipv6h->saddr, | ||
79 | &ipv6h->daddr, csum); | ||
80 | |||
81 | if (uh->check == 0) | ||
82 | uh->check = CSUM_MANGLED_0; | ||
83 | |||
92 | skb->ip_summed = CHECKSUM_NONE; | 84 | skb->ip_summed = CHECKSUM_NONE; |
93 | 85 | ||
94 | /* Check if there is enough headroom to insert fragment header. */ | 86 | /* Check if there is enough headroom to insert fragment header. */ |
@@ -127,10 +119,52 @@ static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb, | |||
127 | out: | 119 | out: |
128 | return segs; | 120 | return segs; |
129 | } | 121 | } |
122 | |||
123 | static struct sk_buff **udp6_gro_receive(struct sk_buff **head, | ||
124 | struct sk_buff *skb) | ||
125 | { | ||
126 | struct udphdr *uh = udp_gro_udphdr(skb); | ||
127 | |||
128 | if (unlikely(!uh)) | ||
129 | goto flush; | ||
130 | |||
131 | /* Don't bother verifying checksum if we're going to flush anyway. */ | ||
132 | if (NAPI_GRO_CB(skb)->flush) | ||
133 | goto skip; | ||
134 | |||
135 | if (skb_gro_checksum_validate_zero_check(skb, IPPROTO_UDP, uh->check, | ||
136 | ip6_gro_compute_pseudo)) | ||
137 | goto flush; | ||
138 | else if (uh->check) | ||
139 | skb_gro_checksum_try_convert(skb, IPPROTO_UDP, uh->check, | ||
140 | ip6_gro_compute_pseudo); | ||
141 | |||
142 | skip: | ||
143 | NAPI_GRO_CB(skb)->is_ipv6 = 1; | ||
144 | return udp_gro_receive(head, skb, uh); | ||
145 | |||
146 | flush: | ||
147 | NAPI_GRO_CB(skb)->flush = 1; | ||
148 | return NULL; | ||
149 | } | ||
150 | |||
151 | static int udp6_gro_complete(struct sk_buff *skb, int nhoff) | ||
152 | { | ||
153 | const struct ipv6hdr *ipv6h = ipv6_hdr(skb); | ||
154 | struct udphdr *uh = (struct udphdr *)(skb->data + nhoff); | ||
155 | |||
156 | if (uh->check) | ||
157 | uh->check = ~udp_v6_check(skb->len - nhoff, &ipv6h->saddr, | ||
158 | &ipv6h->daddr, 0); | ||
159 | |||
160 | return udp_gro_complete(skb, nhoff); | ||
161 | } | ||
162 | |||
130 | static const struct net_offload udpv6_offload = { | 163 | static const struct net_offload udpv6_offload = { |
131 | .callbacks = { | 164 | .callbacks = { |
132 | .gso_send_check = udp6_ufo_send_check, | ||
133 | .gso_segment = udp6_ufo_fragment, | 165 | .gso_segment = udp6_ufo_fragment, |
166 | .gro_receive = udp6_gro_receive, | ||
167 | .gro_complete = udp6_gro_complete, | ||
134 | }, | 168 | }, |
135 | }; | 169 | }; |
136 | 170 | ||
diff --git a/net/ipv6/xfrm6_input.c b/net/ipv6/xfrm6_input.c index f8c3cf842f53..f48fbe4d16f5 100644 --- a/net/ipv6/xfrm6_input.c +++ b/net/ipv6/xfrm6_input.c | |||
@@ -3,8 +3,8 @@ | |||
3 | * | 3 | * |
4 | * Authors: | 4 | * Authors: |
5 | * Mitsuru KANDA @USAGI | 5 | * Mitsuru KANDA @USAGI |
6 | * Kazunori MIYAZAWA @USAGI | 6 | * Kazunori MIYAZAWA @USAGI |
7 | * Kunihiro Ishiguro <kunihiro@ipinfusion.com> | 7 | * Kunihiro Ishiguro <kunihiro@ipinfusion.com> |
8 | * YOSHIFUJI Hideaki @USAGI | 8 | * YOSHIFUJI Hideaki @USAGI |
9 | * IPv6 support | 9 | * IPv6 support |
10 | */ | 10 | */ |
@@ -52,7 +52,6 @@ int xfrm6_rcv(struct sk_buff *skb) | |||
52 | return xfrm6_rcv_spi(skb, skb_network_header(skb)[IP6CB(skb)->nhoff], | 52 | return xfrm6_rcv_spi(skb, skb_network_header(skb)[IP6CB(skb)->nhoff], |
53 | 0); | 53 | 0); |
54 | } | 54 | } |
55 | |||
56 | EXPORT_SYMBOL(xfrm6_rcv); | 55 | EXPORT_SYMBOL(xfrm6_rcv); |
57 | 56 | ||
58 | int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr, | 57 | int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr, |
@@ -142,5 +141,4 @@ int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr, | |||
142 | drop: | 141 | drop: |
143 | return -1; | 142 | return -1; |
144 | } | 143 | } |
145 | |||
146 | EXPORT_SYMBOL(xfrm6_input_addr); | 144 | EXPORT_SYMBOL(xfrm6_input_addr); |
diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c index 433672d07d0b..ca3f29b98ae5 100644 --- a/net/ipv6/xfrm6_output.c +++ b/net/ipv6/xfrm6_output.c | |||
@@ -25,7 +25,6 @@ int xfrm6_find_1stfragopt(struct xfrm_state *x, struct sk_buff *skb, | |||
25 | { | 25 | { |
26 | return ip6_find_1stfragopt(skb, prevhdr); | 26 | return ip6_find_1stfragopt(skb, prevhdr); |
27 | } | 27 | } |
28 | |||
29 | EXPORT_SYMBOL(xfrm6_find_1stfragopt); | 28 | EXPORT_SYMBOL(xfrm6_find_1stfragopt); |
30 | 29 | ||
31 | static int xfrm6_local_dontfrag(struct sk_buff *skb) | 30 | static int xfrm6_local_dontfrag(struct sk_buff *skb) |
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c index 2a0bbda2c76a..ac49f84fe2c3 100644 --- a/net/ipv6/xfrm6_policy.c +++ b/net/ipv6/xfrm6_policy.c | |||
@@ -3,11 +3,11 @@ | |||
3 | * | 3 | * |
4 | * Authors: | 4 | * Authors: |
5 | * Mitsuru KANDA @USAGI | 5 | * Mitsuru KANDA @USAGI |
6 | * Kazunori MIYAZAWA @USAGI | 6 | * Kazunori MIYAZAWA @USAGI |
7 | * Kunihiro Ishiguro <kunihiro@ipinfusion.com> | 7 | * Kunihiro Ishiguro <kunihiro@ipinfusion.com> |
8 | * IPv6 support | 8 | * IPv6 support |
9 | * YOSHIFUJI Hideaki | 9 | * YOSHIFUJI Hideaki |
10 | * Split up af-specific portion | 10 | * Split up af-specific portion |
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
@@ -84,7 +84,7 @@ static int xfrm6_init_path(struct xfrm_dst *path, struct dst_entry *dst, | |||
84 | int nfheader_len) | 84 | int nfheader_len) |
85 | { | 85 | { |
86 | if (dst->ops->family == AF_INET6) { | 86 | if (dst->ops->family == AF_INET6) { |
87 | struct rt6_info *rt = (struct rt6_info*)dst; | 87 | struct rt6_info *rt = (struct rt6_info *)dst; |
88 | if (rt->rt6i_node) | 88 | if (rt->rt6i_node) |
89 | path->path_cookie = rt->rt6i_node->fn_sernum; | 89 | path->path_cookie = rt->rt6i_node->fn_sernum; |
90 | } | 90 | } |
@@ -97,7 +97,7 @@ static int xfrm6_init_path(struct xfrm_dst *path, struct dst_entry *dst, | |||
97 | static int xfrm6_fill_dst(struct xfrm_dst *xdst, struct net_device *dev, | 97 | static int xfrm6_fill_dst(struct xfrm_dst *xdst, struct net_device *dev, |
98 | const struct flowi *fl) | 98 | const struct flowi *fl) |
99 | { | 99 | { |
100 | struct rt6_info *rt = (struct rt6_info*)xdst->route; | 100 | struct rt6_info *rt = (struct rt6_info *)xdst->route; |
101 | 101 | ||
102 | xdst->u.dst.dev = dev; | 102 | xdst->u.dst.dev = dev; |
103 | dev_hold(dev); | 103 | dev_hold(dev); |
@@ -296,7 +296,7 @@ static struct xfrm_policy_afinfo xfrm6_policy_afinfo = { | |||
296 | .family = AF_INET6, | 296 | .family = AF_INET6, |
297 | .dst_ops = &xfrm6_dst_ops, | 297 | .dst_ops = &xfrm6_dst_ops, |
298 | .dst_lookup = xfrm6_dst_lookup, | 298 | .dst_lookup = xfrm6_dst_lookup, |
299 | .get_saddr = xfrm6_get_saddr, | 299 | .get_saddr = xfrm6_get_saddr, |
300 | .decode_session = _decode_session6, | 300 | .decode_session = _decode_session6, |
301 | .get_tos = xfrm6_get_tos, | 301 | .get_tos = xfrm6_get_tos, |
302 | .init_dst = xfrm6_init_dst, | 302 | .init_dst = xfrm6_init_dst, |
@@ -319,9 +319,9 @@ static void xfrm6_policy_fini(void) | |||
319 | static struct ctl_table xfrm6_policy_table[] = { | 319 | static struct ctl_table xfrm6_policy_table[] = { |
320 | { | 320 | { |
321 | .procname = "xfrm6_gc_thresh", | 321 | .procname = "xfrm6_gc_thresh", |
322 | .data = &init_net.xfrm.xfrm6_dst_ops.gc_thresh, | 322 | .data = &init_net.xfrm.xfrm6_dst_ops.gc_thresh, |
323 | .maxlen = sizeof(int), | 323 | .maxlen = sizeof(int), |
324 | .mode = 0644, | 324 | .mode = 0644, |
325 | .proc_handler = proc_dointvec, | 325 | .proc_handler = proc_dointvec, |
326 | }, | 326 | }, |
327 | { } | 327 | { } |
diff --git a/net/ipv6/xfrm6_state.c b/net/ipv6/xfrm6_state.c index 3fc970135fc6..8a1f9c0d2a13 100644 --- a/net/ipv6/xfrm6_state.c +++ b/net/ipv6/xfrm6_state.c | |||
@@ -3,11 +3,11 @@ | |||
3 | * | 3 | * |
4 | * Authors: | 4 | * Authors: |
5 | * Mitsuru KANDA @USAGI | 5 | * Mitsuru KANDA @USAGI |
6 | * Kazunori MIYAZAWA @USAGI | 6 | * Kazunori MIYAZAWA @USAGI |
7 | * Kunihiro Ishiguro <kunihiro@ipinfusion.com> | 7 | * Kunihiro Ishiguro <kunihiro@ipinfusion.com> |
8 | * IPv6 support | 8 | * IPv6 support |
9 | * YOSHIFUJI Hideaki @USAGI | 9 | * YOSHIFUJI Hideaki @USAGI |
10 | * Split up af-specific portion | 10 | * Split up af-specific portion |
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
@@ -45,10 +45,10 @@ xfrm6_init_temprop(struct xfrm_state *x, const struct xfrm_tmpl *tmpl, | |||
45 | const xfrm_address_t *daddr, const xfrm_address_t *saddr) | 45 | const xfrm_address_t *daddr, const xfrm_address_t *saddr) |
46 | { | 46 | { |
47 | x->id = tmpl->id; | 47 | x->id = tmpl->id; |
48 | if (ipv6_addr_any((struct in6_addr*)&x->id.daddr)) | 48 | if (ipv6_addr_any((struct in6_addr *)&x->id.daddr)) |
49 | memcpy(&x->id.daddr, daddr, sizeof(x->sel.daddr)); | 49 | memcpy(&x->id.daddr, daddr, sizeof(x->sel.daddr)); |
50 | memcpy(&x->props.saddr, &tmpl->saddr, sizeof(x->props.saddr)); | 50 | memcpy(&x->props.saddr, &tmpl->saddr, sizeof(x->props.saddr)); |
51 | if (ipv6_addr_any((struct in6_addr*)&x->props.saddr)) | 51 | if (ipv6_addr_any((struct in6_addr *)&x->props.saddr)) |
52 | memcpy(&x->props.saddr, saddr, sizeof(x->props.saddr)); | 52 | memcpy(&x->props.saddr, saddr, sizeof(x->props.saddr)); |
53 | x->props.mode = tmpl->mode; | 53 | x->props.mode = tmpl->mode; |
54 | x->props.reqid = tmpl->reqid; | 54 | x->props.reqid = tmpl->reqid; |
diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c index 1c66465a42dd..5743044cd660 100644 --- a/net/ipv6/xfrm6_tunnel.c +++ b/net/ipv6/xfrm6_tunnel.c | |||
@@ -15,7 +15,7 @@ | |||
15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. | 15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
16 | * | 16 | * |
17 | * Authors Mitsuru KANDA <mk@linux-ipv6.org> | 17 | * Authors Mitsuru KANDA <mk@linux-ipv6.org> |
18 | * YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> | 18 | * YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> |
19 | * | 19 | * |
20 | * Based on net/ipv4/xfrm4_tunnel.c | 20 | * Based on net/ipv4/xfrm4_tunnel.c |
21 | * | 21 | * |
@@ -110,7 +110,6 @@ __be32 xfrm6_tunnel_spi_lookup(struct net *net, const xfrm_address_t *saddr) | |||
110 | rcu_read_unlock_bh(); | 110 | rcu_read_unlock_bh(); |
111 | return htonl(spi); | 111 | return htonl(spi); |
112 | } | 112 | } |
113 | |||
114 | EXPORT_SYMBOL(xfrm6_tunnel_spi_lookup); | 113 | EXPORT_SYMBOL(xfrm6_tunnel_spi_lookup); |
115 | 114 | ||
116 | static int __xfrm6_tunnel_spi_check(struct net *net, u32 spi) | 115 | static int __xfrm6_tunnel_spi_check(struct net *net, u32 spi) |
@@ -187,7 +186,6 @@ __be32 xfrm6_tunnel_alloc_spi(struct net *net, xfrm_address_t *saddr) | |||
187 | 186 | ||
188 | return htonl(spi); | 187 | return htonl(spi); |
189 | } | 188 | } |
190 | |||
191 | EXPORT_SYMBOL(xfrm6_tunnel_alloc_spi); | 189 | EXPORT_SYMBOL(xfrm6_tunnel_alloc_spi); |
192 | 190 | ||
193 | static void x6spi_destroy_rcu(struct rcu_head *head) | 191 | static void x6spi_destroy_rcu(struct rcu_head *head) |