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