aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/nfs/client.c57
1 files changed, 38 insertions, 19 deletions
diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index b643f0ec5c21..9b728f3565a1 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -223,31 +223,54 @@ void nfs_put_client(struct nfs_client *clp)
223 } 223 }
224} 224}
225 225
226static int nfs_sockaddr_match_ipaddr4(const struct sockaddr_in *sa1, 226#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
227 const struct sockaddr_in *sa2) 227static const struct in6_addr *nfs_map_ipv4_addr(const struct sockaddr *sa, struct in6_addr *addr_mapped)
228{ 228{
229 return sa1->sin_addr.s_addr == sa2->sin_addr.s_addr; 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 }
230} 240}
231 241
232static int nfs_sockaddr_match_ipaddr6(const struct sockaddr_in6 *sa1, 242static int nfs_sockaddr_match_ipaddr(const struct sockaddr *sa1,
233 const struct sockaddr_in6 *sa2) 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#else
259static int nfs_sockaddr_match_ipaddr4(const struct sockaddr_in *sa1,
260 const struct sockaddr_in *sa2)
234{ 261{
235 return ipv6_addr_equal(&sa1->sin6_addr, &sa2->sin6_addr); 262 return sa1->sin_addr.s_addr == sa2->sin_addr.s_addr;
236} 263}
237 264
238static int nfs_sockaddr_match_ipaddr(const struct sockaddr *sa1, 265static int nfs_sockaddr_match_ipaddr(const struct sockaddr *sa1,
239 const struct sockaddr *sa2) 266 const struct sockaddr *sa2)
240{ 267{
241 switch (sa1->sa_family) { 268 if (unlikely(sa1->sa_family != AF_INET || sa2->sa_family != AF_INET))
242 case AF_INET: 269 return 0;
243 return nfs_sockaddr_match_ipaddr4((const struct sockaddr_in *)sa1, 270 return nfs_sockaddr_match_ipaddr4((const struct sockaddr_in *)sa1,
244 (const struct sockaddr_in *)sa2); 271 (const struct sockaddr_in *)sa2);
245 case AF_INET6:
246 return nfs_sockaddr_match_ipaddr6((const struct sockaddr_in6 *)sa1,
247 (const struct sockaddr_in6 *)sa2);
248 }
249 BUG();
250} 272}
273#endif
251 274
252/* 275/*
253 * Find a client by IP address and protocol version 276 * Find a client by IP address and protocol version
@@ -269,8 +292,6 @@ struct nfs_client *nfs_find_client(const struct sockaddr *addr, u32 nfsversion)
269 if (clp->rpc_ops->version != nfsversion) 292 if (clp->rpc_ops->version != nfsversion)
270 continue; 293 continue;
271 294
272 if (addr->sa_family != clap->sa_family)
273 continue;
274 /* Match only the IP address, not the port number */ 295 /* Match only the IP address, not the port number */
275 if (!nfs_sockaddr_match_ipaddr(addr, clap)) 296 if (!nfs_sockaddr_match_ipaddr(addr, clap))
276 continue; 297 continue;
@@ -304,8 +325,6 @@ struct nfs_client *nfs_find_client_next(struct nfs_client *clp)
304 if (clp->rpc_ops->version != nfsvers) 325 if (clp->rpc_ops->version != nfsvers)
305 continue; 326 continue;
306 327
307 if (sap->sa_family != clap->sa_family)
308 continue;
309 /* Match only the IP address, not the port number */ 328 /* Match only the IP address, not the port number */
310 if (!nfs_sockaddr_match_ipaddr(sap, clap)) 329 if (!nfs_sockaddr_match_ipaddr(sap, clap))
311 continue; 330 continue;