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