]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/rpc/rpc_generic.c
Upgrade to 9.6-ESV-R4-P1, which address the following issues:
[FreeBSD/FreeBSD.git] / sys / rpc / rpc_generic.c
1 /*      $NetBSD: rpc_generic.c,v 1.4 2000/09/28 09:07:04 kleink Exp $   */
2
3 /*
4  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
5  * unrestricted use provided that this legend is included on all tape
6  * media and as a part of the software program in whole or part.  Users
7  * may copy or modify Sun RPC without charge, but are not authorized
8  * to license or distribute it to anyone else except as part of a product or
9  * program developed by the user.
10  * 
11  * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
12  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
13  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
14  * 
15  * Sun RPC is provided with no support and without any obligation on the
16  * part of Sun Microsystems, Inc. to assist in its use, correction,
17  * modification or enhancement.
18  * 
19  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
20  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
21  * OR ANY PART THEREOF.
22  * 
23  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
24  * or profits or other special, indirect and consequential damages, even if
25  * Sun has been advised of the possibility of such damages.
26  * 
27  * Sun Microsystems, Inc.
28  * 2550 Garcia Avenue
29  * Mountain View, California  94043
30  */
31 /*
32  * Copyright (c) 1986-1991 by Sun Microsystems Inc. 
33  */
34
35 /* #pragma ident        "@(#)rpc_generic.c      1.17    94/04/24 SMI" */
36 #include <sys/cdefs.h>
37 __FBSDID("$FreeBSD$");
38
39 /*
40  * rpc_generic.c, Miscl routines for RPC.
41  *
42  */
43
44 #include "opt_inet6.h"
45
46 #include <sys/param.h>
47 #include <sys/kernel.h>
48 #include <sys/malloc.h>
49 #include <sys/mbuf.h>
50 #include <sys/module.h>
51 #include <sys/proc.h>
52 #include <sys/protosw.h>
53 #include <sys/sbuf.h>
54 #include <sys/systm.h>
55 #include <sys/socket.h>
56 #include <sys/socketvar.h>
57 #include <sys/syslog.h>
58
59 #include <net/vnet.h>
60
61 #include <rpc/rpc.h>
62 #include <rpc/nettype.h>
63
64 #include <rpc/rpc_com.h>
65
66 extern  u_long sb_max_adj;      /* not defined in socketvar.h */
67
68 #if __FreeBSD_version < 700000
69 #define strrchr rindex
70 #endif
71
72 struct handle {
73         NCONF_HANDLE *nhandle;
74         int nflag;              /* Whether NETPATH or NETCONFIG */
75         int nettype;
76 };
77
78 static const struct _rpcnettype {
79         const char *name;
80         const int type;
81 } _rpctypelist[] = {
82         { "netpath", _RPC_NETPATH },
83         { "visible", _RPC_VISIBLE },
84         { "circuit_v", _RPC_CIRCUIT_V },
85         { "datagram_v", _RPC_DATAGRAM_V },
86         { "circuit_n", _RPC_CIRCUIT_N },
87         { "datagram_n", _RPC_DATAGRAM_N },
88         { "tcp", _RPC_TCP },
89         { "udp", _RPC_UDP },
90         { 0, _RPC_NONE }
91 };
92
93 struct netid_af {
94         const char      *netid;
95         int             af;
96         int             protocol;
97 };
98
99 static const struct netid_af na_cvt[] = {
100         { "udp",  AF_INET,  IPPROTO_UDP },
101         { "tcp",  AF_INET,  IPPROTO_TCP },
102 #ifdef INET6
103         { "udp6", AF_INET6, IPPROTO_UDP },
104         { "tcp6", AF_INET6, IPPROTO_TCP },
105 #endif
106         { "local", AF_LOCAL, 0 }
107 };
108
109 struct rpc_createerr rpc_createerr;
110
111 /*
112  * Find the appropriate buffer size
113  */
114 u_int
115 /*ARGSUSED*/
116 __rpc_get_t_size(int af, int proto, int size)
117 {
118         int defsize;
119
120         switch (proto) {
121         case IPPROTO_TCP:
122                 defsize = 64 * 1024;    /* XXX */
123                 break;
124         case IPPROTO_UDP:
125                 defsize = UDPMSGSIZE;
126                 break;
127         default:
128                 defsize = RPC_MAXDATASIZE;
129                 break;
130         }
131         if (size == 0)
132                 return defsize;
133
134         /* Check whether the value is within the upper max limit */
135         return (size > sb_max_adj ? (u_int)sb_max_adj : (u_int)size);
136 }
137
138 /*
139  * Find the appropriate address buffer size
140  */
141 u_int
142 __rpc_get_a_size(af)
143         int af;
144 {
145         switch (af) {
146         case AF_INET:
147                 return sizeof (struct sockaddr_in);
148 #ifdef INET6
149         case AF_INET6:
150                 return sizeof (struct sockaddr_in6);
151 #endif
152         case AF_LOCAL:
153                 return sizeof (struct sockaddr_un);
154         default:
155                 break;
156         }
157         return ((u_int)RPC_MAXADDRSIZE);
158 }
159
160 #if 0
161
162 /*
163  * Used to ping the NULL procedure for clnt handle.
164  * Returns NULL if fails, else a non-NULL pointer.
165  */
166 void *
167 rpc_nullproc(clnt)
168         CLIENT *clnt;
169 {
170         struct timeval TIMEOUT = {25, 0};
171
172         if (clnt_call(clnt, NULLPROC, (xdrproc_t) xdr_void, NULL,
173                 (xdrproc_t) xdr_void, NULL, TIMEOUT) != RPC_SUCCESS) {
174                 return (NULL);
175         }
176         return ((void *) clnt);
177 }
178
179 #endif
180
181 int
182 __rpc_socket2sockinfo(struct socket *so, struct __rpc_sockinfo *sip)
183 {
184         int type, proto;
185         struct sockaddr *sa;
186         sa_family_t family;
187         struct sockopt opt;
188         int error;
189
190         CURVNET_SET(so->so_vnet);
191         error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa);
192         CURVNET_RESTORE();
193         if (error)
194                 return 0;
195
196         sip->si_alen = sa->sa_len;
197         family = sa->sa_family;
198         free(sa, M_SONAME);
199
200         opt.sopt_dir = SOPT_GET;
201         opt.sopt_level = SOL_SOCKET;
202         opt.sopt_name = SO_TYPE;
203         opt.sopt_val = &type;
204         opt.sopt_valsize = sizeof type;
205         opt.sopt_td = NULL;
206         error = sogetopt(so, &opt);
207         if (error)
208                 return 0;
209
210         /* XXX */
211         if (family != AF_LOCAL) {
212                 if (type == SOCK_STREAM)
213                         proto = IPPROTO_TCP;
214                 else if (type == SOCK_DGRAM)
215                         proto = IPPROTO_UDP;
216                 else
217                         return 0;
218         } else
219                 proto = 0;
220
221         sip->si_af = family;
222         sip->si_proto = proto;
223         sip->si_socktype = type;
224
225         return 1;
226 }
227
228 /*
229  * Linear search, but the number of entries is small.
230  */
231 int
232 __rpc_nconf2sockinfo(const struct netconfig *nconf, struct __rpc_sockinfo *sip)
233 {
234         int i;
235
236         for (i = 0; i < (sizeof na_cvt) / (sizeof (struct netid_af)); i++)
237                 if (strcmp(na_cvt[i].netid, nconf->nc_netid) == 0 || (
238                     strcmp(nconf->nc_netid, "unix") == 0 &&
239                     strcmp(na_cvt[i].netid, "local") == 0)) {
240                         sip->si_af = na_cvt[i].af;
241                         sip->si_proto = na_cvt[i].protocol;
242                         sip->si_socktype =
243                             __rpc_seman2socktype((int)nconf->nc_semantics);
244                         if (sip->si_socktype == -1)
245                                 return 0;
246                         sip->si_alen = __rpc_get_a_size(sip->si_af);
247                         return 1;
248                 }
249
250         return 0;
251 }
252
253 struct socket *
254 __rpc_nconf2socket(const struct netconfig *nconf)
255 {
256         struct __rpc_sockinfo si;
257         struct socket *so;
258         int error;
259
260         if (!__rpc_nconf2sockinfo(nconf, &si))
261                 return 0;
262
263         so = NULL;
264         error =  socreate(si.si_af, &so, si.si_socktype, si.si_proto,
265             curthread->td_ucred, curthread);
266
267         if (error)
268                 return NULL;
269         else
270                 return so;
271 }
272
273 char *
274 taddr2uaddr(const struct netconfig *nconf, const struct netbuf *nbuf)
275 {
276         struct __rpc_sockinfo si;
277
278         if (!__rpc_nconf2sockinfo(nconf, &si))
279                 return NULL;
280         return __rpc_taddr2uaddr_af(si.si_af, nbuf);
281 }
282
283 struct netbuf *
284 uaddr2taddr(const struct netconfig *nconf, const char *uaddr)
285 {
286         struct __rpc_sockinfo si;
287         
288         if (!__rpc_nconf2sockinfo(nconf, &si))
289                 return NULL;
290         return __rpc_uaddr2taddr_af(si.si_af, uaddr);
291 }
292
293 char *
294 __rpc_taddr2uaddr_af(int af, const struct netbuf *nbuf)
295 {
296         char *ret;
297         struct sbuf sb;
298         struct sockaddr_in *sin;
299         struct sockaddr_un *sun;
300         char namebuf[INET_ADDRSTRLEN];
301 #ifdef INET6
302         struct sockaddr_in6 *sin6;
303         char namebuf6[INET6_ADDRSTRLEN];
304 #endif
305         u_int16_t port;
306
307         sbuf_new(&sb, NULL, 0, SBUF_AUTOEXTEND);
308
309         switch (af) {
310         case AF_INET:
311                 sin = nbuf->buf;
312                 if (inet_ntop(af, &sin->sin_addr, namebuf, sizeof namebuf)
313                     == NULL)
314                         return NULL;
315                 port = ntohs(sin->sin_port);
316                 if (sbuf_printf(&sb, "%s.%u.%u", namebuf,
317                         ((uint32_t)port) >> 8,
318                         port & 0xff) < 0)
319                         return NULL;
320                 break;
321 #ifdef INET6
322         case AF_INET6:
323                 sin6 = nbuf->buf;
324                 if (inet_ntop(af, &sin6->sin6_addr, namebuf6, sizeof namebuf6)
325                     == NULL)
326                         return NULL;
327                 port = ntohs(sin6->sin6_port);
328                 if (sbuf_printf(&sb, "%s.%u.%u", namebuf6,
329                         ((uint32_t)port) >> 8,
330                         port & 0xff) < 0)
331                         return NULL;
332                 break;
333 #endif
334         case AF_LOCAL:
335                 sun = nbuf->buf;
336                 if (sbuf_printf(&sb, "%.*s", (int)(sun->sun_len -
337                             offsetof(struct sockaddr_un, sun_path)),
338                         sun->sun_path) < 0)
339                         return (NULL);
340                 break;
341         default:
342                 return NULL;
343         }
344
345         sbuf_finish(&sb);
346         ret = strdup(sbuf_data(&sb), M_RPC);
347         sbuf_delete(&sb);
348
349         return ret;
350 }
351
352 struct netbuf *
353 __rpc_uaddr2taddr_af(int af, const char *uaddr)
354 {
355         struct netbuf *ret = NULL;
356         char *addrstr, *p;
357         unsigned port, portlo, porthi;
358         struct sockaddr_in *sin;
359 #ifdef INET6
360         struct sockaddr_in6 *sin6;
361 #endif
362         struct sockaddr_un *sun;
363
364         port = 0;
365         sin = NULL;
366         addrstr = strdup(uaddr, M_RPC);
367         if (addrstr == NULL)
368                 return NULL;
369
370         /*
371          * AF_LOCAL addresses are expected to be absolute
372          * pathnames, anything else will be AF_INET or AF_INET6.
373          */
374         if (*addrstr != '/') {
375                 p = strrchr(addrstr, '.');
376                 if (p == NULL)
377                         goto out;
378                 portlo = (unsigned)strtol(p + 1, NULL, 10);
379                 *p = '\0';
380
381                 p = strrchr(addrstr, '.');
382                 if (p == NULL)
383                         goto out;
384                 porthi = (unsigned)strtol(p + 1, NULL, 10);
385                 *p = '\0';
386                 port = (porthi << 8) | portlo;
387         }
388
389         ret = (struct netbuf *)malloc(sizeof *ret, M_RPC, M_WAITOK);
390         if (ret == NULL)
391                 goto out;
392         
393         switch (af) {
394         case AF_INET:
395                 sin = (struct sockaddr_in *)malloc(sizeof *sin, M_RPC,
396                     M_WAITOK);
397                 if (sin == NULL)
398                         goto out;
399                 memset(sin, 0, sizeof *sin);
400                 sin->sin_family = AF_INET;
401                 sin->sin_port = htons(port);
402                 if (inet_pton(AF_INET, addrstr, &sin->sin_addr) <= 0) {
403                         free(sin, M_RPC);
404                         free(ret, M_RPC);
405                         ret = NULL;
406                         goto out;
407                 }
408                 sin->sin_len = ret->maxlen = ret->len = sizeof *sin;
409                 ret->buf = sin;
410                 break;
411 #ifdef INET6
412         case AF_INET6:
413                 sin6 = (struct sockaddr_in6 *)malloc(sizeof *sin6, M_RPC,
414                     M_WAITOK);
415                 if (sin6 == NULL)
416                         goto out;
417                 memset(sin6, 0, sizeof *sin6);
418                 sin6->sin6_family = AF_INET6;
419                 sin6->sin6_port = htons(port);
420                 if (inet_pton(AF_INET6, addrstr, &sin6->sin6_addr) <= 0) {
421                         free(sin6, M_RPC);
422                         free(ret, M_RPC);
423                         ret = NULL;
424                         goto out;
425                 }
426                 sin6->sin6_len = ret->maxlen = ret->len = sizeof *sin6;
427                 ret->buf = sin6;
428                 break;
429 #endif
430         case AF_LOCAL:
431                 sun = (struct sockaddr_un *)malloc(sizeof *sun, M_RPC,
432                     M_WAITOK);
433                 if (sun == NULL)
434                         goto out;
435                 memset(sun, 0, sizeof *sun);
436                 sun->sun_family = AF_LOCAL;
437                 strncpy(sun->sun_path, addrstr, sizeof(sun->sun_path) - 1);
438                 ret->len = ret->maxlen = sun->sun_len = SUN_LEN(sun);
439                 ret->buf = sun;
440                 break;
441         default:
442                 break;
443         }
444 out:
445         free(addrstr, M_RPC);
446         return ret;
447 }
448
449 int
450 __rpc_seman2socktype(int semantics)
451 {
452         switch (semantics) {
453         case NC_TPI_CLTS:
454                 return SOCK_DGRAM;
455         case NC_TPI_COTS_ORD:
456                 return SOCK_STREAM;
457         case NC_TPI_RAW:
458                 return SOCK_RAW;
459         default:
460                 break;
461         }
462
463         return -1;
464 }
465
466 int
467 __rpc_socktype2seman(int socktype)
468 {
469         switch (socktype) {
470         case SOCK_DGRAM:
471                 return NC_TPI_CLTS;
472         case SOCK_STREAM:
473                 return NC_TPI_COTS_ORD;
474         case SOCK_RAW:
475                 return NC_TPI_RAW;
476         default:
477                 break;
478         }
479
480         return -1;
481 }
482
483 /*
484  * Returns the type of the network as defined in <rpc/nettype.h>
485  * If nettype is NULL, it defaults to NETPATH.
486  */
487 static int
488 getnettype(const char *nettype)
489 {
490         int i;
491
492         if ((nettype == NULL) || (nettype[0] == 0)) {
493                 return (_RPC_NETPATH);  /* Default */
494         }
495
496 #if 0
497         nettype = strlocase(nettype);
498 #endif
499         for (i = 0; _rpctypelist[i].name; i++)
500                 if (strcasecmp(nettype, _rpctypelist[i].name) == 0) {
501                         return (_rpctypelist[i].type);
502                 }
503         return (_rpctypelist[i].type);
504 }
505
506 /*
507  * For the given nettype (tcp or udp only), return the first structure found.
508  * This should be freed by calling freenetconfigent()
509  */
510 struct netconfig *
511 __rpc_getconfip(const char *nettype)
512 {
513         char *netid;
514         static char *netid_tcp = (char *) NULL;
515         static char *netid_udp = (char *) NULL;
516         struct netconfig *dummy;
517
518         if (!netid_udp && !netid_tcp) {
519                 struct netconfig *nconf;
520                 void *confighandle;
521
522                 if (!(confighandle = setnetconfig())) {
523                         log(LOG_ERR, "rpc: failed to open " NETCONFIG);
524                         return (NULL);
525                 }
526                 while ((nconf = getnetconfig(confighandle)) != NULL) {
527                         if (strcmp(nconf->nc_protofmly, NC_INET) == 0) {
528                                 if (strcmp(nconf->nc_proto, NC_TCP) == 0) {
529                                         netid_tcp = strdup(nconf->nc_netid,
530                                             M_RPC);
531                                 } else
532                                 if (strcmp(nconf->nc_proto, NC_UDP) == 0) {
533                                         netid_udp = strdup(nconf->nc_netid,
534                                             M_RPC);
535                                 }
536                         }
537                 }
538                 endnetconfig(confighandle);
539         }
540         if (strcmp(nettype, "udp") == 0)
541                 netid = netid_udp;
542         else if (strcmp(nettype, "tcp") == 0)
543                 netid = netid_tcp;
544         else {
545                 return (NULL);
546         }
547         if ((netid == NULL) || (netid[0] == 0)) {
548                 return (NULL);
549         }
550         dummy = getnetconfigent(netid);
551         return (dummy);
552 }
553
554 /*
555  * Returns the type of the nettype, which should then be used with
556  * __rpc_getconf().
557  *
558  * For simplicity in the kernel, we don't support the NETPATH
559  * environment variable. We behave as userland would then NETPATH is
560  * unset, i.e. iterate over all visible entries in netconfig.
561  */
562 void *
563 __rpc_setconf(nettype)
564         const char *nettype;
565 {
566         struct handle *handle;
567
568         handle = (struct handle *) malloc(sizeof (struct handle),
569             M_RPC, M_WAITOK);
570         switch (handle->nettype = getnettype(nettype)) {
571         case _RPC_NETPATH:
572         case _RPC_CIRCUIT_N:
573         case _RPC_DATAGRAM_N:
574                 if (!(handle->nhandle = setnetconfig()))
575                         goto failed;
576                 handle->nflag = TRUE;
577                 break;
578         case _RPC_VISIBLE:
579         case _RPC_CIRCUIT_V:
580         case _RPC_DATAGRAM_V:
581         case _RPC_TCP:
582         case _RPC_UDP:
583                 if (!(handle->nhandle = setnetconfig())) {
584                         log(LOG_ERR, "rpc: failed to open " NETCONFIG);
585                         goto failed;
586                 }
587                 handle->nflag = FALSE;
588                 break;
589         default:
590                 goto failed;
591         }
592
593         return (handle);
594
595 failed:
596         free(handle, M_RPC);
597         return (NULL);
598 }
599
600 /*
601  * Returns the next netconfig struct for the given "net" type.
602  * __rpc_setconf() should have been called previously.
603  */
604 struct netconfig *
605 __rpc_getconf(void *vhandle)
606 {
607         struct handle *handle;
608         struct netconfig *nconf;
609
610         handle = (struct handle *)vhandle;
611         if (handle == NULL) {
612                 return (NULL);
613         }
614         for (;;) {
615                 if (handle->nflag) {
616                         nconf = getnetconfig(handle->nhandle);
617                         if (nconf && !(nconf->nc_flag & NC_VISIBLE))
618                                 continue;
619                 } else {
620                         nconf = getnetconfig(handle->nhandle);
621                 }
622                 if (nconf == NULL)
623                         break;
624                 if ((nconf->nc_semantics != NC_TPI_CLTS) &&
625                         (nconf->nc_semantics != NC_TPI_COTS) &&
626                         (nconf->nc_semantics != NC_TPI_COTS_ORD))
627                         continue;
628                 switch (handle->nettype) {
629                 case _RPC_VISIBLE:
630                         if (!(nconf->nc_flag & NC_VISIBLE))
631                                 continue;
632                         /* FALLTHROUGH */
633                 case _RPC_NETPATH:      /* Be happy */
634                         break;
635                 case _RPC_CIRCUIT_V:
636                         if (!(nconf->nc_flag & NC_VISIBLE))
637                                 continue;
638                         /* FALLTHROUGH */
639                 case _RPC_CIRCUIT_N:
640                         if ((nconf->nc_semantics != NC_TPI_COTS) &&
641                                 (nconf->nc_semantics != NC_TPI_COTS_ORD))
642                                 continue;
643                         break;
644                 case _RPC_DATAGRAM_V:
645                         if (!(nconf->nc_flag & NC_VISIBLE))
646                                 continue;
647                         /* FALLTHROUGH */
648                 case _RPC_DATAGRAM_N:
649                         if (nconf->nc_semantics != NC_TPI_CLTS)
650                                 continue;
651                         break;
652                 case _RPC_TCP:
653                         if (((nconf->nc_semantics != NC_TPI_COTS) &&
654                                 (nconf->nc_semantics != NC_TPI_COTS_ORD)) ||
655                                 (strcmp(nconf->nc_protofmly, NC_INET)
656 #ifdef INET6
657                                  && strcmp(nconf->nc_protofmly, NC_INET6))
658 #else
659                                 )
660 #endif
661                                 ||
662                                 strcmp(nconf->nc_proto, NC_TCP))
663                                 continue;
664                         break;
665                 case _RPC_UDP:
666                         if ((nconf->nc_semantics != NC_TPI_CLTS) ||
667                                 (strcmp(nconf->nc_protofmly, NC_INET)
668 #ifdef INET6
669                                 && strcmp(nconf->nc_protofmly, NC_INET6))
670 #else
671                                 )
672 #endif
673                                 ||
674                                 strcmp(nconf->nc_proto, NC_UDP))
675                                 continue;
676                         break;
677                 }
678                 break;
679         }
680         return (nconf);
681 }
682
683 void
684 __rpc_endconf(vhandle)
685         void * vhandle;
686 {
687         struct handle *handle;
688
689         handle = (struct handle *) vhandle;
690         if (handle == NULL) {
691                 return;
692         }
693         endnetconfig(handle->nhandle);
694         free(handle, M_RPC);
695 }
696
697 int
698 __rpc_sockisbound(struct socket *so)
699 {
700         struct sockaddr *sa;
701         int error, bound;
702
703         error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa);
704         if (error)
705                 return (0);
706
707         switch (sa->sa_family) {
708                 case AF_INET:
709                         bound = (((struct sockaddr_in *) sa)->sin_port != 0);
710                         break;
711 #ifdef INET6
712                 case AF_INET6:
713                         bound = (((struct sockaddr_in6 *) sa)->sin6_port != 0);
714                         break;
715 #endif
716                 case AF_LOCAL:
717                         /* XXX check this */
718                         bound = (((struct sockaddr_un *) sa)->sun_path[0] != '\0');
719                         break;
720                 default:
721                         bound = FALSE;
722                         break;
723         }
724
725         free(sa, M_SONAME);
726
727         return bound;
728 }
729
730 /*
731  * Implement XDR-style API for RPC call.
732  */
733 enum clnt_stat
734 clnt_call_private(
735         CLIENT          *cl,            /* client handle */
736         struct rpc_callextra *ext,      /* call metadata */
737         rpcproc_t       proc,           /* procedure number */
738         xdrproc_t       xargs,          /* xdr routine for args */
739         void            *argsp,         /* pointer to args */
740         xdrproc_t       xresults,       /* xdr routine for results */
741         void            *resultsp,      /* pointer to results */
742         struct timeval  utimeout)       /* seconds to wait before giving up */
743 {
744         XDR xdrs;
745         struct mbuf *mreq;
746         struct mbuf *mrep;
747         enum clnt_stat stat;
748
749         MGET(mreq, M_WAIT, MT_DATA);
750         MCLGET(mreq, M_WAIT);
751         mreq->m_len = 0;
752
753         xdrmbuf_create(&xdrs, mreq, XDR_ENCODE);
754         if (!xargs(&xdrs, argsp)) {
755                 m_freem(mreq);
756                 return (RPC_CANTENCODEARGS);
757         }
758         XDR_DESTROY(&xdrs);
759
760         stat = CLNT_CALL_MBUF(cl, ext, proc, mreq, &mrep, utimeout);
761         m_freem(mreq);
762
763         if (stat == RPC_SUCCESS) {
764                 xdrmbuf_create(&xdrs, mrep, XDR_DECODE);
765                 if (!xresults(&xdrs, resultsp)) {
766                         XDR_DESTROY(&xdrs);
767                         return (RPC_CANTDECODERES);
768                 }
769                 XDR_DESTROY(&xdrs);
770         }
771
772         return (stat);
773 }
774
775 /*
776  * Bind a socket to a privileged IP port
777  */
778 int
779 bindresvport(struct socket *so, struct sockaddr *sa)
780 {
781         int old, error, af;
782         bool_t freesa = FALSE;
783         struct sockaddr_in *sin;
784 #ifdef INET6
785         struct sockaddr_in6 *sin6;
786 #endif
787         struct sockopt opt;
788         int proto, portrange, portlow;
789         u_int16_t *portp;
790         socklen_t salen;
791
792         if (sa == NULL) {
793                 error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa);
794                 if (error)
795                         return (error);
796                 freesa = TRUE;
797                 af = sa->sa_family;
798                 salen = sa->sa_len;
799                 memset(sa, 0, sa->sa_len);
800         } else {
801                 af = sa->sa_family;
802                 salen = sa->sa_len;
803         }
804
805         switch (af) {
806         case AF_INET:
807                 proto = IPPROTO_IP;
808                 portrange = IP_PORTRANGE;
809                 portlow = IP_PORTRANGE_LOW;
810                 sin = (struct sockaddr_in *)sa;
811                 portp = &sin->sin_port;
812                 break;
813 #ifdef INET6
814         case AF_INET6:
815                 proto = IPPROTO_IPV6;
816                 portrange = IPV6_PORTRANGE;
817                 portlow = IPV6_PORTRANGE_LOW;
818                 sin6 = (struct sockaddr_in6 *)sa;
819                 portp = &sin6->sin6_port;
820                 break;
821 #endif
822         default:
823                 return (EPFNOSUPPORT);
824         }
825
826         sa->sa_family = af;
827         sa->sa_len = salen;
828
829         if (*portp == 0) {
830                 bzero(&opt, sizeof(opt));
831                 opt.sopt_dir = SOPT_GET;
832                 opt.sopt_level = proto;
833                 opt.sopt_name = portrange;
834                 opt.sopt_val = &old;
835                 opt.sopt_valsize = sizeof(old);
836                 error = sogetopt(so, &opt);
837                 if (error) {
838                         goto out;
839                 }
840
841                 opt.sopt_dir = SOPT_SET;
842                 opt.sopt_val = &portlow;
843                 error = sosetopt(so, &opt);
844                 if (error)
845                         goto out;
846         }
847
848         error = sobind(so, sa, curthread);
849
850         if (*portp == 0) {
851                 if (error) {
852                         opt.sopt_dir = SOPT_SET;
853                         opt.sopt_val = &old;
854                         sosetopt(so, &opt);
855                 }
856         }
857 out:
858         if (freesa)
859                 free(sa, M_SONAME);
860
861         return (error);
862 }
863
864 /*
865  * Kernel module glue
866  */
867 static int
868 krpc_modevent(module_t mod, int type, void *data)
869 {
870
871         return (0);
872 }
873 static moduledata_t krpc_mod = {
874         "krpc",
875         krpc_modevent,
876         NULL,
877 };
878 DECLARE_MODULE(krpc, krpc_mod, SI_SUB_VFS, SI_ORDER_ANY);
879
880 /* So that loader and kldload(2) can find us, wherever we are.. */
881 MODULE_VERSION(krpc, 1);