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