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