pmap_clnt.c 8.4 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
/*
 * linux/net/sunrpc/pmap.c
 *
 * Portmapper client.
 *
 * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
 */

#include <linux/types.h>
#include <linux/socket.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/uio.h>
#include <linux/in.h>
#include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/xprt.h>
#include <linux/sunrpc/sched.h>

#ifdef RPC_DEBUG
# define RPCDBG_FACILITY	RPCDBG_PMAP
#endif

#define PMAP_SET		1
#define PMAP_UNSET		2
#define PMAP_GETPORT		3

27 28 29 30 31 32 33 34
struct portmap_args {
	u32			pm_prog;
	u32			pm_vers;
	u32			pm_prot;
	unsigned short		pm_port;
	struct rpc_task *	pm_task;
};

L
Linus Torvalds 已提交
35
static struct rpc_procinfo	pmap_procedures[];
36
static struct rpc_clnt *	pmap_create(char *, struct sockaddr_in *, int, int);
37
static void			pmap_getport_done(struct rpc_task *, void *);
L
Linus Torvalds 已提交
38
static struct rpc_program	pmap_program;
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77

static void pmap_getport_prepare(struct rpc_task *task, void *calldata)
{
	struct portmap_args *map = calldata;
	struct rpc_message msg = {
		.rpc_proc	= &pmap_procedures[PMAP_GETPORT],
		.rpc_argp	= map,
		.rpc_resp	= &map->pm_port,
	};

	rpc_call_setup(task, &msg, 0);
}

static inline struct portmap_args *pmap_map_alloc(void)
{
	return kmalloc(sizeof(struct portmap_args), GFP_NOFS);
}

static inline void pmap_map_free(struct portmap_args *map)
{
	kfree(map);
}

static void pmap_map_release(void *data)
{
	pmap_map_free(data);
}

static const struct rpc_call_ops pmap_getport_ops = {
	.rpc_call_prepare	= pmap_getport_prepare,
	.rpc_call_done		= pmap_getport_done,
	.rpc_release		= pmap_map_release,
};

static inline void pmap_wake_portmap_waiters(struct rpc_xprt *xprt)
{
	xprt_clear_binding(xprt);
	rpc_wake_up(&xprt->binding);
}
L
Linus Torvalds 已提交
78 79 80 81 82 83 84 85

/*
 * Obtain the port for a given RPC service on a given host. This one can
 * be called for an ongoing RPC request.
 */
void
rpc_getport(struct rpc_task *task, struct rpc_clnt *clnt)
{
86 87 88
	struct rpc_xprt *xprt = task->tk_xprt;
	struct sockaddr_in *sap = &xprt->addr;
	struct portmap_args *map;
L
Linus Torvalds 已提交
89
	struct rpc_clnt	*pmap_clnt;
90
	struct rpc_task *child;
L
Linus Torvalds 已提交
91

92
	dprintk("RPC: %4d rpc_getport(%s, %u, %u, %d)\n",
L
Linus Torvalds 已提交
93
			task->tk_pid, clnt->cl_server,
94
			clnt->cl_prog, clnt->cl_vers, xprt->prot);
L
Linus Torvalds 已提交
95

96 97 98
	/* Autobind on cloned rpc clients is discouraged */
	BUG_ON(clnt->cl_parent != clnt);

99 100 101
	if (xprt_test_and_set_binding(xprt)) {
		task->tk_status = -EACCES;	/* tell caller to check again */
		rpc_sleep_on(&xprt->binding, task, NULL, NULL);
L
Linus Torvalds 已提交
102 103
		return;
	}
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120

	/* Someone else may have bound if we slept */
	if (xprt_bound(xprt)) {
		task->tk_status = 0;
		goto bailout_nofree;
	}

	map = pmap_map_alloc();
	if (!map) {
		task->tk_status = -ENOMEM;
		goto bailout_nofree;
	}
	map->pm_prog = clnt->cl_prog;
	map->pm_vers = clnt->cl_vers;
	map->pm_prot = xprt->prot;
	map->pm_port = 0;
	map->pm_task = task;
L
Linus Torvalds 已提交
121

122
	pmap_clnt = pmap_create(clnt->cl_server, sap, map->pm_prot, 0);
L
Linus Torvalds 已提交
123 124 125 126 127
	if (IS_ERR(pmap_clnt)) {
		task->tk_status = PTR_ERR(pmap_clnt);
		goto bailout;
	}

128 129 130
	child = rpc_run_task(pmap_clnt, RPC_TASK_ASYNC, &pmap_getport_ops, map);
	if (IS_ERR(child)) {
		task->tk_status = -EIO;
L
Linus Torvalds 已提交
131
		goto bailout;
132 133
	}
	rpc_release_task(child);
L
Linus Torvalds 已提交
134

135
	rpc_sleep_on(&xprt->binding, task, NULL, NULL);
L
Linus Torvalds 已提交
136

137
	task->tk_xprt->stat.bind_count++;
L
Linus Torvalds 已提交
138 139 140
	return;

bailout:
141 142 143
	pmap_map_free(map);
bailout_nofree:
	pmap_wake_portmap_waiters(xprt);
L
Linus Torvalds 已提交
144 145 146 147 148 149
}

