174462Salfred/* $NetBSD: clnt_bcast.c,v 1.3 2000/07/06 03:05:20 christos Exp $ */ 274462Salfred 374462Salfred/* 474462Salfred * Sun RPC is a product of Sun Microsystems, Inc. and is provided for 574462Salfred * unrestricted use provided that this legend is included on all tape 674462Salfred * media and as a part of the software program in whole or part. Users 774462Salfred * may copy or modify Sun RPC without charge, but are not authorized 874462Salfred * to license or distribute it to anyone else except as part of a product or 974462Salfred * program developed by the user. 1074462Salfred * 1174462Salfred * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE 1274462Salfred * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 1374462Salfred * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. 1474462Salfred * 1574462Salfred * Sun RPC is provided with no support and without any obligation on the 1674462Salfred * part of Sun Microsystems, Inc. to assist in its use, correction, 1774462Salfred * modification or enhancement. 1874462Salfred * 1974462Salfred * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE 2074462Salfred * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC 2174462Salfred * OR ANY PART THEREOF. 2274462Salfred * 2374462Salfred * In no event will Sun Microsystems, Inc. be liable for any lost revenue 2474462Salfred * or profits or other special, indirect and consequential damages, even if 2574462Salfred * Sun has been advised of the possibility of such damages. 2674462Salfred * 2774462Salfred * Sun Microsystems, Inc. 2874462Salfred * 2550 Garcia Avenue 2974462Salfred * Mountain View, California 94043 3074462Salfred */ 3174462Salfred/* 3274462Salfred * Copyright (c) 1986-1991 by Sun Microsystems Inc. 3374462Salfred */ 3474462Salfred 35136581Sobrien#if defined(LIBC_SCCS) && !defined(lint) 36136581Sobrien#ident "@(#)clnt_bcast.c 1.18 94/05/03 SMI" 3774462Salfredstatic char sccsid[] = "@(#)clnt_bcast.c 1.15 89/04/21 Copyr 1988 Sun Micro"; 3874462Salfred#endif 3992990Sobrien#include <sys/cdefs.h> 4092990Sobrien__FBSDID("$FreeBSD$"); 4174462Salfred 4274462Salfred 4374462Salfred/* 4474462Salfred * clnt_bcast.c 4574462Salfred * Client interface to broadcast service. 4674462Salfred * 4774462Salfred * Copyright (C) 1988, Sun Microsystems, Inc. 4874462Salfred * 4974462Salfred * The following is kludged-up support for simple rpc broadcasts. 5074462Salfred * Someday a large, complicated system will replace these routines. 5174462Salfred */ 5274462Salfred 5374462Salfred#include "namespace.h" 5474462Salfred#include <sys/types.h> 5574462Salfred#include <sys/socket.h> 5674462Salfred#include <sys/queue.h> 5774462Salfred#include <net/if.h> 5874462Salfred#include <netinet/in.h> 5974462Salfred#include <ifaddrs.h> 6074462Salfred#include <sys/poll.h> 6174462Salfred#include <rpc/rpc.h> 6274462Salfred#ifdef PORTMAP 6374462Salfred#include <rpc/pmap_prot.h> 6474462Salfred#include <rpc/pmap_clnt.h> 6574462Salfred#include <rpc/pmap_rmt.h> 6674462Salfred#endif /* PORTMAP */ 6774462Salfred#include <rpc/nettype.h> 6874462Salfred#include <arpa/inet.h> 6974462Salfred#ifdef RPC_DEBUG 7074462Salfred#include <stdio.h> 7174462Salfred#endif 7274462Salfred#include <errno.h> 7374462Salfred#include <stdlib.h> 7474462Salfred#include <unistd.h> 7574462Salfred#include <netdb.h> 7674462Salfred#include <err.h> 7774462Salfred#include <string.h> 7874462Salfred#include "un-namespace.h" 7974462Salfred 8074462Salfred#include "rpc_com.h" 8174462Salfred 8274462Salfred#define MAXBCAST 20 /* Max no of broadcasting transports */ 8374462Salfred#define INITTIME 4000 /* Time to wait initially */ 8474462Salfred#define WAITTIME 8000 /* Maximum time to wait */ 8574462Salfred 8674462Salfred/* 8774462Salfred * If nettype is NULL, it broadcasts on all the available 8874462Salfred * datagram_n transports. May potentially lead to broadacst storms 8974462Salfred * and hence should be used with caution, care and courage. 9074462Salfred * 9174462Salfred * The current parameter xdr packet size is limited by the max tsdu 9274462Salfred * size of the transport. If the max tsdu size of any transport is 9374462Salfred * smaller than the parameter xdr packet, then broadcast is not 9474462Salfred * sent on that transport. 9574462Salfred * 9674462Salfred * Also, the packet size should be less the packet size of 9774462Salfred * the data link layer (for ethernet it is 1400 bytes). There is 9874462Salfred * no easy way to find out the max size of the data link layer and 9974462Salfred * we are assuming that the args would be smaller than that. 10074462Salfred * 10174462Salfred * The result size has to be smaller than the transport tsdu size. 10274462Salfred * 10374462Salfred * If PORTMAP has been defined, we send two packets for UDP, one for 10474462Salfred * rpcbind and one for portmap. For those machines which support 10574462Salfred * both rpcbind and portmap, it will cause them to reply twice, and 10674462Salfred * also here it will get two responses ... inefficient and clumsy. 10774462Salfred */ 10874462Salfred 10974462Salfredstruct broadif { 11074462Salfred int index; 11174462Salfred struct sockaddr_storage broadaddr; 11274462Salfred TAILQ_ENTRY(broadif) link; 11374462Salfred}; 11474462Salfred 11574462Salfredtypedef TAILQ_HEAD(, broadif) broadlist_t; 11674462Salfred 11792905Sobrienint __rpc_getbroadifs(int, int, int, broadlist_t *); 11892905Sobrienvoid __rpc_freebroadifs(broadlist_t *); 11992905Sobrienint __rpc_broadenable(int, int, struct broadif *); 12074462Salfred 12174462Salfredint __rpc_lowvers = 0; 12274462Salfred 12374462Salfredint 12474462Salfred__rpc_getbroadifs(int af, int proto, int socktype, broadlist_t *list) 12574462Salfred{ 12674462Salfred int count = 0; 12774462Salfred struct broadif *bip; 12874462Salfred struct ifaddrs *ifap, *ifp; 12974462Salfred#ifdef INET6 13074462Salfred struct sockaddr_in6 *sin6; 13174462Salfred#endif 13274462Salfred struct sockaddr_in *sin; 13374462Salfred struct addrinfo hints, *res; 13474462Salfred 13574462Salfred if (getifaddrs(&ifp) < 0) 13674462Salfred return 0; 13774462Salfred 13874462Salfred memset(&hints, 0, sizeof hints); 13974462Salfred 14074462Salfred hints.ai_family = af; 14174462Salfred hints.ai_protocol = proto; 14274462Salfred hints.ai_socktype = socktype; 14374462Salfred 144162189Smbr if (getaddrinfo(NULL, "sunrpc", &hints, &res) != 0) { 145162189Smbr freeifaddrs(ifp); 14674462Salfred return 0; 147162189Smbr } 14874462Salfred 14974462Salfred for (ifap = ifp; ifap != NULL; ifap = ifap->ifa_next) { 15074462Salfred if (ifap->ifa_addr->sa_family != af || 15174462Salfred !(ifap->ifa_flags & IFF_UP)) 15274462Salfred continue; 15374462Salfred bip = (struct broadif *)malloc(sizeof *bip); 15474462Salfred if (bip == NULL) 15574462Salfred break; 15674462Salfred bip->index = if_nametoindex(ifap->ifa_name); 157109955Smbr if ( 15874462Salfred#ifdef INET6 159109955Smbr af != AF_INET6 && 16074462Salfred#endif 161109955Smbr (ifap->ifa_flags & IFF_BROADCAST) && 162109955Smbr ifap->ifa_broadaddr) { 16374462Salfred memcpy(&bip->broadaddr, ifap->ifa_broadaddr, 16474462Salfred (size_t)ifap->ifa_broadaddr->sa_len); 16574462Salfred sin = (struct sockaddr_in *)(void *)&bip->broadaddr; 16674462Salfred sin->sin_port = 16774462Salfred ((struct sockaddr_in *) 16874462Salfred (void *)res->ai_addr)->sin_port; 169109955Smbr } else 17074462Salfred#ifdef INET6 171109955Smbr if (af == AF_INET6 && (ifap->ifa_flags & IFF_MULTICAST)) { 17274462Salfred sin6 = (struct sockaddr_in6 *)(void *)&bip->broadaddr; 17374462Salfred inet_pton(af, RPCB_MULTICAST_ADDR, &sin6->sin6_addr); 17474462Salfred sin6->sin6_family = af; 17574462Salfred sin6->sin6_len = sizeof *sin6; 17674462Salfred sin6->sin6_port = 17774462Salfred ((struct sockaddr_in6 *) 17874462Salfred (void *)res->ai_addr)->sin6_port; 17974462Salfred sin6->sin6_scope_id = bip->index; 180109955Smbr } else 18174462Salfred#endif 182109955Smbr { 183109955Smbr free(bip); 184109955Smbr continue; 18574462Salfred } 18674462Salfred TAILQ_INSERT_TAIL(list, bip, link); 18774462Salfred count++; 18874462Salfred } 18974462Salfred freeifaddrs(ifp); 19074462Salfred freeaddrinfo(res); 19174462Salfred 19274462Salfred return count; 19374462Salfred} 19474462Salfred 19574462Salfredvoid 19674462Salfred__rpc_freebroadifs(broadlist_t *list) 19774462Salfred{ 19874462Salfred struct broadif *bip, *next; 19974462Salfred 20074462Salfred bip = TAILQ_FIRST(list); 20174462Salfred 20274462Salfred while (bip != NULL) { 20374462Salfred next = TAILQ_NEXT(bip, link); 20474462Salfred free(bip); 20574462Salfred bip = next; 20674462Salfred } 20774462Salfred} 20874462Salfred 20974462Salfredint 21074462Salfred/*ARGSUSED*/ 21174462Salfred__rpc_broadenable(int af, int s, struct broadif *bip) 21274462Salfred{ 21374462Salfred int o = 1; 21474462Salfred 21574462Salfred#if 0 21674462Salfred if (af == AF_INET6) { 21774462Salfred fprintf(stderr, "set v6 multicast if to %d\n", bip->index); 21874462Salfred if (_setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, &bip->index, 21974462Salfred sizeof bip->index) < 0) 22074462Salfred return -1; 22174462Salfred } else 22274462Salfred#endif 22374462Salfred if (_setsockopt(s, SOL_SOCKET, SO_BROADCAST, &o, sizeof o) < 0) 22474462Salfred return -1; 22574462Salfred 22674462Salfred return 0; 22774462Salfred} 22874462Salfred 22974462Salfred 23074462Salfredenum clnt_stat 23174462Salfredrpc_broadcast_exp(prog, vers, proc, xargs, argsp, xresults, resultsp, 23274462Salfred eachresult, inittime, waittime, nettype) 23374462Salfred rpcprog_t prog; /* program number */ 23474462Salfred rpcvers_t vers; /* version number */ 23574462Salfred rpcproc_t proc; /* procedure number */ 23674462Salfred xdrproc_t xargs; /* xdr routine for args */ 23774462Salfred caddr_t argsp; /* pointer to args */ 23874462Salfred xdrproc_t xresults; /* xdr routine for results */ 23974462Salfred caddr_t resultsp; /* pointer to results */ 24074462Salfred resultproc_t eachresult; /* call with each result obtained */ 24174462Salfred int inittime; /* how long to wait initially */ 24274462Salfred int waittime; /* maximum time to wait */ 24374462Salfred const char *nettype; /* transport type */ 24474462Salfred{ 24574462Salfred enum clnt_stat stat = RPC_SUCCESS; /* Return status */ 24674462Salfred XDR xdr_stream; /* XDR stream */ 24774462Salfred XDR *xdrs = &xdr_stream; 24874462Salfred struct rpc_msg msg; /* RPC message */ 24974462Salfred struct timeval t; 25074462Salfred char *outbuf = NULL; /* Broadcast msg buffer */ 25174462Salfred char *inbuf = NULL; /* Reply buf */ 25274462Salfred int inlen; 25374462Salfred u_int maxbufsize = 0; 25474462Salfred AUTH *sys_auth = authunix_create_default(); 25574462Salfred int i; 25674462Salfred void *handle; 25774462Salfred char uaddress[1024]; /* A self imposed limit */ 25874462Salfred char *uaddrp = uaddress; 25974462Salfred int pmap_reply_flag; /* reply recvd from PORTMAP */ 26074462Salfred /* An array of all the suitable broadcast transports */ 26174462Salfred struct { 26274462Salfred int fd; /* File descriptor */ 26374462Salfred int af; 26474462Salfred int proto; 26574462Salfred struct netconfig *nconf; /* Netconfig structure */ 26674462Salfred u_int asize; /* Size of the addr buf */ 26774462Salfred u_int dsize; /* Size of the data buf */ 26874462Salfred struct sockaddr_storage raddr; /* Remote address */ 26974462Salfred broadlist_t nal; 27074462Salfred } fdlist[MAXBCAST]; 27174462Salfred struct pollfd pfd[MAXBCAST]; 27274462Salfred size_t fdlistno = 0; 27374462Salfred struct r_rpcb_rmtcallargs barg; /* Remote arguments */ 27474462Salfred struct r_rpcb_rmtcallres bres; /* Remote results */ 27590271Salfred size_t outlen; 27674462Salfred struct netconfig *nconf; 27774462Salfred int msec; 27874462Salfred int pollretval; 27974462Salfred int fds_found; 28074462Salfred 28174462Salfred#ifdef PORTMAP 28290271Salfred size_t outlen_pmap = 0; 28374462Salfred u_long port; /* Remote port number */ 28474462Salfred int pmap_flag = 0; /* UDP exists ? */ 28574462Salfred char *outbuf_pmap = NULL; 28674462Salfred struct rmtcallargs barg_pmap; /* Remote arguments */ 28774462Salfred struct rmtcallres bres_pmap; /* Remote results */ 28874462Salfred u_int udpbufsz = 0; 28974462Salfred#endif /* PORTMAP */ 29074462Salfred 29174462Salfred if (sys_auth == NULL) { 29274462Salfred return (RPC_SYSTEMERROR); 29374462Salfred } 29474462Salfred /* 29574462Salfred * initialization: create a fd, a broadcast address, and send the 29674462Salfred * request on the broadcast transport. 29774462Salfred * Listen on all of them and on replies, call the user supplied 29874462Salfred * function. 29974462Salfred */ 30074462Salfred 30174462Salfred if (nettype == NULL) 30274462Salfred nettype = "datagram_n"; 30374462Salfred if ((handle = __rpc_setconf(nettype)) == NULL) { 304162189Smbr AUTH_DESTROY(sys_auth); 30574462Salfred return (RPC_UNKNOWNPROTO); 30674462Salfred } 30774462Salfred while ((nconf = __rpc_getconf(handle)) != NULL) { 30874462Salfred int fd; 30974462Salfred struct __rpc_sockinfo si; 31074462Salfred 31174462Salfred if (nconf->nc_semantics != NC_TPI_CLTS) 31274462Salfred continue; 31374462Salfred if (fdlistno >= MAXBCAST) 31474462Salfred break; /* No more slots available */ 31574462Salfred if (!__rpc_nconf2sockinfo(nconf, &si)) 31674462Salfred continue; 31774462Salfred 31874462Salfred TAILQ_INIT(&fdlist[fdlistno].nal); 31974462Salfred if (__rpc_getbroadifs(si.si_af, si.si_proto, si.si_socktype, 32074462Salfred &fdlist[fdlistno].nal) == 0) 32174462Salfred continue; 32274462Salfred 32374462Salfred fd = _socket(si.si_af, si.si_socktype, si.si_proto); 32474462Salfred if (fd < 0) { 32574462Salfred stat = RPC_CANTSEND; 32674462Salfred continue; 32774462Salfred } 32874462Salfred fdlist[fdlistno].af = si.si_af; 32974462Salfred fdlist[fdlistno].proto = si.si_proto; 33074462Salfred fdlist[fdlistno].fd = fd; 33174462Salfred fdlist[fdlistno].nconf = nconf; 33274462Salfred fdlist[fdlistno].asize = __rpc_get_a_size(si.si_af); 33374462Salfred pfd[fdlistno].events = POLLIN | POLLPRI | 33474462Salfred POLLRDNORM | POLLRDBAND; 33574462Salfred pfd[fdlistno].fd = fdlist[fdlistno].fd = fd; 33674462Salfred fdlist[fdlistno].dsize = __rpc_get_t_size(si.si_af, si.si_proto, 33774462Salfred 0); 33874462Salfred 33974462Salfred if (maxbufsize <= fdlist[fdlistno].dsize) 34074462Salfred maxbufsize = fdlist[fdlistno].dsize; 34174462Salfred 34274462Salfred#ifdef PORTMAP 34374462Salfred if (si.si_af == AF_INET && si.si_proto == IPPROTO_UDP) { 34474462Salfred udpbufsz = fdlist[fdlistno].dsize; 34574462Salfred if ((outbuf_pmap = malloc(udpbufsz)) == NULL) { 34674462Salfred _close(fd); 34774462Salfred stat = RPC_SYSTEMERROR; 34874462Salfred goto done_broad; 34974462Salfred } 35074462Salfred pmap_flag = 1; 35174462Salfred } 35274462Salfred#endif /* PORTMAP */ 35374462Salfred fdlistno++; 35474462Salfred } 35574462Salfred 35674462Salfred if (fdlistno == 0) { 35774462Salfred if (stat == RPC_SUCCESS) 35874462Salfred stat = RPC_UNKNOWNPROTO; 35974462Salfred goto done_broad; 36074462Salfred } 36174462Salfred if (maxbufsize == 0) { 36274462Salfred if (stat == RPC_SUCCESS) 36374462Salfred stat = RPC_CANTSEND; 36474462Salfred goto done_broad; 36574462Salfred } 36674462Salfred inbuf = malloc(maxbufsize); 36774462Salfred outbuf = malloc(maxbufsize); 36874462Salfred if ((inbuf == NULL) || (outbuf == NULL)) { 36974462Salfred stat = RPC_SYSTEMERROR; 37074462Salfred goto done_broad; 37174462Salfred } 37274462Salfred 37374462Salfred /* Serialize all the arguments which have to be sent */ 37474462Salfred (void) gettimeofday(&t, NULL); 37574462Salfred msg.rm_xid = __RPC_GETXID(&t); 37674462Salfred msg.rm_direction = CALL; 37774462Salfred msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; 37874462Salfred msg.rm_call.cb_prog = RPCBPROG; 37974462Salfred msg.rm_call.cb_vers = RPCBVERS; 38074462Salfred msg.rm_call.cb_proc = RPCBPROC_CALLIT; 38174462Salfred barg.prog = prog; 38274462Salfred barg.vers = vers; 38374462Salfred barg.proc = proc; 38474462Salfred barg.args.args_val = argsp; 38574462Salfred barg.xdr_args = xargs; 38674462Salfred bres.addr = uaddrp; 38774462Salfred bres.results.results_val = resultsp; 38874462Salfred bres.xdr_res = xresults; 38974462Salfred msg.rm_call.cb_cred = sys_auth->ah_cred; 39074462Salfred msg.rm_call.cb_verf = sys_auth->ah_verf; 39174462Salfred xdrmem_create(xdrs, outbuf, maxbufsize, XDR_ENCODE); 39274462Salfred if ((!xdr_callmsg(xdrs, &msg)) || 39374462Salfred (!xdr_rpcb_rmtcallargs(xdrs, 39474462Salfred (struct rpcb_rmtcallargs *)(void *)&barg))) { 39574462Salfred stat = RPC_CANTENCODEARGS; 39674462Salfred goto done_broad; 39774462Salfred } 39874462Salfred outlen = xdr_getpos(xdrs); 39974462Salfred xdr_destroy(xdrs); 40074462Salfred 40174462Salfred#ifdef PORTMAP 40274462Salfred /* Prepare the packet for version 2 PORTMAP */ 40374462Salfred if (pmap_flag) { 40474462Salfred msg.rm_xid++; /* One way to distinguish */ 40574462Salfred msg.rm_call.cb_prog = PMAPPROG; 40674462Salfred msg.rm_call.cb_vers = PMAPVERS; 40774462Salfred msg.rm_call.cb_proc = PMAPPROC_CALLIT; 40874462Salfred barg_pmap.prog = prog; 40974462Salfred barg_pmap.vers = vers; 41074462Salfred barg_pmap.proc = proc; 41174462Salfred barg_pmap.args_ptr = argsp; 41274462Salfred barg_pmap.xdr_args = xargs; 41374462Salfred bres_pmap.port_ptr = &port; 41474462Salfred bres_pmap.xdr_results = xresults; 41574462Salfred bres_pmap.results_ptr = resultsp; 41674462Salfred xdrmem_create(xdrs, outbuf_pmap, udpbufsz, XDR_ENCODE); 41774462Salfred if ((! xdr_callmsg(xdrs, &msg)) || 41874462Salfred (! xdr_rmtcall_args(xdrs, &barg_pmap))) { 41974462Salfred stat = RPC_CANTENCODEARGS; 42074462Salfred goto done_broad; 42174462Salfred } 42274462Salfred outlen_pmap = xdr_getpos(xdrs); 42374462Salfred xdr_destroy(xdrs); 42474462Salfred } 42587966Speter#endif /* PORTMAP */ 42674462Salfred 42774462Salfred /* 42874462Salfred * Basic loop: broadcast the packets to transports which 42974462Salfred * support data packets of size such that one can encode 43074462Salfred * all the arguments. 43174462Salfred * Wait a while for response(s). 43274462Salfred * The response timeout grows larger per iteration. 43374462Salfred */ 43474462Salfred for (msec = inittime; msec <= waittime; msec += msec) { 43574462Salfred struct broadif *bip; 43674462Salfred 43774462Salfred /* Broadcast all the packets now */ 43874462Salfred for (i = 0; i < fdlistno; i++) { 43974462Salfred if (fdlist[i].dsize < outlen) { 44074462Salfred stat = RPC_CANTSEND; 44174462Salfred continue; 44274462Salfred } 44374462Salfred for (bip = TAILQ_FIRST(&fdlist[i].nal); bip != NULL; 44474462Salfred bip = TAILQ_NEXT(bip, link)) { 44574462Salfred void *addr; 44674462Salfred 44774462Salfred addr = &bip->broadaddr; 44874462Salfred 44974462Salfred __rpc_broadenable(fdlist[i].af, fdlist[i].fd, 45074462Salfred bip); 45174462Salfred 45274462Salfred /* 45374462Salfred * Only use version 3 if lowvers is not set 45474462Salfred */ 45574462Salfred 45674462Salfred if (!__rpc_lowvers) 45774462Salfred if (_sendto(fdlist[i].fd, outbuf, 45874462Salfred outlen, 0, (struct sockaddr*)addr, 45974462Salfred (size_t)fdlist[i].asize) != 46074462Salfred outlen) { 46174462Salfred#ifdef RPC_DEBUG 46274462Salfred perror("sendto"); 46374462Salfred#endif 464190871Semaste warnx("clnt_bcast: cannot send " 46574462Salfred "broadcast packet"); 46674462Salfred stat = RPC_CANTSEND; 46774462Salfred continue; 46874462Salfred }; 46974462Salfred#ifdef RPC_DEBUG 47074462Salfred if (!__rpc_lowvers) 47174462Salfred fprintf(stderr, "Broadcast packet sent " 47274462Salfred "for %s\n", 47374462Salfred fdlist[i].nconf->nc_netid); 47474462Salfred#endif 47574462Salfred#ifdef PORTMAP 47674462Salfred /* 47774462Salfred * Send the version 2 packet also 47874462Salfred * for UDP/IP 47974462Salfred */ 480109954Smbr if (pmap_flag && 481109954Smbr fdlist[i].proto == IPPROTO_UDP) { 48274462Salfred if (_sendto(fdlist[i].fd, outbuf_pmap, 48374462Salfred outlen_pmap, 0, addr, 48474462Salfred (size_t)fdlist[i].asize) != 48574462Salfred outlen_pmap) { 48674462Salfred warnx("clnt_bcast: " 48774462Salfred "Cannot send broadcast packet"); 48874462Salfred stat = RPC_CANTSEND; 48974462Salfred continue; 49074462Salfred } 49174462Salfred } 49274462Salfred#ifdef RPC_DEBUG 49374462Salfred fprintf(stderr, "PMAP Broadcast packet " 49474462Salfred "sent for %s\n", 49574462Salfred fdlist[i].nconf->nc_netid); 49674462Salfred#endif 49774462Salfred#endif /* PORTMAP */ 49874462Salfred } 49974462Salfred /* End for sending all packets on this transport */ 50074462Salfred } /* End for sending on all transports */ 50174462Salfred 50274462Salfred if (eachresult == NULL) { 50374462Salfred stat = RPC_SUCCESS; 50474462Salfred goto done_broad; 50574462Salfred } 50674462Salfred 50774462Salfred /* 50874462Salfred * Get all the replies from these broadcast requests 50974462Salfred */ 51074462Salfred recv_again: 51174462Salfred 51274462Salfred switch (pollretval = _poll(pfd, fdlistno, msec)) { 51374462Salfred case 0: /* timed out */ 51474462Salfred stat = RPC_TIMEDOUT; 51574462Salfred continue; 51674462Salfred case -1: /* some kind of error - we ignore it */ 51774462Salfred goto recv_again; 51874462Salfred } /* end of poll results switch */ 51974462Salfred 52074462Salfred for (i = fds_found = 0; 52174462Salfred i < fdlistno && fds_found < pollretval; i++) { 52274462Salfred bool_t done = FALSE; 52374462Salfred 52474462Salfred if (pfd[i].revents == 0) 52574462Salfred continue; 52674462Salfred else if (pfd[i].revents & POLLNVAL) { 52774462Salfred /* 52874462Salfred * Something bad has happened to this descri- 52974462Salfred * ptor. We can cause _poll() to ignore 53074462Salfred * it simply by using a negative fd. We do that 53174462Salfred * rather than compacting the pfd[] and fdlist[] 53274462Salfred * arrays. 53374462Salfred */ 53474462Salfred pfd[i].fd = -1; 53574462Salfred fds_found++; 53674462Salfred continue; 53774462Salfred } else 53874462Salfred fds_found++; 53974462Salfred#ifdef RPC_DEBUG 54074462Salfred fprintf(stderr, "response for %s\n", 54174462Salfred fdlist[i].nconf->nc_netid); 54274462Salfred#endif 54374462Salfred try_again: 54474462Salfred inlen = _recvfrom(fdlist[i].fd, inbuf, fdlist[i].dsize, 54574462Salfred 0, (struct sockaddr *)(void *)&fdlist[i].raddr, 54674462Salfred &fdlist[i].asize); 54774462Salfred if (inlen < 0) { 54874462Salfred if (errno == EINTR) 54974462Salfred goto try_again; 55074462Salfred warnx("clnt_bcast: Cannot receive reply to " 55174462Salfred "broadcast"); 55274462Salfred stat = RPC_CANTRECV; 55374462Salfred continue; 55474462Salfred } 55574462Salfred if (inlen < sizeof (u_int32_t)) 55674462Salfred continue; /* Drop that and go ahead */ 55774462Salfred /* 55874462Salfred * see if reply transaction id matches sent id. 55974462Salfred * If so, decode the results. If return id is xid + 1 56074462Salfred * it was a PORTMAP reply 56174462Salfred */ 56274462Salfred if (*((u_int32_t *)(void *)(inbuf)) == 56374462Salfred *((u_int32_t *)(void *)(outbuf))) { 56474462Salfred pmap_reply_flag = 0; 56574462Salfred msg.acpted_rply.ar_verf = _null_auth; 56674462Salfred msg.acpted_rply.ar_results.where = 56774462Salfred (caddr_t)(void *)&bres; 56874462Salfred msg.acpted_rply.ar_results.proc = 56974462Salfred (xdrproc_t)xdr_rpcb_rmtcallres; 57074462Salfred#ifdef PORTMAP 57174462Salfred } else if (pmap_flag && 57274462Salfred *((u_int32_t *)(void *)(inbuf)) == 57374462Salfred *((u_int32_t *)(void *)(outbuf_pmap))) { 57474462Salfred pmap_reply_flag = 1; 57574462Salfred msg.acpted_rply.ar_verf = _null_auth; 57674462Salfred msg.acpted_rply.ar_results.where = 57774462Salfred (caddr_t)(void *)&bres_pmap; 57874462Salfred msg.acpted_rply.ar_results.proc = 57974462Salfred (xdrproc_t)xdr_rmtcallres; 58074462Salfred#endif /* PORTMAP */ 58174462Salfred } else 58274462Salfred continue; 58374462Salfred xdrmem_create(xdrs, inbuf, (u_int)inlen, XDR_DECODE); 58474462Salfred if (xdr_replymsg(xdrs, &msg)) { 58574462Salfred if ((msg.rm_reply.rp_stat == MSG_ACCEPTED) && 58674462Salfred (msg.acpted_rply.ar_stat == SUCCESS)) { 58774462Salfred struct netbuf taddr, *np; 58874462Salfred struct sockaddr_in *sin; 58974462Salfred 59074462Salfred#ifdef PORTMAP 59174462Salfred if (pmap_flag && pmap_reply_flag) { 59274462Salfred sin = (struct sockaddr_in *) 59374462Salfred (void *)&fdlist[i].raddr; 59474462Salfred sin->sin_port = 59574462Salfred htons((u_short)port); 59674462Salfred taddr.len = taddr.maxlen = 59774462Salfred fdlist[i].raddr.ss_len; 59874462Salfred taddr.buf = &fdlist[i].raddr; 59974462Salfred done = (*eachresult)(resultsp, 60074462Salfred &taddr, fdlist[i].nconf); 60174462Salfred } else { 60274462Salfred#endif /* PORTMAP */ 60374462Salfred#ifdef RPC_DEBUG 60474462Salfred fprintf(stderr, "uaddr %s\n", 60574462Salfred uaddrp); 60674462Salfred#endif 60774462Salfred np = uaddr2taddr( 60874462Salfred fdlist[i].nconf, uaddrp); 60974462Salfred done = (*eachresult)(resultsp, 61074462Salfred np, fdlist[i].nconf); 61174462Salfred free(np); 61274462Salfred#ifdef PORTMAP 61374462Salfred } 61474462Salfred#endif /* PORTMAP */ 61574462Salfred } 61674462Salfred /* otherwise, we just ignore the errors ... */ 61774462Salfred } 61874462Salfred /* else some kind of deserialization problem ... */ 61974462Salfred 62074462Salfred xdrs->x_op = XDR_FREE; 62174462Salfred msg.acpted_rply.ar_results.proc = (xdrproc_t) xdr_void; 62274462Salfred (void) xdr_replymsg(xdrs, &msg); 62374462Salfred (void) (*xresults)(xdrs, resultsp); 62474462Salfred XDR_DESTROY(xdrs); 62574462Salfred if (done) { 62674462Salfred stat = RPC_SUCCESS; 62774462Salfred goto done_broad; 62874462Salfred } else { 62974462Salfred goto recv_again; 63074462Salfred } 63174462Salfred } /* The recv for loop */ 63274462Salfred } /* The giant for loop */ 63374462Salfred 63474462Salfreddone_broad: 63574462Salfred if (inbuf) 63674462Salfred (void) free(inbuf); 63774462Salfred if (outbuf) 63874462Salfred (void) free(outbuf); 63974462Salfred#ifdef PORTMAP 64074462Salfred if (outbuf_pmap) 64174462Salfred (void) free(outbuf_pmap); 64274462Salfred#endif /* PORTMAP */ 64374462Salfred for (i = 0; i < fdlistno; i++) { 64474462Salfred (void)_close(fdlist[i].fd); 64574462Salfred __rpc_freebroadifs(&fdlist[i].nal); 64674462Salfred } 64774462Salfred AUTH_DESTROY(sys_auth); 64874462Salfred (void) __rpc_endconf(handle); 64974462Salfred 65074462Salfred return (stat); 65174462Salfred} 65274462Salfred 65374462Salfred 65474462Salfredenum clnt_stat 65574462Salfredrpc_broadcast(prog, vers, proc, xargs, argsp, xresults, resultsp, 65674462Salfred eachresult, nettype) 65774462Salfred rpcprog_t prog; /* program number */ 65874462Salfred rpcvers_t vers; /* version number */ 65974462Salfred rpcproc_t proc; /* procedure number */ 66074462Salfred xdrproc_t xargs; /* xdr routine for args */ 66174462Salfred caddr_t argsp; /* pointer to args */ 66274462Salfred xdrproc_t xresults; /* xdr routine for results */ 66374462Salfred caddr_t resultsp; /* pointer to results */ 66474462Salfred resultproc_t eachresult; /* call with each result obtained */ 66574462Salfred const char *nettype; /* transport type */ 66674462Salfred{ 66774462Salfred enum clnt_stat dummy; 66874462Salfred 66974462Salfred dummy = rpc_broadcast_exp(prog, vers, proc, xargs, argsp, 67074462Salfred xresults, resultsp, eachresult, 67174462Salfred INITTIME, WAITTIME, nettype); 67274462Salfred return (dummy); 67374462Salfred} 674