rpc_generic.c revision 172259
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: head/lib/libc/rpc/rpc_generic.c 172259 2007-09-20 22:35:24Z matteo $");
38
39/*
40 * rpc_generic.c, Miscl routines for RPC.
41 *
42 */
43
44#include "namespace.h"
45#include "reentrant.h"
46#include <sys/types.h>
47#include <sys/param.h>
48#include <sys/socket.h>
49#include <sys/time.h>
50#include <sys/un.h>
51#include <sys/resource.h>
52#include <netinet/in.h>
53#include <arpa/inet.h>
54#include <rpc/rpc.h>
55#include <ctype.h>
56#include <stddef.h>
57#include <stdio.h>
58#include <netdb.h>
59#include <netconfig.h>
60#include <stdlib.h>
61#include <string.h>
62#include <syslog.h>
63#include <rpc/nettype.h>
64#include "un-namespace.h"
65#include "rpc_com.h"
66#include "mt_misc.h"
67
68struct handle {
69	NCONF_HANDLE *nhandle;
70	int nflag;		/* Whether NETPATH or NETCONFIG */
71	int nettype;
72};
73
74static const struct _rpcnettype {
75	const char *name;
76	const int type;
77} _rpctypelist[] = {
78	{ "netpath", _RPC_NETPATH },
79	{ "visible", _RPC_VISIBLE },
80	{ "circuit_v", _RPC_CIRCUIT_V },
81	{ "datagram_v", _RPC_DATAGRAM_V },
82	{ "circuit_n", _RPC_CIRCUIT_N },
83	{ "datagram_n", _RPC_DATAGRAM_N },
84	{ "tcp", _RPC_TCP },
85	{ "udp", _RPC_UDP },
86	{ 0, _RPC_NONE }
87};
88
89struct netid_af {
90	const char	*netid;
91	int		af;
92	int		protocol;
93};
94
95static const struct netid_af na_cvt[] = {
96	{ "udp",  AF_INET,  IPPROTO_UDP },
97	{ "tcp",  AF_INET,  IPPROTO_TCP },
98#ifdef INET6
99	{ "udp6", AF_INET6, IPPROTO_UDP },
100	{ "tcp6", AF_INET6, IPPROTO_TCP },
101#endif
102	{ "local", AF_LOCAL, 0 }
103};
104
105#if 0
106static char *strlocase(char *);
107#endif
108static int getnettype(const char *);
109
110/*
111 * Cache the result of getrlimit(), so we don't have to do an
112 * expensive call every time.
113 */
114int
115__rpc_dtbsize()
116{
117	static int tbsize;
118	struct rlimit rl;
119
120	if (tbsize) {
121		return (tbsize);
122	}
123	if (getrlimit(RLIMIT_NOFILE, &rl) == 0) {
124		return (tbsize = (int)rl.rlim_max);
125	}
126	/*
127	 * Something wrong.  I'll try to save face by returning a
128	 * pessimistic number.
129	 */
130	return (32);
131}
132
133
134/*
135 * Find the appropriate buffer size
136 */
137u_int
138/*ARGSUSED*/
139__rpc_get_t_size(af, proto, size)
140	int af, proto;
141	int size;	/* Size requested */
142{
143	int maxsize, defsize;
144
145	maxsize = 256 * 1024;	/* XXX */
146	switch (proto) {
147	case IPPROTO_TCP:
148		defsize = 64 * 1024;	/* XXX */
149		break;
150	case IPPROTO_UDP:
151		defsize = UDPMSGSIZE;
152		break;
153	default:
154		defsize = RPC_MAXDATASIZE;
155		break;
156	}
157	if (size == 0)
158		return defsize;
159
160	/* Check whether the value is within the upper max limit */
161	return (size > maxsize ? (u_int)maxsize : (u_int)size);
162}
163
164/*
165 * Find the appropriate address buffer size
166 */
167u_int
168__rpc_get_a_size(af)
169	int af;
170{
171	switch (af) {
172	case AF_INET:
173		return sizeof (struct sockaddr_in);
174#ifdef INET6
175	case AF_INET6:
176		return sizeof (struct sockaddr_in6);
177#endif
178	case AF_LOCAL:
179		return sizeof (struct sockaddr_un);
180	default:
181		break;
182	}
183	return ((u_int)RPC_MAXADDRSIZE);
184}
185
186#if 0
187static char *
188strlocase(p)
189	char *p;
190{
191	char *t = p;
192
193	for (; *p; p++)
194		if (isupper(*p))
195			*p = tolower(*p);
196	return (t);
197}
198#endif
199
200/*
201 * Returns the type of the network as defined in <rpc/nettype.h>
202 * If nettype is NULL, it defaults to NETPATH.
203 */
204static int
205getnettype(nettype)
206	const char *nettype;
207{
208	int i;
209
210	if ((nettype == NULL) || (nettype[0] == 0)) {
211		return (_RPC_NETPATH);	/* Default */
212	}
213
214#if 0
215	nettype = strlocase(nettype);
216#endif
217	for (i = 0; _rpctypelist[i].name; i++)
218		if (strcasecmp(nettype, _rpctypelist[i].name) == 0) {
219			return (_rpctypelist[i].type);
220		}
221	return (_rpctypelist[i].type);
222}
223
224/*
225 * For the given nettype (tcp or udp only), return the first structure found.
226 * This should be freed by calling freenetconfigent()
227 */
228struct netconfig *
229__rpc_getconfip(nettype)
230	const char *nettype;
231{
232	char *netid;
233	char *netid_tcp = (char *) NULL;
234	char *netid_udp = (char *) NULL;
235	static char *netid_tcp_main;
236	static char *netid_udp_main;
237	struct netconfig *dummy;
238	int main_thread;
239	static thread_key_t tcp_key, udp_key;
240
241	if ((main_thread = thr_main())) {
242		netid_udp = netid_udp_main;
243		netid_tcp = netid_tcp_main;
244	} else {
245		if (tcp_key == 0) {
246			mutex_lock(&tsd_lock);
247			if (tcp_key == 0)
248				thr_keycreate(&tcp_key, free);
249			mutex_unlock(&tsd_lock);
250		}
251		netid_tcp = (char *)thr_getspecific(tcp_key);
252		if (udp_key == 0) {
253			mutex_lock(&tsd_lock);
254			if (udp_key == 0)
255				thr_keycreate(&udp_key, free);
256			mutex_unlock(&tsd_lock);
257		}
258		netid_udp = (char *)thr_getspecific(udp_key);
259	}
260	if (!netid_udp && !netid_tcp) {
261		struct netconfig *nconf;
262		void *confighandle;
263
264		if (!(confighandle = setnetconfig())) {
265			syslog (LOG_ERR, "rpc: failed to open " NETCONFIG);
266			return (NULL);
267		}
268		while ((nconf = getnetconfig(confighandle)) != NULL) {
269			if (strcmp(nconf->nc_protofmly, NC_INET) == 0) {
270				if (strcmp(nconf->nc_proto, NC_TCP) == 0) {
271					netid_tcp = strdup(nconf->nc_netid);
272					if (main_thread)
273						netid_tcp_main = netid_tcp;
274					else
275						thr_setspecific(tcp_key,
276							(void *) netid_tcp);
277				} else
278				if (strcmp(nconf->nc_proto, NC_UDP) == 0) {
279					netid_udp = strdup(nconf->nc_netid);
280					if (main_thread)
281						netid_udp_main = netid_udp;
282					else
283						thr_setspecific(udp_key,
284						(void *) netid_udp);
285				}
286			}
287		}
288		endnetconfig(confighandle);
289	}
290	if (strcmp(nettype, "udp") == 0)
291		netid = netid_udp;
292	else if (strcmp(nettype, "tcp") == 0)
293		netid = netid_tcp;
294	else {
295		return (NULL);
296	}
297	if ((netid == NULL) || (netid[0] == 0)) {
298		return (NULL);
299	}
300	dummy = getnetconfigent(netid);
301	return (dummy);
302}
303
304/*
305 * Returns the type of the nettype, which should then be used with
306 * __rpc_getconf().
307 */
308void *
309__rpc_setconf(nettype)
310	const char *nettype;
311{
312	struct handle *handle;
313
314	handle = (struct handle *) malloc(sizeof (struct handle));
315	if (handle == NULL) {
316		return (NULL);
317	}
318	switch (handle->nettype = getnettype(nettype)) {
319	case _RPC_NETPATH:
320	case _RPC_CIRCUIT_N:
321	case _RPC_DATAGRAM_N:
322		if (!(handle->nhandle = setnetpath()))
323			goto failed;
324		handle->nflag = TRUE;
325		break;
326	case _RPC_VISIBLE:
327	case _RPC_CIRCUIT_V:
328	case _RPC_DATAGRAM_V:
329	case _RPC_TCP:
330	case _RPC_UDP:
331		if (!(handle->nhandle = setnetconfig())) {
332		        syslog (LOG_ERR, "rpc: failed to open " NETCONFIG);
333			goto failed;
334		}
335		handle->nflag = FALSE;
336		break;
337	default:
338		goto failed;
339	}
340
341	return (handle);
342
343failed:
344	free(handle);
345	return (NULL);
346}
347
348/*
349 * Returns the next netconfig struct for the given "net" type.
350 * __rpc_setconf() should have been called previously.
351 */
352struct netconfig *
353__rpc_getconf(vhandle)
354	void *vhandle;
355{
356	struct handle *handle;
357	struct netconfig *nconf;
358
359	handle = (struct handle *)vhandle;
360	if (handle == NULL) {
361		return (NULL);
362	}
363	for (;;) {
364		if (handle->nflag)
365			nconf = getnetpath(handle->nhandle);
366		else
367			nconf = getnetconfig(handle->nhandle);
368		if (nconf == NULL)
369			break;
370		if ((nconf->nc_semantics != NC_TPI_CLTS) &&
371			(nconf->nc_semantics != NC_TPI_COTS) &&
372			(nconf->nc_semantics != NC_TPI_COTS_ORD))
373			continue;
374		switch (handle->nettype) {
375		case _RPC_VISIBLE:
376			if (!(nconf->nc_flag & NC_VISIBLE))
377				continue;
378			/* FALLTHROUGH */
379		case _RPC_NETPATH:	/* Be happy */
380			break;
381		case _RPC_CIRCUIT_V:
382			if (!(nconf->nc_flag & NC_VISIBLE))
383				continue;
384			/* FALLTHROUGH */
385		case _RPC_CIRCUIT_N:
386			if ((nconf->nc_semantics != NC_TPI_COTS) &&
387				(nconf->nc_semantics != NC_TPI_COTS_ORD))
388				continue;
389			break;
390		case _RPC_DATAGRAM_V:
391			if (!(nconf->nc_flag & NC_VISIBLE))
392				continue;
393			/* FALLTHROUGH */
394		case _RPC_DATAGRAM_N:
395			if (nconf->nc_semantics != NC_TPI_CLTS)
396				continue;
397			break;
398		case _RPC_TCP:
399			if (((nconf->nc_semantics != NC_TPI_COTS) &&
400				(nconf->nc_semantics != NC_TPI_COTS_ORD)) ||
401				(strcmp(nconf->nc_protofmly, NC_INET)
402#ifdef INET6
403				 && strcmp(nconf->nc_protofmly, NC_INET6))
404#else
405				)
406#endif
407				||
408				strcmp(nconf->nc_proto, NC_TCP))
409				continue;
410			break;
411		case _RPC_UDP:
412			if ((nconf->nc_semantics != NC_TPI_CLTS) ||
413				(strcmp(nconf->nc_protofmly, NC_INET)
414#ifdef INET6
415				&& strcmp(nconf->nc_protofmly, NC_INET6))
416#else
417				)
418#endif
419				||
420				strcmp(nconf->nc_proto, NC_UDP))
421				continue;
422			break;
423		}
424		break;
425	}
426	return (nconf);
427}
428
429void
430__rpc_endconf(vhandle)
431	void * vhandle;
432{
433	struct handle *handle;
434
435	handle = (struct handle *) vhandle;
436	if (handle == NULL) {
437		return;
438	}
439	if (handle->nflag) {
440		endnetpath(handle->nhandle);
441	} else {
442		endnetconfig(handle->nhandle);
443	}
444	free(handle);
445}
446
447/*
448 * Used to ping the NULL procedure for clnt handle.
449 * Returns NULL if fails, else a non-NULL pointer.
450 */
451void *
452rpc_nullproc(clnt)
453	CLIENT *clnt;
454{
455	struct timeval TIMEOUT = {25, 0};
456
457	if (clnt_call(clnt, NULLPROC, (xdrproc_t) xdr_void, NULL,
458		(xdrproc_t) xdr_void, NULL, TIMEOUT) != RPC_SUCCESS) {
459		return (NULL);
460	}
461	return ((void *) clnt);
462}
463
464/*
465 * Try all possible transports until
466 * one succeeds in finding the netconf for the given fd.
467 */
468struct netconfig *
469__rpcgettp(fd)
470	int fd;
471{
472	const char *netid;
473	struct __rpc_sockinfo si;
474
475	if (!__rpc_fd2sockinfo(fd, &si))
476		return NULL;
477
478	if (!__rpc_sockinfo2netid(&si, &netid))
479		return NULL;
480
481	/*LINTED const castaway*/
482	return getnetconfigent((char *)netid);
483}
484
485int
486__rpc_fd2sockinfo(int fd, struct __rpc_sockinfo *sip)
487{
488	socklen_t len;
489	int type, proto;
490	struct sockaddr_storage ss;
491
492	len = sizeof ss;
493	if (_getsockname(fd, (struct sockaddr *)(void *)&ss, &len) < 0)
494		return 0;
495	sip->si_alen = len;
496
497	len = sizeof type;
498	if (_getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &len) < 0)
499		return 0;
500
501	/* XXX */
502	if (ss.ss_family != AF_LOCAL) {
503		if (type == SOCK_STREAM)
504			proto = IPPROTO_TCP;
505		else if (type == SOCK_DGRAM)
506			proto = IPPROTO_UDP;
507		else
508			return 0;
509	} else
510		proto = 0;
511
512	sip->si_af = ss.ss_family;
513	sip->si_proto = proto;
514	sip->si_socktype = type;
515
516	return 1;
517}
518
519/*
520 * Linear search, but the number of entries is small.
521 */
522int
523__rpc_nconf2sockinfo(const struct netconfig *nconf, struct __rpc_sockinfo *sip)
524{
525	int i;
526
527	for (i = 0; i < (sizeof na_cvt) / (sizeof (struct netid_af)); i++)
528		if (strcmp(na_cvt[i].netid, nconf->nc_netid) == 0 || (
529		    strcmp(nconf->nc_netid, "unix") == 0 &&
530		    strcmp(na_cvt[i].netid, "local") == 0)) {
531			sip->si_af = na_cvt[i].af;
532			sip->si_proto = na_cvt[i].protocol;
533			sip->si_socktype =
534			    __rpc_seman2socktype((int)nconf->nc_semantics);
535			if (sip->si_socktype == -1)
536				return 0;
537			sip->si_alen = __rpc_get_a_size(sip->si_af);
538			return 1;
539		}
540
541	return 0;
542}
543
544int
545__rpc_nconf2fd(const struct netconfig *nconf)
546{
547	struct __rpc_sockinfo si;
548
549	if (!__rpc_nconf2sockinfo(nconf, &si))
550		return 0;
551
552	return _socket(si.si_af, si.si_socktype, si.si_proto);
553}
554
555int
556__rpc_sockinfo2netid(struct __rpc_sockinfo *sip, const char **netid)
557{
558	int i;
559	struct netconfig *nconf;
560
561	nconf = getnetconfigent("local");
562
563	for (i = 0; i < (sizeof na_cvt) / (sizeof (struct netid_af)); i++) {
564		if (na_cvt[i].af == sip->si_af &&
565		    na_cvt[i].protocol == sip->si_proto) {
566			if (strcmp(na_cvt[i].netid, "local") == 0 && nconf == NULL) {
567				if (netid)
568					*netid = "unix";
569			} else {
570				if (netid)
571					*netid = na_cvt[i].netid;
572			}
573			if (nconf != NULL)
574				freenetconfigent(nconf);
575			return 1;
576		}
577	}
578	if (nconf != NULL)
579		freenetconfigent(nconf);
580
581	return 0;
582}
583
584char *
585taddr2uaddr(const struct netconfig *nconf, const struct netbuf *nbuf)
586{
587	struct __rpc_sockinfo si;
588
589	if (!__rpc_nconf2sockinfo(nconf, &si))
590		return NULL;
591	return __rpc_taddr2uaddr_af(si.si_af, nbuf);
592}
593
594struct netbuf *
595uaddr2taddr(const struct netconfig *nconf, const char *uaddr)
596{
597	struct __rpc_sockinfo si;
598
599	if (!__rpc_nconf2sockinfo(nconf, &si))
600		return NULL;
601	return __rpc_uaddr2taddr_af(si.si_af, uaddr);
602}
603
604char *
605__rpc_taddr2uaddr_af(int af, const struct netbuf *nbuf)
606{
607	char *ret;
608	struct sockaddr_in *sin;
609	struct sockaddr_un *sun;
610	char namebuf[INET_ADDRSTRLEN];
611#ifdef INET6
612	struct sockaddr_in6 *sin6;
613	char namebuf6[INET6_ADDRSTRLEN];
614#endif
615	u_int16_t port;
616
617	switch (af) {
618	case AF_INET:
619		sin = nbuf->buf;
620		if (inet_ntop(af, &sin->sin_addr, namebuf, sizeof namebuf)
621		    == NULL)
622			return NULL;
623		port = ntohs(sin->sin_port);
624		if (asprintf(&ret, "%s.%u.%u", namebuf, ((u_int32_t)port) >> 8,
625		    port & 0xff) < 0)
626			return NULL;
627		break;
628#ifdef INET6
629	case AF_INET6:
630		sin6 = nbuf->buf;
631		if (inet_ntop(af, &sin6->sin6_addr, namebuf6, sizeof namebuf6)
632		    == NULL)
633			return NULL;
634		port = ntohs(sin6->sin6_port);
635		if (asprintf(&ret, "%s.%u.%u", namebuf6, ((u_int32_t)port) >> 8,
636		    port & 0xff) < 0)
637			return NULL;
638		break;
639#endif
640	case AF_LOCAL:
641		sun = nbuf->buf;
642		if (asprintf(&ret, "%.*s", (int)(sun->sun_len -
643		    offsetof(struct sockaddr_un, sun_path)),
644		    sun->sun_path) < 0)
645			return (NULL);
646		break;
647	default:
648		return NULL;
649	}
650
651	return ret;
652}
653
654struct netbuf *
655__rpc_uaddr2taddr_af(int af, const char *uaddr)
656{
657	struct netbuf *ret = NULL;
658	char *addrstr, *p;
659	unsigned port, portlo, porthi;
660	struct sockaddr_in *sin;
661#ifdef INET6
662	struct sockaddr_in6 *sin6;
663#endif
664	struct sockaddr_un *sun;
665
666	port = 0;
667	sin = NULL;
668	addrstr = strdup(uaddr);
669	if (addrstr == NULL)
670		return NULL;
671
672	/*
673	 * AF_LOCAL addresses are expected to be absolute
674	 * pathnames, anything else will be AF_INET or AF_INET6.
675	 */
676	if (*addrstr != '/') {
677		p = strrchr(addrstr, '.');
678		if (p == NULL)
679			goto out;
680		portlo = (unsigned)atoi(p + 1);
681		*p = '\0';
682
683		p = strrchr(addrstr, '.');
684		if (p == NULL)
685			goto out;
686		porthi = (unsigned)atoi(p + 1);
687		*p = '\0';
688		port = (porthi << 8) | portlo;
689	}
690
691	ret = (struct netbuf *)malloc(sizeof *ret);
692	if (ret == NULL)
693		goto out;
694
695	switch (af) {
696	case AF_INET:
697		sin = (struct sockaddr_in *)malloc(sizeof *sin);
698		if (sin == NULL)
699			goto out;
700		memset(sin, 0, sizeof *sin);
701		sin->sin_family = AF_INET;
702		sin->sin_port = htons(port);
703		if (inet_pton(AF_INET, addrstr, &sin->sin_addr) <= 0) {
704			free(sin);
705			free(ret);
706			ret = NULL;
707			goto out;
708		}
709		sin->sin_len = ret->maxlen = ret->len = sizeof *sin;
710		ret->buf = sin;
711		break;
712#ifdef INET6
713	case AF_INET6:
714		sin6 = (struct sockaddr_in6 *)malloc(sizeof *sin6);
715		if (sin6 == NULL)
716			goto out;
717		memset(sin6, 0, sizeof *sin6);
718		sin6->sin6_family = AF_INET6;
719		sin6->sin6_port = htons(port);
720		if (inet_pton(AF_INET6, addrstr, &sin6->sin6_addr) <= 0) {
721			free(sin6);
722			free(ret);
723			ret = NULL;
724			goto out;
725		}
726		sin6->sin6_len = ret->maxlen = ret->len = sizeof *sin6;
727		ret->buf = sin6;
728		break;
729#endif
730	case AF_LOCAL:
731		sun = (struct sockaddr_un *)malloc(sizeof *sun);
732		if (sun == NULL)
733			goto out;
734		memset(sun, 0, sizeof *sun);
735		sun->sun_family = AF_LOCAL;
736		strncpy(sun->sun_path, addrstr, sizeof(sun->sun_path) - 1);
737		ret->len = ret->maxlen = sun->sun_len = SUN_LEN(sun);
738		ret->buf = sun;
739		break;
740	default:
741		break;
742	}
743out:
744	free(addrstr);
745	return ret;
746}
747
748int
749__rpc_seman2socktype(int semantics)
750{
751	switch (semantics) {
752	case NC_TPI_CLTS:
753		return SOCK_DGRAM;
754	case NC_TPI_COTS_ORD:
755		return SOCK_STREAM;
756	case NC_TPI_RAW:
757		return SOCK_RAW;
758	default:
759		break;
760	}
761
762	return -1;
763}
764
765int
766__rpc_socktype2seman(int socktype)
767{
768	switch (socktype) {
769	case SOCK_DGRAM:
770		return NC_TPI_CLTS;
771	case SOCK_STREAM:
772		return NC_TPI_COTS_ORD;
773	case SOCK_RAW:
774		return NC_TPI_RAW;
775	default:
776		break;
777	}
778
779	return -1;
780}
781
782/*
783 * XXXX - IPv6 scope IDs can't be handled in universal addresses.
784 * Here, we compare the original server address to that of the RPC
785 * service we just received back from a call to rpcbind on the remote
786 * machine. If they are both "link local" or "site local", copy
787 * the scope id of the server address over to the service address.
788 */
789int
790__rpc_fixup_addr(struct netbuf *new, const struct netbuf *svc)
791{
792#ifdef INET6
793	struct sockaddr *sa_new, *sa_svc;
794	struct sockaddr_in6 *sin6_new, *sin6_svc;
795
796	sa_svc = (struct sockaddr *)svc->buf;
797	sa_new = (struct sockaddr *)new->buf;
798
799	if (sa_new->sa_family == sa_svc->sa_family &&
800	    sa_new->sa_family == AF_INET6) {
801		sin6_new = (struct sockaddr_in6 *)new->buf;
802		sin6_svc = (struct sockaddr_in6 *)svc->buf;
803
804		if ((IN6_IS_ADDR_LINKLOCAL(&sin6_new->sin6_addr) &&
805		     IN6_IS_ADDR_LINKLOCAL(&sin6_svc->sin6_addr)) ||
806		    (IN6_IS_ADDR_SITELOCAL(&sin6_new->sin6_addr) &&
807		     IN6_IS_ADDR_SITELOCAL(&sin6_svc->sin6_addr))) {
808			sin6_new->sin6_scope_id = sin6_svc->sin6_scope_id;
809		}
810	}
811#endif
812	return 1;
813}
814
815int
816__rpc_sockisbound(int fd)
817{
818	struct sockaddr_storage ss;
819	socklen_t slen;
820
821	slen = sizeof (struct sockaddr_storage);
822	if (_getsockname(fd, (struct sockaddr *)(void *)&ss, &slen) < 0)
823		return 0;
824
825	switch (ss.ss_family) {
826		case AF_INET:
827			return (((struct sockaddr_in *)
828			    (void *)&ss)->sin_port != 0);
829#ifdef INET6
830		case AF_INET6:
831			return (((struct sockaddr_in6 *)
832			    (void *)&ss)->sin6_port != 0);
833#endif
834		case AF_LOCAL:
835			/* XXX check this */
836			return (((struct sockaddr_un *)
837			    (void *)&ss)->sun_path[0] != '\0');
838		default:
839			break;
840	}
841
842	return 0;
843}
844