From 7b9e8522a65886d8ae168547a67c3617b6ba83f1 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Mon, 28 Jan 2013 14:41:07 -0500 Subject: [PATCH] nfsd: fix IPv6 address handling in the DRC Currently, it only stores the first 16 bytes of any address. struct sockaddr_in6 is 28 bytes however, so we're currently ignoring the last 12 bytes of the address. Expand the c_addr field to a sockaddr_in6, and cast it to a sockaddr_in as necessary. Also fix the comparitor to use the existing RPC helpers for this. Signed-off-by: Jeff Layton Signed-off-by: J. Bruce Fields --- fs/nfsd/cache.h | 6 +++++- fs/nfsd/nfscache.c | 7 +++++-- include/linux/sunrpc/clnt.h | 4 +++- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/fs/nfsd/cache.h b/fs/nfsd/cache.h index 93cc9d34c459..2cac76c63b97 100644 --- a/fs/nfsd/cache.h +++ b/fs/nfsd/cache.h @@ -12,6 +12,10 @@ /* * Representation of a reply cache entry. + * + * Note that we use a sockaddr_in6 to hold the address instead of the more + * typical sockaddr_storage. This is for space reasons, since sockaddr_storage + * is much larger than a sockaddr_in6. */ struct svc_cacherep { struct hlist_node c_hash; @@ -20,7 +24,7 @@ struct svc_cacherep { unsigned char c_state, /* unused, inprog, done */ c_type, /* status, buffer */ c_secure : 1; /* req came from port < 1024 */ - struct sockaddr_in c_addr; + struct sockaddr_in6 c_addr; __be32 c_xid; u32 c_prot; u32 c_proc; diff --git a/fs/nfsd/nfscache.c b/fs/nfsd/nfscache.c index 2cbac34a55da..5dd9ec2a177f 100644 --- a/fs/nfsd/nfscache.c +++ b/fs/nfsd/nfscache.c @@ -9,6 +9,7 @@ */ #include +#include #include "nfsd.h" #include "cache.h" @@ -146,7 +147,8 @@ nfsd_cache_lookup(struct svc_rqst *rqstp) xid == rp->c_xid && proc == rp->c_proc && proto == rp->c_prot && vers == rp->c_vers && time_before(jiffies, rp->c_timestamp + 120*HZ) && - memcmp((char*)&rqstp->rq_addr, (char*)&rp->c_addr, sizeof(rp->c_addr))==0) { + rpc_cmp_addr(svc_addr(rqstp), (struct sockaddr *)&rp->c_addr) && + rpc_get_port(svc_addr(rqstp)) == rpc_get_port((struct sockaddr *)&rp->c_addr)) { nfsdstats.rchits++; goto found_entry; } @@ -183,7 +185,8 @@ nfsd_cache_lookup(struct svc_rqst *rqstp) rp->c_state = RC_INPROG; rp->c_xid = xid; rp->c_proc = proc; - memcpy(&rp->c_addr, svc_addr_in(rqstp), sizeof(rp->c_addr)); + rpc_copy_addr((struct sockaddr *)&rp->c_addr, svc_addr(rqstp)); + rpc_set_port((struct sockaddr *)&rp->c_addr, rpc_get_port(svc_addr(rqstp))); rp->c_prot = proto; rp->c_vers = vers; rp->c_timestamp = jiffies; diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h index 34206b84d8da..47354a25a927 100644 --- a/include/linux/sunrpc/clnt.h +++ b/include/linux/sunrpc/clnt.h @@ -263,7 +263,9 @@ static inline bool __rpc_copy_addr6(struct sockaddr *dst, * @sap1: first sockaddr * @sap2: second sockaddr * - * Just compares the family and address portion. Ignores port, scope, etc. + * Just compares the family and address portion. Ignores port, but + * compares the scope if it's a link-local address. + * * Returns true if the addrs are equal, false if they aren't. */ static inline bool rpc_cmp_addr(const struct sockaddr *sap1, -- 2.34.1