1 /*	$NetBSD: nfs_prot_svc.c,v 1.1.1.3 2015/01/17 16:34:15 christos Exp $	*/
2 
3 /*
4  * Copyright (c) 1997-2014 Erez Zadok
5  * Copyright (c) 1989 Jan-Simon Pendry
6  * Copyright (c) 1989 Imperial College of Science, Technology & Medicine
7  * Copyright (c) 1989 The Regents of the University of California.
8  * All rights reserved.
9  *
10  * This code is derived from software contributed to Berkeley by
11  * Jan-Simon Pendry at Imperial College, London.
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that the following conditions
15  * are met:
16  * 1. Redistributions of source code must retain the above copyright
17  *    notice, this list of conditions and the following disclaimer.
18  * 2. Redistributions in binary form must reproduce the above copyright
19  *    notice, this list of conditions and the following disclaimer in the
20  *    documentation and/or other materials provided with the distribution.
21  * 3. Neither the name of the University nor the names of its contributors
22  *    may be used to endorse or promote products derived from this software
23  *    without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35  * SUCH DAMAGE.
36  *
37  *
38  * File: am-utils/amd/nfs_prot_svc.c
39  *
40  */
41 
42 #ifdef HAVE_CONFIG_H
43 # include <config.h>
44 #endif /* HAVE_CONFIG_H */
45 #include <am_defs.h>
46 #include <amd.h>
47 
48 /* external definitions */
49 extern voidp nfsproc_null_2_svc(voidp, struct svc_req *);
50 extern nfsattrstat *nfsproc_getattr_2_svc(am_nfs_fh *, struct svc_req *);
51 extern nfsattrstat *nfsproc_setattr_2_svc(nfssattrargs *, struct svc_req *);
52 extern voidp nfsproc_root_2_svc(voidp, struct svc_req *);
53 extern nfsdiropres *nfsproc_lookup_2_svc(nfsdiropargs *, struct svc_req *);
54 extern nfsreadlinkres *nfsproc_readlink_2_svc(am_nfs_fh *, struct svc_req *);
55 extern nfsreadres *nfsproc_read_2_svc(nfsreadargs *, struct svc_req *);
56 extern voidp nfsproc_writecache_2_svc(voidp, struct svc_req *);
57 extern nfsattrstat *nfsproc_write_2_svc(nfswriteargs *, struct svc_req *);
58 extern nfsdiropres *nfsproc_create_2_svc(nfscreateargs *, struct svc_req *);
59 extern nfsstat *nfsproc_remove_2_svc(nfsdiropargs *, struct svc_req *);
60 extern nfsstat *nfsproc_rename_2_svc(nfsrenameargs *, struct svc_req *);
61 extern nfsstat *nfsproc_link_2_svc(nfslinkargs *, struct svc_req *);
62 extern nfsstat *nfsproc_symlink_2_svc(nfssymlinkargs *, struct svc_req *);
63 extern nfsdiropres *nfsproc_mkdir_2_svc(nfscreateargs *, struct svc_req *);
64 extern nfsstat *nfsproc_rmdir_2_svc(nfsdiropargs *, struct svc_req *);
65 extern nfsreaddirres *nfsproc_readdir_2_svc(nfsreaddirargs *, struct svc_req *);
66 extern nfsstatfsres *nfsproc_statfs_2_svc(am_nfs_fh *, struct svc_req *);
67 
68 /* global variables */
69 SVCXPRT *current_transp;
70 dispatcher_t nfs_dispatcher = nfs_program_2;
71 
72 /* typedefs */
73 typedef char *(*nfssvcproc_t)(voidp, struct svc_req *);
74 
75 
76 void
nfs_program_2(struct svc_req * rqstp,SVCXPRT * transp)77 nfs_program_2(struct svc_req *rqstp, SVCXPRT *transp)
78 {
79   union {
80     am_nfs_fh		nfsproc_getattr_2_arg;
81     nfssattrargs	nfsproc_setattr_2_arg;
82     nfsdiropargs	nfsproc_lookup_2_arg;
83     am_nfs_fh		nfsproc_readlink_2_arg;
84     nfsreadargs		nfsproc_read_2_arg;
85     nfswriteargs	nfsproc_write_2_arg;
86     nfscreateargs	nfsproc_create_2_arg;
87     nfsdiropargs	nfsproc_remove_2_arg;
88     nfsrenameargs	nfsproc_rename_2_arg;
89     nfslinkargs		nfsproc_link_2_arg;
90     nfssymlinkargs	nfsproc_symlink_2_arg;
91     nfscreateargs	nfsproc_mkdir_2_arg;
92     nfsdiropargs	fsproc_rmdir_2_arg;
93     nfsreaddirargs	nfsproc_readdir_2_arg;
94     am_nfs_fh		nfsproc_statfs_2_arg;
95   } argument;
96   char *result;
97   xdrproc_t xdr_argument, xdr_result;
98   nfssvcproc_t local;
99 
100 #ifdef HAVE_TRANSPORT_TYPE_TLI
101   /*
102    * On TLI systems we don't use an INET network type, but a "ticlts" (see
103    * /etc/netconfig and conf/transp_tli.c:create_nfs_service).  This means
104    * that packets could only come from the loopback interface, and we don't
105    * need to check them and filter possibly spoofed packets.  Therefore we
106    * only need to check if the UID caller is correct.
107    */
108 # ifdef HAVE___RPC_GET_LOCAL_UID
109   uid_t u;
110   /* extern definition for an internal libnsl function */
111   extern int __rpc_get_local_uid(SVCXPRT *transp, uid_t *uid);
112   if (__rpc_get_local_uid(transp, &u) >= 0  &&  u != 0) {
113     plog(XLOG_WARNING, "ignoring request from UID %ld, must be 0", (long) u);
114     return;
115   }
116 # else /* not HAVE___RPC_GET_LOCAL_UID */
117   dlog("cannot verify local uid for rpc request");
118 # endif /* HAVE___RPC_GET_LOCAL_UID */
119 #else /* not HAVE_TRANPORT_TYPE_TLI */
120   struct sockaddr_in *sinp;
121   char dq[20], dq2[28];
122   sinp = amu_svc_getcaller(rqstp->rq_xprt);
123 # ifdef MNT2_NFS_OPT_RESVPORT
124   /* Verify that the request comes from a reserved port */
125   if (sinp &&
126       ntohs(sinp->sin_port) >= IPPORT_RESERVED &&
127       !(gopt.flags & CFM_NFS_INSECURE_PORT)) {
128     plog(XLOG_WARNING, "ignoring request from %s:%u, port not reserved",
129 	 inet_dquad(dq, sizeof(dq), sinp->sin_addr.s_addr),
130 	 ntohs(sinp->sin_port));
131     return;
132   }
133 # endif /* MNT2_NFS_OPT_RESVPORT */
134   /* if the address does not match, ignore the request */
135   if (sinp && (sinp->sin_addr.s_addr != myipaddr.s_addr)) {
136     if (gopt.flags & CFM_NFS_ANY_INTERFACE) {
137       if (!is_interface_local(sinp->sin_addr.s_addr)) {
138 	plog(XLOG_WARNING, "ignoring request from %s:%u, not a local interface",
139 	     inet_dquad(dq, sizeof(dq), sinp->sin_addr.s_addr),
140 	     ntohs(sinp->sin_port));
141       }
142     } else {
143       plog(XLOG_WARNING, "ignoring request from %s:%u, expected %s",
144 	   inet_dquad(dq, sizeof(dq), sinp->sin_addr.s_addr),
145 	   ntohs(sinp->sin_port),
146 	   inet_dquad(dq2, sizeof(dq2), myipaddr.s_addr));
147       return;
148     }
149   }
150 #endif /* not HAVE_TRANPORT_TYPE_TLI */
151 
152   current_transp = NULL;
153 
154   switch (rqstp->rq_proc) {
155 
156   case NFSPROC_NULL:
157     xdr_argument = (xdrproc_t) xdr_void;
158     xdr_result = (xdrproc_t) xdr_void;
159     local = (nfssvcproc_t) nfsproc_null_2_svc;
160     break;
161 
162   case NFSPROC_GETATTR:
163     xdr_argument = (xdrproc_t) xdr_nfs_fh;
164     xdr_result = (xdrproc_t) xdr_attrstat;
165     local = (nfssvcproc_t) nfsproc_getattr_2_svc;
166     break;
167 
168   case NFSPROC_SETATTR:
169     xdr_argument = (xdrproc_t) xdr_sattrargs;
170     xdr_result = (xdrproc_t) xdr_attrstat;
171     local = (nfssvcproc_t) nfsproc_setattr_2_svc;
172     break;
173 
174   case NFSPROC_ROOT:
175     xdr_argument = (xdrproc_t) xdr_void;
176     xdr_result = (xdrproc_t) xdr_void;
177     local = (nfssvcproc_t) nfsproc_root_2_svc;
178     break;
179 
180   case NFSPROC_LOOKUP:
181     xdr_argument = (xdrproc_t) xdr_diropargs;
182     xdr_result = (xdrproc_t) xdr_diropres;
183     local = (nfssvcproc_t) nfsproc_lookup_2_svc;
184     /*
185      * Cheap way to pass transp down to amfs_auto_lookuppn so it can
186      * be stored in the am_node structure and later used for
187      * quick_reply().
188      */
189     current_transp = transp;
190     break;
191 
192   case NFSPROC_READLINK:
193     xdr_argument = (xdrproc_t) xdr_nfs_fh;
194     xdr_result = (xdrproc_t) xdr_readlinkres;
195     local = (nfssvcproc_t) nfsproc_readlink_2_svc;
196     break;
197 
198   case NFSPROC_READ:
199     xdr_argument = (xdrproc_t) xdr_readargs;
200     xdr_result = (xdrproc_t) xdr_readres;
201     local = (nfssvcproc_t) nfsproc_read_2_svc;
202     break;
203 
204   case NFSPROC_WRITECACHE:
205     xdr_argument = (xdrproc_t) xdr_void;
206     xdr_result = (xdrproc_t) xdr_void;
207     local = (nfssvcproc_t) nfsproc_writecache_2_svc;
208     break;
209 
210   case NFSPROC_WRITE:
211     xdr_argument = (xdrproc_t) xdr_writeargs;
212     xdr_result = (xdrproc_t) xdr_attrstat;
213     local = (nfssvcproc_t) nfsproc_write_2_svc;
214     break;
215 
216   case NFSPROC_CREATE:
217     xdr_argument = (xdrproc_t) xdr_createargs;
218     xdr_result = (xdrproc_t) xdr_diropres;
219     local = (nfssvcproc_t) nfsproc_create_2_svc;
220     break;
221 
222   case NFSPROC_REMOVE:
223     xdr_argument = (xdrproc_t) xdr_diropargs;
224     xdr_result = (xdrproc_t) xdr_nfsstat;
225     local = (nfssvcproc_t) nfsproc_remove_2_svc;
226     break;
227 
228   case NFSPROC_RENAME:
229     xdr_argument = (xdrproc_t) xdr_renameargs;
230     xdr_result = (xdrproc_t) xdr_nfsstat;
231     local = (nfssvcproc_t) nfsproc_rename_2_svc;
232     break;
233 
234   case NFSPROC_LINK:
235     xdr_argument = (xdrproc_t) xdr_linkargs;
236     xdr_result = (xdrproc_t) xdr_nfsstat;
237     local = (nfssvcproc_t) nfsproc_link_2_svc;
238     break;
239 
240   case NFSPROC_SYMLINK:
241     xdr_argument = (xdrproc_t) xdr_symlinkargs;
242     xdr_result = (xdrproc_t) xdr_nfsstat;
243     local = (nfssvcproc_t) nfsproc_symlink_2_svc;
244     break;
245 
246   case NFSPROC_MKDIR:
247     xdr_argument = (xdrproc_t) xdr_createargs;
248     xdr_result = (xdrproc_t) xdr_diropres;
249     local = (nfssvcproc_t) nfsproc_mkdir_2_svc;
250     break;
251 
252   case NFSPROC_RMDIR:
253     xdr_argument = (xdrproc_t) xdr_diropargs;
254     xdr_result = (xdrproc_t) xdr_nfsstat;
255     local = (nfssvcproc_t) nfsproc_rmdir_2_svc;
256     break;
257 
258   case NFSPROC_READDIR:
259     xdr_argument = (xdrproc_t) xdr_readdirargs;
260     xdr_result = (xdrproc_t) xdr_readdirres;
261     local = (nfssvcproc_t) nfsproc_readdir_2_svc;
262     break;
263 
264   case NFSPROC_STATFS:
265     xdr_argument = (xdrproc_t) xdr_nfs_fh;
266     xdr_result = (xdrproc_t) xdr_statfsres;
267     local = (nfssvcproc_t) nfsproc_statfs_2_svc;
268     break;
269 
270   default:
271     svcerr_noproc(transp);
272     return;
273   }
274 
275   memset((char *) &argument, 0, sizeof(argument));
276   if (!svc_getargs(transp,
277 		   (XDRPROC_T_TYPE) xdr_argument,
278 		   (SVC_IN_ARG_TYPE) &argument)) {
279     plog(XLOG_ERROR,
280 	 "NFS xdr decode failed for %d %d %d",
281 	 (int) rqstp->rq_prog, (int) rqstp->rq_vers, (int) rqstp->rq_proc);
282     svcerr_decode(transp);
283     return;
284   }
285   result = (*local) (&argument, rqstp);
286 
287   current_transp = NULL;
288 
289   if (result != NULL && !svc_sendreply(transp,
290 				       (XDRPROC_T_TYPE) xdr_result,
291 				       result)) {
292     svcerr_systemerr(transp);
293   }
294   if (!svc_freeargs(transp,
295 		    (XDRPROC_T_TYPE) xdr_argument,
296 		    (SVC_IN_ARG_TYPE) & argument)) {
297     plog(XLOG_FATAL, "unable to free rpc arguments in nfs_program_2");
298     going_down(1);
299   }
300 }
301 
302 void
nfs_program_3(struct svc_req * rqstp,register SVCXPRT * transp)303 nfs_program_3(struct svc_req *rqstp, register SVCXPRT *transp)
304 {
305   union {
306     am_GETATTR3args am_nfs3_getattr_3_arg;
307     am_SETATTR3args am_nfs3_setattr_3_arg;
308     am_LOOKUP3args am_nfs3_lookup_3_arg;
309     am_ACCESS3args am_nfs3_access_3_arg;
310     am_READLINK3args am_nfs3_readlink_3_arg;
311     am_READ3args am_nfs3_read_3_arg;
312     am_WRITE3args am_nfs3_write_3_arg;
313     am_CREATE3args am_nfs3_create_3_arg;
314     am_MKDIR3args am_nfs3_mkdir_3_arg;
315     am_SYMLINK3args am_nfs3_symlink_3_arg;
316     am_MKNOD3args am_nfs3_mknod_3_arg;
317     am_REMOVE3args am_nfs3_remove_3_arg;
318     am_RMDIR3args am_nfs3_rmdir_3_arg;
319     am_RENAME3args am_nfs3_rename_3_arg;
320     am_LINK3args am_nfs3_link_3_arg;
321     am_READDIR3args am_nfs3_readdir_3_arg;
322     am_READDIRPLUS3args am_nfs3_readdirplus_3_arg;
323     am_FSSTAT3args am_nfs3_fsstat_3_arg;
324     am_FSINFO3args am_nfs3_fsinfo_3_arg;
325     am_PATHCONF3args am_nfs3_pathconf_3_arg;
326     am_COMMIT3args am_nfs3_commit_3_arg;
327   } argument;
328   char *result;
329   xdrproc_t _xdr_argument, _xdr_result;
330   nfssvcproc_t local;
331 
332   switch (rqstp->rq_proc) {
333   case AM_NFS3_NULL:
334     _xdr_argument = (xdrproc_t) xdr_void;
335     _xdr_result = (xdrproc_t) xdr_void;
336     local = (nfssvcproc_t) am_nfs3_null_3_svc;
337     break;
338 
339   case AM_NFS3_GETATTR:
340     _xdr_argument = (xdrproc_t) xdr_am_GETATTR3args;
341     _xdr_result = (xdrproc_t) xdr_am_GETATTR3res;
342     local = (nfssvcproc_t) (char *(*)(char *, struct svc_req *)) am_nfs3_getattr_3_svc;
343     break;
344 
345   case AM_NFS3_SETATTR:
346     _xdr_argument = (xdrproc_t) xdr_am_SETATTR3args;
347     _xdr_result = (xdrproc_t) xdr_am_SETATTR3res;
348     local = (nfssvcproc_t) (char *(*)(char *, struct svc_req *)) am_nfs3_setattr_3_svc;
349     break;
350 
351   case AM_NFS3_LOOKUP:
352     _xdr_argument = (xdrproc_t) xdr_am_LOOKUP3args;
353     _xdr_result = (xdrproc_t) xdr_am_LOOKUP3res;
354     local = (nfssvcproc_t) (char *(*)(char *, struct svc_req *)) am_nfs3_lookup_3_svc;
355     break;
356 
357   case AM_NFS3_ACCESS:
358     _xdr_argument = (xdrproc_t) xdr_am_ACCESS3args;
359     _xdr_result = (xdrproc_t) xdr_am_ACCESS3res;
360     local = (nfssvcproc_t) (char *(*)(char *, struct svc_req *)) am_nfs3_access_3_svc;
361     break;
362 
363   case AM_NFS3_READLINK:
364     _xdr_argument = (xdrproc_t) xdr_am_READLINK3args;
365     _xdr_result = (xdrproc_t) xdr_am_READLINK3res;
366     local = (nfssvcproc_t) (char *(*)(char *, struct svc_req *)) am_nfs3_readlink_3_svc;
367     break;
368 
369   case AM_NFS3_READ:
370     _xdr_argument = (xdrproc_t) xdr_am_READ3args;
371     _xdr_result = (xdrproc_t) xdr_am_READ3res;
372     local = (nfssvcproc_t) (char *(*)(char *, struct svc_req *)) am_nfs3_read_3_svc;
373     break;
374 
375   case AM_NFS3_WRITE:
376     _xdr_argument = (xdrproc_t) xdr_am_WRITE3args;
377     _xdr_result = (xdrproc_t) xdr_am_WRITE3res;
378     local = (nfssvcproc_t) (char *(*)(char *, struct svc_req *)) am_nfs3_write_3_svc;
379     break;
380 
381   case AM_NFS3_CREATE:
382     _xdr_argument = (xdrproc_t) xdr_am_CREATE3args;
383     _xdr_result = (xdrproc_t) xdr_am_CREATE3res;
384     local = (nfssvcproc_t) (char *(*)(char *, struct svc_req *)) am_nfs3_create_3_svc;
385     break;
386 
387   case AM_NFS3_MKDIR:
388     _xdr_argument = (xdrproc_t) xdr_am_MKDIR3args;
389     _xdr_result = (xdrproc_t) xdr_am_MKDIR3res;
390     local = (nfssvcproc_t) (char *(*)(char *, struct svc_req *)) am_nfs3_mkdir_3_svc;
391     break;
392 
393   case AM_NFS3_SYMLINK:
394     _xdr_argument = (xdrproc_t) xdr_am_SYMLINK3args;
395     _xdr_result = (xdrproc_t) xdr_am_SYMLINK3res;
396     local = (nfssvcproc_t) (char *(*)(char *, struct svc_req *)) am_nfs3_symlink_3_svc;
397     break;
398 
399   case AM_NFS3_MKNOD:
400     _xdr_argument = (xdrproc_t) xdr_am_MKNOD3args;
401     _xdr_result = (xdrproc_t) xdr_am_MKNOD3res;
402     local = (nfssvcproc_t) (char *(*)(char *, struct svc_req *)) am_nfs3_mknod_3_svc;
403     break;
404 
405   case AM_NFS3_REMOVE:
406     _xdr_argument = (xdrproc_t) xdr_am_REMOVE3args;
407     _xdr_result = (xdrproc_t) xdr_am_REMOVE3res;
408     local = (nfssvcproc_t) (char *(*)(char *, struct svc_req *)) am_nfs3_remove_3_svc;
409     break;
410 
411   case AM_NFS3_RMDIR:
412     _xdr_argument = (xdrproc_t) xdr_am_RMDIR3args;
413     _xdr_result = (xdrproc_t) xdr_am_RMDIR3res;
414     local = (nfssvcproc_t) (char *(*)(char *, struct svc_req *)) am_nfs3_rmdir_3_svc;
415     break;
416 
417   case AM_NFS3_RENAME:
418     _xdr_argument = (xdrproc_t) xdr_am_RENAME3args;
419     _xdr_result = (xdrproc_t) xdr_am_RENAME3res;
420     local = (nfssvcproc_t) (char *(*)(char *, struct svc_req *)) am_nfs3_rename_3_svc;
421     break;
422 
423   case AM_NFS3_LINK:
424     _xdr_argument = (xdrproc_t) xdr_am_LINK3args;
425     _xdr_result = (xdrproc_t) xdr_am_LINK3res;
426     local = (nfssvcproc_t) (char *(*)(char *, struct svc_req *)) am_nfs3_link_3_svc;
427     break;
428 
429   case AM_NFS3_READDIR:
430     _xdr_argument = (xdrproc_t) xdr_am_READDIR3args;
431     _xdr_result = (xdrproc_t) xdr_am_READDIR3res;
432     local = (nfssvcproc_t) (char *(*)(char *, struct svc_req *)) am_nfs3_readdir_3_svc;
433     break;
434 
435   case AM_NFS3_READDIRPLUS:
436     _xdr_argument = (xdrproc_t) xdr_am_READDIRPLUS3args;
437     _xdr_result = (xdrproc_t) xdr_am_READDIRPLUS3res;
438     local = (nfssvcproc_t) (char *(*)(char *, struct svc_req *)) am_nfs3_readdirplus_3_svc;
439     break;
440 
441   case AM_NFS3_FSSTAT:
442     _xdr_argument = (xdrproc_t) xdr_am_FSSTAT3args;
443     _xdr_result = (xdrproc_t) xdr_am_FSSTAT3res;
444     local = (nfssvcproc_t) (char *(*)(char *, struct svc_req *)) am_nfs3_fsstat_3_svc;
445     break;
446 
447   case AM_NFS3_FSINFO:
448     _xdr_argument = (xdrproc_t) xdr_am_FSINFO3args;
449     _xdr_result = (xdrproc_t) xdr_am_FSINFO3res;
450     local = (nfssvcproc_t) (char *(*)(char *, struct svc_req *)) am_nfs3_fsinfo_3_svc;
451     break;
452 
453   case AM_NFS3_PATHCONF:
454     _xdr_argument = (xdrproc_t) xdr_am_PATHCONF3args;
455     _xdr_result = (xdrproc_t) xdr_am_PATHCONF3res;
456     local = (nfssvcproc_t) (char *(*)(char *, struct svc_req *)) am_nfs3_pathconf_3_svc;
457     break;
458 
459   case AM_NFS3_COMMIT:
460     _xdr_argument = (xdrproc_t) xdr_am_COMMIT3args;
461     _xdr_result = (xdrproc_t) xdr_am_COMMIT3res;
462     local = (nfssvcproc_t) (char *(*)(char *, struct svc_req *)) am_nfs3_commit_3_svc;
463     break;
464 
465   default:
466     svcerr_noproc (transp);
467     return;
468   }
469 
470   memset ((char *)&argument, 0, sizeof (argument));
471 
472   if (!svc_getargs(transp, (xdrproc_t) _xdr_argument, (caddr_t) &argument)) {
473     plog(XLOG_ERROR,
474 	 "NFS xdr decode failed for %d %d %d",
475 	 (int) rqstp->rq_prog, (int) rqstp->rq_vers, (int) rqstp->rq_proc);
476     svcerr_decode(transp);
477     return;
478   }
479 
480   result = (*local) (&argument, rqstp);
481   if (result != NULL && !svc_sendreply(transp, (xdrproc_t) _xdr_result, result)) {
482     svcerr_systemerr (transp);
483   }
484 
485   if (!svc_freeargs (transp, (xdrproc_t) _xdr_argument, (caddr_t) &argument)) {
486     plog(XLOG_FATAL, "unable to free rpc arguments in nfs_program_3");
487     going_down(1);
488   }
489   return;
490 }
491