diff options
Diffstat (limited to 'net/sunrpc/xprtsock.c')
-rw-r--r-- | net/sunrpc/xprtsock.c | 59 |
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 | ||
1279 | static 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 | |||
1288 | static 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 | |||
1279 | static int xs_bind4(struct sock_xprt *transport, struct socket *sock) | 1299 | static 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 | } |