aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/sunrpc/xprtsock.c59
1 files changed, 38 insertions, 21 deletions
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
index abb40c140738..b5544514ee57 100644
--- a/net/sunrpc/xprtsock.c
+++ b/net/sunrpc/xprtsock.c
@@ -1276,34 +1276,53 @@ static void xs_set_port(struct rpc_xprt *xprt, unsigned short port)
1276 } 1276 }
1277} 1277}
1278 1278
1279static unsigned short xs_get_srcport(struct sock_xprt *transport, struct socket *sock)
1280{
1281 unsigned short port = transport->port;
1282
1283 if (port == 0 && transport->xprt.resvport)
1284 port = xs_get_random_port();
1285 return port;
1286}
1287
1288static unsigned short xs_next_srcport(struct sock_xprt *transport, struct socket *sock, unsigned short port)
1289{
1290 if (transport->port != 0)
1291 transport->port = 0;
1292 if (!transport->xprt.resvport)
1293 return 0;
1294 if (port <= xprt_min_resvport || port > xprt_max_resvport)
1295 return xprt_max_resvport;
1296 return --port;
1297}
1298
1279static int xs_bind4(struct sock_xprt *transport, struct socket *sock) 1299static int xs_bind4(struct sock_xprt *transport, struct socket *sock)
1280{ 1300{
1281 struct sockaddr_in myaddr = { 1301 struct sockaddr_in myaddr = {
1282 .sin_family = AF_INET, 1302 .sin_family = AF_INET,
1283 }; 1303 };
1284 struct sockaddr_in *sa; 1304 struct sockaddr_in *sa;
1285 int err; 1305 int err, nloop = 0;
1286 unsigned short port = transport->port; 1306 unsigned short port = xs_get_srcport(transport, sock);
1307 unsigned short last;
1287 1308
1288 if (!transport->xprt.resvport)
1289 port = 0;
1290 sa = (struct sockaddr_in *)&transport->addr; 1309 sa = (struct sockaddr_in *)&transport->addr;
1291 myaddr.sin_addr = sa->sin_addr; 1310 myaddr.sin_addr = sa->sin_addr;
1292 do { 1311 do {
1293 myaddr.sin_port = htons(port); 1312 myaddr.sin_port = htons(port);
1294 err = kernel_bind(sock, (struct sockaddr *) &myaddr, 1313 err = kernel_bind(sock, (struct sockaddr *) &myaddr,
1295 sizeof(myaddr)); 1314 sizeof(myaddr));
1296 if (!transport->xprt.resvport) 1315 if (port == 0)
1297 break; 1316 break;
1298 if (err == 0) { 1317 if (err == 0) {
1299 transport->port = port; 1318 transport->port = port;
1300 break; 1319 break;
1301 } 1320 }
1302 if (port <= xprt_min_resvport) 1321 last = port;
1303 port = xprt_max_resvport; 1322 port = xs_next_srcport(transport, sock, port);
1304 else 1323 if (port > last)
1305 port--; 1324 nloop++;
1306 } while (err == -EADDRINUSE && port != transport->port); 1325 } while (err == -EADDRINUSE && nloop != 2);
1307 dprintk("RPC: %s "NIPQUAD_FMT":%u: %s (%d)\n", 1326 dprintk("RPC: %s "NIPQUAD_FMT":%u: %s (%d)\n",
1308 __FUNCTION__, NIPQUAD(myaddr.sin_addr), 1327 __FUNCTION__, NIPQUAD(myaddr.sin_addr),
1309 port, err ? "failed" : "ok", err); 1328 port, err ? "failed" : "ok", err);
@@ -1316,28 +1335,27 @@ static int xs_bind6(struct sock_xprt *transport, struct socket *sock)
1316 .sin6_family = AF_INET6, 1335 .sin6_family = AF_INET6,
1317 }; 1336 };
1318 struct sockaddr_in6 *sa; 1337 struct sockaddr_in6 *sa;
1319 int err; 1338 int err, nloop = 0;
1320 unsigned short port = transport->port; 1339 unsigned short port = xs_get_srcport(transport, sock);
1340 unsigned short last;
1321 1341
1322 if (!transport->xprt.resvport)
1323 port = 0;
1324 sa = (struct sockaddr_in6 *)&transport->addr; 1342 sa = (struct sockaddr_in6 *)&transport->addr;
1325 myaddr.sin6_addr = sa->sin6_addr; 1343 myaddr.sin6_addr = sa->sin6_addr;
1326 do { 1344 do {
1327 myaddr.sin6_port = htons(port); 1345 myaddr.sin6_port = htons(port);
1328 err = kernel_bind(sock, (struct sockaddr *) &myaddr, 1346 err = kernel_bind(sock, (struct sockaddr *) &myaddr,
1329 sizeof(myaddr)); 1347 sizeof(myaddr));
1330 if (!transport->xprt.resvport) 1348 if (port == 0)
1331 break; 1349 break;
1332 if (err == 0) { 1350 if (err == 0) {
1333 transport->port = port; 1351 transport->port = port;
1334 break; 1352 break;
1335 } 1353 }
1336 if (port <= xprt_min_resvport) 1354 last = port;
1337 port = xprt_max_resvport; 1355 port = xs_next_srcport(transport, sock, port);
1338 else 1356 if (port > last)
1339 port--; 1357 nloop++;
1340 } while (err == -EADDRINUSE && port != transport->port); 1358 } while (err == -EADDRINUSE && nloop != 2);
1341 dprintk("RPC: xs_bind6 "NIP6_FMT":%u: %s (%d)\n", 1359 dprintk("RPC: xs_bind6 "NIP6_FMT":%u: %s (%d)\n",
1342 NIP6(myaddr.sin6_addr), port, err ? "failed" : "ok", err); 1360 NIP6(myaddr.sin6_addr), port, err ? "failed" : "ok", err);
1343 return err; 1361 return err;
@@ -1819,7 +1837,6 @@ static struct rpc_xprt *xs_setup_xprt(struct xprt_create *args,
1819 xprt->addrlen = args->addrlen; 1837 xprt->addrlen = args->addrlen;
1820 if (args->srcaddr) 1838 if (args->srcaddr)
1821 memcpy(&new->addr, args->srcaddr, args->addrlen); 1839 memcpy(&new->addr, args->srcaddr, args->addrlen);
1822 new->port = xs_get_random_port();
1823 1840
1824 return xprt; 1841 return xprt;
1825} 1842}