xref: /illumos-gate/usr/src/stand/lib/fs/nfs/pmap.c (revision b531f6d1)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
237c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate /*
287c478bd9Sstevel@tonic-gate  * This file contains the routines that maintain a linked list of known
297c478bd9Sstevel@tonic-gate  * program to udp port mappings. There are three static members initialized
307c478bd9Sstevel@tonic-gate  * by default, one for the portmapper itself (of course), one for rpcbind,
317c478bd9Sstevel@tonic-gate  * and one for nfs. If a program number is not in the list, then routines
327c478bd9Sstevel@tonic-gate  * in this file contact the portmapper on the server, and dynamically add
337c478bd9Sstevel@tonic-gate  * new members to this list.
347c478bd9Sstevel@tonic-gate  *
357c478bd9Sstevel@tonic-gate  * This file also contains bpmap_rmtcall() - which lets one get the port
367c478bd9Sstevel@tonic-gate  * number AND run the rpc call in one step. Only the server that successfully
377c478bd9Sstevel@tonic-gate  * completes the rpc call will return a result.
387c478bd9Sstevel@tonic-gate  *
397c478bd9Sstevel@tonic-gate  * NOTE: Because we will end up caching the port entries we need
407c478bd9Sstevel@tonic-gate  * before the kernel begins running, we can use dynamic allocation here.
417c478bd9Sstevel@tonic-gate  * boot_memfree() calls bpmap_memfree() to free up any dynamically
427c478bd9Sstevel@tonic-gate  * allocated entries when the boot program has finished its job.
437c478bd9Sstevel@tonic-gate  */
447c478bd9Sstevel@tonic-gate 
457c478bd9Sstevel@tonic-gate #include <sys/types.h>
467c478bd9Sstevel@tonic-gate #include <rpc/types.h>
477c478bd9Sstevel@tonic-gate #include <sys/errno.h>
487c478bd9Sstevel@tonic-gate #include <sys/time.h>
497c478bd9Sstevel@tonic-gate #include <sys/socket.h>
507c478bd9Sstevel@tonic-gate #include <net/if.h>
517c478bd9Sstevel@tonic-gate #include <netinet/in.h>
527c478bd9Sstevel@tonic-gate #include <netinet/if_ether.h>
537c478bd9Sstevel@tonic-gate #include <rpc/xdr.h>
547c478bd9Sstevel@tonic-gate #include <rpc/auth.h>
557c478bd9Sstevel@tonic-gate #include <sys/t_lock.h>
567c478bd9Sstevel@tonic-gate #include "clnt.h"
577c478bd9Sstevel@tonic-gate #include <rpc/pmap_prot.h>
587c478bd9Sstevel@tonic-gate #include <rpc/pmap_rmt.h>
597c478bd9Sstevel@tonic-gate #include <rpc/rpc.h>
607c478bd9Sstevel@tonic-gate #include "brpc.h"
617c478bd9Sstevel@tonic-gate #include "pmap.h"
627c478bd9Sstevel@tonic-gate #include "nfs_inet.h"
637c478bd9Sstevel@tonic-gate #include <rpcsvc/nfs_prot.h>
647c478bd9Sstevel@tonic-gate #include <rpc/rpcb_prot.h>
657c478bd9Sstevel@tonic-gate #include <sys/salib.h>
667c478bd9Sstevel@tonic-gate #include "socket_inet.h"
677c478bd9Sstevel@tonic-gate #include <sys/promif.h>
687c478bd9Sstevel@tonic-gate #include <sys/bootdebug.h>
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate /* portmap structure */
717c478bd9Sstevel@tonic-gate #define	PMAP_STATIC	(3)	/* last statically allocated list entry */
727c478bd9Sstevel@tonic-gate struct pmaplist pre_init[PMAP_STATIC + 1] = {
737c478bd9Sstevel@tonic-gate 	{ {PMAPPROG,	PMAPVERS,	IPPROTO_UDP, PMAPPORT}, &pre_init[1] },
747c478bd9Sstevel@tonic-gate 	/* SVR4 rpcbind listens to old portmapper port */
757c478bd9Sstevel@tonic-gate 	{ {RPCBPROG,	RPCBVERS,	IPPROTO_UDP, PMAPPORT}, &pre_init[2] },
767c478bd9Sstevel@tonic-gate 	{ {NFS_PROGRAM, NFS_VERSION,	IPPROTO_UDP, NFS_PORT}, &pre_init[3] },
777c478bd9Sstevel@tonic-gate 	{ {NFS_PROGRAM, NFS_V3,		IPPROTO_UDP, NFS_PORT}, NULL }
787c478bd9Sstevel@tonic-gate };
797c478bd9Sstevel@tonic-gate 
807c478bd9Sstevel@tonic-gate struct pmaplist *map_head = &pre_init[0];
817c478bd9Sstevel@tonic-gate struct pmaplist *map_tail = &pre_init[PMAP_STATIC];
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate #define	dprintf	if (boothowto & RB_DEBUG) printf
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate /*
867c478bd9Sstevel@tonic-gate  * bpmap_addport: adds a new entry on to the end of the pmap cache.
877c478bd9Sstevel@tonic-gate  * Items are kept in host order.
887c478bd9Sstevel@tonic-gate  */
897c478bd9Sstevel@tonic-gate static void
bpmap_addport(rpcprog_t prog,rpcvers_t vers,rpcport_t port)907c478bd9Sstevel@tonic-gate bpmap_addport(rpcprog_t prog, rpcvers_t vers, rpcport_t port)
917c478bd9Sstevel@tonic-gate {
927c478bd9Sstevel@tonic-gate 	struct pmaplist *newp;
937c478bd9Sstevel@tonic-gate 
947c478bd9Sstevel@tonic-gate 	/* allocate new pmaplist */
957c478bd9Sstevel@tonic-gate 	newp = (struct pmaplist *)bkmem_alloc(sizeof (struct pmaplist));
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate 	if (newp == NULL)
987c478bd9Sstevel@tonic-gate 		return; /* not fatal here, we'll just throw out the entry */
997c478bd9Sstevel@tonic-gate 
1007c478bd9Sstevel@tonic-gate 	newp->pml_map.pm_prog = prog;
1017c478bd9Sstevel@tonic-gate 	newp->pml_map.pm_vers = vers;
1027c478bd9Sstevel@tonic-gate 	newp->pml_map.pm_prot = (rpcprot_t)IPPROTO_UDP;
1037c478bd9Sstevel@tonic-gate 	newp->pml_map.pm_port = port;
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate 	map_tail->pml_next = newp;
1067c478bd9Sstevel@tonic-gate 	newp->pml_next = NULL;
1077c478bd9Sstevel@tonic-gate 	map_tail = newp;
1087c478bd9Sstevel@tonic-gate }
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate /*
1117c478bd9Sstevel@tonic-gate  * bpmap_delport: deletes an existing entry from the list. Caution - don't
1127c478bd9Sstevel@tonic-gate  * call this function to delete statically allocated entries. Why would
1137c478bd9Sstevel@tonic-gate  * you want to, anyway? Only IPPROTO_UDP is supported, of course.
1147c478bd9Sstevel@tonic-gate  */
1157c478bd9Sstevel@tonic-gate static void
bpmap_delport(rpcprog_t prog,rpcvers_t vers)1167c478bd9Sstevel@tonic-gate bpmap_delport(rpcprog_t prog, rpcvers_t vers)
1177c478bd9Sstevel@tonic-gate {
1187c478bd9Sstevel@tonic-gate 	struct pmaplist *tmp, *prev;
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate 	prev = map_head;
1217c478bd9Sstevel@tonic-gate 	for (tmp = map_head; tmp != NULL; tmp = tmp->pml_next) {
1227c478bd9Sstevel@tonic-gate 		if ((tmp->pml_map.pm_prog == prog) &&
1237c478bd9Sstevel@tonic-gate 		    (tmp->pml_map.pm_vers == vers)) {
1247c478bd9Sstevel@tonic-gate 			if (tmp == map_head)
1257c478bd9Sstevel@tonic-gate 				map_head = tmp->pml_next; /* new head */
1267c478bd9Sstevel@tonic-gate 			else if (tmp == map_tail) {
1277c478bd9Sstevel@tonic-gate 				map_tail = prev;	/* new tail */
1287c478bd9Sstevel@tonic-gate 				map_tail->pml_next = NULL;
1297c478bd9Sstevel@tonic-gate 			} else {
1307c478bd9Sstevel@tonic-gate 				/* internal delete */
1317c478bd9Sstevel@tonic-gate 				prev->pml_next = tmp->pml_next;
1327c478bd9Sstevel@tonic-gate 			}
1337c478bd9Sstevel@tonic-gate #ifdef	DEBUG
1347c478bd9Sstevel@tonic-gate 			printf("bpmap_delport: prog: %x, vers: %x\n", prog,
1357c478bd9Sstevel@tonic-gate 			    vers);
1367c478bd9Sstevel@tonic-gate #endif	/* DEBUG */
1377c478bd9Sstevel@tonic-gate 			bkmem_free((caddr_t)tmp, sizeof (struct pmaplist));
1387c478bd9Sstevel@tonic-gate 			break;
1397c478bd9Sstevel@tonic-gate 		} else
1407c478bd9Sstevel@tonic-gate 			prev = tmp;
1417c478bd9Sstevel@tonic-gate 	}
1427c478bd9Sstevel@tonic-gate }
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate /*
1457c478bd9Sstevel@tonic-gate  * Modified strtol(3).
1467c478bd9Sstevel@tonic-gate  */
1477c478bd9Sstevel@tonic-gate static int
strtoi(char * str,char ** ptr)1487c478bd9Sstevel@tonic-gate strtoi(char *str, char **ptr)
1497c478bd9Sstevel@tonic-gate {
1507c478bd9Sstevel@tonic-gate 	int c, val;
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate 	for (val = 0, c = *str++; c >= '0' && c <= '9'; c = *str++) {
1537c478bd9Sstevel@tonic-gate 		val *= 10;
1547c478bd9Sstevel@tonic-gate 		val += c - '0';
1557c478bd9Sstevel@tonic-gate 	}
1567c478bd9Sstevel@tonic-gate 	*ptr = str;
1577c478bd9Sstevel@tonic-gate 	return (val);
1587c478bd9Sstevel@tonic-gate }
1597c478bd9Sstevel@tonic-gate 
1607c478bd9Sstevel@tonic-gate /*
1617c478bd9Sstevel@tonic-gate  * (from dlboot_inet.c) (kernel)
1627c478bd9Sstevel@tonic-gate  * Convert a port number from a sockaddr_in expressed
1637c478bd9Sstevel@tonic-gate  * in universal address format.
1647c478bd9Sstevel@tonic-gate  */
1657c478bd9Sstevel@tonic-gate static int
uaddr2port(char * addr)1667c478bd9Sstevel@tonic-gate uaddr2port(char	*addr)
1677c478bd9Sstevel@tonic-gate {
1687c478bd9Sstevel@tonic-gate 	int	p1, p2;
1697c478bd9Sstevel@tonic-gate 	char	*next;
1707c478bd9Sstevel@tonic-gate 
1717c478bd9Sstevel@tonic-gate 	/*
1727c478bd9Sstevel@tonic-gate 	 * A struct sockaddr_in expressed in universal address
1737c478bd9Sstevel@tonic-gate 	 * format looks like:
1747c478bd9Sstevel@tonic-gate 	 *
1757c478bd9Sstevel@tonic-gate 	 *	"IP.IP.IP.IP.PORT[top byte].PORT[bot. byte]"
1767c478bd9Sstevel@tonic-gate 	 *
1777c478bd9Sstevel@tonic-gate 	 * Where each component expresses as a charactor,
1787c478bd9Sstevel@tonic-gate 	 * the corresponding part of the IP address
1797c478bd9Sstevel@tonic-gate 	 * and port number.
1807c478bd9Sstevel@tonic-gate 	 * Thus 127.0.0.1, port 2345 looks like:
1817c478bd9Sstevel@tonic-gate 	 *
1827c478bd9Sstevel@tonic-gate 	 *	49 50 55 46 48 46 48 46 49 46 57 46 52 49
1837c478bd9Sstevel@tonic-gate 	 *	1  2  7  .  0  .  0  .  1  .  9  .  4  1
1847c478bd9Sstevel@tonic-gate 	 *
1857c478bd9Sstevel@tonic-gate 	 * 2345 = 929base16 = 9.32+9 = 9.41
1867c478bd9Sstevel@tonic-gate 	 */
1877c478bd9Sstevel@tonic-gate 	(void) strtoi(addr, &next);
1887c478bd9Sstevel@tonic-gate 	(void) strtoi(next, &next);
1897c478bd9Sstevel@tonic-gate 	(void) strtoi(next, &next);
1907c478bd9Sstevel@tonic-gate 	(void) strtoi(next, &next);
1917c478bd9Sstevel@tonic-gate 	p1 = strtoi(next, &next);
1927c478bd9Sstevel@tonic-gate 	p2 = strtoi(next, &next);
1937c478bd9Sstevel@tonic-gate 
1947c478bd9Sstevel@tonic-gate 	return ((p1 << 8) + p2);
1957c478bd9Sstevel@tonic-gate }
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate /*
1987c478bd9Sstevel@tonic-gate  * Xdr routines used for calling portmapper/rpcbind.
1997c478bd9Sstevel@tonic-gate  */
2007c478bd9Sstevel@tonic-gate 
2017c478bd9Sstevel@tonic-gate bool_t
xdr_pmap(XDR * xdrs,struct pmap * regs)2027c478bd9Sstevel@tonic-gate xdr_pmap(XDR *xdrs, struct pmap *regs)
2037c478bd9Sstevel@tonic-gate {
2047c478bd9Sstevel@tonic-gate 	if (xdr_rpcprog(xdrs, &regs->pm_prog) &&
2057c478bd9Sstevel@tonic-gate 		xdr_rpcvers(xdrs, &regs->pm_vers) &&
2067c478bd9Sstevel@tonic-gate 		xdr_rpcprot(xdrs, &regs->pm_prot))
2077c478bd9Sstevel@tonic-gate 		return (xdr_rpcprot(xdrs, &regs->pm_port));
2087c478bd9Sstevel@tonic-gate 	return (FALSE);
2097c478bd9Sstevel@tonic-gate }
2107c478bd9Sstevel@tonic-gate 
2117c478bd9Sstevel@tonic-gate bool_t
xdr_rpcb(XDR * xdrs,RPCB * objp)2127c478bd9Sstevel@tonic-gate xdr_rpcb(XDR *xdrs, RPCB *objp)
2137c478bd9Sstevel@tonic-gate {
2147c478bd9Sstevel@tonic-gate 	if (!xdr_rpcprog(xdrs, &objp->r_prog))
2157c478bd9Sstevel@tonic-gate 		return (FALSE);
2167c478bd9Sstevel@tonic-gate 	if (!xdr_rpcvers(xdrs, &objp->r_vers))
2177c478bd9Sstevel@tonic-gate 		return (FALSE);
2187c478bd9Sstevel@tonic-gate 	if (!xdr_string(xdrs, &objp->r_netid, ~0))
2197c478bd9Sstevel@tonic-gate 		return (FALSE);
2207c478bd9Sstevel@tonic-gate 	if (!xdr_string(xdrs, &objp->r_addr, ~0))
2217c478bd9Sstevel@tonic-gate 		return (FALSE);
2227c478bd9Sstevel@tonic-gate 	if (!xdr_string(xdrs, &objp->r_owner, ~0))
2237c478bd9Sstevel@tonic-gate 		return (FALSE);
2247c478bd9Sstevel@tonic-gate 	return (TRUE);
2257c478bd9Sstevel@tonic-gate }
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate /*
2287c478bd9Sstevel@tonic-gate  * XDR remote call arguments
2297c478bd9Sstevel@tonic-gate  * written for XDR_ENCODE direction only
2307c478bd9Sstevel@tonic-gate  */
2317c478bd9Sstevel@tonic-gate bool_t
xdr_rmtcall_args(XDR * xdrs,struct rmtcallargs * cap)2327c478bd9Sstevel@tonic-gate xdr_rmtcall_args(XDR *xdrs, struct rmtcallargs *cap)
2337c478bd9Sstevel@tonic-gate {
2347c478bd9Sstevel@tonic-gate 	uint_t	lenposition, argposition, position;
2357c478bd9Sstevel@tonic-gate 
2367c478bd9Sstevel@tonic-gate 	if (xdr_rpcprog(xdrs, &(cap->prog)) &&
2377c478bd9Sstevel@tonic-gate 	    xdr_rpcvers(xdrs, &(cap->vers)) &&
2387c478bd9Sstevel@tonic-gate 	    xdr_rpcproc(xdrs, &(cap->proc))) {
2397c478bd9Sstevel@tonic-gate 		lenposition = XDR_GETPOS(xdrs);
2407c478bd9Sstevel@tonic-gate 		if (!xdr_u_int(xdrs, &(cap->arglen)))
2417c478bd9Sstevel@tonic-gate 			return (FALSE);
2427c478bd9Sstevel@tonic-gate 		argposition = XDR_GETPOS(xdrs);
2437c478bd9Sstevel@tonic-gate 		if (!(*(cap->xdr_args))(xdrs, cap->args_ptr))
2447c478bd9Sstevel@tonic-gate 			return (FALSE);
2457c478bd9Sstevel@tonic-gate 		position = XDR_GETPOS(xdrs);
2467c478bd9Sstevel@tonic-gate 		cap->arglen = position - argposition;
247*b531f6d1SToomas Soome 		(void) XDR_SETPOS(xdrs, lenposition);
2487c478bd9Sstevel@tonic-gate 		if (!xdr_u_int(xdrs, &(cap->arglen)))
2497c478bd9Sstevel@tonic-gate 			return (FALSE);
250*b531f6d1SToomas Soome 		(void) XDR_SETPOS(xdrs, position);
2517c478bd9Sstevel@tonic-gate 		return (TRUE);
2527c478bd9Sstevel@tonic-gate 	}
2537c478bd9Sstevel@tonic-gate 	return (FALSE);
2547c478bd9Sstevel@tonic-gate }
2557c478bd9Sstevel@tonic-gate 
2567c478bd9Sstevel@tonic-gate /*
2577c478bd9Sstevel@tonic-gate  * XDR remote call results
2587c478bd9Sstevel@tonic-gate  * written for XDR_DECODE direction only
2597c478bd9Sstevel@tonic-gate  */
2607c478bd9Sstevel@tonic-gate bool_t
xdr_rmtcallres(XDR * xdrs,struct rmtcallres * crp)2617c478bd9Sstevel@tonic-gate xdr_rmtcallres(XDR *xdrs, struct rmtcallres *crp)
2627c478bd9Sstevel@tonic-gate {
2637c478bd9Sstevel@tonic-gate 	caddr_t	port_ptr;
2647c478bd9Sstevel@tonic-gate 
2657c478bd9Sstevel@tonic-gate 	port_ptr = (caddr_t)crp->port_ptr;
2667c478bd9Sstevel@tonic-gate 	if (xdr_reference(xdrs, &port_ptr, sizeof (uint_t), xdr_u_int) &&
2677c478bd9Sstevel@tonic-gate 	    xdr_u_int(xdrs, &crp->resultslen)) {
2687c478bd9Sstevel@tonic-gate 		crp->port_ptr = (rpcport_t *)port_ptr;
2697c478bd9Sstevel@tonic-gate 		return ((*(crp->xdr_results))(xdrs, crp->results_ptr));
2707c478bd9Sstevel@tonic-gate 	}
2717c478bd9Sstevel@tonic-gate 	return (FALSE);
2727c478bd9Sstevel@tonic-gate }
2737c478bd9Sstevel@tonic-gate 
2747c478bd9Sstevel@tonic-gate /*
2757c478bd9Sstevel@tonic-gate  * XDR remote call arguments
2767c478bd9Sstevel@tonic-gate  * written for XDR_ENCODE direction only
2777c478bd9Sstevel@tonic-gate  */
2787c478bd9Sstevel@tonic-gate bool_t
xdr_rpcb_rmtcallargs(XDR * xdrs,struct rpcb_rmtcallargs * objp)2797c478bd9Sstevel@tonic-gate xdr_rpcb_rmtcallargs(XDR *xdrs, struct rpcb_rmtcallargs *objp)
2807c478bd9Sstevel@tonic-gate {
2817c478bd9Sstevel@tonic-gate 	uint_t lenposition, argposition, position;
2827c478bd9Sstevel@tonic-gate 
2837c478bd9Sstevel@tonic-gate 	if (!xdr_rpcprog(xdrs, &objp->prog))
2847c478bd9Sstevel@tonic-gate 		return (FALSE);
2857c478bd9Sstevel@tonic-gate 	if (!xdr_rpcvers(xdrs, &objp->vers))
2867c478bd9Sstevel@tonic-gate 		return (FALSE);
2877c478bd9Sstevel@tonic-gate 	if (!xdr_rpcproc(xdrs, &objp->proc))
2887c478bd9Sstevel@tonic-gate 		return (FALSE);
2897c478bd9Sstevel@tonic-gate 	/*
2907c478bd9Sstevel@tonic-gate 	 * All the jugglery for just getting the size of the arguments
2917c478bd9Sstevel@tonic-gate 	 */
2927c478bd9Sstevel@tonic-gate 	lenposition = XDR_GETPOS(xdrs);
2937c478bd9Sstevel@tonic-gate 	if (!xdr_u_int(xdrs, &(objp->arglen)))
2947c478bd9Sstevel@tonic-gate 		return (FALSE);
2957c478bd9Sstevel@tonic-gate 	argposition = XDR_GETPOS(xdrs);
2967c478bd9Sstevel@tonic-gate 	if (!(*(objp->xdr_args))(xdrs, objp->args_ptr))
2977c478bd9Sstevel@tonic-gate 		return (FALSE);
2987c478bd9Sstevel@tonic-gate 	position = XDR_GETPOS(xdrs);
2997c478bd9Sstevel@tonic-gate 	objp->arglen = position - argposition;
300*b531f6d1SToomas Soome 	(void) XDR_SETPOS(xdrs, lenposition);
3017c478bd9Sstevel@tonic-gate 	if (!xdr_u_int(xdrs, &(objp->arglen)))
3027c478bd9Sstevel@tonic-gate 		return (FALSE);
303*b531f6d1SToomas Soome 	(void) XDR_SETPOS(xdrs, position);
3047c478bd9Sstevel@tonic-gate 	return (TRUE);
3057c478bd9Sstevel@tonic-gate }
3067c478bd9Sstevel@tonic-gate 
3077c478bd9Sstevel@tonic-gate /*
3087c478bd9Sstevel@tonic-gate  * XDR remote call results
3097c478bd9Sstevel@tonic-gate  * written for XDR_DECODE direction only
3107c478bd9Sstevel@tonic-gate  */
3117c478bd9Sstevel@tonic-gate bool_t
xdr_rpcb_rmtcallres(XDR * xdrs,struct rpcb_rmtcallres * objp)3127c478bd9Sstevel@tonic-gate xdr_rpcb_rmtcallres(XDR *xdrs, struct rpcb_rmtcallres *objp)
3137c478bd9Sstevel@tonic-gate {
3147c478bd9Sstevel@tonic-gate 	if (!xdr_string(xdrs, &objp->addr_ptr, ~0))
3157c478bd9Sstevel@tonic-gate 		return (FALSE);
3167c478bd9Sstevel@tonic-gate 	if (!xdr_u_int(xdrs, &objp->resultslen))
3177c478bd9Sstevel@tonic-gate 		return (FALSE);
3187c478bd9Sstevel@tonic-gate 	return ((*(objp->xdr_results))(xdrs, objp->results_ptr));
3197c478bd9Sstevel@tonic-gate }
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate /*
3227c478bd9Sstevel@tonic-gate  * bpmap_rmtcall: does PMAPPROC_CALLIT broadcasts w/ rpc_call requests.
3237c478bd9Sstevel@tonic-gate  * Lets one do a PMAPGETPORT/RPC PROC call in one easy step. sockaddr_in args
3247c478bd9Sstevel@tonic-gate  * are taken as network order.
3257c478bd9Sstevel@tonic-gate  *
3267c478bd9Sstevel@tonic-gate  * Code adapted from bpmap_rmtcall() in dlboot_inet.c (kernel)
3277c478bd9Sstevel@tonic-gate  */
3287c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3297c478bd9Sstevel@tonic-gate enum clnt_stat
bpmap_rmtcall(rpcprog_t prog,rpcvers_t vers,rpcproc_t proc,xdrproc_t in_xdr,caddr_t args,xdrproc_t out_xdr,caddr_t ret,int rexmit,int wait,struct sockaddr_in * to,struct sockaddr_in * from,uint_t auth)3307c478bd9Sstevel@tonic-gate bpmap_rmtcall(
3317c478bd9Sstevel@tonic-gate 	rpcprog_t		prog,	/* rpc program number to call. */
3327c478bd9Sstevel@tonic-gate 	rpcvers_t		vers,	/* rpc program version */
3337c478bd9Sstevel@tonic-gate 	rpcproc_t		proc,	/* rpc procedure to call */
3347c478bd9Sstevel@tonic-gate 	xdrproc_t		in_xdr,	/* routine to serialize arguments */
3357c478bd9Sstevel@tonic-gate 	caddr_t			args,	/* arg vector for remote call */
3367c478bd9Sstevel@tonic-gate 	xdrproc_t		out_xdr, /* routine to deserialize results */
3377c478bd9Sstevel@tonic-gate 	caddr_t			ret,	/* addr of buf to place results in */
3387c478bd9Sstevel@tonic-gate 	int			rexmit,	/* retransmission interval (secs) */
3397c478bd9Sstevel@tonic-gate 	int			wait,	/* how long (secs) to wait for a resp */
3407c478bd9Sstevel@tonic-gate 	struct sockaddr_in 	*to,	/* destination */
3417c478bd9Sstevel@tonic-gate 	struct sockaddr_in	*from,	/* filled in w/ responder's port/addr */
3427c478bd9Sstevel@tonic-gate 	uint_t			auth)	/* type of authentication wanted. */
3437c478bd9Sstevel@tonic-gate {
3447c478bd9Sstevel@tonic-gate 	enum clnt_stat		status;		/* rpc_call status */
3457c478bd9Sstevel@tonic-gate 	rpcport_t		port = 0;	/* returned port # */
3467c478bd9Sstevel@tonic-gate 	struct rmtcallargs	pmap_a;		/* args for pmap call */
3477c478bd9Sstevel@tonic-gate 	struct rmtcallres	pmap_r;		/* results from pmap call */
3487c478bd9Sstevel@tonic-gate 	struct rpcb_rmtcallargs	rpcb_a;		/* args for rpcb call */
3497c478bd9Sstevel@tonic-gate 	struct rpcb_rmtcallres	rpcb_r;		/* results from rpcb call */
3507c478bd9Sstevel@tonic-gate 	char			ua[UA_SIZE];	/* universal addr buffer */
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate 	/* initialize pmap */
3537c478bd9Sstevel@tonic-gate 	pmap_a.prog = prog;
3547c478bd9Sstevel@tonic-gate 	pmap_a.vers = vers;
3557c478bd9Sstevel@tonic-gate 	pmap_a.proc = proc;
3567c478bd9Sstevel@tonic-gate 	pmap_a.args_ptr = args;
3577c478bd9Sstevel@tonic-gate 	pmap_a.xdr_args = in_xdr;
3587c478bd9Sstevel@tonic-gate 	pmap_r.port_ptr = &port;
3597c478bd9Sstevel@tonic-gate 	pmap_r.results_ptr = ret;
3607c478bd9Sstevel@tonic-gate 	pmap_r.xdr_results = out_xdr;
3617c478bd9Sstevel@tonic-gate 
3627c478bd9Sstevel@tonic-gate 	status = brpc_call((rpcprog_t)PMAPPROG, (rpcvers_t)PMAPVERS,
3637c478bd9Sstevel@tonic-gate 	    (rpcproc_t)PMAPPROC_CALLIT, xdr_rmtcall_args, (caddr_t)&pmap_a,
3647c478bd9Sstevel@tonic-gate 	    xdr_rmtcallres, (caddr_t)&pmap_r, rexmit, wait, to, from,
3657c478bd9Sstevel@tonic-gate 	    AUTH_NONE);
3667c478bd9Sstevel@tonic-gate 	if (status != RPC_PROGUNAVAIL) {
3677c478bd9Sstevel@tonic-gate 		if (status == RPC_SUCCESS) {
3687c478bd9Sstevel@tonic-gate 			/* delete old port mapping, if it exists */
3697c478bd9Sstevel@tonic-gate 			bpmap_delport(prog, vers);
3707c478bd9Sstevel@tonic-gate 
3717c478bd9Sstevel@tonic-gate 			/* save the new port mapping */
3727c478bd9Sstevel@tonic-gate 			bpmap_addport(prog, vers, port);
3737c478bd9Sstevel@tonic-gate 		}
3747c478bd9Sstevel@tonic-gate 		return (status);
3757c478bd9Sstevel@tonic-gate 	}
3767c478bd9Sstevel@tonic-gate 
3777c478bd9Sstevel@tonic-gate 	/*
3787c478bd9Sstevel@tonic-gate 	 * PMAP is unavailable. Maybe there's a SVR4 machine, with rpcbind.
3797c478bd9Sstevel@tonic-gate 	 */
3807c478bd9Sstevel@tonic-gate 	bzero(ua, sizeof (ua));
3817c478bd9Sstevel@tonic-gate 
3827c478bd9Sstevel@tonic-gate 	/* initialize rpcb */
3837c478bd9Sstevel@tonic-gate 	rpcb_a.prog = prog;
3847c478bd9Sstevel@tonic-gate 	rpcb_a.vers = vers;
3857c478bd9Sstevel@tonic-gate 	rpcb_a.proc = proc;
3867c478bd9Sstevel@tonic-gate 	rpcb_a.args_ptr = args;
3877c478bd9Sstevel@tonic-gate 	rpcb_a.xdr_args = in_xdr;
3887c478bd9Sstevel@tonic-gate 	rpcb_r.addr_ptr = ua;
3897c478bd9Sstevel@tonic-gate 	rpcb_r.results_ptr = ret;
3907c478bd9Sstevel@tonic-gate 	rpcb_r.xdr_results = out_xdr;
3917c478bd9Sstevel@tonic-gate 
3927c478bd9Sstevel@tonic-gate 	status = brpc_call((rpcprog_t)RPCBPROG, (rpcvers_t)RPCBVERS,
3937c478bd9Sstevel@tonic-gate 	    (rpcproc_t)RPCBPROC_CALLIT, xdr_rpcb_rmtcallargs, (caddr_t)&rpcb_a,
3947c478bd9Sstevel@tonic-gate 	    xdr_rpcb_rmtcallres, (caddr_t)&rpcb_r, rexmit, wait, to, from,
3957c478bd9Sstevel@tonic-gate 	    AUTH_NONE);
3967c478bd9Sstevel@tonic-gate 	if (status == RPC_SUCCESS) {
3977c478bd9Sstevel@tonic-gate 		/* delete old port mapping, if it exists */
3987c478bd9Sstevel@tonic-gate 		bpmap_delport(prog, vers);
3997c478bd9Sstevel@tonic-gate 
4007c478bd9Sstevel@tonic-gate 		/* save the new port mapping */
4017c478bd9Sstevel@tonic-gate 		port = ntohs(uaddr2port(ua));
4027c478bd9Sstevel@tonic-gate 		bpmap_addport(prog, vers, port);
4037c478bd9Sstevel@tonic-gate 	}
4047c478bd9Sstevel@tonic-gate 	return (status);
4057c478bd9Sstevel@tonic-gate }
4067c478bd9Sstevel@tonic-gate 
4077c478bd9Sstevel@tonic-gate /*
4087c478bd9Sstevel@tonic-gate  * bpmap_getport: Queries current list of cached pmap_list entries,
4097c478bd9Sstevel@tonic-gate  * returns the port number of the entry found. If the port number
4107c478bd9Sstevel@tonic-gate  * is not cached, then getport makes a rpc call first to the portmapper,
4117c478bd9Sstevel@tonic-gate  * and then to rpcbind (SVR4) if the portmapper does not respond. The
4127c478bd9Sstevel@tonic-gate  * returned port is then added to the cache, and the port number is
4137c478bd9Sstevel@tonic-gate  * returned. If both portmapper and rpc bind fail to give us the necessary
4147c478bd9Sstevel@tonic-gate  * port, we return 0 to signal we hit an error, and set rpc_stat to
4157c478bd9Sstevel@tonic-gate  * the appropriate RPC error code. Only IPPROTO_UDP protocol is supported.
4167c478bd9Sstevel@tonic-gate  *
4177c478bd9Sstevel@tonic-gate  * Port and sockaddr_in arguments taken in network order. rpcport_t is returned
4187c478bd9Sstevel@tonic-gate  * in host order.
4197c478bd9Sstevel@tonic-gate  */
4207c478bd9Sstevel@tonic-gate rpcport_t
bpmap_getport(rpcprog_t prog,rpcvers_t vers,enum clnt_stat * rpc_stat,struct sockaddr_in * to,struct sockaddr_in * from)4217c478bd9Sstevel@tonic-gate bpmap_getport(rpcprog_t prog, rpcvers_t vers, enum clnt_stat *rpc_stat,
4227c478bd9Sstevel@tonic-gate     struct sockaddr_in *to, struct sockaddr_in *from)
4237c478bd9Sstevel@tonic-gate {
4247c478bd9Sstevel@tonic-gate 	struct pmaplist	*walk;
4257c478bd9Sstevel@tonic-gate 	struct pmap	pmap_send;	/* portmap */
4267c478bd9Sstevel@tonic-gate 	in_port_t	pmap_port;
4277c478bd9Sstevel@tonic-gate 	rpcport_t	dport;
4287c478bd9Sstevel@tonic-gate 
4297c478bd9Sstevel@tonic-gate #ifdef DEBUG
4307c478bd9Sstevel@tonic-gate 	printf("bpmap_getport: called with: prog: %d, vers: %d\n", prog, vers);
4317c478bd9Sstevel@tonic-gate #endif /* DEBUG */
4327c478bd9Sstevel@tonic-gate 	for (walk = map_head; walk != 0; walk = walk->pml_next) {
4337c478bd9Sstevel@tonic-gate 		if ((walk->pml_map.pm_prog == prog) &&
4347c478bd9Sstevel@tonic-gate 		    (walk->pml_map.pm_vers == vers) &&
4357c478bd9Sstevel@tonic-gate 		    (walk->pml_map.pm_prot == (rpcprot_t)IPPROTO_UDP)) {
4367c478bd9Sstevel@tonic-gate #ifdef DEBUG
4377c478bd9Sstevel@tonic-gate 			printf("bpmap_getport: Found in cache. returning: %d\n",
4387c478bd9Sstevel@tonic-gate 			    walk->pml_map.pm_port);
4397c478bd9Sstevel@tonic-gate #endif /* DEBUG */
4407c478bd9Sstevel@tonic-gate 			return (walk->pml_map.pm_port);
4417c478bd9Sstevel@tonic-gate 		}
4427c478bd9Sstevel@tonic-gate 	}
4437c478bd9Sstevel@tonic-gate 
4447c478bd9Sstevel@tonic-gate 	/*
4457c478bd9Sstevel@tonic-gate 	 * Not in the cache. First try the portmapper (SunOS server?) and
4467c478bd9Sstevel@tonic-gate 	 * if that fails, try rpcbind (SVR4 server).
4477c478bd9Sstevel@tonic-gate 	 */
4487c478bd9Sstevel@tonic-gate 	pmap_send.pm_prog = prog;
4497c478bd9Sstevel@tonic-gate 	pmap_send.pm_vers = vers;
4507c478bd9Sstevel@tonic-gate 	pmap_send.pm_prot = (rpcprot_t)IPPROTO_UDP;
4517c478bd9Sstevel@tonic-gate 	pmap_send.pm_port = 0;	/* what we're after */
4527c478bd9Sstevel@tonic-gate 
4537c478bd9Sstevel@tonic-gate 	*rpc_stat = brpc_call(PMAPPROG, PMAPVERS, PMAPPROC_GETPORT,
4547c478bd9Sstevel@tonic-gate 	    xdr_pmap, (caddr_t)&pmap_send, xdr_u_short,
4557c478bd9Sstevel@tonic-gate 	    (caddr_t)&pmap_port, 0, 0, to, from, AUTH_NONE);
4567c478bd9Sstevel@tonic-gate 
4577c478bd9Sstevel@tonic-gate 	if (*rpc_stat == RPC_PROGUNAVAIL) {
4587c478bd9Sstevel@tonic-gate 		/*
4597c478bd9Sstevel@tonic-gate 		 * The portmapper isn't available. Try rpcbind.
4607c478bd9Sstevel@tonic-gate 		 * Maybe the server is a SVR4 server.
4617c478bd9Sstevel@tonic-gate 		 */
4627c478bd9Sstevel@tonic-gate 		char	*ua;			/* universal address */
4637c478bd9Sstevel@tonic-gate 		char	ua_buf[UA_SIZE];	/* and its buffer */
4647c478bd9Sstevel@tonic-gate 		RPCB	rpcb_send;
4657c478bd9Sstevel@tonic-gate 
4667c478bd9Sstevel@tonic-gate 		rpcb_send.r_prog = prog;
4677c478bd9Sstevel@tonic-gate 		rpcb_send.r_vers = vers;
4687c478bd9Sstevel@tonic-gate 		rpcb_send.r_netid = NULL;
4697c478bd9Sstevel@tonic-gate 		rpcb_send.r_addr = NULL;
4707c478bd9Sstevel@tonic-gate 		rpcb_send.r_owner = NULL;
4717c478bd9Sstevel@tonic-gate 
4727c478bd9Sstevel@tonic-gate 		bzero(ua_buf, UA_SIZE);
4737c478bd9Sstevel@tonic-gate 		ua = ua_buf;
4747c478bd9Sstevel@tonic-gate 
4757c478bd9Sstevel@tonic-gate 		/*
4767c478bd9Sstevel@tonic-gate 		 * Again, default # of retries. xdr_wrapstring()
4777c478bd9Sstevel@tonic-gate 		 * wants a char **.
4787c478bd9Sstevel@tonic-gate 		 */
4797c478bd9Sstevel@tonic-gate 		*rpc_stat = brpc_call(RPCBPROG, RPCBVERS, RPCBPROC_GETADDR,
4807c478bd9Sstevel@tonic-gate 		    xdr_rpcb, (caddr_t)&rpcb_send, xdr_wrapstring,
4817c478bd9Sstevel@tonic-gate 		    (char *)&ua, 0, 0, to, from, AUTH_NONE);
4827c478bd9Sstevel@tonic-gate 
4837c478bd9Sstevel@tonic-gate 		if (*rpc_stat == RPC_SUCCESS) {
4847c478bd9Sstevel@tonic-gate 			if (ua[0] != '\0')
4857c478bd9Sstevel@tonic-gate 				dport = ntohs(uaddr2port(ua));
4867c478bd9Sstevel@tonic-gate 			else
4877c478bd9Sstevel@tonic-gate 				return (0); /* Address unknown */
4887c478bd9Sstevel@tonic-gate 		}
4897c478bd9Sstevel@tonic-gate 	} else {
4907c478bd9Sstevel@tonic-gate 		/*
4917c478bd9Sstevel@tonic-gate 		 * Why are rpcport_t's uint32_t? port numbers are uint16_t
4927c478bd9Sstevel@tonic-gate 		 * for ipv4 AND ipv6.... XXXX
4937c478bd9Sstevel@tonic-gate 		 */
4947c478bd9Sstevel@tonic-gate 		dport = (rpcport_t)pmap_port;
4957c478bd9Sstevel@tonic-gate 	}
4967c478bd9Sstevel@tonic-gate 
4977c478bd9Sstevel@tonic-gate 	if (*rpc_stat != RPC_SUCCESS)  {
4987c478bd9Sstevel@tonic-gate 		dprintf("pmap_getport: Failed getting port.\n");
4997c478bd9Sstevel@tonic-gate 		return (0);	/* we failed. */
5007c478bd9Sstevel@tonic-gate 	}
5017c478bd9Sstevel@tonic-gate 
5027c478bd9Sstevel@tonic-gate #ifdef DEBUG
5037c478bd9Sstevel@tonic-gate 	printf("bpmap_getport: prog: %d, vers: %d; returning port: %d.\n",
5047c478bd9Sstevel@tonic-gate 	    prog, vers, dport);
5057c478bd9Sstevel@tonic-gate #endif /* DEBUG */
5067c478bd9Sstevel@tonic-gate 
5077c478bd9Sstevel@tonic-gate 	bpmap_addport(prog, vers, dport);
5087c478bd9Sstevel@tonic-gate 
5097c478bd9Sstevel@tonic-gate 	return (dport);
5107c478bd9Sstevel@tonic-gate }
5117c478bd9Sstevel@tonic-gate 
5127c478bd9Sstevel@tonic-gate /*
5137c478bd9Sstevel@tonic-gate  * bpmap_memfree: frees up any dynamically allocated entries.
5147c478bd9Sstevel@tonic-gate  */
5157c478bd9Sstevel@tonic-gate void
bpmap_memfree(void)5167c478bd9Sstevel@tonic-gate bpmap_memfree(void)
5177c478bd9Sstevel@tonic-gate {
5187c478bd9Sstevel@tonic-gate 	struct pmaplist *current, *tmp;
5197c478bd9Sstevel@tonic-gate 
5207c478bd9Sstevel@tonic-gate 	if (map_tail == &pre_init[PMAP_STATIC])
5217c478bd9Sstevel@tonic-gate 		return; /* no dynamic entries */
5227c478bd9Sstevel@tonic-gate 
5237c478bd9Sstevel@tonic-gate 	/* free from head of the list to the tail. */
5247c478bd9Sstevel@tonic-gate 	current = pre_init[PMAP_STATIC].pml_next;
5257c478bd9Sstevel@tonic-gate 	while (current != NULL) {
5267c478bd9Sstevel@tonic-gate 		tmp = current->pml_next;
5277c478bd9Sstevel@tonic-gate 		bkmem_free((caddr_t)current, sizeof (struct pmaplist));
5287c478bd9Sstevel@tonic-gate 		current = tmp;
5297c478bd9Sstevel@tonic-gate 	}
5307c478bd9Sstevel@tonic-gate }
531