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