diff options
-rw-r--r-- | fs/nfs/client.c | 68 |
1 files changed, 39 insertions, 29 deletions
diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 06654b831d19..574158ae2398 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c | |||
@@ -255,6 +255,32 @@ static int nfs_sockaddr_match_ipaddr(const struct sockaddr *sa1, | |||
255 | } | 255 | } |
256 | return 0; | 256 | return 0; |
257 | } | 257 | } |
258 | |||
259 | /* | ||
260 | * Test if two ip6 socket addresses refer to the same socket by | ||
261 | * comparing relevant fields. The padding bytes specifically, are not | ||
262 | * compared. sin6_flowinfo is not compared because it only affects QoS | ||
263 | * and sin6_scope_id is only compared if the address is "link local" | ||
264 | * because "link local" addresses need only be unique to a specific | ||
265 | * link. Conversely, ordinary unicast addresses might have different | ||
266 | * sin6_scope_id. | ||
267 | * | ||
268 | * The caller should ensure both socket addresses are AF_INET6. | ||
269 | */ | ||
270 | static int nfs_sockaddr_cmp_ip6(const struct sockaddr *sa1, | ||
271 | const struct sockaddr *sa2) | ||
272 | { | ||
273 | const struct sockaddr_in6 *saddr1 = (const struct sockaddr_in6 *)sa1; | ||
274 | const struct sockaddr_in6 *saddr2 = (const struct sockaddr_in6 *)sa2; | ||
275 | |||
276 | if (!ipv6_addr_equal(&saddr1->sin6_addr, | ||
277 | &saddr1->sin6_addr)) | ||
278 | 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 | } | ||
258 | #else | 284 | #else |
259 | static int nfs_sockaddr_match_ipaddr4(const struct sockaddr_in *sa1, | 285 | static int nfs_sockaddr_match_ipaddr4(const struct sockaddr_in *sa1, |
260 | const struct sockaddr_in *sa2) | 286 | const struct sockaddr_in *sa2) |
@@ -270,6 +296,12 @@ static int nfs_sockaddr_match_ipaddr(const struct sockaddr *sa1, | |||
270 | return nfs_sockaddr_match_ipaddr4((const struct sockaddr_in *)sa1, | 296 | return nfs_sockaddr_match_ipaddr4((const struct sockaddr_in *)sa1, |
271 | (const struct sockaddr_in *)sa2); | 297 | (const struct sockaddr_in *)sa2); |
272 | } | 298 | } |
299 | |||
300 | static int nfs_sockaddr_cmp_ip6(const struct sockaddr * sa1, | ||
301 | const struct sockaddr * sa2) | ||
302 | { | ||
303 | return 0; | ||
304 | } | ||
273 | #endif | 305 | #endif |
274 | 306 | ||
275 | /* | 307 | /* |
@@ -279,38 +311,18 @@ static int nfs_sockaddr_match_ipaddr(const struct sockaddr *sa1, | |||
279 | * | 311 | * |
280 | * The caller should ensure both socket addresses are AF_INET. | 312 | * The caller should ensure both socket addresses are AF_INET. |
281 | */ | 313 | */ |
282 | static int nfs_sockaddr_cmp_ip4(const struct sockaddr_in * saddr1, | 314 | static int nfs_sockaddr_cmp_ip4(const struct sockaddr *sa1, |
283 | const struct sockaddr_in * saddr2) | 315 | const struct sockaddr *sa2) |
284 | { | 316 | { |
317 | const struct sockaddr_in *saddr1 = (const struct sockaddr_in *)sa1; | ||
318 | const struct sockaddr_in *saddr2 = (const struct sockaddr_in *)sa2; | ||
319 | |||
285 | if (saddr1->sin_addr.s_addr != saddr2->sin_addr.s_addr) | 320 | if (saddr1->sin_addr.s_addr != saddr2->sin_addr.s_addr) |
286 | return 0; | 321 | return 0; |
287 | return saddr1->sin_port == saddr2->sin_port; | 322 | return saddr1->sin_port == saddr2->sin_port; |
288 | } | 323 | } |
289 | 324 | ||
290 | /* | 325 | /* |
291 | * Test if two ip6 socket addresses refer to the same socket by | ||
292 | * comparing relevant fields. The padding bytes specifically, are not | ||
293 | * compared. sin6_flowinfo is not compared because it only affects QoS | ||
294 | * and sin6_scope_id is only compared if the address is "link local" | ||
295 | * because "link local" addresses need only be unique to a specific | ||
296 | * link. Conversely, ordinary unicast addresses might have different | ||
297 | * sin6_scope_id. | ||
298 | * | ||
299 | * The caller should ensure both socket addresses are AF_INET6. | ||
300 | */ | ||
301 | static int nfs_sockaddr_cmp_ip6 (const struct sockaddr_in6 * saddr1, | ||
302 | const struct sockaddr_in6 * saddr2) | ||
303 | { | ||
304 | if (!ipv6_addr_equal(&saddr1->sin6_addr, | ||
305 | &saddr1->sin6_addr)) | ||
306 | return 0; | ||
307 | if (ipv6_addr_scope(&saddr1->sin6_addr) == IPV6_ADDR_SCOPE_LINKLOCAL && | ||
308 | saddr1->sin6_scope_id != saddr2->sin6_scope_id) | ||
309 | return 0; | ||
310 | return saddr1->sin6_port == saddr2->sin6_port; | ||
311 | } | ||
312 | |||
313 | /* | ||
314 | * Test if two socket addresses represent the same actual socket, | 326 | * Test if two socket addresses represent the same actual socket, |
315 | * by comparing (only) relevant fields. | 327 | * by comparing (only) relevant fields. |
316 | */ | 328 | */ |
@@ -322,11 +334,9 @@ static int nfs_sockaddr_cmp(const struct sockaddr *sa1, | |||
322 | 334 | ||
323 | switch (sa1->sa_family) { | 335 | switch (sa1->sa_family) { |
324 | case AF_INET: | 336 | case AF_INET: |
325 | return nfs_sockaddr_cmp_ip4((const struct sockaddr_in *) sa1, | 337 | return nfs_sockaddr_cmp_ip4(sa1, sa2); |
326 | (const struct sockaddr_in *) sa2); | ||
327 | case AF_INET6: | 338 | case AF_INET6: |
328 | return nfs_sockaddr_cmp_ip6((const struct sockaddr_in6 *) sa1, | 339 | return nfs_sockaddr_cmp_ip6(sa1, sa2); |
329 | (const struct sockaddr_in6 *) sa2); | ||
330 | } | 340 | } |
331 | return 0; | 341 | return 0; |
332 | } | 342 | } |