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