rpc_generic.c revision 213756
1215207Sgnn/*	$NetBSD: rpc_generic.c,v 1.4 2000/09/28 09:07:04 kleink Exp $	*/
2283927Sjhb
3215207Sgnn/*
4215207Sgnn * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
5215207Sgnn * unrestricted use provided that this legend is included on all tape
6215207Sgnn * media and as a part of the software program in whole or part.  Users
7215207Sgnn * may copy or modify Sun RPC without charge, but are not authorized
8215207Sgnn * to license or distribute it to anyone else except as part of a product or
9215207Sgnn * program developed by the user.
10215207Sgnn *
11215207Sgnn * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
12215207Sgnn * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
13215207Sgnn * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
14215207Sgnn *
15215207Sgnn * Sun RPC is provided with no support and without any obligation on the
16215207Sgnn * part of Sun Microsystems, Inc. to assist in its use, correction,
17215207Sgnn * modification or enhancement.
18215207Sgnn *
19215207Sgnn * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
20215207Sgnn * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
21215207Sgnn * OR ANY PART THEREOF.
22215207Sgnn *
23215207Sgnn * In no event will Sun Microsystems, Inc. be liable for any lost revenue
24215207Sgnn * or profits or other special, indirect and consequential damages, even if
25215207Sgnn * Sun has been advised of the possibility of such damages.
26215207Sgnn *
27215207Sgnn * Sun Microsystems, Inc.
28215207Sgnn * 2550 Garcia Avenue
29215207Sgnn * Mountain View, California  94043
30215207Sgnn */
31215207Sgnn/*
32215207Sgnn * Copyright (c) 1986-1991 by Sun Microsystems Inc.
33215207Sgnn */
34215207Sgnn
35215207Sgnn/* #pragma ident	"@(#)rpc_generic.c	1.17	94/04/24 SMI" */
36215207Sgnn#include <sys/cdefs.h>
37215207Sgnn__FBSDID("$FreeBSD: head/sys/rpc/rpc_generic.c 213756 2010-10-13 00:57:14Z rmacklem $");
38215207Sgnn
39215207Sgnn/*
40215207Sgnn * rpc_generic.c, Miscl routines for RPC.
41215207Sgnn *
42215207Sgnn */
43215207Sgnn
44215207Sgnn#include "opt_inet6.h"
45215207Sgnn
46215207Sgnn#include <sys/param.h>
47215207Sgnn#include <sys/kernel.h>
48215207Sgnn#include <sys/malloc.h>
49215207Sgnn#include <sys/mbuf.h>
50215207Sgnn#include <sys/module.h>
51215207Sgnn#include <sys/proc.h>
52215207Sgnn#include <sys/protosw.h>
53215207Sgnn#include <sys/sbuf.h>
54215207Sgnn#include <sys/systm.h>
55215207Sgnn#include <sys/socket.h>
56215207Sgnn#include <sys/socketvar.h>
57215207Sgnn#include <sys/syslog.h>
58215207Sgnn
59215207Sgnn#include <net/vnet.h>
60215207Sgnn
61215207Sgnn#include <rpc/rpc.h>
62215207Sgnn#include <rpc/nettype.h>
63215207Sgnn
64215207Sgnn#include <rpc/rpc_com.h>
65215207Sgnn
66215207Sgnnextern	u_long sb_max_adj;	/* not defined in socketvar.h */
67215207Sgnn
68215207Sgnn#if __FreeBSD_version < 700000
69215207Sgnn#define strrchr rindex
70215207Sgnn#endif
71215207Sgnn
72215207Sgnnstruct handle {
73215207Sgnn	NCONF_HANDLE *nhandle;
74215207Sgnn	int nflag;		/* Whether NETPATH or NETCONFIG */
75215207Sgnn	int nettype;
76215207Sgnn};
77215207Sgnn
78215207Sgnnstatic const struct _rpcnettype {
79215207Sgnn	const char *name;
80215207Sgnn	const int type;
81215207Sgnn} _rpctypelist[] = {
82215207Sgnn	{ "netpath", _RPC_NETPATH },
83215207Sgnn	{ "visible", _RPC_VISIBLE },
84215207Sgnn	{ "circuit_v", _RPC_CIRCUIT_V },
85215207Sgnn	{ "datagram_v", _RPC_DATAGRAM_V },
86215207Sgnn	{ "circuit_n", _RPC_CIRCUIT_N },
87215207Sgnn	{ "datagram_n", _RPC_DATAGRAM_N },
88215207Sgnn	{ "tcp", _RPC_TCP },
89215207Sgnn	{ "udp", _RPC_UDP },
90215207Sgnn	{ 0, _RPC_NONE }
91215207Sgnn};
92215207Sgnn
93215207Sgnnstruct netid_af {
94215207Sgnn	const char	*netid;
95215207Sgnn	int		af;
96215207Sgnn	int		protocol;
97215207Sgnn};
98215207Sgnn
99215207Sgnnstatic const struct netid_af na_cvt[] = {
100215207Sgnn	{ "udp",  AF_INET,  IPPROTO_UDP },
101215207Sgnn	{ "tcp",  AF_INET,  IPPROTO_TCP },
102215207Sgnn#ifdef INET6
103215207Sgnn	{ "udp6", AF_INET6, IPPROTO_UDP },
104215207Sgnn	{ "tcp6", AF_INET6, IPPROTO_TCP },
105215207Sgnn#endif
106215207Sgnn	{ "local", AF_LOCAL, 0 }
107215207Sgnn};
108215207Sgnn
109215207Sgnnstruct rpc_createerr rpc_createerr;
110215207Sgnn
111215207Sgnn/*
112215207Sgnn * Find the appropriate buffer size
113215207Sgnn */
114215207Sgnnu_int
115215207Sgnn/*ARGSUSED*/
116215207Sgnn__rpc_get_t_size(int af, int proto, int size)
117215207Sgnn{
118215207Sgnn	int defsize;
119215207Sgnn
120215207Sgnn	switch (proto) {
121215207Sgnn	case IPPROTO_TCP:
122215207Sgnn		defsize = 64 * 1024;	/* XXX */
123215207Sgnn		break;
124215207Sgnn	case IPPROTO_UDP:
125215207Sgnn		defsize = UDPMSGSIZE;
126215207Sgnn		break;
127215207Sgnn	default:
128215207Sgnn		defsize = RPC_MAXDATASIZE;
129215207Sgnn		break;
130215207Sgnn	}
131215207Sgnn	if (size == 0)
132215207Sgnn		return defsize;
133215207Sgnn
134215207Sgnn	/* Check whether the value is within the upper max limit */
135215207Sgnn	return (size > sb_max_adj ? (u_int)sb_max_adj : (u_int)size);
136215207Sgnn}
137215207Sgnn
138215207Sgnn/*
139215207Sgnn * Find the appropriate address buffer size
140215207Sgnn */
141215207Sgnnu_int
142215207Sgnn__rpc_get_a_size(af)
143215207Sgnn	int af;
144215207Sgnn{
145215207Sgnn	switch (af) {
146215207Sgnn	case AF_INET:
147215207Sgnn		return sizeof (struct sockaddr_in);
148215207Sgnn#ifdef INET6
149215207Sgnn	case AF_INET6:
150215207Sgnn		return sizeof (struct sockaddr_in6);
151215207Sgnn#endif
152215207Sgnn	case AF_LOCAL:
153215207Sgnn		return sizeof (struct sockaddr_un);
154215207Sgnn	default:
155215207Sgnn		break;
156215207Sgnn	}
157215207Sgnn	return ((u_int)RPC_MAXADDRSIZE);
158215207Sgnn}
159215207Sgnn
160215207Sgnn#if 0
161215207Sgnn
162215207Sgnn/*
163215207Sgnn * Used to ping the NULL procedure for clnt handle.
164 * Returns NULL if fails, else a non-NULL pointer.
165 */
166void *
167rpc_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
181int
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 */
229int
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
251struct 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
271char *
272taddr2uaddr(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
281struct netbuf *
282uaddr2taddr(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
291char *
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
350struct 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	}
442out:
443	free(addrstr, M_RPC);
444	return ret;
445}
446
447int
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
464int
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 */
485static int
486getnettype(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 */
508struct 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 */
560void *
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
593failed:
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 */
602struct 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
681void
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
695int
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 */
731enum clnt_stat
732clnt_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 */
776int
777bindresvport(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	}
860out:
861	if (freesa)
862		free(sa, M_SONAME);
863
864	return (error);
865}
866
867/*
868 * Kernel module glue
869 */
870static int
871krpc_modevent(module_t mod, int type, void *data)
872{
873
874	return (0);
875}
876static moduledata_t krpc_mod = {
877	"krpc",
878	krpc_modevent,
879	NULL,
880};
881DECLARE_MODULE(krpc, krpc_mod, SI_SUB_VFS, SI_ORDER_ANY);
882
883/* So that loader and kldload(2) can find us, wherever we are.. */
884MODULE_VERSION(krpc, 1);
885