174462Salfred/* $NetBSD: clnt_bcast.c,v 1.3 2000/07/06 03:05:20 christos Exp $ */ 274462Salfred 3261057Smav/*- 4261057Smav * Copyright (c) 2009, Sun Microsystems, Inc. 5261057Smav * All rights reserved. 6261057Smav * 7261057Smav * Redistribution and use in source and binary forms, with or without 8261057Smav * modification, are permitted provided that the following conditions are met: 9261057Smav * - Redistributions of source code must retain the above copyright notice, 10261057Smav * this list of conditions and the following disclaimer. 11261057Smav * - Redistributions in binary form must reproduce the above copyright notice, 12261057Smav * this list of conditions and the following disclaimer in the documentation 13261057Smav * and/or other materials provided with the distribution. 14261057Smav * - Neither the name of Sun Microsystems, Inc. nor the names of its 15261057Smav * contributors may be used to endorse or promote products derived 16261057Smav * from this software without specific prior written permission. 1774462Salfred * 18261057Smav * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19261057Smav * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20261057Smav * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21261057Smav * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22261057Smav * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23261057Smav * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24261057Smav * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25261057Smav * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26261057Smav * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27261057Smav * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28261057Smav * 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$"); 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 22874462Salfred 22974462Salfredenum clnt_stat 23074462Salfredrpc_broadcast_exp(prog, vers, proc, xargs, argsp, xresults, resultsp, 23174462Salfred eachresult, inittime, waittime, nettype) 23274462Salfred rpcprog_t prog; /* program number */ 23374462Salfred rpcvers_t vers; /* version number */ 23474462Salfred rpcproc_t proc; /* procedure number */ 23574462Salfred xdrproc_t xargs; /* xdr routine for args */ 23674462Salfred caddr_t argsp; /* pointer to args */ 23774462Salfred xdrproc_t xresults; /* xdr routine for results */ 23874462Salfred caddr_t resultsp; /* pointer to results */ 23974462Salfred resultproc_t eachresult; /* call with each result obtained */ 24074462Salfred int inittime; /* how long to wait initially */ 24174462Salfred int waittime; /* maximum time to wait */ 24274462Salfred const char *nettype; /* transport type */ 24374462Salfred{ 24474462Salfred enum clnt_stat stat = RPC_SUCCESS; /* Return status */ 24574462Salfred XDR xdr_stream; /* XDR stream */ 24674462Salfred XDR *xdrs = &xdr_stream; 24774462Salfred struct rpc_msg msg; /* RPC message */ 24874462Salfred struct timeval t; 24974462Salfred char *outbuf = NULL; /* Broadcast msg buffer */ 25074462Salfred char *inbuf = NULL; /* Reply buf */ 25174462Salfred int inlen; 25274462Salfred u_int maxbufsize = 0; 25374462Salfred AUTH *sys_auth = authunix_create_default(); 25474462Salfred int i; 25574462Salfred void *handle; 25674462Salfred char uaddress[1024]; /* A self imposed limit */ 25774462Salfred char *uaddrp = uaddress; 25874462Salfred int pmap_reply_flag; /* reply recvd from PORTMAP */ 25974462Salfred /* An array of all the suitable broadcast transports */ 26074462Salfred struct { 26174462Salfred int fd; /* File descriptor */ 26274462Salfred int af; 26374462Salfred int proto; 26474462Salfred struct netconfig *nconf; /* Netconfig structure */ 26574462Salfred u_int asize; /* Size of the addr buf */ 26674462Salfred u_int dsize; /* Size of the data buf */ 26774462Salfred struct sockaddr_storage raddr; /* Remote address */ 26874462Salfred broadlist_t nal; 26974462Salfred } fdlist[MAXBCAST]; 27074462Salfred struct pollfd pfd[MAXBCAST]; 27174462Salfred size_t fdlistno = 0; 27274462Salfred struct r_rpcb_rmtcallargs barg; /* Remote arguments */ 27374462Salfred struct r_rpcb_rmtcallres bres; /* Remote results */ 27490271Salfred size_t outlen; 27574462Salfred struct netconfig *nconf; 27674462Salfred int msec; 27774462Salfred int pollretval; 27874462Salfred int fds_found; 27974462Salfred 28074462Salfred#ifdef PORTMAP 28190271Salfred size_t outlen_pmap = 0; 28274462Salfred u_long port; /* Remote port number */ 28374462Salfred int pmap_flag = 0; /* UDP exists ? */ 28474462Salfred char *outbuf_pmap = NULL; 28574462Salfred struct rmtcallargs barg_pmap; /* Remote arguments */ 28674462Salfred struct rmtcallres bres_pmap; /* Remote results */ 28774462Salfred u_int udpbufsz = 0; 28874462Salfred#endif /* PORTMAP */ 28974462Salfred 29074462Salfred if (sys_auth == NULL) { 29174462Salfred return (RPC_SYSTEMERROR); 29274462Salfred } 29374462Salfred /* 29474462Salfred * initialization: create a fd, a broadcast address, and send the 29574462Salfred * request on the broadcast transport. 29674462Salfred * Listen on all of them and on replies, call the user supplied 29774462Salfred * function. 29874462Salfred */ 29974462Salfred 30074462Salfred if (nettype == NULL) 30174462Salfred nettype = "datagram_n"; 30274462Salfred if ((handle = __rpc_setconf(nettype)) == NULL) { 303162189Smbr AUTH_DESTROY(sys_auth); 30474462Salfred return (RPC_UNKNOWNPROTO); 30574462Salfred } 30674462Salfred while ((nconf = __rpc_getconf(handle)) != NULL) { 30774462Salfred int fd; 30874462Salfred struct __rpc_sockinfo si; 30974462Salfred 31074462Salfred if (nconf->nc_semantics != NC_TPI_CLTS) 31174462Salfred continue; 31274462Salfred if (fdlistno >= MAXBCAST) 31374462Salfred break; /* No more slots available */ 31474462Salfred if (!__rpc_nconf2sockinfo(nconf, &si)) 31574462Salfred continue; 31674462Salfred 31774462Salfred TAILQ_INIT(&fdlist[fdlistno].nal); 31874462Salfred if (__rpc_getbroadifs(si.si_af, si.si_proto, si.si_socktype, 31974462Salfred &fdlist[fdlistno].nal) == 0) 32074462Salfred continue; 32174462Salfred 32274462Salfred fd = _socket(si.si_af, si.si_socktype, si.si_proto); 32374462Salfred if (fd < 0) { 32474462Salfred stat = RPC_CANTSEND; 32574462Salfred continue; 32674462Salfred } 32774462Salfred fdlist[fdlistno].af = si.si_af; 32874462Salfred fdlist[fdlistno].proto = si.si_proto; 32974462Salfred fdlist[fdlistno].fd = fd; 33074462Salfred fdlist[fdlistno].nconf = nconf; 33174462Salfred fdlist[fdlistno].asize = __rpc_get_a_size(si.si_af); 33274462Salfred pfd[fdlistno].events = POLLIN | POLLPRI | 33374462Salfred POLLRDNORM | POLLRDBAND; 33474462Salfred pfd[fdlistno].fd = fdlist[fdlistno].fd = fd; 33574462Salfred fdlist[fdlistno].dsize = __rpc_get_t_size(si.si_af, si.si_proto, 33674462Salfred 0); 33774462Salfred 33874462Salfred if (maxbufsize <= fdlist[fdlistno].dsize) 33974462Salfred maxbufsize = fdlist[fdlistno].dsize; 34074462Salfred 34174462Salfred#ifdef PORTMAP 34274462Salfred if (si.si_af == AF_INET && si.si_proto == IPPROTO_UDP) { 34374462Salfred udpbufsz = fdlist[fdlistno].dsize; 34474462Salfred if ((outbuf_pmap = malloc(udpbufsz)) == NULL) { 34574462Salfred _close(fd); 34674462Salfred stat = RPC_SYSTEMERROR; 34774462Salfred goto done_broad; 34874462Salfred } 34974462Salfred pmap_flag = 1; 35074462Salfred } 35174462Salfred#endif /* PORTMAP */ 35274462Salfred fdlistno++; 35374462Salfred } 35474462Salfred 35574462Salfred if (fdlistno == 0) { 35674462Salfred if (stat == RPC_SUCCESS) 35774462Salfred stat = RPC_UNKNOWNPROTO; 35874462Salfred goto done_broad; 35974462Salfred } 36074462Salfred if (maxbufsize == 0) { 36174462Salfred if (stat == RPC_SUCCESS) 36274462Salfred stat = RPC_CANTSEND; 36374462Salfred goto done_broad; 36474462Salfred } 36574462Salfred inbuf = malloc(maxbufsize); 36674462Salfred outbuf = malloc(maxbufsize); 36774462Salfred if ((inbuf == NULL) || (outbuf == NULL)) { 36874462Salfred stat = RPC_SYSTEMERROR; 36974462Salfred goto done_broad; 37074462Salfred } 37174462Salfred 37274462Salfred /* Serialize all the arguments which have to be sent */ 37374462Salfred (void) gettimeofday(&t, NULL); 37474462Salfred msg.rm_xid = __RPC_GETXID(&t); 37574462Salfred msg.rm_direction = CALL; 37674462Salfred msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; 37774462Salfred msg.rm_call.cb_prog = RPCBPROG; 37874462Salfred msg.rm_call.cb_vers = RPCBVERS; 37974462Salfred msg.rm_call.cb_proc = RPCBPROC_CALLIT; 38074462Salfred barg.prog = prog; 38174462Salfred barg.vers = vers; 38274462Salfred barg.proc = proc; 38374462Salfred barg.args.args_val = argsp; 38474462Salfred barg.xdr_args = xargs; 38574462Salfred bres.addr = uaddrp; 38674462Salfred bres.results.results_val = resultsp; 38774462Salfred bres.xdr_res = xresults; 38874462Salfred msg.rm_call.cb_cred = sys_auth->ah_cred; 38974462Salfred msg.rm_call.cb_verf = sys_auth->ah_verf; 39074462Salfred xdrmem_create(xdrs, outbuf, maxbufsize, XDR_ENCODE); 39174462Salfred if ((!xdr_callmsg(xdrs, &msg)) || 39274462Salfred (!xdr_rpcb_rmtcallargs(xdrs, 39374462Salfred (struct rpcb_rmtcallargs *)(void *)&barg))) { 39474462Salfred stat = RPC_CANTENCODEARGS; 39574462Salfred goto done_broad; 39674462Salfred } 39774462Salfred outlen = xdr_getpos(xdrs); 39874462Salfred xdr_destroy(xdrs); 39974462Salfred 40074462Salfred#ifdef PORTMAP 40174462Salfred /* Prepare the packet for version 2 PORTMAP */ 40274462Salfred if (pmap_flag) { 40374462Salfred msg.rm_xid++; /* One way to distinguish */ 40474462Salfred msg.rm_call.cb_prog = PMAPPROG; 40574462Salfred msg.rm_call.cb_vers = PMAPVERS; 40674462Salfred msg.rm_call.cb_proc = PMAPPROC_CALLIT; 40774462Salfred barg_pmap.prog = prog; 40874462Salfred barg_pmap.vers = vers; 40974462Salfred barg_pmap.proc = proc; 41074462Salfred barg_pmap.args_ptr = argsp; 41174462Salfred barg_pmap.xdr_args = xargs; 41274462Salfred bres_pmap.port_ptr = &port; 41374462Salfred bres_pmap.xdr_results = xresults; 41474462Salfred bres_pmap.results_ptr = resultsp; 41574462Salfred xdrmem_create(xdrs, outbuf_pmap, udpbufsz, XDR_ENCODE); 41674462Salfred if ((! xdr_callmsg(xdrs, &msg)) || 41774462Salfred (! xdr_rmtcall_args(xdrs, &barg_pmap))) { 41874462Salfred stat = RPC_CANTENCODEARGS; 41974462Salfred goto done_broad; 42074462Salfred } 42174462Salfred outlen_pmap = xdr_getpos(xdrs); 42274462Salfred xdr_destroy(xdrs); 42374462Salfred } 42487966Speter#endif /* PORTMAP */ 42574462Salfred 42674462Salfred /* 42774462Salfred * Basic loop: broadcast the packets to transports which 42874462Salfred * support data packets of size such that one can encode 42974462Salfred * all the arguments. 43074462Salfred * Wait a while for response(s). 43174462Salfred * The response timeout grows larger per iteration. 43274462Salfred */ 43374462Salfred for (msec = inittime; msec <= waittime; msec += msec) { 43474462Salfred struct broadif *bip; 43574462Salfred 43674462Salfred /* Broadcast all the packets now */ 43774462Salfred for (i = 0; i < fdlistno; i++) { 43874462Salfred if (fdlist[i].dsize < outlen) { 43974462Salfred stat = RPC_CANTSEND; 44074462Salfred continue; 44174462Salfred } 44274462Salfred for (bip = TAILQ_FIRST(&fdlist[i].nal); bip != NULL; 44374462Salfred bip = TAILQ_NEXT(bip, link)) { 44474462Salfred void *addr; 44574462Salfred 44674462Salfred addr = &bip->broadaddr; 44774462Salfred 44874462Salfred __rpc_broadenable(fdlist[i].af, fdlist[i].fd, 44974462Salfred bip); 45074462Salfred 45174462Salfred /* 45274462Salfred * Only use version 3 if lowvers is not set 45374462Salfred */ 45474462Salfred 45574462Salfred if (!__rpc_lowvers) 45674462Salfred if (_sendto(fdlist[i].fd, outbuf, 45774462Salfred outlen, 0, (struct sockaddr*)addr, 45874462Salfred (size_t)fdlist[i].asize) != 45974462Salfred outlen) { 46074462Salfred#ifdef RPC_DEBUG 46174462Salfred perror("sendto"); 46274462Salfred#endif 463190871Semaste warnx("clnt_bcast: cannot send " 46474462Salfred "broadcast packet"); 46574462Salfred stat = RPC_CANTSEND; 46674462Salfred continue; 46774462Salfred }; 46874462Salfred#ifdef RPC_DEBUG 46974462Salfred if (!__rpc_lowvers) 47074462Salfred fprintf(stderr, "Broadcast packet sent " 47174462Salfred "for %s\n", 47274462Salfred fdlist[i].nconf->nc_netid); 47374462Salfred#endif 47474462Salfred#ifdef PORTMAP 47574462Salfred /* 47674462Salfred * Send the version 2 packet also 47774462Salfred * for UDP/IP 47874462Salfred */ 479109954Smbr if (pmap_flag && 480109954Smbr fdlist[i].proto == IPPROTO_UDP) { 48174462Salfred if (_sendto(fdlist[i].fd, outbuf_pmap, 48274462Salfred outlen_pmap, 0, addr, 48374462Salfred (size_t)fdlist[i].asize) != 48474462Salfred outlen_pmap) { 48574462Salfred warnx("clnt_bcast: " 48674462Salfred "Cannot send broadcast packet"); 48774462Salfred stat = RPC_CANTSEND; 48874462Salfred continue; 48974462Salfred } 49074462Salfred } 49174462Salfred#ifdef RPC_DEBUG 49274462Salfred fprintf(stderr, "PMAP Broadcast packet " 49374462Salfred "sent for %s\n", 49474462Salfred fdlist[i].nconf->nc_netid); 49574462Salfred#endif 49674462Salfred#endif /* PORTMAP */ 49774462Salfred } 49874462Salfred /* End for sending all packets on this transport */ 49974462Salfred } /* End for sending on all transports */ 50074462Salfred 50174462Salfred if (eachresult == NULL) { 50274462Salfred stat = RPC_SUCCESS; 50374462Salfred goto done_broad; 50474462Salfred } 50574462Salfred 50674462Salfred /* 50774462Salfred * Get all the replies from these broadcast requests 50874462Salfred */ 50974462Salfred recv_again: 51074462Salfred 51174462Salfred switch (pollretval = _poll(pfd, fdlistno, msec)) { 51274462Salfred case 0: /* timed out */ 51374462Salfred stat = RPC_TIMEDOUT; 51474462Salfred continue; 51574462Salfred case -1: /* some kind of error - we ignore it */ 51674462Salfred goto recv_again; 51774462Salfred } /* end of poll results switch */ 51874462Salfred 51974462Salfred for (i = fds_found = 0; 52074462Salfred i < fdlistno && fds_found < pollretval; i++) { 52174462Salfred bool_t done = FALSE; 52274462Salfred 52374462Salfred if (pfd[i].revents == 0) 52474462Salfred continue; 52574462Salfred else if (pfd[i].revents & POLLNVAL) { 52674462Salfred /* 52774462Salfred * Something bad has happened to this descri- 52874462Salfred * ptor. We can cause _poll() to ignore 52974462Salfred * it simply by using a negative fd. We do that 53074462Salfred * rather than compacting the pfd[] and fdlist[] 53174462Salfred * arrays. 53274462Salfred */ 53374462Salfred pfd[i].fd = -1; 53474462Salfred fds_found++; 53574462Salfred continue; 53674462Salfred } else 53774462Salfred fds_found++; 53874462Salfred#ifdef RPC_DEBUG 53974462Salfred fprintf(stderr, "response for %s\n", 54074462Salfred fdlist[i].nconf->nc_netid); 54174462Salfred#endif 54274462Salfred try_again: 54374462Salfred inlen = _recvfrom(fdlist[i].fd, inbuf, fdlist[i].dsize, 54474462Salfred 0, (struct sockaddr *)(void *)&fdlist[i].raddr, 54574462Salfred &fdlist[i].asize); 54674462Salfred if (inlen < 0) { 54774462Salfred if (errno == EINTR) 54874462Salfred goto try_again; 54974462Salfred warnx("clnt_bcast: Cannot receive reply to " 55074462Salfred "broadcast"); 55174462Salfred stat = RPC_CANTRECV; 55274462Salfred continue; 55374462Salfred } 55474462Salfred if (inlen < sizeof (u_int32_t)) 55574462Salfred continue; /* Drop that and go ahead */ 55674462Salfred /* 55774462Salfred * see if reply transaction id matches sent id. 55874462Salfred * If so, decode the results. If return id is xid + 1 55974462Salfred * it was a PORTMAP reply 56074462Salfred */ 56174462Salfred if (*((u_int32_t *)(void *)(inbuf)) == 56274462Salfred *((u_int32_t *)(void *)(outbuf))) { 56374462Salfred pmap_reply_flag = 0; 56474462Salfred msg.acpted_rply.ar_verf = _null_auth; 56574462Salfred msg.acpted_rply.ar_results.where = 56674462Salfred (caddr_t)(void *)&bres; 56774462Salfred msg.acpted_rply.ar_results.proc = 56874462Salfred (xdrproc_t)xdr_rpcb_rmtcallres; 56974462Salfred#ifdef PORTMAP 57074462Salfred } else if (pmap_flag && 57174462Salfred *((u_int32_t *)(void *)(inbuf)) == 57274462Salfred *((u_int32_t *)(void *)(outbuf_pmap))) { 57374462Salfred pmap_reply_flag = 1; 57474462Salfred msg.acpted_rply.ar_verf = _null_auth; 57574462Salfred msg.acpted_rply.ar_results.where = 57674462Salfred (caddr_t)(void *)&bres_pmap; 57774462Salfred msg.acpted_rply.ar_results.proc = 57874462Salfred (xdrproc_t)xdr_rmtcallres; 57974462Salfred#endif /* PORTMAP */ 58074462Salfred } else 58174462Salfred continue; 58274462Salfred xdrmem_create(xdrs, inbuf, (u_int)inlen, XDR_DECODE); 58374462Salfred if (xdr_replymsg(xdrs, &msg)) { 58474462Salfred if ((msg.rm_reply.rp_stat == MSG_ACCEPTED) && 58574462Salfred (msg.acpted_rply.ar_stat == SUCCESS)) { 58674462Salfred struct netbuf taddr, *np; 58774462Salfred struct sockaddr_in *sin; 58874462Salfred 58974462Salfred#ifdef PORTMAP 59074462Salfred if (pmap_flag && pmap_reply_flag) { 59174462Salfred sin = (struct sockaddr_in *) 59274462Salfred (void *)&fdlist[i].raddr; 59374462Salfred sin->sin_port = 59474462Salfred htons((u_short)port); 59574462Salfred taddr.len = taddr.maxlen = 59674462Salfred fdlist[i].raddr.ss_len; 59774462Salfred taddr.buf = &fdlist[i].raddr; 59874462Salfred done = (*eachresult)(resultsp, 59974462Salfred &taddr, fdlist[i].nconf); 60074462Salfred } else { 60174462Salfred#endif /* PORTMAP */ 60274462Salfred#ifdef RPC_DEBUG 60374462Salfred fprintf(stderr, "uaddr %s\n", 60474462Salfred uaddrp); 60574462Salfred#endif 60674462Salfred np = uaddr2taddr( 60774462Salfred fdlist[i].nconf, uaddrp); 60874462Salfred done = (*eachresult)(resultsp, 60974462Salfred np, fdlist[i].nconf); 61074462Salfred free(np); 61174462Salfred#ifdef PORTMAP 61274462Salfred } 61374462Salfred#endif /* PORTMAP */ 61474462Salfred } 61574462Salfred /* otherwise, we just ignore the errors ... */ 61674462Salfred } 61774462Salfred /* else some kind of deserialization problem ... */ 61874462Salfred 61974462Salfred xdrs->x_op = XDR_FREE; 62074462Salfred msg.acpted_rply.ar_results.proc = (xdrproc_t) xdr_void; 62174462Salfred (void) xdr_replymsg(xdrs, &msg); 62274462Salfred (void) (*xresults)(xdrs, resultsp); 62374462Salfred XDR_DESTROY(xdrs); 62474462Salfred if (done) { 62574462Salfred stat = RPC_SUCCESS; 62674462Salfred goto done_broad; 62774462Salfred } else { 62874462Salfred goto recv_again; 62974462Salfred } 63074462Salfred } /* The recv for loop */ 63174462Salfred } /* The giant for loop */ 63274462Salfred 63374462Salfreddone_broad: 63474462Salfred if (inbuf) 63574462Salfred (void) free(inbuf); 63674462Salfred if (outbuf) 63774462Salfred (void) free(outbuf); 63874462Salfred#ifdef PORTMAP 63974462Salfred if (outbuf_pmap) 64074462Salfred (void) free(outbuf_pmap); 64174462Salfred#endif /* PORTMAP */ 64274462Salfred for (i = 0; i < fdlistno; i++) { 64374462Salfred (void)_close(fdlist[i].fd); 64474462Salfred __rpc_freebroadifs(&fdlist[i].nal); 64574462Salfred } 64674462Salfred AUTH_DESTROY(sys_auth); 64774462Salfred (void) __rpc_endconf(handle); 64874462Salfred 64974462Salfred return (stat); 65074462Salfred} 65174462Salfred 65274462Salfred 65374462Salfredenum clnt_stat 65474462Salfredrpc_broadcast(prog, vers, proc, xargs, argsp, xresults, resultsp, 65574462Salfred eachresult, nettype) 65674462Salfred rpcprog_t prog; /* program number */ 65774462Salfred rpcvers_t vers; /* version number */ 65874462Salfred rpcproc_t proc; /* procedure number */ 65974462Salfred xdrproc_t xargs; /* xdr routine for args */ 66074462Salfred caddr_t argsp; /* pointer to args */ 66174462Salfred xdrproc_t xresults; /* xdr routine for results */ 66274462Salfred caddr_t resultsp; /* pointer to results */ 66374462Salfred resultproc_t eachresult; /* call with each result obtained */ 66474462Salfred const char *nettype; /* transport type */ 66574462Salfred{ 66674462Salfred enum clnt_stat dummy; 66774462Salfred 66874462Salfred dummy = rpc_broadcast_exp(prog, vers, proc, xargs, argsp, 66974462Salfred xresults, resultsp, eachresult, 67074462Salfred INITTIME, WAITTIME, nettype); 67174462Salfred return (dummy); 67274462Salfred} 673