diff options
Diffstat (limited to 'net/ipv6/udp.c')
-rw-r--r-- | net/ipv6/udp.c | 27 |
1 files changed, 25 insertions, 2 deletions
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 5bc7cdbf030a..1e5fadd997b7 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c | |||
@@ -81,8 +81,30 @@ int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2) | |||
81 | return 0; | 81 | return 0; |
82 | } | 82 | } |
83 | 83 | ||
84 | static unsigned int udp6_portaddr_hash(struct net *net, | ||
85 | const struct in6_addr *addr6, | ||
86 | unsigned int port) | ||
87 | { | ||
88 | unsigned int hash, mix = net_hash_mix(net); | ||
89 | |||
90 | if (ipv6_addr_any(addr6)) | ||
91 | hash = jhash_1word(0, mix); | ||
92 | else if (ipv6_addr_type(addr6) == IPV6_ADDR_MAPPED) | ||
93 | hash = jhash_1word(addr6->s6_addr32[3], mix); | ||
94 | else | ||
95 | hash = jhash2(addr6->s6_addr32, 4, mix); | ||
96 | |||
97 | return hash ^ port; | ||
98 | } | ||
99 | |||
100 | |||
84 | int udp_v6_get_port(struct sock *sk, unsigned short snum) | 101 | int udp_v6_get_port(struct sock *sk, unsigned short snum) |
85 | { | 102 | { |
103 | /* precompute partial secondary hash */ | ||
104 | udp_sk(sk)->udp_portaddr_hash = | ||
105 | udp6_portaddr_hash(sock_net(sk), | ||
106 | &inet6_sk(sk)->rcv_saddr, | ||
107 | 0); | ||
86 | return udp_lib_get_port(sk, snum, ipv6_rcv_saddr_equal); | 108 | return udp_lib_get_port(sk, snum, ipv6_rcv_saddr_equal); |
87 | } | 109 | } |
88 | 110 | ||
@@ -94,7 +116,7 @@ static inline int compute_score(struct sock *sk, struct net *net, | |||
94 | { | 116 | { |
95 | int score = -1; | 117 | int score = -1; |
96 | 118 | ||
97 | if (net_eq(sock_net(sk), net) && sk->sk_hash == hnum && | 119 | if (net_eq(sock_net(sk), net) && udp_sk(sk)->udp_port_hash == hnum && |
98 | sk->sk_family == PF_INET6) { | 120 | sk->sk_family == PF_INET6) { |
99 | struct ipv6_pinfo *np = inet6_sk(sk); | 121 | struct ipv6_pinfo *np = inet6_sk(sk); |
100 | struct inet_sock *inet = inet_sk(sk); | 122 | struct inet_sock *inet = inet_sk(sk); |
@@ -415,7 +437,8 @@ static struct sock *udp_v6_mcast_next(struct net *net, struct sock *sk, | |||
415 | if (!net_eq(sock_net(s), net)) | 437 | if (!net_eq(sock_net(s), net)) |
416 | continue; | 438 | continue; |
417 | 439 | ||
418 | if (s->sk_hash == num && s->sk_family == PF_INET6) { | 440 | if (udp_sk(s)->udp_port_hash == num && |
441 | s->sk_family == PF_INET6) { | ||
419 | struct ipv6_pinfo *np = inet6_sk(s); | 442 | struct ipv6_pinfo *np = inet6_sk(s); |
420 | if (inet->inet_dport) { | 443 | if (inet->inet_dport) { |
421 | if (inet->inet_dport != rmt_port) | 444 | if (inet->inet_dport != rmt_port) |