aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/sunrpc/clnt.h1
-rw-r--r--include/linux/sunrpc/xprt.h1
-rw-r--r--net/sunrpc/clnt.c1
-rw-r--r--net/sunrpc/xprtsock.c24
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
199struct rpc_xprtsock_create { 199struct 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
1148static int xs_bindresvport(struct sock_xprt *transport, struct socket *sock) 1149static 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;