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