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