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