FreeBSD/Linux Kernel Cross Reference
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: releng/8.2/sys/rpc/rpc_generic.c 214415 2010-10-27 13:10:08Z rmacklem $");
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);
Cache object: 01c741ab95364b50f64a44c440c31f19
|