diff options
-rw-r--r-- | include/linux/sunrpc/clnt.h | 1 | ||||
-rw-r--r-- | net/sunrpc/clnt.c | 149 |
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 *); | |||
161 | void rpc_force_rebind(struct rpc_clnt *); | 161 | void rpc_force_rebind(struct rpc_clnt *); |
162 | size_t rpc_peeraddr(struct rpc_clnt *, struct sockaddr *, size_t); | 162 | size_t rpc_peeraddr(struct rpc_clnt *, struct sockaddr *, size_t); |
163 | const char *rpc_peeraddr2str(struct rpc_clnt *, enum rpc_display_format_t); | 163 | const char *rpc_peeraddr2str(struct rpc_clnt *, enum rpc_display_format_t); |
164 | int rpc_localaddr(struct rpc_clnt *, struct sockaddr *, size_t); | ||
164 | 165 | ||
165 | size_t rpc_ntop(const struct sockaddr *, char *, const size_t); | 166 | size_t rpc_ntop(const struct sockaddr *, char *, const size_t); |
166 | size_t rpc_pton(struct net *, const char *, const size_t, | 167 | size_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 | } |
915 | EXPORT_SYMBOL_GPL(rpc_peeraddr2str); | 915 | EXPORT_SYMBOL_GPL(rpc_peeraddr2str); |
916 | 916 | ||
917 | static const struct sockaddr_in rpc_inaddr_loopback = { | ||
918 | .sin_family = AF_INET, | ||
919 | .sin_addr.s_addr = htonl(INADDR_ANY), | ||
920 | }; | ||
921 | |||
922 | static 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 | */ | ||
935 | static 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 | |||
987 | out_release: | ||
988 | sock_release(sock); | ||
989 | out: | ||
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 | */ | ||
1001 | static 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 | */ | ||
1040 | int 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 | } | ||
1064 | EXPORT_SYMBOL_GPL(rpc_localaddr); | ||
1065 | |||
917 | void | 1066 | void |
918 | rpc_setbufsize(struct rpc_clnt *clnt, unsigned int sndsize, unsigned int rcvsize) | 1067 | rpc_setbufsize(struct rpc_clnt *clnt, unsigned int sndsize, unsigned int rcvsize) |
919 | { | 1068 | { |