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