aboutsummaryrefslogtreecommitdiffstats
path: root/net/sunrpc/xprtsock.c
diff options
context:
space:
mode:
authorChuck Lever <chuck.lever@oracle.com>2010-10-20 11:53:01 -0400
committerJ. Bruce Fields <bfields@redhat.com>2010-10-21 10:11:47 -0400
commit9247685088398cf21bcb513bd2832b4cd42516c4 (patch)
treeaf6e9cd7d168903912895cc80849ec4cc43a9535 /net/sunrpc/xprtsock.c
parent4232e8634ad82c5a53389e4016de15a8b15c09c3 (diff)
SUNRPC: Properly initialize sock_xprt.srcaddr in all cases
The source address field in the transport's sock_xprt is initialized ONLY IF the RPC application passed a pointer to a source address during the call to rpc_create(). However, xs_bind() subsequently uses the value of this field without regard to whether the source address was initialized during transport creation or not. So far we've been lucky: the uninitialized value of this field is zeroes. xs_bind(), until recently, used only the sin[6]_addr field in this sockaddr, and all zeroes is a valid value for this: it means ANYADDR. This is a happy coincidence. However, xs_bind() now wants to use the sa_family field as well, and expects it to be initialized to something other than zero. Therefore, the source address sockaddr field should be fully initialized at transport create time in _every_ case, not just when the RPC application wants to use a specific bind address. Bruce added a workaround for this missing initialization by adjusting commit 6bc9638a, but the "right" way to do this is to ensure that the source address sockaddr is always correctly initialized from the get-go. This patch doesn't introduce a behavior change. It's simply a clean-up of Bruce's fix, to prevent future problems of this kind. It may look like overkill, but a) it clearly documents the default initial value of this field, b) it doesn't assume that the sockaddr_storage memory is first initialized to any particular value, and c) it will fail verbosely if some unknown address family is passed in Originally introduced by commit d3bc9a1d. Signed-off-by: Chuck Lever <chuck.lever@oracle.com> Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Diffstat (limited to 'net/sunrpc/xprtsock.c')
-rw-r--r--net/sunrpc/xprtsock.c33
1 files changed, 32 insertions, 1 deletions
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
index b58eef76a518..27fc4b4cb82b 100644
--- a/net/sunrpc/xprtsock.c
+++ b/net/sunrpc/xprtsock.c
@@ -1629,7 +1629,6 @@ static struct socket *xs_create_sock(struct rpc_xprt *xprt,
1629 protocol, -err); 1629 protocol, -err);
1630 goto out; 1630 goto out;
1631 } 1631 }
1632 transport->srcaddr.ss_family = family;
1633 xs_reclassify_socket(family, sock); 1632 xs_reclassify_socket(family, sock);
1634 1633
1635 if (xs_bind(transport, sock)) { 1634 if (xs_bind(transport, sock)) {
@@ -2136,6 +2135,31 @@ static struct rpc_xprt_ops bc_tcp_ops = {
2136 .print_stats = xs_tcp_print_stats, 2135 .print_stats = xs_tcp_print_stats,
2137}; 2136};
2138 2137
2138static int xs_init_anyaddr(const int family, struct sockaddr *sap)
2139{
2140 static const struct sockaddr_in sin = {
2141 .sin_family = AF_INET,
2142 .sin_addr.s_addr = htonl(INADDR_ANY),
2143 };
2144 static const struct sockaddr_in6 sin6 = {
2145 .sin6_family = AF_INET6,
2146 .sin6_addr = IN6ADDR_ANY_INIT,
2147 };
2148
2149 switch (family) {
2150 case AF_INET:
2151 memcpy(sap, &sin, sizeof(sin));
2152 break;
2153 case AF_INET6:
2154 memcpy(sap, &sin6, sizeof(sin6));
2155 break;
2156 default:
2157 dprintk("RPC: %s: Bad address family\n", __func__);
2158 return -EAFNOSUPPORT;
2159 }
2160 return 0;
2161}
2162
2139static struct rpc_xprt *xs_setup_xprt(struct xprt_create *args, 2163static struct rpc_xprt *xs_setup_xprt(struct xprt_create *args,
2140 unsigned int slot_table_size) 2164 unsigned int slot_table_size)
2141{ 2165{
@@ -2159,6 +2183,13 @@ static struct rpc_xprt *xs_setup_xprt(struct xprt_create *args,
2159 xprt->addrlen = args->addrlen; 2183 xprt->addrlen = args->addrlen;
2160 if (args->srcaddr) 2184 if (args->srcaddr)
2161 memcpy(&new->srcaddr, args->srcaddr, args->addrlen); 2185 memcpy(&new->srcaddr, args->srcaddr, args->addrlen);
2186 else {
2187 int err;
2188 err = xs_init_anyaddr(args->dstaddr->sa_family,
2189 (struct sockaddr *)&new->srcaddr);
2190 if (err != 0)
2191 return ERR_PTR(err);
2192 }
2162 2193
2163 return xprt; 2194 return xprt;
2164} 2195}