174462Salfred/* $NetBSD: clnt_bcast.c,v 1.3 2000/07/06 03:05:20 christos Exp $ */ 274462Salfred 3261046Smav/*- 4261046Smav * Copyright (c) 2009, Sun Microsystems, Inc. 5261046Smav * All rights reserved. 6261046Smav * 7261046Smav * Redistribution and use in source and binary forms, with or without 8261046Smav * modification, are permitted provided that the following conditions are met: 9261046Smav * - Redistributions of source code must retain the above copyright notice, 10261046Smav * this list of conditions and the following disclaimer. 11261046Smav * - Redistributions in binary form must reproduce the above copyright notice, 12261046Smav * this list of conditions and the following disclaimer in the documentation 13261046Smav * and/or other materials provided with the distribution. 14261046Smav * - Neither the name of Sun Microsystems, Inc. nor the names of its 15261046Smav * contributors may be used to endorse or promote products derived 16261046Smav * from this software without specific prior written permission. 1774462Salfred * 18261046Smav * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19261046Smav * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20261046Smav * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21261046Smav * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22261046Smav * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23261046Smav * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24261046Smav * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25261046Smav * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26261046Smav * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27261046Smav * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28261046Smav * POSSIBILITY OF SUCH DAMAGE. 2974462Salfred */ 3074462Salfred/* 3174462Salfred * Copyright (c) 1986-1991 by Sun Microsystems Inc. 3274462Salfred */ 3374462Salfred 34136581Sobrien#if defined(LIBC_SCCS) && !defined(lint) 35136581Sobrien#ident "@(#)clnt_bcast.c 1.18 94/05/03 SMI" 3674462Salfredstatic char sccsid[] = "@(#)clnt_bcast.c 1.15 89/04/21 Copyr 1988 Sun Micro"; 3774462Salfred#endif 3892990Sobrien#include <sys/cdefs.h> 3992990Sobrien__FBSDID("$FreeBSD: stable/10/lib/libc/rpc/clnt_bcast.c 309499 2016-12-03 18:45:12Z ngie $"); 4074462Salfred 4174462Salfred 4274462Salfred/* 4374462Salfred * clnt_bcast.c 4474462Salfred * Client interface to broadcast service. 4574462Salfred * 4674462Salfred * Copyright (C) 1988, Sun Microsystems, Inc. 4774462Salfred * 4874462Salfred * The following is kludged-up support for simple rpc broadcasts. 4974462Salfred * Someday a large, complicated system will replace these routines. 5074462Salfred */ 5174462Salfred 5274462Salfred#include "namespace.h" 5374462Salfred#include <sys/types.h> 5474462Salfred#include <sys/socket.h> 5574462Salfred#include <sys/queue.h> 5674462Salfred#include <net/if.h> 5774462Salfred#include <netinet/in.h> 5874462Salfred#include <ifaddrs.h> 5974462Salfred#include <sys/poll.h> 6074462Salfred#include <rpc/rpc.h> 6174462Salfred#ifdef PORTMAP 6274462Salfred#include <rpc/pmap_prot.h> 6374462Salfred#include <rpc/pmap_clnt.h> 6474462Salfred#include <rpc/pmap_rmt.h> 6574462Salfred#endif /* PORTMAP */ 6674462Salfred#include <rpc/nettype.h> 6774462Salfred#include <arpa/inet.h> 6874462Salfred#ifdef RPC_DEBUG 6974462Salfred#include <stdio.h> 7074462Salfred#endif 7174462Salfred#include <errno.h> 7274462Salfred#include <stdlib.h> 7374462Salfred#include <unistd.h> 7474462Salfred#include <netdb.h> 7574462Salfred#include <err.h> 7674462Salfred#include <string.h> 7774462Salfred#include "un-namespace.h" 7874462Salfred 7974462Salfred#include "rpc_com.h" 8074462Salfred 8174462Salfred#define MAXBCAST 20 /* Max no of broadcasting transports */ 8274462Salfred#define INITTIME 4000 /* Time to wait initially */ 8374462Salfred#define WAITTIME 8000 /* Maximum time to wait */ 8474462Salfred 8574462Salfred/* 8674462Salfred * If nettype is NULL, it broadcasts on all the available 8774462Salfred * datagram_n transports. May potentially lead to broadacst storms 8874462Salfred * and hence should be used with caution, care and courage. 8974462Salfred * 9074462Salfred * The current parameter xdr packet size is limited by the max tsdu 9174462Salfred * size of the transport. If the max tsdu size of any transport is 9274462Salfred * smaller than the parameter xdr packet, then broadcast is not 9374462Salfred * sent on that transport. 9474462Salfred * 9574462Salfred * Also, the packet size should be less the packet size of 9674462Salfred * the data link layer (for ethernet it is 1400 bytes). There is 9774462Salfred * no easy way to find out the max size of the data link layer and 9874462Salfred * we are assuming that the args would be smaller than that. 9974462Salfred * 10074462Salfred * The result size has to be smaller than the transport tsdu size. 10174462Salfred * 10274462Salfred * If PORTMAP has been defined, we send two packets for UDP, one for 10374462Salfred * rpcbind and one for portmap. For those machines which support 10474462Salfred * both rpcbind and portmap, it will cause them to reply twice, and 10574462Salfred * also here it will get two responses ... inefficient and clumsy. 10674462Salfred */ 10774462Salfred 10874462Salfredstruct broadif { 10974462Salfred int index; 11074462Salfred struct sockaddr_storage broadaddr; 11174462Salfred TAILQ_ENTRY(broadif) link; 11274462Salfred}; 11374462Salfred 11474462Salfredtypedef TAILQ_HEAD(, broadif) broadlist_t; 11574462Salfred 11692905Sobrienint __rpc_getbroadifs(int, int, int, broadlist_t *); 11792905Sobrienvoid __rpc_freebroadifs(broadlist_t *); 11892905Sobrienint __rpc_broadenable(int, int, struct broadif *); 11974462Salfred 12074462Salfredint __rpc_lowvers = 0; 12174462Salfred 12274462Salfredint 12374462Salfred__rpc_getbroadifs(int af, int proto, int socktype, broadlist_t *list) 12474462Salfred{ 12574462Salfred int count = 0; 12674462Salfred struct broadif *bip; 12774462Salfred struct ifaddrs *ifap, *ifp; 12874462Salfred#ifdef INET6 12974462Salfred struct sockaddr_in6 *sin6; 13074462Salfred#endif 13174462Salfred struct sockaddr_in *sin; 13274462Salfred struct addrinfo hints, *res; 13374462Salfred 13474462Salfred if (getifaddrs(&ifp) < 0) 13574462Salfred return 0; 13674462Salfred 13774462Salfred memset(&hints, 0, sizeof hints); 13874462Salfred 13974462Salfred hints.ai_family = af; 14074462Salfred hints.ai_protocol = proto; 14174462Salfred hints.ai_socktype = socktype; 14274462Salfred 143162189Smbr if (getaddrinfo(NULL, "sunrpc", &hints, &res) != 0) { 144162189Smbr freeifaddrs(ifp); 14574462Salfred return 0; 146162189Smbr } 14774462Salfred 14874462Salfred for (ifap = ifp; ifap != NULL; ifap = ifap->ifa_next) { 14974462Salfred if (ifap->ifa_addr->sa_family != af || 15074462Salfred !(ifap->ifa_flags & IFF_UP)) 15174462Salfred continue; 15274462Salfred bip = (struct broadif *)malloc(sizeof *bip); 15374462Salfred if (bip == NULL) 15474462Salfred break; 15574462Salfred bip->index = if_nametoindex(ifap->ifa_name); 156109955Smbr if ( 15774462Salfred#ifdef INET6 158109955Smbr af != AF_INET6 && 15974462Salfred#endif 160109955Smbr (ifap->ifa_flags & IFF_BROADCAST) && 161109955Smbr ifap->ifa_broadaddr) { 16274462Salfred memcpy(&bip->broadaddr, ifap->ifa_broadaddr, 16374462Salfred (size_t)ifap->ifa_broadaddr->sa_len); 16474462Salfred sin = (struct sockaddr_in *)(void *)&bip->broadaddr; 16574462Salfred sin->sin_port = 16674462Salfred ((struct sockaddr_in *) 16774462Salfred (void *)res->ai_addr)->sin_port; 168109955Smbr } else 16974462Salfred#ifdef INET6 170109955Smbr if (af == AF_INET6 && (ifap->ifa_flags & IFF_MULTICAST)) { 17174462Salfred sin6 = (struct sockaddr_in6 *)(void *)&bip->broadaddr; 17274462Salfred inet_pton(af, RPCB_MULTICAST_ADDR, &sin6->sin6_addr); 17374462Salfred sin6->sin6_family = af; 17474462Salfred sin6->sin6_len = sizeof *sin6; 17574462Salfred sin6->sin6_port = 17674462Salfred ((struct sockaddr_in6 *) 17774462Salfred (void *)res->ai_addr)->sin6_port; 17874462Salfred sin6->sin6_scope_id = bip->index; 179109955Smbr } else 18074462Salfred#endif 181109955Smbr { 182109955Smbr free(bip); 183109955Smbr continue; 18474462Salfred } 18574462Salfred TAILQ_INSERT_TAIL(list, bip, link); 18674462Salfred count++; 18774462Salfred } 18874462Salfred freeifaddrs(ifp); 18974462Salfred freeaddrinfo(res); 19074462Salfred 19174462Salfred return count; 19274462Salfred} 19374462Salfred 19474462Salfredvoid 19574462Salfred__rpc_freebroadifs(broadlist_t *list) 19674462Salfred{ 19774462Salfred struct broadif *bip, *next; 19874462Salfred 19974462Salfred bip = TAILQ_FIRST(list); 20074462Salfred 20174462Salfred while (bip != NULL) { 20274462Salfred next = TAILQ_NEXT(bip, link); 20374462Salfred free(bip); 20474462Salfred bip = next; 20574462Salfred } 20674462Salfred} 20774462Salfred 20874462Salfredint 20974462Salfred/*ARGSUSED*/ 21074462Salfred__rpc_broadenable(int af, int s, struct broadif *bip) 21174462Salfred{ 21274462Salfred int o = 1; 21374462Salfred 21474462Salfred#if 0 21574462Salfred if (af == AF_INET6) { 21674462Salfred fprintf(stderr, "set v6 multicast if to %d\n", bip->index); 21774462Salfred if (_setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, &bip->index, 21874462Salfred sizeof bip->index) < 0) 21974462Salfred return -1; 22074462Salfred } else 22174462Salfred#endif 22274462Salfred if (_setsockopt(s, SOL_SOCKET, SO_BROADCAST, &o, sizeof o) < 0) 22374462Salfred return -1; 22474462Salfred 22574462Salfred return 0; 22674462Salfred} 22774462Salfred 228309487Sngie/* 229309487Sngie * rpc_broadcast_exp() 230309487Sngie * 231309487Sngie * prog - program number 232309487Sngie * vers - version number 233309487Sngie * proc - procedure number 234309487Sngie * xargs - xdr routine for args 235309487Sngie * argsp - pointer to args 236309487Sngie * xresults - xdr routine for results 237309487Sngie * resultsp - pointer to results 238309487Sngie * eachresult - call with each result obtained 239309487Sngie * inittime - how long to wait initially 240309487Sngie * waittime - maximum time to wait 241309487Sngie * nettype - transport type 242309487Sngie */ 24374462Salfredenum clnt_stat 244309487Sngierpc_broadcast_exp(rpcprog_t prog, rpcvers_t vers, rpcproc_t proc, 245309487Sngie xdrproc_t xargs, caddr_t argsp, xdrproc_t xresults, caddr_t resultsp, 246309487Sngie resultproc_t eachresult, int inittime, int waittime, 247309487Sngie const char *nettype) 24874462Salfred{ 24974462Salfred enum clnt_stat stat = RPC_SUCCESS; /* Return status */ 25074462Salfred XDR xdr_stream; /* XDR stream */ 25174462Salfred XDR *xdrs = &xdr_stream; 25274462Salfred struct rpc_msg msg; /* RPC message */ 25374462Salfred struct timeval t; 25474462Salfred char *outbuf = NULL; /* Broadcast msg buffer */ 25574462Salfred char *inbuf = NULL; /* Reply buf */ 25674462Salfred int inlen; 25774462Salfred u_int maxbufsize = 0; 25874462Salfred AUTH *sys_auth = authunix_create_default(); 259309499Sngie u_int i; 26074462Salfred void *handle; 26174462Salfred char uaddress[1024]; /* A self imposed limit */ 26274462Salfred char *uaddrp = uaddress; 26374462Salfred int pmap_reply_flag; /* reply recvd from PORTMAP */ 26474462Salfred /* An array of all the suitable broadcast transports */ 26574462Salfred struct { 26674462Salfred int fd; /* File descriptor */ 26774462Salfred int af; 26874462Salfred int proto; 26974462Salfred struct netconfig *nconf; /* Netconfig structure */ 27074462Salfred u_int asize; /* Size of the addr buf */ 27174462Salfred u_int dsize; /* Size of the data buf */ 27274462Salfred struct sockaddr_storage raddr; /* Remote address */ 27374462Salfred broadlist_t nal; 27474462Salfred } fdlist[MAXBCAST]; 27574462Salfred struct pollfd pfd[MAXBCAST]; 27674462Salfred size_t fdlistno = 0; 27774462Salfred struct r_rpcb_rmtcallargs barg; /* Remote arguments */ 27874462Salfred struct r_rpcb_rmtcallres bres; /* Remote results */ 27990271Salfred size_t outlen; 28074462Salfred struct netconfig *nconf; 28174462Salfred int msec; 28274462Salfred int pollretval; 28374462Salfred int fds_found; 28474462Salfred 28574462Salfred#ifdef PORTMAP 28690271Salfred size_t outlen_pmap = 0; 28774462Salfred u_long port; /* Remote port number */ 28874462Salfred int pmap_flag = 0; /* UDP exists ? */ 28974462Salfred char *outbuf_pmap = NULL; 29074462Salfred struct rmtcallargs barg_pmap; /* Remote arguments */ 29174462Salfred struct rmtcallres bres_pmap; /* Remote results */ 29274462Salfred u_int udpbufsz = 0; 29374462Salfred#endif /* PORTMAP */ 29474462Salfred 29574462Salfred if (sys_auth == NULL) { 29674462Salfred return (RPC_SYSTEMERROR); 29774462Salfred } 29874462Salfred /* 29974462Salfred * initialization: create a fd, a broadcast address, and send the 30074462Salfred * request on the broadcast transport. 30174462Salfred * Listen on all of them and on replies, call the user supplied 30274462Salfred * function. 30374462Salfred */ 30474462Salfred 30574462Salfred if (nettype == NULL) 30674462Salfred nettype = "datagram_n"; 30774462Salfred if ((handle = __rpc_setconf(nettype)) == NULL) { 308162189Smbr AUTH_DESTROY(sys_auth); 30974462Salfred return (RPC_UNKNOWNPROTO); 31074462Salfred } 31174462Salfred while ((nconf = __rpc_getconf(handle)) != NULL) { 31274462Salfred int fd; 31374462Salfred struct __rpc_sockinfo si; 31474462Salfred 31574462Salfred if (nconf->nc_semantics != NC_TPI_CLTS) 31674462Salfred continue; 31774462Salfred if (fdlistno >= MAXBCAST) 31874462Salfred break; /* No more slots available */ 31974462Salfred if (!__rpc_nconf2sockinfo(nconf, &si)) 32074462Salfred continue; 32174462Salfred 32274462Salfred TAILQ_INIT(&fdlist[fdlistno].nal); 32374462Salfred if (__rpc_getbroadifs(si.si_af, si.si_proto, si.si_socktype, 32474462Salfred &fdlist[fdlistno].nal) == 0) 32574462Salfred continue; 32674462Salfred 32774462Salfred fd = _socket(si.si_af, si.si_socktype, si.si_proto); 32874462Salfred if (fd < 0) { 32974462Salfred stat = RPC_CANTSEND; 33074462Salfred continue; 33174462Salfred } 33274462Salfred fdlist[fdlistno].af = si.si_af; 33374462Salfred fdlist[fdlistno].proto = si.si_proto; 33474462Salfred fdlist[fdlistno].fd = fd; 33574462Salfred fdlist[fdlistno].nconf = nconf; 33674462Salfred fdlist[fdlistno].asize = __rpc_get_a_size(si.si_af); 33774462Salfred pfd[fdlistno].events = POLLIN | POLLPRI | 33874462Salfred POLLRDNORM | POLLRDBAND; 33974462Salfred pfd[fdlistno].fd = fdlist[fdlistno].fd = fd; 34074462Salfred fdlist[fdlistno].dsize = __rpc_get_t_size(si.si_af, si.si_proto, 34174462Salfred 0); 34274462Salfred 34374462Salfred if (maxbufsize <= fdlist[fdlistno].dsize) 34474462Salfred maxbufsize = fdlist[fdlistno].dsize; 34574462Salfred 34674462Salfred#ifdef PORTMAP 34774462Salfred if (si.si_af == AF_INET && si.si_proto == IPPROTO_UDP) { 34874462Salfred udpbufsz = fdlist[fdlistno].dsize; 349301622Sngie outbuf_pmap = reallocf(outbuf_pmap, udpbufsz); 350301622Sngie if (outbuf_pmap == NULL) { 35174462Salfred _close(fd); 35274462Salfred stat = RPC_SYSTEMERROR; 35374462Salfred goto done_broad; 35474462Salfred } 35574462Salfred pmap_flag = 1; 35674462Salfred } 35774462Salfred#endif /* PORTMAP */ 35874462Salfred fdlistno++; 35974462Salfred } 36074462Salfred 36174462Salfred if (fdlistno == 0) { 36274462Salfred if (stat == RPC_SUCCESS) 36374462Salfred stat = RPC_UNKNOWNPROTO; 36474462Salfred goto done_broad; 36574462Salfred } 36674462Salfred if (maxbufsize == 0) { 36774462Salfred if (stat == RPC_SUCCESS) 36874462Salfred stat = RPC_CANTSEND; 36974462Salfred goto done_broad; 37074462Salfred } 37174462Salfred inbuf = malloc(maxbufsize); 37274462Salfred outbuf = malloc(maxbufsize); 37374462Salfred if ((inbuf == NULL) || (outbuf == NULL)) { 37474462Salfred stat = RPC_SYSTEMERROR; 37574462Salfred goto done_broad; 37674462Salfred } 37774462Salfred 37874462Salfred /* Serialize all the arguments which have to be sent */ 37974462Salfred (void) gettimeofday(&t, NULL); 38074462Salfred msg.rm_xid = __RPC_GETXID(&t); 38174462Salfred msg.rm_direction = CALL; 38274462Salfred msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; 38374462Salfred msg.rm_call.cb_prog = RPCBPROG; 38474462Salfred msg.rm_call.cb_vers = RPCBVERS; 38574462Salfred msg.rm_call.cb_proc = RPCBPROC_CALLIT; 38674462Salfred barg.prog = prog; 38774462Salfred barg.vers = vers; 38874462Salfred barg.proc = proc; 38974462Salfred barg.args.args_val = argsp; 39074462Salfred barg.xdr_args = xargs; 39174462Salfred bres.addr = uaddrp; 39274462Salfred bres.results.results_val = resultsp; 39374462Salfred bres.xdr_res = xresults; 39474462Salfred msg.rm_call.cb_cred = sys_auth->ah_cred; 39574462Salfred msg.rm_call.cb_verf = sys_auth->ah_verf; 39674462Salfred xdrmem_create(xdrs, outbuf, maxbufsize, XDR_ENCODE); 39774462Salfred if ((!xdr_callmsg(xdrs, &msg)) || 39874462Salfred (!xdr_rpcb_rmtcallargs(xdrs, 39974462Salfred (struct rpcb_rmtcallargs *)(void *)&barg))) { 40074462Salfred stat = RPC_CANTENCODEARGS; 40174462Salfred goto done_broad; 40274462Salfred } 40374462Salfred outlen = xdr_getpos(xdrs); 40474462Salfred xdr_destroy(xdrs); 40574462Salfred 40674462Salfred#ifdef PORTMAP 40774462Salfred /* Prepare the packet for version 2 PORTMAP */ 40874462Salfred if (pmap_flag) { 40974462Salfred msg.rm_xid++; /* One way to distinguish */ 41074462Salfred msg.rm_call.cb_prog = PMAPPROG; 41174462Salfred msg.rm_call.cb_vers = PMAPVERS; 41274462Salfred msg.rm_call.cb_proc = PMAPPROC_CALLIT; 41374462Salfred barg_pmap.prog = prog; 41474462Salfred barg_pmap.vers = vers; 41574462Salfred barg_pmap.proc = proc; 41674462Salfred barg_pmap.args_ptr = argsp; 41774462Salfred barg_pmap.xdr_args = xargs; 41874462Salfred bres_pmap.port_ptr = &port; 41974462Salfred bres_pmap.xdr_results = xresults; 42074462Salfred bres_pmap.results_ptr = resultsp; 42174462Salfred xdrmem_create(xdrs, outbuf_pmap, udpbufsz, XDR_ENCODE); 42274462Salfred if ((! xdr_callmsg(xdrs, &msg)) || 42374462Salfred (! xdr_rmtcall_args(xdrs, &barg_pmap))) { 42474462Salfred stat = RPC_CANTENCODEARGS; 42574462Salfred goto done_broad; 42674462Salfred } 42774462Salfred outlen_pmap = xdr_getpos(xdrs); 42874462Salfred xdr_destroy(xdrs); 42974462Salfred } 43087966Speter#endif /* PORTMAP */ 43174462Salfred 43274462Salfred /* 43374462Salfred * Basic loop: broadcast the packets to transports which 43474462Salfred * support data packets of size such that one can encode 43574462Salfred * all the arguments. 43674462Salfred * Wait a while for response(s). 43774462Salfred * The response timeout grows larger per iteration. 43874462Salfred */ 43974462Salfred for (msec = inittime; msec <= waittime; msec += msec) { 44074462Salfred struct broadif *bip; 44174462Salfred 44274462Salfred /* Broadcast all the packets now */ 44374462Salfred for (i = 0; i < fdlistno; i++) { 44474462Salfred if (fdlist[i].dsize < outlen) { 44574462Salfred stat = RPC_CANTSEND; 44674462Salfred continue; 44774462Salfred } 44874462Salfred for (bip = TAILQ_FIRST(&fdlist[i].nal); bip != NULL; 44974462Salfred bip = TAILQ_NEXT(bip, link)) { 45074462Salfred void *addr; 45174462Salfred 45274462Salfred addr = &bip->broadaddr; 45374462Salfred 45474462Salfred __rpc_broadenable(fdlist[i].af, fdlist[i].fd, 45574462Salfred bip); 45674462Salfred 45774462Salfred /* 45874462Salfred * Only use version 3 if lowvers is not set 45974462Salfred */ 46074462Salfred 46174462Salfred if (!__rpc_lowvers) 46274462Salfred if (_sendto(fdlist[i].fd, outbuf, 46374462Salfred outlen, 0, (struct sockaddr*)addr, 46474462Salfred (size_t)fdlist[i].asize) != 46574462Salfred outlen) { 46674462Salfred#ifdef RPC_DEBUG 46774462Salfred perror("sendto"); 46874462Salfred#endif 469190871Semaste warnx("clnt_bcast: cannot send " 47074462Salfred "broadcast packet"); 47174462Salfred stat = RPC_CANTSEND; 47274462Salfred continue; 47374462Salfred }; 47474462Salfred#ifdef RPC_DEBUG 47574462Salfred if (!__rpc_lowvers) 47674462Salfred fprintf(stderr, "Broadcast packet sent " 47774462Salfred "for %s\n", 47874462Salfred fdlist[i].nconf->nc_netid); 47974462Salfred#endif 48074462Salfred#ifdef PORTMAP 48174462Salfred /* 48274462Salfred * Send the version 2 packet also 48374462Salfred * for UDP/IP 48474462Salfred */ 485109954Smbr if (pmap_flag && 486109954Smbr fdlist[i].proto == IPPROTO_UDP) { 48774462Salfred if (_sendto(fdlist[i].fd, outbuf_pmap, 48874462Salfred outlen_pmap, 0, addr, 48974462Salfred (size_t)fdlist[i].asize) != 49074462Salfred outlen_pmap) { 49174462Salfred warnx("clnt_bcast: " 49274462Salfred "Cannot send broadcast packet"); 49374462Salfred stat = RPC_CANTSEND; 49474462Salfred continue; 49574462Salfred } 49674462Salfred } 49774462Salfred#ifdef RPC_DEBUG 49874462Salfred fprintf(stderr, "PMAP Broadcast packet " 49974462Salfred "sent for %s\n", 50074462Salfred fdlist[i].nconf->nc_netid); 50174462Salfred#endif 50274462Salfred#endif /* PORTMAP */ 50374462Salfred } 50474462Salfred /* End for sending all packets on this transport */ 50574462Salfred } /* End for sending on all transports */ 50674462Salfred 50774462Salfred if (eachresult == NULL) { 50874462Salfred stat = RPC_SUCCESS; 50974462Salfred goto done_broad; 51074462Salfred } 51174462Salfred 51274462Salfred /* 51374462Salfred * Get all the replies from these broadcast requests 51474462Salfred */ 51574462Salfred recv_again: 51674462Salfred 51774462Salfred switch (pollretval = _poll(pfd, fdlistno, msec)) { 51874462Salfred case 0: /* timed out */ 51974462Salfred stat = RPC_TIMEDOUT; 52074462Salfred continue; 52174462Salfred case -1: /* some kind of error - we ignore it */ 52274462Salfred goto recv_again; 52374462Salfred } /* end of poll results switch */ 52474462Salfred 52574462Salfred for (i = fds_found = 0; 52674462Salfred i < fdlistno && fds_found < pollretval; i++) { 52774462Salfred bool_t done = FALSE; 52874462Salfred 52974462Salfred if (pfd[i].revents == 0) 53074462Salfred continue; 53174462Salfred else if (pfd[i].revents & POLLNVAL) { 53274462Salfred /* 53374462Salfred * Something bad has happened to this descri- 53474462Salfred * ptor. We can cause _poll() to ignore 53574462Salfred * it simply by using a negative fd. We do that 53674462Salfred * rather than compacting the pfd[] and fdlist[] 53774462Salfred * arrays. 53874462Salfred */ 53974462Salfred pfd[i].fd = -1; 54074462Salfred fds_found++; 54174462Salfred continue; 54274462Salfred } else 54374462Salfred fds_found++; 54474462Salfred#ifdef RPC_DEBUG 54574462Salfred fprintf(stderr, "response for %s\n", 54674462Salfred fdlist[i].nconf->nc_netid); 54774462Salfred#endif 54874462Salfred try_again: 54974462Salfred inlen = _recvfrom(fdlist[i].fd, inbuf, fdlist[i].dsize, 55074462Salfred 0, (struct sockaddr *)(void *)&fdlist[i].raddr, 55174462Salfred &fdlist[i].asize); 55274462Salfred if (inlen < 0) { 55374462Salfred if (errno == EINTR) 55474462Salfred goto try_again; 55574462Salfred warnx("clnt_bcast: Cannot receive reply to " 55674462Salfred "broadcast"); 55774462Salfred stat = RPC_CANTRECV; 55874462Salfred continue; 55974462Salfred } 56074462Salfred if (inlen < sizeof (u_int32_t)) 56174462Salfred continue; /* Drop that and go ahead */ 56274462Salfred /* 56374462Salfred * see if reply transaction id matches sent id. 56474462Salfred * If so, decode the results. If return id is xid + 1 56574462Salfred * it was a PORTMAP reply 56674462Salfred */ 56774462Salfred if (*((u_int32_t *)(void *)(inbuf)) == 56874462Salfred *((u_int32_t *)(void *)(outbuf))) { 56974462Salfred pmap_reply_flag = 0; 57074462Salfred msg.acpted_rply.ar_verf = _null_auth; 57174462Salfred msg.acpted_rply.ar_results.where = 57274462Salfred (caddr_t)(void *)&bres; 57374462Salfred msg.acpted_rply.ar_results.proc = 57474462Salfred (xdrproc_t)xdr_rpcb_rmtcallres; 57574462Salfred#ifdef PORTMAP 57674462Salfred } else if (pmap_flag && 57774462Salfred *((u_int32_t *)(void *)(inbuf)) == 57874462Salfred *((u_int32_t *)(void *)(outbuf_pmap))) { 57974462Salfred pmap_reply_flag = 1; 58074462Salfred msg.acpted_rply.ar_verf = _null_auth; 58174462Salfred msg.acpted_rply.ar_results.where = 58274462Salfred (caddr_t)(void *)&bres_pmap; 58374462Salfred msg.acpted_rply.ar_results.proc = 58474462Salfred (xdrproc_t)xdr_rmtcallres; 58574462Salfred#endif /* PORTMAP */ 58674462Salfred } else 58774462Salfred continue; 58874462Salfred xdrmem_create(xdrs, inbuf, (u_int)inlen, XDR_DECODE); 58974462Salfred if (xdr_replymsg(xdrs, &msg)) { 59074462Salfred if ((msg.rm_reply.rp_stat == MSG_ACCEPTED) && 59174462Salfred (msg.acpted_rply.ar_stat == SUCCESS)) { 59274462Salfred struct netbuf taddr, *np; 59374462Salfred struct sockaddr_in *sin; 59474462Salfred 59574462Salfred#ifdef PORTMAP 59674462Salfred if (pmap_flag && pmap_reply_flag) { 59774462Salfred sin = (struct sockaddr_in *) 59874462Salfred (void *)&fdlist[i].raddr; 59974462Salfred sin->sin_port = 60074462Salfred htons((u_short)port); 60174462Salfred taddr.len = taddr.maxlen = 60274462Salfred fdlist[i].raddr.ss_len; 60374462Salfred taddr.buf = &fdlist[i].raddr; 60474462Salfred done = (*eachresult)(resultsp, 60574462Salfred &taddr, fdlist[i].nconf); 60674462Salfred } else { 60774462Salfred#endif /* PORTMAP */ 60874462Salfred#ifdef RPC_DEBUG 60974462Salfred fprintf(stderr, "uaddr %s\n", 61074462Salfred uaddrp); 61174462Salfred#endif 61274462Salfred np = uaddr2taddr( 61374462Salfred fdlist[i].nconf, uaddrp); 61474462Salfred done = (*eachresult)(resultsp, 61574462Salfred np, fdlist[i].nconf); 61674462Salfred free(np); 61774462Salfred#ifdef PORTMAP 61874462Salfred } 61974462Salfred#endif /* PORTMAP */ 62074462Salfred } 62174462Salfred /* otherwise, we just ignore the errors ... */ 62274462Salfred } 62374462Salfred /* else some kind of deserialization problem ... */ 62474462Salfred 62574462Salfred xdrs->x_op = XDR_FREE; 62674462Salfred msg.acpted_rply.ar_results.proc = (xdrproc_t) xdr_void; 62774462Salfred (void) xdr_replymsg(xdrs, &msg); 62874462Salfred (void) (*xresults)(xdrs, resultsp); 62974462Salfred XDR_DESTROY(xdrs); 63074462Salfred if (done) { 63174462Salfred stat = RPC_SUCCESS; 63274462Salfred goto done_broad; 63374462Salfred } else { 63474462Salfred goto recv_again; 63574462Salfred } 63674462Salfred } /* The recv for loop */ 63774462Salfred } /* The giant for loop */ 63874462Salfred 63974462Salfreddone_broad: 640290899Sngie free(inbuf); 641290899Sngie free(outbuf); 64274462Salfred#ifdef PORTMAP 643290899Sngie free(outbuf_pmap); 64474462Salfred#endif /* PORTMAP */ 64574462Salfred for (i = 0; i < fdlistno; i++) { 64674462Salfred (void)_close(fdlist[i].fd); 64774462Salfred __rpc_freebroadifs(&fdlist[i].nal); 64874462Salfred } 64974462Salfred AUTH_DESTROY(sys_auth); 65074462Salfred (void) __rpc_endconf(handle); 65174462Salfred 65274462Salfred return (stat); 65374462Salfred} 65474462Salfred 655309487Sngie/* 656309487Sngie * rpc_broadcast() 657309487Sngie * 658309487Sngie * prog - program number 659309487Sngie * vers - version number 660309487Sngie * proc - procedure number 661309487Sngie * xargs - xdr routine for args 662309487Sngie * argsp - pointer to args 663309487Sngie * xresults - xdr routine for results 664309487Sngie * resultsp - pointer to results 665309487Sngie * eachresult - call with each result obtained 666309487Sngie * nettype - transport type 667309487Sngie */ 66874462Salfredenum clnt_stat 669309487Sngierpc_broadcast(rpcprog_t prog, rpcvers_t vers, rpcproc_t proc, xdrproc_t xargs, 670309487Sngie caddr_t argsp, xdrproc_t xresults, caddr_t resultsp, 671309487Sngie resultproc_t eachresult, const char *nettype) 67274462Salfred{ 67374462Salfred enum clnt_stat dummy; 67474462Salfred 67574462Salfred dummy = rpc_broadcast_exp(prog, vers, proc, xargs, argsp, 67674462Salfred xresults, resultsp, eachresult, 67774462Salfred INITTIME, WAITTIME, nettype); 67874462Salfred return (dummy); 67974462Salfred} 680