OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [net/] [sunrpc/] [svc.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.