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 commit6bc9638a
, 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 commitd3bc9a1d
. Signed-off-by: Chuck Lever <chuck.lever@oracle.com> Signed-off-by: J. Bruce Fields <bfields@redhat.com>
This commit is contained in:
parent
4232e8634a
commit
9247685088
1 changed files with 32 additions and 1 deletions
|
@ -1629,7 +1629,6 @@ static struct socket *xs_create_sock(struct rpc_xprt *xprt,
|
|||
protocol, -err);
|
||||
goto out;
|
||||
}
|
||||
transport->srcaddr.ss_family = family;
|
||||
xs_reclassify_socket(family, sock);
|
||||
|
||||
if (xs_bind(transport, sock)) {
|
||||
|
@ -2136,6 +2135,31 @@ static struct rpc_xprt_ops bc_tcp_ops = {
|
|||
.print_stats = xs_tcp_print_stats,
|
||||
};
|
||||
|
||||
static int xs_init_anyaddr(const int family, struct sockaddr *sap)
|
||||
{
|
||||
static const struct sockaddr_in sin = {
|
||||
.sin_family = AF_INET,
|
||||
.sin_addr.s_addr = htonl(INADDR_ANY),
|
||||
};
|
||||
static const struct sockaddr_in6 sin6 = {
|
||||
.sin6_family = AF_INET6,
|
||||
.sin6_addr = IN6ADDR_ANY_INIT,
|
||||
};
|
||||
|
||||
switch (family) {
|
||||
case AF_INET:
|
||||
memcpy(sap, &sin, sizeof(sin));
|
||||
break;
|
||||
case AF_INET6:
|
||||
memcpy(sap, &sin6, sizeof(sin6));
|
||||
break;
|
||||
default:
|
||||
dprintk("RPC: %s: Bad address family\n", __func__);
|
||||
return -EAFNOSUPPORT;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct rpc_xprt *xs_setup_xprt(struct xprt_create *args,
|
||||
unsigned int slot_table_size)
|
||||
{
|
||||
|
@ -2159,6 +2183,13 @@ static struct rpc_xprt *xs_setup_xprt(struct xprt_create *args,
|
|||
xprt->addrlen = args->addrlen;
|
||||
if (args->srcaddr)
|
||||
memcpy(&new->srcaddr, args->srcaddr, args->addrlen);
|
||||
else {
|
||||
int err;
|
||||
err = xs_init_anyaddr(args->dstaddr->sa_family,
|
||||
(struct sockaddr *)&new->srcaddr);
|
||||
if (err != 0)
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
return xprt;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue