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