diff options
author | Frank van Maarseveen <frankvm@frankvm.com> | 2007-07-09 16:23:35 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2007-07-10 23:40:49 -0400 |
commit | d3bc9a1deb8964d774af8535814cb91bf8f6def0 (patch) | |
tree | c8ae19f3684b40a4c53d948adc3b0f688d373497 | |
parent | a97476926ec061f90b77da478620ea6dc71a3237 (diff) |
SUNRPC client: add interface for binding to a local address
In addition to binding to a local privileged port the NFS client should
allow binding to a specific local address. This is used by the server
for callbacks. The patch adds the necessary interface.
Signed-off-by: Frank van Maarseveen <frankvm@frankvm.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-rw-r--r-- | include/linux/sunrpc/clnt.h | 1 | ||||
-rw-r--r-- | include/linux/sunrpc/xprt.h | 1 | ||||
-rw-r--r-- | net/sunrpc/clnt.c | 1 | ||||
-rw-r--r-- | net/sunrpc/xprtsock.c | 24 |
4 files changed, 19 insertions, 8 deletions
diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h index c1b37972b0d5..c0d9d14983b3 100644 --- a/include/linux/sunrpc/clnt.h +++ b/include/linux/sunrpc/clnt.h | |||
@@ -98,6 +98,7 @@ struct rpc_create_args { | |||
98 | int protocol; | 98 | int protocol; |
99 | struct sockaddr *address; | 99 | struct sockaddr *address; |
100 | size_t addrsize; | 100 | size_t addrsize; |
101 | struct sockaddr *saddress; | ||
101 | struct rpc_timeout *timeout; | 102 | struct rpc_timeout *timeout; |
102 | char *servername; | 103 | char *servername; |
103 | struct rpc_program *program; | 104 | struct rpc_program *program; |
diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index ea828b09e4ad..d11cedd14f0f 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h | |||
@@ -198,6 +198,7 @@ struct rpc_xprt { | |||
198 | 198 | ||
199 | struct rpc_xprtsock_create { | 199 | struct rpc_xprtsock_create { |
200 | int proto; /* IPPROTO_UDP or IPPROTO_TCP */ | 200 | int proto; /* IPPROTO_UDP or IPPROTO_TCP */ |
201 | struct sockaddr * srcaddr; /* optional local address */ | ||
201 | struct sockaddr * dstaddr; /* remote peer address */ | 202 | struct sockaddr * dstaddr; /* remote peer address */ |
202 | size_t addrlen; | 203 | size_t addrlen; |
203 | struct rpc_timeout * timeout; /* optional timeout parameters */ | 204 | struct rpc_timeout * timeout; /* optional timeout parameters */ |
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 25bbf2d7f603..5d3fe7b22488 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c | |||
@@ -236,6 +236,7 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args) | |||
236 | struct rpc_clnt *clnt; | 236 | struct rpc_clnt *clnt; |
237 | struct rpc_xprtsock_create xprtargs = { | 237 | struct rpc_xprtsock_create xprtargs = { |
238 | .proto = args->protocol, | 238 | .proto = args->protocol, |
239 | .srcaddr = args->saddress, | ||
239 | .dstaddr = args->address, | 240 | .dstaddr = args->address, |
240 | .addrlen = args->addrsize, | 241 | .addrlen = args->addrsize, |
241 | .timeout = args->timeout | 242 | .timeout = args->timeout |
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 6b7cea57651c..4ae7eed7f617 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c | |||
@@ -235,6 +235,7 @@ struct sock_xprt { | |||
235 | * Connection of transports | 235 | * Connection of transports |
236 | */ | 236 | */ |
237 | struct delayed_work connect_worker; | 237 | struct delayed_work connect_worker; |
238 | struct sockaddr_storage addr; | ||
238 | unsigned short port; | 239 | unsigned short port; |
239 | 240 | ||
240 | /* | 241 | /* |
@@ -1145,31 +1146,36 @@ static void xs_set_port(struct rpc_xprt *xprt, unsigned short port) | |||
1145 | sap->sin_port = htons(port); | 1146 | sap->sin_port = htons(port); |
1146 | } | 1147 | } |
1147 | 1148 | ||
1148 | static int xs_bindresvport(struct sock_xprt *transport, struct socket *sock) | 1149 | static int xs_bind(struct sock_xprt *transport, struct socket *sock) |
1149 | { | 1150 | { |
1150 | struct sockaddr_in myaddr = { | 1151 | struct sockaddr_in myaddr = { |
1151 | .sin_family = AF_INET, | 1152 | .sin_family = AF_INET, |
1152 | }; | 1153 | }; |
1154 | struct sockaddr_in *sa; | ||
1153 | int err; | 1155 | int err; |
1154 | unsigned short port = transport->port; | 1156 | unsigned short port = transport->port; |
1155 | 1157 | ||
1158 | if (!transport->xprt.resvport) | ||
1159 | port = 0; | ||
1160 | sa = (struct sockaddr_in *)&transport->addr; | ||
1161 | myaddr.sin_addr = sa->sin_addr; | ||
1156 | do { | 1162 | do { |
1157 | myaddr.sin_port = htons(port); | 1163 | myaddr.sin_port = htons(port); |
1158 | err = kernel_bind(sock, (struct sockaddr *) &myaddr, | 1164 | err = kernel_bind(sock, (struct sockaddr *) &myaddr, |
1159 | sizeof(myaddr)); | 1165 | sizeof(myaddr)); |
1166 | if (!transport->xprt.resvport) | ||
1167 | break; | ||
1160 | if (err == 0) { | 1168 | if (err == 0) { |
1161 | transport->port = port; | 1169 | transport->port = port; |
1162 | dprintk("RPC: xs_bindresvport bound to port %u\n", | 1170 | break; |
1163 | port); | ||
1164 | return 0; | ||
1165 | } | 1171 | } |
1166 | if (port <= xprt_min_resvport) | 1172 | if (port <= xprt_min_resvport) |
1167 | port = xprt_max_resvport; | 1173 | port = xprt_max_resvport; |
1168 | else | 1174 | else |
1169 | port--; | 1175 | port--; |
1170 | } while (err == -EADDRINUSE && port != transport->port); | 1176 | } while (err == -EADDRINUSE && port != transport->port); |
1171 | 1177 | dprintk("RPC: xs_bind "NIPQUAD_FMT":%u: %s (%d)\n", | |
1172 | dprintk("RPC: can't bind to reserved port (%d).\n", -err); | 1178 | NIPQUAD(myaddr.sin_addr), port, err ? "failed" : "ok", err); |
1173 | return err; | 1179 | return err; |
1174 | } | 1180 | } |
1175 | 1181 | ||
@@ -1228,7 +1234,7 @@ static void xs_udp_connect_worker(struct work_struct *work) | |||
1228 | } | 1234 | } |
1229 | xs_reclassify_socket(sock); | 1235 | xs_reclassify_socket(sock); |
1230 | 1236 | ||
1231 | if (xprt->resvport && xs_bindresvport(transport, sock) < 0) { | 1237 | if (xs_bind(transport, sock)) { |
1232 | sock_release(sock); | 1238 | sock_release(sock); |
1233 | goto out; | 1239 | goto out; |
1234 | } | 1240 | } |
@@ -1315,7 +1321,7 @@ static void xs_tcp_connect_worker(struct work_struct *work) | |||
1315 | } | 1321 | } |
1316 | xs_reclassify_socket(sock); | 1322 | xs_reclassify_socket(sock); |
1317 | 1323 | ||
1318 | if (xprt->resvport && xs_bindresvport(transport, sock) < 0) { | 1324 | if (xs_bind(transport, sock)) { |
1319 | sock_release(sock); | 1325 | sock_release(sock); |
1320 | goto out; | 1326 | goto out; |
1321 | } | 1327 | } |
@@ -1531,6 +1537,8 @@ static struct rpc_xprt *xs_setup_xprt(struct rpc_xprtsock_create *args, unsigned | |||
1531 | 1537 | ||
1532 | memcpy(&xprt->addr, args->dstaddr, args->addrlen); | 1538 | memcpy(&xprt->addr, args->dstaddr, args->addrlen); |
1533 | xprt->addrlen = args->addrlen; | 1539 | xprt->addrlen = args->addrlen; |
1540 | if (args->srcaddr) | ||
1541 | memcpy(&new->addr, args->srcaddr, args->addrlen); | ||
1534 | new->port = xs_get_random_port(); | 1542 | new->port = xs_get_random_port(); |
1535 | 1543 | ||
1536 | return xprt; | 1544 | return xprt; |