| 1 | /*	$NetBSD: clnt_bcast.c,v 1.26 2013/03/11 20:19:28 tron Exp $	*/ | 
| 2 |  | 
| 3 | /* | 
| 4 |  * Copyright (c) 2010, Oracle America, Inc. | 
| 5 |  * | 
| 6 |  * Redistribution and use in source and binary forms, with or without | 
| 7 |  * modification, are permitted provided that the following conditions are | 
| 8 |  * met: | 
| 9 |  * | 
| 10 |  *     * Redistributions of source code must retain the above copyright | 
| 11 |  *       notice, this list of conditions and the following disclaimer. | 
| 12 |  *     * Redistributions in binary form must reproduce the above | 
| 13 |  *       copyright notice, this list of conditions and the following | 
| 14 |  *       disclaimer in the documentation and/or other materials | 
| 15 |  *       provided with the distribution. | 
| 16 |  *     * Neither the name of the "Oracle America, Inc." nor the names of its | 
| 17 |  *       contributors may be used to endorse or promote products derived | 
| 18 |  *       from this software without specific prior written permission. | 
| 19 |  * | 
| 20 |  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 
| 21 |  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 
| 22 |  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | 
| 23 |  *   FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | 
| 24 |  *   COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, | 
| 25 |  *   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 
| 26 |  *   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE | 
| 27 |  *   GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | 
| 28 |  *   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | 
| 29 |  *   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | 
| 30 |  *   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 
| 31 |  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
| 32 |  */ | 
| 33 | /* | 
| 34 |  * Copyright (c) 1986-1991 by Sun Microsystems Inc.  | 
| 35 |  */ | 
| 36 |  | 
| 37 | /* #ident	"@(#)clnt_bcast.c	1.18	94/05/03 SMI" */ | 
| 38 |  | 
| 39 | #include <sys/cdefs.h> | 
| 40 | #if defined(LIBC_SCCS) && !defined(lint) | 
| 41 | #if 0 | 
| 42 | static char sccsid[] = "@(#)clnt_bcast.c 1.15 89/04/21 Copyr 1988 Sun Micro" ; | 
| 43 | #else | 
| 44 | __RCSID("$NetBSD: clnt_bcast.c,v 1.26 2013/03/11 20:19:28 tron Exp $" ); | 
| 45 | #endif | 
| 46 | #endif | 
| 47 |  | 
| 48 | /* | 
| 49 |  * clnt_bcast.c | 
| 50 |  * Client interface to broadcast service. | 
| 51 |  * | 
| 52 |  * Copyright (C) 1988, Sun Microsystems, Inc. | 
| 53 |  * | 
| 54 |  * The following is kludged-up support for simple rpc broadcasts. | 
| 55 |  * Someday a large, complicated system will replace these routines. | 
| 56 |  */ | 
| 57 |  | 
| 58 | #include "namespace.h" | 
| 59 | #include <sys/types.h> | 
| 60 | #include <sys/socket.h> | 
| 61 | #include <sys/queue.h> | 
| 62 | #include <net/if.h> | 
| 63 | #include <netinet/in.h> | 
| 64 | #include <ifaddrs.h> | 
| 65 | #include <sys/poll.h> | 
| 66 | #include <rpc/rpc.h> | 
| 67 | #ifdef PORTMAP | 
| 68 | #include <rpc/pmap_prot.h> | 
| 69 | #include <rpc/pmap_clnt.h> | 
| 70 | #include <rpc/pmap_rmt.h> | 
| 71 | #endif | 
| 72 | #include <rpc/nettype.h> | 
| 73 | #include <arpa/inet.h> | 
| 74 | #ifdef RPC_DEBUG | 
| 75 | #include <stdio.h> | 
| 76 | #endif | 
| 77 | #include <assert.h> | 
| 78 | #include <errno.h> | 
| 79 | #include <stdlib.h> | 
| 80 | #include <unistd.h> | 
| 81 | #include <netdb.h> | 
| 82 | #include <err.h> | 
| 83 | #include <string.h> | 
| 84 |  | 
| 85 | #include "rpc_internal.h" | 
| 86 | #include "svc_fdset.h" | 
| 87 |  | 
| 88 | #define	MAXBCAST 20	/* Max no of broadcasting transports */ | 
| 89 | #define	INITTIME 4000	/* Time to wait initially */ | 
| 90 | #define	WAITTIME 8000	/* Maximum time to wait */ | 
| 91 |  | 
| 92 | /* | 
| 93 |  * If nettype is NULL, it broadcasts on all the available | 
| 94 |  * datagram_n transports. May potentially lead to broadacst storms | 
| 95 |  * and hence should be used with caution, care and courage. | 
| 96 |  * | 
| 97 |  * The current parameter xdr packet size is limited by the max tsdu | 
| 98 |  * size of the transport. If the max tsdu size of any transport is | 
| 99 |  * smaller than the parameter xdr packet, then broadcast is not | 
| 100 |  * sent on that transport. | 
| 101 |  * | 
| 102 |  * Also, the packet size should be less the packet size of | 
| 103 |  * the data link layer (for ethernet it is 1400 bytes).  There is | 
| 104 |  * no easy way to find out the max size of the data link layer and | 
| 105 |  * we are assuming that the args would be smaller than that. | 
| 106 |  * | 
| 107 |  * The result size has to be smaller than the transport tsdu size. | 
| 108 |  * | 
| 109 |  * If PORTMAP has been defined, we send two packets for UDP, one for | 
| 110 |  * rpcbind and one for portmap. For those machines which support | 
| 111 |  * both rpcbind and portmap, it will cause them to reply twice, and | 
| 112 |  * also here it will get two responses ... inefficient and clumsy. | 
| 113 |  */ | 
| 114 |  | 
| 115 | #ifdef __weak_alias | 
| 116 | __weak_alias(rpc_broadcast_exp,_rpc_broadcast_exp) | 
| 117 | __weak_alias(rpc_broadcast,_rpc_broadcast) | 
| 118 | #endif | 
| 119 |  | 
| 120 | struct broadif { | 
| 121 | 	int index; | 
| 122 | 	struct sockaddr_storage broadaddr; | 
| 123 | 	TAILQ_ENTRY(broadif) link; | 
| 124 | }; | 
| 125 |  | 
| 126 | typedef TAILQ_HEAD(, broadif) broadlist_t; | 
| 127 |  | 
| 128 | int __rpc_getbroadifs(int, int, int, broadlist_t *); | 
| 129 | void __rpc_freebroadifs(broadlist_t *); | 
| 130 | int __rpc_broadenable(int, int, struct broadif *); | 
| 131 |  | 
| 132 | int __rpc_lowvers = 0; | 
| 133 |  | 
| 134 | int | 
| 135 | __rpc_getbroadifs(int af, int proto, int socktype, broadlist_t *list) | 
| 136 | { | 
| 137 | 	int count = 0; | 
| 138 | 	struct broadif *bip; | 
| 139 | 	struct ifaddrs *ifap, *ifp; | 
| 140 | #ifdef INET6 | 
| 141 | 	struct sockaddr_in6 *sin6; | 
| 142 | #endif | 
| 143 | 	struct sockaddr_in *gbsin; | 
| 144 | 	struct addrinfo hints, *res; | 
| 145 |  | 
| 146 | 	_DIAGASSERT(list != NULL); | 
| 147 |  | 
| 148 | 	if (getifaddrs(&ifp) < 0) | 
| 149 | 		return 0; | 
| 150 |  | 
| 151 | 	memset(&hints, 0, sizeof hints); | 
| 152 |  | 
| 153 | 	hints.ai_family = af; | 
| 154 | 	hints.ai_protocol = proto; | 
| 155 | 	hints.ai_socktype = socktype; | 
| 156 |  | 
| 157 | 	if (getaddrinfo(NULL, "sunrpc" , &hints, &res) != 0) { | 
| 158 | 		freeifaddrs(ifp); | 
| 159 | 		return 0; | 
| 160 | 	} | 
| 161 |  | 
| 162 | 	for (ifap = ifp; ifap != NULL; ifap = ifap->ifa_next) { | 
| 163 | 		if (ifap->ifa_addr->sa_family != af || | 
| 164 | 		    !(ifap->ifa_flags & IFF_UP)) | 
| 165 | 			continue; | 
| 166 | 		bip = malloc(sizeof(*bip)); | 
| 167 | 		if (bip == NULL) | 
| 168 | 			break; | 
| 169 | 		bip->index = if_nametoindex(ifap->ifa_name); | 
| 170 | 		if ( | 
| 171 | #ifdef INET6 | 
| 172 | 		    af != AF_INET6 && | 
| 173 | #endif | 
| 174 | 		    (ifap->ifa_flags & IFF_BROADCAST) && | 
| 175 | 		    ifap->ifa_broadaddr) { | 
| 176 | 			memcpy(&bip->broadaddr, ifap->ifa_broadaddr, | 
| 177 | 			    (size_t)ifap->ifa_broadaddr->sa_len); | 
| 178 | 			gbsin = (struct sockaddr_in *)(void *)&bip->broadaddr; | 
| 179 | 			gbsin->sin_port = | 
| 180 | 			    ((struct sockaddr_in *) | 
| 181 | 			    (void *)res->ai_addr)->sin_port; | 
| 182 | 		} else | 
| 183 | #ifdef INET6 | 
| 184 | 		if (af == AF_INET6 && (ifap->ifa_flags & IFF_MULTICAST)) { | 
| 185 | 			sin6 = (struct sockaddr_in6 *)(void *)&bip->broadaddr; | 
| 186 | 			inet_pton(af, RPCB_MULTICAST_ADDR, &sin6->sin6_addr); | 
| 187 | 			sin6->sin6_family = af; | 
| 188 | 			sin6->sin6_len = sizeof *sin6; | 
| 189 | 			sin6->sin6_port = | 
| 190 | 			    ((struct sockaddr_in6 *) | 
| 191 | 			    (void *)res->ai_addr)->sin6_port; | 
| 192 | 			sin6->sin6_scope_id = bip->index; | 
| 193 | 		} else | 
| 194 | #endif | 
| 195 | 		{ | 
| 196 | 			free(bip); | 
| 197 | 			continue; | 
| 198 | 		} | 
| 199 | 		TAILQ_INSERT_TAIL(list, bip, link); | 
| 200 | 		count++; | 
| 201 | 	} | 
| 202 | 	freeifaddrs(ifp); | 
| 203 | 	freeaddrinfo(res); | 
| 204 |  | 
| 205 | 	return count; | 
| 206 | } | 
| 207 |  | 
| 208 | void | 
| 209 | __rpc_freebroadifs(broadlist_t *list) | 
| 210 | { | 
| 211 | 	struct broadif *bip, *next; | 
| 212 |  | 
| 213 | 	_DIAGASSERT(list != NULL); | 
| 214 |  | 
| 215 | 	bip = TAILQ_FIRST(list); | 
| 216 |  | 
| 217 | 	while (bip != NULL) { | 
| 218 | 		next = TAILQ_NEXT(bip, link); | 
| 219 | 		free(bip); | 
| 220 | 		bip = next; | 
| 221 | 	} | 
| 222 | } | 
| 223 |  | 
| 224 | int | 
| 225 | /*ARGSUSED*/ | 
| 226 | __rpc_broadenable(int af, int s, struct broadif *bip) | 
| 227 | { | 
| 228 | 	int o = 1; | 
| 229 |  | 
| 230 | #if 0 | 
| 231 | 	_DIAGASSERT(bip != NULL); | 
| 232 |  | 
| 233 | 	if (af == AF_INET6) { | 
| 234 | 		fprintf(stderr, "set v6 multicast if to %d\n" , bip->index); | 
| 235 | 		if (setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, &bip->index, | 
| 236 | 		    sizeof bip->index) < 0) | 
| 237 | 			return -1; | 
| 238 | 	} else | 
| 239 | #endif | 
| 240 | 		if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &o, | 
| 241 | 		    (socklen_t)sizeof(o)) == -1) | 
| 242 | 			return -1; | 
| 243 |  | 
| 244 | 	return 0; | 
| 245 | } | 
| 246 |  | 
| 247 |  | 
| 248 | enum clnt_stat | 
| 249 | rpc_broadcast_exp( | 
| 250 | 	rpcprog_t	prog,		/* program number */ | 
| 251 | 	rpcvers_t	vers,		/* version number */ | 
| 252 | 	rpcproc_t	proc,		/* procedure number */ | 
| 253 | 	xdrproc_t	xargs,		/* xdr routine for args */ | 
| 254 | 	const char *	argsp,		/* pointer to args */ | 
| 255 | 	xdrproc_t	xresults,	/* xdr routine for results */ | 
| 256 | 	caddr_t		resultsp,	/* pointer to results */ | 
| 257 | 	resultproc_t	eachresult,	/* call with each result obtained */ | 
| 258 | 	int 		inittime,	/* how long to wait initially */ | 
| 259 | 	int 		waittime,	/* maximum time to wait */ | 
| 260 | 	const char *	nettype)	/* transport type */ | 
| 261 | { | 
| 262 | 	enum clnt_stat	stat = RPC_SUCCESS; /* Return status */ | 
| 263 | 	XDR 		xdr_stream; /* XDR stream */ | 
| 264 | 	XDR 		*xdrs = &xdr_stream; | 
| 265 | 	struct rpc_msg	msg;	/* RPC message */ | 
| 266 | 	char 		*outbuf = NULL;	/* Broadcast msg buffer */ | 
| 267 | 	char		*inbuf = NULL; /* Reply buf */ | 
| 268 | 	ssize_t		inlen; | 
| 269 | 	u_int 		maxbufsize = 0; | 
| 270 | 	AUTH 		*sys_auth = authunix_create_default(); | 
| 271 | 	size_t		i; | 
| 272 | 	void		*handle; | 
| 273 | 	char		uaddress[1024];	/* A self imposed limit */ | 
| 274 | 	char		*uaddrp = uaddress; | 
| 275 | 	int 		pmap_reply_flag; /* reply recvd from PORTMAP */ | 
| 276 | 	/* An array of all the suitable broadcast transports */ | 
| 277 | 	struct { | 
| 278 | 		int fd;		/* File descriptor */ | 
| 279 | 		int af; | 
| 280 | 		int proto; | 
| 281 | 		struct netconfig *nconf; /* Netconfig structure */ | 
| 282 | 		u_int asize;	/* Size of the addr buf */ | 
| 283 | 		u_int dsize;	/* Size of the data buf */ | 
| 284 | 		struct sockaddr_storage raddr; /* Remote address */ | 
| 285 | 		broadlist_t nal; | 
| 286 | 	} fdlist[MAXBCAST]; | 
| 287 | 	struct pollfd pfd[MAXBCAST]; | 
| 288 | 	nfds_t fdlistno = 0; | 
| 289 | 	struct r_rpcb_rmtcallargs barg;	/* Remote arguments */ | 
| 290 | 	struct r_rpcb_rmtcallres bres; /* Remote results */ | 
| 291 | 	size_t outlen; | 
| 292 | 	struct netconfig *nconf; | 
| 293 | 	int msec; | 
| 294 | 	int pollretval; | 
| 295 | 	int fds_found; | 
| 296 | 	struct timespec ts; | 
| 297 |  | 
| 298 | #ifdef PORTMAP | 
| 299 | 	size_t outlen_pmap = 0; | 
| 300 | 	u_long port;		/* Remote port number */ | 
| 301 | 	int pmap_flag = 0;	/* UDP exists ? */ | 
| 302 | 	char *outbuf_pmap = NULL; | 
| 303 | 	struct rmtcallargs barg_pmap;	/* Remote arguments */ | 
| 304 | 	struct rmtcallres bres_pmap; /* Remote results */ | 
| 305 | 	u_int udpbufsz = 0; | 
| 306 | #endif				/* PORTMAP */ | 
| 307 |  | 
| 308 | 	if (sys_auth == NULL) { | 
| 309 | 		return (RPC_SYSTEMERROR); | 
| 310 | 	} | 
| 311 | 	/* | 
| 312 | 	 * initialization: create a fd, a broadcast address, and send the | 
| 313 | 	 * request on the broadcast transport. | 
| 314 | 	 * Listen on all of them and on replies, call the user supplied | 
| 315 | 	 * function. | 
| 316 | 	 */ | 
| 317 |  | 
| 318 | 	if (nettype == NULL) | 
| 319 | 		nettype = "datagram_n" ; | 
| 320 | 	if ((handle = __rpc_setconf(nettype)) == NULL) { | 
| 321 | 		AUTH_DESTROY(sys_auth); | 
| 322 | 		return (RPC_UNKNOWNPROTO); | 
| 323 | 	} | 
| 324 | 	while ((nconf = __rpc_getconf(handle)) != NULL) { | 
| 325 | 		int fd; | 
| 326 | 		struct __rpc_sockinfo si; | 
| 327 |  | 
| 328 | 		if (nconf->nc_semantics != NC_TPI_CLTS) | 
| 329 | 			continue; | 
| 330 | 		if (fdlistno >= MAXBCAST) | 
| 331 | 			break;	/* No more slots available */ | 
| 332 | 		if (!__rpc_nconf2sockinfo(nconf, &si)) | 
| 333 | 			continue; | 
| 334 |  | 
| 335 | 		TAILQ_INIT(&fdlist[fdlistno].nal); | 
| 336 | 		if (__rpc_getbroadifs(si.si_af, si.si_proto, si.si_socktype,  | 
| 337 | 		    &fdlist[fdlistno].nal) == 0) | 
| 338 | 			continue; | 
| 339 |  | 
| 340 | 		fd = socket(si.si_af, si.si_socktype, si.si_proto); | 
| 341 | 		if (fd < 0) { | 
| 342 | 			stat = RPC_CANTSEND; | 
| 343 | 			continue; | 
| 344 | 		} | 
| 345 | 		fdlist[fdlistno].af = si.si_af; | 
| 346 | 		fdlist[fdlistno].proto = si.si_proto; | 
| 347 | 		fdlist[fdlistno].fd = fd; | 
| 348 | 		fdlist[fdlistno].nconf = nconf; | 
| 349 | 		fdlist[fdlistno].asize = __rpc_get_a_size(si.si_af); | 
| 350 | 		pfd[fdlistno].events = POLLIN | POLLPRI | | 
| 351 | 			POLLRDNORM | POLLRDBAND; | 
| 352 | 		pfd[fdlistno].fd = fdlist[fdlistno].fd = fd; | 
| 353 | 		fdlist[fdlistno].dsize = __rpc_get_t_size(si.si_af, si.si_proto, | 
| 354 | 							  0); | 
| 355 |  | 
| 356 | 		if (maxbufsize <= fdlist[fdlistno].dsize) | 
| 357 | 			maxbufsize = fdlist[fdlistno].dsize; | 
| 358 | 			 | 
| 359 | #ifdef PORTMAP | 
| 360 | 		if (si.si_af == AF_INET && si.si_proto == IPPROTO_UDP) { | 
| 361 | 			udpbufsz = fdlist[fdlistno].dsize; | 
| 362 | 			if ((outbuf_pmap = malloc(udpbufsz)) == NULL) { | 
| 363 | 				close(fd); | 
| 364 | 				stat = RPC_SYSTEMERROR; | 
| 365 | 				goto done_broad; | 
| 366 | 			} | 
| 367 | 			pmap_flag = 1; | 
| 368 | 		} | 
| 369 | #endif | 
| 370 | 		fdlistno++; | 
| 371 | 	} | 
| 372 |  | 
| 373 | 	if (fdlistno == 0) { | 
| 374 | 		if (stat == RPC_SUCCESS) | 
| 375 | 			stat = RPC_UNKNOWNPROTO; | 
| 376 | 		goto done_broad; | 
| 377 | 	} | 
| 378 | 	if (maxbufsize == 0) { | 
| 379 | 		if (stat == RPC_SUCCESS) | 
| 380 | 			stat = RPC_CANTSEND; | 
| 381 | 		goto done_broad; | 
| 382 | 	} | 
| 383 | 	inbuf = malloc(maxbufsize); | 
| 384 | 	outbuf = malloc(maxbufsize); | 
| 385 | 	if ((inbuf == NULL) || (outbuf == NULL)) { | 
| 386 | 		stat = RPC_SYSTEMERROR; | 
| 387 | 		goto done_broad; | 
| 388 | 	} | 
| 389 |  | 
| 390 | 	/* Serialize all the arguments which have to be sent */ | 
| 391 | 	msg.rm_xid = __RPC_GETXID(); | 
| 392 | 	msg.rm_direction = CALL; | 
| 393 | 	msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; | 
| 394 | 	msg.rm_call.cb_prog = RPCBPROG; | 
| 395 | 	msg.rm_call.cb_vers = RPCBVERS; | 
| 396 | 	msg.rm_call.cb_proc = RPCBPROC_CALLIT; | 
| 397 | 	barg.prog = prog; | 
| 398 | 	barg.vers = vers; | 
| 399 | 	barg.proc = proc; | 
| 400 | 	barg.args.args_val = argsp; | 
| 401 | 	barg.xdr_args = xargs; | 
| 402 | 	bres.addr = uaddrp; | 
| 403 | 	bres.results.results_val = resultsp; | 
| 404 | 	bres.xdr_res = xresults; | 
| 405 | 	msg.rm_call.cb_cred = sys_auth->ah_cred; | 
| 406 | 	msg.rm_call.cb_verf = sys_auth->ah_verf; | 
| 407 | 	xdrmem_create(xdrs, outbuf, maxbufsize, XDR_ENCODE); | 
| 408 | 	if ((!xdr_callmsg(xdrs, &msg)) || | 
| 409 | 	    (!xdr_rpcb_rmtcallargs(xdrs, | 
| 410 | 	    (struct rpcb_rmtcallargs *)(void *)&barg))) { | 
| 411 | 		stat = RPC_CANTENCODEARGS; | 
| 412 | 		goto done_broad; | 
| 413 | 	} | 
| 414 | 	outlen = xdr_getpos(xdrs); | 
| 415 | 	xdr_destroy(xdrs); | 
| 416 |  | 
| 417 | #ifdef PORTMAP | 
| 418 | 	/* Prepare the packet for version 2 PORTMAP */ | 
| 419 | 	if (pmap_flag) { | 
| 420 | 		msg.rm_xid++;	/* One way to distinguish */ | 
| 421 | 		msg.rm_call.cb_prog = PMAPPROG; | 
| 422 | 		msg.rm_call.cb_vers = PMAPVERS; | 
| 423 | 		msg.rm_call.cb_proc = PMAPPROC_CALLIT; | 
| 424 | 		barg_pmap.prog = prog; | 
| 425 | 		barg_pmap.vers = vers; | 
| 426 | 		barg_pmap.proc = proc; | 
| 427 | 		barg_pmap.args_ptr = argsp; | 
| 428 | 		barg_pmap.xdr_args = xargs; | 
| 429 | 		bres_pmap.port_ptr = &port; | 
| 430 | 		bres_pmap.xdr_results = xresults; | 
| 431 | 		bres_pmap.results_ptr = resultsp; | 
| 432 | 		xdrmem_create(xdrs, outbuf_pmap, udpbufsz, XDR_ENCODE); | 
| 433 | 		if ((! xdr_callmsg(xdrs, &msg)) || | 
| 434 | 		    (! xdr_rmtcall_args(xdrs, &barg_pmap))) { | 
| 435 | 			stat = RPC_CANTENCODEARGS; | 
| 436 | 			goto done_broad; | 
| 437 | 		} | 
| 438 | 		outlen_pmap = xdr_getpos(xdrs); | 
| 439 | 		xdr_destroy(xdrs); | 
| 440 | 	} | 
| 441 | #endif				/* PORTMAP */ | 
| 442 |  | 
| 443 | 	/* | 
| 444 | 	 * Basic loop: broadcast the packets to transports which | 
| 445 | 	 * support data packets of size such that one can encode | 
| 446 | 	 * all the arguments. | 
| 447 | 	 * Wait a while for response(s). | 
| 448 | 	 * The response timeout grows larger per iteration. | 
| 449 | 	 */ | 
| 450 | 	for (msec = inittime; msec <= waittime; msec += msec) { | 
| 451 | 		struct broadif *bip; | 
| 452 |  | 
| 453 | 		/* Broadcast all the packets now */ | 
| 454 | 		for (i = 0; i < fdlistno; i++) { | 
| 455 | 			if (fdlist[i].dsize < outlen) { | 
| 456 | 				stat = RPC_CANTSEND; | 
| 457 | 				continue; | 
| 458 | 			} | 
| 459 | 			for (bip = TAILQ_FIRST(&fdlist[i].nal); bip != NULL; | 
| 460 | 			     bip = TAILQ_NEXT(bip, link)) { | 
| 461 | 				void *addr; | 
| 462 |  | 
| 463 | 				addr = &bip->broadaddr; | 
| 464 |  | 
| 465 | 				__rpc_broadenable(fdlist[i].af, fdlist[i].fd, | 
| 466 | 				    bip); | 
| 467 |  | 
| 468 | 				/* | 
| 469 | 				 * Only use version 3 if lowvers is not set | 
| 470 | 				 */ | 
| 471 |  | 
| 472 | 				if (!__rpc_lowvers) | 
| 473 | 					if ((size_t)sendto(fdlist[i].fd, outbuf, | 
| 474 | 					    outlen, 0, (struct sockaddr*)addr, | 
| 475 | 					    (socklen_t)fdlist[i].asize) != | 
| 476 | 					    outlen) { | 
| 477 | 						warn("clnt_bcast: cannot send"  | 
| 478 | 						      " broadcast packet" ); | 
| 479 | 						stat = RPC_CANTSEND; | 
| 480 | 						continue; | 
| 481 | 					} | 
| 482 | #ifdef RPC_DEBUG | 
| 483 | 				if (!__rpc_lowvers) | 
| 484 | 					fprintf(stderr, "Broadcast packet sent "  | 
| 485 | 						"for %s\n" , | 
| 486 | 						 fdlist[i].nconf->nc_netid); | 
| 487 | #endif | 
| 488 | #ifdef PORTMAP | 
| 489 | 				/* | 
| 490 | 				 * Send the version 2 packet also | 
| 491 | 				 * for UDP/IP | 
| 492 | 				 */ | 
| 493 | 				if (pmap_flag && | 
| 494 | 				    fdlist[i].proto == IPPROTO_UDP) { | 
| 495 | 					if ((size_t)sendto(fdlist[i].fd, | 
| 496 | 					    outbuf_pmap, outlen_pmap, 0, addr, | 
| 497 | 					    (socklen_t)fdlist[i].asize) != | 
| 498 | 						outlen_pmap) { | 
| 499 | 						warnx("clnt_bcast: "  | 
| 500 | 						    "Cannot send "  | 
| 501 | 						    "broadcast packet" ); | 
| 502 | 						stat = RPC_CANTSEND; | 
| 503 | 						continue; | 
| 504 | 					} | 
| 505 | 				} | 
| 506 | #ifdef RPC_DEBUG | 
| 507 | 				fprintf(stderr, "PMAP Broadcast packet "  | 
| 508 | 					"sent for %s\n" , | 
| 509 | 					fdlist[i].nconf->nc_netid); | 
| 510 | #endif | 
| 511 | #endif				/* PORTMAP */ | 
| 512 | 			} | 
| 513 | 			/* End for sending all packets on this transport */ | 
| 514 | 		}	/* End for sending on all transports */ | 
| 515 |  | 
| 516 | 		if (eachresult == NULL) { | 
| 517 | 			stat = RPC_SUCCESS; | 
| 518 | 			goto done_broad; | 
| 519 | 		} | 
| 520 |  | 
| 521 | 		/* | 
| 522 | 		 * Get all the replies from these broadcast requests | 
| 523 | 		 */ | 
| 524 | 	recv_again: | 
| 525 | 		ts.tv_sec = msec / 1000; | 
| 526 | 		ts.tv_nsec = (msec % 1000) * 1000000; | 
| 527 |  | 
| 528 | 		switch (pollretval = pollts(pfd, fdlistno, &ts, NULL)) { | 
| 529 | 		case 0:		/* timed out */ | 
| 530 | 			stat = RPC_TIMEDOUT; | 
| 531 | 			continue; | 
| 532 | 		case -1:	/* some kind of error - we ignore it */ | 
| 533 | 			goto recv_again; | 
| 534 | 		}		/* end of poll results switch */ | 
| 535 |  | 
| 536 | 		for (i = fds_found = 0; | 
| 537 | 		     i < fdlistno && fds_found < pollretval; i++) { | 
| 538 | 			bool_t done = FALSE; | 
| 539 |  | 
| 540 | 			if (pfd[i].revents == 0) | 
| 541 | 				continue; | 
| 542 | 			else if (pfd[i].revents & POLLNVAL) { | 
| 543 | 				/* | 
| 544 | 				 * Something bad has happened to this descri- | 
| 545 | 				 * ptor. We can cause pollts() to ignore | 
| 546 | 				 * it simply by using a negative fd.  We do that | 
| 547 | 				 * rather than compacting the pfd[] and fdlist[] | 
| 548 | 				 * arrays. | 
| 549 | 				 */ | 
| 550 | 				pfd[i].fd = -1; | 
| 551 | 				fds_found++; | 
| 552 | 				continue; | 
| 553 | 			} else | 
| 554 | 				fds_found++; | 
| 555 | #ifdef RPC_DEBUG | 
| 556 | 			fprintf(stderr, "response for %s\n" , | 
| 557 | 				fdlist[i].nconf->nc_netid); | 
| 558 | #endif | 
| 559 | 		try_again: | 
| 560 | 			inlen = recvfrom(fdlist[i].fd, inbuf, fdlist[i].dsize, | 
| 561 | 			    0, (struct sockaddr *)(void *)&fdlist[i].raddr, | 
| 562 | 			    &fdlist[i].asize); | 
| 563 | 			if (inlen < 0) { | 
| 564 | 				if (errno == EINTR) | 
| 565 | 					goto try_again; | 
| 566 | 				warnx("clnt_bcast: Cannot receive reply to "  | 
| 567 | 					"broadcast" ); | 
| 568 | 				stat = RPC_CANTRECV; | 
| 569 | 				continue; | 
| 570 | 			} | 
| 571 | 			if (inlen < (ssize_t)sizeof(u_int32_t)) | 
| 572 | 				continue; /* Drop that and go ahead */ | 
| 573 | 			/* | 
| 574 | 			 * see if reply transaction id matches sent id. | 
| 575 | 			 * If so, decode the results. If return id is xid + 1 | 
| 576 | 			 * it was a PORTMAP reply | 
| 577 | 			 */ | 
| 578 | 			if (*((u_int32_t *)(void *)(inbuf)) == | 
| 579 | 			    *((u_int32_t *)(void *)(outbuf))) { | 
| 580 | 				pmap_reply_flag = 0; | 
| 581 | 				msg.acpted_rply.ar_verf = _null_auth; | 
| 582 | 				msg.acpted_rply.ar_results.where = | 
| 583 | 					(caddr_t)(void *)&bres; | 
| 584 | 				msg.acpted_rply.ar_results.proc = | 
| 585 | 					(xdrproc_t)xdr_rpcb_rmtcallres; | 
| 586 | #ifdef PORTMAP | 
| 587 | 			} else if (pmap_flag && | 
| 588 | 				*((u_int32_t *)(void *)(inbuf)) == | 
| 589 | 				*((u_int32_t *)(void *)(outbuf_pmap))) { | 
| 590 | 				pmap_reply_flag = 1; | 
| 591 | 				msg.acpted_rply.ar_verf = _null_auth; | 
| 592 | 				msg.acpted_rply.ar_results.where = | 
| 593 | 					(caddr_t)(void *)&bres_pmap; | 
| 594 | 				msg.acpted_rply.ar_results.proc = | 
| 595 | 					(xdrproc_t)xdr_rmtcallres; | 
| 596 | #endif				/* PORTMAP */ | 
| 597 | 			} else | 
| 598 | 				continue; | 
| 599 | 			xdrmem_create(xdrs, inbuf, (u_int)inlen, XDR_DECODE); | 
| 600 | 			if (xdr_replymsg(xdrs, &msg)) { | 
| 601 | 				if ((msg.rm_reply.rp_stat == MSG_ACCEPTED) && | 
| 602 | 				    (msg.acpted_rply.ar_stat == SUCCESS)) { | 
| 603 | 					struct netbuf taddr, *np; | 
| 604 | 					struct sockaddr_in *bsin; | 
| 605 |  | 
| 606 | #ifdef PORTMAP | 
| 607 | 					if (pmap_flag && pmap_reply_flag) { | 
| 608 | 						bsin = (struct sockaddr_in *) | 
| 609 | 						    (void *)&fdlist[i].raddr; | 
| 610 | 						bsin->sin_port = | 
| 611 | 						    htons((u_short)port); | 
| 612 | 						taddr.len = taddr.maxlen =  | 
| 613 | 						    fdlist[i].raddr.ss_len; | 
| 614 | 						taddr.buf = &fdlist[i].raddr; | 
| 615 | 						done = (*eachresult)(resultsp, | 
| 616 | 						    &taddr, fdlist[i].nconf); | 
| 617 | 					} else { | 
| 618 | #endif | 
| 619 | #ifdef RPC_DEBUG | 
| 620 | 						fprintf(stderr, "uaddr %s\n" , | 
| 621 | 						    uaddrp); | 
| 622 | #endif | 
| 623 | 						np = uaddr2taddr( | 
| 624 | 						    fdlist[i].nconf, uaddrp); | 
| 625 | 						done = (*eachresult)(resultsp, | 
| 626 | 						    np, fdlist[i].nconf); | 
| 627 | 						free(np); | 
| 628 | #ifdef PORTMAP | 
| 629 | 					} | 
| 630 | #endif | 
| 631 | 				} | 
| 632 | 				/* otherwise, we just ignore the errors ... */ | 
| 633 | 			} | 
| 634 | 			/* else some kind of deserialization problem ... */ | 
| 635 |  | 
| 636 | 			xdrs->x_op = XDR_FREE; | 
| 637 | 			msg.acpted_rply.ar_results.proc = (xdrproc_t) xdr_void; | 
| 638 | 			(void) xdr_replymsg(xdrs, &msg); | 
| 639 | 			(void) (*xresults)(xdrs, resultsp); | 
| 640 | 			XDR_DESTROY(xdrs); | 
| 641 | 			if (done) { | 
| 642 | 				stat = RPC_SUCCESS; | 
| 643 | 				goto done_broad; | 
| 644 | 			} else { | 
| 645 | 				goto recv_again; | 
| 646 | 			} | 
| 647 | 		}		/* The recv for loop */ | 
| 648 | 	}			/* The giant for loop */ | 
| 649 |  | 
| 650 | done_broad: | 
| 651 | 	if (inbuf) | 
| 652 | 		(void) free(inbuf); | 
| 653 | 	if (outbuf) | 
| 654 | 		(void) free(outbuf); | 
| 655 | #ifdef PORTMAP | 
| 656 | 	if (outbuf_pmap) | 
| 657 | 		(void) free(outbuf_pmap); | 
| 658 | #endif | 
| 659 | 	for (i = 0; i < fdlistno; i++) { | 
| 660 | 		(void) close(fdlist[i].fd); | 
| 661 | 		__rpc_freebroadifs(&fdlist[i].nal); | 
| 662 | 	} | 
| 663 | 	AUTH_DESTROY(sys_auth); | 
| 664 | 	(void) __rpc_endconf(handle); | 
| 665 |  | 
| 666 | 	return (stat); | 
| 667 | } | 
| 668 |  | 
| 669 |  | 
| 670 | enum clnt_stat | 
| 671 | rpc_broadcast( | 
| 672 | 	rpcprog_t	prog,		/* program number */ | 
| 673 | 	rpcvers_t	vers,		/* version number */ | 
| 674 | 	rpcproc_t	proc,		/* procedure number */ | 
| 675 | 	xdrproc_t	xargs,		/* xdr routine for args */ | 
| 676 | 	const char *	argsp,		/* pointer to args */ | 
| 677 | 	xdrproc_t	xresults,	/* xdr routine for results */ | 
| 678 | 	caddr_t		resultsp,	/* pointer to results */ | 
| 679 | 	resultproc_t	eachresult,	/* call with each result obtained */ | 
| 680 | 	const char *	nettype)	/* transport type */ | 
| 681 | { | 
| 682 | 	enum clnt_stat	dummy; | 
| 683 |  | 
| 684 | 	dummy = rpc_broadcast_exp(prog, vers, proc, xargs, argsp, | 
| 685 | 		xresults, resultsp, eachresult, | 
| 686 | 		INITTIME, WAITTIME, nettype); | 
| 687 | 	return (dummy); | 
| 688 | } | 
| 689 |  |