File: /usr/src/linux/net/sunrpc/svc.c

1     /*
2      * linux/net/sunrpc/svc.c
3      *
4      * High-level RPC service routines
5      *
6      * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
7      */
8     
9     #define __KERNEL_SYSCALLS__
10     #include <linux/linkage.h>
11     #include <linux/sched.h>
12     #include <linux/errno.h>
13     #include <linux/net.h>
14     #include <linux/in.h>
15     #include <linux/unistd.h>
16     
17     #include <linux/sunrpc/types.h>
18     #include <linux/sunrpc/xdr.h>
19     #include <linux/sunrpc/stats.h>
20     #include <linux/sunrpc/svcsock.h>
21     #include <linux/sunrpc/clnt.h>
22     
23     #define RPCDBG_FACILITY	RPCDBG_SVCDSP
24     #define RPC_PARANOIA 1
25     
26     /*
27      * Create an RPC service
28      */
29     struct svc_serv *
30     svc_create(struct svc_program *prog, unsigned int bufsize, unsigned int xdrsize)
31     {
32     	struct svc_serv	*serv;
33     
34     #ifdef RPC_DEBUG
35     	rpc_register_sysctl();
36     #endif
37     
38     	if (!(serv = (struct svc_serv *) kmalloc(sizeof(*serv), GFP_KERNEL)))
39     		return NULL;
40     
41     	memset(serv, 0, sizeof(*serv));
42     	serv->sv_program   = prog;
43     	serv->sv_nrthreads = 1;
44     	serv->sv_stats     = prog->pg_stats;
45     	serv->sv_bufsz	   = bufsize? bufsize : 4096;
46     	serv->sv_xdrsize   = xdrsize;
47     	spin_lock_init(&serv->sv_lock);
48     
49     	serv->sv_name      = prog->pg_name;
50     
51     	/* Remove any stale portmap registrations */
52     	svc_register(serv, 0, 0);
53     
54     	return serv;
55     }
56     
57     /*
58      * Destroy an RPC service
59      */
60     void
61     svc_destroy(struct svc_serv *serv)
62     {
63     	struct svc_sock	*svsk;
64     
65     	dprintk("RPC: svc_destroy(%s, %d)\n",
66     				serv->sv_program->pg_name,
67     				serv->sv_nrthreads);
68     
69     	if (serv->sv_nrthreads) {
70     		if (--(serv->sv_nrthreads) != 0)
71     			return;
72     	} else
73     		printk("svc_destroy: no threads for serv=%p!\n", serv);
74     
75     	while ((svsk = serv->sv_allsocks) != NULL)
76     		svc_delete_socket(svsk);
77     
78     	/* Unregister service with the portmapper */
79     	svc_register(serv, 0, 0);
80     	kfree(serv);
81     }
82     
83     /*
84      * Allocate an RPC server buffer
85      * Later versions may do nifty things by allocating multiple pages
86      * of memory directly and putting them into the bufp->iov.
87      */
88     int
89     svc_init_buffer(struct svc_buf *bufp, unsigned int size)
90     {
91     	if (!(bufp->area = (u32 *) kmalloc(size, GFP_KERNEL)))
92     		return 0;
93     	bufp->base   = bufp->area;
94     	bufp->buf    = bufp->area;
95     	bufp->len    = 0;
96     	bufp->buflen = size >> 2;
97     
98     	bufp->iov[0].iov_base = bufp->area;
99     	bufp->iov[0].iov_len  = size;
100     	bufp->nriov = 1;
101     
102     	return 1;
103     }
104     
105     /*
106      * Release an RPC server buffer
107      */
108     void
109     svc_release_buffer(struct svc_buf *bufp)
110     {
111     	kfree(bufp->area);
112     	bufp->area = 0;
113     }
114     
115     /*
116      * Create a server thread
117      */
118     int
119     svc_create_thread(svc_thread_fn func, struct svc_serv *serv)
120     {
121     	struct svc_rqst	*rqstp;
122     	int		error = -ENOMEM;
123     
124     	rqstp = kmalloc(sizeof(*rqstp), GFP_KERNEL);
125     	if (!rqstp)
126     		goto out;
127     
128     	memset(rqstp, 0, sizeof(*rqstp));
129     	init_waitqueue_head(&rqstp->rq_wait);
130     
131     	if (!(rqstp->rq_argp = (u32 *) kmalloc(serv->sv_xdrsize, GFP_KERNEL))
132     	 || !(rqstp->rq_resp = (u32 *) kmalloc(serv->sv_xdrsize, GFP_KERNEL))
133     	 || !svc_init_buffer(&rqstp->rq_defbuf, serv->sv_bufsz))
134     		goto out_thread;
135     
136     	serv->sv_nrthreads++;
137     	rqstp->rq_server = serv;
138     	error = kernel_thread((int (*)(void *)) func, rqstp, 0);
139     	if (error < 0)
140     		goto out_thread;
141     	error = 0;
142     out:
143     	return error;
144     
145     out_thread:
146     	svc_exit_thread(rqstp);
147     	goto out;
148     }
149     
150     /*
151      * Destroy an RPC server thread
152      */
153     void
154     svc_exit_thread(struct svc_rqst *rqstp)
155     {
156     	struct svc_serv	*serv = rqstp->rq_server;
157     
158     	svc_release_buffer(&rqstp->rq_defbuf);
159     	if (rqstp->rq_resp)
160     		kfree(rqstp->rq_resp);
161     	if (rqstp->rq_argp)
162     		kfree(rqstp->rq_argp);
163     	kfree(rqstp);
164     
165     	/* Release the server */
166     	if (serv)
167     		svc_destroy(serv);
168     }
169     
170     /*
171      * Register an RPC service with the local portmapper.
172      * To unregister a service, call this routine with 
173      * proto and port == 0.
174      */
175     int
176     svc_register(struct svc_serv *serv, int proto, unsigned short port)
177     {
178     	struct svc_program	*progp;
179     	unsigned long		flags;
180     	int			i, error = 0, dummy;
181     
182     	progp = serv->sv_program;
183     
184     	dprintk("RPC: svc_register(%s, %s, %d)\n",
185     		progp->pg_name, proto == IPPROTO_UDP? "udp" : "tcp", port);
186     
187     	if (!port)
188     		current->sigpending = 0;
189     
190     	for (i = 0; i < progp->pg_nvers; i++) {
191     		if (progp->pg_vers[i] == NULL)
192     			continue;
193     		error = rpc_register(progp->pg_prog, i, proto, port, &dummy);
194     		if (error < 0)
195     			break;
196     		if (port && !dummy) {
197     			error = -EACCES;
198     			break;
199     		}
200     	}
201     
202     	if (!port) {
203     		spin_lock_irqsave(&current->sigmask_lock, flags);
204     		recalc_sigpending(current);
205     		spin_unlock_irqrestore(&current->sigmask_lock, flags);
206     	}
207     
208     	return error;
209     }
210     
211     /*
212      * Process the RPC request.
213      */
214     int
215     svc_process(struct svc_serv *serv, struct svc_rqst *rqstp)
216     {
217     	struct svc_program	*progp;
218     	struct svc_version	*versp = NULL;	/* compiler food */
219     	struct svc_procedure	*procp = NULL;
220     	struct svc_buf *	argp = &rqstp->rq_argbuf;
221     	struct svc_buf *	resp = &rqstp->rq_resbuf;
222     	kxdrproc_t		xdr;
223     	u32			*bufp, *statp;
224     	u32			dir, prog, vers, proc,
225     				auth_stat, rpc_stat;
226     
227     	rpc_stat = rpc_success;
228     	bufp = argp->buf;
229     
230     	if (argp->len < 5)
231     		goto err_short_len;
232     
233     	dir  = ntohl(*bufp++);
234     	vers = ntohl(*bufp++);
235     
236     	/* First words of reply: */
237     	svc_putlong(resp, xdr_one);		/* REPLY */
238     	svc_putlong(resp, xdr_zero);		/* ACCEPT */
239     
240     	if (dir != 0)		/* direction != CALL */
241     		goto err_bad_dir;
242     	if (vers != 2)		/* RPC version number */
243     		goto err_bad_rpc;
244     
245     	rqstp->rq_prog = prog = ntohl(*bufp++);	/* program number */
246     	rqstp->rq_vers = vers = ntohl(*bufp++);	/* version number */
247     	rqstp->rq_proc = proc = ntohl(*bufp++);	/* procedure number */
248     
249     	argp->buf += 5;
250     	argp->len -= 5;
251     
252     	/* Used by nfsd to only allow the NULL procedure for amd. */
253     	if (rqstp->rq_auth && !rqstp->rq_client && proc) {
254     		auth_stat = rpc_autherr_badcred;
255     		goto err_bad_auth;
256     	}
257     
258     	/*
259     	 * Decode auth data, and add verifier to reply buffer.
260     	 * We do this before anything else in order to get a decent
261     	 * auth verifier.
262     	 */
263     	svc_authenticate(rqstp, &rpc_stat, &auth_stat);
264     
265     	if (rpc_stat != rpc_success)
266     		goto err_garbage;
267     
268     	if (auth_stat != rpc_auth_ok)
269     		goto err_bad_auth;
270     
271     	progp = serv->sv_program;
272     	if (prog != progp->pg_prog)
273     		goto err_bad_prog;
274     
275     	if (vers >= progp->pg_nvers ||
276     	  !(versp = progp->pg_vers[vers]))
277     		goto err_bad_vers;
278     
279     	procp = versp->vs_proc + proc;
280     	if (proc >= versp->vs_nproc || !procp->pc_func)
281     		goto err_bad_proc;
282     	rqstp->rq_server   = serv;
283     	rqstp->rq_procinfo = procp;
284     
285     	/* Syntactic check complete */
286     	serv->sv_stats->rpccnt++;
287     
288     	/* Build the reply header. */
289     	statp = resp->buf;
290     	svc_putlong(resp, rpc_success);		/* RPC_SUCCESS */
291     
292     	/* Bump per-procedure stats counter */
293     	procp->pc_count++;
294     
295     	/* Initialize storage for argp and resp */
296     	memset(rqstp->rq_argp, 0, procp->pc_argsize);
297     	memset(rqstp->rq_resp, 0, procp->pc_ressize);
298     
299     	/* Call the function that processes the request. */
300     	if (!versp->vs_dispatch) {
301     		/* Decode arguments */
302     		xdr = procp->pc_decode;
303     		if (xdr && !xdr(rqstp, rqstp->rq_argbuf.buf, rqstp->rq_argp))
304     			goto err_garbage;
305     
306     		*statp = procp->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp);
307     
308     		/* Encode reply */
309     		if (*statp == rpc_success && (xdr = procp->pc_encode)
310     		 && !xdr(rqstp, rqstp->rq_resbuf.buf, rqstp->rq_resp)) {
311     			dprintk("svc: failed to encode reply\n");
312     			/* serv->sv_stats->rpcsystemerr++; */
313     			*statp = rpc_system_err;
314     		}
315     	} else {
316     		dprintk("svc: calling dispatcher\n");
317     		if (!versp->vs_dispatch(rqstp, statp))
318     			goto dropit;
319     	}
320     
321     	/* Check RPC status result */
322     	if (*statp != rpc_success)
323     		resp->len = statp + 1 - resp->base;
324     
325     	/* Release reply info */
326     	if (procp->pc_release)
327     		procp->pc_release(rqstp, NULL, rqstp->rq_resp);
328     
329     	if (procp->pc_encode == NULL)
330     		goto dropit;
331     sendit:
332     	return svc_send(rqstp);
333     
334     dropit:
335     	dprintk("svc: svc_process dropit\n");
336     	svc_drop(rqstp);
337     	return 0;
338     
339     err_short_len:
340     #ifdef RPC_PARANOIA
341     	printk("svc: short len %d, dropping request\n", argp->len);
342     #endif
343     	goto dropit;			/* drop request */
344     
345     err_bad_dir:
346     #ifdef RPC_PARANOIA
347     	printk("svc: bad direction %d, dropping request\n", dir);
348     #endif
349     	serv->sv_stats->rpcbadfmt++;
350     	goto dropit;			/* drop request */
351     
352     err_bad_rpc:
353     	serv->sv_stats->rpcbadfmt++;
354     	resp->buf[-1] = xdr_one;	/* REJECT */
355     	svc_putlong(resp, xdr_zero);	/* RPC_MISMATCH */
356     	svc_putlong(resp, xdr_two);	/* Only RPCv2 supported */
357     	svc_putlong(resp, xdr_two);
358     	goto sendit;
359     
360     err_bad_auth:
361     	dprintk("svc: authentication failed (%d)\n", ntohl(auth_stat));
362     	serv->sv_stats->rpcbadauth++;
363     	resp->buf[-1] = xdr_one;	/* REJECT */
364     	svc_putlong(resp, xdr_one);	/* AUTH_ERROR */
365     	svc_putlong(resp, auth_stat);	/* status */
366     	goto sendit;
367     
368     err_bad_prog:
369     #ifdef RPC_PARANOIA
370     	if (prog != 100227 || progp->pg_prog != 100003)
371     		printk("svc: unknown program %d (me %d)\n", prog, progp->pg_prog);
372     	/* else it is just a Solaris client seeing if ACLs are supported */
373     #endif
374     	serv->sv_stats->rpcbadfmt++;
375     	svc_putlong(resp, rpc_prog_unavail);
376     	goto sendit;
377     
378     err_bad_vers:
379     #ifdef RPC_PARANOIA
380     	printk("svc: unknown version (%d)\n", vers);
381     #endif
382     	serv->sv_stats->rpcbadfmt++;
383     	svc_putlong(resp, rpc_prog_mismatch);
384     	svc_putlong(resp, htonl(progp->pg_lovers));
385     	svc_putlong(resp, htonl(progp->pg_hivers));
386     	goto sendit;
387     
388     err_bad_proc:
389     #ifdef RPC_PARANOIA
390     	printk("svc: unknown procedure (%d)\n", proc);
391     #endif
392     	serv->sv_stats->rpcbadfmt++;
393     	svc_putlong(resp, rpc_proc_unavail);
394     	goto sendit;
395     
396     err_garbage:
397     #ifdef RPC_PARANOIA
398     	printk("svc: failed to decode args\n");
399     #endif
400     	serv->sv_stats->rpcbadfmt++;
401     	svc_putlong(resp, rpc_garbage_args);
402     	goto sendit;
403     }
404