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