SUNRPC: Fix socket address handling in rpcb_clnt
[safe/jmp/linux-2.6] / net / sunrpc / rpcb_clnt.c
index 9b06a21..c1310f7 100644 (file)
@@ -23,6 +23,7 @@
 
 #include <linux/sunrpc/clnt.h>
 #include <linux/sunrpc/sched.h>
+#include <linux/sunrpc/xprtsock.h>
 
 #ifdef RPC_DEBUG
 # define RPCDBG_FACILITY       RPCDBG_BIND
@@ -93,26 +94,6 @@ enum {
 #define RPCB_MAXADDRLEN                (128u)
 
 /*
- * r_netid
- *
- * Quoting RFC 3530, section 2.2:
- *
- * For TCP over IPv4 the value of r_netid is the string "tcp".  For UDP
- * over IPv4 the value of r_netid is the string "udp".
- *
- * ...
- *
- * For TCP over IPv6 the value of r_netid is the string "tcp6".  For UDP
- * over IPv6 the value of r_netid is the string "udp6".
- */
-#define RPCB_NETID_UDP "\165\144\160"          /* "udp" */
-#define RPCB_NETID_TCP "\164\143\160"          /* "tcp" */
-#define RPCB_NETID_UDP6        "\165\144\160\066"      /* "udp6" */
-#define RPCB_NETID_TCP6        "\164\143\160\066"      /* "tcp6" */
-
-#define RPCB_MAXNETIDLEN       (4u)
-
-/*
  * r_owner
  *
  * The "owner" is allowed to unset a service in the rpcbind database.
@@ -122,7 +103,7 @@ enum {
 #define RPCB_MAXOWNERLEN       sizeof(RPCB_OWNER_STRING)
 
 static void                    rpcb_getport_done(struct rpc_task *, void *);
-extern struct rpc_program      rpcb_program;
+static struct rpc_program      rpcb_program;
 
 struct rpcbind_args {
        struct rpc_xprt *       r_xprt;
@@ -147,19 +128,6 @@ struct rpcb_info {
 static struct rpcb_info rpcb_next_version[];
 static struct rpcb_info rpcb_next_version6[];
 
-static void rpcb_getport_prepare(struct rpc_task *task, void *calldata)
-{
-       struct rpcbind_args *map = calldata;
-       struct rpc_xprt *xprt = map->r_xprt;
-       struct rpc_message msg = {
-               .rpc_proc       = rpcb_next_version[xprt->bind_index].rpc_proc,
-               .rpc_argp       = map,
-               .rpc_resp       = &map->r_port,
-       };
-
-       rpc_call_setup(task, &msg, 0);
-}
-
 static void rpcb_map_release(void *data)
 {
        struct rpcbind_args *map = data;
@@ -169,7 +137,6 @@ static void rpcb_map_release(void *data)
 }
 
 static const struct rpc_call_ops rpcb_getport_ops = {
-       .rpc_call_prepare       = rpcb_getport_prepare,
        .rpc_call_done          = rpcb_getport_done,
        .rpc_release            = rpcb_map_release,
 };
@@ -181,12 +148,13 @@ static void rpcb_wake_rpcbind_waiters(struct rpc_xprt *xprt, int status)
 }
 
 static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr,
-                                       int proto, int version, int privileged)
+                                   size_t salen, int proto, int version,
+                                   int privileged)
 {
        struct rpc_create_args args = {
                .protocol       = proto,
                .address        = srvaddr,
-               .addrsize       = sizeof(struct sockaddr_in),
+               .addrsize       = salen,
                .servername     = hostname,
                .program        = &rpcb_program,
                .version        = version,
@@ -249,7 +217,7 @@ int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay)
                        prog, vers, prot, port);
 
        rpcb_clnt = rpcb_create("localhost", (struct sockaddr *) &sin,
-                                       IPPROTO_UDP, 2, 1);
+                               sizeof(sin), XPRT_TRANSPORT_UDP, 2, 1);
        if (IS_ERR(rpcb_clnt))
                return PTR_ERR(rpcb_clnt);
 
@@ -298,7 +266,8 @@ int rpcb_getport_sync(struct sockaddr_in *sin, __u32 prog,
                __FUNCTION__, NIPQUAD(sin->sin_addr.s_addr), prog, vers, prot);
 
        sprintf(hostname, NIPQUAD_FMT, NIPQUAD(sin->sin_addr.s_addr));
-       rpcb_clnt = rpcb_create(hostname, (struct sockaddr *)sin, prot, 2, 0);
+       rpcb_clnt = rpcb_create(hostname, (struct sockaddr *)sin,
+                               sizeof(sin), prot, 2, 0);
        if (IS_ERR(rpcb_clnt))
                return PTR_ERR(rpcb_clnt);
 
@@ -314,6 +283,24 @@ int rpcb_getport_sync(struct sockaddr_in *sin, __u32 prog,
 }
 EXPORT_SYMBOL_GPL(rpcb_getport_sync);
 
+static struct rpc_task *rpcb_call_async(struct rpc_clnt *rpcb_clnt, struct rpcbind_args *map, int version)
+{
+       struct rpc_message msg = {
+               .rpc_proc = rpcb_next_version[version].rpc_proc,
+               .rpc_argp = map,
+               .rpc_resp = &map->r_port,
+       };
+       struct rpc_task_setup task_setup_data = {
+               .rpc_client = rpcb_clnt,
+               .rpc_message = &msg,
+               .callback_ops = &rpcb_getport_ops,
+               .callback_data = map,
+               .flags = RPC_TASK_ASYNC,
+       };
+
+       return rpc_run_task(&task_setup_data);
+}
+
 /**
  * rpcb_getport_async - obtain the port for a given RPC service on a given host
  * @task: task that is waiting for portmapper request
@@ -329,7 +316,9 @@ void rpcb_getport_async(struct rpc_task *task)
        struct rpc_clnt *rpcb_clnt;
        static struct rpcbind_args *map;
        struct rpc_task *child;
-       struct sockaddr addr;
+       struct sockaddr_storage addr;
+       struct sockaddr *sap = (struct sockaddr *)&addr;
+       size_t salen;
        int status;
        struct rpcb_info *info;
 
@@ -359,10 +348,10 @@ void rpcb_getport_async(struct rpc_task *task)
                goto bailout_nofree;
        }
 
-       rpc_peeraddr(clnt, (void *)&addr, sizeof(addr));
+       salen = rpc_peeraddr(clnt, sap, sizeof(addr));
 
        /* Don't ever use rpcbind v2 for AF_INET6 requests */
-       switch (addr.sa_family) {
+       switch (sap->sa_family) {
        case AF_INET:
                info = rpcb_next_version;
                break;
@@ -377,7 +366,7 @@ void rpcb_getport_async(struct rpc_task *task)
        }
        if (info[xprt->bind_index].rpc_proc == NULL) {
                xprt->bind_index = 0;
-               status = -EACCES;       /* tell caller to try again later */
+               status = -EPFNOSUPPORT;
                dprintk("RPC: %5u %s: no more getport versions available\n",
                        task->tk_pid, __FUNCTION__);
                goto bailout_nofree;
@@ -387,7 +376,7 @@ void rpcb_getport_async(struct rpc_task *task)
        dprintk("RPC: %5u %s: trying rpcbind version %u\n",
                task->tk_pid, __FUNCTION__, bind_version);
 
-       rpcb_clnt = rpcb_create(clnt->cl_server, &addr, xprt->prot,
+       rpcb_clnt = rpcb_create(clnt->cl_server, sap, salen, xprt->prot,
                                bind_version, 0);
        if (IS_ERR(rpcb_clnt)) {
                status = PTR_ERR(rpcb_clnt);
@@ -408,14 +397,13 @@ void rpcb_getport_async(struct rpc_task *task)
        map->r_prot = xprt->prot;
        map->r_port = 0;
        map->r_xprt = xprt_get(xprt);
-       map->r_netid = (xprt->prot == IPPROTO_TCP) ? RPCB_NETID_TCP :
-                                                  RPCB_NETID_UDP;
+       map->r_netid = rpc_peeraddr2str(clnt, RPC_DISPLAY_NETID);
        memcpy(map->r_addr,
               rpc_peeraddr2str(rpcb_clnt, RPC_DISPLAY_UNIVERSAL_ADDR),
               sizeof(map->r_addr));
        map->r_owner = RPCB_OWNER_STRING;       /* ignored for GETADDR */
 
-       child = rpc_run_task(rpcb_clnt, RPC_TASK_ASYNC, &rpcb_getport_ops, map);
+       child = rpcb_call_async(rpcb_clnt, map, xprt->bind_index);
        rpc_release_client(rpcb_clnt);
        if (IS_ERR(child)) {
                status = -EIO;
@@ -436,6 +424,7 @@ bailout_nofree:
 bailout_nowake:
        task->tk_status = status;
 }
+EXPORT_SYMBOL_GPL(rpcb_getport_async);
 
 /*
  * Rpcbind child task calls this callback via tk_exit.
@@ -587,7 +576,7 @@ out_err:
 #define RPCB_port_sz           (1u)
 #define RPCB_boolean_sz                (1u)
 
-#define RPCB_netid_sz          (1+XDR_QUADLEN(RPCB_MAXNETIDLEN))
+#define RPCB_netid_sz          (1+XDR_QUADLEN(RPCBIND_MAXNETIDLEN))
 #define RPCB_addr_sz           (1+XDR_QUADLEN(RPCB_MAXADDRLEN))
 #define RPCB_ownerstring_sz    (1+XDR_QUADLEN(RPCB_MAXOWNERLEN))
 
@@ -685,7 +674,7 @@ static struct rpc_version *rpcb_version[] = {
 
 static struct rpc_stat rpcb_stats;
 
-struct rpc_program rpcb_program = {
+static struct rpc_program rpcb_program = {
        .name           = "rpcbind",
        .number         = RPCBIND_PROGRAM,
        .nrvers         = ARRAY_SIZE(rpcb_version),