]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/rpc/rpc_generic.c
amd64: use register macros for gdb_cpu_getreg()
[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  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  * Copyright (c) 2009, Sun Microsystems, Inc.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without 
10  * modification, are permitted provided that the following conditions are met:
11  * - Redistributions of source code must retain the above copyright notice, 
12  *   this list of conditions and the following disclaimer.
13  * - Redistributions in binary form must reproduce the above copyright notice, 
14  *   this list of conditions and the following disclaimer in the documentation 
15  *   and/or other materials provided with the distribution.
16  * - Neither the name of Sun Microsystems, Inc. nor the names of its 
17  *   contributors may be used to endorse or promote products derived 
18  *   from this software without specific prior written permission.
19  * 
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
23  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 
24  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 /*
33  * Copyright (c) 1986-1991 by Sun Microsystems Inc. 
34  */
35
36 /* #pragma ident        "@(#)rpc_generic.c      1.17    94/04/24 SMI" */
37 #include <sys/cdefs.h>
38 __FBSDID("$FreeBSD$");
39
40 /*
41  * rpc_generic.c, Miscl routines for RPC.
42  *
43  */
44
45 #include "opt_inet6.h"
46
47 #include <sys/param.h>
48 #include <sys/kernel.h>
49 #include <sys/malloc.h>
50 #include <sys/mbuf.h>
51 #include <sys/module.h>
52 #include <sys/proc.h>
53 #include <sys/protosw.h>
54 #include <sys/sbuf.h>
55 #include <sys/systm.h>
56 #include <sys/socket.h>
57 #include <sys/socketvar.h>
58 #include <sys/syslog.h>
59
60 #include <net/vnet.h>
61
62 #include <rpc/rpc.h>
63 #include <rpc/nettype.h>
64 #include <rpc/rpcsec_gss.h>
65 #include <rpc/rpcsec_tls.h>
66
67 #include <rpc/rpc_com.h>
68 #include <rpc/krpc.h>
69
70 #include <vm/vm.h>
71 #include <vm/pmap.h>
72 #include <vm/vm_param.h>
73
74 extern  u_long sb_max_adj;      /* not defined in socketvar.h */
75
76 /* Provide an entry point hook for the rpcsec_gss module. */
77 struct rpc_gss_entries  rpc_gss_entries;
78
79 struct handle {
80         NCONF_HANDLE *nhandle;
81         int nflag;              /* Whether NETPATH or NETCONFIG */
82         int nettype;
83 };
84
85 static const struct _rpcnettype {
86         const char *name;
87         const int type;
88 } _rpctypelist[] = {
89         { "netpath", _RPC_NETPATH },
90         { "visible", _RPC_VISIBLE },
91         { "circuit_v", _RPC_CIRCUIT_V },
92         { "datagram_v", _RPC_DATAGRAM_V },
93         { "circuit_n", _RPC_CIRCUIT_N },
94         { "datagram_n", _RPC_DATAGRAM_N },
95         { "tcp", _RPC_TCP },
96         { "udp", _RPC_UDP },
97         { 0, _RPC_NONE }
98 };
99
100 struct netid_af {
101         const char      *netid;
102         int             af;
103         int             protocol;
104 };
105
106 static const struct netid_af na_cvt[] = {
107         { "udp",  AF_INET,  IPPROTO_UDP },
108         { "tcp",  AF_INET,  IPPROTO_TCP },
109 #ifdef INET6
110         { "udp6", AF_INET6, IPPROTO_UDP },
111         { "tcp6", AF_INET6, IPPROTO_TCP },
112 #endif
113         { "local", AF_LOCAL, 0 }
114 };
115
116 struct rpc_createerr rpc_createerr;
117
118 /*
119  * Find the appropriate buffer size
120  */
121 u_int
122 /*ARGSUSED*/
123 __rpc_get_t_size(int af, int proto, int size)
124 {
125         int defsize;
126
127         switch (proto) {
128         case IPPROTO_TCP:
129                 defsize = 64 * 1024;    /* XXX */
130                 break;
131         case IPPROTO_UDP:
132                 defsize = UDPMSGSIZE;
133                 break;
134         default:
135                 defsize = RPC_MAXDATASIZE;
136                 break;
137         }
138         if (size == 0)
139                 return defsize;
140
141         /* Check whether the value is within the upper max limit */
142         return (size > sb_max_adj ? (u_int)sb_max_adj : (u_int)size);
143 }
144
145 /*
146  * Find the appropriate address buffer size
147  */
148 u_int
149 __rpc_get_a_size(af)
150         int af;
151 {
152         switch (af) {
153         case AF_INET:
154                 return sizeof (struct sockaddr_in);
155 #ifdef INET6
156         case AF_INET6:
157                 return sizeof (struct sockaddr_in6);
158 #endif
159         case AF_LOCAL:
160                 return sizeof (struct sockaddr_un);
161         default:
162                 break;
163         }
164         return ((u_int)RPC_MAXADDRSIZE);
165 }
166
167 #if 0
168
169 /*
170  * Used to ping the NULL procedure for clnt handle.
171  * Returns NULL if fails, else a non-NULL pointer.
172  */
173 void *
174 rpc_nullproc(clnt)
175         CLIENT *clnt;
176 {
177         struct timeval TIMEOUT = {25, 0};
178
179         if (clnt_call(clnt, NULLPROC, (xdrproc_t) xdr_void, NULL,
180                 (xdrproc_t) xdr_void, NULL, TIMEOUT) != RPC_SUCCESS) {
181                 return (NULL);
182         }
183         return ((void *) clnt);
184 }
185
186 #endif
187
188 int
189 __rpc_socket2sockinfo(struct socket *so, struct __rpc_sockinfo *sip)
190 {
191         int type, proto;
192         struct sockaddr *sa;
193         sa_family_t family;
194         struct sockopt opt;
195         int error;
196
197         CURVNET_SET(so->so_vnet);
198         error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa);
199         CURVNET_RESTORE();
200         if (error)
201                 return 0;
202
203         sip->si_alen = sa->sa_len;
204         family = sa->sa_family;
205         free(sa, M_SONAME);
206
207         opt.sopt_dir = SOPT_GET;
208         opt.sopt_level = SOL_SOCKET;
209         opt.sopt_name = SO_TYPE;
210         opt.sopt_val = &type;
211         opt.sopt_valsize = sizeof type;
212         opt.sopt_td = NULL;
213         error = sogetopt(so, &opt);
214         if (error)
215                 return 0;
216
217         /* XXX */
218         if (family != AF_LOCAL) {
219                 if (type == SOCK_STREAM)
220                         proto = IPPROTO_TCP;
221                 else if (type == SOCK_DGRAM)
222                         proto = IPPROTO_UDP;
223                 else
224                         return 0;
225         } else
226                 proto = 0;
227
228         sip->si_af = family;
229         sip->si_proto = proto;
230         sip->si_socktype = type;
231
232         return 1;
233 }
234
235 /*
236  * Linear search, but the number of entries is small.
237  */
238 int
239 __rpc_nconf2sockinfo(const struct netconfig *nconf, struct __rpc_sockinfo *sip)
240 {
241         int i;
242
243         for (i = 0; i < (sizeof na_cvt) / (sizeof (struct netid_af)); i++)
244                 if (strcmp(na_cvt[i].netid, nconf->nc_netid) == 0 || (
245                     strcmp(nconf->nc_netid, "unix") == 0 &&
246                     strcmp(na_cvt[i].netid, "local") == 0)) {
247                         sip->si_af = na_cvt[i].af;
248                         sip->si_proto = na_cvt[i].protocol;
249                         sip->si_socktype =
250                             __rpc_seman2socktype((int)nconf->nc_semantics);
251                         if (sip->si_socktype == -1)
252                                 return 0;
253                         sip->si_alen = __rpc_get_a_size(sip->si_af);
254                         return 1;
255                 }
256
257         return 0;
258 }
259
260 struct socket *
261 __rpc_nconf2socket(const struct netconfig *nconf)
262 {
263         struct __rpc_sockinfo si;
264         struct socket *so;
265         int error;
266
267         if (!__rpc_nconf2sockinfo(nconf, &si))
268                 return 0;
269
270         so = NULL;
271         error =  socreate(si.si_af, &so, si.si_socktype, si.si_proto,
272             curthread->td_ucred, curthread);
273
274         if (error)
275                 return NULL;
276         else
277                 return so;
278 }
279
280 char *
281 taddr2uaddr(const struct netconfig *nconf, const struct netbuf *nbuf)
282 {
283         struct __rpc_sockinfo si;
284
285         if (!__rpc_nconf2sockinfo(nconf, &si))
286                 return NULL;
287         return __rpc_taddr2uaddr_af(si.si_af, nbuf);
288 }
289
290 struct netbuf *
291 uaddr2taddr(const struct netconfig *nconf, const char *uaddr)
292 {
293         struct __rpc_sockinfo si;
294         
295         if (!__rpc_nconf2sockinfo(nconf, &si))
296                 return NULL;
297         return __rpc_uaddr2taddr_af(si.si_af, uaddr);
298 }
299
300 char *
301 __rpc_taddr2uaddr_af(int af, const struct netbuf *nbuf)
302 {
303         char *ret;
304         struct sbuf sb;
305         struct sockaddr_in *sin;
306         struct sockaddr_un *sun;
307         char namebuf[INET_ADDRSTRLEN];
308 #ifdef INET6
309         struct sockaddr_in6 *sin6;
310         char namebuf6[INET6_ADDRSTRLEN];
311 #endif
312         u_int16_t port;
313
314         sbuf_new(&sb, NULL, 0, SBUF_AUTOEXTEND);
315
316         switch (af) {
317         case AF_INET:
318                 if (nbuf->len < sizeof(*sin))
319                         return NULL;
320                 sin = nbuf->buf;
321                 if (inet_ntop(af, &sin->sin_addr, namebuf, sizeof namebuf)
322                     == NULL)
323                         return NULL;
324                 port = ntohs(sin->sin_port);
325                 if (sbuf_printf(&sb, "%s.%u.%u", namebuf,
326                         ((uint32_t)port) >> 8,
327                         port & 0xff) < 0)
328                         return NULL;
329                 break;
330 #ifdef INET6
331         case AF_INET6:
332                 if (nbuf->len < sizeof(*sin6))
333                         return NULL;
334                 sin6 = nbuf->buf;
335                 if (inet_ntop(af, &sin6->sin6_addr, namebuf6, sizeof namebuf6)
336                     == NULL)
337                         return NULL;
338                 port = ntohs(sin6->sin6_port);
339                 if (sbuf_printf(&sb, "%s.%u.%u", namebuf6,
340                         ((uint32_t)port) >> 8,
341                         port & 0xff) < 0)
342                         return NULL;
343                 break;
344 #endif
345         case AF_LOCAL:
346                 sun = nbuf->buf;
347                 if (sbuf_printf(&sb, "%.*s", (int)(sun->sun_len -
348                             offsetof(struct sockaddr_un, sun_path)),
349                         sun->sun_path) < 0)
350                         return (NULL);
351                 break;
352         default:
353                 return NULL;
354         }
355
356         sbuf_finish(&sb);
357         ret = strdup(sbuf_data(&sb), M_RPC);
358         sbuf_delete(&sb);
359
360         return ret;
361 }
362
363 struct netbuf *
364 __rpc_uaddr2taddr_af(int af, const char *uaddr)
365 {
366         struct netbuf *ret = NULL;
367         char *addrstr, *p;
368         unsigned port, portlo, porthi;
369         struct sockaddr_in *sin;
370 #ifdef INET6
371         struct sockaddr_in6 *sin6;
372 #endif
373         struct sockaddr_un *sun;
374
375         port = 0;
376         sin = NULL;
377
378         if (uaddr == NULL)
379                 return NULL;
380
381         addrstr = strdup(uaddr, M_RPC);
382         if (addrstr == NULL)
383                 return NULL;
384
385         /*
386          * AF_LOCAL addresses are expected to be absolute
387          * pathnames, anything else will be AF_INET or AF_INET6.
388          */
389         if (*addrstr != '/') {
390                 p = strrchr(addrstr, '.');
391                 if (p == NULL)
392                         goto out;
393                 portlo = (unsigned)strtol(p + 1, NULL, 10);
394                 *p = '\0';
395
396                 p = strrchr(addrstr, '.');
397                 if (p == NULL)
398                         goto out;
399                 porthi = (unsigned)strtol(p + 1, NULL, 10);
400                 *p = '\0';
401                 port = (porthi << 8) | portlo;
402         }
403
404         ret = (struct netbuf *)malloc(sizeof *ret, M_RPC, M_WAITOK);
405         
406         switch (af) {
407         case AF_INET:
408                 sin = (struct sockaddr_in *)malloc(sizeof *sin, M_RPC,
409                     M_WAITOK);
410                 memset(sin, 0, sizeof *sin);
411                 sin->sin_family = AF_INET;
412                 sin->sin_port = htons(port);
413                 if (inet_pton(AF_INET, addrstr, &sin->sin_addr) <= 0) {
414                         free(sin, M_RPC);
415                         free(ret, M_RPC);
416                         ret = NULL;
417                         goto out;
418                 }
419                 sin->sin_len = ret->maxlen = ret->len = sizeof *sin;
420                 ret->buf = sin;
421                 break;
422 #ifdef INET6
423         case AF_INET6:
424                 sin6 = (struct sockaddr_in6 *)malloc(sizeof *sin6, M_RPC,
425                     M_WAITOK);
426                 memset(sin6, 0, sizeof *sin6);
427                 sin6->sin6_family = AF_INET6;
428                 sin6->sin6_port = htons(port);
429                 if (inet_pton(AF_INET6, addrstr, &sin6->sin6_addr) <= 0) {
430                         free(sin6, M_RPC);
431                         free(ret, M_RPC);
432                         ret = NULL;
433                         goto out;
434                 }
435                 sin6->sin6_len = ret->maxlen = ret->len = sizeof *sin6;
436                 ret->buf = sin6;
437                 break;
438 #endif
439         case AF_LOCAL:
440                 sun = (struct sockaddr_un *)malloc(sizeof *sun, M_RPC,
441                     M_WAITOK);
442                 memset(sun, 0, sizeof *sun);
443                 sun->sun_family = AF_LOCAL;
444                 strncpy(sun->sun_path, addrstr, sizeof(sun->sun_path) - 1);
445                 ret->len = ret->maxlen = sun->sun_len = SUN_LEN(sun);
446                 ret->buf = sun;
447                 break;
448         default:
449                 break;
450         }
451 out:
452         free(addrstr, M_RPC);
453         return ret;
454 }
455
456 int
457 __rpc_seman2socktype(int semantics)
458 {
459         switch (semantics) {
460         case NC_TPI_CLTS:
461                 return SOCK_DGRAM;
462         case NC_TPI_COTS_ORD:
463                 return SOCK_STREAM;
464         case NC_TPI_RAW:
465                 return SOCK_RAW;
466         default:
467                 break;
468         }
469
470         return -1;
471 }
472
473 int
474 __rpc_socktype2seman(int socktype)
475 {
476         switch (socktype) {
477         case SOCK_DGRAM:
478                 return NC_TPI_CLTS;
479         case SOCK_STREAM:
480                 return NC_TPI_COTS_ORD;
481         case SOCK_RAW:
482                 return NC_TPI_RAW;
483         default:
484                 break;
485         }
486
487         return -1;
488 }
489
490 /*
491  * Returns the type of the network as defined in <rpc/nettype.h>
492  * If nettype is NULL, it defaults to NETPATH.
493  */
494 static int
495 getnettype(const char *nettype)
496 {
497         int i;
498
499         if ((nettype == NULL) || (nettype[0] == 0)) {
500                 return (_RPC_NETPATH);  /* Default */
501         }
502
503 #if 0
504         nettype = strlocase(nettype);
505 #endif
506         for (i = 0; _rpctypelist[i].name; i++)
507                 if (strcasecmp(nettype, _rpctypelist[i].name) == 0) {
508                         return (_rpctypelist[i].type);
509                 }
510         return (_rpctypelist[i].type);
511 }
512
513 /*
514  * For the given nettype (tcp or udp only), return the first structure found.
515  * This should be freed by calling freenetconfigent()
516  */
517 struct netconfig *
518 __rpc_getconfip(const char *nettype)
519 {
520         char *netid;
521         static char *netid_tcp = (char *) NULL;
522         static char *netid_udp = (char *) NULL;
523         struct netconfig *dummy;
524
525         if (!netid_udp && !netid_tcp) {
526                 struct netconfig *nconf;
527                 void *confighandle;
528
529                 if (!(confighandle = setnetconfig())) {
530                         log(LOG_ERR, "rpc: failed to open " NETCONFIG);
531                         return (NULL);
532                 }
533                 while ((nconf = getnetconfig(confighandle)) != NULL) {
534                         if (strcmp(nconf->nc_protofmly, NC_INET) == 0) {
535                                 if (strcmp(nconf->nc_proto, NC_TCP) == 0) {
536                                         netid_tcp = strdup(nconf->nc_netid,
537                                             M_RPC);
538                                 } else
539                                 if (strcmp(nconf->nc_proto, NC_UDP) == 0) {
540                                         netid_udp = strdup(nconf->nc_netid,
541                                             M_RPC);
542                                 }
543                         }
544                 }
545                 endnetconfig(confighandle);
546         }
547         if (strcmp(nettype, "udp") == 0)
548                 netid = netid_udp;
549         else if (strcmp(nettype, "tcp") == 0)
550                 netid = netid_tcp;
551         else {
552                 return (NULL);
553         }
554         if ((netid == NULL) || (netid[0] == 0)) {
555                 return (NULL);
556         }
557         dummy = getnetconfigent(netid);
558         return (dummy);
559 }
560
561 /*
562  * Returns the type of the nettype, which should then be used with
563  * __rpc_getconf().
564  *
565  * For simplicity in the kernel, we don't support the NETPATH
566  * environment variable. We behave as userland would then NETPATH is
567  * unset, i.e. iterate over all visible entries in netconfig.
568  */
569 void *
570 __rpc_setconf(nettype)
571         const char *nettype;
572 {
573         struct handle *handle;
574
575         handle = (struct handle *) malloc(sizeof (struct handle),
576             M_RPC, M_WAITOK);
577         switch (handle->nettype = getnettype(nettype)) {
578         case _RPC_NETPATH:
579         case _RPC_CIRCUIT_N:
580         case _RPC_DATAGRAM_N:
581                 if (!(handle->nhandle = setnetconfig()))
582                         goto failed;
583                 handle->nflag = TRUE;
584                 break;
585         case _RPC_VISIBLE:
586         case _RPC_CIRCUIT_V:
587         case _RPC_DATAGRAM_V:
588         case _RPC_TCP:
589         case _RPC_UDP:
590                 if (!(handle->nhandle = setnetconfig())) {
591                         log(LOG_ERR, "rpc: failed to open " NETCONFIG);
592                         goto failed;
593                 }
594                 handle->nflag = FALSE;
595                 break;
596         default:
597                 goto failed;
598         }
599
600         return (handle);
601
602 failed:
603         free(handle, M_RPC);
604         return (NULL);
605 }
606
607 /*
608  * Returns the next netconfig struct for the given "net" type.
609  * __rpc_setconf() should have been called previously.
610  */
611 struct netconfig *
612 __rpc_getconf(void *vhandle)
613 {
614         struct handle *handle;
615         struct netconfig *nconf;
616
617         handle = (struct handle *)vhandle;
618         if (handle == NULL) {
619                 return (NULL);
620         }
621         for (;;) {
622                 if (handle->nflag) {
623                         nconf = getnetconfig(handle->nhandle);
624                         if (nconf && !(nconf->nc_flag & NC_VISIBLE))
625                                 continue;
626                 } else {
627                         nconf = getnetconfig(handle->nhandle);
628                 }
629                 if (nconf == NULL)
630                         break;
631                 if ((nconf->nc_semantics != NC_TPI_CLTS) &&
632                         (nconf->nc_semantics != NC_TPI_COTS) &&
633                         (nconf->nc_semantics != NC_TPI_COTS_ORD))
634                         continue;
635                 switch (handle->nettype) {
636                 case _RPC_VISIBLE:
637                         if (!(nconf->nc_flag & NC_VISIBLE))
638                                 continue;
639                         /* FALLTHROUGH */
640                 case _RPC_NETPATH:      /* Be happy */
641                         break;
642                 case _RPC_CIRCUIT_V:
643                         if (!(nconf->nc_flag & NC_VISIBLE))
644                                 continue;
645                         /* FALLTHROUGH */
646                 case _RPC_CIRCUIT_N:
647                         if ((nconf->nc_semantics != NC_TPI_COTS) &&
648                                 (nconf->nc_semantics != NC_TPI_COTS_ORD))
649                                 continue;
650                         break;
651                 case _RPC_DATAGRAM_V:
652                         if (!(nconf->nc_flag & NC_VISIBLE))
653                                 continue;
654                         /* FALLTHROUGH */
655                 case _RPC_DATAGRAM_N:
656                         if (nconf->nc_semantics != NC_TPI_CLTS)
657                                 continue;
658                         break;
659                 case _RPC_TCP:
660                         if (((nconf->nc_semantics != NC_TPI_COTS) &&
661                                 (nconf->nc_semantics != NC_TPI_COTS_ORD)) ||
662                                 (strcmp(nconf->nc_protofmly, NC_INET)
663 #ifdef INET6
664                                  && strcmp(nconf->nc_protofmly, NC_INET6))
665 #else
666                                 )
667 #endif
668                                 ||
669                                 strcmp(nconf->nc_proto, NC_TCP))
670                                 continue;
671                         break;
672                 case _RPC_UDP:
673                         if ((nconf->nc_semantics != NC_TPI_CLTS) ||
674                                 (strcmp(nconf->nc_protofmly, NC_INET)
675 #ifdef INET6
676                                 && strcmp(nconf->nc_protofmly, NC_INET6))
677 #else
678                                 )
679 #endif
680                                 ||
681                                 strcmp(nconf->nc_proto, NC_UDP))
682                                 continue;
683                         break;
684                 }
685                 break;
686         }
687         return (nconf);
688 }
689
690 void
691 __rpc_endconf(vhandle)
692         void * vhandle;
693 {
694         struct handle *handle;
695
696         handle = (struct handle *) vhandle;
697         if (handle == NULL) {
698                 return;
699         }
700         endnetconfig(handle->nhandle);
701         free(handle, M_RPC);
702 }
703
704 int
705 __rpc_sockisbound(struct socket *so)
706 {
707         struct sockaddr *sa;
708         int error, bound;
709
710         CURVNET_SET(so->so_vnet);
711         error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa);
712         CURVNET_RESTORE();
713         if (error)
714                 return (0);
715
716         switch (sa->sa_family) {
717                 case AF_INET:
718                         bound = (((struct sockaddr_in *) sa)->sin_port != 0);
719                         break;
720 #ifdef INET6
721                 case AF_INET6:
722                         bound = (((struct sockaddr_in6 *) sa)->sin6_port != 0);
723                         break;
724 #endif
725                 case AF_LOCAL:
726                         /* XXX check this */
727                         bound = (((struct sockaddr_un *) sa)->sun_path[0] != '\0');
728                         break;
729                 default:
730                         bound = FALSE;
731                         break;
732         }
733
734         free(sa, M_SONAME);
735
736         return bound;
737 }
738
739 /*
740  * Implement XDR-style API for RPC call.
741  */
742 enum clnt_stat
743 clnt_call_private(
744         CLIENT          *cl,            /* client handle */
745         struct rpc_callextra *ext,      /* call metadata */
746         rpcproc_t       proc,           /* procedure number */
747         xdrproc_t       xargs,          /* xdr routine for args */
748         void            *argsp,         /* pointer to args */
749         xdrproc_t       xresults,       /* xdr routine for results */
750         void            *resultsp,      /* pointer to results */
751         struct timeval  utimeout)       /* seconds to wait before giving up */
752 {
753         XDR xdrs;
754         struct mbuf *mreq;
755         struct mbuf *mrep;
756         enum clnt_stat stat;
757
758         mreq = m_getcl(M_WAITOK, MT_DATA, 0);
759
760         xdrmbuf_create(&xdrs, mreq, XDR_ENCODE);
761         if (!xargs(&xdrs, argsp)) {
762                 m_freem(mreq);
763                 return (RPC_CANTENCODEARGS);
764         }
765         XDR_DESTROY(&xdrs);
766
767         stat = CLNT_CALL_MBUF(cl, ext, proc, mreq, &mrep, utimeout);
768         m_freem(mreq);
769
770         if (stat == RPC_SUCCESS) {
771                 xdrmbuf_create(&xdrs, mrep, XDR_DECODE);
772                 if (!xresults(&xdrs, resultsp)) {
773                         XDR_DESTROY(&xdrs);
774                         return (RPC_CANTDECODERES);
775                 }
776                 XDR_DESTROY(&xdrs);
777         }
778
779         return (stat);
780 }
781
782 /*
783  * Bind a socket to a privileged IP port
784  */
785 int
786 bindresvport(struct socket *so, struct sockaddr *sa)
787 {
788         int old, error, af;
789         bool_t freesa = FALSE;
790         struct sockaddr_in *sin;
791 #ifdef INET6
792         struct sockaddr_in6 *sin6;
793 #endif
794         struct sockopt opt;
795         int proto, portrange, portlow;
796         u_int16_t *portp;
797         socklen_t salen;
798
799         if (sa == NULL) {
800                 CURVNET_SET(so->so_vnet);
801                 error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa);
802                 CURVNET_RESTORE();
803                 if (error)
804                         return (error);
805                 freesa = TRUE;
806                 af = sa->sa_family;
807                 salen = sa->sa_len;
808                 memset(sa, 0, sa->sa_len);
809         } else {
810                 af = sa->sa_family;
811                 salen = sa->sa_len;
812         }
813
814         switch (af) {
815         case AF_INET:
816                 proto = IPPROTO_IP;
817                 portrange = IP_PORTRANGE;
818                 portlow = IP_PORTRANGE_LOW;
819                 sin = (struct sockaddr_in *)sa;
820                 portp = &sin->sin_port;
821                 break;
822 #ifdef INET6
823         case AF_INET6:
824                 proto = IPPROTO_IPV6;
825                 portrange = IPV6_PORTRANGE;
826                 portlow = IPV6_PORTRANGE_LOW;
827                 sin6 = (struct sockaddr_in6 *)sa;
828                 portp = &sin6->sin6_port;
829                 break;
830 #endif
831         default:
832                 return (EPFNOSUPPORT);
833         }
834
835         sa->sa_family = af;
836         sa->sa_len = salen;
837
838         if (*portp == 0) {
839                 bzero(&opt, sizeof(opt));
840                 opt.sopt_dir = SOPT_GET;
841                 opt.sopt_level = proto;
842                 opt.sopt_name = portrange;
843                 opt.sopt_val = &old;
844                 opt.sopt_valsize = sizeof(old);
845                 error = sogetopt(so, &opt);
846                 if (error) {
847                         goto out;
848                 }
849
850                 opt.sopt_dir = SOPT_SET;
851                 opt.sopt_val = &portlow;
852                 error = sosetopt(so, &opt);
853                 if (error)
854                         goto out;
855         }
856
857         error = sobind(so, sa, curthread);
858
859         if (*portp == 0) {
860                 if (error) {
861                         opt.sopt_dir = SOPT_SET;
862                         opt.sopt_val = &old;
863                         sosetopt(so, &opt);
864                 }
865         }
866 out:
867         if (freesa)
868                 free(sa, M_SONAME);
869
870         return (error);
871 }
872
873 /*
874  * Make sure an mbuf list is made up entirely of ext_pgs mbufs.
875  * This is needed for sosend() when KERN_TLS is being used.
876  * (There might also be a performance improvement for certain
877  *  network interfaces that handle ext_pgs mbufs efficiently.)
878  * It expects at least one non-ext_pgs mbuf followed by zero
879  * or more ext_pgs mbufs.  It does not handle the case where
880  * non-ext_pgs mbuf(s) follow ext_pgs ones.
881  * It also performs sanity checks on the resultant list.
882  * The "mp" argument list is consumed.
883  * The "maxextsiz" argument is the upper bound on the data
884  * size for each mbuf (usually 16K for KERN_TLS).
885  */
886 struct mbuf *
887 _rpc_copym_into_ext_pgs(struct mbuf *mp, int maxextsiz)
888 {
889         struct mbuf *m, *m2, *m3, *mhead;
890         int tlen;
891
892         KASSERT((mp->m_flags & (M_EXT | M_EXTPG)) !=
893             (M_EXT | M_EXTPG), ("_rpc_copym_into_ext_pgs:"
894             " first mbuf is an ext_pgs"));
895         /*
896          * Find the last non-ext_pgs mbuf and the total
897          * length of the non-ext_pgs mbuf(s).
898          * The first mbuf must always be a non-ext_pgs
899          * mbuf.
900          */
901         tlen = mp->m_len;
902         m2 = mp;
903         for (m = mp->m_next; m != NULL; m = m->m_next) {
904                 if ((m->m_flags & M_EXTPG) != 0)
905                         break;
906                 tlen += m->m_len;
907                 m2 = m;
908         }
909
910         /*
911          * Copy the non-ext_pgs mbuf(s) into an ext_pgs
912          * mbuf list.
913          */
914         m2->m_next = NULL;
915         mhead = mb_mapped_to_unmapped(mp, tlen, maxextsiz,
916             M_WAITOK, &m2);
917
918         /*
919          * Link the ext_pgs list onto the newly copied
920          * list and free up the non-ext_pgs mbuf(s).
921          */
922         m2->m_next = m;
923         m_freem(mp);
924
925         /*
926          * Sanity check the resultant mbuf list.  Check for and
927          * remove any 0 length mbufs in the list, since the
928          * KERN_TLS code does not expect any 0 length mbuf(s)
929          * in the list.
930          */
931         m3 = NULL;
932         m2 = mhead;
933         tlen = 0;
934         while (m2 != NULL) {
935                 KASSERT(m2->m_len >= 0, ("_rpc_copym_into_ext_pgs:"
936                     " negative m_len"));
937                 KASSERT((m2->m_flags & (M_EXT | M_EXTPG)) ==
938                     (M_EXT | M_EXTPG), ("_rpc_copym_into_ext_pgs:"
939                             " non-nomap mbuf in list"));
940                 if (m2->m_len == 0) {
941                         if (m3 != NULL)
942                                 m3->m_next = m2->m_next;
943                         else
944                                 m = m2->m_next;
945                         m2->m_next = NULL;
946                         m_free(m2);
947                         if (m3 != NULL)
948                                 m2 = m3->m_next;
949                         else
950                                 m2 = m;
951                 } else {
952                         MBUF_EXT_PGS_ASSERT_SANITY(m2);
953                         m3 = m2;
954                         tlen += m2->m_len;
955                         m2 = m2->m_next;
956                 }
957         }
958         return (mhead);
959 }
960
961 /*
962  * Kernel module glue
963  */
964 static int
965 krpc_modevent(module_t mod, int type, void *data)
966 {
967         int error = 0;
968
969         switch (type) {
970         case MOD_LOAD:
971                 error = rpctls_init();
972                 break;
973         case MOD_UNLOAD:
974                 /*
975                  * Cannot be unloaded, since the rpctlssd or rpctlscd daemons
976                  * might be performing a rpctls syscall.
977                  */
978                 /* FALLTHROUGH */
979         default:
980                 error = EOPNOTSUPP;
981         }
982         return (error);
983 }
984 static moduledata_t krpc_mod = {
985         "krpc",
986         krpc_modevent,
987         NULL,
988 };
989 DECLARE_MODULE(krpc, krpc_mod, SI_SUB_VFS, SI_ORDER_ANY);
990
991 /* So that loader and kldload(2) can find us, wherever we are.. */
992 MODULE_VERSION(krpc, 1);
993 MODULE_DEPEND(krpc, xdr, 1, 1, 1);