xref: /titanic_53/usr/src/cmd/cmd-inet/usr.sbin/route.c (revision 7a23074e5a0337b4d20bc593de1aa7ad34701913)
17c478bd9Sstevel@tonic-gate /*
2*7a23074eSdduvall  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
37c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
47c478bd9Sstevel@tonic-gate  */
57c478bd9Sstevel@tonic-gate 
67c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
77c478bd9Sstevel@tonic-gate /* All Rights Reserved  	*/
87c478bd9Sstevel@tonic-gate 
97c478bd9Sstevel@tonic-gate /* Copyright (c) 1990  Mentat Inc. */
107c478bd9Sstevel@tonic-gate 
117c478bd9Sstevel@tonic-gate /*
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * Copyright (c) 1983, 1989, 1991, 1993
147c478bd9Sstevel@tonic-gate  *	The Regents of the University of California.  All rights reserved.
157c478bd9Sstevel@tonic-gate  *
167c478bd9Sstevel@tonic-gate  * Redistribution and use in source and binary forms, with or without
177c478bd9Sstevel@tonic-gate  * modification, are permitted provided that the following conditions
187c478bd9Sstevel@tonic-gate  * are met:
197c478bd9Sstevel@tonic-gate  * 1. Redistributions of source code must retain the above copyright
207c478bd9Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer.
217c478bd9Sstevel@tonic-gate  * 2. Redistributions in binary form must reproduce the above copyright
227c478bd9Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer in the
237c478bd9Sstevel@tonic-gate  *    documentation and/or other materials provided with the distribution.
247c478bd9Sstevel@tonic-gate  * 3. All advertising materials mentioning features or use of this software
257c478bd9Sstevel@tonic-gate  *    must display the following acknowledgement:
267c478bd9Sstevel@tonic-gate  *	This product includes software developed by the University of
277c478bd9Sstevel@tonic-gate  *	California, Berkeley and its contributors.
287c478bd9Sstevel@tonic-gate  * 4. Neither the name of the University nor the names of its contributors
297c478bd9Sstevel@tonic-gate  *    may be used to endorse or promote products derived from this software
307c478bd9Sstevel@tonic-gate  *    without specific prior written permission.
317c478bd9Sstevel@tonic-gate  *
327c478bd9Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
337c478bd9Sstevel@tonic-gate  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
347c478bd9Sstevel@tonic-gate  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
357c478bd9Sstevel@tonic-gate  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
367c478bd9Sstevel@tonic-gate  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
377c478bd9Sstevel@tonic-gate  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
387c478bd9Sstevel@tonic-gate  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
397c478bd9Sstevel@tonic-gate  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
407c478bd9Sstevel@tonic-gate  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
417c478bd9Sstevel@tonic-gate  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
427c478bd9Sstevel@tonic-gate  * SUCH DAMAGE.
437c478bd9Sstevel@tonic-gate  *
447c478bd9Sstevel@tonic-gate  *	@(#)route.c	8.6 (Berkeley) 4/28/95
457c478bd9Sstevel@tonic-gate  *	@(#)linkaddr.c	8.1 (Berkeley) 6/4/93
467c478bd9Sstevel@tonic-gate  */
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate #include <sys/param.h>
517c478bd9Sstevel@tonic-gate #include <sys/file.h>
527c478bd9Sstevel@tonic-gate #include <sys/socket.h>
537c478bd9Sstevel@tonic-gate #include <sys/ioctl.h>
547c478bd9Sstevel@tonic-gate #include <sys/stream.h>
553f33f4f7Sjl138328 #include <sys/tihdr.h>
56*7a23074eSdduvall #include <sys/sysmacros.h>
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate #include <net/if.h>
597c478bd9Sstevel@tonic-gate #include <net/route.h>
607c478bd9Sstevel@tonic-gate #include <net/if_dl.h>
617c478bd9Sstevel@tonic-gate #include <netinet/in.h>
627c478bd9Sstevel@tonic-gate #include <arpa/inet.h>
637c478bd9Sstevel@tonic-gate #include <netdb.h>
647c478bd9Sstevel@tonic-gate #include <inet/mib2.h>
657c478bd9Sstevel@tonic-gate #include <inet/ip.h>
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate #include <locale.h>
687c478bd9Sstevel@tonic-gate 
697c478bd9Sstevel@tonic-gate #include <errno.h>
707c478bd9Sstevel@tonic-gate #include <unistd.h>
717c478bd9Sstevel@tonic-gate #include <stdio.h>
727c478bd9Sstevel@tonic-gate #include <stdlib.h>
737c478bd9Sstevel@tonic-gate #include <string.h>
747c478bd9Sstevel@tonic-gate #include <stropts.h>
757c478bd9Sstevel@tonic-gate #include <fcntl.h>
767c478bd9Sstevel@tonic-gate #include <assert.h>
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate static struct keytab {
797c478bd9Sstevel@tonic-gate 	char	*kt_cp;
807c478bd9Sstevel@tonic-gate 	int	kt_i;
817c478bd9Sstevel@tonic-gate } keywords[] = {
827c478bd9Sstevel@tonic-gate #define	K_ADD		1
837c478bd9Sstevel@tonic-gate 	{"add",		K_ADD},
847c478bd9Sstevel@tonic-gate #define	K_BLACKHOLE	2
857c478bd9Sstevel@tonic-gate 	{"blackhole",	K_BLACKHOLE},
867c478bd9Sstevel@tonic-gate #define	K_CHANGE	3
877c478bd9Sstevel@tonic-gate 	{"change",	K_CHANGE},
887c478bd9Sstevel@tonic-gate #define	K_CLONING	4
897c478bd9Sstevel@tonic-gate 	{"cloning",	K_CLONING},
907c478bd9Sstevel@tonic-gate #define	K_DELETE	5
917c478bd9Sstevel@tonic-gate 	{"delete",	K_DELETE},
927c478bd9Sstevel@tonic-gate #define	K_DST		6
937c478bd9Sstevel@tonic-gate 	{"dst",		K_DST},
947c478bd9Sstevel@tonic-gate #define	K_EXPIRE	7
957c478bd9Sstevel@tonic-gate 	{"expire",	K_EXPIRE},
967c478bd9Sstevel@tonic-gate #define	K_FLUSH		8
977c478bd9Sstevel@tonic-gate 	{"flush",	K_FLUSH},
987c478bd9Sstevel@tonic-gate #define	K_GATEWAY	9
997c478bd9Sstevel@tonic-gate 	{"gateway",	K_GATEWAY},
1007c478bd9Sstevel@tonic-gate #define	K_GET		11
1017c478bd9Sstevel@tonic-gate 	{"get",		K_GET},
1027c478bd9Sstevel@tonic-gate #define	K_HOPCOUNT	12
1037c478bd9Sstevel@tonic-gate 	{"hopcount",	K_HOPCOUNT},
1047c478bd9Sstevel@tonic-gate #define	K_HOST		13
1057c478bd9Sstevel@tonic-gate 	{"host",	K_HOST},
1067c478bd9Sstevel@tonic-gate #define	K_IFA		14
1077c478bd9Sstevel@tonic-gate 	{"ifa",		K_IFA},
1087c478bd9Sstevel@tonic-gate #define	K_IFACE		15
1097c478bd9Sstevel@tonic-gate 	{"iface",	K_IFACE},
1107c478bd9Sstevel@tonic-gate #define	K_IFP		16
1117c478bd9Sstevel@tonic-gate 	{"ifp",		K_IFP},
1127c478bd9Sstevel@tonic-gate #define	K_INET		17
1137c478bd9Sstevel@tonic-gate 	{"inet",	K_INET},
1147c478bd9Sstevel@tonic-gate #define	K_INET6		18
1157c478bd9Sstevel@tonic-gate 	{"inet6",	K_INET6},
1167c478bd9Sstevel@tonic-gate #define	K_INTERFACE	19
1177c478bd9Sstevel@tonic-gate 	{"interface",	K_INTERFACE},
1187c478bd9Sstevel@tonic-gate #define	K_LINK		20
1197c478bd9Sstevel@tonic-gate 	{"link",	K_LINK},
1207c478bd9Sstevel@tonic-gate #define	K_LOCK		21
1217c478bd9Sstevel@tonic-gate 	{"lock",	K_LOCK},
1227c478bd9Sstevel@tonic-gate #define	K_LOCKREST	22
1237c478bd9Sstevel@tonic-gate 	{"lockrest",	K_LOCKREST},
1247c478bd9Sstevel@tonic-gate #define	K_MASK		23
1257c478bd9Sstevel@tonic-gate 	{"mask",	K_MASK},
1267c478bd9Sstevel@tonic-gate #define	K_MONITOR	24
1277c478bd9Sstevel@tonic-gate 	{"monitor",	K_MONITOR},
1287c478bd9Sstevel@tonic-gate #define	K_MTU		25
1297c478bd9Sstevel@tonic-gate 	{"mtu",		K_MTU},
1307c478bd9Sstevel@tonic-gate #define	K_NET		26
1317c478bd9Sstevel@tonic-gate 	{"net",		K_NET},
1327c478bd9Sstevel@tonic-gate #define	K_NETMASK	27
1337c478bd9Sstevel@tonic-gate 	{"netmask",	K_NETMASK},
1347c478bd9Sstevel@tonic-gate #define	K_NOSTATIC	28
1357c478bd9Sstevel@tonic-gate 	{"nostatic",	K_NOSTATIC},
1367c478bd9Sstevel@tonic-gate #define	K_PRIVATE	29
1377c478bd9Sstevel@tonic-gate 	{"private",	K_PRIVATE},
1387c478bd9Sstevel@tonic-gate #define	K_PROTO1	30
1397c478bd9Sstevel@tonic-gate 	{"proto1",	K_PROTO1},
1407c478bd9Sstevel@tonic-gate #define	K_PROTO2	31
1417c478bd9Sstevel@tonic-gate 	{"proto2",	K_PROTO2},
1427c478bd9Sstevel@tonic-gate #define	K_RECVPIPE	32
1437c478bd9Sstevel@tonic-gate 	{"recvpipe",	K_RECVPIPE},
1447c478bd9Sstevel@tonic-gate #define	K_REJECT	33
1457c478bd9Sstevel@tonic-gate 	{"reject",	K_REJECT},
1467c478bd9Sstevel@tonic-gate #define	K_RTT		34
1477c478bd9Sstevel@tonic-gate 	{"rtt",		K_RTT},
1487c478bd9Sstevel@tonic-gate #define	K_RTTVAR	35
1497c478bd9Sstevel@tonic-gate 	{"rttvar",	K_RTTVAR},
1507c478bd9Sstevel@tonic-gate #define	K_SA		36
1517c478bd9Sstevel@tonic-gate 	{"sa",		K_SA},
1527c478bd9Sstevel@tonic-gate #define	K_SENDPIPE	37
1537c478bd9Sstevel@tonic-gate 	{"sendpipe",	K_SENDPIPE},
1547c478bd9Sstevel@tonic-gate #define	K_SSTHRESH	38
1557c478bd9Sstevel@tonic-gate 	{"ssthresh",	K_SSTHRESH},
1567c478bd9Sstevel@tonic-gate #define	K_STATIC	39
1577c478bd9Sstevel@tonic-gate 	{"static",	K_STATIC},
1587c478bd9Sstevel@tonic-gate #define	K_XRESOLVE	40
1597c478bd9Sstevel@tonic-gate 	{"xresolve",	K_XRESOLVE},
1607c478bd9Sstevel@tonic-gate #define	K_MULTIRT	41
1617c478bd9Sstevel@tonic-gate 	{"multirt",	K_MULTIRT},
1627c478bd9Sstevel@tonic-gate #define	K_SETSRC	42
1637c478bd9Sstevel@tonic-gate 	{"setsrc",	K_SETSRC},
1647c478bd9Sstevel@tonic-gate 	{0, 0}
1657c478bd9Sstevel@tonic-gate };
1667c478bd9Sstevel@tonic-gate 
167*7a23074eSdduvall static union	sockunion {
1687c478bd9Sstevel@tonic-gate 	struct	sockaddr sa;
1697c478bd9Sstevel@tonic-gate 	struct	sockaddr_in sin;
1707c478bd9Sstevel@tonic-gate 	struct	sockaddr_dl sdl;
1717c478bd9Sstevel@tonic-gate 	struct	sockaddr_in6 sin6;
172*7a23074eSdduvall } so_dst, so_gate, so_mask, so_ifa, so_ifp, so_src;
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate typedef struct	mib_item_s {
1757c478bd9Sstevel@tonic-gate 	struct mib_item_s	*next_item;
1767c478bd9Sstevel@tonic-gate 	long			group;
1777c478bd9Sstevel@tonic-gate 	long			mib_id;
1787c478bd9Sstevel@tonic-gate 	long			length;
1797c478bd9Sstevel@tonic-gate 	intmax_t		*valp;
1807c478bd9Sstevel@tonic-gate } mib_item_t;
1817c478bd9Sstevel@tonic-gate 
182*7a23074eSdduvall typedef union sockunion *sup;
1837c478bd9Sstevel@tonic-gate 
1847c478bd9Sstevel@tonic-gate static void		bprintf(FILE *fp, int b, char *s);
1857c478bd9Sstevel@tonic-gate static void		delRouteEntry(mib2_ipRouteEntry_t *rp,
1867c478bd9Sstevel@tonic-gate     mib2_ipv6RouteEntry_t *rp6, int seqno);
1877c478bd9Sstevel@tonic-gate static void		flushroutes(int argc, char *argv[]);
188*7a23074eSdduvall static boolean_t	getaddr(int which, char *s, struct hostent **hpp);
1897c478bd9Sstevel@tonic-gate static boolean_t	in6_getaddr(char *s, struct sockaddr_in6 *sin6,
1907c478bd9Sstevel@tonic-gate     int *plenp, struct hostent **hpp);
1917c478bd9Sstevel@tonic-gate static boolean_t	in_getaddr(char *s, struct sockaddr_in *sin,
192*7a23074eSdduvall     int *plenp, int which, struct hostent **hpp);
1937c478bd9Sstevel@tonic-gate static int		in_getprefixlen(char *addr, int max_plen);
1947c478bd9Sstevel@tonic-gate static boolean_t	in_prefixlentomask(int prefixlen, int maxlen,
1957c478bd9Sstevel@tonic-gate     uchar_t *mask);
196*7a23074eSdduvall static void		inet_makenetandmask(in_addr_t net,
1977c478bd9Sstevel@tonic-gate     struct sockaddr_in *sin);
1987c478bd9Sstevel@tonic-gate static in_addr_t	inet_makesubnetmask(in_addr_t addr, in_addr_t mask);
1997c478bd9Sstevel@tonic-gate static int		keyword(char *cp);
2007c478bd9Sstevel@tonic-gate static void		link_addr(const char *addr, struct sockaddr_dl *sdl);
2017c478bd9Sstevel@tonic-gate static char		*link_ntoa(const struct sockaddr_dl *sdl);
2027c478bd9Sstevel@tonic-gate static mib_item_t	*mibget(int sd);
2037c478bd9Sstevel@tonic-gate static char		*netname(struct sockaddr *sa);
204*7a23074eSdduvall static int		newroute(int argc, char **argv);
2057c478bd9Sstevel@tonic-gate static void		pmsg_addrs(char *cp, int addrs);
2067c478bd9Sstevel@tonic-gate static void		pmsg_common(struct rt_msghdr *rtm);
207*7a23074eSdduvall static void		print_getmsg(struct rt_msghdr *rtm, int msglen);
2087c478bd9Sstevel@tonic-gate static void		print_rtmsg(struct rt_msghdr *rtm, int msglen);
2097c478bd9Sstevel@tonic-gate static void		quit(char *s, int err);
2107c478bd9Sstevel@tonic-gate static char		*routename(struct sockaddr *sa);
2117c478bd9Sstevel@tonic-gate static void		rtmonitor(int argc, char *argv[]);
212*7a23074eSdduvall static int		rtmsg(int cmd, int flags);
2137c478bd9Sstevel@tonic-gate static int		salen(struct sockaddr *sa);
214*7a23074eSdduvall static void		set_metric(char *value, int key);
2157c478bd9Sstevel@tonic-gate static void		sockaddr(char *addr, struct sockaddr *sa);
216*7a23074eSdduvall static void		sodump(sup su, char *which);
2177c478bd9Sstevel@tonic-gate static void		usage(char *cp);
2187c478bd9Sstevel@tonic-gate 
219*7a23074eSdduvall static int		pid, rtm_addrs;
2207c478bd9Sstevel@tonic-gate static int		s;
221*7a23074eSdduvall static boolean_t	forcehost, forcenet, nflag;
2227c478bd9Sstevel@tonic-gate static int		af = AF_INET;
2237c478bd9Sstevel@tonic-gate static boolean_t	qflag, tflag;
224*7a23074eSdduvall static boolean_t	iflag, verbose;
225*7a23074eSdduvall static boolean_t	locking, lockrest, debugonly;
2267c478bd9Sstevel@tonic-gate static boolean_t	fflag;
227*7a23074eSdduvall static struct		rt_metrics rt_metrics;
228*7a23074eSdduvall static ulong_t		rtm_inits;
229*7a23074eSdduvall static int		masklen;
2307c478bd9Sstevel@tonic-gate 
2317c478bd9Sstevel@tonic-gate static struct {
2327c478bd9Sstevel@tonic-gate 	struct	rt_msghdr m_rtm;
2337c478bd9Sstevel@tonic-gate 	char	m_space[512];
2347c478bd9Sstevel@tonic-gate } m_rtmsg;
2357c478bd9Sstevel@tonic-gate 
2367c478bd9Sstevel@tonic-gate /*
2377c478bd9Sstevel@tonic-gate  * Sizes of data structures extracted from the base mib.
2387c478bd9Sstevel@tonic-gate  * This allows the size of the tables entries to grow while preserving
2397c478bd9Sstevel@tonic-gate  * binary compatibility.
2407c478bd9Sstevel@tonic-gate  */
2417c478bd9Sstevel@tonic-gate static int ipRouteEntrySize;
2427c478bd9Sstevel@tonic-gate static int ipv6RouteEntrySize;
2437c478bd9Sstevel@tonic-gate 
2447c478bd9Sstevel@tonic-gate #define	ROUNDUP_LONG(a) \
2457c478bd9Sstevel@tonic-gate 	((a) > 0 ? (1 + (((a) - 1) | (sizeof (long) - 1))) : sizeof (long))
2467c478bd9Sstevel@tonic-gate #define	ADVANCE(x, n) ((x) += ROUNDUP_LONG(salen(n)))
2477c478bd9Sstevel@tonic-gate #define	C(x)	((x) & 0xff)
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate /*
2507c478bd9Sstevel@tonic-gate  * return values from in_getprefixlen()
2517c478bd9Sstevel@tonic-gate  */
2527c478bd9Sstevel@tonic-gate #define	BAD_ADDR	-1	/* prefix is invalid */
2537c478bd9Sstevel@tonic-gate #define	NO_PREFIX	-2	/* no prefix was found */
2547c478bd9Sstevel@tonic-gate 
2557c478bd9Sstevel@tonic-gate void
2567c478bd9Sstevel@tonic-gate usage(char *cp)
2577c478bd9Sstevel@tonic-gate {
258*7a23074eSdduvall 	if (cp != NULL)
2597c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("route: botched keyword: %s\n"),
2607c478bd9Sstevel@tonic-gate 		    cp);
261*7a23074eSdduvall 	(void) fprintf(stderr,
262*7a23074eSdduvall 	    gettext("usage: route [ -fnqv ] cmd [[ -<qualifers> ] args ]\n"));
2637c478bd9Sstevel@tonic-gate 	exit(1);
2647c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
2657c478bd9Sstevel@tonic-gate }
2667c478bd9Sstevel@tonic-gate 
2677c478bd9Sstevel@tonic-gate void
2687c478bd9Sstevel@tonic-gate quit(char *s, int sverrno)
2697c478bd9Sstevel@tonic-gate {
2707c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "route: ");
2717c478bd9Sstevel@tonic-gate 	if (s != NULL)
2727c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "%s: ", s);
2737c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "%s\n", strerror(sverrno));
2747c478bd9Sstevel@tonic-gate 	exit(sverrno);
2757c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
2767c478bd9Sstevel@tonic-gate }
2777c478bd9Sstevel@tonic-gate 
2787c478bd9Sstevel@tonic-gate int
2797c478bd9Sstevel@tonic-gate main(int argc, char **argv)
2807c478bd9Sstevel@tonic-gate {
2817c478bd9Sstevel@tonic-gate 	extern int optind;
2827c478bd9Sstevel@tonic-gate 	int ch;
2837c478bd9Sstevel@tonic-gate 	int key;
2847c478bd9Sstevel@tonic-gate 
2857c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
2867c478bd9Sstevel@tonic-gate 
2877c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
2887c478bd9Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"
2897c478bd9Sstevel@tonic-gate #endif
2907c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate 	if (argc < 2)
2937c478bd9Sstevel@tonic-gate 		usage((char *)NULL);
2947c478bd9Sstevel@tonic-gate 
295*7a23074eSdduvall 	while ((ch = getopt(argc, argv, "nqdtvf")) != EOF) {
2967c478bd9Sstevel@tonic-gate 		switch (ch) {
2977c478bd9Sstevel@tonic-gate 		case 'n':
2987c478bd9Sstevel@tonic-gate 			nflag = B_TRUE;
2997c478bd9Sstevel@tonic-gate 			break;
3007c478bd9Sstevel@tonic-gate 		case 'q':
3017c478bd9Sstevel@tonic-gate 			qflag = B_TRUE;
3027c478bd9Sstevel@tonic-gate 			break;
3037c478bd9Sstevel@tonic-gate 		case 'v':
3047c478bd9Sstevel@tonic-gate 			verbose = B_TRUE;
3057c478bd9Sstevel@tonic-gate 			break;
3067c478bd9Sstevel@tonic-gate 		case 't':
3077c478bd9Sstevel@tonic-gate 			tflag = B_TRUE;
3087c478bd9Sstevel@tonic-gate 			break;
3097c478bd9Sstevel@tonic-gate 		case 'd':
3107c478bd9Sstevel@tonic-gate 			debugonly = B_TRUE;
3117c478bd9Sstevel@tonic-gate 			break;
3127c478bd9Sstevel@tonic-gate 		case 'f':
3137c478bd9Sstevel@tonic-gate 			fflag = B_TRUE;
3147c478bd9Sstevel@tonic-gate 			break;
3157c478bd9Sstevel@tonic-gate 		case '?':
3167c478bd9Sstevel@tonic-gate 		default:
3177c478bd9Sstevel@tonic-gate 			usage((char *)NULL);
3187c478bd9Sstevel@tonic-gate 			/* NOTREACHED */
3197c478bd9Sstevel@tonic-gate 		}
3207c478bd9Sstevel@tonic-gate 	}
3217c478bd9Sstevel@tonic-gate 	argc -= optind;
3227c478bd9Sstevel@tonic-gate 	argv += optind;
3237c478bd9Sstevel@tonic-gate 
3247c478bd9Sstevel@tonic-gate 	pid = getpid();
3257c478bd9Sstevel@tonic-gate 	if (tflag)
3267c478bd9Sstevel@tonic-gate 		s = open("/dev/null", O_WRONLY);
3277c478bd9Sstevel@tonic-gate 	else
3287c478bd9Sstevel@tonic-gate 		s = socket(PF_ROUTE, SOCK_RAW, 0);
3297c478bd9Sstevel@tonic-gate 	if (s < 0)
3307c478bd9Sstevel@tonic-gate 		quit("socket", errno);
3317c478bd9Sstevel@tonic-gate 	if (fflag) {
3327c478bd9Sstevel@tonic-gate 		/*
3337c478bd9Sstevel@tonic-gate 		 * Accept an address family keyword after the -f.  Since the
3347c478bd9Sstevel@tonic-gate 		 * default address family is AF_INET, reassign af only for the
3357c478bd9Sstevel@tonic-gate 		 * other valid address families.
3367c478bd9Sstevel@tonic-gate 		 */
3377c478bd9Sstevel@tonic-gate 		if (*argv != NULL) {
3387c478bd9Sstevel@tonic-gate 			switch (key = keyword(*argv)) {
3397c478bd9Sstevel@tonic-gate 			case K_INET:
3407c478bd9Sstevel@tonic-gate 			case K_INET6:
3417c478bd9Sstevel@tonic-gate 				if (key == K_INET6)
3427c478bd9Sstevel@tonic-gate 					af = AF_INET6;
3437c478bd9Sstevel@tonic-gate 				/* Skip over the address family parameter. */
3447c478bd9Sstevel@tonic-gate 				argc--;
3457c478bd9Sstevel@tonic-gate 				argv++;
3467c478bd9Sstevel@tonic-gate 				break;
3477c478bd9Sstevel@tonic-gate 			}
3487c478bd9Sstevel@tonic-gate 		}
3497c478bd9Sstevel@tonic-gate 		flushroutes(0, NULL);
3507c478bd9Sstevel@tonic-gate 	}
3517c478bd9Sstevel@tonic-gate 	if (*argv != NULL) {
3527c478bd9Sstevel@tonic-gate 		switch (keyword(*argv)) {
3537c478bd9Sstevel@tonic-gate 		case K_GET:
3547c478bd9Sstevel@tonic-gate 		case K_CHANGE:
3557c478bd9Sstevel@tonic-gate 		case K_ADD:
3567c478bd9Sstevel@tonic-gate 		case K_DELETE:
357*7a23074eSdduvall 			return (newroute(argc, argv));
358*7a23074eSdduvall 
3597c478bd9Sstevel@tonic-gate 		case K_MONITOR:
3607c478bd9Sstevel@tonic-gate 			rtmonitor(argc, argv);
3617c478bd9Sstevel@tonic-gate 			/* NOTREACHED */
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate 		case K_FLUSH:
3647c478bd9Sstevel@tonic-gate 			flushroutes(argc, argv);
365*7a23074eSdduvall 			exit(0);
366*7a23074eSdduvall 			/* NOTREACHED */
3677c478bd9Sstevel@tonic-gate 		}
3687c478bd9Sstevel@tonic-gate 	}
3697c478bd9Sstevel@tonic-gate 	if (!fflag)
3707c478bd9Sstevel@tonic-gate 		usage(*argv);
3717c478bd9Sstevel@tonic-gate 	return (0);
3727c478bd9Sstevel@tonic-gate }
3737c478bd9Sstevel@tonic-gate 
3747c478bd9Sstevel@tonic-gate /*
3757c478bd9Sstevel@tonic-gate  * Purge all entries in the routing tables not
3767c478bd9Sstevel@tonic-gate  * associated with network interfaces.
3777c478bd9Sstevel@tonic-gate  */
3787c478bd9Sstevel@tonic-gate void
3797c478bd9Sstevel@tonic-gate flushroutes(int argc, char *argv[])
3807c478bd9Sstevel@tonic-gate {
3817c478bd9Sstevel@tonic-gate 	int seqno;
3827c478bd9Sstevel@tonic-gate 	int sd;	/* mib stream */
3837c478bd9Sstevel@tonic-gate 	mib_item_t	*item;
3847c478bd9Sstevel@tonic-gate 	mib2_ipRouteEntry_t *rp;
3857c478bd9Sstevel@tonic-gate 	mib2_ipv6RouteEntry_t *rp6;
3867c478bd9Sstevel@tonic-gate 	int oerrno;
3877c478bd9Sstevel@tonic-gate 	int off = 0;
3887c478bd9Sstevel@tonic-gate 	int on = 1;
3897c478bd9Sstevel@tonic-gate 
3907c478bd9Sstevel@tonic-gate 	if (setsockopt(s, SOL_SOCKET, SO_USELOOPBACK, (char *)&off,
3917c478bd9Sstevel@tonic-gate 	    sizeof (off)) < 0)
3927c478bd9Sstevel@tonic-gate 		quit("setsockopt", errno);
3937c478bd9Sstevel@tonic-gate 	if (argc > 1) {
3947c478bd9Sstevel@tonic-gate 		argv++;
3957c478bd9Sstevel@tonic-gate 		if (argc == 2 && **argv == '-') {
3967c478bd9Sstevel@tonic-gate 			/*
3977c478bd9Sstevel@tonic-gate 			 * The address family (preceded by a dash) may be used
3987c478bd9Sstevel@tonic-gate 			 * to flush the routes of that particular family.
3997c478bd9Sstevel@tonic-gate 			 */
4007c478bd9Sstevel@tonic-gate 			switch (keyword(*argv + 1)) {
4017c478bd9Sstevel@tonic-gate 			case K_INET:
4027c478bd9Sstevel@tonic-gate 				af = AF_INET;
4037c478bd9Sstevel@tonic-gate 				break;
4047c478bd9Sstevel@tonic-gate 			case K_LINK:
4057c478bd9Sstevel@tonic-gate 				af = AF_LINK;
4067c478bd9Sstevel@tonic-gate 				break;
4077c478bd9Sstevel@tonic-gate 			case K_INET6:
4087c478bd9Sstevel@tonic-gate 				af = AF_INET6;
4097c478bd9Sstevel@tonic-gate 				break;
4107c478bd9Sstevel@tonic-gate 			default:
4117c478bd9Sstevel@tonic-gate 				usage(*argv);
4127c478bd9Sstevel@tonic-gate 				/* NOTREACHED */
4137c478bd9Sstevel@tonic-gate 			}
4147c478bd9Sstevel@tonic-gate 		} else {
4157c478bd9Sstevel@tonic-gate 			usage(*argv);
4167c478bd9Sstevel@tonic-gate 		}
4177c478bd9Sstevel@tonic-gate 	}
4187c478bd9Sstevel@tonic-gate 	sd = open("/dev/ip", O_RDWR);
4197c478bd9Sstevel@tonic-gate 	oerrno = errno;
4207c478bd9Sstevel@tonic-gate 	if (sd < 0) {
4217c478bd9Sstevel@tonic-gate 		switch (errno) {
4227c478bd9Sstevel@tonic-gate 		case EACCES:
4237c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
4247c478bd9Sstevel@tonic-gate 			    gettext("route: flush: insufficient privileges\n"));
4257c478bd9Sstevel@tonic-gate 			exit(oerrno);
4267c478bd9Sstevel@tonic-gate 			/* NOTREACHED */
4277c478bd9Sstevel@tonic-gate 		default:
4287c478bd9Sstevel@tonic-gate 			quit(gettext("can't open mib stream"), oerrno);
4297c478bd9Sstevel@tonic-gate 			/* NOTREACHED */
4307c478bd9Sstevel@tonic-gate 		}
4317c478bd9Sstevel@tonic-gate 	}
4327c478bd9Sstevel@tonic-gate 	if ((item = mibget(sd)) == NULL)
4337c478bd9Sstevel@tonic-gate 		quit("mibget", errno);
4347c478bd9Sstevel@tonic-gate 	if (verbose) {
4357c478bd9Sstevel@tonic-gate 		(void) printf("Examining routing table from "
4367c478bd9Sstevel@tonic-gate 		    "T_SVR4_OPTMGMT_REQ\n");
4377c478bd9Sstevel@tonic-gate 	}
4387c478bd9Sstevel@tonic-gate 	seqno = 0;		/* ??? */
4397c478bd9Sstevel@tonic-gate 	switch (af) {
4407c478bd9Sstevel@tonic-gate 	case AF_INET:
4417c478bd9Sstevel@tonic-gate 		/* Extract ipRouteEntrySize */
4427c478bd9Sstevel@tonic-gate 		for (; item != NULL; item = item->next_item) {
4437c478bd9Sstevel@tonic-gate 			if (item->mib_id != 0)
4447c478bd9Sstevel@tonic-gate 				continue;
4457c478bd9Sstevel@tonic-gate 			if (item->group == MIB2_IP) {
4467c478bd9Sstevel@tonic-gate 				ipRouteEntrySize =
4477c478bd9Sstevel@tonic-gate 				    ((mib2_ip_t *)item->valp)->ipRouteEntrySize;
4487c478bd9Sstevel@tonic-gate 				assert(IS_P2ALIGNED(ipRouteEntrySize,
4497c478bd9Sstevel@tonic-gate 				    sizeof (mib2_ipRouteEntry_t *)));
4507c478bd9Sstevel@tonic-gate 				break;
4517c478bd9Sstevel@tonic-gate 			}
4527c478bd9Sstevel@tonic-gate 		}
4537c478bd9Sstevel@tonic-gate 		if (ipRouteEntrySize == 0) {
4547c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
4557c478bd9Sstevel@tonic-gate 			    gettext("ipRouteEntrySize can't be determined.\n"));
4567c478bd9Sstevel@tonic-gate 			exit(1);
4577c478bd9Sstevel@tonic-gate 		}
4587c478bd9Sstevel@tonic-gate 		for (; item != NULL; item = item->next_item) {
4597c478bd9Sstevel@tonic-gate 			/*
4607c478bd9Sstevel@tonic-gate 			 * skip all the other trash that comes up the mib stream
4617c478bd9Sstevel@tonic-gate 			 */
4627c478bd9Sstevel@tonic-gate 			if (item->group != MIB2_IP ||
4637c478bd9Sstevel@tonic-gate 			    item->mib_id != MIB2_IP_ROUTE)
4647c478bd9Sstevel@tonic-gate 				continue;
4657c478bd9Sstevel@tonic-gate 			for (rp = (mib2_ipRouteEntry_t *)item->valp;
4667c478bd9Sstevel@tonic-gate 			    (char *)rp < (char *)item->valp + item->length;
4677c478bd9Sstevel@tonic-gate 			    /* LINTED */
4687c478bd9Sstevel@tonic-gate 			    rp = (mib2_ipRouteEntry_t *)
4697c478bd9Sstevel@tonic-gate 				((char *)rp + ipRouteEntrySize)) {
4707c478bd9Sstevel@tonic-gate 				delRouteEntry(rp, NULL, seqno);
4717c478bd9Sstevel@tonic-gate 				seqno++;
4727c478bd9Sstevel@tonic-gate 			}
4737c478bd9Sstevel@tonic-gate 			break;
4747c478bd9Sstevel@tonic-gate 		}
4757c478bd9Sstevel@tonic-gate 		break;
4767c478bd9Sstevel@tonic-gate 	case AF_INET6:
4777c478bd9Sstevel@tonic-gate 		/* Extract ipv6RouteEntrySize */
4787c478bd9Sstevel@tonic-gate 		for (; item != NULL; item = item->next_item) {
4797c478bd9Sstevel@tonic-gate 			if (item->mib_id != 0)
4807c478bd9Sstevel@tonic-gate 				continue;
4817c478bd9Sstevel@tonic-gate 			if (item->group == MIB2_IP6) {
4827c478bd9Sstevel@tonic-gate 				ipv6RouteEntrySize =
4837c478bd9Sstevel@tonic-gate 				    ((mib2_ipv6IfStatsEntry_t *)item->valp)->
4847c478bd9Sstevel@tonic-gate 					ipv6RouteEntrySize;
4857c478bd9Sstevel@tonic-gate 				assert(IS_P2ALIGNED(ipv6RouteEntrySize,
4867c478bd9Sstevel@tonic-gate 				    sizeof (mib2_ipv6RouteEntry_t *)));
4877c478bd9Sstevel@tonic-gate 				break;
4887c478bd9Sstevel@tonic-gate 			}
4897c478bd9Sstevel@tonic-gate 		}
4907c478bd9Sstevel@tonic-gate 		if (ipv6RouteEntrySize == 0) {
4917c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
4927c478bd9Sstevel@tonic-gate 			    "ipv6RouteEntrySize cannot be determined.\n"));
4937c478bd9Sstevel@tonic-gate 			exit(1);
4947c478bd9Sstevel@tonic-gate 		}
4957c478bd9Sstevel@tonic-gate 		for (; item != NULL; item = item->next_item) {
4967c478bd9Sstevel@tonic-gate 			/*
4977c478bd9Sstevel@tonic-gate 			 * skip all the other trash that comes up the mib stream
4987c478bd9Sstevel@tonic-gate 			 */
4997c478bd9Sstevel@tonic-gate 			if (item->group != MIB2_IP6 ||
5007c478bd9Sstevel@tonic-gate 			    item->mib_id != MIB2_IP6_ROUTE)
5017c478bd9Sstevel@tonic-gate 				continue;
5027c478bd9Sstevel@tonic-gate 			for (rp6 = (mib2_ipv6RouteEntry_t *)item->valp;
5037c478bd9Sstevel@tonic-gate 			    (char *)rp6 < (char *)item->valp + item->length;
5047c478bd9Sstevel@tonic-gate 			    /* LINTED */
5057c478bd9Sstevel@tonic-gate 			    rp6 = (mib2_ipv6RouteEntry_t *)
5067c478bd9Sstevel@tonic-gate 				((char *)rp6 + ipv6RouteEntrySize)) {
5077c478bd9Sstevel@tonic-gate 				delRouteEntry(NULL, rp6, seqno);
5087c478bd9Sstevel@tonic-gate 				seqno++;
5097c478bd9Sstevel@tonic-gate 			}
5107c478bd9Sstevel@tonic-gate 			break;
5117c478bd9Sstevel@tonic-gate 		}
5127c478bd9Sstevel@tonic-gate 		break;
5137c478bd9Sstevel@tonic-gate 	}
5147c478bd9Sstevel@tonic-gate 
5157c478bd9Sstevel@tonic-gate 	if (setsockopt(s, SOL_SOCKET, SO_USELOOPBACK, (char *)&on,
5167c478bd9Sstevel@tonic-gate 	    sizeof (on)) < 0)
5177c478bd9Sstevel@tonic-gate 		quit("setsockopt", errno);
5187c478bd9Sstevel@tonic-gate }
5197c478bd9Sstevel@tonic-gate 
5207c478bd9Sstevel@tonic-gate /*
5217c478bd9Sstevel@tonic-gate  * Given the contents of a mib_item_t of id type MIB2_IP_ROUTE or
5227c478bd9Sstevel@tonic-gate  * MIB2_IP6_ROUTE, construct and send an RTM_DELETE routing socket message in
5237c478bd9Sstevel@tonic-gate  * order to facilitate the flushing of RTF_GATEWAY routes.
5247c478bd9Sstevel@tonic-gate  */
5257c478bd9Sstevel@tonic-gate static void
5267c478bd9Sstevel@tonic-gate delRouteEntry(mib2_ipRouteEntry_t *rp, mib2_ipv6RouteEntry_t *rp6, int seqno)
5277c478bd9Sstevel@tonic-gate {
5287c478bd9Sstevel@tonic-gate 	char *cp;
5297c478bd9Sstevel@tonic-gate 	int ire_type;
5307c478bd9Sstevel@tonic-gate 	int rlen;
5317c478bd9Sstevel@tonic-gate 	struct rt_msghdr *rtm;
5327c478bd9Sstevel@tonic-gate 	struct sockaddr_in sin;
5337c478bd9Sstevel@tonic-gate 	struct sockaddr_in6 sin6;
5347c478bd9Sstevel@tonic-gate 	int slen;
5357c478bd9Sstevel@tonic-gate 
5367c478bd9Sstevel@tonic-gate 	if (rp != NULL)
5377c478bd9Sstevel@tonic-gate 		ire_type = rp->ipRouteInfo.re_ire_type;
5387c478bd9Sstevel@tonic-gate 	else
5397c478bd9Sstevel@tonic-gate 		ire_type = rp6->ipv6RouteInfo.re_ire_type;
5407c478bd9Sstevel@tonic-gate 	if (ire_type != IRE_DEFAULT &&
5417c478bd9Sstevel@tonic-gate 	    ire_type != IRE_PREFIX &&
5427c478bd9Sstevel@tonic-gate 	    ire_type != IRE_HOST &&
5437c478bd9Sstevel@tonic-gate 	    ire_type != IRE_HOST_REDIRECT)
5447c478bd9Sstevel@tonic-gate 		return;
5457c478bd9Sstevel@tonic-gate 
5467c478bd9Sstevel@tonic-gate 	rtm = &m_rtmsg.m_rtm;
5477c478bd9Sstevel@tonic-gate 	(void) memset(rtm, 0, sizeof (m_rtmsg));
5487c478bd9Sstevel@tonic-gate 	rtm->rtm_type = RTM_DELETE;
5497c478bd9Sstevel@tonic-gate 	rtm->rtm_seq = seqno;
5507c478bd9Sstevel@tonic-gate 	rtm->rtm_flags |= RTF_GATEWAY;
5517c478bd9Sstevel@tonic-gate 	rtm->rtm_version = RTM_VERSION;
5527c478bd9Sstevel@tonic-gate 	rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
5537c478bd9Sstevel@tonic-gate 	cp = m_rtmsg.m_space;
5547c478bd9Sstevel@tonic-gate 	if (rp != NULL) {
5557c478bd9Sstevel@tonic-gate 		slen = sizeof (struct sockaddr_in);
5567c478bd9Sstevel@tonic-gate 		if (rp->ipRouteMask == IP_HOST_MASK)
5577c478bd9Sstevel@tonic-gate 			rtm->rtm_flags |= RTF_HOST;
5587c478bd9Sstevel@tonic-gate 		(void) memset(&sin, 0, slen);
5597c478bd9Sstevel@tonic-gate 		sin.sin_family = AF_INET;
5607c478bd9Sstevel@tonic-gate 		sin.sin_addr.s_addr = rp->ipRouteDest;
5617c478bd9Sstevel@tonic-gate 		(void) memmove(cp, &sin, slen);
5627c478bd9Sstevel@tonic-gate 		cp += slen;
5637c478bd9Sstevel@tonic-gate 		sin.sin_addr.s_addr = rp->ipRouteNextHop;
5647c478bd9Sstevel@tonic-gate 		(void) memmove(cp, &sin, slen);
5657c478bd9Sstevel@tonic-gate 		cp += slen;
5667c478bd9Sstevel@tonic-gate 		sin.sin_addr.s_addr = rp->ipRouteMask;
5677c478bd9Sstevel@tonic-gate 		(void) memmove(cp, &sin, slen);
5687c478bd9Sstevel@tonic-gate 		cp += slen;
5697c478bd9Sstevel@tonic-gate 	} else {
5707c478bd9Sstevel@tonic-gate 		slen = sizeof (struct sockaddr_in6);
5717c478bd9Sstevel@tonic-gate 		if (rp6->ipv6RoutePfxLength == IPV6_ABITS)
5727c478bd9Sstevel@tonic-gate 			rtm->rtm_flags |= RTF_HOST;
5737c478bd9Sstevel@tonic-gate 		(void) memset(&sin6, 0, slen);
5747c478bd9Sstevel@tonic-gate 		sin6.sin6_family = AF_INET6;
5757c478bd9Sstevel@tonic-gate 		sin6.sin6_addr = rp6->ipv6RouteDest;
5767c478bd9Sstevel@tonic-gate 		(void) memmove(cp, &sin6, slen);
5777c478bd9Sstevel@tonic-gate 		cp += slen;
5787c478bd9Sstevel@tonic-gate 		sin6.sin6_addr = rp6->ipv6RouteNextHop;
5797c478bd9Sstevel@tonic-gate 		(void) memmove(cp, &sin6, slen);
5807c478bd9Sstevel@tonic-gate 		cp += slen;
5817c478bd9Sstevel@tonic-gate 		(void) memset(&sin6.sin6_addr, 0, sizeof (sin6.sin6_addr));
5827c478bd9Sstevel@tonic-gate 		(void) in_prefixlentomask(rp6->ipv6RoutePfxLength, IPV6_ABITS,
5837c478bd9Sstevel@tonic-gate 		    (uchar_t *)&sin6.sin6_addr.s6_addr);
5847c478bd9Sstevel@tonic-gate 		(void) memmove(cp, &sin6, slen);
5857c478bd9Sstevel@tonic-gate 		cp += slen;
5867c478bd9Sstevel@tonic-gate 	}
5877c478bd9Sstevel@tonic-gate 	rtm->rtm_msglen = cp - (char *)&m_rtmsg;
5887c478bd9Sstevel@tonic-gate 	if (debugonly) {
5897c478bd9Sstevel@tonic-gate 		/*
5907c478bd9Sstevel@tonic-gate 		 * In debugonly mode, the routing socket message to delete the
5917c478bd9Sstevel@tonic-gate 		 * current entry is not actually sent.  However if verbose is
5927c478bd9Sstevel@tonic-gate 		 * also set, the routing socket message that would have been
5937c478bd9Sstevel@tonic-gate 		 * is printed.
5947c478bd9Sstevel@tonic-gate 		 */
5957c478bd9Sstevel@tonic-gate 		if (verbose)
5967c478bd9Sstevel@tonic-gate 			print_rtmsg(rtm, rtm->rtm_msglen);
5977c478bd9Sstevel@tonic-gate 		return;
5987c478bd9Sstevel@tonic-gate 	}
5997c478bd9Sstevel@tonic-gate 
6007c478bd9Sstevel@tonic-gate 	rlen = write(s, (char *)&m_rtmsg, rtm->rtm_msglen);
6017c478bd9Sstevel@tonic-gate 	if (rlen < (int)rtm->rtm_msglen) {
6027c478bd9Sstevel@tonic-gate 		if (rlen < 0) {
6037c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
6047c478bd9Sstevel@tonic-gate 			    gettext("route: write to routing socket: %s\n"),
6057c478bd9Sstevel@tonic-gate 			    strerror(errno));
6067c478bd9Sstevel@tonic-gate 		} else {
6077c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("route: write to "
6087c478bd9Sstevel@tonic-gate 			    "routing socket got only %d for rlen\n"), rlen);
6097c478bd9Sstevel@tonic-gate 		}
6107c478bd9Sstevel@tonic-gate 		return;
6117c478bd9Sstevel@tonic-gate 	}
6127c478bd9Sstevel@tonic-gate 	if (qflag) {
6137c478bd9Sstevel@tonic-gate 		/*
6147c478bd9Sstevel@tonic-gate 		 * In quiet mode, nothing is printed at all (unless the write()
6157c478bd9Sstevel@tonic-gate 		 * itself failed.
6167c478bd9Sstevel@tonic-gate 		 */
6177c478bd9Sstevel@tonic-gate 		return;
6187c478bd9Sstevel@tonic-gate 	}
6197c478bd9Sstevel@tonic-gate 	if (verbose) {
6207c478bd9Sstevel@tonic-gate 		print_rtmsg(rtm, rlen);
6217c478bd9Sstevel@tonic-gate 	} else {
6227c478bd9Sstevel@tonic-gate 		struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
6237c478bd9Sstevel@tonic-gate 
6247c478bd9Sstevel@tonic-gate 		(void) printf("%-20.20s ",
6257c478bd9Sstevel@tonic-gate 		    rtm->rtm_flags & RTF_HOST ? routename(sa) :
6267c478bd9Sstevel@tonic-gate 			netname(sa));
6277c478bd9Sstevel@tonic-gate 		/* LINTED */
6287c478bd9Sstevel@tonic-gate 		sa = (struct sockaddr *)(salen(sa) + (char *)sa);
6297c478bd9Sstevel@tonic-gate 		(void) printf("%-20.20s ", routename(sa));
6307c478bd9Sstevel@tonic-gate 		(void) printf("done\n");
6317c478bd9Sstevel@tonic-gate 	}
6327c478bd9Sstevel@tonic-gate }
6337c478bd9Sstevel@tonic-gate 
6347c478bd9Sstevel@tonic-gate /*
6357c478bd9Sstevel@tonic-gate  * Return the name of the host whose address is given.
6367c478bd9Sstevel@tonic-gate  */
6377c478bd9Sstevel@tonic-gate char *
6387c478bd9Sstevel@tonic-gate routename(struct sockaddr *sa)
6397c478bd9Sstevel@tonic-gate {
6407c478bd9Sstevel@tonic-gate 	char *cp;
6417c478bd9Sstevel@tonic-gate 	static char line[MAXHOSTNAMELEN + 1];
6427c478bd9Sstevel@tonic-gate 	struct hostent *hp = NULL;
6437c478bd9Sstevel@tonic-gate 	static char domain[MAXHOSTNAMELEN + 1];
6447c478bd9Sstevel@tonic-gate 	static boolean_t first = B_TRUE;
6457c478bd9Sstevel@tonic-gate 	struct in_addr in;
6467c478bd9Sstevel@tonic-gate 	struct in6_addr in6;
6477c478bd9Sstevel@tonic-gate 	int error_num;
6487c478bd9Sstevel@tonic-gate 	ushort_t *s;
6497c478bd9Sstevel@tonic-gate 	ushort_t *slim;
6507c478bd9Sstevel@tonic-gate 
6517c478bd9Sstevel@tonic-gate 	if (first) {
6527c478bd9Sstevel@tonic-gate 		first = B_FALSE;
6537c478bd9Sstevel@tonic-gate 		if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
6547c478bd9Sstevel@tonic-gate 		    (cp = strchr(domain, '.')))
6557c478bd9Sstevel@tonic-gate 			(void) strcpy(domain, cp + 1);
6567c478bd9Sstevel@tonic-gate 		else
6577c478bd9Sstevel@tonic-gate 			domain[0] = 0;
6587c478bd9Sstevel@tonic-gate 	}
6597c478bd9Sstevel@tonic-gate 
6607c478bd9Sstevel@tonic-gate 	if (salen(sa) == 0) {
6617c478bd9Sstevel@tonic-gate 		(void) strcpy(line, "default");
6627c478bd9Sstevel@tonic-gate 		return (line);
6637c478bd9Sstevel@tonic-gate 	}
6647c478bd9Sstevel@tonic-gate 	switch (sa->sa_family) {
6657c478bd9Sstevel@tonic-gate 
6667c478bd9Sstevel@tonic-gate 	case AF_INET:
6677c478bd9Sstevel@tonic-gate 		/* LINTED */
6687c478bd9Sstevel@tonic-gate 		in = ((struct sockaddr_in *)sa)->sin_addr;
6697c478bd9Sstevel@tonic-gate 
6707c478bd9Sstevel@tonic-gate 		cp = NULL;
6717c478bd9Sstevel@tonic-gate 		if (in.s_addr == INADDR_ANY)
6727c478bd9Sstevel@tonic-gate 			cp = "default";
6737c478bd9Sstevel@tonic-gate 		if (cp == NULL && !nflag) {
6747c478bd9Sstevel@tonic-gate 			hp = gethostbyaddr((char *)&in, sizeof (struct in_addr),
6757c478bd9Sstevel@tonic-gate 				AF_INET);
6767c478bd9Sstevel@tonic-gate 			if (hp != NULL) {
6777c478bd9Sstevel@tonic-gate 				if (((cp = strchr(hp->h_name, '.')) != NULL) &&
6787c478bd9Sstevel@tonic-gate 				    (strcmp(cp + 1, domain) == 0))
6797c478bd9Sstevel@tonic-gate 					*cp = 0;
6807c478bd9Sstevel@tonic-gate 				cp = hp->h_name;
6817c478bd9Sstevel@tonic-gate 			}
6827c478bd9Sstevel@tonic-gate 		}
6837c478bd9Sstevel@tonic-gate 		if (cp != NULL) {
6847c478bd9Sstevel@tonic-gate 			(void) strncpy(line, cp, MAXHOSTNAMELEN);
6857c478bd9Sstevel@tonic-gate 			line[MAXHOSTNAMELEN] = '\0';
6867c478bd9Sstevel@tonic-gate 		} else {
6877c478bd9Sstevel@tonic-gate 			in.s_addr = ntohl(in.s_addr);
6887c478bd9Sstevel@tonic-gate 			(void) sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24),
6897c478bd9Sstevel@tonic-gate 			    C(in.s_addr >> 16), C(in.s_addr >> 8),
6907c478bd9Sstevel@tonic-gate 			    C(in.s_addr));
6917c478bd9Sstevel@tonic-gate 		}
6927c478bd9Sstevel@tonic-gate 		break;
6937c478bd9Sstevel@tonic-gate 
6947c478bd9Sstevel@tonic-gate 	case AF_LINK:
6957c478bd9Sstevel@tonic-gate 		return (link_ntoa((struct sockaddr_dl *)sa));
6967c478bd9Sstevel@tonic-gate 
6977c478bd9Sstevel@tonic-gate 	case AF_INET6:
6987c478bd9Sstevel@tonic-gate 		/* LINTED */
6997c478bd9Sstevel@tonic-gate 		in6 = ((struct sockaddr_in6 *)sa)->sin6_addr;
7007c478bd9Sstevel@tonic-gate 
7017c478bd9Sstevel@tonic-gate 		cp = NULL;
7027c478bd9Sstevel@tonic-gate 		if (IN6_IS_ADDR_UNSPECIFIED(&in6))
7037c478bd9Sstevel@tonic-gate 			cp = "default";
7047c478bd9Sstevel@tonic-gate 		if (cp == NULL && !nflag) {
7057c478bd9Sstevel@tonic-gate 			hp = getipnodebyaddr((char *)&in6,
7067c478bd9Sstevel@tonic-gate 				sizeof (struct in6_addr), AF_INET6, &error_num);
7077c478bd9Sstevel@tonic-gate 			if (hp != NULL) {
7087c478bd9Sstevel@tonic-gate 				if (((cp = strchr(hp->h_name, '.')) != NULL) &&
7097c478bd9Sstevel@tonic-gate 				    (strcmp(cp + 1, domain) == 0))
7107c478bd9Sstevel@tonic-gate 					*cp = 0;
7117c478bd9Sstevel@tonic-gate 				cp = hp->h_name;
7127c478bd9Sstevel@tonic-gate 			}
7137c478bd9Sstevel@tonic-gate 		}
7147c478bd9Sstevel@tonic-gate 		if (cp != NULL) {
7157c478bd9Sstevel@tonic-gate 			(void) strncpy(line, cp, MAXHOSTNAMELEN);
7167c478bd9Sstevel@tonic-gate 			line[MAXHOSTNAMELEN] = '\0';
7177c478bd9Sstevel@tonic-gate 		} else {
7187c478bd9Sstevel@tonic-gate 			(void) inet_ntop(AF_INET6, (void *)&in6, line,
7197c478bd9Sstevel@tonic-gate 			    INET6_ADDRSTRLEN);
7207c478bd9Sstevel@tonic-gate 		}
7217c478bd9Sstevel@tonic-gate 		if (hp != NULL)
7227c478bd9Sstevel@tonic-gate 			freehostent(hp);
7237c478bd9Sstevel@tonic-gate 
7247c478bd9Sstevel@tonic-gate 		break;
7257c478bd9Sstevel@tonic-gate 
7267c478bd9Sstevel@tonic-gate 	default:
7277c478bd9Sstevel@tonic-gate 		s = (ushort_t *)sa;
7287c478bd9Sstevel@tonic-gate 
7297c478bd9Sstevel@tonic-gate 		slim = s + ((salen(sa) + 1) >> 1);
7307c478bd9Sstevel@tonic-gate 		cp = line + sprintf(line, "(%d)", sa->sa_family);
7317c478bd9Sstevel@tonic-gate 
7327c478bd9Sstevel@tonic-gate 		while (++s < slim) /* start with sa->sa_data */
7337c478bd9Sstevel@tonic-gate 			cp += sprintf(cp, " %x", *s);
7347c478bd9Sstevel@tonic-gate 		break;
7357c478bd9Sstevel@tonic-gate 	}
7367c478bd9Sstevel@tonic-gate 	return (line);
7377c478bd9Sstevel@tonic-gate }
7387c478bd9Sstevel@tonic-gate 
7397c478bd9Sstevel@tonic-gate /*
7407c478bd9Sstevel@tonic-gate  * Return the name of the network whose address is given.
7417c478bd9Sstevel@tonic-gate  * The address is assumed to be that of a net or subnet, not a host.
7427c478bd9Sstevel@tonic-gate  */
7437c478bd9Sstevel@tonic-gate static char *
7447c478bd9Sstevel@tonic-gate netname(struct sockaddr *sa)
7457c478bd9Sstevel@tonic-gate {
7467c478bd9Sstevel@tonic-gate 	char *cp = NULL;
7477c478bd9Sstevel@tonic-gate 	static char line[MAXHOSTNAMELEN + 1];
7487c478bd9Sstevel@tonic-gate 	struct netent *np;
7497c478bd9Sstevel@tonic-gate 	in_addr_t net, mask;
7507c478bd9Sstevel@tonic-gate 	int subnetshift;
7517c478bd9Sstevel@tonic-gate 	struct in_addr in;
7527c478bd9Sstevel@tonic-gate 	ushort_t *s;
7537c478bd9Sstevel@tonic-gate 	ushort_t *slim;
7547c478bd9Sstevel@tonic-gate 
7557c478bd9Sstevel@tonic-gate 	switch (sa->sa_family) {
7567c478bd9Sstevel@tonic-gate 
7577c478bd9Sstevel@tonic-gate 	case AF_INET:
7587c478bd9Sstevel@tonic-gate 		/* LINTED */
7597c478bd9Sstevel@tonic-gate 		in = ((struct sockaddr_in *)sa)->sin_addr;
7607c478bd9Sstevel@tonic-gate 
7617c478bd9Sstevel@tonic-gate 		in.s_addr = ntohl(in.s_addr);
7627c478bd9Sstevel@tonic-gate 		if (in.s_addr == INADDR_ANY) {
7637c478bd9Sstevel@tonic-gate 			cp = "default";
7647c478bd9Sstevel@tonic-gate 		} else if (!nflag) {
7657c478bd9Sstevel@tonic-gate 			if (IN_CLASSA(in.s_addr)) {
7667c478bd9Sstevel@tonic-gate 				mask = IN_CLASSA_NET;
7677c478bd9Sstevel@tonic-gate 				subnetshift = 8;
7687c478bd9Sstevel@tonic-gate 			} else if (IN_CLASSB(in.s_addr)) {
7697c478bd9Sstevel@tonic-gate 				mask = IN_CLASSB_NET;
7707c478bd9Sstevel@tonic-gate 				subnetshift = 8;
7717c478bd9Sstevel@tonic-gate 			} else {
7727c478bd9Sstevel@tonic-gate 				mask = IN_CLASSC_NET;
7737c478bd9Sstevel@tonic-gate 				subnetshift = 4;
7747c478bd9Sstevel@tonic-gate 			}
7757c478bd9Sstevel@tonic-gate 			/*
7767c478bd9Sstevel@tonic-gate 			 * If there are more bits than the standard mask
7777c478bd9Sstevel@tonic-gate 			 * would suggest, subnets must be in use.
7787c478bd9Sstevel@tonic-gate 			 * Guess at the subnet mask, assuming reasonable
7797c478bd9Sstevel@tonic-gate 			 * width subnet fields.
7807c478bd9Sstevel@tonic-gate 			 */
7817c478bd9Sstevel@tonic-gate 			while (in.s_addr &~ mask)
7827c478bd9Sstevel@tonic-gate 				mask = (long)mask >> subnetshift;
7837c478bd9Sstevel@tonic-gate 			net = in.s_addr & mask;
7847c478bd9Sstevel@tonic-gate 			while ((mask & 1) == 0)
7857c478bd9Sstevel@tonic-gate 				mask >>= 1, net >>= 1;
7867c478bd9Sstevel@tonic-gate 			np = getnetbyaddr(net, AF_INET);
7877c478bd9Sstevel@tonic-gate 			if (np != NULL)
7887c478bd9Sstevel@tonic-gate 				cp = np->n_name;
7897c478bd9Sstevel@tonic-gate 		}
7907c478bd9Sstevel@tonic-gate 		if (cp != NULL) {
7917c478bd9Sstevel@tonic-gate 			(void) strncpy(line, cp, MAXHOSTNAMELEN);
7927c478bd9Sstevel@tonic-gate 			line[MAXHOSTNAMELEN] = '\0';
7937c478bd9Sstevel@tonic-gate 		} else if ((in.s_addr & 0xffffff) == 0) {
7947c478bd9Sstevel@tonic-gate 			(void) sprintf(line, "%u", C(in.s_addr >> 24));
7957c478bd9Sstevel@tonic-gate 		} else if ((in.s_addr & 0xffff) == 0) {
7967c478bd9Sstevel@tonic-gate 			(void) sprintf(line, "%u.%u", C(in.s_addr >> 24),
7977c478bd9Sstevel@tonic-gate 			    C(in.s_addr >> 16));
7987c478bd9Sstevel@tonic-gate 		} else if ((in.s_addr & 0xff) == 0) {
7997c478bd9Sstevel@tonic-gate 			(void) sprintf(line, "%u.%u.%u", C(in.s_addr >> 24),
8007c478bd9Sstevel@tonic-gate 			    C(in.s_addr >> 16), C(in.s_addr >> 8));
8017c478bd9Sstevel@tonic-gate 		} else {
8027c478bd9Sstevel@tonic-gate 			(void) sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24),
8037c478bd9Sstevel@tonic-gate 			    C(in.s_addr >> 16), C(in.s_addr >> 8),
8047c478bd9Sstevel@tonic-gate 			    C(in.s_addr));
8057c478bd9Sstevel@tonic-gate 		}
8067c478bd9Sstevel@tonic-gate 		break;
8077c478bd9Sstevel@tonic-gate 
8087c478bd9Sstevel@tonic-gate 	case AF_LINK:
8097c478bd9Sstevel@tonic-gate 		return (link_ntoa((struct sockaddr_dl *)sa));
8107c478bd9Sstevel@tonic-gate 
8117c478bd9Sstevel@tonic-gate 	case AF_INET6:
8127c478bd9Sstevel@tonic-gate 		return (routename(sa));
8137c478bd9Sstevel@tonic-gate 
8147c478bd9Sstevel@tonic-gate 	default:
8157c478bd9Sstevel@tonic-gate 		/* LINTED */
8167c478bd9Sstevel@tonic-gate 		s = (ushort_t *)sa->sa_data;
8177c478bd9Sstevel@tonic-gate 
8187c478bd9Sstevel@tonic-gate 		slim = s + ((salen(sa) + 1) >> 1);
8197c478bd9Sstevel@tonic-gate 		cp = line + sprintf(line, "af %d:", sa->sa_family);
8207c478bd9Sstevel@tonic-gate 
8217c478bd9Sstevel@tonic-gate 		while (s < slim)
8227c478bd9Sstevel@tonic-gate 			cp += sprintf(cp, " %x", *s++);
8237c478bd9Sstevel@tonic-gate 		break;
8247c478bd9Sstevel@tonic-gate 	}
8257c478bd9Sstevel@tonic-gate 	return (line);
8267c478bd9Sstevel@tonic-gate }
8277c478bd9Sstevel@tonic-gate 
8287c478bd9Sstevel@tonic-gate void
829*7a23074eSdduvall set_metric(char *value, int key)
8307c478bd9Sstevel@tonic-gate {
8317c478bd9Sstevel@tonic-gate 	int flag = 0;
8327c478bd9Sstevel@tonic-gate 	uint_t noval, *valp = &noval;
8337c478bd9Sstevel@tonic-gate 
8347c478bd9Sstevel@tonic-gate 	switch (key) {
835*7a23074eSdduvall #define	caseof(x, y, z)	case (x): valp = &rt_metrics.z; flag = (y); break
8367c478bd9Sstevel@tonic-gate 	caseof(K_MTU, RTV_MTU, rmx_mtu);
8377c478bd9Sstevel@tonic-gate 	caseof(K_HOPCOUNT, RTV_HOPCOUNT, rmx_hopcount);
8387c478bd9Sstevel@tonic-gate 	caseof(K_EXPIRE, RTV_EXPIRE, rmx_expire);
8397c478bd9Sstevel@tonic-gate 	caseof(K_RECVPIPE, RTV_RPIPE, rmx_recvpipe);
8407c478bd9Sstevel@tonic-gate 	caseof(K_SENDPIPE, RTV_SPIPE, rmx_sendpipe);
8417c478bd9Sstevel@tonic-gate 	caseof(K_SSTHRESH, RTV_SSTHRESH, rmx_ssthresh);
8427c478bd9Sstevel@tonic-gate 	caseof(K_RTT, RTV_RTT, rmx_rtt);
8437c478bd9Sstevel@tonic-gate 	caseof(K_RTTVAR, RTV_RTTVAR, rmx_rttvar);
8447c478bd9Sstevel@tonic-gate #undef	caseof
8457c478bd9Sstevel@tonic-gate 	}
846*7a23074eSdduvall 	rtm_inits |= flag;
847*7a23074eSdduvall 	if (lockrest || locking)
848*7a23074eSdduvall 		rt_metrics.rmx_locks |= flag;
849*7a23074eSdduvall 	if (locking)
850*7a23074eSdduvall 		locking = B_FALSE;
8517c478bd9Sstevel@tonic-gate 	*valp = atoi(value);
8527c478bd9Sstevel@tonic-gate }
8537c478bd9Sstevel@tonic-gate 
854*7a23074eSdduvall int
855*7a23074eSdduvall newroute(int argc, char **argv)
8567c478bd9Sstevel@tonic-gate {
857*7a23074eSdduvall 	char *cmd, *dest = "", *gateway = "", *err;
858*7a23074eSdduvall 	boolean_t ishost = B_FALSE;
859*7a23074eSdduvall 	int ret, attempts, oerrno, flags = RTF_STATIC;
8607c478bd9Sstevel@tonic-gate 	int key;
861*7a23074eSdduvall 	struct hostent *hp = NULL;
862*7a23074eSdduvall 	static char obuf[INET6_ADDRSTRLEN];
8637c478bd9Sstevel@tonic-gate 
864*7a23074eSdduvall 	cmd = argv[0];
865*7a23074eSdduvall 	if (*cmd != 'g' && !tflag) {
866*7a23074eSdduvall 		/* Don't want to read back our messages */
867*7a23074eSdduvall 		(void) shutdown(s, 0);
8687c478bd9Sstevel@tonic-gate 	}
869*7a23074eSdduvall 	while (--argc > 0) {
870*7a23074eSdduvall 		key = keyword(*(++argv));
871*7a23074eSdduvall 		if (key == K_HOST) {
872*7a23074eSdduvall 			forcehost = B_TRUE;
873*7a23074eSdduvall 		} else if (key == K_NET) {
874*7a23074eSdduvall 			forcenet = B_TRUE;
875*7a23074eSdduvall 		} else if (**(argv) == '-') {
876*7a23074eSdduvall 			switch (key = keyword(1 + *argv)) {
8777c478bd9Sstevel@tonic-gate 			case K_LINK:
878*7a23074eSdduvall 				af = AF_LINK;
8797c478bd9Sstevel@tonic-gate 				break;
8807c478bd9Sstevel@tonic-gate 			case K_INET:
881*7a23074eSdduvall 				af = AF_INET;
8827c478bd9Sstevel@tonic-gate 				break;
8837c478bd9Sstevel@tonic-gate 			case K_SA:
884*7a23074eSdduvall 				af = PF_ROUTE;
8857c478bd9Sstevel@tonic-gate 				break;
8867c478bd9Sstevel@tonic-gate 			case K_INET6:
887*7a23074eSdduvall 				af = AF_INET6;
8887c478bd9Sstevel@tonic-gate 				break;
8897c478bd9Sstevel@tonic-gate 			case K_IFACE:
8907c478bd9Sstevel@tonic-gate 			case K_INTERFACE:
8917c478bd9Sstevel@tonic-gate 				iflag = B_TRUE;
892*7a23074eSdduvall 				/* FALLTHROUGH */
8937c478bd9Sstevel@tonic-gate 			case K_NOSTATIC:
894*7a23074eSdduvall 				flags &= ~RTF_STATIC;
8957c478bd9Sstevel@tonic-gate 				break;
8967c478bd9Sstevel@tonic-gate 			case K_LOCK:
897*7a23074eSdduvall 				locking = B_TRUE;
8987c478bd9Sstevel@tonic-gate 				break;
8997c478bd9Sstevel@tonic-gate 			case K_LOCKREST:
9007c478bd9Sstevel@tonic-gate 				lockrest = B_TRUE;
9017c478bd9Sstevel@tonic-gate 				break;
902*7a23074eSdduvall 			case K_HOST:
903*7a23074eSdduvall 				forcehost = B_TRUE;
904*7a23074eSdduvall 				break;
9057c478bd9Sstevel@tonic-gate 			case K_REJECT:
906*7a23074eSdduvall 				flags |= RTF_REJECT;
9077c478bd9Sstevel@tonic-gate 				break;
9087c478bd9Sstevel@tonic-gate 			case K_BLACKHOLE:
909*7a23074eSdduvall 				flags |= RTF_BLACKHOLE;
9107c478bd9Sstevel@tonic-gate 				break;
9117c478bd9Sstevel@tonic-gate 			case K_PROTO1:
912*7a23074eSdduvall 				flags |= RTF_PROTO1;
9137c478bd9Sstevel@tonic-gate 				break;
9147c478bd9Sstevel@tonic-gate 			case K_PROTO2:
915*7a23074eSdduvall 				flags |= RTF_PROTO2;
9167c478bd9Sstevel@tonic-gate 				break;
9177c478bd9Sstevel@tonic-gate 			case K_CLONING:
918*7a23074eSdduvall 				flags |= RTF_CLONING;
9197c478bd9Sstevel@tonic-gate 				break;
9207c478bd9Sstevel@tonic-gate 			case K_XRESOLVE:
921*7a23074eSdduvall 				flags |= RTF_XRESOLVE;
9227c478bd9Sstevel@tonic-gate 				break;
9237c478bd9Sstevel@tonic-gate 			case K_STATIC:
924*7a23074eSdduvall 				flags |= RTF_STATIC;
9257c478bd9Sstevel@tonic-gate 				break;
9267c478bd9Sstevel@tonic-gate 			case K_IFA:
927*7a23074eSdduvall 				argc--;
928*7a23074eSdduvall 				(void) getaddr(RTA_IFA, *++argv, NULL);
9297c478bd9Sstevel@tonic-gate 				break;
9307c478bd9Sstevel@tonic-gate 			case K_IFP:
931*7a23074eSdduvall 				argc--;
932*7a23074eSdduvall 				(void) getaddr(RTA_IFP, *++argv, NULL);
9337c478bd9Sstevel@tonic-gate 				break;
9347c478bd9Sstevel@tonic-gate 			case K_GATEWAY:
935*7a23074eSdduvall 				/*
936*7a23074eSdduvall 				 * For the gateway parameter, retrieve the
937*7a23074eSdduvall 				 * pointer to the struct hostent so that all
938*7a23074eSdduvall 				 * possible addresses can be tried until one
939*7a23074eSdduvall 				 * is successful.
940*7a23074eSdduvall 				 */
941*7a23074eSdduvall 				argc--;
942*7a23074eSdduvall 				gateway = *++argv;
943*7a23074eSdduvall 				(void) getaddr(RTA_GATEWAY, *argv, &hp);
9447c478bd9Sstevel@tonic-gate 				break;
9457c478bd9Sstevel@tonic-gate 			case K_DST:
946*7a23074eSdduvall 				argc--;
947*7a23074eSdduvall 				ishost = getaddr(RTA_DST, *++argv, NULL);
948*7a23074eSdduvall 				dest = *argv;
9497c478bd9Sstevel@tonic-gate 				break;
9507c478bd9Sstevel@tonic-gate 			case K_NETMASK:
951*7a23074eSdduvall 				argc--;
952*7a23074eSdduvall 				(void) getaddr(RTA_NETMASK, *++argv, NULL);
953*7a23074eSdduvall 				/* FALLTHROUGH */
954*7a23074eSdduvall 			case K_NET:
955*7a23074eSdduvall 				forcenet = B_TRUE;
9567c478bd9Sstevel@tonic-gate 				break;
9577c478bd9Sstevel@tonic-gate 			case K_MTU:
9587c478bd9Sstevel@tonic-gate 			case K_HOPCOUNT:
9597c478bd9Sstevel@tonic-gate 			case K_EXPIRE:
9607c478bd9Sstevel@tonic-gate 			case K_RECVPIPE:
9617c478bd9Sstevel@tonic-gate 			case K_SENDPIPE:
9627c478bd9Sstevel@tonic-gate 			case K_SSTHRESH:
9637c478bd9Sstevel@tonic-gate 			case K_RTT:
9647c478bd9Sstevel@tonic-gate 			case K_RTTVAR:
965*7a23074eSdduvall 				argc--;
966*7a23074eSdduvall 				set_metric(*++argv, key);
9677c478bd9Sstevel@tonic-gate 				break;
9687c478bd9Sstevel@tonic-gate 			case K_PRIVATE:
969*7a23074eSdduvall 				flags |= RTF_PRIVATE;
9707c478bd9Sstevel@tonic-gate 				break;
9717c478bd9Sstevel@tonic-gate 			case K_MULTIRT:
972*7a23074eSdduvall 				flags |= RTF_MULTIRT;
9737c478bd9Sstevel@tonic-gate 				break;
9747c478bd9Sstevel@tonic-gate 			case K_SETSRC:
975*7a23074eSdduvall 				argc--;
976*7a23074eSdduvall 				(void) getaddr(RTA_SRC, *++argv, NULL);
977*7a23074eSdduvall 				flags |= RTF_SETSRC;
9787c478bd9Sstevel@tonic-gate 				break;
9797c478bd9Sstevel@tonic-gate 			default:
980*7a23074eSdduvall 				usage(*argv + 1);
981*7a23074eSdduvall 				/* NOTREACHED */
9827c478bd9Sstevel@tonic-gate 			}
983*7a23074eSdduvall 		} else {
984*7a23074eSdduvall 			if ((rtm_addrs & RTA_DST) == 0) {
985*7a23074eSdduvall 				dest = *argv;
986*7a23074eSdduvall 				ishost = getaddr(RTA_DST, *argv, NULL);
987*7a23074eSdduvall 			} else if ((rtm_addrs & RTA_GATEWAY) == 0) {
9887c478bd9Sstevel@tonic-gate 				/*
9897c478bd9Sstevel@tonic-gate 				 * For the gateway parameter, retrieve the
9907c478bd9Sstevel@tonic-gate 				 * pointer to the struct hostent so that all
9917c478bd9Sstevel@tonic-gate 				 * possible addresses can be tried until one
9927c478bd9Sstevel@tonic-gate 				 * is successful.
9937c478bd9Sstevel@tonic-gate 				 */
994*7a23074eSdduvall 				gateway = *argv;
995*7a23074eSdduvall 				(void) getaddr(RTA_GATEWAY, *argv, &hp);
9967c478bd9Sstevel@tonic-gate 			} else {
997*7a23074eSdduvall 				ulong_t metric = strtoul(*argv, &err, 10);
998*7a23074eSdduvall 
9997c478bd9Sstevel@tonic-gate 				/*
10007c478bd9Sstevel@tonic-gate 				 * Assume that a regular number is a metric.
10017c478bd9Sstevel@tonic-gate 				 * Needed for compatibility with old route
10027c478bd9Sstevel@tonic-gate 				 * command syntax.
10037c478bd9Sstevel@tonic-gate 				 */
1004*7a23074eSdduvall 				if (*argv != err && *err == '\0' &&
10057c478bd9Sstevel@tonic-gate 				    metric < 0x80000000ul) {
10067c478bd9Sstevel@tonic-gate 					iflag = (metric == 0);
10077c478bd9Sstevel@tonic-gate 					if (verbose) {
10087c478bd9Sstevel@tonic-gate 						(void) printf("old usage of "
10097c478bd9Sstevel@tonic-gate 						    "trailing number, assuming "
10107c478bd9Sstevel@tonic-gate 						    "route %s\n", iflag ?
10117c478bd9Sstevel@tonic-gate 						    "to if" : "via gateway");
10127c478bd9Sstevel@tonic-gate 					}
10137c478bd9Sstevel@tonic-gate 					continue;
10147c478bd9Sstevel@tonic-gate 				}
1015*7a23074eSdduvall 				(void) getaddr(RTA_NETMASK, *argv, NULL);
10167c478bd9Sstevel@tonic-gate 			}
10177c478bd9Sstevel@tonic-gate 		}
10187c478bd9Sstevel@tonic-gate 	}
1019*7a23074eSdduvall 	if ((rtm_addrs & RTA_DST) == 0) {
10203f33f4f7Sjl138328 		(void) fprintf(stderr,
1021*7a23074eSdduvall 		    gettext("route: destination required following command\n"));
1022*7a23074eSdduvall 		usage((char *)NULL);
1023*7a23074eSdduvall 	} else if ((*cmd == 'a' || *cmd == 'd') &&
1024*7a23074eSdduvall 	    (rtm_addrs & RTA_GATEWAY) == 0) {
1025*7a23074eSdduvall 		(void) fprintf(stderr,
1026*7a23074eSdduvall 		    gettext("route: gateway required for add or delete "
1027*7a23074eSdduvall 		    "command\n"));
1028*7a23074eSdduvall 		usage((char *)NULL);
10293f33f4f7Sjl138328 	}
1030*7a23074eSdduvall 
1031*7a23074eSdduvall 	/*
1032*7a23074eSdduvall 	 * If the netmask has been specified use it to determine RTF_HOST.
1033*7a23074eSdduvall 	 * Otherwise rely on the "-net" and "-host" specifiers.
1034*7a23074eSdduvall 	 * Final fallback is whether ot not any bits were set in the address
1035*7a23074eSdduvall 	 * past the classful network component.
1036*7a23074eSdduvall 	 */
1037*7a23074eSdduvall 	if (rtm_addrs & RTA_NETMASK) {
1038*7a23074eSdduvall 		if ((af == AF_INET &&
1039*7a23074eSdduvall 			so_mask.sin.sin_addr.s_addr == IP_HOST_MASK) ||
1040*7a23074eSdduvall 		    (af == AF_INET6 && masklen == IPV6_ABITS))
1041*7a23074eSdduvall 			forcehost = B_TRUE;
1042*7a23074eSdduvall 		else
1043*7a23074eSdduvall 			forcenet = B_TRUE;
10443f33f4f7Sjl138328 	}
1045*7a23074eSdduvall 	if (forcehost)
1046*7a23074eSdduvall 		ishost = B_TRUE;
1047*7a23074eSdduvall 	if (forcenet)
1048*7a23074eSdduvall 		ishost = B_FALSE;
1049*7a23074eSdduvall 	flags |= RTF_UP;
1050*7a23074eSdduvall 	if (ishost)
1051*7a23074eSdduvall 		flags |= RTF_HOST;
1052*7a23074eSdduvall 	if (!iflag)
1053*7a23074eSdduvall 		flags |= RTF_GATEWAY;
10547c478bd9Sstevel@tonic-gate 	for (attempts = 1; ; attempts++) {
10557c478bd9Sstevel@tonic-gate 		errno = 0;
1056*7a23074eSdduvall 		if ((ret = rtmsg(*cmd, flags)) == 0)
10577c478bd9Sstevel@tonic-gate 			break;
10587c478bd9Sstevel@tonic-gate 		if (errno != ENETUNREACH && errno != ESRCH)
10597c478bd9Sstevel@tonic-gate 			break;
1060*7a23074eSdduvall 		if (*gateway != '\0' && hp != NULL &&
10617c478bd9Sstevel@tonic-gate 		    hp->h_addr_list[attempts] != NULL) {
10627c478bd9Sstevel@tonic-gate 			switch (af) {
10637c478bd9Sstevel@tonic-gate 			case AF_INET:
1064*7a23074eSdduvall 				(void) memmove(&so_gate.sin.sin_addr,
10657c478bd9Sstevel@tonic-gate 				    hp->h_addr_list[attempts], hp->h_length);
10667c478bd9Sstevel@tonic-gate 				continue;
10677c478bd9Sstevel@tonic-gate 			case AF_INET6:
1068*7a23074eSdduvall 				(void) memmove(&so_gate.sin6.sin6_addr,
10697c478bd9Sstevel@tonic-gate 				    hp->h_addr_list[attempts], hp->h_length);
10707c478bd9Sstevel@tonic-gate 				continue;
10717c478bd9Sstevel@tonic-gate 			}
10727c478bd9Sstevel@tonic-gate 		}
10737c478bd9Sstevel@tonic-gate 		break;
10747c478bd9Sstevel@tonic-gate 	}
10757c478bd9Sstevel@tonic-gate 	oerrno = errno;
1076*7a23074eSdduvall 	if (*cmd != 'g') {
1077*7a23074eSdduvall 		(void) printf("%s %s %s", cmd, ishost ? "host" : "net", dest);
1078*7a23074eSdduvall 		if (*gateway != '\0') {
1079*7a23074eSdduvall 			switch (af) {
10807c478bd9Sstevel@tonic-gate 			case AF_INET:
1081*7a23074eSdduvall 				if (nflag) {
1082*7a23074eSdduvall 					(void) printf(": gateway %s",
1083*7a23074eSdduvall 					    inet_ntoa(so_gate.sin.sin_addr));
1084*7a23074eSdduvall 				} else if (attempts > 1 && ret == 0) {
1085*7a23074eSdduvall 					(void) printf(": gateway %s (%s)",
1086*7a23074eSdduvall 					    gateway,
1087*7a23074eSdduvall 					    inet_ntoa(so_gate.sin.sin_addr));
1088*7a23074eSdduvall 				} else {
1089*7a23074eSdduvall 					(void) printf(": gateway %s", gateway);
1090*7a23074eSdduvall 				}
10917c478bd9Sstevel@tonic-gate 				break;
10927c478bd9Sstevel@tonic-gate 			case AF_INET6:
10937c478bd9Sstevel@tonic-gate 				if (inet_ntop(AF_INET6,
1094*7a23074eSdduvall 				    (void *)&so_gate.sin6.sin6_addr, obuf,
1095*7a23074eSdduvall 				    INET6_ADDRSTRLEN) != NULL) {
1096*7a23074eSdduvall 					if (nflag) {
1097*7a23074eSdduvall 						(void) printf(": gateway %s",
1098*7a23074eSdduvall 						    obuf);
1099*7a23074eSdduvall 					} else if (attempts > 1 && ret == 0) {
1100*7a23074eSdduvall 						(void) printf(": gateway %s "
1101*7a23074eSdduvall 						    "(%s)",
1102*7a23074eSdduvall 						    gateway, obuf);
1103*7a23074eSdduvall 					}
1104*7a23074eSdduvall 					break;
1105*7a23074eSdduvall 				}
1106*7a23074eSdduvall 				/* FALLTHROUGH */
1107*7a23074eSdduvall 			default:
1108*7a23074eSdduvall 				(void) printf(": gateway %s", gateway);
1109*7a23074eSdduvall 				break;
1110*7a23074eSdduvall 			}
1111*7a23074eSdduvall 		}
1112*7a23074eSdduvall 		if (ret == 0)
1113*7a23074eSdduvall 			(void) printf("\n");
1114*7a23074eSdduvall 	}
1115*7a23074eSdduvall 	if (ret != 0) {
1116*7a23074eSdduvall 		if (*cmd == 'g') {
1117*7a23074eSdduvall 			if (nflag) {
1118*7a23074eSdduvall 				switch (af) {
1119*7a23074eSdduvall 				case AF_INET:
1120*7a23074eSdduvall 					(void) printf(" %s",
1121*7a23074eSdduvall 					    inet_ntoa(so_dst.sin.sin_addr));
1122*7a23074eSdduvall 					break;
1123*7a23074eSdduvall 				case AF_INET6:
1124*7a23074eSdduvall 					if (inet_ntop(AF_INET6,
1125*7a23074eSdduvall 					    (void *)&so_dst.sin6.sin6_addr,
11267c478bd9Sstevel@tonic-gate 					    obuf, INET6_ADDRSTRLEN) != NULL) {
11277c478bd9Sstevel@tonic-gate 						(void) printf(" %s", obuf);
11287c478bd9Sstevel@tonic-gate 						break;
11297c478bd9Sstevel@tonic-gate 					}
11307c478bd9Sstevel@tonic-gate 					/* FALLTHROUGH */
11317c478bd9Sstevel@tonic-gate 				default:
1132*7a23074eSdduvall 					(void) printf("%s", dest);
11337c478bd9Sstevel@tonic-gate 					break;
11347c478bd9Sstevel@tonic-gate 				}
11357c478bd9Sstevel@tonic-gate 			} else {
1136*7a23074eSdduvall 				(void) printf("%s", dest);
11377c478bd9Sstevel@tonic-gate 			}
11387c478bd9Sstevel@tonic-gate 		}
11397c478bd9Sstevel@tonic-gate 		switch (oerrno) {
11407c478bd9Sstevel@tonic-gate 		case ESRCH:
11417c478bd9Sstevel@tonic-gate 			err = "not in table";
11427c478bd9Sstevel@tonic-gate 			break;
11437c478bd9Sstevel@tonic-gate 		case EBUSY:
11447c478bd9Sstevel@tonic-gate 			err = "entry in use";
11457c478bd9Sstevel@tonic-gate 			break;
11467c478bd9Sstevel@tonic-gate 		case ENOBUFS:
11477c478bd9Sstevel@tonic-gate 			err = "routing table overflow";
11487c478bd9Sstevel@tonic-gate 			break;
11497c478bd9Sstevel@tonic-gate 		case EEXIST:
11507c478bd9Sstevel@tonic-gate 			err = "entry exists";
11517c478bd9Sstevel@tonic-gate 			break;
11527c478bd9Sstevel@tonic-gate 		case EPERM:
11537c478bd9Sstevel@tonic-gate 			err = "insufficient privileges";
11547c478bd9Sstevel@tonic-gate 			break;
11557c478bd9Sstevel@tonic-gate 		default:
11567c478bd9Sstevel@tonic-gate 			err = strerror(oerrno);
11577c478bd9Sstevel@tonic-gate 			break;
11587c478bd9Sstevel@tonic-gate 		}
11597c478bd9Sstevel@tonic-gate 		(void) printf(": %s\n", err);
11607c478bd9Sstevel@tonic-gate 	}
1161*7a23074eSdduvall 	/*
1162*7a23074eSdduvall 	 * In the case of AF_INET6, one of the getipnodebyX() functions was used
1163*7a23074eSdduvall 	 * so free the allocated hostent.
1164*7a23074eSdduvall 	 */
1165*7a23074eSdduvall 	if (af == AF_INET6 && hp != NULL)
1166*7a23074eSdduvall 		freehostent(hp);
11677c478bd9Sstevel@tonic-gate 
11687c478bd9Sstevel@tonic-gate 	return (oerrno);
11697c478bd9Sstevel@tonic-gate }
11707c478bd9Sstevel@tonic-gate 
11717c478bd9Sstevel@tonic-gate 
11727c478bd9Sstevel@tonic-gate /*
11737c478bd9Sstevel@tonic-gate  * Convert a network number to the corresponding IP address.
11747c478bd9Sstevel@tonic-gate  * If the RTA_NETMASK hasn't been specified yet set it based
11757c478bd9Sstevel@tonic-gate  * on the class of address.
11767c478bd9Sstevel@tonic-gate  */
11777c478bd9Sstevel@tonic-gate static void
1178*7a23074eSdduvall inet_makenetandmask(in_addr_t net, struct sockaddr_in *sin)
11797c478bd9Sstevel@tonic-gate {
11807c478bd9Sstevel@tonic-gate 	in_addr_t addr, mask;
1181*7a23074eSdduvall 	char *cp;
11827c478bd9Sstevel@tonic-gate 
11837c478bd9Sstevel@tonic-gate 	if (net == 0) {
11847c478bd9Sstevel@tonic-gate 		mask = addr = 0;
11857c478bd9Sstevel@tonic-gate 	} else if (net < 128) {
11867c478bd9Sstevel@tonic-gate 		addr = net << IN_CLASSA_NSHIFT;
11877c478bd9Sstevel@tonic-gate 		mask = IN_CLASSA_NET;
11887c478bd9Sstevel@tonic-gate 	} else if (net < 65536) {
11897c478bd9Sstevel@tonic-gate 		addr = net << IN_CLASSB_NSHIFT;
11907c478bd9Sstevel@tonic-gate 		mask = IN_CLASSB_NET;
11917c478bd9Sstevel@tonic-gate 	} else if (net < 16777216L) {
11927c478bd9Sstevel@tonic-gate 		addr = net << IN_CLASSC_NSHIFT;
11937c478bd9Sstevel@tonic-gate 		mask = IN_CLASSC_NET;
11947c478bd9Sstevel@tonic-gate 	} else {
11957c478bd9Sstevel@tonic-gate 		addr = net;
11967c478bd9Sstevel@tonic-gate 		if ((addr & IN_CLASSA_HOST) == 0)
11977c478bd9Sstevel@tonic-gate 			mask =  IN_CLASSA_NET;
11987c478bd9Sstevel@tonic-gate 		else if ((addr & IN_CLASSB_HOST) == 0)
11997c478bd9Sstevel@tonic-gate 			mask =  IN_CLASSB_NET;
12007c478bd9Sstevel@tonic-gate 		else if ((addr & IN_CLASSC_HOST) == 0)
12017c478bd9Sstevel@tonic-gate 			mask =  IN_CLASSC_NET;
12027c478bd9Sstevel@tonic-gate 		else {
12037c478bd9Sstevel@tonic-gate 			if (IN_CLASSA(addr))
12047c478bd9Sstevel@tonic-gate 				mask =  IN_CLASSA_NET;
12057c478bd9Sstevel@tonic-gate 			else if (IN_CLASSB(addr))
12067c478bd9Sstevel@tonic-gate 				mask =  IN_CLASSB_NET;
12077c478bd9Sstevel@tonic-gate 			else if (IN_CLASSC(addr))
12087c478bd9Sstevel@tonic-gate 				mask =  IN_CLASSC_NET;
12097c478bd9Sstevel@tonic-gate 			else
12107c478bd9Sstevel@tonic-gate 				mask = IP_HOST_MASK;
12117c478bd9Sstevel@tonic-gate 			mask = inet_makesubnetmask(addr, mask);
12127c478bd9Sstevel@tonic-gate 		}
12137c478bd9Sstevel@tonic-gate 	}
12147c478bd9Sstevel@tonic-gate 	sin->sin_addr.s_addr = htonl(addr);
12157c478bd9Sstevel@tonic-gate 
1216*7a23074eSdduvall 	if (!(rtm_addrs & RTA_NETMASK)) {
1217*7a23074eSdduvall 		rtm_addrs |= RTA_NETMASK;
1218*7a23074eSdduvall 		sin = &so_mask.sin;
12197c478bd9Sstevel@tonic-gate 		sin->sin_addr.s_addr = htonl(mask);
12207c478bd9Sstevel@tonic-gate 		sin->sin_family = AF_INET;
1221*7a23074eSdduvall 		cp = (char *)(&sin->sin_addr + 1);
1222*7a23074eSdduvall 		while (*--cp == 0 && cp > (char *)sin)
1223*7a23074eSdduvall 			;
12247c478bd9Sstevel@tonic-gate 	}
12257c478bd9Sstevel@tonic-gate }
12267c478bd9Sstevel@tonic-gate 
12277c478bd9Sstevel@tonic-gate static in_addr_t
12287c478bd9Sstevel@tonic-gate inet_makesubnetmask(in_addr_t addr, in_addr_t mask)
12297c478bd9Sstevel@tonic-gate {
12307c478bd9Sstevel@tonic-gate 	int n;
12317c478bd9Sstevel@tonic-gate 	struct ifconf ifc;
12327c478bd9Sstevel@tonic-gate 	struct ifreq ifreq;
12337c478bd9Sstevel@tonic-gate 	struct ifreq *ifr;
12347c478bd9Sstevel@tonic-gate 	struct sockaddr_in *sin;
12357c478bd9Sstevel@tonic-gate 	char *buf;
12367c478bd9Sstevel@tonic-gate 	int numifs;
12377c478bd9Sstevel@tonic-gate 	size_t bufsize;
12387c478bd9Sstevel@tonic-gate 	int iosoc;
12397c478bd9Sstevel@tonic-gate 	in_addr_t if_addr, if_mask;
12407c478bd9Sstevel@tonic-gate 	in_addr_t if_subnetmask = 0;
12417c478bd9Sstevel@tonic-gate 	short if_flags;
12427c478bd9Sstevel@tonic-gate 
12437c478bd9Sstevel@tonic-gate 	if (mask == 0)
12447c478bd9Sstevel@tonic-gate 		return (0);
12457c478bd9Sstevel@tonic-gate 	if ((iosoc = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
12467c478bd9Sstevel@tonic-gate 		quit("socket", errno);
12477c478bd9Sstevel@tonic-gate 	if (ioctl(iosoc, SIOCGIFNUM, (char *)&numifs) < 0)
12487c478bd9Sstevel@tonic-gate 		quit("ioctl", errno);
12497c478bd9Sstevel@tonic-gate 	bufsize = numifs * sizeof (struct ifreq);
12507c478bd9Sstevel@tonic-gate 	buf = malloc(bufsize);
12517c478bd9Sstevel@tonic-gate 	if (buf == NULL)
12527c478bd9Sstevel@tonic-gate 		quit("malloc", errno);
12537c478bd9Sstevel@tonic-gate 	(void) memset(&ifc, 0, sizeof (ifc));
12547c478bd9Sstevel@tonic-gate 	ifc.ifc_len = bufsize;
12557c478bd9Sstevel@tonic-gate 	ifc.ifc_buf = buf;
12567c478bd9Sstevel@tonic-gate 	if (ioctl(iosoc, SIOCGIFCONF, (char *)&ifc) < 0)
12577c478bd9Sstevel@tonic-gate 		quit("ioctl (get interface configuration)", errno);
12587c478bd9Sstevel@tonic-gate 	/* Let's check to see if this is maybe a local subnet route. */
12597c478bd9Sstevel@tonic-gate 	ifr = ifc.ifc_req;
12607c478bd9Sstevel@tonic-gate 	for (n = ifc.ifc_len / sizeof (struct ifreq); n > 0; n--, ifr++) {
12617c478bd9Sstevel@tonic-gate 		ifreq = *ifr;
12627c478bd9Sstevel@tonic-gate 		/* LINTED */
12637c478bd9Sstevel@tonic-gate 		sin = (struct sockaddr_in *)&ifr->ifr_addr;
12647c478bd9Sstevel@tonic-gate 		if_addr = ntohl(sin->sin_addr.s_addr);
12657c478bd9Sstevel@tonic-gate 
12667c478bd9Sstevel@tonic-gate 		if (ioctl(iosoc, SIOCGIFFLAGS, (char *)&ifreq) < 0)
12677c478bd9Sstevel@tonic-gate 			quit("ioctl (get interface flags)", errno);
12687c478bd9Sstevel@tonic-gate 		if ((ifreq.ifr_flags & IFF_UP) == 0)
12697c478bd9Sstevel@tonic-gate 			continue;
12707c478bd9Sstevel@tonic-gate 		if_flags = ifreq.ifr_flags;
12717c478bd9Sstevel@tonic-gate 
12727c478bd9Sstevel@tonic-gate 		if (ioctl(iosoc, SIOCGIFNETMASK, (char *)&ifreq) < 0)
12737c478bd9Sstevel@tonic-gate 			quit("ioctl (get netmask)", errno);
12747c478bd9Sstevel@tonic-gate 		/* LINTED */
12757c478bd9Sstevel@tonic-gate 		sin = (struct sockaddr_in *)&ifreq.ifr_addr;
12767c478bd9Sstevel@tonic-gate 		if_mask = ntohl(sin->sin_addr.s_addr);
12777c478bd9Sstevel@tonic-gate 		if ((if_addr & mask) == (addr & mask)) {
12787c478bd9Sstevel@tonic-gate 			/*
12797c478bd9Sstevel@tonic-gate 			 * Don't trust pt-pt interfaces if there are
12807c478bd9Sstevel@tonic-gate 			 * other interfaces.
12817c478bd9Sstevel@tonic-gate 			 */
12827c478bd9Sstevel@tonic-gate 			if (if_flags & IFF_POINTOPOINT) {
12837c478bd9Sstevel@tonic-gate 				if_subnetmask = if_mask;
12847c478bd9Sstevel@tonic-gate 				continue;
12857c478bd9Sstevel@tonic-gate 			}
12867c478bd9Sstevel@tonic-gate 			/*
12877c478bd9Sstevel@tonic-gate 			 * Fine.  Just assume the same net mask as the
12887c478bd9Sstevel@tonic-gate 			 * directly attached subnet interface is using.
12897c478bd9Sstevel@tonic-gate 			 */
12907c478bd9Sstevel@tonic-gate 			return (if_mask);
12917c478bd9Sstevel@tonic-gate 		}
12927c478bd9Sstevel@tonic-gate 	}
12937c478bd9Sstevel@tonic-gate 	if (if_subnetmask != 0)
12947c478bd9Sstevel@tonic-gate 		return (if_subnetmask);
12957c478bd9Sstevel@tonic-gate 	return (mask);
12967c478bd9Sstevel@tonic-gate }
12977c478bd9Sstevel@tonic-gate 
12987c478bd9Sstevel@tonic-gate /*
1299*7a23074eSdduvall  * Interpret an argument as a network address of some kind,
1300*7a23074eSdduvall  * returning B_TRUE if a host address, B_FALSE if a network address.
13017c478bd9Sstevel@tonic-gate  *
13027c478bd9Sstevel@tonic-gate  * If the address family is one looked up in getaddr() using one of the
13037c478bd9Sstevel@tonic-gate  * getipnodebyX() functions (currently only AF_INET6), then callers should
13047c478bd9Sstevel@tonic-gate  * freehostent() the returned "struct hostent" pointer if one was passed in.
13057c478bd9Sstevel@tonic-gate  */
13067c478bd9Sstevel@tonic-gate static boolean_t
1307*7a23074eSdduvall getaddr(int which, char *s, struct hostent **hpp)
13087c478bd9Sstevel@tonic-gate {
1309*7a23074eSdduvall 	sup su;
13107c478bd9Sstevel@tonic-gate 	struct hostent *hp;
13117c478bd9Sstevel@tonic-gate 	boolean_t ret;
13127c478bd9Sstevel@tonic-gate 
1313*7a23074eSdduvall 	if (s == NULL) {
1314*7a23074eSdduvall 		(void) fprintf(stderr,
1315*7a23074eSdduvall 		    gettext("route: argument required following keyword\n"));
1316*7a23074eSdduvall 		usage((char *)NULL);
13173f33f4f7Sjl138328 	}
1318*7a23074eSdduvall 	if (hpp == NULL)
1319*7a23074eSdduvall 		hpp = &hp;
13207c478bd9Sstevel@tonic-gate 	*hpp = NULL;
1321*7a23074eSdduvall 	rtm_addrs |= which;
13227c478bd9Sstevel@tonic-gate 	switch (which) {
13237c478bd9Sstevel@tonic-gate 	case RTA_DST:
1324*7a23074eSdduvall 		su = &so_dst;
1325*7a23074eSdduvall 		su->sa.sa_family = af;
13267c478bd9Sstevel@tonic-gate 		break;
13277c478bd9Sstevel@tonic-gate 	case RTA_GATEWAY:
1328*7a23074eSdduvall 		su = &so_gate;
1329*7a23074eSdduvall 		su->sa.sa_family = af;
13307c478bd9Sstevel@tonic-gate 		break;
13317c478bd9Sstevel@tonic-gate 	case RTA_NETMASK:
1332*7a23074eSdduvall 		su = &so_mask;
1333*7a23074eSdduvall 		su->sa.sa_family = af;
13347c478bd9Sstevel@tonic-gate 		break;
13357c478bd9Sstevel@tonic-gate 	case RTA_IFP:
1336*7a23074eSdduvall 		so_ifp.sdl.sdl_index = if_nametoindex(s);
1337*7a23074eSdduvall 		if (so_ifp.sdl.sdl_index == 0) {
1338*7a23074eSdduvall 			if (errno == ENXIO) {
1339*7a23074eSdduvall 				(void) fprintf(stderr,
1340*7a23074eSdduvall 				    gettext("route: %s: no such interface\n"),
1341*7a23074eSdduvall 					s);
1342*7a23074eSdduvall 				exit(1);
1343*7a23074eSdduvall 			} else {
1344*7a23074eSdduvall 				quit("if_nametoindex", errno);
1345*7a23074eSdduvall 			}
1346*7a23074eSdduvall 		}
1347*7a23074eSdduvall 		so_ifp.sdl.sdl_family = AF_LINK;
1348*7a23074eSdduvall 		return (B_FALSE);
13497c478bd9Sstevel@tonic-gate 		/*
13507c478bd9Sstevel@tonic-gate 		 * RTA_SRC has overloaded meaning. It can represent the
13517c478bd9Sstevel@tonic-gate 		 * src address of incoming or outgoing packets.
13527c478bd9Sstevel@tonic-gate 		 */
13537c478bd9Sstevel@tonic-gate 	case RTA_IFA:
1354*7a23074eSdduvall 		su = &so_ifa;
1355*7a23074eSdduvall 		su->sa.sa_family = af;
13567c478bd9Sstevel@tonic-gate 		break;
13577c478bd9Sstevel@tonic-gate 	case RTA_SRC:
1358*7a23074eSdduvall 		su = &so_src;
1359*7a23074eSdduvall 		su->sa.sa_family = af;
13607c478bd9Sstevel@tonic-gate 		break;
13617c478bd9Sstevel@tonic-gate 	default:
13627c478bd9Sstevel@tonic-gate 		/* NOTREACHED */
13637c478bd9Sstevel@tonic-gate 		quit(gettext("Internal Error"), EINVAL);
13647c478bd9Sstevel@tonic-gate 		/* NOTREACHED */
13657c478bd9Sstevel@tonic-gate 	}
13667c478bd9Sstevel@tonic-gate 	if (strcmp(s, "default") == 0) {
13677c478bd9Sstevel@tonic-gate 		if (which == RTA_DST) {
1368*7a23074eSdduvall 			forcenet = B_TRUE;
1369*7a23074eSdduvall 			(void) getaddr(RTA_NETMASK, s, NULL);
13707c478bd9Sstevel@tonic-gate 		}
13717c478bd9Sstevel@tonic-gate 		if (which == RTA_SRC) {
13727c478bd9Sstevel@tonic-gate 			return (B_TRUE);
13737c478bd9Sstevel@tonic-gate 		}
1374*7a23074eSdduvall 		return (B_FALSE);
13757c478bd9Sstevel@tonic-gate 	}
1376*7a23074eSdduvall 	switch (af) {
13777c478bd9Sstevel@tonic-gate 	case AF_LINK:
13787c478bd9Sstevel@tonic-gate 		link_addr(s, &su->sdl);
13797c478bd9Sstevel@tonic-gate 		return (B_TRUE);
13807c478bd9Sstevel@tonic-gate 	case PF_ROUTE:
13817c478bd9Sstevel@tonic-gate 		sockaddr(s, &su->sa);
13827c478bd9Sstevel@tonic-gate 		return (B_TRUE);
13837c478bd9Sstevel@tonic-gate 	case AF_INET6:
13847c478bd9Sstevel@tonic-gate 		switch (which) {
13857c478bd9Sstevel@tonic-gate 		case RTA_DST:
13867c478bd9Sstevel@tonic-gate 			if (s[0] == '/') {
1387*7a23074eSdduvall 				(void) fprintf(stderr,
1388*7a23074eSdduvall 				    gettext("route: %s: unexpected '/'\n"), s);
1389*7a23074eSdduvall 				exit(1);
13907c478bd9Sstevel@tonic-gate 			}
1391*7a23074eSdduvall 			ret = in6_getaddr(s, &su->sin6, &masklen, hpp);
1392*7a23074eSdduvall 			switch (masklen) {
13937c478bd9Sstevel@tonic-gate 			case NO_PREFIX:
13947c478bd9Sstevel@tonic-gate 				/* Nothing there - ok */
1395*7a23074eSdduvall 				return (ret);
13967c478bd9Sstevel@tonic-gate 			case BAD_ADDR:
1397*7a23074eSdduvall 				(void) fprintf(stderr,
1398*7a23074eSdduvall 				    gettext("route: bad prefix length in %s\n"),
1399*7a23074eSdduvall 					s);
1400*7a23074eSdduvall 				exit(1);
1401*7a23074eSdduvall 				/* NOTREACHED */
14027c478bd9Sstevel@tonic-gate 			default:
1403*7a23074eSdduvall 				(void) memset(&so_mask.sin6.sin6_addr, 0,
1404*7a23074eSdduvall 				    sizeof (so_mask.sin6.sin6_addr));
1405*7a23074eSdduvall 				if (!in_prefixlentomask(masklen, IPV6_ABITS,
1406*7a23074eSdduvall 				    (uchar_t *)&so_mask.sin6.sin6_addr)) {
1407*7a23074eSdduvall 					(void) fprintf(stderr,
1408*7a23074eSdduvall 					    gettext("route: bad prefix length: "
1409*7a23074eSdduvall 					    "%d\n"), masklen);
1410*7a23074eSdduvall 					exit(1);
14117c478bd9Sstevel@tonic-gate 				}
14127c478bd9Sstevel@tonic-gate 				break;
14137c478bd9Sstevel@tonic-gate 			}
1414*7a23074eSdduvall 			so_mask.sin6.sin6_family = af;
1415*7a23074eSdduvall 			rtm_addrs |= RTA_NETMASK;
1416*7a23074eSdduvall 			return (ret);
14177c478bd9Sstevel@tonic-gate 		case RTA_GATEWAY:
14187c478bd9Sstevel@tonic-gate 		case RTA_IFA:
14197c478bd9Sstevel@tonic-gate 		case RTA_SRC:
1420*7a23074eSdduvall 			ret = in6_getaddr(s, &su->sin6, NULL, hpp);
1421*7a23074eSdduvall 			return (ret);
14227c478bd9Sstevel@tonic-gate 		case RTA_NETMASK:
1423*7a23074eSdduvall 			(void) fprintf(stderr,
14247c478bd9Sstevel@tonic-gate 			    gettext("route: -netmask not supported for IPv6: "
1425*7a23074eSdduvall 			    "use <prefix>/<prefix-length> instead"));
1426*7a23074eSdduvall 			exit(1);
1427*7a23074eSdduvall 			/* NOTREACHED */
14287c478bd9Sstevel@tonic-gate 		default:
14297c478bd9Sstevel@tonic-gate 			quit(gettext("Internal Error"), EINVAL);
14307c478bd9Sstevel@tonic-gate 			/* NOTREACHED */
14317c478bd9Sstevel@tonic-gate 		}
14327c478bd9Sstevel@tonic-gate 	case AF_INET:
14337c478bd9Sstevel@tonic-gate 		switch (which) {
14347c478bd9Sstevel@tonic-gate 		case RTA_DST:
14357c478bd9Sstevel@tonic-gate 			if (s[0] == '/') {
1436*7a23074eSdduvall 				(void) fprintf(stderr,
1437*7a23074eSdduvall 				    gettext("route: %s: unexpected '/'\n"), s);
1438*7a23074eSdduvall 				exit(1);
14397c478bd9Sstevel@tonic-gate 			}
1440*7a23074eSdduvall 			ret = in_getaddr(s, &su->sin, &masklen, which, hpp);
1441*7a23074eSdduvall 			switch (masklen) {
14427c478bd9Sstevel@tonic-gate 			case NO_PREFIX:
14437c478bd9Sstevel@tonic-gate 				/* Nothing there - ok */
1444*7a23074eSdduvall 				return (ret);
14457c478bd9Sstevel@tonic-gate 			case BAD_ADDR:
1446*7a23074eSdduvall 				(void) fprintf(stderr,
1447*7a23074eSdduvall 				    gettext("route: bad prefix length in %s\n"),
1448*7a23074eSdduvall 					    s);
1449*7a23074eSdduvall 				exit(1);
1450*7a23074eSdduvall 				/* NOTREACHED */
14517c478bd9Sstevel@tonic-gate 			default:
1452*7a23074eSdduvall 				(void) memset(&so_mask.sin.sin_addr, 0,
1453*7a23074eSdduvall 				    sizeof (so_mask.sin.sin_addr));
1454*7a23074eSdduvall 				if (!in_prefixlentomask(masklen, IP_ABITS,
1455*7a23074eSdduvall 				    (uchar_t *)&so_mask.sin.sin_addr)) {
1456*7a23074eSdduvall 					(void) fprintf(stderr,
1457*7a23074eSdduvall 					    gettext("route: bad prefix length: "
1458*7a23074eSdduvall 					    "%d\n"), masklen);
1459*7a23074eSdduvall 					exit(1);
14607c478bd9Sstevel@tonic-gate 				}
14617c478bd9Sstevel@tonic-gate 				break;
14627c478bd9Sstevel@tonic-gate 			}
1463*7a23074eSdduvall 			so_mask.sin.sin_family = af;
1464*7a23074eSdduvall 			rtm_addrs |= RTA_NETMASK;
1465*7a23074eSdduvall 			return (ret);
14667c478bd9Sstevel@tonic-gate 		case RTA_GATEWAY:
14677c478bd9Sstevel@tonic-gate 		case RTA_IFA:
14687c478bd9Sstevel@tonic-gate 		case RTA_NETMASK:
14697c478bd9Sstevel@tonic-gate 		case RTA_SRC:
1470*7a23074eSdduvall 			ret = in_getaddr(s, &su->sin, NULL, which, hpp);
1471*7a23074eSdduvall 			return (ret);
14727c478bd9Sstevel@tonic-gate 		default:
14737c478bd9Sstevel@tonic-gate 			quit(gettext("Internal Error"), EINVAL);
14747c478bd9Sstevel@tonic-gate 			/* NOTREACHED */
14757c478bd9Sstevel@tonic-gate 		}
14767c478bd9Sstevel@tonic-gate 	default:
14777c478bd9Sstevel@tonic-gate 		quit(gettext("Internal Error"), EINVAL);
14787c478bd9Sstevel@tonic-gate 		/* NOTREACHED */
14797c478bd9Sstevel@tonic-gate 	}
1480*7a23074eSdduvall 
14817c478bd9Sstevel@tonic-gate }
14827c478bd9Sstevel@tonic-gate 
14837c478bd9Sstevel@tonic-gate /*
14847c478bd9Sstevel@tonic-gate  * Interpret an argument as an IPv4 network address of some kind,
1485*7a23074eSdduvall  * returning B_TRUE if a host address, B_FALSE if a network address.
14867c478bd9Sstevel@tonic-gate  * Note that this *always* tries host interpretation before network
14877c478bd9Sstevel@tonic-gate  * interpretation.
14887c478bd9Sstevel@tonic-gate  *
14897c478bd9Sstevel@tonic-gate  * If the plenp argument is non-NULL, allow <addr>/<n> syntax and
14907c478bd9Sstevel@tonic-gate  * pass out <n> in *plenp.
14917c478bd9Sstevel@tonic-gate  * If <n> doesn't parse return BAD_ADDR as *plenp.
14927c478bd9Sstevel@tonic-gate  * If no /<n> is present return NO_PREFIX as *plenp.
14937c478bd9Sstevel@tonic-gate  */
14947c478bd9Sstevel@tonic-gate static boolean_t
14957c478bd9Sstevel@tonic-gate in_getaddr(char *s, struct sockaddr_in *sin, int *plenp, int which,
1496*7a23074eSdduvall     struct hostent **hpp)
14977c478bd9Sstevel@tonic-gate {
14987c478bd9Sstevel@tonic-gate 	struct hostent *hp;
14997c478bd9Sstevel@tonic-gate 	struct netent *np;
15007c478bd9Sstevel@tonic-gate 	in_addr_t val;
15017c478bd9Sstevel@tonic-gate 	char str[BUFSIZ];
15027c478bd9Sstevel@tonic-gate 
15037c478bd9Sstevel@tonic-gate 	(void) strncpy(str, s, sizeof (str));
15047c478bd9Sstevel@tonic-gate 
15057c478bd9Sstevel@tonic-gate 	/*
15067c478bd9Sstevel@tonic-gate 	 * Look for '/'<n> is plenp
15077c478bd9Sstevel@tonic-gate 	 */
15087c478bd9Sstevel@tonic-gate 	if (plenp != NULL) {
15097c478bd9Sstevel@tonic-gate 		char *cp;
15107c478bd9Sstevel@tonic-gate 
15117c478bd9Sstevel@tonic-gate 		*plenp = in_getprefixlen(str, IP_ABITS);
15127c478bd9Sstevel@tonic-gate 		if (*plenp == BAD_ADDR)
15137c478bd9Sstevel@tonic-gate 			return (B_FALSE);
15147c478bd9Sstevel@tonic-gate 		cp = strchr(str, '/');
15157c478bd9Sstevel@tonic-gate 		if (cp != NULL)
15167c478bd9Sstevel@tonic-gate 			*cp = '\0';
15177c478bd9Sstevel@tonic-gate 	} else if (strchr(str, '/') != NULL) {
1518*7a23074eSdduvall 		(void) fprintf(stderr, gettext("route: %s: unexpected '/'\n"),
1519*7a23074eSdduvall 			str);
1520*7a23074eSdduvall 		exit(1);
15217c478bd9Sstevel@tonic-gate 	}
15227c478bd9Sstevel@tonic-gate 
15237c478bd9Sstevel@tonic-gate 	(void) memset(sin, 0, sizeof (*sin));
15247c478bd9Sstevel@tonic-gate 	sin->sin_family = AF_INET;
15257c478bd9Sstevel@tonic-gate 
15267c478bd9Sstevel@tonic-gate 	/*
15277c478bd9Sstevel@tonic-gate 	 * Note: only the route destination can be a network, so we treat
15287c478bd9Sstevel@tonic-gate 	 * all other addresses as though "-net" was not specified.
15297c478bd9Sstevel@tonic-gate 	 */
15307c478bd9Sstevel@tonic-gate 	if ((((val = inet_addr(str)) != (in_addr_t)-1) ||
15317c478bd9Sstevel@tonic-gate 	    strcmp(str, "255.255.255.255") == 0) &&
1532*7a23074eSdduvall 	    (which != RTA_DST || !forcenet)) {
15337c478bd9Sstevel@tonic-gate 		sin->sin_addr.s_addr = val;
15347c478bd9Sstevel@tonic-gate 		if (inet_lnaof(sin->sin_addr) != INADDR_ANY ||
1535*7a23074eSdduvall 		    forcehost)
15367c478bd9Sstevel@tonic-gate 			return (B_TRUE);
15377c478bd9Sstevel@tonic-gate 		val = ntohl(val);
15387c478bd9Sstevel@tonic-gate 		if (which == RTA_DST)
1539*7a23074eSdduvall 			inet_makenetandmask(val, sin);
1540*7a23074eSdduvall 		return (B_FALSE);
15417c478bd9Sstevel@tonic-gate 	}
1542*7a23074eSdduvall 	if (!forcehost && (val = inet_network(str)) != (in_addr_t)-1) {
15437c478bd9Sstevel@tonic-gate 		if (which == RTA_DST)
1544*7a23074eSdduvall 			inet_makenetandmask(val, sin);
1545*7a23074eSdduvall 		return (B_FALSE);
15467c478bd9Sstevel@tonic-gate 	}
1547*7a23074eSdduvall 	if ((which != RTA_DST || !forcenet) &&
15487c478bd9Sstevel@tonic-gate 	    (hp = gethostbyname(str)) != NULL) {
15497c478bd9Sstevel@tonic-gate 		*hpp = hp;
15507c478bd9Sstevel@tonic-gate 		(void) memmove(&sin->sin_addr, hp->h_addr,
15517c478bd9Sstevel@tonic-gate 		    hp->h_length);
15527c478bd9Sstevel@tonic-gate 		return (B_TRUE);
15537c478bd9Sstevel@tonic-gate 	}
1554*7a23074eSdduvall 	if (!forcehost && (np = getnetbyname(str)) != NULL &&
15557c478bd9Sstevel@tonic-gate 	    (val = np->n_net) != 0) {
15567c478bd9Sstevel@tonic-gate 		if (which == RTA_DST)
1557*7a23074eSdduvall 			inet_makenetandmask(val, sin);
15583f33f4f7Sjl138328 		return (B_FALSE);
15597c478bd9Sstevel@tonic-gate 	}
1560*7a23074eSdduvall 	(void) fprintf(stderr, gettext("%s: bad value\n"), s);
1561*7a23074eSdduvall 	exit(1);
1562*7a23074eSdduvall 	/* NOTREACHED */
1563*7a23074eSdduvall }
15647c478bd9Sstevel@tonic-gate 
15657c478bd9Sstevel@tonic-gate /*
15667c478bd9Sstevel@tonic-gate  * Interpret an argument as an IPv6 network address of some kind,
1567*7a23074eSdduvall  * returning B_TRUE if a host address, B_FALSE if a network address.
15687c478bd9Sstevel@tonic-gate  *
15697c478bd9Sstevel@tonic-gate  * If the last argument is non-NULL allow a <addr>/<n> syntax and
15707c478bd9Sstevel@tonic-gate  * pass out <n> in *plenp.
15717c478bd9Sstevel@tonic-gate  * If <n> doesn't parse return BAD_ADDR as *plenp.
15727c478bd9Sstevel@tonic-gate  * If no /<n> is present return NO_PREFIX as *plenp.
15737c478bd9Sstevel@tonic-gate  */
15747c478bd9Sstevel@tonic-gate static boolean_t
15757c478bd9Sstevel@tonic-gate in6_getaddr(char *s, struct sockaddr_in6 *sin6, int *plenp,
15767c478bd9Sstevel@tonic-gate     struct hostent **hpp)
15777c478bd9Sstevel@tonic-gate {
15787c478bd9Sstevel@tonic-gate 	struct hostent *hp;
15797c478bd9Sstevel@tonic-gate 	char str[BUFSIZ];
15807c478bd9Sstevel@tonic-gate 	int error_num;
15817c478bd9Sstevel@tonic-gate 
15827c478bd9Sstevel@tonic-gate 	(void) strncpy(str, s, sizeof (str));
15837c478bd9Sstevel@tonic-gate 
15847c478bd9Sstevel@tonic-gate 	/*
15857c478bd9Sstevel@tonic-gate 	 * Look for '/'<n> is plenp
15867c478bd9Sstevel@tonic-gate 	 */
15877c478bd9Sstevel@tonic-gate 	if (plenp != NULL) {
15887c478bd9Sstevel@tonic-gate 		char *cp;
15897c478bd9Sstevel@tonic-gate 
15907c478bd9Sstevel@tonic-gate 		*plenp = in_getprefixlen(str, IPV6_ABITS);
15917c478bd9Sstevel@tonic-gate 		if (*plenp == BAD_ADDR)
15927c478bd9Sstevel@tonic-gate 			return (B_FALSE);
15937c478bd9Sstevel@tonic-gate 		cp = strchr(str, '/');
15947c478bd9Sstevel@tonic-gate 		if (cp != NULL)
15957c478bd9Sstevel@tonic-gate 			*cp = '\0';
15967c478bd9Sstevel@tonic-gate 	} else if (strchr(str, '/') != NULL) {
1597*7a23074eSdduvall 		(void) fprintf(stderr, gettext("route: %s: unexpected '/'\n"),
1598*7a23074eSdduvall 			str);
1599*7a23074eSdduvall 		exit(1);
16007c478bd9Sstevel@tonic-gate 	}
16017c478bd9Sstevel@tonic-gate 
16027c478bd9Sstevel@tonic-gate 	(void) memset(sin6, 0, sizeof (struct sockaddr_in6));
16037c478bd9Sstevel@tonic-gate 	sin6->sin6_family = AF_INET6;
16047c478bd9Sstevel@tonic-gate 
16057c478bd9Sstevel@tonic-gate 	hp = getipnodebyname(str, AF_INET6, 0, &error_num);
16067c478bd9Sstevel@tonic-gate 	if (hp != NULL) {
16077c478bd9Sstevel@tonic-gate 		*hpp = hp;
16087c478bd9Sstevel@tonic-gate 		(void) memmove(&sin6->sin6_addr, hp->h_addr, hp->h_length);
16097c478bd9Sstevel@tonic-gate 		return (B_TRUE);
16107c478bd9Sstevel@tonic-gate 	}
16117c478bd9Sstevel@tonic-gate 	if (error_num == TRY_AGAIN) {
1612*7a23074eSdduvall 		(void) fprintf(stderr, gettext("route: %s: bad address (try "
16133f33f4f7Sjl138328 		    "again later)\n"), s);
1614*7a23074eSdduvall 	} else {
1615*7a23074eSdduvall 		(void) fprintf(stderr, gettext("route: %s: bad address\n"), s);
16163f33f4f7Sjl138328 	}
1617*7a23074eSdduvall 	exit(1);
1618*7a23074eSdduvall 	/* NOTREACHED */
16197c478bd9Sstevel@tonic-gate }
16207c478bd9Sstevel@tonic-gate 
16217c478bd9Sstevel@tonic-gate /*
16227c478bd9Sstevel@tonic-gate  * If "slash" is zero this parses the whole string as
16237c478bd9Sstevel@tonic-gate  * an integer. With "slash" non zero it parses the tail part as an integer.
16247c478bd9Sstevel@tonic-gate  *
16257c478bd9Sstevel@tonic-gate  * If it is not a valid integer this returns BAD_ADDR.
16267c478bd9Sstevel@tonic-gate  * If there is /<n> present this returns NO_PREFIX.
16277c478bd9Sstevel@tonic-gate  */
16287c478bd9Sstevel@tonic-gate int
16297c478bd9Sstevel@tonic-gate in_getprefixlen(char *addr, int max_plen)
16307c478bd9Sstevel@tonic-gate {
16317c478bd9Sstevel@tonic-gate 	int prefixlen;
16327c478bd9Sstevel@tonic-gate 	char *str, *end;
16337c478bd9Sstevel@tonic-gate 
16347c478bd9Sstevel@tonic-gate 	str = strchr(addr, '/');
16357c478bd9Sstevel@tonic-gate 	if (str == NULL)
16367c478bd9Sstevel@tonic-gate 		return (NO_PREFIX);
16377c478bd9Sstevel@tonic-gate 	str++;
16387c478bd9Sstevel@tonic-gate 
16397c478bd9Sstevel@tonic-gate 	prefixlen = strtol(str, &end, 10);
16407c478bd9Sstevel@tonic-gate 	if (prefixlen < 0)
16417c478bd9Sstevel@tonic-gate 		return (BAD_ADDR);
16427c478bd9Sstevel@tonic-gate 	if (str == end)
16437c478bd9Sstevel@tonic-gate 		return (BAD_ADDR);
16447c478bd9Sstevel@tonic-gate 	if (max_plen != 0 && max_plen < prefixlen)
16457c478bd9Sstevel@tonic-gate 		return (BAD_ADDR);
16467c478bd9Sstevel@tonic-gate 	else
16477c478bd9Sstevel@tonic-gate 		return (prefixlen);
16487c478bd9Sstevel@tonic-gate }
16497c478bd9Sstevel@tonic-gate 
16507c478bd9Sstevel@tonic-gate /*
16517c478bd9Sstevel@tonic-gate  * Convert a prefix length to a mask.
16527c478bd9Sstevel@tonic-gate  * Returns B_TRUE if ok. B_FALSE otherwise.
16537c478bd9Sstevel@tonic-gate  * Assumes the mask array is zeroed by the caller.
16547c478bd9Sstevel@tonic-gate  */
16557c478bd9Sstevel@tonic-gate boolean_t
16567c478bd9Sstevel@tonic-gate in_prefixlentomask(int prefixlen, int maxlen, uchar_t *mask)
16577c478bd9Sstevel@tonic-gate {
16587c478bd9Sstevel@tonic-gate 	if (prefixlen < 0 || prefixlen > maxlen)
16597c478bd9Sstevel@tonic-gate 		return (B_FALSE);
16607c478bd9Sstevel@tonic-gate 
16617c478bd9Sstevel@tonic-gate 	while (prefixlen > 0) {
16627c478bd9Sstevel@tonic-gate 		if (prefixlen >= 8) {
16637c478bd9Sstevel@tonic-gate 			*mask++ = 0xFF;
16647c478bd9Sstevel@tonic-gate 			prefixlen -= 8;
16657c478bd9Sstevel@tonic-gate 			continue;
16667c478bd9Sstevel@tonic-gate 		}
16677c478bd9Sstevel@tonic-gate 		*mask |= 1 << (8 - prefixlen);
16687c478bd9Sstevel@tonic-gate 		prefixlen--;
16697c478bd9Sstevel@tonic-gate 	}
16707c478bd9Sstevel@tonic-gate 	return (B_TRUE);
16717c478bd9Sstevel@tonic-gate }
16727c478bd9Sstevel@tonic-gate 
16737c478bd9Sstevel@tonic-gate void
16747c478bd9Sstevel@tonic-gate rtmonitor(int argc, char *argv[])
16757c478bd9Sstevel@tonic-gate {
16767c478bd9Sstevel@tonic-gate 	int n;
16777c478bd9Sstevel@tonic-gate 	intmax_t msg[2048 / sizeof (intmax_t)];
16787c478bd9Sstevel@tonic-gate 
16797c478bd9Sstevel@tonic-gate 	if (tflag)
16807c478bd9Sstevel@tonic-gate 		exit(0);
16817c478bd9Sstevel@tonic-gate 	verbose = B_TRUE;
16827c478bd9Sstevel@tonic-gate 	if (argc > 1) {
16837c478bd9Sstevel@tonic-gate 		argv++;
16847c478bd9Sstevel@tonic-gate 		if (argc == 2 && **argv == '-') {
16857c478bd9Sstevel@tonic-gate 			switch (keyword(*argv + 1)) {
16867c478bd9Sstevel@tonic-gate 			case K_INET:
16877c478bd9Sstevel@tonic-gate 				af = AF_INET;
16887c478bd9Sstevel@tonic-gate 				break;
16897c478bd9Sstevel@tonic-gate 			case K_LINK:
16907c478bd9Sstevel@tonic-gate 				af = AF_LINK;
16917c478bd9Sstevel@tonic-gate 				break;
16927c478bd9Sstevel@tonic-gate 			case K_INET6:
16937c478bd9Sstevel@tonic-gate 				af = AF_INET6;
16947c478bd9Sstevel@tonic-gate 				break;
16957c478bd9Sstevel@tonic-gate 			default:
16967c478bd9Sstevel@tonic-gate 				usage(*argv);
16977c478bd9Sstevel@tonic-gate 				/* NOTREACHED */
16987c478bd9Sstevel@tonic-gate 			}
16997c478bd9Sstevel@tonic-gate 		} else {
17007c478bd9Sstevel@tonic-gate 			usage(*argv);
17017c478bd9Sstevel@tonic-gate 		}
17027c478bd9Sstevel@tonic-gate 		(void) close(s);
17037c478bd9Sstevel@tonic-gate 		s = socket(PF_ROUTE, SOCK_RAW, af);
17047c478bd9Sstevel@tonic-gate 		if (s < 0)
17057c478bd9Sstevel@tonic-gate 			quit("socket", errno);
17067c478bd9Sstevel@tonic-gate 	}
17077c478bd9Sstevel@tonic-gate 	for (;;) {
17087c478bd9Sstevel@tonic-gate 		n = read(s, msg, sizeof (msg));
17097c478bd9Sstevel@tonic-gate 		if (n <= 0)
17107c478bd9Sstevel@tonic-gate 			quit("read", errno);
17117c478bd9Sstevel@tonic-gate 		(void) printf("got message of size %d\n", n);
17127c478bd9Sstevel@tonic-gate 		print_rtmsg((struct rt_msghdr *)msg, n);
17137c478bd9Sstevel@tonic-gate 	}
17147c478bd9Sstevel@tonic-gate }
17157c478bd9Sstevel@tonic-gate 
17167c478bd9Sstevel@tonic-gate int
1717*7a23074eSdduvall rtmsg(int cmd, int flags)
17187c478bd9Sstevel@tonic-gate {
17197c478bd9Sstevel@tonic-gate 	static int seq;
17207c478bd9Sstevel@tonic-gate 	int rlen;
17217c478bd9Sstevel@tonic-gate 	char *cp = m_rtmsg.m_space;
17227c478bd9Sstevel@tonic-gate 	int l;
17237c478bd9Sstevel@tonic-gate 
17247c478bd9Sstevel@tonic-gate 	errno = 0;
17257c478bd9Sstevel@tonic-gate 	(void) memset(&m_rtmsg, 0, sizeof (m_rtmsg));
1726*7a23074eSdduvall 	if (cmd == 'a') {
1727*7a23074eSdduvall 		cmd = RTM_ADD;
1728*7a23074eSdduvall 	} else if (cmd == 'c') {
1729*7a23074eSdduvall 		cmd = RTM_CHANGE;
1730*7a23074eSdduvall 	} else if (cmd == 'g') {
1731*7a23074eSdduvall 		cmd = RTM_GET;
1732*7a23074eSdduvall 		if (so_ifp.sa.sa_family == 0) {
1733*7a23074eSdduvall 			so_ifp.sa.sa_family = AF_LINK;
1734*7a23074eSdduvall 			rtm_addrs |= RTA_IFP;
17357c478bd9Sstevel@tonic-gate 		}
1736*7a23074eSdduvall 	} else {
1737*7a23074eSdduvall 		cmd = RTM_DELETE;
1738*7a23074eSdduvall 	}
17397c478bd9Sstevel@tonic-gate #define	rtm m_rtmsg.m_rtm
1740*7a23074eSdduvall 	rtm.rtm_type = cmd;
1741*7a23074eSdduvall 	rtm.rtm_flags = flags;
17427c478bd9Sstevel@tonic-gate 	rtm.rtm_version = RTM_VERSION;
17437c478bd9Sstevel@tonic-gate 	rtm.rtm_seq = ++seq;
1744*7a23074eSdduvall 	rtm.rtm_addrs = rtm_addrs;
1745*7a23074eSdduvall 	rtm.rtm_rmx = rt_metrics;
1746*7a23074eSdduvall 	rtm.rtm_inits = rtm_inits;
17477c478bd9Sstevel@tonic-gate 
17487c478bd9Sstevel@tonic-gate #define	NEXTADDR(w, u) \
1749*7a23074eSdduvall 	if (rtm_addrs & (w)) { \
17507c478bd9Sstevel@tonic-gate 		l = ROUNDUP_LONG(salen(&u.sa)); \
17517c478bd9Sstevel@tonic-gate 		(void) memmove(cp, &(u), l); \
17527c478bd9Sstevel@tonic-gate 		cp += l; \
17537c478bd9Sstevel@tonic-gate 		if (verbose) \
17547c478bd9Sstevel@tonic-gate 			sodump(&(u), #u); \
17557c478bd9Sstevel@tonic-gate 	}
1756*7a23074eSdduvall 	NEXTADDR(RTA_DST, so_dst);
1757*7a23074eSdduvall 	NEXTADDR(RTA_GATEWAY, so_gate);
1758*7a23074eSdduvall 	NEXTADDR(RTA_NETMASK, so_mask);
1759*7a23074eSdduvall 	NEXTADDR(RTA_IFP, so_ifp);
1760*7a23074eSdduvall 	NEXTADDR(RTA_IFA, so_ifa);
17617c478bd9Sstevel@tonic-gate 	/*
17627c478bd9Sstevel@tonic-gate 	 * RTA_SRC has overloaded meaning. It can represent the
17637c478bd9Sstevel@tonic-gate 	 * src address of incoming or outgoing packets.
17647c478bd9Sstevel@tonic-gate 	 */
1765*7a23074eSdduvall 	NEXTADDR(RTA_SRC, so_src);
17667c478bd9Sstevel@tonic-gate #undef	NEXTADDR
17677c478bd9Sstevel@tonic-gate 	rtm.rtm_msglen = l = cp - (char *)&m_rtmsg;
17687c478bd9Sstevel@tonic-gate 	if (verbose)
17697c478bd9Sstevel@tonic-gate 		print_rtmsg(&rtm, l);
17707c478bd9Sstevel@tonic-gate 	if (debugonly)
17717c478bd9Sstevel@tonic-gate 		return (0);
17727c478bd9Sstevel@tonic-gate 	if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) {
17737c478bd9Sstevel@tonic-gate 		switch (errno) {
17747c478bd9Sstevel@tonic-gate 		case ESRCH:
17757c478bd9Sstevel@tonic-gate 		case EBUSY:
17767c478bd9Sstevel@tonic-gate 		case ENOBUFS:
17777c478bd9Sstevel@tonic-gate 		case EEXIST:
17787c478bd9Sstevel@tonic-gate 		case ENETUNREACH:
17797c478bd9Sstevel@tonic-gate 		case EHOSTUNREACH:
17807c478bd9Sstevel@tonic-gate 		case EPERM:
17817c478bd9Sstevel@tonic-gate 			break;
17827c478bd9Sstevel@tonic-gate 		default:
17837c478bd9Sstevel@tonic-gate 			perror(gettext("writing to routing socket"));
17847c478bd9Sstevel@tonic-gate 			break;
17857c478bd9Sstevel@tonic-gate 		}
17867c478bd9Sstevel@tonic-gate 		return (-1);
17877c478bd9Sstevel@tonic-gate 	} else if (rlen < (int)rtm.rtm_msglen) {
17887c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
17897c478bd9Sstevel@tonic-gate 		    gettext("route: write to routing socket got only %d for "
17907c478bd9Sstevel@tonic-gate 		    "len\n"), rlen);
17917c478bd9Sstevel@tonic-gate 		return (-1);
17927c478bd9Sstevel@tonic-gate 	}
1793*7a23074eSdduvall 	if (cmd == RTM_GET) {
17947c478bd9Sstevel@tonic-gate 		do {
17957c478bd9Sstevel@tonic-gate 			l = read(s, (char *)&m_rtmsg, sizeof (m_rtmsg));
17967c478bd9Sstevel@tonic-gate 		} while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid));
17977c478bd9Sstevel@tonic-gate 		if (l < 0) {
17987c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
17997c478bd9Sstevel@tonic-gate 			    gettext("route: read from routing socket: %s\n"),
18007c478bd9Sstevel@tonic-gate 			    strerror(errno));
18017c478bd9Sstevel@tonic-gate 		} else {
1802*7a23074eSdduvall 			print_getmsg(&rtm, l);
18037c478bd9Sstevel@tonic-gate 		}
18047c478bd9Sstevel@tonic-gate 	}
18057c478bd9Sstevel@tonic-gate #undef rtm
18067c478bd9Sstevel@tonic-gate 	return (0);
18077c478bd9Sstevel@tonic-gate }
18087c478bd9Sstevel@tonic-gate 
18097c478bd9Sstevel@tonic-gate static char *msgtypes[] = {
18107c478bd9Sstevel@tonic-gate 	"",
18117c478bd9Sstevel@tonic-gate 	"RTM_ADD: Add Route",
18127c478bd9Sstevel@tonic-gate 	"RTM_DELETE: Delete Route",
18137c478bd9Sstevel@tonic-gate 	"RTM_CHANGE: Change Metrics or flags",
18147c478bd9Sstevel@tonic-gate 	"RTM_GET: Report Metrics",
18157c478bd9Sstevel@tonic-gate 	"RTM_LOSING: Kernel Suspects Partitioning",
18167c478bd9Sstevel@tonic-gate 	"RTM_REDIRECT: Told to use different route",
18177c478bd9Sstevel@tonic-gate 	"RTM_MISS: Lookup failed on this address",
18187c478bd9Sstevel@tonic-gate 	"RTM_LOCK: fix specified metrics",
18197c478bd9Sstevel@tonic-gate 	"RTM_OLDADD: caused by SIOCADDRT",
18207c478bd9Sstevel@tonic-gate 	"RTM_OLDDEL: caused by SIOCDELRT",
18217c478bd9Sstevel@tonic-gate 	"RTM_RESOLVE: Route created by cloning",
18227c478bd9Sstevel@tonic-gate 	"RTM_NEWADDR: address being added to iface",
18237c478bd9Sstevel@tonic-gate 	"RTM_DELADDR: address being removed from iface",
18247c478bd9Sstevel@tonic-gate 	"RTM_IFINFO: iface status change",
18257c478bd9Sstevel@tonic-gate 	0,
18267c478bd9Sstevel@tonic-gate };
18277c478bd9Sstevel@tonic-gate 
18287c478bd9Sstevel@tonic-gate #define	NMSGTYPES (sizeof (msgtypes) / sizeof (msgtypes[0]))
18297c478bd9Sstevel@tonic-gate 
18307c478bd9Sstevel@tonic-gate static char metricnames[] =
18317c478bd9Sstevel@tonic-gate "\011pksent\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire\2hopcount"
18327c478bd9Sstevel@tonic-gate 	"\1mtu";
18337c478bd9Sstevel@tonic-gate static char routeflags[] =
18347c478bd9Sstevel@tonic-gate "\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE\010MASK_PRESENT"
18357c478bd9Sstevel@tonic-gate 	"\011CLONING\012XRESOLVE\013LLINFO\014STATIC\015BLACKHOLE"
18367c478bd9Sstevel@tonic-gate 	"\016PRIVATE\017PROTO2\020PROTO1\021MULTIRT\022SETSRC";
18377c478bd9Sstevel@tonic-gate static char ifnetflags[] =
18387c478bd9Sstevel@tonic-gate "\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6NOTRAILERS\7RUNNING\010NOARP"
18397c478bd9Sstevel@tonic-gate 	"\011PPROMISC\012ALLMULTI\013INTELLIGENT\014MULTICAST"
18407c478bd9Sstevel@tonic-gate 	"\015MULTI_BCAST\016UNNUMBERED\017DHCP\020PRIVATE"
18417c478bd9Sstevel@tonic-gate 	"\021NOXMIT\022NOLOCAL\023DEPRECATED\024ADDRCONF"
18427c478bd9Sstevel@tonic-gate 	"\025ROUTER\026NONUD\027ANYCAST\030NORTEXCH\031IPv4\032IPv6"
18437c478bd9Sstevel@tonic-gate 	"\033MIP\034NOFAILOVER\035FAILED\036STANDBY\037INACTIVE\040OFFLINE"
18447c478bd9Sstevel@tonic-gate 	"\041XRESOLV\042COS\043PREFERRED\044TEMPORARY";
18457c478bd9Sstevel@tonic-gate static char addrnames[] =
18467c478bd9Sstevel@tonic-gate "\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD\011SRC";
18477c478bd9Sstevel@tonic-gate 
18487c478bd9Sstevel@tonic-gate void
18497c478bd9Sstevel@tonic-gate print_rtmsg(struct rt_msghdr *rtm, int msglen)
18507c478bd9Sstevel@tonic-gate {
18517c478bd9Sstevel@tonic-gate 	struct if_msghdr *ifm;
18527c478bd9Sstevel@tonic-gate 	struct ifa_msghdr *ifam;
18537c478bd9Sstevel@tonic-gate 
18547c478bd9Sstevel@tonic-gate 	if (!verbose)
18557c478bd9Sstevel@tonic-gate 		return;
18567c478bd9Sstevel@tonic-gate 	if (rtm->rtm_version != RTM_VERSION) {
18577c478bd9Sstevel@tonic-gate 		(void) printf("routing message version %d not understood\n",
18587c478bd9Sstevel@tonic-gate 		    rtm->rtm_version);
18597c478bd9Sstevel@tonic-gate 		return;
18607c478bd9Sstevel@tonic-gate 	}
18617c478bd9Sstevel@tonic-gate 	if (rtm->rtm_msglen > (ushort_t)msglen) {
18627c478bd9Sstevel@tonic-gate 		(void) printf("message length mismatch, in packet %d, "
18637c478bd9Sstevel@tonic-gate 		    "returned %d\n",
18647c478bd9Sstevel@tonic-gate 		    rtm->rtm_msglen, msglen);
18657c478bd9Sstevel@tonic-gate 	}
18667c478bd9Sstevel@tonic-gate 	/*
18677c478bd9Sstevel@tonic-gate 	 * Since rtm->rtm_type is unsigned, we'll just check the case of zero
18687c478bd9Sstevel@tonic-gate 	 * and the upper-bound of (NMSGTYPES - 1).
18697c478bd9Sstevel@tonic-gate 	 */
18707c478bd9Sstevel@tonic-gate 	if (rtm->rtm_type == 0 || rtm->rtm_type >= (NMSGTYPES - 1)) {
18717c478bd9Sstevel@tonic-gate 		(void) printf("routing message type %d not understood\n",
18727c478bd9Sstevel@tonic-gate 		    rtm->rtm_type);
18737c478bd9Sstevel@tonic-gate 		return;
18747c478bd9Sstevel@tonic-gate 	}
18757c478bd9Sstevel@tonic-gate 	(void) printf("%s: len %d, ", msgtypes[rtm->rtm_type], rtm->rtm_msglen);
18767c478bd9Sstevel@tonic-gate 	switch (rtm->rtm_type) {
18777c478bd9Sstevel@tonic-gate 	case RTM_IFINFO:
18787c478bd9Sstevel@tonic-gate 		ifm = (struct if_msghdr *)rtm;
18797c478bd9Sstevel@tonic-gate 		(void) printf("if# %d, flags:", ifm->ifm_index);
18807c478bd9Sstevel@tonic-gate 		bprintf(stdout, ifm->ifm_flags, ifnetflags);
18817c478bd9Sstevel@tonic-gate 		pmsg_addrs((char *)(ifm + 1), ifm->ifm_addrs);
18827c478bd9Sstevel@tonic-gate 		break;
18837c478bd9Sstevel@tonic-gate 	case RTM_NEWADDR:
18847c478bd9Sstevel@tonic-gate 	case RTM_DELADDR:
18857c478bd9Sstevel@tonic-gate 		ifam = (struct ifa_msghdr *)rtm;
18867c478bd9Sstevel@tonic-gate 		(void) printf("metric %d, flags:", ifam->ifam_metric);
18877c478bd9Sstevel@tonic-gate 		bprintf(stdout, ifam->ifam_flags, routeflags);
18887c478bd9Sstevel@tonic-gate 		pmsg_addrs((char *)(ifam + 1), ifam->ifam_addrs);
18897c478bd9Sstevel@tonic-gate 		break;
18907c478bd9Sstevel@tonic-gate 	default:
18917c478bd9Sstevel@tonic-gate 		(void) printf("pid: %ld, seq %d, errno %d, flags:",
18927c478bd9Sstevel@tonic-gate 			rtm->rtm_pid, rtm->rtm_seq, rtm->rtm_errno);
18937c478bd9Sstevel@tonic-gate 		bprintf(stdout, rtm->rtm_flags, routeflags);
18947c478bd9Sstevel@tonic-gate 		pmsg_common(rtm);
18957c478bd9Sstevel@tonic-gate 	}
18967c478bd9Sstevel@tonic-gate }
18977c478bd9Sstevel@tonic-gate 
18987c478bd9Sstevel@tonic-gate void
1899*7a23074eSdduvall print_getmsg(struct rt_msghdr *rtm, int msglen)
19007c478bd9Sstevel@tonic-gate {
19017c478bd9Sstevel@tonic-gate 	struct sockaddr *dst = NULL, *gate = NULL, *mask = NULL, *src = NULL;
19027c478bd9Sstevel@tonic-gate 	struct sockaddr_dl *ifp = NULL;
19037c478bd9Sstevel@tonic-gate 	struct sockaddr *sa;
19047c478bd9Sstevel@tonic-gate 	char *cp;
19057c478bd9Sstevel@tonic-gate 	int i;
19067c478bd9Sstevel@tonic-gate 
1907*7a23074eSdduvall 	(void) printf("   route to: %s\n", routename(&so_dst.sa));
19087c478bd9Sstevel@tonic-gate 	if (rtm->rtm_version != RTM_VERSION) {
19097c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
19107c478bd9Sstevel@tonic-gate 		    gettext("routing message version %d not understood\n"),
19117c478bd9Sstevel@tonic-gate 		    rtm->rtm_version);
19127c478bd9Sstevel@tonic-gate 		return;
19137c478bd9Sstevel@tonic-gate 	}
19147c478bd9Sstevel@tonic-gate 	if (rtm->rtm_msglen > (ushort_t)msglen) {
19157c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
19167c478bd9Sstevel@tonic-gate 		    gettext("message length mismatch, in packet %d, "
19177c478bd9Sstevel@tonic-gate 			"returned %d\n"), rtm->rtm_msglen, msglen);
19187c478bd9Sstevel@tonic-gate 	}
19197c478bd9Sstevel@tonic-gate 	if (rtm->rtm_errno)  {
19207c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "RTM_GET: %s (errno %d)\n",
19217c478bd9Sstevel@tonic-gate 		    strerror(rtm->rtm_errno), rtm->rtm_errno);
19227c478bd9Sstevel@tonic-gate 		return;
19237c478bd9Sstevel@tonic-gate 	}
19247c478bd9Sstevel@tonic-gate 	cp = ((char *)(rtm + 1));
19257c478bd9Sstevel@tonic-gate 	if (rtm->rtm_addrs != 0) {
19267c478bd9Sstevel@tonic-gate 		for (i = 1; i != 0; i <<= 1) {
19277c478bd9Sstevel@tonic-gate 			if (i & rtm->rtm_addrs) {
19287c478bd9Sstevel@tonic-gate 				/* LINTED */
19297c478bd9Sstevel@tonic-gate 				sa = (struct sockaddr *)cp;
19307c478bd9Sstevel@tonic-gate 				switch (i) {
19317c478bd9Sstevel@tonic-gate 				case RTA_DST:
19327c478bd9Sstevel@tonic-gate 					dst = sa;
19337c478bd9Sstevel@tonic-gate 					break;
19347c478bd9Sstevel@tonic-gate 				case RTA_GATEWAY:
19357c478bd9Sstevel@tonic-gate 					gate = sa;
19367c478bd9Sstevel@tonic-gate 					break;
19377c478bd9Sstevel@tonic-gate 				case RTA_NETMASK:
19387c478bd9Sstevel@tonic-gate 					mask = sa;
19397c478bd9Sstevel@tonic-gate 					break;
19407c478bd9Sstevel@tonic-gate 				case RTA_IFP:
19417c478bd9Sstevel@tonic-gate 					if (sa->sa_family == AF_LINK &&
19427c478bd9Sstevel@tonic-gate 					    ((struct sockaddr_dl *)sa)->
19437c478bd9Sstevel@tonic-gate 						sdl_nlen != 0)
19447c478bd9Sstevel@tonic-gate 						ifp = (struct sockaddr_dl *)sa;
19457c478bd9Sstevel@tonic-gate 					break;
19467c478bd9Sstevel@tonic-gate 				case RTA_SRC:
19477c478bd9Sstevel@tonic-gate 					src = sa;
19487c478bd9Sstevel@tonic-gate 					break;
19497c478bd9Sstevel@tonic-gate 				}
19507c478bd9Sstevel@tonic-gate 				ADVANCE(cp, sa);
19517c478bd9Sstevel@tonic-gate 			}
19527c478bd9Sstevel@tonic-gate 		}
19537c478bd9Sstevel@tonic-gate 	}
19547c478bd9Sstevel@tonic-gate 	if (dst != NULL && mask != NULL)
19557c478bd9Sstevel@tonic-gate 		mask->sa_family = dst->sa_family;	/* XXX */
19567c478bd9Sstevel@tonic-gate 	if (dst != NULL)
19577c478bd9Sstevel@tonic-gate 		(void) printf("destination: %s\n", routename(dst));
19587c478bd9Sstevel@tonic-gate 	if (mask != NULL) {
19597c478bd9Sstevel@tonic-gate 		boolean_t savenflag = nflag;
19607c478bd9Sstevel@tonic-gate 
19617c478bd9Sstevel@tonic-gate 		nflag = B_TRUE;
19627c478bd9Sstevel@tonic-gate 		(void) printf("       mask: %s\n", routename(mask));
19637c478bd9Sstevel@tonic-gate 		nflag = savenflag;
19647c478bd9Sstevel@tonic-gate 	}
19657c478bd9Sstevel@tonic-gate 	if (gate != NULL && rtm->rtm_flags & RTF_GATEWAY)
19667c478bd9Sstevel@tonic-gate 		(void) printf("    gateway: %s\n", routename(gate));
19677c478bd9Sstevel@tonic-gate 	if (src != NULL && rtm->rtm_flags & RTF_SETSRC)
19687c478bd9Sstevel@tonic-gate 		(void) printf("     setsrc: %s\n", routename(src));
19697c478bd9Sstevel@tonic-gate 	if (ifp != NULL) {
19707c478bd9Sstevel@tonic-gate 		if (verbose) {
19717c478bd9Sstevel@tonic-gate 			int i;
19727c478bd9Sstevel@tonic-gate 
19737c478bd9Sstevel@tonic-gate 			(void) printf("  interface: %.*s index %d address ",
19747c478bd9Sstevel@tonic-gate 			    ifp->sdl_nlen, ifp->sdl_data, ifp->sdl_index);
19757c478bd9Sstevel@tonic-gate 			for (i = ifp->sdl_nlen;
19767c478bd9Sstevel@tonic-gate 			    i < ifp->sdl_nlen + ifp->sdl_alen;
19777c478bd9Sstevel@tonic-gate 			    i++) {
19787c478bd9Sstevel@tonic-gate 				(void) printf("%02x ",
19797c478bd9Sstevel@tonic-gate 				    ifp->sdl_data[i] & 0xFF);
19807c478bd9Sstevel@tonic-gate 			}
19817c478bd9Sstevel@tonic-gate 			(void) printf("\n");
19827c478bd9Sstevel@tonic-gate 		} else {
19837c478bd9Sstevel@tonic-gate 			(void) printf("  interface: %.*s\n",
19847c478bd9Sstevel@tonic-gate 			    ifp->sdl_nlen, ifp->sdl_data);
19857c478bd9Sstevel@tonic-gate 		}
19867c478bd9Sstevel@tonic-gate 	}
19877c478bd9Sstevel@tonic-gate 	(void) printf("      flags: ");
19887c478bd9Sstevel@tonic-gate 	bprintf(stdout, rtm->rtm_flags, routeflags);
19897c478bd9Sstevel@tonic-gate 
19907c478bd9Sstevel@tonic-gate #define	lock(f)	((rtm->rtm_rmx.rmx_locks & RTV_ ## f) ? 'L' : ' ')
19917c478bd9Sstevel@tonic-gate #define	msec(u)	(((u) + 500) / 1000)		/* usec to msec */
19927c478bd9Sstevel@tonic-gate 
19937c478bd9Sstevel@tonic-gate 	(void) printf("\n%s\n", " recvpipe  sendpipe  ssthresh    rtt,ms "
19947c478bd9Sstevel@tonic-gate 	    "rttvar,ms  hopcount      mtu     expire");
19957c478bd9Sstevel@tonic-gate 	(void) printf("%8d%c ", rtm->rtm_rmx.rmx_recvpipe, lock(RPIPE));
19967c478bd9Sstevel@tonic-gate 	(void) printf("%8d%c ", rtm->rtm_rmx.rmx_sendpipe, lock(SPIPE));
19977c478bd9Sstevel@tonic-gate 	(void) printf("%8d%c ", rtm->rtm_rmx.rmx_ssthresh, lock(SSTHRESH));
19987c478bd9Sstevel@tonic-gate 	(void) printf("%8d%c ", msec(rtm->rtm_rmx.rmx_rtt), lock(RTT));
19997c478bd9Sstevel@tonic-gate 	(void) printf("%8d%c ", msec(rtm->rtm_rmx.rmx_rttvar), lock(RTTVAR));
20007c478bd9Sstevel@tonic-gate 	(void) printf("%8d%c ", rtm->rtm_rmx.rmx_hopcount, lock(HOPCOUNT));
20017c478bd9Sstevel@tonic-gate 	(void) printf("%8d%c ", rtm->rtm_rmx.rmx_mtu, lock(MTU));
20027c478bd9Sstevel@tonic-gate 	if (rtm->rtm_rmx.rmx_expire)
20037c478bd9Sstevel@tonic-gate 		rtm->rtm_rmx.rmx_expire -= time(0);
20047c478bd9Sstevel@tonic-gate 	(void) printf("%8d%c\n", rtm->rtm_rmx.rmx_expire, lock(EXPIRE));
20057c478bd9Sstevel@tonic-gate #undef lock
20067c478bd9Sstevel@tonic-gate #undef msec
20077c478bd9Sstevel@tonic-gate #define	RTA_IGN	\
20087c478bd9Sstevel@tonic-gate 	(RTA_DST|RTA_GATEWAY|RTA_NETMASK|RTA_IFP|RTA_IFA|RTA_BRD|RTA_SRC)
20097c478bd9Sstevel@tonic-gate 	if (verbose) {
20107c478bd9Sstevel@tonic-gate 		pmsg_common(rtm);
20117c478bd9Sstevel@tonic-gate 	} else if (rtm->rtm_addrs &~ RTA_IGN) {
20127c478bd9Sstevel@tonic-gate 		(void) printf("sockaddrs: ");
20137c478bd9Sstevel@tonic-gate 		bprintf(stdout, rtm->rtm_addrs, addrnames);
20147c478bd9Sstevel@tonic-gate 		(void) putchar('\n');
20157c478bd9Sstevel@tonic-gate 	}
20167c478bd9Sstevel@tonic-gate #undef	RTA_IGN
20177c478bd9Sstevel@tonic-gate }
20187c478bd9Sstevel@tonic-gate 
20197c478bd9Sstevel@tonic-gate void
20207c478bd9Sstevel@tonic-gate pmsg_common(struct rt_msghdr *rtm)
20217c478bd9Sstevel@tonic-gate {
20227c478bd9Sstevel@tonic-gate 	(void) printf("\nlocks: ");
20237c478bd9Sstevel@tonic-gate 	bprintf(stdout, (int)rtm->rtm_rmx.rmx_locks, metricnames);
20247c478bd9Sstevel@tonic-gate 	(void) printf(" inits: ");
20257c478bd9Sstevel@tonic-gate 	bprintf(stdout, (int)rtm->rtm_inits, metricnames);
20267c478bd9Sstevel@tonic-gate 	pmsg_addrs(((char *)(rtm + 1)), rtm->rtm_addrs);
20277c478bd9Sstevel@tonic-gate }
20287c478bd9Sstevel@tonic-gate 
20297c478bd9Sstevel@tonic-gate void
20307c478bd9Sstevel@tonic-gate pmsg_addrs(char *cp, int addrs)
20317c478bd9Sstevel@tonic-gate {
20327c478bd9Sstevel@tonic-gate 	struct sockaddr *sa;
20337c478bd9Sstevel@tonic-gate 	int i;
20347c478bd9Sstevel@tonic-gate 
20357c478bd9Sstevel@tonic-gate 	if (addrs == 0)
20367c478bd9Sstevel@tonic-gate 		return;
20377c478bd9Sstevel@tonic-gate 	(void) printf("\nsockaddrs: ");
20387c478bd9Sstevel@tonic-gate 	bprintf(stdout, addrs, addrnames);
20397c478bd9Sstevel@tonic-gate 	(void) putchar('\n');
20407c478bd9Sstevel@tonic-gate 	for (i = 1; i != 0; i <<= 1) {
20417c478bd9Sstevel@tonic-gate 		if (i & addrs) {
20427c478bd9Sstevel@tonic-gate 			/* LINTED */
20437c478bd9Sstevel@tonic-gate 			sa = (struct sockaddr *)cp;
20447c478bd9Sstevel@tonic-gate 			(void) printf(" %s", routename(sa));
20457c478bd9Sstevel@tonic-gate 			ADVANCE(cp, sa);
20467c478bd9Sstevel@tonic-gate 		}
20477c478bd9Sstevel@tonic-gate 	}
20487c478bd9Sstevel@tonic-gate 	(void) putchar('\n');
20497c478bd9Sstevel@tonic-gate 	(void) fflush(stdout);
20507c478bd9Sstevel@tonic-gate }
20517c478bd9Sstevel@tonic-gate 
20527c478bd9Sstevel@tonic-gate void
20537c478bd9Sstevel@tonic-gate bprintf(FILE *fp, int b, char *s)
20547c478bd9Sstevel@tonic-gate {
20557c478bd9Sstevel@tonic-gate 	int i;
20567c478bd9Sstevel@tonic-gate 	boolean_t gotsome = B_FALSE;
20577c478bd9Sstevel@tonic-gate 
20587c478bd9Sstevel@tonic-gate 	if (b == 0)
20597c478bd9Sstevel@tonic-gate 		return;
20607c478bd9Sstevel@tonic-gate 	while ((i = *s++) != 0) {
20617c478bd9Sstevel@tonic-gate 		if (b & (1 << (i - 1))) {
20627c478bd9Sstevel@tonic-gate 			if (!gotsome)
20637c478bd9Sstevel@tonic-gate 				i = '<';
20647c478bd9Sstevel@tonic-gate 			else
20657c478bd9Sstevel@tonic-gate 				i = ',';
20667c478bd9Sstevel@tonic-gate 			(void) putc(i, fp);
20677c478bd9Sstevel@tonic-gate 			gotsome = B_TRUE;
20687c478bd9Sstevel@tonic-gate 			for (; (i = *s) > ' '; s++)
20697c478bd9Sstevel@tonic-gate 				(void) putc(i, fp);
20707c478bd9Sstevel@tonic-gate 		} else {
20717c478bd9Sstevel@tonic-gate 			while (*s > ' ')
20727c478bd9Sstevel@tonic-gate 				s++;
20737c478bd9Sstevel@tonic-gate 		}
20747c478bd9Sstevel@tonic-gate 	}
20757c478bd9Sstevel@tonic-gate 	if (gotsome)
20767c478bd9Sstevel@tonic-gate 		(void) putc('>', fp);
20777c478bd9Sstevel@tonic-gate }
20787c478bd9Sstevel@tonic-gate 
20797c478bd9Sstevel@tonic-gate int
20807c478bd9Sstevel@tonic-gate keyword(char *cp)
20817c478bd9Sstevel@tonic-gate {
20827c478bd9Sstevel@tonic-gate 	struct keytab *kt = keywords;
20837c478bd9Sstevel@tonic-gate 
20847c478bd9Sstevel@tonic-gate 	while (kt->kt_cp && strcmp(kt->kt_cp, cp))
20857c478bd9Sstevel@tonic-gate 		kt++;
20867c478bd9Sstevel@tonic-gate 	return (kt->kt_i);
20877c478bd9Sstevel@tonic-gate }
20887c478bd9Sstevel@tonic-gate 
20897c478bd9Sstevel@tonic-gate void
2090*7a23074eSdduvall sodump(sup su, char *which)
20917c478bd9Sstevel@tonic-gate {
20927c478bd9Sstevel@tonic-gate 	static char obuf[INET6_ADDRSTRLEN];
20937c478bd9Sstevel@tonic-gate 
20947c478bd9Sstevel@tonic-gate 	switch (su->sa.sa_family) {
20957c478bd9Sstevel@tonic-gate 	case AF_LINK:
20967c478bd9Sstevel@tonic-gate 		(void) printf("%s: link %s; ",
20977c478bd9Sstevel@tonic-gate 		    which, link_ntoa(&su->sdl));
20987c478bd9Sstevel@tonic-gate 		break;
20997c478bd9Sstevel@tonic-gate 	case AF_INET:
21007c478bd9Sstevel@tonic-gate 		(void) printf("%s: inet %s; ",
21017c478bd9Sstevel@tonic-gate 		    which, inet_ntoa(su->sin.sin_addr));
21027c478bd9Sstevel@tonic-gate 		break;
21037c478bd9Sstevel@tonic-gate 	case AF_INET6:
21047c478bd9Sstevel@tonic-gate 		if (inet_ntop(AF_INET6, (void *)&su->sin6.sin6_addr, obuf,
21057c478bd9Sstevel@tonic-gate 		    INET6_ADDRSTRLEN) != NULL) {
21067c478bd9Sstevel@tonic-gate 			(void) printf("%s: inet6 %s; ", which, obuf);
21077c478bd9Sstevel@tonic-gate 			break;
21087c478bd9Sstevel@tonic-gate 		}
21097c478bd9Sstevel@tonic-gate 		/* FALLTHROUGH */
21107c478bd9Sstevel@tonic-gate 	default:
21117c478bd9Sstevel@tonic-gate 		quit(gettext("Internal Error"), EINVAL);
21127c478bd9Sstevel@tonic-gate 		/* NOTREACHED */
21137c478bd9Sstevel@tonic-gate 	}
21147c478bd9Sstevel@tonic-gate 	(void) fflush(stdout);
21157c478bd9Sstevel@tonic-gate }
21167c478bd9Sstevel@tonic-gate 
21177c478bd9Sstevel@tonic-gate /* States */
21187c478bd9Sstevel@tonic-gate #define	VIRGIN	0
21197c478bd9Sstevel@tonic-gate #define	GOTONE	1
21207c478bd9Sstevel@tonic-gate #define	GOTTWO	2
21217c478bd9Sstevel@tonic-gate #define	RESET	3
21227c478bd9Sstevel@tonic-gate /* Inputs */
21237c478bd9Sstevel@tonic-gate #define	DIGIT	(4*0)
21247c478bd9Sstevel@tonic-gate #define	END	(4*1)
21257c478bd9Sstevel@tonic-gate #define	DELIM	(4*2)
21267c478bd9Sstevel@tonic-gate #define	LETTER	(4*3)
21277c478bd9Sstevel@tonic-gate 
21287c478bd9Sstevel@tonic-gate void
21297c478bd9Sstevel@tonic-gate sockaddr(char *addr, struct sockaddr *sa)
21307c478bd9Sstevel@tonic-gate {
21317c478bd9Sstevel@tonic-gate 	char *cp = (char *)sa;
21327c478bd9Sstevel@tonic-gate 	int size = salen(sa);
21337c478bd9Sstevel@tonic-gate 	char *cplim = cp + size;
21347c478bd9Sstevel@tonic-gate 	int byte = 0, state = VIRGIN, new;
21357c478bd9Sstevel@tonic-gate 
21367c478bd9Sstevel@tonic-gate 	(void) memset(cp, 0, size);
21377c478bd9Sstevel@tonic-gate 	cp++;
21387c478bd9Sstevel@tonic-gate 	do {
21397c478bd9Sstevel@tonic-gate 		if ((*addr >= '0') && (*addr <= '9')) {
21407c478bd9Sstevel@tonic-gate 			new = *addr - '0';
21417c478bd9Sstevel@tonic-gate 		} else if ((*addr >= 'a') && (*addr <= 'f')) {
21427c478bd9Sstevel@tonic-gate 			new = *addr - 'a' + 10;
21437c478bd9Sstevel@tonic-gate 		} else if ((*addr >= 'A') && (*addr <= 'F')) {
21447c478bd9Sstevel@tonic-gate 			new = *addr - 'A' + 10;
21457c478bd9Sstevel@tonic-gate 		} else if (*addr == 0) {
21467c478bd9Sstevel@tonic-gate 			state |= END;
21477c478bd9Sstevel@tonic-gate 		} else {
21487c478bd9Sstevel@tonic-gate 			state |= DELIM;
21497c478bd9Sstevel@tonic-gate 		}
21507c478bd9Sstevel@tonic-gate 		addr++;
21517c478bd9Sstevel@tonic-gate 		switch (state /* | INPUT */) {
21527c478bd9Sstevel@tonic-gate 		case GOTTWO | DIGIT:
21537c478bd9Sstevel@tonic-gate 			*cp++ = byte;
21547c478bd9Sstevel@tonic-gate 			/* FALLTHROUGH */
21557c478bd9Sstevel@tonic-gate 		case VIRGIN | DIGIT:
21567c478bd9Sstevel@tonic-gate 			state = GOTONE; byte = new; continue;
21577c478bd9Sstevel@tonic-gate 		case GOTONE | DIGIT:
21587c478bd9Sstevel@tonic-gate 			state = GOTTWO; byte = new + (byte << 4); continue;
21597c478bd9Sstevel@tonic-gate 		default: /* | DELIM */
21607c478bd9Sstevel@tonic-gate 			state = VIRGIN; *cp++ = byte; byte = 0; continue;
21617c478bd9Sstevel@tonic-gate 		case GOTONE | END:
21627c478bd9Sstevel@tonic-gate 		case GOTTWO | END:
21637c478bd9Sstevel@tonic-gate 			*cp++ = byte;
21647c478bd9Sstevel@tonic-gate 			/* FALLTHROUGH */
21657c478bd9Sstevel@tonic-gate 		case VIRGIN | END:
21667c478bd9Sstevel@tonic-gate 			break;
21677c478bd9Sstevel@tonic-gate 		}
21687c478bd9Sstevel@tonic-gate 		break;
21697c478bd9Sstevel@tonic-gate 	} while (cp < cplim);
21707c478bd9Sstevel@tonic-gate }
21717c478bd9Sstevel@tonic-gate 
21727c478bd9Sstevel@tonic-gate int
21737c478bd9Sstevel@tonic-gate salen(struct sockaddr *sa)
21747c478bd9Sstevel@tonic-gate {
21757c478bd9Sstevel@tonic-gate 	switch (sa->sa_family) {
21767c478bd9Sstevel@tonic-gate 	case AF_INET:
21777c478bd9Sstevel@tonic-gate 		return (sizeof (struct sockaddr_in));
21787c478bd9Sstevel@tonic-gate 	case AF_LINK:
21797c478bd9Sstevel@tonic-gate 		return (sizeof (struct sockaddr_dl));
21807c478bd9Sstevel@tonic-gate 	case AF_INET6:
21817c478bd9Sstevel@tonic-gate 		return (sizeof (struct sockaddr_in6));
21827c478bd9Sstevel@tonic-gate 	default:
21837c478bd9Sstevel@tonic-gate 		return (sizeof (struct sockaddr));
21847c478bd9Sstevel@tonic-gate 	}
21857c478bd9Sstevel@tonic-gate }
21867c478bd9Sstevel@tonic-gate 
21877c478bd9Sstevel@tonic-gate void
21887c478bd9Sstevel@tonic-gate link_addr(const char *addr, struct sockaddr_dl *sdl)
21897c478bd9Sstevel@tonic-gate {
21907c478bd9Sstevel@tonic-gate 	char *cp = sdl->sdl_data;
21917c478bd9Sstevel@tonic-gate 	char *cplim = sizeof (struct sockaddr_dl) + (char *)sdl;
21927c478bd9Sstevel@tonic-gate 	int byte = 0, state = VIRGIN, new;
21937c478bd9Sstevel@tonic-gate 
21947c478bd9Sstevel@tonic-gate 	(void) memset(sdl, 0, sizeof (struct sockaddr_dl));
21957c478bd9Sstevel@tonic-gate 	sdl->sdl_family = AF_LINK;
21967c478bd9Sstevel@tonic-gate 	do {
21977c478bd9Sstevel@tonic-gate 		state &= ~LETTER;
21987c478bd9Sstevel@tonic-gate 		if ((*addr >= '0') && (*addr <= '9')) {
21997c478bd9Sstevel@tonic-gate 			new = *addr - '0';
22007c478bd9Sstevel@tonic-gate 		} else if ((*addr >= 'a') && (*addr <= 'f')) {
22017c478bd9Sstevel@tonic-gate 			new = *addr - 'a' + 10;
22027c478bd9Sstevel@tonic-gate 		} else if ((*addr >= 'A') && (*addr <= 'F')) {
22037c478bd9Sstevel@tonic-gate 			new = *addr - 'A' + 10;
22047c478bd9Sstevel@tonic-gate 		} else if (*addr == 0) {
22057c478bd9Sstevel@tonic-gate 			state |= END;
22067c478bd9Sstevel@tonic-gate 		} else if (state == VIRGIN &&
22077c478bd9Sstevel@tonic-gate 		    (((*addr >= 'A') && (*addr <= 'Z')) ||
22087c478bd9Sstevel@tonic-gate 		    ((*addr >= 'a') && (*addr <= 'z')))) {
22097c478bd9Sstevel@tonic-gate 			state |= LETTER;
22107c478bd9Sstevel@tonic-gate 		} else {
22117c478bd9Sstevel@tonic-gate 			state |= DELIM;
22127c478bd9Sstevel@tonic-gate 		}
22137c478bd9Sstevel@tonic-gate 		addr++;
22147c478bd9Sstevel@tonic-gate 		switch (state /* | INPUT */) {
22157c478bd9Sstevel@tonic-gate 		case VIRGIN | DIGIT:
22167c478bd9Sstevel@tonic-gate 		case VIRGIN | LETTER:
22177c478bd9Sstevel@tonic-gate 			*cp++ = addr[-1];
22187c478bd9Sstevel@tonic-gate 			continue;
22197c478bd9Sstevel@tonic-gate 		case VIRGIN | DELIM:
22207c478bd9Sstevel@tonic-gate 			state = RESET;
22217c478bd9Sstevel@tonic-gate 			sdl->sdl_nlen = cp - sdl->sdl_data;
22227c478bd9Sstevel@tonic-gate 			continue;
22237c478bd9Sstevel@tonic-gate 		case GOTTWO | DIGIT:
22247c478bd9Sstevel@tonic-gate 			*cp++ = byte;
22257c478bd9Sstevel@tonic-gate 			/* FALLTHROUGH */
22267c478bd9Sstevel@tonic-gate 		case RESET | DIGIT:
22277c478bd9Sstevel@tonic-gate 			state = GOTONE;
22287c478bd9Sstevel@tonic-gate 			byte = new;
22297c478bd9Sstevel@tonic-gate 			continue;
22307c478bd9Sstevel@tonic-gate 		case GOTONE | DIGIT:
22317c478bd9Sstevel@tonic-gate 			state = GOTTWO;
22327c478bd9Sstevel@tonic-gate 			byte = new + (byte << 4);
22337c478bd9Sstevel@tonic-gate 			continue;
22347c478bd9Sstevel@tonic-gate 		default: /* | DELIM */
22357c478bd9Sstevel@tonic-gate 			state = RESET;
22367c478bd9Sstevel@tonic-gate 			*cp++ = byte;
22377c478bd9Sstevel@tonic-gate 			byte = 0;
22387c478bd9Sstevel@tonic-gate 			continue;
22397c478bd9Sstevel@tonic-gate 		case GOTONE | END:
22407c478bd9Sstevel@tonic-gate 		case GOTTWO | END:
22417c478bd9Sstevel@tonic-gate 			*cp++ = byte;
22427c478bd9Sstevel@tonic-gate 			/* FALLTHROUGH */
22437c478bd9Sstevel@tonic-gate 		case RESET | END:
22447c478bd9Sstevel@tonic-gate 			break;
22457c478bd9Sstevel@tonic-gate 		}
22467c478bd9Sstevel@tonic-gate 		break;
22477c478bd9Sstevel@tonic-gate 	} while (cp < cplim);
22487c478bd9Sstevel@tonic-gate 	sdl->sdl_alen = cp - LLADDR(sdl);
22497c478bd9Sstevel@tonic-gate }
22507c478bd9Sstevel@tonic-gate 
22517c478bd9Sstevel@tonic-gate static char hexlist[] = "0123456789abcdef";
22527c478bd9Sstevel@tonic-gate 
22537c478bd9Sstevel@tonic-gate char *
22547c478bd9Sstevel@tonic-gate link_ntoa(const struct sockaddr_dl *sdl)
22557c478bd9Sstevel@tonic-gate {
22567c478bd9Sstevel@tonic-gate 	static char obuf[64];
22577c478bd9Sstevel@tonic-gate 	char *out = obuf;
22587c478bd9Sstevel@tonic-gate 	int i;
22597c478bd9Sstevel@tonic-gate 	uchar_t *in = (uchar_t *)LLADDR(sdl);
22607c478bd9Sstevel@tonic-gate 	uchar_t *inlim = in + sdl->sdl_alen;
22617c478bd9Sstevel@tonic-gate 	boolean_t firsttime = B_TRUE;
22627c478bd9Sstevel@tonic-gate 
22637c478bd9Sstevel@tonic-gate 	if (sdl->sdl_nlen) {
22647c478bd9Sstevel@tonic-gate 		(void) memcpy(obuf, sdl->sdl_data, sdl->sdl_nlen);
22657c478bd9Sstevel@tonic-gate 		out += sdl->sdl_nlen;
22667c478bd9Sstevel@tonic-gate 		if (sdl->sdl_alen)
22677c478bd9Sstevel@tonic-gate 			*out++ = ':';
22687c478bd9Sstevel@tonic-gate 	}
22697c478bd9Sstevel@tonic-gate 	while (in < inlim) {
22707c478bd9Sstevel@tonic-gate 		if (firsttime)
22717c478bd9Sstevel@tonic-gate 			firsttime = B_FALSE;
22727c478bd9Sstevel@tonic-gate 		else
22737c478bd9Sstevel@tonic-gate 			*out++ = '.';
22747c478bd9Sstevel@tonic-gate 		i = *in++;
22757c478bd9Sstevel@tonic-gate 		if (i > 0xf) {
22767c478bd9Sstevel@tonic-gate 			out[1] = hexlist[i & 0xf];
22777c478bd9Sstevel@tonic-gate 			i >>= 4;
22787c478bd9Sstevel@tonic-gate 			out[0] = hexlist[i];
22797c478bd9Sstevel@tonic-gate 			out += 2;
22807c478bd9Sstevel@tonic-gate 		} else {
22817c478bd9Sstevel@tonic-gate 			*out++ = hexlist[i];
22827c478bd9Sstevel@tonic-gate 		}
22837c478bd9Sstevel@tonic-gate 	}
22847c478bd9Sstevel@tonic-gate 	*out = 0;
22857c478bd9Sstevel@tonic-gate 	return (obuf);
22867c478bd9Sstevel@tonic-gate }
22877c478bd9Sstevel@tonic-gate 
22887c478bd9Sstevel@tonic-gate static mib_item_t *
22897c478bd9Sstevel@tonic-gate mibget(int sd)
22907c478bd9Sstevel@tonic-gate {
22917c478bd9Sstevel@tonic-gate 	intmax_t		buf[512 / sizeof (intmax_t)];
22927c478bd9Sstevel@tonic-gate 	int			flags;
22937c478bd9Sstevel@tonic-gate 	int			i, j, getcode;
22947c478bd9Sstevel@tonic-gate 	struct strbuf		ctlbuf, databuf;
22957c478bd9Sstevel@tonic-gate 	struct T_optmgmt_req	*tor = (struct T_optmgmt_req *)buf;
22967c478bd9Sstevel@tonic-gate 	struct T_optmgmt_ack	*toa = (struct T_optmgmt_ack *)buf;
22977c478bd9Sstevel@tonic-gate 	struct T_error_ack	*tea = (struct T_error_ack *)buf;
22987c478bd9Sstevel@tonic-gate 	struct opthdr		*req;
22997c478bd9Sstevel@tonic-gate 	mib_item_t		*first_item = NULL;
23007c478bd9Sstevel@tonic-gate 	mib_item_t		*last_item  = NULL;
23017c478bd9Sstevel@tonic-gate 	mib_item_t		*temp;
23027c478bd9Sstevel@tonic-gate 
23037c478bd9Sstevel@tonic-gate 	tor->PRIM_type = T_SVR4_OPTMGMT_REQ;
23047c478bd9Sstevel@tonic-gate 	tor->OPT_offset = sizeof (struct T_optmgmt_req);
23057c478bd9Sstevel@tonic-gate 	tor->OPT_length = sizeof (struct opthdr);
23067c478bd9Sstevel@tonic-gate 	tor->MGMT_flags = T_CURRENT;
23077c478bd9Sstevel@tonic-gate 	req = (struct opthdr *)&tor[1];
23087c478bd9Sstevel@tonic-gate 	req->level = MIB2_IP;		/* any MIB2_xxx value ok here */
23097c478bd9Sstevel@tonic-gate 	req->name  = 0;
23107c478bd9Sstevel@tonic-gate 	req->len   = 0;
23117c478bd9Sstevel@tonic-gate 
23127c478bd9Sstevel@tonic-gate 	ctlbuf.buf = (char *)buf;
23137c478bd9Sstevel@tonic-gate 	ctlbuf.len = tor->OPT_length + tor->OPT_offset;
23147c478bd9Sstevel@tonic-gate 	flags = 0;
23157c478bd9Sstevel@tonic-gate 	if (putmsg(sd, &ctlbuf, NULL, flags) < 0) {
23167c478bd9Sstevel@tonic-gate 		perror("mibget: putmsg (ctl)");
23177c478bd9Sstevel@tonic-gate 		return (NULL);
23187c478bd9Sstevel@tonic-gate 	}
23197c478bd9Sstevel@tonic-gate 	/*
23207c478bd9Sstevel@tonic-gate 	 * each reply consists of a ctl part for one fixed structure
23217c478bd9Sstevel@tonic-gate 	 * or table, as defined in mib2.h.  The format is a T_OPTMGMT_ACK,
23227c478bd9Sstevel@tonic-gate 	 * containing an opthdr structure.  level/name identify the entry,
23237c478bd9Sstevel@tonic-gate 	 * len is the size of the data part of the message.
23247c478bd9Sstevel@tonic-gate 	 */
23257c478bd9Sstevel@tonic-gate 	req = (struct opthdr *)&toa[1];
23267c478bd9Sstevel@tonic-gate 	ctlbuf.maxlen = sizeof (buf);
23277c478bd9Sstevel@tonic-gate 	for (j = 1; ; j++) {
23287c478bd9Sstevel@tonic-gate 		flags = 0;
23297c478bd9Sstevel@tonic-gate 		getcode = getmsg(sd, &ctlbuf, NULL, &flags);
23307c478bd9Sstevel@tonic-gate 		if (getcode < 0) {
23317c478bd9Sstevel@tonic-gate 			perror("mibget: getmsg (ctl)");
23327c478bd9Sstevel@tonic-gate 			if (verbose) {
23337c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
23347c478bd9Sstevel@tonic-gate 				    "#   level   name    len\n");
23357c478bd9Sstevel@tonic-gate 				i = 0;
23367c478bd9Sstevel@tonic-gate 				for (last_item = first_item; last_item != NULL;
23377c478bd9Sstevel@tonic-gate 				    last_item = last_item->next_item) {
23387c478bd9Sstevel@tonic-gate 					(void) printf("%d  %4ld   %5ld   %ld\n",
23397c478bd9Sstevel@tonic-gate 					    ++i, last_item->group,
23407c478bd9Sstevel@tonic-gate 					    last_item->mib_id,
23417c478bd9Sstevel@tonic-gate 					    last_item->length);
23427c478bd9Sstevel@tonic-gate 				}
23437c478bd9Sstevel@tonic-gate 			}
23447c478bd9Sstevel@tonic-gate 			break;
23457c478bd9Sstevel@tonic-gate 		}
23467c478bd9Sstevel@tonic-gate 		if (getcode == 0 &&
23477c478bd9Sstevel@tonic-gate 		    ctlbuf.len >= sizeof (struct T_optmgmt_ack) &&
23487c478bd9Sstevel@tonic-gate 		    toa->PRIM_type == T_OPTMGMT_ACK &&
23497c478bd9Sstevel@tonic-gate 		    toa->MGMT_flags == T_SUCCESS &&
23507c478bd9Sstevel@tonic-gate 		    req->len == 0) {
23517c478bd9Sstevel@tonic-gate 			if (verbose) {
23527c478bd9Sstevel@tonic-gate 				(void) printf("mibget getmsg() %d returned EOD "
23537c478bd9Sstevel@tonic-gate 				    "(level %lu, name %lu)\n", j, req->level,
23547c478bd9Sstevel@tonic-gate 				    req->name);
23557c478bd9Sstevel@tonic-gate 			}
23567c478bd9Sstevel@tonic-gate 			return (first_item);		/* this is EOD msg */
23577c478bd9Sstevel@tonic-gate 		}
23587c478bd9Sstevel@tonic-gate 
23597c478bd9Sstevel@tonic-gate 		if (ctlbuf.len >= sizeof (struct T_error_ack) &&
23607c478bd9Sstevel@tonic-gate 		    tea->PRIM_type == T_ERROR_ACK) {
23617c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("mibget %d gives "
23627c478bd9Sstevel@tonic-gate 			    "T_ERROR_ACK: TLI_error = 0x%lx, UNIX_error = "
23637c478bd9Sstevel@tonic-gate 			    "0x%lx\n"), j, tea->TLI_error, tea->UNIX_error);
23647c478bd9Sstevel@tonic-gate 			errno = (tea->TLI_error == TSYSERR)
23657c478bd9Sstevel@tonic-gate 				? tea->UNIX_error : EPROTO;
23667c478bd9Sstevel@tonic-gate 			break;
23677c478bd9Sstevel@tonic-gate 		}
23687c478bd9Sstevel@tonic-gate 
23697c478bd9Sstevel@tonic-gate 		if (getcode != MOREDATA ||
23707c478bd9Sstevel@tonic-gate 		    ctlbuf.len < sizeof (struct T_optmgmt_ack) ||
23717c478bd9Sstevel@tonic-gate 		    toa->PRIM_type != T_OPTMGMT_ACK ||
23727c478bd9Sstevel@tonic-gate 		    toa->MGMT_flags != T_SUCCESS) {
23737c478bd9Sstevel@tonic-gate 			(void) printf("mibget getmsg(ctl) %d returned %d, "
23747c478bd9Sstevel@tonic-gate 			    "ctlbuf.len = %d, PRIM_type = %ld\n",
23757c478bd9Sstevel@tonic-gate 			    j, getcode, ctlbuf.len, toa->PRIM_type);
23767c478bd9Sstevel@tonic-gate 			if (toa->PRIM_type == T_OPTMGMT_ACK) {
23777c478bd9Sstevel@tonic-gate 				(void) printf("T_OPTMGMT_ACK: "
23787c478bd9Sstevel@tonic-gate 				    "MGMT_flags = 0x%lx, req->len = %ld\n",
23797c478bd9Sstevel@tonic-gate 				    toa->MGMT_flags, req->len);
23807c478bd9Sstevel@tonic-gate 			}
23817c478bd9Sstevel@tonic-gate 			errno = ENOMSG;
23827c478bd9Sstevel@tonic-gate 			break;
23837c478bd9Sstevel@tonic-gate 		}
23847c478bd9Sstevel@tonic-gate 
23857c478bd9Sstevel@tonic-gate 		temp = malloc(sizeof (mib_item_t));
23867c478bd9Sstevel@tonic-gate 		if (temp == NULL) {
23877c478bd9Sstevel@tonic-gate 			perror("mibget: malloc");
23887c478bd9Sstevel@tonic-gate 			break;
23897c478bd9Sstevel@tonic-gate 		}
23907c478bd9Sstevel@tonic-gate 		if (last_item != NULL)
23917c478bd9Sstevel@tonic-gate 			last_item->next_item = temp;
23927c478bd9Sstevel@tonic-gate 		else
23937c478bd9Sstevel@tonic-gate 			first_item = temp;
23947c478bd9Sstevel@tonic-gate 		last_item = temp;
23957c478bd9Sstevel@tonic-gate 		last_item->next_item = NULL;
23967c478bd9Sstevel@tonic-gate 		last_item->group = req->level;
23977c478bd9Sstevel@tonic-gate 		last_item->mib_id = req->name;
23987c478bd9Sstevel@tonic-gate 		last_item->length = req->len;
23997c478bd9Sstevel@tonic-gate 		last_item->valp = malloc(req->len);
24007c478bd9Sstevel@tonic-gate 		if (verbose) {
24017c478bd9Sstevel@tonic-gate 			(void) printf("msg %d:  group = %4ld   mib_id = %5ld   "
24027c478bd9Sstevel@tonic-gate 			    "length = %ld\n",
24037c478bd9Sstevel@tonic-gate 			    j, last_item->group, last_item->mib_id,
24047c478bd9Sstevel@tonic-gate 			    last_item->length);
24057c478bd9Sstevel@tonic-gate 		}
24067c478bd9Sstevel@tonic-gate 
24077c478bd9Sstevel@tonic-gate 		databuf.maxlen = last_item->length;
24087c478bd9Sstevel@tonic-gate 		databuf.buf    = (char *)last_item->valp;
24097c478bd9Sstevel@tonic-gate 		databuf.len    = 0;
24107c478bd9Sstevel@tonic-gate 		flags = 0;
24117c478bd9Sstevel@tonic-gate 		getcode = getmsg(sd, NULL, &databuf, &flags);
24127c478bd9Sstevel@tonic-gate 		if (getcode < 0) {
24137c478bd9Sstevel@tonic-gate 			perror("mibget: getmsg (data)");
24147c478bd9Sstevel@tonic-gate 			break;
24157c478bd9Sstevel@tonic-gate 		} else if (getcode != 0) {
24167c478bd9Sstevel@tonic-gate 			(void) printf("mibget getmsg(data) returned %d, "
24177c478bd9Sstevel@tonic-gate 			    "databuf.maxlen = %d, databuf.len = %d\n",
24187c478bd9Sstevel@tonic-gate 			    getcode, databuf.maxlen, databuf.len);
24197c478bd9Sstevel@tonic-gate 			break;
24207c478bd9Sstevel@tonic-gate 		}
24217c478bd9Sstevel@tonic-gate 	}
24227c478bd9Sstevel@tonic-gate 
24237c478bd9Sstevel@tonic-gate 	/*
24247c478bd9Sstevel@tonic-gate 	 * On error, free all the allocated mib_item_t objects.
24257c478bd9Sstevel@tonic-gate 	 */
24267c478bd9Sstevel@tonic-gate 	while (first_item != NULL) {
24277c478bd9Sstevel@tonic-gate 		last_item = first_item;
24287c478bd9Sstevel@tonic-gate 		first_item = first_item->next_item;
24297c478bd9Sstevel@tonic-gate 		free(last_item);
24307c478bd9Sstevel@tonic-gate 	}
24317c478bd9Sstevel@tonic-gate 	return (NULL);
24327c478bd9Sstevel@tonic-gate }
2433