aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/sunrpc/clnt.h1
-rw-r--r--net/sunrpc/clnt.c149
2 files changed, 150 insertions, 0 deletions
diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h
index acd5502a8190..523547ecfee2 100644
--- a/include/linux/sunrpc/clnt.h
+++ b/include/linux/sunrpc/clnt.h
@@ -161,6 +161,7 @@ size_t rpc_max_payload(struct rpc_clnt *);
161void rpc_force_rebind(struct rpc_clnt *); 161void rpc_force_rebind(struct rpc_clnt *);
162size_t rpc_peeraddr(struct rpc_clnt *, struct sockaddr *, size_t); 162size_t rpc_peeraddr(struct rpc_clnt *, struct sockaddr *, size_t);
163const char *rpc_peeraddr2str(struct rpc_clnt *, enum rpc_display_format_t); 163const char *rpc_peeraddr2str(struct rpc_clnt *, enum rpc_display_format_t);
164int rpc_localaddr(struct rpc_clnt *, struct sockaddr *, size_t);
164 165
165size_t rpc_ntop(const struct sockaddr *, char *, const size_t); 166size_t rpc_ntop(const struct sockaddr *, char *, const size_t);
166size_t rpc_pton(struct net *, const char *, const size_t, 167size_t rpc_pton(struct net *, const char *, const size_t,
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index e39ace9a4e1d..7a4cb5fdc212 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -914,6 +914,155 @@ const char *rpc_peeraddr2str(struct rpc_clnt *clnt,
914} 914}
915EXPORT_SYMBOL_GPL(rpc_peeraddr2str); 915EXPORT_SYMBOL_GPL(rpc_peeraddr2str);
916 916
917static const struct sockaddr_in rpc_inaddr_loopback = {
918 .sin_family = AF_INET,
919 .sin_addr.s_addr = htonl(INADDR_ANY),
920};
921
922static const struct sockaddr_in6 rpc_in6addr_loopback = {
923 .sin6_family = AF_INET6,
924 .sin6_addr = IN6ADDR_ANY_INIT,
925};
926
927/*
928 * Try a getsockname() on a connected datagram socket. Using a
929 * connected datagram socket prevents leaving a socket in TIME_WAIT.
930 * This conserves the ephemeral port number space.
931 *
932 * Returns zero and fills in "buf" if successful; otherwise, a
933 * negative errno is returned.
934 */
935static int rpc_sockname(struct net *net, struct sockaddr *sap, size_t salen,
936 struct sockaddr *buf, int buflen)
937{
938 struct socket *sock;
939 int err;
940
941 err = __sock_create(net, sap->sa_family,
942 SOCK_DGRAM, IPPROTO_UDP, &sock, 1);
943 if (err < 0) {
944 dprintk("RPC: can't create UDP socket (%d)\n", err);
945 goto out;
946 }
947
948 switch (sap->sa_family) {
949 case AF_INET:
950 err = kernel_bind(sock,
951 (struct sockaddr *)&rpc_inaddr_loopback,
952 sizeof(rpc_inaddr_loopback));
953 break;
954 case AF_INET6:
955 err = kernel_bind(sock,
956 (struct sockaddr *)&rpc_in6addr_loopback,
957 sizeof(rpc_in6addr_loopback));
958 break;
959 default:
960 err = -EAFNOSUPPORT;
961 goto out;
962 }
963 if (err < 0) {
964 dprintk("RPC: can't bind UDP socket (%d)\n", err);
965 goto out_release;
966 }
967
968 err = kernel_connect(sock, sap, salen, 0);
969 if (err < 0) {
970 dprintk("RPC: can't connect UDP socket (%d)\n", err);
971 goto out_release;
972 }
973
974 err = kernel_getsockname(sock, buf, &buflen);
975 if (err < 0) {
976 dprintk("RPC: getsockname failed (%d)\n", err);
977 goto out_release;
978 }
979
980 err = 0;
981 if (buf->sa_family == AF_INET6) {
982 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)buf;
983 sin6->sin6_scope_id = 0;
984 }
985 dprintk("RPC: %s succeeded\n", __func__);
986
987out_release:
988 sock_release(sock);
989out:
990 return err;
991}
992
993/*
994 * Scraping a connected socket failed, so we don't have a useable
995 * local address. Fallback: generate an address that will prevent
996 * the server from calling us back.
997 *
998 * Returns zero and fills in "buf" if successful; otherwise, a
999 * negative errno is returned.
1000 */
1001static int rpc_anyaddr(int family, struct sockaddr *buf, size_t buflen)
1002{
1003 switch (family) {
1004 case AF_INET:
1005 if (buflen < sizeof(rpc_inaddr_loopback))
1006 return -EINVAL;
1007 memcpy(buf, &rpc_inaddr_loopback,
1008 sizeof(rpc_inaddr_loopback));
1009 break;
1010 case AF_INET6:
1011 if (buflen < sizeof(rpc_in6addr_loopback))
1012 return -EINVAL;
1013 memcpy(buf, &rpc_in6addr_loopback,
1014 sizeof(rpc_in6addr_loopback));
1015 default:
1016 dprintk("RPC: %s: address family not supported\n",
1017 __func__);
1018 return -EAFNOSUPPORT;
1019 }
1020 dprintk("RPC: %s: succeeded\n", __func__);
1021 return 0;
1022}
1023
1024/**
1025 * rpc_localaddr - discover local endpoint address for an RPC client
1026 * @clnt: RPC client structure
1027 * @buf: target buffer
1028 * @buflen: size of target buffer, in bytes
1029 *
1030 * Returns zero and fills in "buf" and "buflen" if successful;
1031 * otherwise, a negative errno is returned.
1032 *
1033 * This works even if the underlying transport is not currently connected,
1034 * or if the upper layer never previously provided a source address.
1035 *
1036 * The result of this function call is transient: multiple calls in
1037 * succession may give different results, depending on how local
1038 * networking configuration changes over time.
1039 */
1040int rpc_localaddr(struct rpc_clnt *clnt, struct sockaddr *buf, size_t buflen)
1041{
1042 struct sockaddr_storage address;
1043 struct sockaddr *sap = (struct sockaddr *)&address;
1044 struct rpc_xprt *xprt;
1045 struct net *net;
1046 size_t salen;
1047 int err;
1048
1049 rcu_read_lock();
1050 xprt = rcu_dereference(clnt->cl_xprt);
1051 salen = xprt->addrlen;
1052 memcpy(sap, &xprt->addr, salen);
1053 net = get_net(xprt->xprt_net);
1054 rcu_read_unlock();
1055
1056 rpc_set_port(sap, 0);
1057 err = rpc_sockname(net, sap, salen, buf, buflen);
1058 put_net(net);
1059 if (err != 0)
1060 /* Couldn't discover local address, return ANYADDR */
1061 return rpc_anyaddr(sap->sa_family, buf, buflen);
1062 return 0;
1063}
1064EXPORT_SYMBOL_GPL(rpc_localaddr);
1065
917void 1066void
918rpc_setbufsize(struct rpc_clnt *clnt, unsigned int sndsize, unsigned int rcvsize) 1067rpc_setbufsize(struct rpc_clnt *clnt, unsigned int sndsize, unsigned int rcvsize)
919{ 1068{