#ifdef CONFIG_ROOT_NFS
int
rpc_getport_external(struct sockaddr_in *sin, __u32 prog, __u32 vers, int prot)
{
150
	struct portmap_args map = {
L
Linus Torvalds 已提交
151 152 153 154 155
		.pm_prog	= prog,
		.pm_vers	= vers,
		.pm_prot	= prot,
		.pm_port	= 0
	};
C
Chuck Lever 已提交
156 157 158 159 160
	struct rpc_message msg = {
		.rpc_proc	= &pmap_procedures[PMAP_GETPORT],
		.rpc_argp	= &map,
		.rpc_resp	= &map.pm_port,
	};
L
Linus Torvalds 已提交
161 162 163 164 165 166 167 168
	struct rpc_clnt	*pmap_clnt;
	char		hostname[32];
	int		status;

	dprintk("RPC:      rpc_getport_external(%u.%u.%u.%u, %d, %d, %d)\n",
			NIPQUAD(sin->sin_addr.s_addr), prog, vers, prot);

	sprintf(hostname, "%u.%u.%u.%u", NIPQUAD(sin->sin_addr.s_addr));
169
	pmap_clnt = pmap_create(hostname, sin, prot, 0);
L
Linus Torvalds 已提交
170 171 172 173
	if (IS_ERR(pmap_clnt))
		return PTR_ERR(pmap_clnt);

	/* Setup the call info struct */
C
Chuck Lever 已提交
174
	status = rpc_call_sync(pmap_clnt, &msg, 0);
L
Linus Torvalds 已提交
175 176 177 178 179 180 181 182 183 184 185

	if (status >= 0) {
		if (map.pm_port != 0)
			return map.pm_port;
		status = -EACCES;
	}
	return status;
}
#endif

static void
186
pmap_getport_done(struct rpc_task *child, void *data)
L
Linus Torvalds 已提交
187
{
188 189
	struct portmap_args *map = data;
	struct rpc_task *task = map->pm_task;
190
	struct rpc_xprt *xprt = task->tk_xprt;
191
	int status = child->tk_status;
192

193 194
	if (status < 0) {
		/* Portmapper not available */
195
		xprt->ops->set_port(xprt, 0);
196 197 198
		task->tk_status = status;
	} else if (map->pm_port == 0) {
		/* Requested RPC service wasn't registered */
199
		xprt->ops->set_port(xprt, 0);
200
		task->tk_status = -EACCES;
L
Linus Torvalds 已提交
201
	} else {
202 203
		/* Succeeded */
		xprt->ops->set_port(xprt, map->pm_port);
204
		xprt_set_bound(xprt);
205
		task->tk_status = 0;
L
Linus Torvalds 已提交
206
	}
207 208 209 210 211

	dprintk("RPC: %4d pmap_getport_done(status %d, port %u)\n",
			child->tk_pid, child->tk_status, map->pm_port);

	pmap_wake_portmap_waiters(xprt);
L
Linus Torvalds 已提交
212 213 214 215 216 217 218 219 220
}

/*
 * Set or unset a port registration with the local portmapper.
 * port == 0 means unregister, port != 0 means register.
 */
int
rpc_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay)
{
C
Chuck Lever 已提交
221 222 223 224
	struct sockaddr_in	sin = {
		.sin_family	= AF_INET,
		.sin_addr.s_addr = htonl(INADDR_LOOPBACK),
	};
225
	struct portmap_args	map = {
C
Chuck Lever 已提交
226 227 228 229 230 231 232 233 234 235
		.pm_prog	= prog,
		.pm_vers	= vers,
		.pm_prot	= prot,
		.pm_port	= port,
	};
	struct rpc_message msg = {
		.rpc_proc	= &pmap_procedures[port ? PMAP_SET : PMAP_UNSET],
		.rpc_argp	= &map,
		.rpc_resp	= okay,
	};
L
Linus Torvalds 已提交
236 237 238 239 240 241
	struct rpc_clnt		*pmap_clnt;
	int error = 0;

	dprintk("RPC: registering (%d, %d, %d, %d) with portmapper.\n",
			prog, vers, prot, port);

242
	pmap_clnt = pmap_create("localhost", &sin, IPPROTO_UDP, 1);
L
Linus Torvalds 已提交
243 244 245 246 247 248
	if (IS_ERR(pmap_clnt)) {
		error = PTR_ERR(pmap_clnt);
		dprintk("RPC: couldn't create pmap client. Error = %d\n", error);
		return error;
	}

C
Chuck Lever 已提交
249
	error = rpc_call_sync(pmap_clnt, &msg, 0);
L
Linus Torvalds 已提交
250 251 252 253 254 255 256 257 258 259 260 261 262

	if (error < 0) {
		printk(KERN_WARNING
			"RPC: failed to contact portmap (errno %d).\n",
			error);
	}
	dprintk("RPC: registration status %d/%d\n", error, *okay);

	/* Client deleted automatically because cl_oneshot == 1 */
	return error;
}

