Blame view

net/sunrpc/pmap_clnt.c 7.01 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
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
27
28
  /*
   * linux/net/sunrpc/pmap.c
   *
   * Portmapper client.
   *
   * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
   */
  
  #include <linux/config.h>
  #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
  
  static struct rpc_procinfo	pmap_procedures[];
6cd7525a0   Chuck Lever   SUNRPC: fix bug i...
29
  static struct rpc_clnt *	pmap_create(char *, struct sockaddr_in *, int, int);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
  static void			pmap_getport_done(struct rpc_task *);
  static struct rpc_program	pmap_program;
  static DEFINE_SPINLOCK(pmap_lock);
  
  /*
   * 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)
  {
  	struct rpc_portmap *map = clnt->cl_pmap;
  	struct sockaddr_in *sap = &clnt->cl_xprt->addr;
  	struct rpc_message msg = {
  		.rpc_proc	= &pmap_procedures[PMAP_GETPORT],
  		.rpc_argp	= map,
  		.rpc_resp	= &clnt->cl_port,
  		.rpc_cred	= NULL
  	};
  	struct rpc_clnt	*pmap_clnt;
  	struct rpc_task	*child;
  
  	dprintk("RPC: %4d rpc_getport(%s, %d, %d, %d)
  ",
  			task->tk_pid, clnt->cl_server,
  			map->pm_prog, map->pm_vers, map->pm_prot);
007e251f2   Andreas Gruenbacher   [PATCH] RPC: Allo...
56
57
  	/* Autobind on cloned rpc clients is discouraged */
  	BUG_ON(clnt->cl_parent != clnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58
59
60
61
62
63
64
65
  	spin_lock(&pmap_lock);
  	if (map->pm_binding) {
  		rpc_sleep_on(&map->pm_bindwait, task, NULL, NULL);
  		spin_unlock(&pmap_lock);
  		return;
  	}
  	map->pm_binding = 1;
  	spin_unlock(&pmap_lock);
6cd7525a0   Chuck Lever   SUNRPC: fix bug i...
66
  	pmap_clnt = pmap_create(clnt->cl_server, sap, map->pm_prot, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
  	if (IS_ERR(pmap_clnt)) {
  		task->tk_status = PTR_ERR(pmap_clnt);
  		goto bailout;
  	}
  	task->tk_status = 0;
  
  	/*
  	 * Note: rpc_new_child will release client after a failure.
  	 */
  	if (!(child = rpc_new_child(pmap_clnt, task)))
  		goto bailout;
  
  	/* Setup the call info struct */
  	rpc_call_setup(child, &msg, 0);
  
  	/* ... and run the child task */
  	rpc_run_child(task, child, pmap_getport_done);
  	return;
  
  bailout:
  	spin_lock(&pmap_lock);
  	map->pm_binding = 0;
  	rpc_wake_up(&map->pm_bindwait);
  	spin_unlock(&pmap_lock);
abbcf28f2   Trond Myklebust   SUNRPC: Yet more ...
91
  	rpc_exit(task, -EIO);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
  }
  
  #ifdef CONFIG_ROOT_NFS
  int
  rpc_getport_external(struct sockaddr_in *sin, __u32 prog, __u32 vers, int prot)
  {
  	struct rpc_portmap map = {
  		.pm_prog	= prog,
  		.pm_vers	= vers,
  		.pm_prot	= prot,
  		.pm_port	= 0
  	};
  	struct rpc_clnt	*pmap_clnt;
  	char		hostname[32];
  	int		status;
  
  	dprintk("RPC:      rpc_getport_external(%u.%u.%u.%u, %d, %d, %d)
  ",
  			NIPQUAD(sin->sin_addr.s_addr), prog, vers, prot);
  
  	sprintf(hostname, "%u.%u.%u.%u", NIPQUAD(sin->sin_addr.s_addr));
6cd7525a0   Chuck Lever   SUNRPC: fix bug i...
113
  	pmap_clnt = pmap_create(hostname, sin, prot, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
  	if (IS_ERR(pmap_clnt))
  		return PTR_ERR(pmap_clnt);
  
  	/* Setup the call info struct */
  	status = rpc_call(pmap_clnt, PMAP_GETPORT, &map, &map.pm_port, 0);
  
  	if (status >= 0) {
  		if (map.pm_port != 0)
  			return map.pm_port;
  		status = -EACCES;
  	}
  	return status;
  }
  #endif
  
  static void
  pmap_getport_done(struct rpc_task *task)
  {
  	struct rpc_clnt	*clnt = task->tk_client;
922004120   Chuck Lever   SUNRPC: transport...
133
  	struct rpc_xprt *xprt = task->tk_xprt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
134
135
136
137
138
  	struct rpc_portmap *map = clnt->cl_pmap;
  
  	dprintk("RPC: %4d pmap_getport_done(status %d, port %d)
  ",
  			task->tk_pid, task->tk_status, clnt->cl_port);
922004120   Chuck Lever   SUNRPC: transport...
139
140
  
  	xprt->ops->set_port(xprt, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
141
142
  	if (task->tk_status < 0) {
  		/* Make the calling task exit with an error */
abbcf28f2   Trond Myklebust   SUNRPC: Yet more ...
143
  		task->tk_action = rpc_exit_task;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
144
145
  	} else if (clnt->cl_port == 0) {
  		/* Program not registered */
abbcf28f2   Trond Myklebust   SUNRPC: Yet more ...
146
  		rpc_exit(task, -EACCES);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
147
  	} else {
922004120   Chuck Lever   SUNRPC: transport...
148
  		xprt->ops->set_port(xprt, clnt->cl_port);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
149
  		clnt->cl_port = htons(clnt->cl_port);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
  	}
  	spin_lock(&pmap_lock);
  	map->pm_binding = 0;
  	rpc_wake_up(&map->pm_bindwait);
  	spin_unlock(&pmap_lock);
  }
  
  /*
   * 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)
  {
  	struct sockaddr_in	sin;
  	struct rpc_portmap	map;
  	struct rpc_clnt		*pmap_clnt;
  	int error = 0;
  
  	dprintk("RPC: registering (%d, %d, %d, %d) with portmapper.
  ",
  			prog, vers, prot, port);
  
  	sin.sin_family = AF_INET;
  	sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
6cd7525a0   Chuck Lever   SUNRPC: fix bug i...
175
  	pmap_clnt = pmap_create("localhost", &sin, IPPROTO_UDP, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
  	if (IS_ERR(pmap_clnt)) {
  		error = PTR_ERR(pmap_clnt);
  		dprintk("RPC: couldn't create pmap client. Error = %d
  ", error);
  		return error;
  	}
  
  	map.pm_prog = prog;
  	map.pm_vers = vers;
  	map.pm_prot = prot;
  	map.pm_port = port;
  
  	error = rpc_call(pmap_clnt, port? PMAP_SET : PMAP_UNSET,
  					&map, okay, 0);
  
  	if (error < 0) {
  		printk(KERN_WARNING
  			"RPC: failed to contact portmap (errno %d).
  ",
  			error);
  	}
  	dprintk("RPC: registration status %d/%d
  ", error, *okay);
  
  	/* Client deleted automatically because cl_oneshot == 1 */
  	return error;
  }
  
  static struct rpc_clnt *
6cd7525a0   Chuck Lever   SUNRPC: fix bug i...
205
  pmap_create(char *hostname, struct sockaddr_in *srvaddr, int proto, int privileged)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
206
207
208
209
210
211
212
213
214
  {
  	struct rpc_xprt	*xprt;
  	struct rpc_clnt	*clnt;
  
  	/* printk("pmap: create xprt
  "); */
  	xprt = xprt_create_proto(proto, srvaddr, NULL);
  	if (IS_ERR(xprt))
  		return (struct rpc_clnt *)xprt;
922004120   Chuck Lever   SUNRPC: transport...
215
  	xprt->ops->set_port(xprt, RPC_PMAP_PORT);
6cd7525a0   Chuck Lever   SUNRPC: fix bug i...
216
217
  	if (!privileged)
  		xprt->resvport = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
218
219
220
  
  	/* printk("pmap: create clnt
  "); */
5ee0ed7d3   Trond Myklebust   [PATCH] RPC: Make...
221
  	clnt = rpc_new_client(xprt, hostname,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
222
223
  				&pmap_program, RPC_PMAP_VERSION,
  				RPC_AUTH_UNIX);
5b616f5d5   Trond Myklebust   [PATCH] RPC: Make...
224
  	if (!IS_ERR(clnt)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
225
  		clnt->cl_softrtry = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
  		clnt->cl_oneshot  = 1;
  	}
  	return clnt;
  }
  
  /*
   * XDR encode/decode functions for PMAP
   */
  static int
  xdr_encode_mapping(struct rpc_rqst *req, u32 *p, struct rpc_portmap *map)
  {
  	dprintk("RPC: xdr_encode_mapping(%d, %d, %d, %d)
  ",
  		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,
  	},
  [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,
  	},
  [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,
  	},
  };
  
  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,
  };