diff options
Diffstat (limited to 'fs/nfs/client.c')
-rw-r--r-- | fs/nfs/client.c | 116 |
1 files changed, 52 insertions, 64 deletions
diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 574158ae2398..855daac0f246 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c | |||
@@ -224,38 +224,6 @@ void nfs_put_client(struct nfs_client *clp) | |||
224 | } | 224 | } |
225 | 225 | ||
226 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | 226 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) |
227 | static const struct in6_addr *nfs_map_ipv4_addr(const struct sockaddr *sa, struct in6_addr *addr_mapped) | ||
228 | { | ||
229 | switch (sa->sa_family) { | ||
230 | default: | ||
231 | return NULL; | ||
232 | case AF_INET6: | ||
233 | return &((const struct sockaddr_in6 *)sa)->sin6_addr; | ||
234 | break; | ||
235 | case AF_INET: | ||
236 | ipv6_addr_set_v4mapped(((const struct sockaddr_in *)sa)->sin_addr.s_addr, | ||
237 | addr_mapped); | ||
238 | return addr_mapped; | ||
239 | } | ||
240 | } | ||
241 | |||
242 | static int nfs_sockaddr_match_ipaddr(const struct sockaddr *sa1, | ||
243 | const struct sockaddr *sa2) | ||
244 | { | ||
245 | const struct in6_addr *addr1; | ||
246 | const struct in6_addr *addr2; | ||
247 | struct in6_addr addr1_mapped; | ||
248 | struct in6_addr addr2_mapped; | ||
249 | |||
250 | addr1 = nfs_map_ipv4_addr(sa1, &addr1_mapped); | ||
251 | if (likely(addr1 != NULL)) { | ||
252 | addr2 = nfs_map_ipv4_addr(sa2, &addr2_mapped); | ||
253 | if (likely(addr2 != NULL)) | ||
254 | return ipv6_addr_equal(addr1, addr2); | ||
255 | } | ||
256 | return 0; | ||
257 | } | ||
258 | |||
259 | /* | 227 | /* |
260 | * Test if two ip6 socket addresses refer to the same socket by | 228 | * Test if two ip6 socket addresses refer to the same socket by |
261 | * comparing relevant fields. The padding bytes specifically, are not | 229 | * comparing relevant fields. The padding bytes specifically, are not |
@@ -267,38 +235,21 @@ static int nfs_sockaddr_match_ipaddr(const struct sockaddr *sa1, | |||
267 | * | 235 | * |
268 | * The caller should ensure both socket addresses are AF_INET6. | 236 | * The caller should ensure both socket addresses are AF_INET6. |
269 | */ | 237 | */ |
270 | static int nfs_sockaddr_cmp_ip6(const struct sockaddr *sa1, | 238 | static int nfs_sockaddr_match_ipaddr6(const struct sockaddr *sa1, |
271 | const struct sockaddr *sa2) | 239 | const struct sockaddr *sa2) |
272 | { | 240 | { |
273 | const struct sockaddr_in6 *saddr1 = (const struct sockaddr_in6 *)sa1; | 241 | const struct sockaddr_in6 *sin1 = (const struct sockaddr_in6 *)sa1; |
274 | const struct sockaddr_in6 *saddr2 = (const struct sockaddr_in6 *)sa2; | 242 | const struct sockaddr_in6 *sin2 = (const struct sockaddr_in6 *)sa2; |
275 | 243 | ||
276 | if (!ipv6_addr_equal(&saddr1->sin6_addr, | 244 | if (ipv6_addr_scope(&sin1->sin6_addr) == IPV6_ADDR_SCOPE_LINKLOCAL && |
277 | &saddr1->sin6_addr)) | 245 | sin1->sin6_scope_id != sin2->sin6_scope_id) |
278 | return 0; | 246 | return 0; |
279 | if (ipv6_addr_scope(&saddr1->sin6_addr) == IPV6_ADDR_SCOPE_LINKLOCAL && | ||
280 | saddr1->sin6_scope_id != saddr2->sin6_scope_id) | ||
281 | return 0; | ||
282 | return saddr1->sin6_port == saddr2->sin6_port; | ||
283 | } | ||
284 | #else | ||
285 | static int nfs_sockaddr_match_ipaddr4(const struct sockaddr_in *sa1, | ||
286 | const struct sockaddr_in *sa2) | ||
287 | { | ||
288 | return sa1->sin_addr.s_addr == sa2->sin_addr.s_addr; | ||
289 | } | ||
290 | 247 | ||
291 | static int nfs_sockaddr_match_ipaddr(const struct sockaddr *sa1, | 248 | return ipv6_addr_equal(&sin1->sin6_addr, &sin1->sin6_addr); |
292 | const struct sockaddr *sa2) | ||
293 | { | ||
294 | if (unlikely(sa1->sa_family != AF_INET || sa2->sa_family != AF_INET)) | ||
295 | return 0; | ||
296 | return nfs_sockaddr_match_ipaddr4((const struct sockaddr_in *)sa1, | ||
297 | (const struct sockaddr_in *)sa2); | ||
298 | } | 249 | } |
299 | 250 | #else /* !defined(CONFIG_IPV6) && !defined(CONFIG_IPV6_MODULE) */ | |
300 | static int nfs_sockaddr_cmp_ip6(const struct sockaddr * sa1, | 251 | static int nfs_sockaddr_match_ipaddr6(const struct sockaddr *sa1, |
301 | const struct sockaddr * sa2) | 252 | const struct sockaddr *sa2) |
302 | { | 253 | { |
303 | return 0; | 254 | return 0; |
304 | } | 255 | } |
@@ -311,20 +262,57 @@ static int nfs_sockaddr_cmp_ip6(const struct sockaddr * sa1, | |||
311 | * | 262 | * |
312 | * The caller should ensure both socket addresses are AF_INET. | 263 | * The caller should ensure both socket addresses are AF_INET. |
313 | */ | 264 | */ |
265 | static int nfs_sockaddr_match_ipaddr4(const struct sockaddr *sa1, | ||
266 | const struct sockaddr *sa2) | ||
267 | { | ||
268 | const struct sockaddr_in *sin1 = (const struct sockaddr_in *)sa1; | ||
269 | const struct sockaddr_in *sin2 = (const struct sockaddr_in *)sa2; | ||
270 | |||
271 | return sin1->sin_addr.s_addr == sin2->sin_addr.s_addr; | ||
272 | } | ||
273 | |||
274 | static int nfs_sockaddr_cmp_ip6(const struct sockaddr *sa1, | ||
275 | const struct sockaddr *sa2) | ||
276 | { | ||
277 | const struct sockaddr_in6 *sin1 = (const struct sockaddr_in6 *)sa1; | ||
278 | const struct sockaddr_in6 *sin2 = (const struct sockaddr_in6 *)sa2; | ||
279 | |||
280 | return nfs_sockaddr_match_ipaddr6(sa1, sa2) && | ||
281 | (sin1->sin6_port == sin2->sin6_port); | ||
282 | } | ||
283 | |||
314 | static int nfs_sockaddr_cmp_ip4(const struct sockaddr *sa1, | 284 | static int nfs_sockaddr_cmp_ip4(const struct sockaddr *sa1, |
315 | const struct sockaddr *sa2) | 285 | const struct sockaddr *sa2) |
316 | { | 286 | { |
317 | const struct sockaddr_in *saddr1 = (const struct sockaddr_in *)sa1; | 287 | const struct sockaddr_in *sin1 = (const struct sockaddr_in *)sa1; |
318 | const struct sockaddr_in *saddr2 = (const struct sockaddr_in *)sa2; | 288 | const struct sockaddr_in *sin2 = (const struct sockaddr_in *)sa2; |
319 | 289 | ||
320 | if (saddr1->sin_addr.s_addr != saddr2->sin_addr.s_addr) | 290 | return nfs_sockaddr_match_ipaddr4(sa1, sa2) && |
291 | (sin1->sin_port == sin2->sin_port); | ||
292 | } | ||
293 | |||
294 | /* | ||
295 | * Test if two socket addresses represent the same actual socket, | ||
296 | * by comparing (only) relevant fields, excluding the port number. | ||
297 | */ | ||
298 | static int nfs_sockaddr_match_ipaddr(const struct sockaddr *sa1, | ||
299 | const struct sockaddr *sa2) | ||
300 | { | ||
301 | if (sa1->sa_family != sa2->sa_family) | ||
321 | return 0; | 302 | return 0; |
322 | return saddr1->sin_port == saddr2->sin_port; | 303 | |
304 | switch (sa1->sa_family) { | ||
305 | case AF_INET: | ||
306 | return nfs_sockaddr_match_ipaddr4(sa1, sa2); | ||
307 | case AF_INET6: | ||
308 | return nfs_sockaddr_match_ipaddr6(sa1, sa2); | ||
309 | } | ||
310 | return 0; | ||
323 | } | 311 | } |
324 | 312 | ||
325 | /* | 313 | /* |
326 | * Test if two socket addresses represent the same actual socket, | 314 | * Test if two socket addresses represent the same actual socket, |
327 | * by comparing (only) relevant fields. | 315 | * by comparing (only) relevant fields, including the port number. |
328 | */ | 316 | */ |
329 | static int nfs_sockaddr_cmp(const struct sockaddr *sa1, | 317 | static int nfs_sockaddr_cmp(const struct sockaddr *sa1, |
330 | const struct sockaddr *sa2) | 318 | const struct sockaddr *sa2) |