static struct rpc_clnt *
263
pmap_create(char *hostname, struct sockaddr_in *srvaddr, int proto, int privileged)
L
Linus Torvalds 已提交
264 265 266 267 268 269 270 271
{
	struct rpc_xprt	*xprt;
	struct rpc_clnt	*clnt;

	/* printk("pmap: create xprt\n"); */
	xprt = xprt_create_proto(proto, srvaddr, NULL);
	if (IS_ERR(xprt))
		return (struct rpc_clnt *)xprt;
272
	xprt->ops->set_port(xprt, RPC_PMAP_PORT);
273
	xprt_set_bound(xprt);
274 275
	if (!privileged)
		xprt->resvport = 0;
L
Linus Torvalds 已提交
276 277

	/* printk("pmap: create clnt\n"); */
278
	clnt = rpc_new_client(xprt, hostname,
L
Linus Torvalds 已提交
279 280
				&pmap_program, RPC_PMAP_VERSION,
				RPC_AUTH_UNIX);
281
	if (!IS_ERR(clnt)) {
L
Linus Torvalds 已提交
282 283 284 285 286 287 288 289 290 291
		clnt->cl_softrtry = 1;
		clnt->cl_oneshot  = 1;
	}
	return clnt;
}

/*
 * XDR encode/decode functions for PMAP
 */
static int
292
xdr_encode_mapping(struct rpc_rqst *req, u32 *p, struct portmap_args *map)
L
Linus Torvalds 已提交
293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325
{
	dprintk("RPC: xdr_encode_mapping(%d, %d, %d, %d)\n",
		map->pm_prog, map->pm_vers, map->pm_prot, map->pm_port);
	*p++ = htonl(map->pm_prog);
	*p++ = htonl(map->pm_vers);
	*p++ = htonl(map->pm_prot);
	*p++ = htonl(map->pm_port);

	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
	return 0;
}

static int
xdr_decode_port(struct rpc_rqst *req, u32 *p, unsigned short *portp)
{
	*portp = (unsigned short) ntohl(*p++);
	return 0;
}

static int
xdr_decode_bool(struct rpc_rqst *req, u32 *p, unsigned int *boolp)
{
	*boolp = (unsigned int) ntohl(*p++);
	return 0;
}

static struct rpc_procinfo	pmap_procedures[] = {
[PMAP_SET] = {
	  .p_proc		= PMAP_SET,
	  .p_encode		= (kxdrproc_t) xdr_encode_mapping,	
	  .p_decode		= (kxdrproc_t) xdr_decode_bool,
	  .p_bufsiz		= 4,
	  .p_count		= 1,
326 327
	  .p_statidx		= PMAP_SET,
	  .p_name		= "SET",
L
Linus Torvalds 已提交
328 329 330 331 332 333 334
	},
[PMAP_UNSET] = {
	  .p_proc		= PMAP_UNSET,
	  .p_encode		= (kxdrproc_t) xdr_encode_mapping,	
	  .p_decode		= (kxdrproc_t) xdr_decode_bool,
	  .p_bufsiz		= 4,
	  .p_count		= 1,
335 336
	  .p_statidx		= PMAP_UNSET,
	  .p_name		= "UNSET",
L
Linus Torvalds 已提交
337 338 339 340 341 342 343
	},
[PMAP_GETPORT] = {
	  .p_proc		= PMAP_GETPORT,
	  .p_encode		= (kxdrproc_t) xdr_encode_mapping,
	  .p_decode		= (kxdrproc_t) xdr_decode_port,
	  .p_bufsiz		= 4,
	  .p_count		= 1,
344 345
	  .p_statidx		= PMAP_GETPORT,
	  .p_name		= "GETPORT",
L
Linus Torvalds 已提交
346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369
	},
};

static struct rpc_version	pmap_version2 = {
	.number		= 2,
	.nrprocs	= 4,
	.procs		= pmap_procedures
};

static struct rpc_version *	pmap_version[] = {
	NULL,
	NULL,
	&pmap_version2
};

static struct rpc_stat		pmap_stats;

static struct rpc_program	pmap_program = {
	.name		= "portmap",
	.number		= RPC_PMAP_PROGRAM,
	.nrvers		= ARRAY_SIZE(pmap_version),
	.version	= pmap_version,
	.stats		= &pmap_stats,
};