diff options
Diffstat (limited to 'net/ipv6/udp.c')
-rw-r--r-- | net/ipv6/udp.c | 70 |
1 files changed, 30 insertions, 40 deletions
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index dfaa29b8b293..599e1ba6d1ce 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c | |||
@@ -45,6 +45,7 @@ | |||
45 | #include <net/tcp_states.h> | 45 | #include <net/tcp_states.h> |
46 | #include <net/ip6_checksum.h> | 46 | #include <net/ip6_checksum.h> |
47 | #include <net/xfrm.h> | 47 | #include <net/xfrm.h> |
48 | #include <net/inet6_hashtables.h> | ||
48 | 49 | ||
49 | #include <linux/proc_fs.h> | 50 | #include <linux/proc_fs.h> |
50 | #include <linux/seq_file.h> | 51 | #include <linux/seq_file.h> |
@@ -203,7 +204,8 @@ static struct sock *udp6_lib_lookup2(struct net *net, | |||
203 | { | 204 | { |
204 | struct sock *sk, *result; | 205 | struct sock *sk, *result; |
205 | struct hlist_nulls_node *node; | 206 | struct hlist_nulls_node *node; |
206 | int score, badness; | 207 | int score, badness, matches = 0, reuseport = 0; |
208 | u32 hash = 0; | ||
207 | 209 | ||
208 | begin: | 210 | begin: |
209 | result = NULL; | 211 | result = NULL; |
@@ -214,8 +216,18 @@ begin: | |||
214 | if (score > badness) { | 216 | if (score > badness) { |
215 | result = sk; | 217 | result = sk; |
216 | badness = score; | 218 | badness = score; |
217 | if (score == SCORE2_MAX) | 219 | reuseport = sk->sk_reuseport; |
220 | if (reuseport) { | ||
221 | hash = inet6_ehashfn(net, daddr, hnum, | ||
222 | saddr, sport); | ||
223 | matches = 1; | ||
224 | } else if (score == SCORE2_MAX) | ||
218 | goto exact_match; | 225 | goto exact_match; |
226 | } else if (score == badness && reuseport) { | ||
227 | matches++; | ||
228 | if (((u64)hash * matches) >> 32 == 0) | ||
229 | result = sk; | ||
230 | hash = next_pseudo_random32(hash); | ||
219 | } | 231 | } |
220 | } | 232 | } |
221 | /* | 233 | /* |
@@ -249,7 +261,8 @@ struct sock *__udp6_lib_lookup(struct net *net, | |||
249 | unsigned short hnum = ntohs(dport); | 261 | unsigned short hnum = ntohs(dport); |
250 | unsigned int hash2, slot2, slot = udp_hashfn(net, hnum, udptable->mask); | 262 | unsigned int hash2, slot2, slot = udp_hashfn(net, hnum, udptable->mask); |
251 | struct udp_hslot *hslot2, *hslot = &udptable->hash[slot]; | 263 | struct udp_hslot *hslot2, *hslot = &udptable->hash[slot]; |
252 | int score, badness; | 264 | int score, badness, matches = 0, reuseport = 0; |
265 | u32 hash = 0; | ||
253 | 266 | ||
254 | rcu_read_lock(); | 267 | rcu_read_lock(); |
255 | if (hslot->count > 10) { | 268 | if (hslot->count > 10) { |
@@ -284,6 +297,17 @@ begin: | |||
284 | if (score > badness) { | 297 | if (score > badness) { |
285 | result = sk; | 298 | result = sk; |
286 | badness = score; | 299 | badness = score; |
300 | reuseport = sk->sk_reuseport; | ||
301 | if (reuseport) { | ||
302 | hash = inet6_ehashfn(net, daddr, hnum, | ||
303 | saddr, sport); | ||
304 | matches = 1; | ||
305 | } | ||
306 | } else if (score == badness && reuseport) { | ||
307 | matches++; | ||
308 | if (((u64)hash * matches) >> 32 == 0) | ||
309 | result = sk; | ||
310 | hash = next_pseudo_random32(hash); | ||
287 | } | 311 | } |
288 | } | 312 | } |
289 | /* | 313 | /* |
@@ -443,7 +467,7 @@ try_again: | |||
443 | ip_cmsg_recv(msg, skb); | 467 | ip_cmsg_recv(msg, skb); |
444 | } else { | 468 | } else { |
445 | if (np->rxopt.all) | 469 | if (np->rxopt.all) |
446 | datagram_recv_ctl(sk, msg, skb); | 470 | ip6_datagram_recv_ctl(sk, msg, skb); |
447 | } | 471 | } |
448 | 472 | ||
449 | err = copied; | 473 | err = copied; |
@@ -752,40 +776,6 @@ static int __udp6_lib_mcast_deliver(struct net *net, struct sk_buff *skb, | |||
752 | return 0; | 776 | return 0; |
753 | } | 777 | } |
754 | 778 | ||
755 | static inline int udp6_csum_init(struct sk_buff *skb, struct udphdr *uh, | ||
756 | int proto) | ||
757 | { | ||
758 | int err; | ||
759 | |||
760 | UDP_SKB_CB(skb)->partial_cov = 0; | ||
761 | UDP_SKB_CB(skb)->cscov = skb->len; | ||
762 | |||
763 | if (proto == IPPROTO_UDPLITE) { | ||
764 | err = udplite_checksum_init(skb, uh); | ||
765 | if (err) | ||
766 | return err; | ||
767 | } | ||
768 | |||
769 | if (uh->check == 0) { | ||
770 | /* RFC 2460 section 8.1 says that we SHOULD log | ||
771 | this error. Well, it is reasonable. | ||
772 | */ | ||
773 | LIMIT_NETDEBUG(KERN_INFO "IPv6: udp checksum is 0\n"); | ||
774 | return 1; | ||
775 | } | ||
776 | if (skb->ip_summed == CHECKSUM_COMPLETE && | ||
777 | !csum_ipv6_magic(&ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, | ||
778 | skb->len, proto, skb->csum)) | ||
779 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
780 | |||
781 | if (!skb_csum_unnecessary(skb)) | ||
782 | skb->csum = ~csum_unfold(csum_ipv6_magic(&ipv6_hdr(skb)->saddr, | ||
783 | &ipv6_hdr(skb)->daddr, | ||
784 | skb->len, proto, 0)); | ||
785 | |||
786 | return 0; | ||
787 | } | ||
788 | |||
789 | int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable, | 779 | int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable, |
790 | int proto) | 780 | int proto) |
791 | { | 781 | { |
@@ -1153,8 +1143,8 @@ do_udp_sendmsg: | |||
1153 | memset(opt, 0, sizeof(struct ipv6_txoptions)); | 1143 | memset(opt, 0, sizeof(struct ipv6_txoptions)); |
1154 | opt->tot_len = sizeof(*opt); | 1144 | opt->tot_len = sizeof(*opt); |
1155 | 1145 | ||
1156 | err = datagram_send_ctl(sock_net(sk), sk, msg, &fl6, opt, | 1146 | err = ip6_datagram_send_ctl(sock_net(sk), sk, msg, &fl6, opt, |
1157 | &hlimit, &tclass, &dontfrag); | 1147 | &hlimit, &tclass, &dontfrag); |
1158 | if (err < 0) { | 1148 | if (err < 0) { |
1159 | fl6_sock_release(flowlabel); | 1149 | fl6_sock_release(flowlabel); |
1160 | return err; | 1150 | return err; |