xref: /titanic_52/usr/src/cmd/cmd-inet/usr.sbin/route.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
3*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
4*7c478bd9Sstevel@tonic-gate  */
5*7c478bd9Sstevel@tonic-gate 
6*7c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
7*7c478bd9Sstevel@tonic-gate /* All Rights Reserved  	*/
8*7c478bd9Sstevel@tonic-gate 
9*7c478bd9Sstevel@tonic-gate /* Copyright (c) 1990  Mentat Inc. */
10*7c478bd9Sstevel@tonic-gate 
11*7c478bd9Sstevel@tonic-gate /*
12*7c478bd9Sstevel@tonic-gate  *
13*7c478bd9Sstevel@tonic-gate  * Copyright (c) 1983, 1989, 1991, 1993
14*7c478bd9Sstevel@tonic-gate  *	The Regents of the University of California.  All rights reserved.
15*7c478bd9Sstevel@tonic-gate  *
16*7c478bd9Sstevel@tonic-gate  * Redistribution and use in source and binary forms, with or without
17*7c478bd9Sstevel@tonic-gate  * modification, are permitted provided that the following conditions
18*7c478bd9Sstevel@tonic-gate  * are met:
19*7c478bd9Sstevel@tonic-gate  * 1. Redistributions of source code must retain the above copyright
20*7c478bd9Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer.
21*7c478bd9Sstevel@tonic-gate  * 2. Redistributions in binary form must reproduce the above copyright
22*7c478bd9Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer in the
23*7c478bd9Sstevel@tonic-gate  *    documentation and/or other materials provided with the distribution.
24*7c478bd9Sstevel@tonic-gate  * 3. All advertising materials mentioning features or use of this software
25*7c478bd9Sstevel@tonic-gate  *    must display the following acknowledgement:
26*7c478bd9Sstevel@tonic-gate  *	This product includes software developed by the University of
27*7c478bd9Sstevel@tonic-gate  *	California, Berkeley and its contributors.
28*7c478bd9Sstevel@tonic-gate  * 4. Neither the name of the University nor the names of its contributors
29*7c478bd9Sstevel@tonic-gate  *    may be used to endorse or promote products derived from this software
30*7c478bd9Sstevel@tonic-gate  *    without specific prior written permission.
31*7c478bd9Sstevel@tonic-gate  *
32*7c478bd9Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
33*7c478bd9Sstevel@tonic-gate  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
34*7c478bd9Sstevel@tonic-gate  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
35*7c478bd9Sstevel@tonic-gate  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
36*7c478bd9Sstevel@tonic-gate  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37*7c478bd9Sstevel@tonic-gate  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38*7c478bd9Sstevel@tonic-gate  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39*7c478bd9Sstevel@tonic-gate  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
40*7c478bd9Sstevel@tonic-gate  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
41*7c478bd9Sstevel@tonic-gate  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
42*7c478bd9Sstevel@tonic-gate  * SUCH DAMAGE.
43*7c478bd9Sstevel@tonic-gate  *
44*7c478bd9Sstevel@tonic-gate  *	@(#)route.c	8.6 (Berkeley) 4/28/95
45*7c478bd9Sstevel@tonic-gate  *	@(#)linkaddr.c	8.1 (Berkeley) 6/4/93
46*7c478bd9Sstevel@tonic-gate  */
47*7c478bd9Sstevel@tonic-gate 
48*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
49*7c478bd9Sstevel@tonic-gate 
50*7c478bd9Sstevel@tonic-gate #include <sys/param.h>
51*7c478bd9Sstevel@tonic-gate #include <sys/file.h>
52*7c478bd9Sstevel@tonic-gate #include <sys/socket.h>
53*7c478bd9Sstevel@tonic-gate #include <sys/ioctl.h>
54*7c478bd9Sstevel@tonic-gate #include <sys/stream.h>
55*7c478bd9Sstevel@tonic-gate #include <sys/tihdr.h>
56*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
57*7c478bd9Sstevel@tonic-gate 
58*7c478bd9Sstevel@tonic-gate #include <net/if.h>
59*7c478bd9Sstevel@tonic-gate #include <net/route.h>
60*7c478bd9Sstevel@tonic-gate #include <net/if_dl.h>
61*7c478bd9Sstevel@tonic-gate #include <netinet/in.h>
62*7c478bd9Sstevel@tonic-gate #include <arpa/inet.h>
63*7c478bd9Sstevel@tonic-gate #include <netdb.h>
64*7c478bd9Sstevel@tonic-gate #include <inet/mib2.h>
65*7c478bd9Sstevel@tonic-gate #include <inet/ip.h>
66*7c478bd9Sstevel@tonic-gate 
67*7c478bd9Sstevel@tonic-gate #include <locale.h>
68*7c478bd9Sstevel@tonic-gate 
69*7c478bd9Sstevel@tonic-gate #include <errno.h>
70*7c478bd9Sstevel@tonic-gate #include <unistd.h>
71*7c478bd9Sstevel@tonic-gate #include <stdio.h>
72*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
73*7c478bd9Sstevel@tonic-gate #include <string.h>
74*7c478bd9Sstevel@tonic-gate #include <stropts.h>
75*7c478bd9Sstevel@tonic-gate #include <fcntl.h>
76*7c478bd9Sstevel@tonic-gate #include <assert.h>
77*7c478bd9Sstevel@tonic-gate 
78*7c478bd9Sstevel@tonic-gate static struct keytab {
79*7c478bd9Sstevel@tonic-gate 	char	*kt_cp;
80*7c478bd9Sstevel@tonic-gate 	int	kt_i;
81*7c478bd9Sstevel@tonic-gate } keywords[] = {
82*7c478bd9Sstevel@tonic-gate #define	K_ADD		1
83*7c478bd9Sstevel@tonic-gate 	{"add",		K_ADD},
84*7c478bd9Sstevel@tonic-gate #define	K_BLACKHOLE	2
85*7c478bd9Sstevel@tonic-gate 	{"blackhole",	K_BLACKHOLE},
86*7c478bd9Sstevel@tonic-gate #define	K_CHANGE	3
87*7c478bd9Sstevel@tonic-gate 	{"change",	K_CHANGE},
88*7c478bd9Sstevel@tonic-gate #define	K_CLONING	4
89*7c478bd9Sstevel@tonic-gate 	{"cloning",	K_CLONING},
90*7c478bd9Sstevel@tonic-gate #define	K_DELETE	5
91*7c478bd9Sstevel@tonic-gate 	{"delete",	K_DELETE},
92*7c478bd9Sstevel@tonic-gate #define	K_DST		6
93*7c478bd9Sstevel@tonic-gate 	{"dst",		K_DST},
94*7c478bd9Sstevel@tonic-gate #define	K_EXPIRE	7
95*7c478bd9Sstevel@tonic-gate 	{"expire",	K_EXPIRE},
96*7c478bd9Sstevel@tonic-gate #define	K_FLUSH		8
97*7c478bd9Sstevel@tonic-gate 	{"flush",	K_FLUSH},
98*7c478bd9Sstevel@tonic-gate #define	K_GATEWAY	9
99*7c478bd9Sstevel@tonic-gate 	{"gateway",	K_GATEWAY},
100*7c478bd9Sstevel@tonic-gate #define	K_GET		11
101*7c478bd9Sstevel@tonic-gate 	{"get",		K_GET},
102*7c478bd9Sstevel@tonic-gate #define	K_HOPCOUNT	12
103*7c478bd9Sstevel@tonic-gate 	{"hopcount",	K_HOPCOUNT},
104*7c478bd9Sstevel@tonic-gate #define	K_HOST		13
105*7c478bd9Sstevel@tonic-gate 	{"host",	K_HOST},
106*7c478bd9Sstevel@tonic-gate #define	K_IFA		14
107*7c478bd9Sstevel@tonic-gate 	{"ifa",		K_IFA},
108*7c478bd9Sstevel@tonic-gate #define	K_IFACE		15
109*7c478bd9Sstevel@tonic-gate 	{"iface",	K_IFACE},
110*7c478bd9Sstevel@tonic-gate #define	K_IFP		16
111*7c478bd9Sstevel@tonic-gate 	{"ifp",		K_IFP},
112*7c478bd9Sstevel@tonic-gate #define	K_INET		17
113*7c478bd9Sstevel@tonic-gate 	{"inet",	K_INET},
114*7c478bd9Sstevel@tonic-gate #define	K_INET6		18
115*7c478bd9Sstevel@tonic-gate 	{"inet6",	K_INET6},
116*7c478bd9Sstevel@tonic-gate #define	K_INTERFACE	19
117*7c478bd9Sstevel@tonic-gate 	{"interface",	K_INTERFACE},
118*7c478bd9Sstevel@tonic-gate #define	K_LINK		20
119*7c478bd9Sstevel@tonic-gate 	{"link",	K_LINK},
120*7c478bd9Sstevel@tonic-gate #define	K_LOCK		21
121*7c478bd9Sstevel@tonic-gate 	{"lock",	K_LOCK},
122*7c478bd9Sstevel@tonic-gate #define	K_LOCKREST	22
123*7c478bd9Sstevel@tonic-gate 	{"lockrest",	K_LOCKREST},
124*7c478bd9Sstevel@tonic-gate #define	K_MASK		23
125*7c478bd9Sstevel@tonic-gate 	{"mask",	K_MASK},
126*7c478bd9Sstevel@tonic-gate #define	K_MONITOR	24
127*7c478bd9Sstevel@tonic-gate 	{"monitor",	K_MONITOR},
128*7c478bd9Sstevel@tonic-gate #define	K_MTU		25
129*7c478bd9Sstevel@tonic-gate 	{"mtu",		K_MTU},
130*7c478bd9Sstevel@tonic-gate #define	K_NET		26
131*7c478bd9Sstevel@tonic-gate 	{"net",		K_NET},
132*7c478bd9Sstevel@tonic-gate #define	K_NETMASK	27
133*7c478bd9Sstevel@tonic-gate 	{"netmask",	K_NETMASK},
134*7c478bd9Sstevel@tonic-gate #define	K_NOSTATIC	28
135*7c478bd9Sstevel@tonic-gate 	{"nostatic",	K_NOSTATIC},
136*7c478bd9Sstevel@tonic-gate #define	K_PRIVATE	29
137*7c478bd9Sstevel@tonic-gate 	{"private",	K_PRIVATE},
138*7c478bd9Sstevel@tonic-gate #define	K_PROTO1	30
139*7c478bd9Sstevel@tonic-gate 	{"proto1",	K_PROTO1},
140*7c478bd9Sstevel@tonic-gate #define	K_PROTO2	31
141*7c478bd9Sstevel@tonic-gate 	{"proto2",	K_PROTO2},
142*7c478bd9Sstevel@tonic-gate #define	K_RECVPIPE	32
143*7c478bd9Sstevel@tonic-gate 	{"recvpipe",	K_RECVPIPE},
144*7c478bd9Sstevel@tonic-gate #define	K_REJECT	33
145*7c478bd9Sstevel@tonic-gate 	{"reject",	K_REJECT},
146*7c478bd9Sstevel@tonic-gate #define	K_RTT		34
147*7c478bd9Sstevel@tonic-gate 	{"rtt",		K_RTT},
148*7c478bd9Sstevel@tonic-gate #define	K_RTTVAR	35
149*7c478bd9Sstevel@tonic-gate 	{"rttvar",	K_RTTVAR},
150*7c478bd9Sstevel@tonic-gate #define	K_SA		36
151*7c478bd9Sstevel@tonic-gate 	{"sa",		K_SA},
152*7c478bd9Sstevel@tonic-gate #define	K_SENDPIPE	37
153*7c478bd9Sstevel@tonic-gate 	{"sendpipe",	K_SENDPIPE},
154*7c478bd9Sstevel@tonic-gate #define	K_SSTHRESH	38
155*7c478bd9Sstevel@tonic-gate 	{"ssthresh",	K_SSTHRESH},
156*7c478bd9Sstevel@tonic-gate #define	K_STATIC	39
157*7c478bd9Sstevel@tonic-gate 	{"static",	K_STATIC},
158*7c478bd9Sstevel@tonic-gate #define	K_XRESOLVE	40
159*7c478bd9Sstevel@tonic-gate 	{"xresolve",	K_XRESOLVE},
160*7c478bd9Sstevel@tonic-gate #define	K_MULTIRT	41
161*7c478bd9Sstevel@tonic-gate 	{"multirt",	K_MULTIRT},
162*7c478bd9Sstevel@tonic-gate #define	K_SETSRC	42
163*7c478bd9Sstevel@tonic-gate 	{"setsrc",	K_SETSRC},
164*7c478bd9Sstevel@tonic-gate 	{0, 0}
165*7c478bd9Sstevel@tonic-gate };
166*7c478bd9Sstevel@tonic-gate 
167*7c478bd9Sstevel@tonic-gate static union	sockunion {
168*7c478bd9Sstevel@tonic-gate 	struct	sockaddr sa;
169*7c478bd9Sstevel@tonic-gate 	struct	sockaddr_in sin;
170*7c478bd9Sstevel@tonic-gate 	struct	sockaddr_dl sdl;
171*7c478bd9Sstevel@tonic-gate 	struct	sockaddr_in6 sin6;
172*7c478bd9Sstevel@tonic-gate } so_dst, so_gate, so_mask, so_ifa, so_ifp, so_src;
173*7c478bd9Sstevel@tonic-gate 
174*7c478bd9Sstevel@tonic-gate typedef struct	mib_item_s {
175*7c478bd9Sstevel@tonic-gate 	struct mib_item_s	*next_item;
176*7c478bd9Sstevel@tonic-gate 	long			group;
177*7c478bd9Sstevel@tonic-gate 	long			mib_id;
178*7c478bd9Sstevel@tonic-gate 	long			length;
179*7c478bd9Sstevel@tonic-gate 	intmax_t		*valp;
180*7c478bd9Sstevel@tonic-gate } mib_item_t;
181*7c478bd9Sstevel@tonic-gate 
182*7c478bd9Sstevel@tonic-gate typedef union sockunion *sup;
183*7c478bd9Sstevel@tonic-gate 
184*7c478bd9Sstevel@tonic-gate static void		bprintf(FILE *fp, int b, char *s);
185*7c478bd9Sstevel@tonic-gate static void		delRouteEntry(mib2_ipRouteEntry_t *rp,
186*7c478bd9Sstevel@tonic-gate     mib2_ipv6RouteEntry_t *rp6, int seqno);
187*7c478bd9Sstevel@tonic-gate static void		flushroutes(int argc, char *argv[]);
188*7c478bd9Sstevel@tonic-gate static boolean_t	getaddr(int which, char *s, struct hostent **hpp);
189*7c478bd9Sstevel@tonic-gate static boolean_t	in6_getaddr(char *s, struct sockaddr_in6 *sin6,
190*7c478bd9Sstevel@tonic-gate     int *plenp, struct hostent **hpp);
191*7c478bd9Sstevel@tonic-gate static boolean_t	in_getaddr(char *s, struct sockaddr_in *sin,
192*7c478bd9Sstevel@tonic-gate     int *plenp, int which, struct hostent **hpp);
193*7c478bd9Sstevel@tonic-gate static int		in_getprefixlen(char *addr, int max_plen);
194*7c478bd9Sstevel@tonic-gate static boolean_t	in_prefixlentomask(int prefixlen, int maxlen,
195*7c478bd9Sstevel@tonic-gate     uchar_t *mask);
196*7c478bd9Sstevel@tonic-gate static void		inet_makenetandmask(in_addr_t net,
197*7c478bd9Sstevel@tonic-gate     struct sockaddr_in *sin);
198*7c478bd9Sstevel@tonic-gate static in_addr_t	inet_makesubnetmask(in_addr_t addr, in_addr_t mask);
199*7c478bd9Sstevel@tonic-gate static int		keyword(char *cp);
200*7c478bd9Sstevel@tonic-gate static void		link_addr(const char *addr, struct sockaddr_dl *sdl);
201*7c478bd9Sstevel@tonic-gate static char		*link_ntoa(const struct sockaddr_dl *sdl);
202*7c478bd9Sstevel@tonic-gate static mib_item_t	*mibget(int sd);
203*7c478bd9Sstevel@tonic-gate static char		*netname(struct sockaddr *sa);
204*7c478bd9Sstevel@tonic-gate static int		newroute(int argc, char **argv);
205*7c478bd9Sstevel@tonic-gate static void		pmsg_addrs(char *cp, int addrs);
206*7c478bd9Sstevel@tonic-gate static void		pmsg_common(struct rt_msghdr *rtm);
207*7c478bd9Sstevel@tonic-gate static void		print_getmsg(struct rt_msghdr *rtm, int msglen);
208*7c478bd9Sstevel@tonic-gate static void		print_rtmsg(struct rt_msghdr *rtm, int msglen);
209*7c478bd9Sstevel@tonic-gate static void		quit(char *s, int err);
210*7c478bd9Sstevel@tonic-gate static char		*routename(struct sockaddr *sa);
211*7c478bd9Sstevel@tonic-gate static void		rtmonitor(int argc, char *argv[]);
212*7c478bd9Sstevel@tonic-gate static int		rtmsg(int cmd, int flags);
213*7c478bd9Sstevel@tonic-gate static int		salen(struct sockaddr *sa);
214*7c478bd9Sstevel@tonic-gate static void		set_metric(char *value, int key);
215*7c478bd9Sstevel@tonic-gate static void		sockaddr(char *addr, struct sockaddr *sa);
216*7c478bd9Sstevel@tonic-gate static void		sodump(sup su, char *which);
217*7c478bd9Sstevel@tonic-gate static void		usage(char *cp);
218*7c478bd9Sstevel@tonic-gate 
219*7c478bd9Sstevel@tonic-gate static int		pid, rtm_addrs;
220*7c478bd9Sstevel@tonic-gate static int		s;
221*7c478bd9Sstevel@tonic-gate static boolean_t	forcehost, forcenet, nflag;
222*7c478bd9Sstevel@tonic-gate static int		af = AF_INET;
223*7c478bd9Sstevel@tonic-gate static boolean_t	qflag, tflag;
224*7c478bd9Sstevel@tonic-gate static boolean_t	iflag, verbose;
225*7c478bd9Sstevel@tonic-gate static boolean_t	locking, lockrest, debugonly;
226*7c478bd9Sstevel@tonic-gate static boolean_t	fflag;
227*7c478bd9Sstevel@tonic-gate static struct		rt_metrics rt_metrics;
228*7c478bd9Sstevel@tonic-gate static ulong_t		rtm_inits;
229*7c478bd9Sstevel@tonic-gate static int		masklen;
230*7c478bd9Sstevel@tonic-gate 
231*7c478bd9Sstevel@tonic-gate static struct {
232*7c478bd9Sstevel@tonic-gate 	struct	rt_msghdr m_rtm;
233*7c478bd9Sstevel@tonic-gate 	char	m_space[512];
234*7c478bd9Sstevel@tonic-gate } m_rtmsg;
235*7c478bd9Sstevel@tonic-gate 
236*7c478bd9Sstevel@tonic-gate /*
237*7c478bd9Sstevel@tonic-gate  * Sizes of data structures extracted from the base mib.
238*7c478bd9Sstevel@tonic-gate  * This allows the size of the tables entries to grow while preserving
239*7c478bd9Sstevel@tonic-gate  * binary compatibility.
240*7c478bd9Sstevel@tonic-gate  */
241*7c478bd9Sstevel@tonic-gate static int ipRouteEntrySize;
242*7c478bd9Sstevel@tonic-gate static int ipv6RouteEntrySize;
243*7c478bd9Sstevel@tonic-gate 
244*7c478bd9Sstevel@tonic-gate #define	ROUNDUP_LONG(a) \
245*7c478bd9Sstevel@tonic-gate 	((a) > 0 ? (1 + (((a) - 1) | (sizeof (long) - 1))) : sizeof (long))
246*7c478bd9Sstevel@tonic-gate #define	ADVANCE(x, n) ((x) += ROUNDUP_LONG(salen(n)))
247*7c478bd9Sstevel@tonic-gate #define	C(x)	((x) & 0xff)
248*7c478bd9Sstevel@tonic-gate 
249*7c478bd9Sstevel@tonic-gate /*
250*7c478bd9Sstevel@tonic-gate  * return values from in_getprefixlen()
251*7c478bd9Sstevel@tonic-gate  */
252*7c478bd9Sstevel@tonic-gate #define	BAD_ADDR	-1	/* prefix is invalid */
253*7c478bd9Sstevel@tonic-gate #define	NO_PREFIX	-2	/* no prefix was found */
254*7c478bd9Sstevel@tonic-gate 
255*7c478bd9Sstevel@tonic-gate void
256*7c478bd9Sstevel@tonic-gate usage(char *cp)
257*7c478bd9Sstevel@tonic-gate {
258*7c478bd9Sstevel@tonic-gate 	if (cp != NULL)
259*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("route: botched keyword: %s\n"),
260*7c478bd9Sstevel@tonic-gate 		    cp);
261*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,
262*7c478bd9Sstevel@tonic-gate 	    gettext("usage: route [ -fnqv ] cmd [[ -<qualifers> ] args ]\n"));
263*7c478bd9Sstevel@tonic-gate 	exit(1);
264*7c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
265*7c478bd9Sstevel@tonic-gate }
266*7c478bd9Sstevel@tonic-gate 
267*7c478bd9Sstevel@tonic-gate void
268*7c478bd9Sstevel@tonic-gate quit(char *s, int sverrno)
269*7c478bd9Sstevel@tonic-gate {
270*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "route: ");
271*7c478bd9Sstevel@tonic-gate 	if (s != NULL)
272*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "%s: ", s);
273*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "%s\n", strerror(sverrno));
274*7c478bd9Sstevel@tonic-gate 	exit(sverrno);
275*7c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
276*7c478bd9Sstevel@tonic-gate }
277*7c478bd9Sstevel@tonic-gate 
278*7c478bd9Sstevel@tonic-gate int
279*7c478bd9Sstevel@tonic-gate main(int argc, char **argv)
280*7c478bd9Sstevel@tonic-gate {
281*7c478bd9Sstevel@tonic-gate 	extern int optind;
282*7c478bd9Sstevel@tonic-gate 	int ch;
283*7c478bd9Sstevel@tonic-gate 	int key;
284*7c478bd9Sstevel@tonic-gate 
285*7c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
286*7c478bd9Sstevel@tonic-gate 
287*7c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
288*7c478bd9Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"
289*7c478bd9Sstevel@tonic-gate #endif
290*7c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
291*7c478bd9Sstevel@tonic-gate 
292*7c478bd9Sstevel@tonic-gate 	if (argc < 2)
293*7c478bd9Sstevel@tonic-gate 		usage((char *)NULL);
294*7c478bd9Sstevel@tonic-gate 
295*7c478bd9Sstevel@tonic-gate 	while ((ch = getopt(argc, argv, "nqdtvf")) != EOF) {
296*7c478bd9Sstevel@tonic-gate 		switch (ch) {
297*7c478bd9Sstevel@tonic-gate 		case 'n':
298*7c478bd9Sstevel@tonic-gate 			nflag = B_TRUE;
299*7c478bd9Sstevel@tonic-gate 			break;
300*7c478bd9Sstevel@tonic-gate 		case 'q':
301*7c478bd9Sstevel@tonic-gate 			qflag = B_TRUE;
302*7c478bd9Sstevel@tonic-gate 			break;
303*7c478bd9Sstevel@tonic-gate 		case 'v':
304*7c478bd9Sstevel@tonic-gate 			verbose = B_TRUE;
305*7c478bd9Sstevel@tonic-gate 			break;
306*7c478bd9Sstevel@tonic-gate 		case 't':
307*7c478bd9Sstevel@tonic-gate 			tflag = B_TRUE;
308*7c478bd9Sstevel@tonic-gate 			break;
309*7c478bd9Sstevel@tonic-gate 		case 'd':
310*7c478bd9Sstevel@tonic-gate 			debugonly = B_TRUE;
311*7c478bd9Sstevel@tonic-gate 			break;
312*7c478bd9Sstevel@tonic-gate 		case 'f':
313*7c478bd9Sstevel@tonic-gate 			fflag = B_TRUE;
314*7c478bd9Sstevel@tonic-gate 			break;
315*7c478bd9Sstevel@tonic-gate 		case '?':
316*7c478bd9Sstevel@tonic-gate 		default:
317*7c478bd9Sstevel@tonic-gate 			usage((char *)NULL);
318*7c478bd9Sstevel@tonic-gate 			/* NOTREACHED */
319*7c478bd9Sstevel@tonic-gate 		}
320*7c478bd9Sstevel@tonic-gate 	}
321*7c478bd9Sstevel@tonic-gate 	argc -= optind;
322*7c478bd9Sstevel@tonic-gate 	argv += optind;
323*7c478bd9Sstevel@tonic-gate 
324*7c478bd9Sstevel@tonic-gate 	pid = getpid();
325*7c478bd9Sstevel@tonic-gate 	if (tflag)
326*7c478bd9Sstevel@tonic-gate 		s = open("/dev/null", O_WRONLY);
327*7c478bd9Sstevel@tonic-gate 	else
328*7c478bd9Sstevel@tonic-gate 		s = socket(PF_ROUTE, SOCK_RAW, 0);
329*7c478bd9Sstevel@tonic-gate 	if (s < 0)
330*7c478bd9Sstevel@tonic-gate 		quit("socket", errno);
331*7c478bd9Sstevel@tonic-gate 	if (fflag) {
332*7c478bd9Sstevel@tonic-gate 		/*
333*7c478bd9Sstevel@tonic-gate 		 * Accept an address family keyword after the -f.  Since the
334*7c478bd9Sstevel@tonic-gate 		 * default address family is AF_INET, reassign af only for the
335*7c478bd9Sstevel@tonic-gate 		 * other valid address families.
336*7c478bd9Sstevel@tonic-gate 		 */
337*7c478bd9Sstevel@tonic-gate 		if (*argv != NULL) {
338*7c478bd9Sstevel@tonic-gate 			switch (key = keyword(*argv)) {
339*7c478bd9Sstevel@tonic-gate 			case K_INET:
340*7c478bd9Sstevel@tonic-gate 			case K_INET6:
341*7c478bd9Sstevel@tonic-gate 				if (key == K_INET6)
342*7c478bd9Sstevel@tonic-gate 					af = AF_INET6;
343*7c478bd9Sstevel@tonic-gate 				/* Skip over the address family parameter. */
344*7c478bd9Sstevel@tonic-gate 				argc--;
345*7c478bd9Sstevel@tonic-gate 				argv++;
346*7c478bd9Sstevel@tonic-gate 				break;
347*7c478bd9Sstevel@tonic-gate 			}
348*7c478bd9Sstevel@tonic-gate 		}
349*7c478bd9Sstevel@tonic-gate 		flushroutes(0, NULL);
350*7c478bd9Sstevel@tonic-gate 	}
351*7c478bd9Sstevel@tonic-gate 	if (*argv != NULL) {
352*7c478bd9Sstevel@tonic-gate 		switch (keyword(*argv)) {
353*7c478bd9Sstevel@tonic-gate 		case K_GET:
354*7c478bd9Sstevel@tonic-gate 		case K_CHANGE:
355*7c478bd9Sstevel@tonic-gate 		case K_ADD:
356*7c478bd9Sstevel@tonic-gate 		case K_DELETE:
357*7c478bd9Sstevel@tonic-gate 			return (newroute(argc, argv));
358*7c478bd9Sstevel@tonic-gate 
359*7c478bd9Sstevel@tonic-gate 		case K_MONITOR:
360*7c478bd9Sstevel@tonic-gate 			rtmonitor(argc, argv);
361*7c478bd9Sstevel@tonic-gate 			/* NOTREACHED */
362*7c478bd9Sstevel@tonic-gate 
363*7c478bd9Sstevel@tonic-gate 		case K_FLUSH:
364*7c478bd9Sstevel@tonic-gate 			flushroutes(argc, argv);
365*7c478bd9Sstevel@tonic-gate 			exit(0);
366*7c478bd9Sstevel@tonic-gate 			/* NOTREACHED */
367*7c478bd9Sstevel@tonic-gate 		}
368*7c478bd9Sstevel@tonic-gate 	}
369*7c478bd9Sstevel@tonic-gate 	if (!fflag)
370*7c478bd9Sstevel@tonic-gate 		usage(*argv);
371*7c478bd9Sstevel@tonic-gate 	return (0);
372*7c478bd9Sstevel@tonic-gate }
373*7c478bd9Sstevel@tonic-gate 
374*7c478bd9Sstevel@tonic-gate /*
375*7c478bd9Sstevel@tonic-gate  * Purge all entries in the routing tables not
376*7c478bd9Sstevel@tonic-gate  * associated with network interfaces.
377*7c478bd9Sstevel@tonic-gate  */
378*7c478bd9Sstevel@tonic-gate void
379*7c478bd9Sstevel@tonic-gate flushroutes(int argc, char *argv[])
380*7c478bd9Sstevel@tonic-gate {
381*7c478bd9Sstevel@tonic-gate 	int seqno;
382*7c478bd9Sstevel@tonic-gate 	int sd;	/* mib stream */
383*7c478bd9Sstevel@tonic-gate 	mib_item_t	*item;
384*7c478bd9Sstevel@tonic-gate 	mib2_ipRouteEntry_t *rp;
385*7c478bd9Sstevel@tonic-gate 	mib2_ipv6RouteEntry_t *rp6;
386*7c478bd9Sstevel@tonic-gate 	int oerrno;
387*7c478bd9Sstevel@tonic-gate 	int off = 0;
388*7c478bd9Sstevel@tonic-gate 	int on = 1;
389*7c478bd9Sstevel@tonic-gate 
390*7c478bd9Sstevel@tonic-gate 	if (setsockopt(s, SOL_SOCKET, SO_USELOOPBACK, (char *)&off,
391*7c478bd9Sstevel@tonic-gate 	    sizeof (off)) < 0)
392*7c478bd9Sstevel@tonic-gate 		quit("setsockopt", errno);
393*7c478bd9Sstevel@tonic-gate 	if (argc > 1) {
394*7c478bd9Sstevel@tonic-gate 		argv++;
395*7c478bd9Sstevel@tonic-gate 		if (argc == 2 && **argv == '-') {
396*7c478bd9Sstevel@tonic-gate 			/*
397*7c478bd9Sstevel@tonic-gate 			 * The address family (preceded by a dash) may be used
398*7c478bd9Sstevel@tonic-gate 			 * to flush the routes of that particular family.
399*7c478bd9Sstevel@tonic-gate 			 */
400*7c478bd9Sstevel@tonic-gate 			switch (keyword(*argv + 1)) {
401*7c478bd9Sstevel@tonic-gate 			case K_INET:
402*7c478bd9Sstevel@tonic-gate 				af = AF_INET;
403*7c478bd9Sstevel@tonic-gate 				break;
404*7c478bd9Sstevel@tonic-gate 			case K_LINK:
405*7c478bd9Sstevel@tonic-gate 				af = AF_LINK;
406*7c478bd9Sstevel@tonic-gate 				break;
407*7c478bd9Sstevel@tonic-gate 			case K_INET6:
408*7c478bd9Sstevel@tonic-gate 				af = AF_INET6;
409*7c478bd9Sstevel@tonic-gate 				break;
410*7c478bd9Sstevel@tonic-gate 			default:
411*7c478bd9Sstevel@tonic-gate 				usage(*argv);
412*7c478bd9Sstevel@tonic-gate 				/* NOTREACHED */
413*7c478bd9Sstevel@tonic-gate 			}
414*7c478bd9Sstevel@tonic-gate 		} else {
415*7c478bd9Sstevel@tonic-gate 			usage(*argv);
416*7c478bd9Sstevel@tonic-gate 		}
417*7c478bd9Sstevel@tonic-gate 	}
418*7c478bd9Sstevel@tonic-gate 	sd = open("/dev/ip", O_RDWR);
419*7c478bd9Sstevel@tonic-gate 	oerrno = errno;
420*7c478bd9Sstevel@tonic-gate 	if (sd < 0) {
421*7c478bd9Sstevel@tonic-gate 		switch (errno) {
422*7c478bd9Sstevel@tonic-gate 		case EACCES:
423*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
424*7c478bd9Sstevel@tonic-gate 			    gettext("route: flush: insufficient privileges\n"));
425*7c478bd9Sstevel@tonic-gate 			exit(oerrno);
426*7c478bd9Sstevel@tonic-gate 			/* NOTREACHED */
427*7c478bd9Sstevel@tonic-gate 		default:
428*7c478bd9Sstevel@tonic-gate 			quit(gettext("can't open mib stream"), oerrno);
429*7c478bd9Sstevel@tonic-gate 			/* NOTREACHED */
430*7c478bd9Sstevel@tonic-gate 		}
431*7c478bd9Sstevel@tonic-gate 	}
432*7c478bd9Sstevel@tonic-gate 	if ((item = mibget(sd)) == NULL)
433*7c478bd9Sstevel@tonic-gate 		quit("mibget", errno);
434*7c478bd9Sstevel@tonic-gate 	if (verbose) {
435*7c478bd9Sstevel@tonic-gate 		(void) printf("Examining routing table from "
436*7c478bd9Sstevel@tonic-gate 		    "T_SVR4_OPTMGMT_REQ\n");
437*7c478bd9Sstevel@tonic-gate 	}
438*7c478bd9Sstevel@tonic-gate 	seqno = 0;		/* ??? */
439*7c478bd9Sstevel@tonic-gate 	switch (af) {
440*7c478bd9Sstevel@tonic-gate 	case AF_INET:
441*7c478bd9Sstevel@tonic-gate 		/* Extract ipRouteEntrySize */
442*7c478bd9Sstevel@tonic-gate 		for (; item != NULL; item = item->next_item) {
443*7c478bd9Sstevel@tonic-gate 			if (item->mib_id != 0)
444*7c478bd9Sstevel@tonic-gate 				continue;
445*7c478bd9Sstevel@tonic-gate 			if (item->group == MIB2_IP) {
446*7c478bd9Sstevel@tonic-gate 				ipRouteEntrySize =
447*7c478bd9Sstevel@tonic-gate 				    ((mib2_ip_t *)item->valp)->ipRouteEntrySize;
448*7c478bd9Sstevel@tonic-gate 				assert(IS_P2ALIGNED(ipRouteEntrySize,
449*7c478bd9Sstevel@tonic-gate 				    sizeof (mib2_ipRouteEntry_t *)));
450*7c478bd9Sstevel@tonic-gate 				break;
451*7c478bd9Sstevel@tonic-gate 			}
452*7c478bd9Sstevel@tonic-gate 		}
453*7c478bd9Sstevel@tonic-gate 		if (ipRouteEntrySize == 0) {
454*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
455*7c478bd9Sstevel@tonic-gate 			    gettext("ipRouteEntrySize can't be determined.\n"));
456*7c478bd9Sstevel@tonic-gate 			exit(1);
457*7c478bd9Sstevel@tonic-gate 		}
458*7c478bd9Sstevel@tonic-gate 		for (; item != NULL; item = item->next_item) {
459*7c478bd9Sstevel@tonic-gate 			/*
460*7c478bd9Sstevel@tonic-gate 			 * skip all the other trash that comes up the mib stream
461*7c478bd9Sstevel@tonic-gate 			 */
462*7c478bd9Sstevel@tonic-gate 			if (item->group != MIB2_IP ||
463*7c478bd9Sstevel@tonic-gate 			    item->mib_id != MIB2_IP_ROUTE)
464*7c478bd9Sstevel@tonic-gate 				continue;
465*7c478bd9Sstevel@tonic-gate 			for (rp = (mib2_ipRouteEntry_t *)item->valp;
466*7c478bd9Sstevel@tonic-gate 			    (char *)rp < (char *)item->valp + item->length;
467*7c478bd9Sstevel@tonic-gate 			    /* LINTED */
468*7c478bd9Sstevel@tonic-gate 			    rp = (mib2_ipRouteEntry_t *)
469*7c478bd9Sstevel@tonic-gate 				((char *)rp + ipRouteEntrySize)) {
470*7c478bd9Sstevel@tonic-gate 				delRouteEntry(rp, NULL, seqno);
471*7c478bd9Sstevel@tonic-gate 				seqno++;
472*7c478bd9Sstevel@tonic-gate 			}
473*7c478bd9Sstevel@tonic-gate 			break;
474*7c478bd9Sstevel@tonic-gate 		}
475*7c478bd9Sstevel@tonic-gate 		break;
476*7c478bd9Sstevel@tonic-gate 	case AF_INET6:
477*7c478bd9Sstevel@tonic-gate 		/* Extract ipv6RouteEntrySize */
478*7c478bd9Sstevel@tonic-gate 		for (; item != NULL; item = item->next_item) {
479*7c478bd9Sstevel@tonic-gate 			if (item->mib_id != 0)
480*7c478bd9Sstevel@tonic-gate 				continue;
481*7c478bd9Sstevel@tonic-gate 			if (item->group == MIB2_IP6) {
482*7c478bd9Sstevel@tonic-gate 				ipv6RouteEntrySize =
483*7c478bd9Sstevel@tonic-gate 				    ((mib2_ipv6IfStatsEntry_t *)item->valp)->
484*7c478bd9Sstevel@tonic-gate 					ipv6RouteEntrySize;
485*7c478bd9Sstevel@tonic-gate 				assert(IS_P2ALIGNED(ipv6RouteEntrySize,
486*7c478bd9Sstevel@tonic-gate 				    sizeof (mib2_ipv6RouteEntry_t *)));
487*7c478bd9Sstevel@tonic-gate 				break;
488*7c478bd9Sstevel@tonic-gate 			}
489*7c478bd9Sstevel@tonic-gate 		}
490*7c478bd9Sstevel@tonic-gate 		if (ipv6RouteEntrySize == 0) {
491*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
492*7c478bd9Sstevel@tonic-gate 			    "ipv6RouteEntrySize cannot be determined.\n"));
493*7c478bd9Sstevel@tonic-gate 			exit(1);
494*7c478bd9Sstevel@tonic-gate 		}
495*7c478bd9Sstevel@tonic-gate 		for (; item != NULL; item = item->next_item) {
496*7c478bd9Sstevel@tonic-gate 			/*
497*7c478bd9Sstevel@tonic-gate 			 * skip all the other trash that comes up the mib stream
498*7c478bd9Sstevel@tonic-gate 			 */
499*7c478bd9Sstevel@tonic-gate 			if (item->group != MIB2_IP6 ||
500*7c478bd9Sstevel@tonic-gate 			    item->mib_id != MIB2_IP6_ROUTE)
501*7c478bd9Sstevel@tonic-gate 				continue;
502*7c478bd9Sstevel@tonic-gate 			for (rp6 = (mib2_ipv6RouteEntry_t *)item->valp;
503*7c478bd9Sstevel@tonic-gate 			    (char *)rp6 < (char *)item->valp + item->length;
504*7c478bd9Sstevel@tonic-gate 			    /* LINTED */
505*7c478bd9Sstevel@tonic-gate 			    rp6 = (mib2_ipv6RouteEntry_t *)
506*7c478bd9Sstevel@tonic-gate 				((char *)rp6 + ipv6RouteEntrySize)) {
507*7c478bd9Sstevel@tonic-gate 				delRouteEntry(NULL, rp6, seqno);
508*7c478bd9Sstevel@tonic-gate 				seqno++;
509*7c478bd9Sstevel@tonic-gate 			}
510*7c478bd9Sstevel@tonic-gate 			break;
511*7c478bd9Sstevel@tonic-gate 		}
512*7c478bd9Sstevel@tonic-gate 		break;
513*7c478bd9Sstevel@tonic-gate 	}
514*7c478bd9Sstevel@tonic-gate 
515*7c478bd9Sstevel@tonic-gate 	if (setsockopt(s, SOL_SOCKET, SO_USELOOPBACK, (char *)&on,
516*7c478bd9Sstevel@tonic-gate 	    sizeof (on)) < 0)
517*7c478bd9Sstevel@tonic-gate 		quit("setsockopt", errno);
518*7c478bd9Sstevel@tonic-gate }
519*7c478bd9Sstevel@tonic-gate 
520*7c478bd9Sstevel@tonic-gate /*
521*7c478bd9Sstevel@tonic-gate  * Given the contents of a mib_item_t of id type MIB2_IP_ROUTE or
522*7c478bd9Sstevel@tonic-gate  * MIB2_IP6_ROUTE, construct and send an RTM_DELETE routing socket message in
523*7c478bd9Sstevel@tonic-gate  * order to facilitate the flushing of RTF_GATEWAY routes.
524*7c478bd9Sstevel@tonic-gate  */
525*7c478bd9Sstevel@tonic-gate static void
526*7c478bd9Sstevel@tonic-gate delRouteEntry(mib2_ipRouteEntry_t *rp, mib2_ipv6RouteEntry_t *rp6, int seqno)
527*7c478bd9Sstevel@tonic-gate {
528*7c478bd9Sstevel@tonic-gate 	char *cp;
529*7c478bd9Sstevel@tonic-gate 	int ire_type;
530*7c478bd9Sstevel@tonic-gate 	int rlen;
531*7c478bd9Sstevel@tonic-gate 	struct rt_msghdr *rtm;
532*7c478bd9Sstevel@tonic-gate 	struct sockaddr_in sin;
533*7c478bd9Sstevel@tonic-gate 	struct sockaddr_in6 sin6;
534*7c478bd9Sstevel@tonic-gate 	int slen;
535*7c478bd9Sstevel@tonic-gate 
536*7c478bd9Sstevel@tonic-gate 	if (rp != NULL)
537*7c478bd9Sstevel@tonic-gate 		ire_type = rp->ipRouteInfo.re_ire_type;
538*7c478bd9Sstevel@tonic-gate 	else
539*7c478bd9Sstevel@tonic-gate 		ire_type = rp6->ipv6RouteInfo.re_ire_type;
540*7c478bd9Sstevel@tonic-gate 	if (ire_type != IRE_DEFAULT &&
541*7c478bd9Sstevel@tonic-gate 	    ire_type != IRE_PREFIX &&
542*7c478bd9Sstevel@tonic-gate 	    ire_type != IRE_HOST &&
543*7c478bd9Sstevel@tonic-gate 	    ire_type != IRE_HOST_REDIRECT)
544*7c478bd9Sstevel@tonic-gate 		return;
545*7c478bd9Sstevel@tonic-gate 
546*7c478bd9Sstevel@tonic-gate 	rtm = &m_rtmsg.m_rtm;
547*7c478bd9Sstevel@tonic-gate 	(void) memset(rtm, 0, sizeof (m_rtmsg));
548*7c478bd9Sstevel@tonic-gate 	rtm->rtm_type = RTM_DELETE;
549*7c478bd9Sstevel@tonic-gate 	rtm->rtm_seq = seqno;
550*7c478bd9Sstevel@tonic-gate 	rtm->rtm_flags |= RTF_GATEWAY;
551*7c478bd9Sstevel@tonic-gate 	rtm->rtm_version = RTM_VERSION;
552*7c478bd9Sstevel@tonic-gate 	rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
553*7c478bd9Sstevel@tonic-gate 	cp = m_rtmsg.m_space;
554*7c478bd9Sstevel@tonic-gate 	if (rp != NULL) {
555*7c478bd9Sstevel@tonic-gate 		slen = sizeof (struct sockaddr_in);
556*7c478bd9Sstevel@tonic-gate 		if (rp->ipRouteMask == IP_HOST_MASK)
557*7c478bd9Sstevel@tonic-gate 			rtm->rtm_flags |= RTF_HOST;
558*7c478bd9Sstevel@tonic-gate 		(void) memset(&sin, 0, slen);
559*7c478bd9Sstevel@tonic-gate 		sin.sin_family = AF_INET;
560*7c478bd9Sstevel@tonic-gate 		sin.sin_addr.s_addr = rp->ipRouteDest;
561*7c478bd9Sstevel@tonic-gate 		(void) memmove(cp, &sin, slen);
562*7c478bd9Sstevel@tonic-gate 		cp += slen;
563*7c478bd9Sstevel@tonic-gate 		sin.sin_addr.s_addr = rp->ipRouteNextHop;
564*7c478bd9Sstevel@tonic-gate 		(void) memmove(cp, &sin, slen);
565*7c478bd9Sstevel@tonic-gate 		cp += slen;
566*7c478bd9Sstevel@tonic-gate 		sin.sin_addr.s_addr = rp->ipRouteMask;
567*7c478bd9Sstevel@tonic-gate 		(void) memmove(cp, &sin, slen);
568*7c478bd9Sstevel@tonic-gate 		cp += slen;
569*7c478bd9Sstevel@tonic-gate 	} else {
570*7c478bd9Sstevel@tonic-gate 		slen = sizeof (struct sockaddr_in6);
571*7c478bd9Sstevel@tonic-gate 		if (rp6->ipv6RoutePfxLength == IPV6_ABITS)
572*7c478bd9Sstevel@tonic-gate 			rtm->rtm_flags |= RTF_HOST;
573*7c478bd9Sstevel@tonic-gate 		(void) memset(&sin6, 0, slen);
574*7c478bd9Sstevel@tonic-gate 		sin6.sin6_family = AF_INET6;
575*7c478bd9Sstevel@tonic-gate 		sin6.sin6_addr = rp6->ipv6RouteDest;
576*7c478bd9Sstevel@tonic-gate 		(void) memmove(cp, &sin6, slen);
577*7c478bd9Sstevel@tonic-gate 		cp += slen;
578*7c478bd9Sstevel@tonic-gate 		sin6.sin6_addr = rp6->ipv6RouteNextHop;
579*7c478bd9Sstevel@tonic-gate 		(void) memmove(cp, &sin6, slen);
580*7c478bd9Sstevel@tonic-gate 		cp += slen;
581*7c478bd9Sstevel@tonic-gate 		(void) memset(&sin6.sin6_addr, 0, sizeof (sin6.sin6_addr));
582*7c478bd9Sstevel@tonic-gate 		(void) in_prefixlentomask(rp6->ipv6RoutePfxLength, IPV6_ABITS,
583*7c478bd9Sstevel@tonic-gate 		    (uchar_t *)&sin6.sin6_addr.s6_addr);
584*7c478bd9Sstevel@tonic-gate 		(void) memmove(cp, &sin6, slen);
585*7c478bd9Sstevel@tonic-gate 		cp += slen;
586*7c478bd9Sstevel@tonic-gate 	}
587*7c478bd9Sstevel@tonic-gate 	rtm->rtm_msglen = cp - (char *)&m_rtmsg;
588*7c478bd9Sstevel@tonic-gate 	if (debugonly) {
589*7c478bd9Sstevel@tonic-gate 		/*
590*7c478bd9Sstevel@tonic-gate 		 * In debugonly mode, the routing socket message to delete the
591*7c478bd9Sstevel@tonic-gate 		 * current entry is not actually sent.  However if verbose is
592*7c478bd9Sstevel@tonic-gate 		 * also set, the routing socket message that would have been
593*7c478bd9Sstevel@tonic-gate 		 * is printed.
594*7c478bd9Sstevel@tonic-gate 		 */
595*7c478bd9Sstevel@tonic-gate 		if (verbose)
596*7c478bd9Sstevel@tonic-gate 			print_rtmsg(rtm, rtm->rtm_msglen);
597*7c478bd9Sstevel@tonic-gate 		return;
598*7c478bd9Sstevel@tonic-gate 	}
599*7c478bd9Sstevel@tonic-gate 
600*7c478bd9Sstevel@tonic-gate 	rlen = write(s, (char *)&m_rtmsg, rtm->rtm_msglen);
601*7c478bd9Sstevel@tonic-gate 	if (rlen < (int)rtm->rtm_msglen) {
602*7c478bd9Sstevel@tonic-gate 		if (rlen < 0) {
603*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
604*7c478bd9Sstevel@tonic-gate 			    gettext("route: write to routing socket: %s\n"),
605*7c478bd9Sstevel@tonic-gate 			    strerror(errno));
606*7c478bd9Sstevel@tonic-gate 		} else {
607*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("route: write to "
608*7c478bd9Sstevel@tonic-gate 			    "routing socket got only %d for rlen\n"), rlen);
609*7c478bd9Sstevel@tonic-gate 		}
610*7c478bd9Sstevel@tonic-gate 		return;
611*7c478bd9Sstevel@tonic-gate 	}
612*7c478bd9Sstevel@tonic-gate 	if (qflag) {
613*7c478bd9Sstevel@tonic-gate 		/*
614*7c478bd9Sstevel@tonic-gate 		 * In quiet mode, nothing is printed at all (unless the write()
615*7c478bd9Sstevel@tonic-gate 		 * itself failed.
616*7c478bd9Sstevel@tonic-gate 		 */
617*7c478bd9Sstevel@tonic-gate 		return;
618*7c478bd9Sstevel@tonic-gate 	}
619*7c478bd9Sstevel@tonic-gate 	if (verbose) {
620*7c478bd9Sstevel@tonic-gate 		print_rtmsg(rtm, rlen);
621*7c478bd9Sstevel@tonic-gate 	} else {
622*7c478bd9Sstevel@tonic-gate 		struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
623*7c478bd9Sstevel@tonic-gate 
624*7c478bd9Sstevel@tonic-gate 		(void) printf("%-20.20s ",
625*7c478bd9Sstevel@tonic-gate 		    rtm->rtm_flags & RTF_HOST ? routename(sa) :
626*7c478bd9Sstevel@tonic-gate 			netname(sa));
627*7c478bd9Sstevel@tonic-gate 		/* LINTED */
628*7c478bd9Sstevel@tonic-gate 		sa = (struct sockaddr *)(salen(sa) + (char *)sa);
629*7c478bd9Sstevel@tonic-gate 		(void) printf("%-20.20s ", routename(sa));
630*7c478bd9Sstevel@tonic-gate 		(void) printf("done\n");
631*7c478bd9Sstevel@tonic-gate 	}
632*7c478bd9Sstevel@tonic-gate }
633*7c478bd9Sstevel@tonic-gate 
634*7c478bd9Sstevel@tonic-gate /*
635*7c478bd9Sstevel@tonic-gate  * Return the name of the host whose address is given.
636*7c478bd9Sstevel@tonic-gate  */
637*7c478bd9Sstevel@tonic-gate char *
638*7c478bd9Sstevel@tonic-gate routename(struct sockaddr *sa)
639*7c478bd9Sstevel@tonic-gate {
640*7c478bd9Sstevel@tonic-gate 	char *cp;
641*7c478bd9Sstevel@tonic-gate 	static char line[MAXHOSTNAMELEN + 1];
642*7c478bd9Sstevel@tonic-gate 	struct hostent *hp = NULL;
643*7c478bd9Sstevel@tonic-gate 	static char domain[MAXHOSTNAMELEN + 1];
644*7c478bd9Sstevel@tonic-gate 	static boolean_t first = B_TRUE;
645*7c478bd9Sstevel@tonic-gate 	struct in_addr in;
646*7c478bd9Sstevel@tonic-gate 	struct in6_addr in6;
647*7c478bd9Sstevel@tonic-gate 	int error_num;
648*7c478bd9Sstevel@tonic-gate 	ushort_t *s;
649*7c478bd9Sstevel@tonic-gate 	ushort_t *slim;
650*7c478bd9Sstevel@tonic-gate 
651*7c478bd9Sstevel@tonic-gate 	if (first) {
652*7c478bd9Sstevel@tonic-gate 		first = B_FALSE;
653*7c478bd9Sstevel@tonic-gate 		if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
654*7c478bd9Sstevel@tonic-gate 		    (cp = strchr(domain, '.')))
655*7c478bd9Sstevel@tonic-gate 			(void) strcpy(domain, cp + 1);
656*7c478bd9Sstevel@tonic-gate 		else
657*7c478bd9Sstevel@tonic-gate 			domain[0] = 0;
658*7c478bd9Sstevel@tonic-gate 	}
659*7c478bd9Sstevel@tonic-gate 
660*7c478bd9Sstevel@tonic-gate 	if (salen(sa) == 0) {
661*7c478bd9Sstevel@tonic-gate 		(void) strcpy(line, "default");
662*7c478bd9Sstevel@tonic-gate 		return (line);
663*7c478bd9Sstevel@tonic-gate 	}
664*7c478bd9Sstevel@tonic-gate 	switch (sa->sa_family) {
665*7c478bd9Sstevel@tonic-gate 
666*7c478bd9Sstevel@tonic-gate 	case AF_INET:
667*7c478bd9Sstevel@tonic-gate 		/* LINTED */
668*7c478bd9Sstevel@tonic-gate 		in = ((struct sockaddr_in *)sa)->sin_addr;
669*7c478bd9Sstevel@tonic-gate 
670*7c478bd9Sstevel@tonic-gate 		cp = NULL;
671*7c478bd9Sstevel@tonic-gate 		if (in.s_addr == INADDR_ANY)
672*7c478bd9Sstevel@tonic-gate 			cp = "default";
673*7c478bd9Sstevel@tonic-gate 		if (cp == NULL && !nflag) {
674*7c478bd9Sstevel@tonic-gate 			hp = gethostbyaddr((char *)&in, sizeof (struct in_addr),
675*7c478bd9Sstevel@tonic-gate 				AF_INET);
676*7c478bd9Sstevel@tonic-gate 			if (hp != NULL) {
677*7c478bd9Sstevel@tonic-gate 				if (((cp = strchr(hp->h_name, '.')) != NULL) &&
678*7c478bd9Sstevel@tonic-gate 				    (strcmp(cp + 1, domain) == 0))
679*7c478bd9Sstevel@tonic-gate 					*cp = 0;
680*7c478bd9Sstevel@tonic-gate 				cp = hp->h_name;
681*7c478bd9Sstevel@tonic-gate 			}
682*7c478bd9Sstevel@tonic-gate 		}
683*7c478bd9Sstevel@tonic-gate 		if (cp != NULL) {
684*7c478bd9Sstevel@tonic-gate 			(void) strncpy(line, cp, MAXHOSTNAMELEN);
685*7c478bd9Sstevel@tonic-gate 			line[MAXHOSTNAMELEN] = '\0';
686*7c478bd9Sstevel@tonic-gate 		} else {
687*7c478bd9Sstevel@tonic-gate 			in.s_addr = ntohl(in.s_addr);
688*7c478bd9Sstevel@tonic-gate 			(void) sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24),
689*7c478bd9Sstevel@tonic-gate 			    C(in.s_addr >> 16), C(in.s_addr >> 8),
690*7c478bd9Sstevel@tonic-gate 			    C(in.s_addr));
691*7c478bd9Sstevel@tonic-gate 		}
692*7c478bd9Sstevel@tonic-gate 		break;
693*7c478bd9Sstevel@tonic-gate 
694*7c478bd9Sstevel@tonic-gate 	case AF_LINK:
695*7c478bd9Sstevel@tonic-gate 		return (link_ntoa((struct sockaddr_dl *)sa));
696*7c478bd9Sstevel@tonic-gate 
697*7c478bd9Sstevel@tonic-gate 	case AF_INET6:
698*7c478bd9Sstevel@tonic-gate 		/* LINTED */
699*7c478bd9Sstevel@tonic-gate 		in6 = ((struct sockaddr_in6 *)sa)->sin6_addr;
700*7c478bd9Sstevel@tonic-gate 
701*7c478bd9Sstevel@tonic-gate 		cp = NULL;
702*7c478bd9Sstevel@tonic-gate 		if (IN6_IS_ADDR_UNSPECIFIED(&in6))
703*7c478bd9Sstevel@tonic-gate 			cp = "default";
704*7c478bd9Sstevel@tonic-gate 		if (cp == NULL && !nflag) {
705*7c478bd9Sstevel@tonic-gate 			hp = getipnodebyaddr((char *)&in6,
706*7c478bd9Sstevel@tonic-gate 				sizeof (struct in6_addr), AF_INET6, &error_num);
707*7c478bd9Sstevel@tonic-gate 			if (hp != NULL) {
708*7c478bd9Sstevel@tonic-gate 				if (((cp = strchr(hp->h_name, '.')) != NULL) &&
709*7c478bd9Sstevel@tonic-gate 				    (strcmp(cp + 1, domain) == 0))
710*7c478bd9Sstevel@tonic-gate 					*cp = 0;
711*7c478bd9Sstevel@tonic-gate 				cp = hp->h_name;
712*7c478bd9Sstevel@tonic-gate 			}
713*7c478bd9Sstevel@tonic-gate 		}
714*7c478bd9Sstevel@tonic-gate 		if (cp != NULL) {
715*7c478bd9Sstevel@tonic-gate 			(void) strncpy(line, cp, MAXHOSTNAMELEN);
716*7c478bd9Sstevel@tonic-gate 			line[MAXHOSTNAMELEN] = '\0';
717*7c478bd9Sstevel@tonic-gate 		} else {
718*7c478bd9Sstevel@tonic-gate 			(void) inet_ntop(AF_INET6, (void *)&in6, line,
719*7c478bd9Sstevel@tonic-gate 			    INET6_ADDRSTRLEN);
720*7c478bd9Sstevel@tonic-gate 		}
721*7c478bd9Sstevel@tonic-gate 		if (hp != NULL)
722*7c478bd9Sstevel@tonic-gate 			freehostent(hp);
723*7c478bd9Sstevel@tonic-gate 
724*7c478bd9Sstevel@tonic-gate 		break;
725*7c478bd9Sstevel@tonic-gate 
726*7c478bd9Sstevel@tonic-gate 	default:
727*7c478bd9Sstevel@tonic-gate 		s = (ushort_t *)sa;
728*7c478bd9Sstevel@tonic-gate 
729*7c478bd9Sstevel@tonic-gate 		slim = s + ((salen(sa) + 1) >> 1);
730*7c478bd9Sstevel@tonic-gate 		cp = line + sprintf(line, "(%d)", sa->sa_family);
731*7c478bd9Sstevel@tonic-gate 
732*7c478bd9Sstevel@tonic-gate 		while (++s < slim) /* start with sa->sa_data */
733*7c478bd9Sstevel@tonic-gate 			cp += sprintf(cp, " %x", *s);
734*7c478bd9Sstevel@tonic-gate 		break;
735*7c478bd9Sstevel@tonic-gate 	}
736*7c478bd9Sstevel@tonic-gate 	return (line);
737*7c478bd9Sstevel@tonic-gate }
738*7c478bd9Sstevel@tonic-gate 
739*7c478bd9Sstevel@tonic-gate /*
740*7c478bd9Sstevel@tonic-gate  * Return the name of the network whose address is given.
741*7c478bd9Sstevel@tonic-gate  * The address is assumed to be that of a net or subnet, not a host.
742*7c478bd9Sstevel@tonic-gate  */
743*7c478bd9Sstevel@tonic-gate static char *
744*7c478bd9Sstevel@tonic-gate netname(struct sockaddr *sa)
745*7c478bd9Sstevel@tonic-gate {
746*7c478bd9Sstevel@tonic-gate 	char *cp = NULL;
747*7c478bd9Sstevel@tonic-gate 	static char line[MAXHOSTNAMELEN + 1];
748*7c478bd9Sstevel@tonic-gate 	struct netent *np;
749*7c478bd9Sstevel@tonic-gate 	in_addr_t net, mask;
750*7c478bd9Sstevel@tonic-gate 	int subnetshift;
751*7c478bd9Sstevel@tonic-gate 	struct in_addr in;
752*7c478bd9Sstevel@tonic-gate 	ushort_t *s;
753*7c478bd9Sstevel@tonic-gate 	ushort_t *slim;
754*7c478bd9Sstevel@tonic-gate 
755*7c478bd9Sstevel@tonic-gate 	switch (sa->sa_family) {
756*7c478bd9Sstevel@tonic-gate 
757*7c478bd9Sstevel@tonic-gate 	case AF_INET:
758*7c478bd9Sstevel@tonic-gate 		/* LINTED */
759*7c478bd9Sstevel@tonic-gate 		in = ((struct sockaddr_in *)sa)->sin_addr;
760*7c478bd9Sstevel@tonic-gate 
761*7c478bd9Sstevel@tonic-gate 		in.s_addr = ntohl(in.s_addr);
762*7c478bd9Sstevel@tonic-gate 		if (in.s_addr == INADDR_ANY) {
763*7c478bd9Sstevel@tonic-gate 			cp = "default";
764*7c478bd9Sstevel@tonic-gate 		} else if (!nflag) {
765*7c478bd9Sstevel@tonic-gate 			if (IN_CLASSA(in.s_addr)) {
766*7c478bd9Sstevel@tonic-gate 				mask = IN_CLASSA_NET;
767*7c478bd9Sstevel@tonic-gate 				subnetshift = 8;
768*7c478bd9Sstevel@tonic-gate 			} else if (IN_CLASSB(in.s_addr)) {
769*7c478bd9Sstevel@tonic-gate 				mask = IN_CLASSB_NET;
770*7c478bd9Sstevel@tonic-gate 				subnetshift = 8;
771*7c478bd9Sstevel@tonic-gate 			} else {
772*7c478bd9Sstevel@tonic-gate 				mask = IN_CLASSC_NET;
773*7c478bd9Sstevel@tonic-gate 				subnetshift = 4;
774*7c478bd9Sstevel@tonic-gate 			}
775*7c478bd9Sstevel@tonic-gate 			/*
776*7c478bd9Sstevel@tonic-gate 			 * If there are more bits than the standard mask
777*7c478bd9Sstevel@tonic-gate 			 * would suggest, subnets must be in use.
778*7c478bd9Sstevel@tonic-gate 			 * Guess at the subnet mask, assuming reasonable
779*7c478bd9Sstevel@tonic-gate 			 * width subnet fields.
780*7c478bd9Sstevel@tonic-gate 			 */
781*7c478bd9Sstevel@tonic-gate 			while (in.s_addr &~ mask)
782*7c478bd9Sstevel@tonic-gate 				mask = (long)mask >> subnetshift;
783*7c478bd9Sstevel@tonic-gate 			net = in.s_addr & mask;
784*7c478bd9Sstevel@tonic-gate 			while ((mask & 1) == 0)
785*7c478bd9Sstevel@tonic-gate 				mask >>= 1, net >>= 1;
786*7c478bd9Sstevel@tonic-gate 			np = getnetbyaddr(net, AF_INET);
787*7c478bd9Sstevel@tonic-gate 			if (np != NULL)
788*7c478bd9Sstevel@tonic-gate 				cp = np->n_name;
789*7c478bd9Sstevel@tonic-gate 		}
790*7c478bd9Sstevel@tonic-gate 		if (cp != NULL) {
791*7c478bd9Sstevel@tonic-gate 			(void) strncpy(line, cp, MAXHOSTNAMELEN);
792*7c478bd9Sstevel@tonic-gate 			line[MAXHOSTNAMELEN] = '\0';
793*7c478bd9Sstevel@tonic-gate 		} else if ((in.s_addr & 0xffffff) == 0) {
794*7c478bd9Sstevel@tonic-gate 			(void) sprintf(line, "%u", C(in.s_addr >> 24));
795*7c478bd9Sstevel@tonic-gate 		} else if ((in.s_addr & 0xffff) == 0) {
796*7c478bd9Sstevel@tonic-gate 			(void) sprintf(line, "%u.%u", C(in.s_addr >> 24),
797*7c478bd9Sstevel@tonic-gate 			    C(in.s_addr >> 16));
798*7c478bd9Sstevel@tonic-gate 		} else if ((in.s_addr & 0xff) == 0) {
799*7c478bd9Sstevel@tonic-gate 			(void) sprintf(line, "%u.%u.%u", C(in.s_addr >> 24),
800*7c478bd9Sstevel@tonic-gate 			    C(in.s_addr >> 16), C(in.s_addr >> 8));
801*7c478bd9Sstevel@tonic-gate 		} else {
802*7c478bd9Sstevel@tonic-gate 			(void) sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24),
803*7c478bd9Sstevel@tonic-gate 			    C(in.s_addr >> 16), C(in.s_addr >> 8),
804*7c478bd9Sstevel@tonic-gate 			    C(in.s_addr));
805*7c478bd9Sstevel@tonic-gate 		}
806*7c478bd9Sstevel@tonic-gate 		break;
807*7c478bd9Sstevel@tonic-gate 
808*7c478bd9Sstevel@tonic-gate 	case AF_LINK:
809*7c478bd9Sstevel@tonic-gate 		return (link_ntoa((struct sockaddr_dl *)sa));
810*7c478bd9Sstevel@tonic-gate 
811*7c478bd9Sstevel@tonic-gate 	case AF_INET6:
812*7c478bd9Sstevel@tonic-gate 		return (routename(sa));
813*7c478bd9Sstevel@tonic-gate 
814*7c478bd9Sstevel@tonic-gate 	default:
815*7c478bd9Sstevel@tonic-gate 		/* LINTED */
816*7c478bd9Sstevel@tonic-gate 		s = (ushort_t *)sa->sa_data;
817*7c478bd9Sstevel@tonic-gate 
818*7c478bd9Sstevel@tonic-gate 		slim = s + ((salen(sa) + 1) >> 1);
819*7c478bd9Sstevel@tonic-gate 		cp = line + sprintf(line, "af %d:", sa->sa_family);
820*7c478bd9Sstevel@tonic-gate 
821*7c478bd9Sstevel@tonic-gate 		while (s < slim)
822*7c478bd9Sstevel@tonic-gate 			cp += sprintf(cp, " %x", *s++);
823*7c478bd9Sstevel@tonic-gate 		break;
824*7c478bd9Sstevel@tonic-gate 	}
825*7c478bd9Sstevel@tonic-gate 	return (line);
826*7c478bd9Sstevel@tonic-gate }
827*7c478bd9Sstevel@tonic-gate 
828*7c478bd9Sstevel@tonic-gate void
829*7c478bd9Sstevel@tonic-gate set_metric(char *value, int key)
830*7c478bd9Sstevel@tonic-gate {
831*7c478bd9Sstevel@tonic-gate 	int flag = 0;
832*7c478bd9Sstevel@tonic-gate 	uint_t noval, *valp = &noval;
833*7c478bd9Sstevel@tonic-gate 
834*7c478bd9Sstevel@tonic-gate 	switch (key) {
835*7c478bd9Sstevel@tonic-gate #define	caseof(x, y, z)	case (x): valp = &rt_metrics.z; flag = (y); break
836*7c478bd9Sstevel@tonic-gate 	caseof(K_MTU, RTV_MTU, rmx_mtu);
837*7c478bd9Sstevel@tonic-gate 	caseof(K_HOPCOUNT, RTV_HOPCOUNT, rmx_hopcount);
838*7c478bd9Sstevel@tonic-gate 	caseof(K_EXPIRE, RTV_EXPIRE, rmx_expire);
839*7c478bd9Sstevel@tonic-gate 	caseof(K_RECVPIPE, RTV_RPIPE, rmx_recvpipe);
840*7c478bd9Sstevel@tonic-gate 	caseof(K_SENDPIPE, RTV_SPIPE, rmx_sendpipe);
841*7c478bd9Sstevel@tonic-gate 	caseof(K_SSTHRESH, RTV_SSTHRESH, rmx_ssthresh);
842*7c478bd9Sstevel@tonic-gate 	caseof(K_RTT, RTV_RTT, rmx_rtt);
843*7c478bd9Sstevel@tonic-gate 	caseof(K_RTTVAR, RTV_RTTVAR, rmx_rttvar);
844*7c478bd9Sstevel@tonic-gate #undef	caseof
845*7c478bd9Sstevel@tonic-gate 	}
846*7c478bd9Sstevel@tonic-gate 	rtm_inits |= flag;
847*7c478bd9Sstevel@tonic-gate 	if (lockrest || locking)
848*7c478bd9Sstevel@tonic-gate 		rt_metrics.rmx_locks |= flag;
849*7c478bd9Sstevel@tonic-gate 	if (locking)
850*7c478bd9Sstevel@tonic-gate 		locking = B_FALSE;
851*7c478bd9Sstevel@tonic-gate 	*valp = atoi(value);
852*7c478bd9Sstevel@tonic-gate }
853*7c478bd9Sstevel@tonic-gate 
854*7c478bd9Sstevel@tonic-gate int
855*7c478bd9Sstevel@tonic-gate newroute(int argc, char **argv)
856*7c478bd9Sstevel@tonic-gate {
857*7c478bd9Sstevel@tonic-gate 	char *cmd, *dest = "", *gateway = "", *err;
858*7c478bd9Sstevel@tonic-gate 	boolean_t ishost = B_FALSE;
859*7c478bd9Sstevel@tonic-gate 	int ret, attempts, oerrno, flags = RTF_STATIC;
860*7c478bd9Sstevel@tonic-gate 	int key;
861*7c478bd9Sstevel@tonic-gate 	struct hostent *hp = NULL;
862*7c478bd9Sstevel@tonic-gate 	static char obuf[INET6_ADDRSTRLEN];
863*7c478bd9Sstevel@tonic-gate 
864*7c478bd9Sstevel@tonic-gate 	cmd = argv[0];
865*7c478bd9Sstevel@tonic-gate 	if (*cmd != 'g' && !tflag) {
866*7c478bd9Sstevel@tonic-gate 		/* Don't want to read back our messages */
867*7c478bd9Sstevel@tonic-gate 		(void) shutdown(s, 0);
868*7c478bd9Sstevel@tonic-gate 	}
869*7c478bd9Sstevel@tonic-gate 	while (--argc > 0) {
870*7c478bd9Sstevel@tonic-gate 		key = keyword(*(++argv));
871*7c478bd9Sstevel@tonic-gate 		if (key == K_HOST) {
872*7c478bd9Sstevel@tonic-gate 			forcehost = B_TRUE;
873*7c478bd9Sstevel@tonic-gate 		} else if (key == K_NET) {
874*7c478bd9Sstevel@tonic-gate 			forcenet = B_TRUE;
875*7c478bd9Sstevel@tonic-gate 		} else if (**(argv) == '-') {
876*7c478bd9Sstevel@tonic-gate 			switch (key = keyword(1 + *argv)) {
877*7c478bd9Sstevel@tonic-gate 			case K_LINK:
878*7c478bd9Sstevel@tonic-gate 				af = AF_LINK;
879*7c478bd9Sstevel@tonic-gate 				break;
880*7c478bd9Sstevel@tonic-gate 			case K_INET:
881*7c478bd9Sstevel@tonic-gate 				af = AF_INET;
882*7c478bd9Sstevel@tonic-gate 				break;
883*7c478bd9Sstevel@tonic-gate 			case K_SA:
884*7c478bd9Sstevel@tonic-gate 				af = PF_ROUTE;
885*7c478bd9Sstevel@tonic-gate 				break;
886*7c478bd9Sstevel@tonic-gate 			case K_INET6:
887*7c478bd9Sstevel@tonic-gate 				af = AF_INET6;
888*7c478bd9Sstevel@tonic-gate 				break;
889*7c478bd9Sstevel@tonic-gate 			case K_IFACE:
890*7c478bd9Sstevel@tonic-gate 			case K_INTERFACE:
891*7c478bd9Sstevel@tonic-gate 				iflag = B_TRUE;
892*7c478bd9Sstevel@tonic-gate 				/* FALLTHROUGH */
893*7c478bd9Sstevel@tonic-gate 			case K_NOSTATIC:
894*7c478bd9Sstevel@tonic-gate 				flags &= ~RTF_STATIC;
895*7c478bd9Sstevel@tonic-gate 				break;
896*7c478bd9Sstevel@tonic-gate 			case K_LOCK:
897*7c478bd9Sstevel@tonic-gate 				locking = B_TRUE;
898*7c478bd9Sstevel@tonic-gate 				break;
899*7c478bd9Sstevel@tonic-gate 			case K_LOCKREST:
900*7c478bd9Sstevel@tonic-gate 				lockrest = B_TRUE;
901*7c478bd9Sstevel@tonic-gate 				break;
902*7c478bd9Sstevel@tonic-gate 			case K_HOST:
903*7c478bd9Sstevel@tonic-gate 				forcehost = B_TRUE;
904*7c478bd9Sstevel@tonic-gate 				break;
905*7c478bd9Sstevel@tonic-gate 			case K_REJECT:
906*7c478bd9Sstevel@tonic-gate 				flags |= RTF_REJECT;
907*7c478bd9Sstevel@tonic-gate 				break;
908*7c478bd9Sstevel@tonic-gate 			case K_BLACKHOLE:
909*7c478bd9Sstevel@tonic-gate 				flags |= RTF_BLACKHOLE;
910*7c478bd9Sstevel@tonic-gate 				break;
911*7c478bd9Sstevel@tonic-gate 			case K_PROTO1:
912*7c478bd9Sstevel@tonic-gate 				flags |= RTF_PROTO1;
913*7c478bd9Sstevel@tonic-gate 				break;
914*7c478bd9Sstevel@tonic-gate 			case K_PROTO2:
915*7c478bd9Sstevel@tonic-gate 				flags |= RTF_PROTO2;
916*7c478bd9Sstevel@tonic-gate 				break;
917*7c478bd9Sstevel@tonic-gate 			case K_CLONING:
918*7c478bd9Sstevel@tonic-gate 				flags |= RTF_CLONING;
919*7c478bd9Sstevel@tonic-gate 				break;
920*7c478bd9Sstevel@tonic-gate 			case K_XRESOLVE:
921*7c478bd9Sstevel@tonic-gate 				flags |= RTF_XRESOLVE;
922*7c478bd9Sstevel@tonic-gate 				break;
923*7c478bd9Sstevel@tonic-gate 			case K_STATIC:
924*7c478bd9Sstevel@tonic-gate 				flags |= RTF_STATIC;
925*7c478bd9Sstevel@tonic-gate 				break;
926*7c478bd9Sstevel@tonic-gate 			case K_IFA:
927*7c478bd9Sstevel@tonic-gate 				argc--;
928*7c478bd9Sstevel@tonic-gate 				(void) getaddr(RTA_IFA, *++argv, NULL);
929*7c478bd9Sstevel@tonic-gate 				break;
930*7c478bd9Sstevel@tonic-gate 			case K_IFP:
931*7c478bd9Sstevel@tonic-gate 				argc--;
932*7c478bd9Sstevel@tonic-gate 				(void) getaddr(RTA_IFP, *++argv, NULL);
933*7c478bd9Sstevel@tonic-gate 				break;
934*7c478bd9Sstevel@tonic-gate 			case K_GATEWAY:
935*7c478bd9Sstevel@tonic-gate 				/*
936*7c478bd9Sstevel@tonic-gate 				 * For the gateway parameter, retrieve the
937*7c478bd9Sstevel@tonic-gate 				 * pointer to the struct hostent so that all
938*7c478bd9Sstevel@tonic-gate 				 * possible addresses can be tried until one
939*7c478bd9Sstevel@tonic-gate 				 * is successful.
940*7c478bd9Sstevel@tonic-gate 				 */
941*7c478bd9Sstevel@tonic-gate 				argc--;
942*7c478bd9Sstevel@tonic-gate 				gateway = *++argv;
943*7c478bd9Sstevel@tonic-gate 				(void) getaddr(RTA_GATEWAY, *argv, &hp);
944*7c478bd9Sstevel@tonic-gate 				break;
945*7c478bd9Sstevel@tonic-gate 			case K_DST:
946*7c478bd9Sstevel@tonic-gate 				argc--;
947*7c478bd9Sstevel@tonic-gate 				ishost = getaddr(RTA_DST, *++argv, NULL);
948*7c478bd9Sstevel@tonic-gate 				dest = *argv;
949*7c478bd9Sstevel@tonic-gate 				break;
950*7c478bd9Sstevel@tonic-gate 			case K_NETMASK:
951*7c478bd9Sstevel@tonic-gate 				argc--;
952*7c478bd9Sstevel@tonic-gate 				(void) getaddr(RTA_NETMASK, *++argv, NULL);
953*7c478bd9Sstevel@tonic-gate 				/* FALLTHROUGH */
954*7c478bd9Sstevel@tonic-gate 			case K_NET:
955*7c478bd9Sstevel@tonic-gate 				forcenet = B_TRUE;
956*7c478bd9Sstevel@tonic-gate 				break;
957*7c478bd9Sstevel@tonic-gate 			case K_MTU:
958*7c478bd9Sstevel@tonic-gate 			case K_HOPCOUNT:
959*7c478bd9Sstevel@tonic-gate 			case K_EXPIRE:
960*7c478bd9Sstevel@tonic-gate 			case K_RECVPIPE:
961*7c478bd9Sstevel@tonic-gate 			case K_SENDPIPE:
962*7c478bd9Sstevel@tonic-gate 			case K_SSTHRESH:
963*7c478bd9Sstevel@tonic-gate 			case K_RTT:
964*7c478bd9Sstevel@tonic-gate 			case K_RTTVAR:
965*7c478bd9Sstevel@tonic-gate 				argc--;
966*7c478bd9Sstevel@tonic-gate 				set_metric(*++argv, key);
967*7c478bd9Sstevel@tonic-gate 				break;
968*7c478bd9Sstevel@tonic-gate 			case K_PRIVATE:
969*7c478bd9Sstevel@tonic-gate 				flags |= RTF_PRIVATE;
970*7c478bd9Sstevel@tonic-gate 				break;
971*7c478bd9Sstevel@tonic-gate 			case K_MULTIRT:
972*7c478bd9Sstevel@tonic-gate 				flags |= RTF_MULTIRT;
973*7c478bd9Sstevel@tonic-gate 				break;
974*7c478bd9Sstevel@tonic-gate 			case K_SETSRC:
975*7c478bd9Sstevel@tonic-gate 				argc--;
976*7c478bd9Sstevel@tonic-gate 				(void) getaddr(RTA_SRC, *++argv, NULL);
977*7c478bd9Sstevel@tonic-gate 				flags |= RTF_SETSRC;
978*7c478bd9Sstevel@tonic-gate 				break;
979*7c478bd9Sstevel@tonic-gate 			default:
980*7c478bd9Sstevel@tonic-gate 				usage(*argv + 1);
981*7c478bd9Sstevel@tonic-gate 				/* NOTREACHED */
982*7c478bd9Sstevel@tonic-gate 			}
983*7c478bd9Sstevel@tonic-gate 		} else {
984*7c478bd9Sstevel@tonic-gate 			if ((rtm_addrs & RTA_DST) == 0) {
985*7c478bd9Sstevel@tonic-gate 				dest = *argv;
986*7c478bd9Sstevel@tonic-gate 				ishost = getaddr(RTA_DST, *argv, NULL);
987*7c478bd9Sstevel@tonic-gate 			} else if ((rtm_addrs & RTA_GATEWAY) == 0) {
988*7c478bd9Sstevel@tonic-gate 				/*
989*7c478bd9Sstevel@tonic-gate 				 * For the gateway parameter, retrieve the
990*7c478bd9Sstevel@tonic-gate 				 * pointer to the struct hostent so that all
991*7c478bd9Sstevel@tonic-gate 				 * possible addresses can be tried until one
992*7c478bd9Sstevel@tonic-gate 				 * is successful.
993*7c478bd9Sstevel@tonic-gate 				 */
994*7c478bd9Sstevel@tonic-gate 				gateway = *argv;
995*7c478bd9Sstevel@tonic-gate 				(void) getaddr(RTA_GATEWAY, *argv, &hp);
996*7c478bd9Sstevel@tonic-gate 			} else {
997*7c478bd9Sstevel@tonic-gate 				ulong_t metric = strtoul(*argv, &err, 10);
998*7c478bd9Sstevel@tonic-gate 
999*7c478bd9Sstevel@tonic-gate 				/*
1000*7c478bd9Sstevel@tonic-gate 				 * Assume that a regular number is a metric.
1001*7c478bd9Sstevel@tonic-gate 				 * Needed for compatibility with old route
1002*7c478bd9Sstevel@tonic-gate 				 * command syntax.
1003*7c478bd9Sstevel@tonic-gate 				 */
1004*7c478bd9Sstevel@tonic-gate 				if (*argv != err && *err == '\0' &&
1005*7c478bd9Sstevel@tonic-gate 				    metric < 0x80000000ul) {
1006*7c478bd9Sstevel@tonic-gate 					iflag = (metric == 0);
1007*7c478bd9Sstevel@tonic-gate 					if (verbose) {
1008*7c478bd9Sstevel@tonic-gate 						(void) printf("old usage of "
1009*7c478bd9Sstevel@tonic-gate 						    "trailing number, assuming "
1010*7c478bd9Sstevel@tonic-gate 						    "route %s\n", iflag ?
1011*7c478bd9Sstevel@tonic-gate 						    "to if" : "via gateway");
1012*7c478bd9Sstevel@tonic-gate 					}
1013*7c478bd9Sstevel@tonic-gate 					continue;
1014*7c478bd9Sstevel@tonic-gate 				}
1015*7c478bd9Sstevel@tonic-gate 				(void) getaddr(RTA_NETMASK, *argv, NULL);
1016*7c478bd9Sstevel@tonic-gate 			}
1017*7c478bd9Sstevel@tonic-gate 		}
1018*7c478bd9Sstevel@tonic-gate 	}
1019*7c478bd9Sstevel@tonic-gate 	if ((rtm_addrs & RTA_DST) == 0) {
1020*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
1021*7c478bd9Sstevel@tonic-gate 		    gettext("route: destination required following command\n"));
1022*7c478bd9Sstevel@tonic-gate 		usage((char *)NULL);
1023*7c478bd9Sstevel@tonic-gate 	} else if ((*cmd == 'a' || *cmd == 'd') &&
1024*7c478bd9Sstevel@tonic-gate 	    (rtm_addrs & RTA_GATEWAY) == 0) {
1025*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
1026*7c478bd9Sstevel@tonic-gate 		    gettext("route: gateway required for add or delete "
1027*7c478bd9Sstevel@tonic-gate 		    "command\n"));
1028*7c478bd9Sstevel@tonic-gate 		usage((char *)NULL);
1029*7c478bd9Sstevel@tonic-gate 	}
1030*7c478bd9Sstevel@tonic-gate 
1031*7c478bd9Sstevel@tonic-gate 	/*
1032*7c478bd9Sstevel@tonic-gate 	 * If the netmask has been specified use it to determine RTF_HOST.
1033*7c478bd9Sstevel@tonic-gate 	 * Otherwise rely on the "-net" and "-host" specifiers.
1034*7c478bd9Sstevel@tonic-gate 	 * Final fallback is whether ot not any bits were set in the address
1035*7c478bd9Sstevel@tonic-gate 	 * past the classful network component.
1036*7c478bd9Sstevel@tonic-gate 	 */
1037*7c478bd9Sstevel@tonic-gate 	if (rtm_addrs & RTA_NETMASK) {
1038*7c478bd9Sstevel@tonic-gate 		if ((af == AF_INET &&
1039*7c478bd9Sstevel@tonic-gate 			so_mask.sin.sin_addr.s_addr == IP_HOST_MASK) ||
1040*7c478bd9Sstevel@tonic-gate 		    (af == AF_INET6 && masklen == IPV6_ABITS))
1041*7c478bd9Sstevel@tonic-gate 			forcehost = B_TRUE;
1042*7c478bd9Sstevel@tonic-gate 		else
1043*7c478bd9Sstevel@tonic-gate 			forcenet = B_TRUE;
1044*7c478bd9Sstevel@tonic-gate 	}
1045*7c478bd9Sstevel@tonic-gate 	if (forcehost)
1046*7c478bd9Sstevel@tonic-gate 		ishost = B_TRUE;
1047*7c478bd9Sstevel@tonic-gate 	if (forcenet)
1048*7c478bd9Sstevel@tonic-gate 		ishost = B_FALSE;
1049*7c478bd9Sstevel@tonic-gate 	flags |= RTF_UP;
1050*7c478bd9Sstevel@tonic-gate 	if (ishost)
1051*7c478bd9Sstevel@tonic-gate 		flags |= RTF_HOST;
1052*7c478bd9Sstevel@tonic-gate 	if (!iflag)
1053*7c478bd9Sstevel@tonic-gate 		flags |= RTF_GATEWAY;
1054*7c478bd9Sstevel@tonic-gate 	for (attempts = 1; ; attempts++) {
1055*7c478bd9Sstevel@tonic-gate 		errno = 0;
1056*7c478bd9Sstevel@tonic-gate 		if ((ret = rtmsg(*cmd, flags)) == 0)
1057*7c478bd9Sstevel@tonic-gate 			break;
1058*7c478bd9Sstevel@tonic-gate 		if (errno != ENETUNREACH && errno != ESRCH)
1059*7c478bd9Sstevel@tonic-gate 			break;
1060*7c478bd9Sstevel@tonic-gate 		if (*gateway != '\0' && hp != NULL &&
1061*7c478bd9Sstevel@tonic-gate 		    hp->h_addr_list[attempts] != NULL) {
1062*7c478bd9Sstevel@tonic-gate 			switch (af) {
1063*7c478bd9Sstevel@tonic-gate 			case AF_INET:
1064*7c478bd9Sstevel@tonic-gate 				(void) memmove(&so_gate.sin.sin_addr,
1065*7c478bd9Sstevel@tonic-gate 				    hp->h_addr_list[attempts], hp->h_length);
1066*7c478bd9Sstevel@tonic-gate 				continue;
1067*7c478bd9Sstevel@tonic-gate 			case AF_INET6:
1068*7c478bd9Sstevel@tonic-gate 				(void) memmove(&so_gate.sin6.sin6_addr,
1069*7c478bd9Sstevel@tonic-gate 				    hp->h_addr_list[attempts], hp->h_length);
1070*7c478bd9Sstevel@tonic-gate 				continue;
1071*7c478bd9Sstevel@tonic-gate 			}
1072*7c478bd9Sstevel@tonic-gate 		}
1073*7c478bd9Sstevel@tonic-gate 		break;
1074*7c478bd9Sstevel@tonic-gate 	}
1075*7c478bd9Sstevel@tonic-gate 	oerrno = errno;
1076*7c478bd9Sstevel@tonic-gate 	if (*cmd != 'g') {
1077*7c478bd9Sstevel@tonic-gate 		(void) printf("%s %s %s", cmd, ishost ? "host" : "net", dest);
1078*7c478bd9Sstevel@tonic-gate 		if (*gateway != '\0') {
1079*7c478bd9Sstevel@tonic-gate 			switch (af) {
1080*7c478bd9Sstevel@tonic-gate 			case AF_INET:
1081*7c478bd9Sstevel@tonic-gate 				if (nflag) {
1082*7c478bd9Sstevel@tonic-gate 					(void) printf(": gateway %s",
1083*7c478bd9Sstevel@tonic-gate 					    inet_ntoa(so_gate.sin.sin_addr));
1084*7c478bd9Sstevel@tonic-gate 				} else if (attempts > 1 && ret == 0) {
1085*7c478bd9Sstevel@tonic-gate 					(void) printf(": gateway %s (%s)",
1086*7c478bd9Sstevel@tonic-gate 					    gateway,
1087*7c478bd9Sstevel@tonic-gate 					    inet_ntoa(so_gate.sin.sin_addr));
1088*7c478bd9Sstevel@tonic-gate 				} else {
1089*7c478bd9Sstevel@tonic-gate 					(void) printf(": gateway %s", gateway);
1090*7c478bd9Sstevel@tonic-gate 				}
1091*7c478bd9Sstevel@tonic-gate 				break;
1092*7c478bd9Sstevel@tonic-gate 			case AF_INET6:
1093*7c478bd9Sstevel@tonic-gate 				if (inet_ntop(AF_INET6,
1094*7c478bd9Sstevel@tonic-gate 				    (void *)&so_gate.sin6.sin6_addr, obuf,
1095*7c478bd9Sstevel@tonic-gate 				    INET6_ADDRSTRLEN) != NULL) {
1096*7c478bd9Sstevel@tonic-gate 					if (nflag) {
1097*7c478bd9Sstevel@tonic-gate 						(void) printf(": gateway %s",
1098*7c478bd9Sstevel@tonic-gate 						    obuf);
1099*7c478bd9Sstevel@tonic-gate 					} else if (attempts > 1 && ret == 0) {
1100*7c478bd9Sstevel@tonic-gate 						(void) printf(": gateway %s "
1101*7c478bd9Sstevel@tonic-gate 						    "(%s)",
1102*7c478bd9Sstevel@tonic-gate 						    gateway, obuf);
1103*7c478bd9Sstevel@tonic-gate 					}
1104*7c478bd9Sstevel@tonic-gate 					break;
1105*7c478bd9Sstevel@tonic-gate 				}
1106*7c478bd9Sstevel@tonic-gate 				/* FALLTHROUGH */
1107*7c478bd9Sstevel@tonic-gate 			default:
1108*7c478bd9Sstevel@tonic-gate 				(void) printf(": gateway %s", gateway);
1109*7c478bd9Sstevel@tonic-gate 				break;
1110*7c478bd9Sstevel@tonic-gate 			}
1111*7c478bd9Sstevel@tonic-gate 		}
1112*7c478bd9Sstevel@tonic-gate 		if (ret == 0)
1113*7c478bd9Sstevel@tonic-gate 			(void) printf("\n");
1114*7c478bd9Sstevel@tonic-gate 	}
1115*7c478bd9Sstevel@tonic-gate 	if (ret != 0) {
1116*7c478bd9Sstevel@tonic-gate 		if (*cmd == 'g') {
1117*7c478bd9Sstevel@tonic-gate 			if (nflag) {
1118*7c478bd9Sstevel@tonic-gate 				switch (af) {
1119*7c478bd9Sstevel@tonic-gate 				case AF_INET:
1120*7c478bd9Sstevel@tonic-gate 					(void) printf(" %s",
1121*7c478bd9Sstevel@tonic-gate 					    inet_ntoa(so_dst.sin.sin_addr));
1122*7c478bd9Sstevel@tonic-gate 					break;
1123*7c478bd9Sstevel@tonic-gate 				case AF_INET6:
1124*7c478bd9Sstevel@tonic-gate 					if (inet_ntop(AF_INET6,
1125*7c478bd9Sstevel@tonic-gate 					    (void *)&so_dst.sin6.sin6_addr,
1126*7c478bd9Sstevel@tonic-gate 					    obuf, INET6_ADDRSTRLEN) != NULL) {
1127*7c478bd9Sstevel@tonic-gate 						(void) printf(" %s", obuf);
1128*7c478bd9Sstevel@tonic-gate 						break;
1129*7c478bd9Sstevel@tonic-gate 					}
1130*7c478bd9Sstevel@tonic-gate 					/* FALLTHROUGH */
1131*7c478bd9Sstevel@tonic-gate 				default:
1132*7c478bd9Sstevel@tonic-gate 					(void) printf("%s", dest);
1133*7c478bd9Sstevel@tonic-gate 					break;
1134*7c478bd9Sstevel@tonic-gate 				}
1135*7c478bd9Sstevel@tonic-gate 			} else {
1136*7c478bd9Sstevel@tonic-gate 				(void) printf("%s", dest);
1137*7c478bd9Sstevel@tonic-gate 			}
1138*7c478bd9Sstevel@tonic-gate 		}
1139*7c478bd9Sstevel@tonic-gate 		switch (oerrno) {
1140*7c478bd9Sstevel@tonic-gate 		case ESRCH:
1141*7c478bd9Sstevel@tonic-gate 			err = "not in table";
1142*7c478bd9Sstevel@tonic-gate 			break;
1143*7c478bd9Sstevel@tonic-gate 		case EBUSY:
1144*7c478bd9Sstevel@tonic-gate 			err = "entry in use";
1145*7c478bd9Sstevel@tonic-gate 			break;
1146*7c478bd9Sstevel@tonic-gate 		case ENOBUFS:
1147*7c478bd9Sstevel@tonic-gate 			err = "routing table overflow";
1148*7c478bd9Sstevel@tonic-gate 			break;
1149*7c478bd9Sstevel@tonic-gate 		case EEXIST:
1150*7c478bd9Sstevel@tonic-gate 			err = "entry exists";
1151*7c478bd9Sstevel@tonic-gate 			break;
1152*7c478bd9Sstevel@tonic-gate 		case EPERM:
1153*7c478bd9Sstevel@tonic-gate 			err = "insufficient privileges";
1154*7c478bd9Sstevel@tonic-gate 			break;
1155*7c478bd9Sstevel@tonic-gate 		default:
1156*7c478bd9Sstevel@tonic-gate 			err = strerror(oerrno);
1157*7c478bd9Sstevel@tonic-gate 			break;
1158*7c478bd9Sstevel@tonic-gate 		}
1159*7c478bd9Sstevel@tonic-gate 		(void) printf(": %s\n", err);
1160*7c478bd9Sstevel@tonic-gate 	}
1161*7c478bd9Sstevel@tonic-gate 	/*
1162*7c478bd9Sstevel@tonic-gate 	 * In the case of AF_INET6, one of the getipnodebyX() functions was used
1163*7c478bd9Sstevel@tonic-gate 	 * so free the allocated hostent.
1164*7c478bd9Sstevel@tonic-gate 	 */
1165*7c478bd9Sstevel@tonic-gate 	if (af == AF_INET6 && hp != NULL)
1166*7c478bd9Sstevel@tonic-gate 		freehostent(hp);
1167*7c478bd9Sstevel@tonic-gate 
1168*7c478bd9Sstevel@tonic-gate 	return (oerrno);
1169*7c478bd9Sstevel@tonic-gate }
1170*7c478bd9Sstevel@tonic-gate 
1171*7c478bd9Sstevel@tonic-gate 
1172*7c478bd9Sstevel@tonic-gate /*
1173*7c478bd9Sstevel@tonic-gate  * Convert a network number to the corresponding IP address.
1174*7c478bd9Sstevel@tonic-gate  * If the RTA_NETMASK hasn't been specified yet set it based
1175*7c478bd9Sstevel@tonic-gate  * on the class of address.
1176*7c478bd9Sstevel@tonic-gate  */
1177*7c478bd9Sstevel@tonic-gate static void
1178*7c478bd9Sstevel@tonic-gate inet_makenetandmask(in_addr_t net, struct sockaddr_in *sin)
1179*7c478bd9Sstevel@tonic-gate {
1180*7c478bd9Sstevel@tonic-gate 	in_addr_t addr, mask;
1181*7c478bd9Sstevel@tonic-gate 	char *cp;
1182*7c478bd9Sstevel@tonic-gate 
1183*7c478bd9Sstevel@tonic-gate 	if (net == 0) {
1184*7c478bd9Sstevel@tonic-gate 		mask = addr = 0;
1185*7c478bd9Sstevel@tonic-gate 	} else if (net < 128) {
1186*7c478bd9Sstevel@tonic-gate 		addr = net << IN_CLASSA_NSHIFT;
1187*7c478bd9Sstevel@tonic-gate 		mask = IN_CLASSA_NET;
1188*7c478bd9Sstevel@tonic-gate 	} else if (net < 65536) {
1189*7c478bd9Sstevel@tonic-gate 		addr = net << IN_CLASSB_NSHIFT;
1190*7c478bd9Sstevel@tonic-gate 		mask = IN_CLASSB_NET;
1191*7c478bd9Sstevel@tonic-gate 	} else if (net < 16777216L) {
1192*7c478bd9Sstevel@tonic-gate 		addr = net << IN_CLASSC_NSHIFT;
1193*7c478bd9Sstevel@tonic-gate 		mask = IN_CLASSC_NET;
1194*7c478bd9Sstevel@tonic-gate 	} else {
1195*7c478bd9Sstevel@tonic-gate 		addr = net;
1196*7c478bd9Sstevel@tonic-gate 		if ((addr & IN_CLASSA_HOST) == 0)
1197*7c478bd9Sstevel@tonic-gate 			mask =  IN_CLASSA_NET;
1198*7c478bd9Sstevel@tonic-gate 		else if ((addr & IN_CLASSB_HOST) == 0)
1199*7c478bd9Sstevel@tonic-gate 			mask =  IN_CLASSB_NET;
1200*7c478bd9Sstevel@tonic-gate 		else if ((addr & IN_CLASSC_HOST) == 0)
1201*7c478bd9Sstevel@tonic-gate 			mask =  IN_CLASSC_NET;
1202*7c478bd9Sstevel@tonic-gate 		else {
1203*7c478bd9Sstevel@tonic-gate 			if (IN_CLASSA(addr))
1204*7c478bd9Sstevel@tonic-gate 				mask =  IN_CLASSA_NET;
1205*7c478bd9Sstevel@tonic-gate 			else if (IN_CLASSB(addr))
1206*7c478bd9Sstevel@tonic-gate 				mask =  IN_CLASSB_NET;
1207*7c478bd9Sstevel@tonic-gate 			else if (IN_CLASSC(addr))
1208*7c478bd9Sstevel@tonic-gate 				mask =  IN_CLASSC_NET;
1209*7c478bd9Sstevel@tonic-gate 			else
1210*7c478bd9Sstevel@tonic-gate 				mask = IP_HOST_MASK;
1211*7c478bd9Sstevel@tonic-gate 			mask = inet_makesubnetmask(addr, mask);
1212*7c478bd9Sstevel@tonic-gate 		}
1213*7c478bd9Sstevel@tonic-gate 	}
1214*7c478bd9Sstevel@tonic-gate 	sin->sin_addr.s_addr = htonl(addr);
1215*7c478bd9Sstevel@tonic-gate 
1216*7c478bd9Sstevel@tonic-gate 	if (!(rtm_addrs & RTA_NETMASK)) {
1217*7c478bd9Sstevel@tonic-gate 		rtm_addrs |= RTA_NETMASK;
1218*7c478bd9Sstevel@tonic-gate 		sin = &so_mask.sin;
1219*7c478bd9Sstevel@tonic-gate 		sin->sin_addr.s_addr = htonl(mask);
1220*7c478bd9Sstevel@tonic-gate 		sin->sin_family = AF_INET;
1221*7c478bd9Sstevel@tonic-gate 		cp = (char *)(&sin->sin_addr + 1);
1222*7c478bd9Sstevel@tonic-gate 		while (*--cp == 0 && cp > (char *)sin)
1223*7c478bd9Sstevel@tonic-gate 			;
1224*7c478bd9Sstevel@tonic-gate 	}
1225*7c478bd9Sstevel@tonic-gate }
1226*7c478bd9Sstevel@tonic-gate 
1227*7c478bd9Sstevel@tonic-gate static in_addr_t
1228*7c478bd9Sstevel@tonic-gate inet_makesubnetmask(in_addr_t addr, in_addr_t mask)
1229*7c478bd9Sstevel@tonic-gate {
1230*7c478bd9Sstevel@tonic-gate 	int n;
1231*7c478bd9Sstevel@tonic-gate 	struct ifconf ifc;
1232*7c478bd9Sstevel@tonic-gate 	struct ifreq ifreq;
1233*7c478bd9Sstevel@tonic-gate 	struct ifreq *ifr;
1234*7c478bd9Sstevel@tonic-gate 	struct sockaddr_in *sin;
1235*7c478bd9Sstevel@tonic-gate 	char *buf;
1236*7c478bd9Sstevel@tonic-gate 	int numifs;
1237*7c478bd9Sstevel@tonic-gate 	size_t bufsize;
1238*7c478bd9Sstevel@tonic-gate 	int iosoc;
1239*7c478bd9Sstevel@tonic-gate 	in_addr_t if_addr, if_mask;
1240*7c478bd9Sstevel@tonic-gate 	in_addr_t if_subnetmask = 0;
1241*7c478bd9Sstevel@tonic-gate 	short if_flags;
1242*7c478bd9Sstevel@tonic-gate 
1243*7c478bd9Sstevel@tonic-gate 	if (mask == 0)
1244*7c478bd9Sstevel@tonic-gate 		return (0);
1245*7c478bd9Sstevel@tonic-gate 	if ((iosoc = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
1246*7c478bd9Sstevel@tonic-gate 		quit("socket", errno);
1247*7c478bd9Sstevel@tonic-gate 	if (ioctl(iosoc, SIOCGIFNUM, (char *)&numifs) < 0)
1248*7c478bd9Sstevel@tonic-gate 		quit("ioctl", errno);
1249*7c478bd9Sstevel@tonic-gate 	bufsize = numifs * sizeof (struct ifreq);
1250*7c478bd9Sstevel@tonic-gate 	buf = malloc(bufsize);
1251*7c478bd9Sstevel@tonic-gate 	if (buf == NULL)
1252*7c478bd9Sstevel@tonic-gate 		quit("malloc", errno);
1253*7c478bd9Sstevel@tonic-gate 	(void) memset(&ifc, 0, sizeof (ifc));
1254*7c478bd9Sstevel@tonic-gate 	ifc.ifc_len = bufsize;
1255*7c478bd9Sstevel@tonic-gate 	ifc.ifc_buf = buf;
1256*7c478bd9Sstevel@tonic-gate 	if (ioctl(iosoc, SIOCGIFCONF, (char *)&ifc) < 0)
1257*7c478bd9Sstevel@tonic-gate 		quit("ioctl (get interface configuration)", errno);
1258*7c478bd9Sstevel@tonic-gate 	/* Let's check to see if this is maybe a local subnet route. */
1259*7c478bd9Sstevel@tonic-gate 	ifr = ifc.ifc_req;
1260*7c478bd9Sstevel@tonic-gate 	for (n = ifc.ifc_len / sizeof (struct ifreq); n > 0; n--, ifr++) {
1261*7c478bd9Sstevel@tonic-gate 		ifreq = *ifr;
1262*7c478bd9Sstevel@tonic-gate 		/* LINTED */
1263*7c478bd9Sstevel@tonic-gate 		sin = (struct sockaddr_in *)&ifr->ifr_addr;
1264*7c478bd9Sstevel@tonic-gate 		if_addr = ntohl(sin->sin_addr.s_addr);
1265*7c478bd9Sstevel@tonic-gate 
1266*7c478bd9Sstevel@tonic-gate 		if (ioctl(iosoc, SIOCGIFFLAGS, (char *)&ifreq) < 0)
1267*7c478bd9Sstevel@tonic-gate 			quit("ioctl (get interface flags)", errno);
1268*7c478bd9Sstevel@tonic-gate 		if ((ifreq.ifr_flags & IFF_UP) == 0)
1269*7c478bd9Sstevel@tonic-gate 			continue;
1270*7c478bd9Sstevel@tonic-gate 		if_flags = ifreq.ifr_flags;
1271*7c478bd9Sstevel@tonic-gate 
1272*7c478bd9Sstevel@tonic-gate 		if (ioctl(iosoc, SIOCGIFNETMASK, (char *)&ifreq) < 0)
1273*7c478bd9Sstevel@tonic-gate 			quit("ioctl (get netmask)", errno);
1274*7c478bd9Sstevel@tonic-gate 		/* LINTED */
1275*7c478bd9Sstevel@tonic-gate 		sin = (struct sockaddr_in *)&ifreq.ifr_addr;
1276*7c478bd9Sstevel@tonic-gate 		if_mask = ntohl(sin->sin_addr.s_addr);
1277*7c478bd9Sstevel@tonic-gate 		if ((if_addr & mask) == (addr & mask)) {
1278*7c478bd9Sstevel@tonic-gate 			/*
1279*7c478bd9Sstevel@tonic-gate 			 * Don't trust pt-pt interfaces if there are
1280*7c478bd9Sstevel@tonic-gate 			 * other interfaces.
1281*7c478bd9Sstevel@tonic-gate 			 */
1282*7c478bd9Sstevel@tonic-gate 			if (if_flags & IFF_POINTOPOINT) {
1283*7c478bd9Sstevel@tonic-gate 				if_subnetmask = if_mask;
1284*7c478bd9Sstevel@tonic-gate 				continue;
1285*7c478bd9Sstevel@tonic-gate 			}
1286*7c478bd9Sstevel@tonic-gate 			/*
1287*7c478bd9Sstevel@tonic-gate 			 * Fine.  Just assume the same net mask as the
1288*7c478bd9Sstevel@tonic-gate 			 * directly attached subnet interface is using.
1289*7c478bd9Sstevel@tonic-gate 			 */
1290*7c478bd9Sstevel@tonic-gate 			return (if_mask);
1291*7c478bd9Sstevel@tonic-gate 		}
1292*7c478bd9Sstevel@tonic-gate 	}
1293*7c478bd9Sstevel@tonic-gate 	if (if_subnetmask != 0)
1294*7c478bd9Sstevel@tonic-gate 		return (if_subnetmask);
1295*7c478bd9Sstevel@tonic-gate 	return (mask);
1296*7c478bd9Sstevel@tonic-gate }
1297*7c478bd9Sstevel@tonic-gate 
1298*7c478bd9Sstevel@tonic-gate /*
1299*7c478bd9Sstevel@tonic-gate  * Interpret an argument as a network address of some kind,
1300*7c478bd9Sstevel@tonic-gate  * returning B_TRUE if a host address, B_FALSE if a network address.
1301*7c478bd9Sstevel@tonic-gate  *
1302*7c478bd9Sstevel@tonic-gate  * If the address family is one looked up in getaddr() using one of the
1303*7c478bd9Sstevel@tonic-gate  * getipnodebyX() functions (currently only AF_INET6), then callers should
1304*7c478bd9Sstevel@tonic-gate  * freehostent() the returned "struct hostent" pointer if one was passed in.
1305*7c478bd9Sstevel@tonic-gate  */
1306*7c478bd9Sstevel@tonic-gate static boolean_t
1307*7c478bd9Sstevel@tonic-gate getaddr(int which, char *s, struct hostent **hpp)
1308*7c478bd9Sstevel@tonic-gate {
1309*7c478bd9Sstevel@tonic-gate 	sup su;
1310*7c478bd9Sstevel@tonic-gate 	struct hostent *hp;
1311*7c478bd9Sstevel@tonic-gate 	boolean_t ret;
1312*7c478bd9Sstevel@tonic-gate 
1313*7c478bd9Sstevel@tonic-gate 	if (s == NULL) {
1314*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
1315*7c478bd9Sstevel@tonic-gate 		    gettext("route: argument required following keyword\n"));
1316*7c478bd9Sstevel@tonic-gate 		usage((char *)NULL);
1317*7c478bd9Sstevel@tonic-gate 	}
1318*7c478bd9Sstevel@tonic-gate 	if (hpp == NULL)
1319*7c478bd9Sstevel@tonic-gate 		hpp = &hp;
1320*7c478bd9Sstevel@tonic-gate 	*hpp = NULL;
1321*7c478bd9Sstevel@tonic-gate 	rtm_addrs |= which;
1322*7c478bd9Sstevel@tonic-gate 	switch (which) {
1323*7c478bd9Sstevel@tonic-gate 	case RTA_DST:
1324*7c478bd9Sstevel@tonic-gate 		su = &so_dst;
1325*7c478bd9Sstevel@tonic-gate 		su->sa.sa_family = af;
1326*7c478bd9Sstevel@tonic-gate 		break;
1327*7c478bd9Sstevel@tonic-gate 	case RTA_GATEWAY:
1328*7c478bd9Sstevel@tonic-gate 		su = &so_gate;
1329*7c478bd9Sstevel@tonic-gate 		su->sa.sa_family = af;
1330*7c478bd9Sstevel@tonic-gate 		break;
1331*7c478bd9Sstevel@tonic-gate 	case RTA_NETMASK:
1332*7c478bd9Sstevel@tonic-gate 		su = &so_mask;
1333*7c478bd9Sstevel@tonic-gate 		su->sa.sa_family = af;
1334*7c478bd9Sstevel@tonic-gate 		break;
1335*7c478bd9Sstevel@tonic-gate 	case RTA_IFP:
1336*7c478bd9Sstevel@tonic-gate 		so_ifp.sdl.sdl_index = if_nametoindex(s);
1337*7c478bd9Sstevel@tonic-gate 		if (so_ifp.sdl.sdl_index == 0) {
1338*7c478bd9Sstevel@tonic-gate 			if (errno == ENXIO) {
1339*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
1340*7c478bd9Sstevel@tonic-gate 				    gettext("route: %s: no such interface\n"),
1341*7c478bd9Sstevel@tonic-gate 					s);
1342*7c478bd9Sstevel@tonic-gate 				exit(1);
1343*7c478bd9Sstevel@tonic-gate 			} else {
1344*7c478bd9Sstevel@tonic-gate 				quit("if_nametoindex", errno);
1345*7c478bd9Sstevel@tonic-gate 			}
1346*7c478bd9Sstevel@tonic-gate 		}
1347*7c478bd9Sstevel@tonic-gate 		so_ifp.sdl.sdl_family = AF_LINK;
1348*7c478bd9Sstevel@tonic-gate 		return (B_FALSE);
1349*7c478bd9Sstevel@tonic-gate 		/*
1350*7c478bd9Sstevel@tonic-gate 		 * RTA_SRC has overloaded meaning. It can represent the
1351*7c478bd9Sstevel@tonic-gate 		 * src address of incoming or outgoing packets.
1352*7c478bd9Sstevel@tonic-gate 		 */
1353*7c478bd9Sstevel@tonic-gate 	case RTA_IFA:
1354*7c478bd9Sstevel@tonic-gate 		su = &so_ifa;
1355*7c478bd9Sstevel@tonic-gate 		su->sa.sa_family = af;
1356*7c478bd9Sstevel@tonic-gate 		break;
1357*7c478bd9Sstevel@tonic-gate 	case RTA_SRC:
1358*7c478bd9Sstevel@tonic-gate 		su = &so_src;
1359*7c478bd9Sstevel@tonic-gate 		su->sa.sa_family = af;
1360*7c478bd9Sstevel@tonic-gate 		break;
1361*7c478bd9Sstevel@tonic-gate 	default:
1362*7c478bd9Sstevel@tonic-gate 		/* NOTREACHED */
1363*7c478bd9Sstevel@tonic-gate 		quit(gettext("Internal Error"), EINVAL);
1364*7c478bd9Sstevel@tonic-gate 		/* NOTREACHED */
1365*7c478bd9Sstevel@tonic-gate 	}
1366*7c478bd9Sstevel@tonic-gate 	if (strcmp(s, "default") == 0) {
1367*7c478bd9Sstevel@tonic-gate 		if (which == RTA_DST) {
1368*7c478bd9Sstevel@tonic-gate 			forcenet = B_TRUE;
1369*7c478bd9Sstevel@tonic-gate 			(void) getaddr(RTA_NETMASK, s, NULL);
1370*7c478bd9Sstevel@tonic-gate 		}
1371*7c478bd9Sstevel@tonic-gate 		if (which == RTA_SRC) {
1372*7c478bd9Sstevel@tonic-gate 			return (B_TRUE);
1373*7c478bd9Sstevel@tonic-gate 		}
1374*7c478bd9Sstevel@tonic-gate 		return (B_FALSE);
1375*7c478bd9Sstevel@tonic-gate 	}
1376*7c478bd9Sstevel@tonic-gate 	switch (af) {
1377*7c478bd9Sstevel@tonic-gate 	case AF_LINK:
1378*7c478bd9Sstevel@tonic-gate 		link_addr(s, &su->sdl);
1379*7c478bd9Sstevel@tonic-gate 		return (B_TRUE);
1380*7c478bd9Sstevel@tonic-gate 	case PF_ROUTE:
1381*7c478bd9Sstevel@tonic-gate 		sockaddr(s, &su->sa);
1382*7c478bd9Sstevel@tonic-gate 		return (B_TRUE);
1383*7c478bd9Sstevel@tonic-gate 	case AF_INET6:
1384*7c478bd9Sstevel@tonic-gate 		switch (which) {
1385*7c478bd9Sstevel@tonic-gate 		case RTA_DST:
1386*7c478bd9Sstevel@tonic-gate 			if (s[0] == '/') {
1387*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
1388*7c478bd9Sstevel@tonic-gate 				    gettext("route: %s: unexpected '/'\n"), s);
1389*7c478bd9Sstevel@tonic-gate 				exit(1);
1390*7c478bd9Sstevel@tonic-gate 			}
1391*7c478bd9Sstevel@tonic-gate 			ret = in6_getaddr(s, &su->sin6, &masklen, hpp);
1392*7c478bd9Sstevel@tonic-gate 			switch (masklen) {
1393*7c478bd9Sstevel@tonic-gate 			case NO_PREFIX:
1394*7c478bd9Sstevel@tonic-gate 				/* Nothing there - ok */
1395*7c478bd9Sstevel@tonic-gate 				return (ret);
1396*7c478bd9Sstevel@tonic-gate 			case BAD_ADDR:
1397*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
1398*7c478bd9Sstevel@tonic-gate 				    gettext("route: bad prefix length in %s\n"),
1399*7c478bd9Sstevel@tonic-gate 					s);
1400*7c478bd9Sstevel@tonic-gate 				exit(1);
1401*7c478bd9Sstevel@tonic-gate 				/* NOTREACHED */
1402*7c478bd9Sstevel@tonic-gate 			default:
1403*7c478bd9Sstevel@tonic-gate 				(void) memset(&so_mask.sin6.sin6_addr, 0,
1404*7c478bd9Sstevel@tonic-gate 				    sizeof (so_mask.sin6.sin6_addr));
1405*7c478bd9Sstevel@tonic-gate 				if (!in_prefixlentomask(masklen, IPV6_ABITS,
1406*7c478bd9Sstevel@tonic-gate 				    (uchar_t *)&so_mask.sin6.sin6_addr)) {
1407*7c478bd9Sstevel@tonic-gate 					(void) fprintf(stderr,
1408*7c478bd9Sstevel@tonic-gate 					    gettext("route: bad prefix length: "
1409*7c478bd9Sstevel@tonic-gate 					    "%d\n"), masklen);
1410*7c478bd9Sstevel@tonic-gate 					exit(1);
1411*7c478bd9Sstevel@tonic-gate 				}
1412*7c478bd9Sstevel@tonic-gate 				break;
1413*7c478bd9Sstevel@tonic-gate 			}
1414*7c478bd9Sstevel@tonic-gate 			so_mask.sin6.sin6_family = af;
1415*7c478bd9Sstevel@tonic-gate 			rtm_addrs |= RTA_NETMASK;
1416*7c478bd9Sstevel@tonic-gate 			return (ret);
1417*7c478bd9Sstevel@tonic-gate 		case RTA_GATEWAY:
1418*7c478bd9Sstevel@tonic-gate 		case RTA_IFA:
1419*7c478bd9Sstevel@tonic-gate 		case RTA_SRC:
1420*7c478bd9Sstevel@tonic-gate 			ret = in6_getaddr(s, &su->sin6, NULL, hpp);
1421*7c478bd9Sstevel@tonic-gate 			return (ret);
1422*7c478bd9Sstevel@tonic-gate 		case RTA_NETMASK:
1423*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
1424*7c478bd9Sstevel@tonic-gate 			    gettext("route: -netmask not supported for IPv6: "
1425*7c478bd9Sstevel@tonic-gate 			    "use <prefix>/<prefix-length> instead"));
1426*7c478bd9Sstevel@tonic-gate 			exit(1);
1427*7c478bd9Sstevel@tonic-gate 			/* NOTREACHED */
1428*7c478bd9Sstevel@tonic-gate 		default:
1429*7c478bd9Sstevel@tonic-gate 			quit(gettext("Internal Error"), EINVAL);
1430*7c478bd9Sstevel@tonic-gate 			/* NOTREACHED */
1431*7c478bd9Sstevel@tonic-gate 		}
1432*7c478bd9Sstevel@tonic-gate 	case AF_INET:
1433*7c478bd9Sstevel@tonic-gate 		switch (which) {
1434*7c478bd9Sstevel@tonic-gate 		case RTA_DST:
1435*7c478bd9Sstevel@tonic-gate 			if (s[0] == '/') {
1436*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
1437*7c478bd9Sstevel@tonic-gate 				    gettext("route: %s: unexpected '/'\n"), s);
1438*7c478bd9Sstevel@tonic-gate 				exit(1);
1439*7c478bd9Sstevel@tonic-gate 			}
1440*7c478bd9Sstevel@tonic-gate 			ret = in_getaddr(s, &su->sin, &masklen, which, hpp);
1441*7c478bd9Sstevel@tonic-gate 			switch (masklen) {
1442*7c478bd9Sstevel@tonic-gate 			case NO_PREFIX:
1443*7c478bd9Sstevel@tonic-gate 				/* Nothing there - ok */
1444*7c478bd9Sstevel@tonic-gate 				return (ret);
1445*7c478bd9Sstevel@tonic-gate 			case BAD_ADDR:
1446*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
1447*7c478bd9Sstevel@tonic-gate 				    gettext("route: bad prefix length in %s\n"),
1448*7c478bd9Sstevel@tonic-gate 					    s);
1449*7c478bd9Sstevel@tonic-gate 				exit(1);
1450*7c478bd9Sstevel@tonic-gate 				/* NOTREACHED */
1451*7c478bd9Sstevel@tonic-gate 			default:
1452*7c478bd9Sstevel@tonic-gate 				(void) memset(&so_mask.sin.sin_addr, 0,
1453*7c478bd9Sstevel@tonic-gate 				    sizeof (so_mask.sin.sin_addr));
1454*7c478bd9Sstevel@tonic-gate 				if (!in_prefixlentomask(masklen, IP_ABITS,
1455*7c478bd9Sstevel@tonic-gate 				    (uchar_t *)&so_mask.sin.sin_addr)) {
1456*7c478bd9Sstevel@tonic-gate 					(void) fprintf(stderr,
1457*7c478bd9Sstevel@tonic-gate 					    gettext("route: bad prefix length: "
1458*7c478bd9Sstevel@tonic-gate 					    "%d\n"), masklen);
1459*7c478bd9Sstevel@tonic-gate 					exit(1);
1460*7c478bd9Sstevel@tonic-gate 				}
1461*7c478bd9Sstevel@tonic-gate 				break;
1462*7c478bd9Sstevel@tonic-gate 			}
1463*7c478bd9Sstevel@tonic-gate 			so_mask.sin.sin_family = af;
1464*7c478bd9Sstevel@tonic-gate 			rtm_addrs |= RTA_NETMASK;
1465*7c478bd9Sstevel@tonic-gate 			return (ret);
1466*7c478bd9Sstevel@tonic-gate 		case RTA_GATEWAY:
1467*7c478bd9Sstevel@tonic-gate 		case RTA_IFA:
1468*7c478bd9Sstevel@tonic-gate 		case RTA_NETMASK:
1469*7c478bd9Sstevel@tonic-gate 		case RTA_SRC:
1470*7c478bd9Sstevel@tonic-gate 			ret = in_getaddr(s, &su->sin, NULL, which, hpp);
1471*7c478bd9Sstevel@tonic-gate 			return (ret);
1472*7c478bd9Sstevel@tonic-gate 		default:
1473*7c478bd9Sstevel@tonic-gate 			quit(gettext("Internal Error"), EINVAL);
1474*7c478bd9Sstevel@tonic-gate 			/* NOTREACHED */
1475*7c478bd9Sstevel@tonic-gate 		}
1476*7c478bd9Sstevel@tonic-gate 	default:
1477*7c478bd9Sstevel@tonic-gate 		quit(gettext("Internal Error"), EINVAL);
1478*7c478bd9Sstevel@tonic-gate 		/* NOTREACHED */
1479*7c478bd9Sstevel@tonic-gate 	}
1480*7c478bd9Sstevel@tonic-gate 
1481*7c478bd9Sstevel@tonic-gate }
1482*7c478bd9Sstevel@tonic-gate 
1483*7c478bd9Sstevel@tonic-gate /*
1484*7c478bd9Sstevel@tonic-gate  * Interpret an argument as an IPv4 network address of some kind,
1485*7c478bd9Sstevel@tonic-gate  * returning B_TRUE if a host address, B_FALSE if a network address.
1486*7c478bd9Sstevel@tonic-gate  * Note that this *always* tries host interpretation before network
1487*7c478bd9Sstevel@tonic-gate  * interpretation.
1488*7c478bd9Sstevel@tonic-gate  *
1489*7c478bd9Sstevel@tonic-gate  * If the plenp argument is non-NULL, allow <addr>/<n> syntax and
1490*7c478bd9Sstevel@tonic-gate  * pass out <n> in *plenp.
1491*7c478bd9Sstevel@tonic-gate  * If <n> doesn't parse return BAD_ADDR as *plenp.
1492*7c478bd9Sstevel@tonic-gate  * If no /<n> is present return NO_PREFIX as *plenp.
1493*7c478bd9Sstevel@tonic-gate  */
1494*7c478bd9Sstevel@tonic-gate static boolean_t
1495*7c478bd9Sstevel@tonic-gate in_getaddr(char *s, struct sockaddr_in *sin, int *plenp, int which,
1496*7c478bd9Sstevel@tonic-gate     struct hostent **hpp)
1497*7c478bd9Sstevel@tonic-gate {
1498*7c478bd9Sstevel@tonic-gate 	struct hostent *hp;
1499*7c478bd9Sstevel@tonic-gate 	struct netent *np;
1500*7c478bd9Sstevel@tonic-gate 	in_addr_t val;
1501*7c478bd9Sstevel@tonic-gate 	char str[BUFSIZ];
1502*7c478bd9Sstevel@tonic-gate 
1503*7c478bd9Sstevel@tonic-gate 	(void) strncpy(str, s, sizeof (str));
1504*7c478bd9Sstevel@tonic-gate 
1505*7c478bd9Sstevel@tonic-gate 	/*
1506*7c478bd9Sstevel@tonic-gate 	 * Look for '/'<n> is plenp
1507*7c478bd9Sstevel@tonic-gate 	 */
1508*7c478bd9Sstevel@tonic-gate 	if (plenp != NULL) {
1509*7c478bd9Sstevel@tonic-gate 		char *cp;
1510*7c478bd9Sstevel@tonic-gate 
1511*7c478bd9Sstevel@tonic-gate 		*plenp = in_getprefixlen(str, IP_ABITS);
1512*7c478bd9Sstevel@tonic-gate 		if (*plenp == BAD_ADDR)
1513*7c478bd9Sstevel@tonic-gate 			return (B_FALSE);
1514*7c478bd9Sstevel@tonic-gate 		cp = strchr(str, '/');
1515*7c478bd9Sstevel@tonic-gate 		if (cp != NULL)
1516*7c478bd9Sstevel@tonic-gate 			*cp = '\0';
1517*7c478bd9Sstevel@tonic-gate 	} else if (strchr(str, '/') != NULL) {
1518*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("route: %s: unexpected '/'\n"),
1519*7c478bd9Sstevel@tonic-gate 			str);
1520*7c478bd9Sstevel@tonic-gate 		exit(1);
1521*7c478bd9Sstevel@tonic-gate 	}
1522*7c478bd9Sstevel@tonic-gate 
1523*7c478bd9Sstevel@tonic-gate 	(void) memset(sin, 0, sizeof (*sin));
1524*7c478bd9Sstevel@tonic-gate 	sin->sin_family = AF_INET;
1525*7c478bd9Sstevel@tonic-gate 
1526*7c478bd9Sstevel@tonic-gate 	/*
1527*7c478bd9Sstevel@tonic-gate 	 * Note: only the route destination can be a network, so we treat
1528*7c478bd9Sstevel@tonic-gate 	 * all other addresses as though "-net" was not specified.
1529*7c478bd9Sstevel@tonic-gate 	 */
1530*7c478bd9Sstevel@tonic-gate 	if ((((val = inet_addr(str)) != (in_addr_t)-1) ||
1531*7c478bd9Sstevel@tonic-gate 	    strcmp(str, "255.255.255.255") == 0) &&
1532*7c478bd9Sstevel@tonic-gate 	    (which != RTA_DST || !forcenet)) {
1533*7c478bd9Sstevel@tonic-gate 		sin->sin_addr.s_addr = val;
1534*7c478bd9Sstevel@tonic-gate 		if (inet_lnaof(sin->sin_addr) != INADDR_ANY ||
1535*7c478bd9Sstevel@tonic-gate 		    forcehost)
1536*7c478bd9Sstevel@tonic-gate 			return (B_TRUE);
1537*7c478bd9Sstevel@tonic-gate 		val = ntohl(val);
1538*7c478bd9Sstevel@tonic-gate 		if (which == RTA_DST)
1539*7c478bd9Sstevel@tonic-gate 			inet_makenetandmask(val, sin);
1540*7c478bd9Sstevel@tonic-gate 		return (B_FALSE);
1541*7c478bd9Sstevel@tonic-gate 	}
1542*7c478bd9Sstevel@tonic-gate 	if (!forcehost && (val = inet_network(str)) != (in_addr_t)-1) {
1543*7c478bd9Sstevel@tonic-gate 		if (which == RTA_DST)
1544*7c478bd9Sstevel@tonic-gate 			inet_makenetandmask(val, sin);
1545*7c478bd9Sstevel@tonic-gate 		return (B_FALSE);
1546*7c478bd9Sstevel@tonic-gate 	}
1547*7c478bd9Sstevel@tonic-gate 	if ((which != RTA_DST || !forcenet) &&
1548*7c478bd9Sstevel@tonic-gate 	    (hp = gethostbyname(str)) != NULL) {
1549*7c478bd9Sstevel@tonic-gate 		*hpp = hp;
1550*7c478bd9Sstevel@tonic-gate 		(void) memmove(&sin->sin_addr, hp->h_addr,
1551*7c478bd9Sstevel@tonic-gate 		    hp->h_length);
1552*7c478bd9Sstevel@tonic-gate 		return (B_TRUE);
1553*7c478bd9Sstevel@tonic-gate 	}
1554*7c478bd9Sstevel@tonic-gate 	if (!forcehost && (np = getnetbyname(str)) != NULL &&
1555*7c478bd9Sstevel@tonic-gate 	    (val = np->n_net) != 0) {
1556*7c478bd9Sstevel@tonic-gate 		if (which == RTA_DST)
1557*7c478bd9Sstevel@tonic-gate 			inet_makenetandmask(val, sin);
1558*7c478bd9Sstevel@tonic-gate 		return (B_FALSE);
1559*7c478bd9Sstevel@tonic-gate 	}
1560*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext("%s: bad value\n"), s);
1561*7c478bd9Sstevel@tonic-gate 	exit(1);
1562*7c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
1563*7c478bd9Sstevel@tonic-gate }
1564*7c478bd9Sstevel@tonic-gate 
1565*7c478bd9Sstevel@tonic-gate /*
1566*7c478bd9Sstevel@tonic-gate  * Interpret an argument as an IPv6 network address of some kind,
1567*7c478bd9Sstevel@tonic-gate  * returning B_TRUE if a host address, B_FALSE if a network address.
1568*7c478bd9Sstevel@tonic-gate  *
1569*7c478bd9Sstevel@tonic-gate  * If the last argument is non-NULL allow a <addr>/<n> syntax and
1570*7c478bd9Sstevel@tonic-gate  * pass out <n> in *plenp.
1571*7c478bd9Sstevel@tonic-gate  * If <n> doesn't parse return BAD_ADDR as *plenp.
1572*7c478bd9Sstevel@tonic-gate  * If no /<n> is present return NO_PREFIX as *plenp.
1573*7c478bd9Sstevel@tonic-gate  */
1574*7c478bd9Sstevel@tonic-gate static boolean_t
1575*7c478bd9Sstevel@tonic-gate in6_getaddr(char *s, struct sockaddr_in6 *sin6, int *plenp,
1576*7c478bd9Sstevel@tonic-gate     struct hostent **hpp)
1577*7c478bd9Sstevel@tonic-gate {
1578*7c478bd9Sstevel@tonic-gate 	struct hostent *hp;
1579*7c478bd9Sstevel@tonic-gate 	char str[BUFSIZ];
1580*7c478bd9Sstevel@tonic-gate 	int error_num;
1581*7c478bd9Sstevel@tonic-gate 
1582*7c478bd9Sstevel@tonic-gate 	(void) strncpy(str, s, sizeof (str));
1583*7c478bd9Sstevel@tonic-gate 
1584*7c478bd9Sstevel@tonic-gate 	/*
1585*7c478bd9Sstevel@tonic-gate 	 * Look for '/'<n> is plenp
1586*7c478bd9Sstevel@tonic-gate 	 */
1587*7c478bd9Sstevel@tonic-gate 	if (plenp != NULL) {
1588*7c478bd9Sstevel@tonic-gate 		char *cp;
1589*7c478bd9Sstevel@tonic-gate 
1590*7c478bd9Sstevel@tonic-gate 		*plenp = in_getprefixlen(str, IPV6_ABITS);
1591*7c478bd9Sstevel@tonic-gate 		if (*plenp == BAD_ADDR)
1592*7c478bd9Sstevel@tonic-gate 			return (B_FALSE);
1593*7c478bd9Sstevel@tonic-gate 		cp = strchr(str, '/');
1594*7c478bd9Sstevel@tonic-gate 		if (cp != NULL)
1595*7c478bd9Sstevel@tonic-gate 			*cp = '\0';
1596*7c478bd9Sstevel@tonic-gate 	} else if (strchr(str, '/') != NULL) {
1597*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("route: %s: unexpected '/'\n"),
1598*7c478bd9Sstevel@tonic-gate 			str);
1599*7c478bd9Sstevel@tonic-gate 		exit(1);
1600*7c478bd9Sstevel@tonic-gate 	}
1601*7c478bd9Sstevel@tonic-gate 
1602*7c478bd9Sstevel@tonic-gate 	(void) memset(sin6, 0, sizeof (struct sockaddr_in6));
1603*7c478bd9Sstevel@tonic-gate 	sin6->sin6_family = AF_INET6;
1604*7c478bd9Sstevel@tonic-gate 
1605*7c478bd9Sstevel@tonic-gate 	hp = getipnodebyname(str, AF_INET6, 0, &error_num);
1606*7c478bd9Sstevel@tonic-gate 	if (hp != NULL) {
1607*7c478bd9Sstevel@tonic-gate 		*hpp = hp;
1608*7c478bd9Sstevel@tonic-gate 		(void) memmove(&sin6->sin6_addr, hp->h_addr, hp->h_length);
1609*7c478bd9Sstevel@tonic-gate 		return (B_TRUE);
1610*7c478bd9Sstevel@tonic-gate 	}
1611*7c478bd9Sstevel@tonic-gate 	if (error_num == TRY_AGAIN) {
1612*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("route: %s: bad address (try "
1613*7c478bd9Sstevel@tonic-gate 		    "again later)\n"), s);
1614*7c478bd9Sstevel@tonic-gate 	} else {
1615*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("route: %s: bad address\n"), s);
1616*7c478bd9Sstevel@tonic-gate 	}
1617*7c478bd9Sstevel@tonic-gate 	exit(1);
1618*7c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
1619*7c478bd9Sstevel@tonic-gate }
1620*7c478bd9Sstevel@tonic-gate 
1621*7c478bd9Sstevel@tonic-gate /*
1622*7c478bd9Sstevel@tonic-gate  * If "slash" is zero this parses the whole string as
1623*7c478bd9Sstevel@tonic-gate  * an integer. With "slash" non zero it parses the tail part as an integer.
1624*7c478bd9Sstevel@tonic-gate  *
1625*7c478bd9Sstevel@tonic-gate  * If it is not a valid integer this returns BAD_ADDR.
1626*7c478bd9Sstevel@tonic-gate  * If there is /<n> present this returns NO_PREFIX.
1627*7c478bd9Sstevel@tonic-gate  */
1628*7c478bd9Sstevel@tonic-gate int
1629*7c478bd9Sstevel@tonic-gate in_getprefixlen(char *addr, int max_plen)
1630*7c478bd9Sstevel@tonic-gate {
1631*7c478bd9Sstevel@tonic-gate 	int prefixlen;
1632*7c478bd9Sstevel@tonic-gate 	char *str, *end;
1633*7c478bd9Sstevel@tonic-gate 
1634*7c478bd9Sstevel@tonic-gate 	str = strchr(addr, '/');
1635*7c478bd9Sstevel@tonic-gate 	if (str == NULL)
1636*7c478bd9Sstevel@tonic-gate 		return (NO_PREFIX);
1637*7c478bd9Sstevel@tonic-gate 	str++;
1638*7c478bd9Sstevel@tonic-gate 
1639*7c478bd9Sstevel@tonic-gate 	prefixlen = strtol(str, &end, 10);
1640*7c478bd9Sstevel@tonic-gate 	if (prefixlen < 0)
1641*7c478bd9Sstevel@tonic-gate 		return (BAD_ADDR);
1642*7c478bd9Sstevel@tonic-gate 	if (str == end)
1643*7c478bd9Sstevel@tonic-gate 		return (BAD_ADDR);
1644*7c478bd9Sstevel@tonic-gate 	if (max_plen != 0 && max_plen < prefixlen)
1645*7c478bd9Sstevel@tonic-gate 		return (BAD_ADDR);
1646*7c478bd9Sstevel@tonic-gate 	else
1647*7c478bd9Sstevel@tonic-gate 		return (prefixlen);
1648*7c478bd9Sstevel@tonic-gate }
1649*7c478bd9Sstevel@tonic-gate 
1650*7c478bd9Sstevel@tonic-gate /*
1651*7c478bd9Sstevel@tonic-gate  * Convert a prefix length to a mask.
1652*7c478bd9Sstevel@tonic-gate  * Returns B_TRUE if ok. B_FALSE otherwise.
1653*7c478bd9Sstevel@tonic-gate  * Assumes the mask array is zeroed by the caller.
1654*7c478bd9Sstevel@tonic-gate  */
1655*7c478bd9Sstevel@tonic-gate boolean_t
1656*7c478bd9Sstevel@tonic-gate in_prefixlentomask(int prefixlen, int maxlen, uchar_t *mask)
1657*7c478bd9Sstevel@tonic-gate {
1658*7c478bd9Sstevel@tonic-gate 	if (prefixlen < 0 || prefixlen > maxlen)
1659*7c478bd9Sstevel@tonic-gate 		return (B_FALSE);
1660*7c478bd9Sstevel@tonic-gate 
1661*7c478bd9Sstevel@tonic-gate 	while (prefixlen > 0) {
1662*7c478bd9Sstevel@tonic-gate 		if (prefixlen >= 8) {
1663*7c478bd9Sstevel@tonic-gate 			*mask++ = 0xFF;
1664*7c478bd9Sstevel@tonic-gate 			prefixlen -= 8;
1665*7c478bd9Sstevel@tonic-gate 			continue;
1666*7c478bd9Sstevel@tonic-gate 		}
1667*7c478bd9Sstevel@tonic-gate 		*mask |= 1 << (8 - prefixlen);
1668*7c478bd9Sstevel@tonic-gate 		prefixlen--;
1669*7c478bd9Sstevel@tonic-gate 	}
1670*7c478bd9Sstevel@tonic-gate 	return (B_TRUE);
1671*7c478bd9Sstevel@tonic-gate }
1672*7c478bd9Sstevel@tonic-gate 
1673*7c478bd9Sstevel@tonic-gate void
1674*7c478bd9Sstevel@tonic-gate rtmonitor(int argc, char *argv[])
1675*7c478bd9Sstevel@tonic-gate {
1676*7c478bd9Sstevel@tonic-gate 	int n;
1677*7c478bd9Sstevel@tonic-gate 	intmax_t msg[2048 / sizeof (intmax_t)];
1678*7c478bd9Sstevel@tonic-gate 
1679*7c478bd9Sstevel@tonic-gate 	if (tflag)
1680*7c478bd9Sstevel@tonic-gate 		exit(0);
1681*7c478bd9Sstevel@tonic-gate 	verbose = B_TRUE;
1682*7c478bd9Sstevel@tonic-gate 	if (argc > 1) {
1683*7c478bd9Sstevel@tonic-gate 		argv++;
1684*7c478bd9Sstevel@tonic-gate 		if (argc == 2 && **argv == '-') {
1685*7c478bd9Sstevel@tonic-gate 			switch (keyword(*argv + 1)) {
1686*7c478bd9Sstevel@tonic-gate 			case K_INET:
1687*7c478bd9Sstevel@tonic-gate 				af = AF_INET;
1688*7c478bd9Sstevel@tonic-gate 				break;
1689*7c478bd9Sstevel@tonic-gate 			case K_LINK:
1690*7c478bd9Sstevel@tonic-gate 				af = AF_LINK;
1691*7c478bd9Sstevel@tonic-gate 				break;
1692*7c478bd9Sstevel@tonic-gate 			case K_INET6:
1693*7c478bd9Sstevel@tonic-gate 				af = AF_INET6;
1694*7c478bd9Sstevel@tonic-gate 				break;
1695*7c478bd9Sstevel@tonic-gate 			default:
1696*7c478bd9Sstevel@tonic-gate 				usage(*argv);
1697*7c478bd9Sstevel@tonic-gate 				/* NOTREACHED */
1698*7c478bd9Sstevel@tonic-gate 			}
1699*7c478bd9Sstevel@tonic-gate 		} else {
1700*7c478bd9Sstevel@tonic-gate 			usage(*argv);
1701*7c478bd9Sstevel@tonic-gate 		}
1702*7c478bd9Sstevel@tonic-gate 		(void) close(s);
1703*7c478bd9Sstevel@tonic-gate 		s = socket(PF_ROUTE, SOCK_RAW, af);
1704*7c478bd9Sstevel@tonic-gate 		if (s < 0)
1705*7c478bd9Sstevel@tonic-gate 			quit("socket", errno);
1706*7c478bd9Sstevel@tonic-gate 	}
1707*7c478bd9Sstevel@tonic-gate 	for (;;) {
1708*7c478bd9Sstevel@tonic-gate 		n = read(s, msg, sizeof (msg));
1709*7c478bd9Sstevel@tonic-gate 		if (n <= 0)
1710*7c478bd9Sstevel@tonic-gate 			quit("read", errno);
1711*7c478bd9Sstevel@tonic-gate 		(void) printf("got message of size %d\n", n);
1712*7c478bd9Sstevel@tonic-gate 		print_rtmsg((struct rt_msghdr *)msg, n);
1713*7c478bd9Sstevel@tonic-gate 	}
1714*7c478bd9Sstevel@tonic-gate }
1715*7c478bd9Sstevel@tonic-gate 
1716*7c478bd9Sstevel@tonic-gate int
1717*7c478bd9Sstevel@tonic-gate rtmsg(int cmd, int flags)
1718*7c478bd9Sstevel@tonic-gate {
1719*7c478bd9Sstevel@tonic-gate 	static int seq;
1720*7c478bd9Sstevel@tonic-gate 	int rlen;
1721*7c478bd9Sstevel@tonic-gate 	char *cp = m_rtmsg.m_space;
1722*7c478bd9Sstevel@tonic-gate 	int l;
1723*7c478bd9Sstevel@tonic-gate 
1724*7c478bd9Sstevel@tonic-gate 	errno = 0;
1725*7c478bd9Sstevel@tonic-gate 	(void) memset(&m_rtmsg, 0, sizeof (m_rtmsg));
1726*7c478bd9Sstevel@tonic-gate 	if (cmd == 'a') {
1727*7c478bd9Sstevel@tonic-gate 		cmd = RTM_ADD;
1728*7c478bd9Sstevel@tonic-gate 	} else if (cmd == 'c') {
1729*7c478bd9Sstevel@tonic-gate 		cmd = RTM_CHANGE;
1730*7c478bd9Sstevel@tonic-gate 	} else if (cmd == 'g') {
1731*7c478bd9Sstevel@tonic-gate 		cmd = RTM_GET;
1732*7c478bd9Sstevel@tonic-gate 		if (so_ifp.sa.sa_family == 0) {
1733*7c478bd9Sstevel@tonic-gate 			so_ifp.sa.sa_family = AF_LINK;
1734*7c478bd9Sstevel@tonic-gate 			rtm_addrs |= RTA_IFP;
1735*7c478bd9Sstevel@tonic-gate 		}
1736*7c478bd9Sstevel@tonic-gate 	} else {
1737*7c478bd9Sstevel@tonic-gate 		cmd = RTM_DELETE;
1738*7c478bd9Sstevel@tonic-gate 	}
1739*7c478bd9Sstevel@tonic-gate #define	rtm m_rtmsg.m_rtm
1740*7c478bd9Sstevel@tonic-gate 	rtm.rtm_type = cmd;
1741*7c478bd9Sstevel@tonic-gate 	rtm.rtm_flags = flags;
1742*7c478bd9Sstevel@tonic-gate 	rtm.rtm_version = RTM_VERSION;
1743*7c478bd9Sstevel@tonic-gate 	rtm.rtm_seq = ++seq;
1744*7c478bd9Sstevel@tonic-gate 	rtm.rtm_addrs = rtm_addrs;
1745*7c478bd9Sstevel@tonic-gate 	rtm.rtm_rmx = rt_metrics;
1746*7c478bd9Sstevel@tonic-gate 	rtm.rtm_inits = rtm_inits;
1747*7c478bd9Sstevel@tonic-gate 
1748*7c478bd9Sstevel@tonic-gate #define	NEXTADDR(w, u) \
1749*7c478bd9Sstevel@tonic-gate 	if (rtm_addrs & (w)) { \
1750*7c478bd9Sstevel@tonic-gate 		l = ROUNDUP_LONG(salen(&u.sa)); \
1751*7c478bd9Sstevel@tonic-gate 		(void) memmove(cp, &(u), l); \
1752*7c478bd9Sstevel@tonic-gate 		cp += l; \
1753*7c478bd9Sstevel@tonic-gate 		if (verbose) \
1754*7c478bd9Sstevel@tonic-gate 			sodump(&(u), #u); \
1755*7c478bd9Sstevel@tonic-gate 	}
1756*7c478bd9Sstevel@tonic-gate 	NEXTADDR(RTA_DST, so_dst);
1757*7c478bd9Sstevel@tonic-gate 	NEXTADDR(RTA_GATEWAY, so_gate);
1758*7c478bd9Sstevel@tonic-gate 	NEXTADDR(RTA_NETMASK, so_mask);
1759*7c478bd9Sstevel@tonic-gate 	NEXTADDR(RTA_IFP, so_ifp);
1760*7c478bd9Sstevel@tonic-gate 	NEXTADDR(RTA_IFA, so_ifa);
1761*7c478bd9Sstevel@tonic-gate 	/*
1762*7c478bd9Sstevel@tonic-gate 	 * RTA_SRC has overloaded meaning. It can represent the
1763*7c478bd9Sstevel@tonic-gate 	 * src address of incoming or outgoing packets.
1764*7c478bd9Sstevel@tonic-gate 	 */
1765*7c478bd9Sstevel@tonic-gate 	NEXTADDR(RTA_SRC, so_src);
1766*7c478bd9Sstevel@tonic-gate #undef	NEXTADDR
1767*7c478bd9Sstevel@tonic-gate 	rtm.rtm_msglen = l = cp - (char *)&m_rtmsg;
1768*7c478bd9Sstevel@tonic-gate 	if (verbose)
1769*7c478bd9Sstevel@tonic-gate 		print_rtmsg(&rtm, l);
1770*7c478bd9Sstevel@tonic-gate 	if (debugonly)
1771*7c478bd9Sstevel@tonic-gate 		return (0);
1772*7c478bd9Sstevel@tonic-gate 	if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) {
1773*7c478bd9Sstevel@tonic-gate 		switch (errno) {
1774*7c478bd9Sstevel@tonic-gate 		case ESRCH:
1775*7c478bd9Sstevel@tonic-gate 		case EBUSY:
1776*7c478bd9Sstevel@tonic-gate 		case ENOBUFS:
1777*7c478bd9Sstevel@tonic-gate 		case EEXIST:
1778*7c478bd9Sstevel@tonic-gate 		case ENETUNREACH:
1779*7c478bd9Sstevel@tonic-gate 		case EHOSTUNREACH:
1780*7c478bd9Sstevel@tonic-gate 		case EPERM:
1781*7c478bd9Sstevel@tonic-gate 			break;
1782*7c478bd9Sstevel@tonic-gate 		default:
1783*7c478bd9Sstevel@tonic-gate 			perror(gettext("writing to routing socket"));
1784*7c478bd9Sstevel@tonic-gate 			break;
1785*7c478bd9Sstevel@tonic-gate 		}
1786*7c478bd9Sstevel@tonic-gate 		return (-1);
1787*7c478bd9Sstevel@tonic-gate 	} else if (rlen < (int)rtm.rtm_msglen) {
1788*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
1789*7c478bd9Sstevel@tonic-gate 		    gettext("route: write to routing socket got only %d for "
1790*7c478bd9Sstevel@tonic-gate 		    "len\n"), rlen);
1791*7c478bd9Sstevel@tonic-gate 		return (-1);
1792*7c478bd9Sstevel@tonic-gate 	}
1793*7c478bd9Sstevel@tonic-gate 	if (cmd == RTM_GET) {
1794*7c478bd9Sstevel@tonic-gate 		do {
1795*7c478bd9Sstevel@tonic-gate 			l = read(s, (char *)&m_rtmsg, sizeof (m_rtmsg));
1796*7c478bd9Sstevel@tonic-gate 		} while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid));
1797*7c478bd9Sstevel@tonic-gate 		if (l < 0) {
1798*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
1799*7c478bd9Sstevel@tonic-gate 			    gettext("route: read from routing socket: %s\n"),
1800*7c478bd9Sstevel@tonic-gate 			    strerror(errno));
1801*7c478bd9Sstevel@tonic-gate 		} else {
1802*7c478bd9Sstevel@tonic-gate 			print_getmsg(&rtm, l);
1803*7c478bd9Sstevel@tonic-gate 		}
1804*7c478bd9Sstevel@tonic-gate 	}
1805*7c478bd9Sstevel@tonic-gate #undef rtm
1806*7c478bd9Sstevel@tonic-gate 	return (0);
1807*7c478bd9Sstevel@tonic-gate }
1808*7c478bd9Sstevel@tonic-gate 
1809*7c478bd9Sstevel@tonic-gate static char *msgtypes[] = {
1810*7c478bd9Sstevel@tonic-gate 	"",
1811*7c478bd9Sstevel@tonic-gate 	"RTM_ADD: Add Route",
1812*7c478bd9Sstevel@tonic-gate 	"RTM_DELETE: Delete Route",
1813*7c478bd9Sstevel@tonic-gate 	"RTM_CHANGE: Change Metrics or flags",
1814*7c478bd9Sstevel@tonic-gate 	"RTM_GET: Report Metrics",
1815*7c478bd9Sstevel@tonic-gate 	"RTM_LOSING: Kernel Suspects Partitioning",
1816*7c478bd9Sstevel@tonic-gate 	"RTM_REDIRECT: Told to use different route",
1817*7c478bd9Sstevel@tonic-gate 	"RTM_MISS: Lookup failed on this address",
1818*7c478bd9Sstevel@tonic-gate 	"RTM_LOCK: fix specified metrics",
1819*7c478bd9Sstevel@tonic-gate 	"RTM_OLDADD: caused by SIOCADDRT",
1820*7c478bd9Sstevel@tonic-gate 	"RTM_OLDDEL: caused by SIOCDELRT",
1821*7c478bd9Sstevel@tonic-gate 	"RTM_RESOLVE: Route created by cloning",
1822*7c478bd9Sstevel@tonic-gate 	"RTM_NEWADDR: address being added to iface",
1823*7c478bd9Sstevel@tonic-gate 	"RTM_DELADDR: address being removed from iface",
1824*7c478bd9Sstevel@tonic-gate 	"RTM_IFINFO: iface status change",
1825*7c478bd9Sstevel@tonic-gate 	0,
1826*7c478bd9Sstevel@tonic-gate };
1827*7c478bd9Sstevel@tonic-gate 
1828*7c478bd9Sstevel@tonic-gate #define	NMSGTYPES (sizeof (msgtypes) / sizeof (msgtypes[0]))
1829*7c478bd9Sstevel@tonic-gate 
1830*7c478bd9Sstevel@tonic-gate static char metricnames[] =
1831*7c478bd9Sstevel@tonic-gate "\011pksent\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire\2hopcount"
1832*7c478bd9Sstevel@tonic-gate 	"\1mtu";
1833*7c478bd9Sstevel@tonic-gate static char routeflags[] =
1834*7c478bd9Sstevel@tonic-gate "\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE\010MASK_PRESENT"
1835*7c478bd9Sstevel@tonic-gate 	"\011CLONING\012XRESOLVE\013LLINFO\014STATIC\015BLACKHOLE"
1836*7c478bd9Sstevel@tonic-gate 	"\016PRIVATE\017PROTO2\020PROTO1\021MULTIRT\022SETSRC";
1837*7c478bd9Sstevel@tonic-gate static char ifnetflags[] =
1838*7c478bd9Sstevel@tonic-gate "\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6NOTRAILERS\7RUNNING\010NOARP"
1839*7c478bd9Sstevel@tonic-gate 	"\011PPROMISC\012ALLMULTI\013INTELLIGENT\014MULTICAST"
1840*7c478bd9Sstevel@tonic-gate 	"\015MULTI_BCAST\016UNNUMBERED\017DHCP\020PRIVATE"
1841*7c478bd9Sstevel@tonic-gate 	"\021NOXMIT\022NOLOCAL\023DEPRECATED\024ADDRCONF"
1842*7c478bd9Sstevel@tonic-gate 	"\025ROUTER\026NONUD\027ANYCAST\030NORTEXCH\031IPv4\032IPv6"
1843*7c478bd9Sstevel@tonic-gate 	"\033MIP\034NOFAILOVER\035FAILED\036STANDBY\037INACTIVE\040OFFLINE"
1844*7c478bd9Sstevel@tonic-gate 	"\041XRESOLV\042COS\043PREFERRED\044TEMPORARY";
1845*7c478bd9Sstevel@tonic-gate static char addrnames[] =
1846*7c478bd9Sstevel@tonic-gate "\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD\011SRC";
1847*7c478bd9Sstevel@tonic-gate 
1848*7c478bd9Sstevel@tonic-gate void
1849*7c478bd9Sstevel@tonic-gate print_rtmsg(struct rt_msghdr *rtm, int msglen)
1850*7c478bd9Sstevel@tonic-gate {
1851*7c478bd9Sstevel@tonic-gate 	struct if_msghdr *ifm;
1852*7c478bd9Sstevel@tonic-gate 	struct ifa_msghdr *ifam;
1853*7c478bd9Sstevel@tonic-gate 
1854*7c478bd9Sstevel@tonic-gate 	if (!verbose)
1855*7c478bd9Sstevel@tonic-gate 		return;
1856*7c478bd9Sstevel@tonic-gate 	if (rtm->rtm_version != RTM_VERSION) {
1857*7c478bd9Sstevel@tonic-gate 		(void) printf("routing message version %d not understood\n",
1858*7c478bd9Sstevel@tonic-gate 		    rtm->rtm_version);
1859*7c478bd9Sstevel@tonic-gate 		return;
1860*7c478bd9Sstevel@tonic-gate 	}
1861*7c478bd9Sstevel@tonic-gate 	if (rtm->rtm_msglen > (ushort_t)msglen) {
1862*7c478bd9Sstevel@tonic-gate 		(void) printf("message length mismatch, in packet %d, "
1863*7c478bd9Sstevel@tonic-gate 		    "returned %d\n",
1864*7c478bd9Sstevel@tonic-gate 		    rtm->rtm_msglen, msglen);
1865*7c478bd9Sstevel@tonic-gate 	}
1866*7c478bd9Sstevel@tonic-gate 	/*
1867*7c478bd9Sstevel@tonic-gate 	 * Since rtm->rtm_type is unsigned, we'll just check the case of zero
1868*7c478bd9Sstevel@tonic-gate 	 * and the upper-bound of (NMSGTYPES - 1).
1869*7c478bd9Sstevel@tonic-gate 	 */
1870*7c478bd9Sstevel@tonic-gate 	if (rtm->rtm_type == 0 || rtm->rtm_type >= (NMSGTYPES - 1)) {
1871*7c478bd9Sstevel@tonic-gate 		(void) printf("routing message type %d not understood\n",
1872*7c478bd9Sstevel@tonic-gate 		    rtm->rtm_type);
1873*7c478bd9Sstevel@tonic-gate 		return;
1874*7c478bd9Sstevel@tonic-gate 	}
1875*7c478bd9Sstevel@tonic-gate 	(void) printf("%s: len %d, ", msgtypes[rtm->rtm_type], rtm->rtm_msglen);
1876*7c478bd9Sstevel@tonic-gate 	switch (rtm->rtm_type) {
1877*7c478bd9Sstevel@tonic-gate 	case RTM_IFINFO:
1878*7c478bd9Sstevel@tonic-gate 		ifm = (struct if_msghdr *)rtm;
1879*7c478bd9Sstevel@tonic-gate 		(void) printf("if# %d, flags:", ifm->ifm_index);
1880*7c478bd9Sstevel@tonic-gate 		bprintf(stdout, ifm->ifm_flags, ifnetflags);
1881*7c478bd9Sstevel@tonic-gate 		pmsg_addrs((char *)(ifm + 1), ifm->ifm_addrs);
1882*7c478bd9Sstevel@tonic-gate 		break;
1883*7c478bd9Sstevel@tonic-gate 	case RTM_NEWADDR:
1884*7c478bd9Sstevel@tonic-gate 	case RTM_DELADDR:
1885*7c478bd9Sstevel@tonic-gate 		ifam = (struct ifa_msghdr *)rtm;
1886*7c478bd9Sstevel@tonic-gate 		(void) printf("metric %d, flags:", ifam->ifam_metric);
1887*7c478bd9Sstevel@tonic-gate 		bprintf(stdout, ifam->ifam_flags, routeflags);
1888*7c478bd9Sstevel@tonic-gate 		pmsg_addrs((char *)(ifam + 1), ifam->ifam_addrs);
1889*7c478bd9Sstevel@tonic-gate 		break;
1890*7c478bd9Sstevel@tonic-gate 	default:
1891*7c478bd9Sstevel@tonic-gate 		(void) printf("pid: %ld, seq %d, errno %d, flags:",
1892*7c478bd9Sstevel@tonic-gate 			rtm->rtm_pid, rtm->rtm_seq, rtm->rtm_errno);
1893*7c478bd9Sstevel@tonic-gate 		bprintf(stdout, rtm->rtm_flags, routeflags);
1894*7c478bd9Sstevel@tonic-gate 		pmsg_common(rtm);
1895*7c478bd9Sstevel@tonic-gate 	}
1896*7c478bd9Sstevel@tonic-gate }
1897*7c478bd9Sstevel@tonic-gate 
1898*7c478bd9Sstevel@tonic-gate void
1899*7c478bd9Sstevel@tonic-gate print_getmsg(struct rt_msghdr *rtm, int msglen)
1900*7c478bd9Sstevel@tonic-gate {
1901*7c478bd9Sstevel@tonic-gate 	struct sockaddr *dst = NULL, *gate = NULL, *mask = NULL, *src = NULL;
1902*7c478bd9Sstevel@tonic-gate 	struct sockaddr_dl *ifp = NULL;
1903*7c478bd9Sstevel@tonic-gate 	struct sockaddr *sa;
1904*7c478bd9Sstevel@tonic-gate 	char *cp;
1905*7c478bd9Sstevel@tonic-gate 	int i;
1906*7c478bd9Sstevel@tonic-gate 
1907*7c478bd9Sstevel@tonic-gate 	(void) printf("   route to: %s\n", routename(&so_dst.sa));
1908*7c478bd9Sstevel@tonic-gate 	if (rtm->rtm_version != RTM_VERSION) {
1909*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
1910*7c478bd9Sstevel@tonic-gate 		    gettext("routing message version %d not understood\n"),
1911*7c478bd9Sstevel@tonic-gate 		    rtm->rtm_version);
1912*7c478bd9Sstevel@tonic-gate 		return;
1913*7c478bd9Sstevel@tonic-gate 	}
1914*7c478bd9Sstevel@tonic-gate 	if (rtm->rtm_msglen > (ushort_t)msglen) {
1915*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
1916*7c478bd9Sstevel@tonic-gate 		    gettext("message length mismatch, in packet %d, "
1917*7c478bd9Sstevel@tonic-gate 			"returned %d\n"), rtm->rtm_msglen, msglen);
1918*7c478bd9Sstevel@tonic-gate 	}
1919*7c478bd9Sstevel@tonic-gate 	if (rtm->rtm_errno)  {
1920*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "RTM_GET: %s (errno %d)\n",
1921*7c478bd9Sstevel@tonic-gate 		    strerror(rtm->rtm_errno), rtm->rtm_errno);
1922*7c478bd9Sstevel@tonic-gate 		return;
1923*7c478bd9Sstevel@tonic-gate 	}
1924*7c478bd9Sstevel@tonic-gate 	cp = ((char *)(rtm + 1));
1925*7c478bd9Sstevel@tonic-gate 	if (rtm->rtm_addrs != 0) {
1926*7c478bd9Sstevel@tonic-gate 		for (i = 1; i != 0; i <<= 1) {
1927*7c478bd9Sstevel@tonic-gate 			if (i & rtm->rtm_addrs) {
1928*7c478bd9Sstevel@tonic-gate 				/* LINTED */
1929*7c478bd9Sstevel@tonic-gate 				sa = (struct sockaddr *)cp;
1930*7c478bd9Sstevel@tonic-gate 				switch (i) {
1931*7c478bd9Sstevel@tonic-gate 				case RTA_DST:
1932*7c478bd9Sstevel@tonic-gate 					dst = sa;
1933*7c478bd9Sstevel@tonic-gate 					break;
1934*7c478bd9Sstevel@tonic-gate 				case RTA_GATEWAY:
1935*7c478bd9Sstevel@tonic-gate 					gate = sa;
1936*7c478bd9Sstevel@tonic-gate 					break;
1937*7c478bd9Sstevel@tonic-gate 				case RTA_NETMASK:
1938*7c478bd9Sstevel@tonic-gate 					mask = sa;
1939*7c478bd9Sstevel@tonic-gate 					break;
1940*7c478bd9Sstevel@tonic-gate 				case RTA_IFP:
1941*7c478bd9Sstevel@tonic-gate 					if (sa->sa_family == AF_LINK &&
1942*7c478bd9Sstevel@tonic-gate 					    ((struct sockaddr_dl *)sa)->
1943*7c478bd9Sstevel@tonic-gate 						sdl_nlen != 0)
1944*7c478bd9Sstevel@tonic-gate 						ifp = (struct sockaddr_dl *)sa;
1945*7c478bd9Sstevel@tonic-gate 					break;
1946*7c478bd9Sstevel@tonic-gate 				case RTA_SRC:
1947*7c478bd9Sstevel@tonic-gate 					src = sa;
1948*7c478bd9Sstevel@tonic-gate 					break;
1949*7c478bd9Sstevel@tonic-gate 				}
1950*7c478bd9Sstevel@tonic-gate 				ADVANCE(cp, sa);
1951*7c478bd9Sstevel@tonic-gate 			}
1952*7c478bd9Sstevel@tonic-gate 		}
1953*7c478bd9Sstevel@tonic-gate 	}
1954*7c478bd9Sstevel@tonic-gate 	if (dst != NULL && mask != NULL)
1955*7c478bd9Sstevel@tonic-gate 		mask->sa_family = dst->sa_family;	/* XXX */
1956*7c478bd9Sstevel@tonic-gate 	if (dst != NULL)
1957*7c478bd9Sstevel@tonic-gate 		(void) printf("destination: %s\n", routename(dst));
1958*7c478bd9Sstevel@tonic-gate 	if (mask != NULL) {
1959*7c478bd9Sstevel@tonic-gate 		boolean_t savenflag = nflag;
1960*7c478bd9Sstevel@tonic-gate 
1961*7c478bd9Sstevel@tonic-gate 		nflag = B_TRUE;
1962*7c478bd9Sstevel@tonic-gate 		(void) printf("       mask: %s\n", routename(mask));
1963*7c478bd9Sstevel@tonic-gate 		nflag = savenflag;
1964*7c478bd9Sstevel@tonic-gate 	}
1965*7c478bd9Sstevel@tonic-gate 	if (gate != NULL && rtm->rtm_flags & RTF_GATEWAY)
1966*7c478bd9Sstevel@tonic-gate 		(void) printf("    gateway: %s\n", routename(gate));
1967*7c478bd9Sstevel@tonic-gate 	if (src != NULL && rtm->rtm_flags & RTF_SETSRC)
1968*7c478bd9Sstevel@tonic-gate 		(void) printf("     setsrc: %s\n", routename(src));
1969*7c478bd9Sstevel@tonic-gate 	if (ifp != NULL) {
1970*7c478bd9Sstevel@tonic-gate 		if (verbose) {
1971*7c478bd9Sstevel@tonic-gate 			int i;
1972*7c478bd9Sstevel@tonic-gate 
1973*7c478bd9Sstevel@tonic-gate 			(void) printf("  interface: %.*s index %d address ",
1974*7c478bd9Sstevel@tonic-gate 			    ifp->sdl_nlen, ifp->sdl_data, ifp->sdl_index);
1975*7c478bd9Sstevel@tonic-gate 			for (i = ifp->sdl_nlen;
1976*7c478bd9Sstevel@tonic-gate 			    i < ifp->sdl_nlen + ifp->sdl_alen;
1977*7c478bd9Sstevel@tonic-gate 			    i++) {
1978*7c478bd9Sstevel@tonic-gate 				(void) printf("%02x ",
1979*7c478bd9Sstevel@tonic-gate 				    ifp->sdl_data[i] & 0xFF);
1980*7c478bd9Sstevel@tonic-gate 			}
1981*7c478bd9Sstevel@tonic-gate 			(void) printf("\n");
1982*7c478bd9Sstevel@tonic-gate 		} else {
1983*7c478bd9Sstevel@tonic-gate 			(void) printf("  interface: %.*s\n",
1984*7c478bd9Sstevel@tonic-gate 			    ifp->sdl_nlen, ifp->sdl_data);
1985*7c478bd9Sstevel@tonic-gate 		}
1986*7c478bd9Sstevel@tonic-gate 	}
1987*7c478bd9Sstevel@tonic-gate 	(void) printf("      flags: ");
1988*7c478bd9Sstevel@tonic-gate 	bprintf(stdout, rtm->rtm_flags, routeflags);
1989*7c478bd9Sstevel@tonic-gate 
1990*7c478bd9Sstevel@tonic-gate #define	lock(f)	((rtm->rtm_rmx.rmx_locks & RTV_ ## f) ? 'L' : ' ')
1991*7c478bd9Sstevel@tonic-gate #define	msec(u)	(((u) + 500) / 1000)		/* usec to msec */
1992*7c478bd9Sstevel@tonic-gate 
1993*7c478bd9Sstevel@tonic-gate 	(void) printf("\n%s\n", " recvpipe  sendpipe  ssthresh    rtt,ms "
1994*7c478bd9Sstevel@tonic-gate 	    "rttvar,ms  hopcount      mtu     expire");
1995*7c478bd9Sstevel@tonic-gate 	(void) printf("%8d%c ", rtm->rtm_rmx.rmx_recvpipe, lock(RPIPE));
1996*7c478bd9Sstevel@tonic-gate 	(void) printf("%8d%c ", rtm->rtm_rmx.rmx_sendpipe, lock(SPIPE));
1997*7c478bd9Sstevel@tonic-gate 	(void) printf("%8d%c ", rtm->rtm_rmx.rmx_ssthresh, lock(SSTHRESH));
1998*7c478bd9Sstevel@tonic-gate 	(void) printf("%8d%c ", msec(rtm->rtm_rmx.rmx_rtt), lock(RTT));
1999*7c478bd9Sstevel@tonic-gate 	(void) printf("%8d%c ", msec(rtm->rtm_rmx.rmx_rttvar), lock(RTTVAR));
2000*7c478bd9Sstevel@tonic-gate 	(void) printf("%8d%c ", rtm->rtm_rmx.rmx_hopcount, lock(HOPCOUNT));
2001*7c478bd9Sstevel@tonic-gate 	(void) printf("%8d%c ", rtm->rtm_rmx.rmx_mtu, lock(MTU));
2002*7c478bd9Sstevel@tonic-gate 	if (rtm->rtm_rmx.rmx_expire)
2003*7c478bd9Sstevel@tonic-gate 		rtm->rtm_rmx.rmx_expire -= time(0);
2004*7c478bd9Sstevel@tonic-gate 	(void) printf("%8d%c\n", rtm->rtm_rmx.rmx_expire, lock(EXPIRE));
2005*7c478bd9Sstevel@tonic-gate #undef lock
2006*7c478bd9Sstevel@tonic-gate #undef msec
2007*7c478bd9Sstevel@tonic-gate #define	RTA_IGN	\
2008*7c478bd9Sstevel@tonic-gate 	(RTA_DST|RTA_GATEWAY|RTA_NETMASK|RTA_IFP|RTA_IFA|RTA_BRD|RTA_SRC)
2009*7c478bd9Sstevel@tonic-gate 	if (verbose) {
2010*7c478bd9Sstevel@tonic-gate 		pmsg_common(rtm);
2011*7c478bd9Sstevel@tonic-gate 	} else if (rtm->rtm_addrs &~ RTA_IGN) {
2012*7c478bd9Sstevel@tonic-gate 		(void) printf("sockaddrs: ");
2013*7c478bd9Sstevel@tonic-gate 		bprintf(stdout, rtm->rtm_addrs, addrnames);
2014*7c478bd9Sstevel@tonic-gate 		(void) putchar('\n');
2015*7c478bd9Sstevel@tonic-gate 	}
2016*7c478bd9Sstevel@tonic-gate #undef	RTA_IGN
2017*7c478bd9Sstevel@tonic-gate }
2018*7c478bd9Sstevel@tonic-gate 
2019*7c478bd9Sstevel@tonic-gate void
2020*7c478bd9Sstevel@tonic-gate pmsg_common(struct rt_msghdr *rtm)
2021*7c478bd9Sstevel@tonic-gate {
2022*7c478bd9Sstevel@tonic-gate 	(void) printf("\nlocks: ");
2023*7c478bd9Sstevel@tonic-gate 	bprintf(stdout, (int)rtm->rtm_rmx.rmx_locks, metricnames);
2024*7c478bd9Sstevel@tonic-gate 	(void) printf(" inits: ");
2025*7c478bd9Sstevel@tonic-gate 	bprintf(stdout, (int)rtm->rtm_inits, metricnames);
2026*7c478bd9Sstevel@tonic-gate 	pmsg_addrs(((char *)(rtm + 1)), rtm->rtm_addrs);
2027*7c478bd9Sstevel@tonic-gate }
2028*7c478bd9Sstevel@tonic-gate 
2029*7c478bd9Sstevel@tonic-gate void
2030*7c478bd9Sstevel@tonic-gate pmsg_addrs(char *cp, int addrs)
2031*7c478bd9Sstevel@tonic-gate {
2032*7c478bd9Sstevel@tonic-gate 	struct sockaddr *sa;
2033*7c478bd9Sstevel@tonic-gate 	int i;
2034*7c478bd9Sstevel@tonic-gate 
2035*7c478bd9Sstevel@tonic-gate 	if (addrs == 0)
2036*7c478bd9Sstevel@tonic-gate 		return;
2037*7c478bd9Sstevel@tonic-gate 	(void) printf("\nsockaddrs: ");
2038*7c478bd9Sstevel@tonic-gate 	bprintf(stdout, addrs, addrnames);
2039*7c478bd9Sstevel@tonic-gate 	(void) putchar('\n');
2040*7c478bd9Sstevel@tonic-gate 	for (i = 1; i != 0; i <<= 1) {
2041*7c478bd9Sstevel@tonic-gate 		if (i & addrs) {
2042*7c478bd9Sstevel@tonic-gate 			/* LINTED */
2043*7c478bd9Sstevel@tonic-gate 			sa = (struct sockaddr *)cp;
2044*7c478bd9Sstevel@tonic-gate 			(void) printf(" %s", routename(sa));
2045*7c478bd9Sstevel@tonic-gate 			ADVANCE(cp, sa);
2046*7c478bd9Sstevel@tonic-gate 		}
2047*7c478bd9Sstevel@tonic-gate 	}
2048*7c478bd9Sstevel@tonic-gate 	(void) putchar('\n');
2049*7c478bd9Sstevel@tonic-gate 	(void) fflush(stdout);
2050*7c478bd9Sstevel@tonic-gate }
2051*7c478bd9Sstevel@tonic-gate 
2052*7c478bd9Sstevel@tonic-gate void
2053*7c478bd9Sstevel@tonic-gate bprintf(FILE *fp, int b, char *s)
2054*7c478bd9Sstevel@tonic-gate {
2055*7c478bd9Sstevel@tonic-gate 	int i;
2056*7c478bd9Sstevel@tonic-gate 	boolean_t gotsome = B_FALSE;
2057*7c478bd9Sstevel@tonic-gate 
2058*7c478bd9Sstevel@tonic-gate 	if (b == 0)
2059*7c478bd9Sstevel@tonic-gate 		return;
2060*7c478bd9Sstevel@tonic-gate 	while ((i = *s++) != 0) {
2061*7c478bd9Sstevel@tonic-gate 		if (b & (1 << (i - 1))) {
2062*7c478bd9Sstevel@tonic-gate 			if (!gotsome)
2063*7c478bd9Sstevel@tonic-gate 				i = '<';
2064*7c478bd9Sstevel@tonic-gate 			else
2065*7c478bd9Sstevel@tonic-gate 				i = ',';
2066*7c478bd9Sstevel@tonic-gate 			(void) putc(i, fp);
2067*7c478bd9Sstevel@tonic-gate 			gotsome = B_TRUE;
2068*7c478bd9Sstevel@tonic-gate 			for (; (i = *s) > ' '; s++)
2069*7c478bd9Sstevel@tonic-gate 				(void) putc(i, fp);
2070*7c478bd9Sstevel@tonic-gate 		} else {
2071*7c478bd9Sstevel@tonic-gate 			while (*s > ' ')
2072*7c478bd9Sstevel@tonic-gate 				s++;
2073*7c478bd9Sstevel@tonic-gate 		}
2074*7c478bd9Sstevel@tonic-gate 	}
2075*7c478bd9Sstevel@tonic-gate 	if (gotsome)
2076*7c478bd9Sstevel@tonic-gate 		(void) putc('>', fp);
2077*7c478bd9Sstevel@tonic-gate }
2078*7c478bd9Sstevel@tonic-gate 
2079*7c478bd9Sstevel@tonic-gate int
2080*7c478bd9Sstevel@tonic-gate keyword(char *cp)
2081*7c478bd9Sstevel@tonic-gate {
2082*7c478bd9Sstevel@tonic-gate 	struct keytab *kt = keywords;
2083*7c478bd9Sstevel@tonic-gate 
2084*7c478bd9Sstevel@tonic-gate 	while (kt->kt_cp && strcmp(kt->kt_cp, cp))
2085*7c478bd9Sstevel@tonic-gate 		kt++;
2086*7c478bd9Sstevel@tonic-gate 	return (kt->kt_i);
2087*7c478bd9Sstevel@tonic-gate }
2088*7c478bd9Sstevel@tonic-gate 
2089*7c478bd9Sstevel@tonic-gate void
2090*7c478bd9Sstevel@tonic-gate sodump(sup su, char *which)
2091*7c478bd9Sstevel@tonic-gate {
2092*7c478bd9Sstevel@tonic-gate 	static char obuf[INET6_ADDRSTRLEN];
2093*7c478bd9Sstevel@tonic-gate 
2094*7c478bd9Sstevel@tonic-gate 	switch (su->sa.sa_family) {
2095*7c478bd9Sstevel@tonic-gate 	case AF_LINK:
2096*7c478bd9Sstevel@tonic-gate 		(void) printf("%s: link %s; ",
2097*7c478bd9Sstevel@tonic-gate 		    which, link_ntoa(&su->sdl));
2098*7c478bd9Sstevel@tonic-gate 		break;
2099*7c478bd9Sstevel@tonic-gate 	case AF_INET:
2100*7c478bd9Sstevel@tonic-gate 		(void) printf("%s: inet %s; ",
2101*7c478bd9Sstevel@tonic-gate 		    which, inet_ntoa(su->sin.sin_addr));
2102*7c478bd9Sstevel@tonic-gate 		break;
2103*7c478bd9Sstevel@tonic-gate 	case AF_INET6:
2104*7c478bd9Sstevel@tonic-gate 		if (inet_ntop(AF_INET6, (void *)&su->sin6.sin6_addr, obuf,
2105*7c478bd9Sstevel@tonic-gate 		    INET6_ADDRSTRLEN) != NULL) {
2106*7c478bd9Sstevel@tonic-gate 			(void) printf("%s: inet6 %s; ", which, obuf);
2107*7c478bd9Sstevel@tonic-gate 			break;
2108*7c478bd9Sstevel@tonic-gate 		}
2109*7c478bd9Sstevel@tonic-gate 		/* FALLTHROUGH */
2110*7c478bd9Sstevel@tonic-gate 	default:
2111*7c478bd9Sstevel@tonic-gate 		quit(gettext("Internal Error"), EINVAL);
2112*7c478bd9Sstevel@tonic-gate 		/* NOTREACHED */
2113*7c478bd9Sstevel@tonic-gate 	}
2114*7c478bd9Sstevel@tonic-gate 	(void) fflush(stdout);
2115*7c478bd9Sstevel@tonic-gate }
2116*7c478bd9Sstevel@tonic-gate 
2117*7c478bd9Sstevel@tonic-gate /* States */
2118*7c478bd9Sstevel@tonic-gate #define	VIRGIN	0
2119*7c478bd9Sstevel@tonic-gate #define	GOTONE	1
2120*7c478bd9Sstevel@tonic-gate #define	GOTTWO	2
2121*7c478bd9Sstevel@tonic-gate #define	RESET	3
2122*7c478bd9Sstevel@tonic-gate /* Inputs */
2123*7c478bd9Sstevel@tonic-gate #define	DIGIT	(4*0)
2124*7c478bd9Sstevel@tonic-gate #define	END	(4*1)
2125*7c478bd9Sstevel@tonic-gate #define	DELIM	(4*2)
2126*7c478bd9Sstevel@tonic-gate #define	LETTER	(4*3)
2127*7c478bd9Sstevel@tonic-gate 
2128*7c478bd9Sstevel@tonic-gate void
2129*7c478bd9Sstevel@tonic-gate sockaddr(char *addr, struct sockaddr *sa)
2130*7c478bd9Sstevel@tonic-gate {
2131*7c478bd9Sstevel@tonic-gate 	char *cp = (char *)sa;
2132*7c478bd9Sstevel@tonic-gate 	int size = salen(sa);
2133*7c478bd9Sstevel@tonic-gate 	char *cplim = cp + size;
2134*7c478bd9Sstevel@tonic-gate 	int byte = 0, state = VIRGIN, new;
2135*7c478bd9Sstevel@tonic-gate 
2136*7c478bd9Sstevel@tonic-gate 	(void) memset(cp, 0, size);
2137*7c478bd9Sstevel@tonic-gate 	cp++;
2138*7c478bd9Sstevel@tonic-gate 	do {
2139*7c478bd9Sstevel@tonic-gate 		if ((*addr >= '0') && (*addr <= '9')) {
2140*7c478bd9Sstevel@tonic-gate 			new = *addr - '0';
2141*7c478bd9Sstevel@tonic-gate 		} else if ((*addr >= 'a') && (*addr <= 'f')) {
2142*7c478bd9Sstevel@tonic-gate 			new = *addr - 'a' + 10;
2143*7c478bd9Sstevel@tonic-gate 		} else if ((*addr >= 'A') && (*addr <= 'F')) {
2144*7c478bd9Sstevel@tonic-gate 			new = *addr - 'A' + 10;
2145*7c478bd9Sstevel@tonic-gate 		} else if (*addr == 0) {
2146*7c478bd9Sstevel@tonic-gate 			state |= END;
2147*7c478bd9Sstevel@tonic-gate 		} else {
2148*7c478bd9Sstevel@tonic-gate 			state |= DELIM;
2149*7c478bd9Sstevel@tonic-gate 		}
2150*7c478bd9Sstevel@tonic-gate 		addr++;
2151*7c478bd9Sstevel@tonic-gate 		switch (state /* | INPUT */) {
2152*7c478bd9Sstevel@tonic-gate 		case GOTTWO | DIGIT:
2153*7c478bd9Sstevel@tonic-gate 			*cp++ = byte;
2154*7c478bd9Sstevel@tonic-gate 			/* FALLTHROUGH */
2155*7c478bd9Sstevel@tonic-gate 		case VIRGIN | DIGIT:
2156*7c478bd9Sstevel@tonic-gate 			state = GOTONE; byte = new; continue;
2157*7c478bd9Sstevel@tonic-gate 		case GOTONE | DIGIT:
2158*7c478bd9Sstevel@tonic-gate 			state = GOTTWO; byte = new + (byte << 4); continue;
2159*7c478bd9Sstevel@tonic-gate 		default: /* | DELIM */
2160*7c478bd9Sstevel@tonic-gate 			state = VIRGIN; *cp++ = byte; byte = 0; continue;
2161*7c478bd9Sstevel@tonic-gate 		case GOTONE | END:
2162*7c478bd9Sstevel@tonic-gate 		case GOTTWO | END:
2163*7c478bd9Sstevel@tonic-gate 			*cp++ = byte;
2164*7c478bd9Sstevel@tonic-gate 			/* FALLTHROUGH */
2165*7c478bd9Sstevel@tonic-gate 		case VIRGIN | END:
2166*7c478bd9Sstevel@tonic-gate 			break;
2167*7c478bd9Sstevel@tonic-gate 		}
2168*7c478bd9Sstevel@tonic-gate 		break;
2169*7c478bd9Sstevel@tonic-gate 	} while (cp < cplim);
2170*7c478bd9Sstevel@tonic-gate }
2171*7c478bd9Sstevel@tonic-gate 
2172*7c478bd9Sstevel@tonic-gate int
2173*7c478bd9Sstevel@tonic-gate salen(struct sockaddr *sa)
2174*7c478bd9Sstevel@tonic-gate {
2175*7c478bd9Sstevel@tonic-gate 	switch (sa->sa_family) {
2176*7c478bd9Sstevel@tonic-gate 	case AF_INET:
2177*7c478bd9Sstevel@tonic-gate 		return (sizeof (struct sockaddr_in));
2178*7c478bd9Sstevel@tonic-gate 	case AF_LINK:
2179*7c478bd9Sstevel@tonic-gate 		return (sizeof (struct sockaddr_dl));
2180*7c478bd9Sstevel@tonic-gate 	case AF_INET6:
2181*7c478bd9Sstevel@tonic-gate 		return (sizeof (struct sockaddr_in6));
2182*7c478bd9Sstevel@tonic-gate 	default:
2183*7c478bd9Sstevel@tonic-gate 		return (sizeof (struct sockaddr));
2184*7c478bd9Sstevel@tonic-gate 	}
2185*7c478bd9Sstevel@tonic-gate }
2186*7c478bd9Sstevel@tonic-gate 
2187*7c478bd9Sstevel@tonic-gate void
2188*7c478bd9Sstevel@tonic-gate link_addr(const char *addr, struct sockaddr_dl *sdl)
2189*7c478bd9Sstevel@tonic-gate {
2190*7c478bd9Sstevel@tonic-gate 	char *cp = sdl->sdl_data;
2191*7c478bd9Sstevel@tonic-gate 	char *cplim = sizeof (struct sockaddr_dl) + (char *)sdl;
2192*7c478bd9Sstevel@tonic-gate 	int byte = 0, state = VIRGIN, new;
2193*7c478bd9Sstevel@tonic-gate 
2194*7c478bd9Sstevel@tonic-gate 	(void) memset(sdl, 0, sizeof (struct sockaddr_dl));
2195*7c478bd9Sstevel@tonic-gate 	sdl->sdl_family = AF_LINK;
2196*7c478bd9Sstevel@tonic-gate 	do {
2197*7c478bd9Sstevel@tonic-gate 		state &= ~LETTER;
2198*7c478bd9Sstevel@tonic-gate 		if ((*addr >= '0') && (*addr <= '9')) {
2199*7c478bd9Sstevel@tonic-gate 			new = *addr - '0';
2200*7c478bd9Sstevel@tonic-gate 		} else if ((*addr >= 'a') && (*addr <= 'f')) {
2201*7c478bd9Sstevel@tonic-gate 			new = *addr - 'a' + 10;
2202*7c478bd9Sstevel@tonic-gate 		} else if ((*addr >= 'A') && (*addr <= 'F')) {
2203*7c478bd9Sstevel@tonic-gate 			new = *addr - 'A' + 10;
2204*7c478bd9Sstevel@tonic-gate 		} else if (*addr == 0) {
2205*7c478bd9Sstevel@tonic-gate 			state |= END;
2206*7c478bd9Sstevel@tonic-gate 		} else if (state == VIRGIN &&
2207*7c478bd9Sstevel@tonic-gate 		    (((*addr >= 'A') && (*addr <= 'Z')) ||
2208*7c478bd9Sstevel@tonic-gate 		    ((*addr >= 'a') && (*addr <= 'z')))) {
2209*7c478bd9Sstevel@tonic-gate 			state |= LETTER;
2210*7c478bd9Sstevel@tonic-gate 		} else {
2211*7c478bd9Sstevel@tonic-gate 			state |= DELIM;
2212*7c478bd9Sstevel@tonic-gate 		}
2213*7c478bd9Sstevel@tonic-gate 		addr++;
2214*7c478bd9Sstevel@tonic-gate 		switch (state /* | INPUT */) {
2215*7c478bd9Sstevel@tonic-gate 		case VIRGIN | DIGIT:
2216*7c478bd9Sstevel@tonic-gate 		case VIRGIN | LETTER:
2217*7c478bd9Sstevel@tonic-gate 			*cp++ = addr[-1];
2218*7c478bd9Sstevel@tonic-gate 			continue;
2219*7c478bd9Sstevel@tonic-gate 		case VIRGIN | DELIM:
2220*7c478bd9Sstevel@tonic-gate 			state = RESET;
2221*7c478bd9Sstevel@tonic-gate 			sdl->sdl_nlen = cp - sdl->sdl_data;
2222*7c478bd9Sstevel@tonic-gate 			continue;
2223*7c478bd9Sstevel@tonic-gate 		case GOTTWO | DIGIT:
2224*7c478bd9Sstevel@tonic-gate 			*cp++ = byte;
2225*7c478bd9Sstevel@tonic-gate 			/* FALLTHROUGH */
2226*7c478bd9Sstevel@tonic-gate 		case RESET | DIGIT:
2227*7c478bd9Sstevel@tonic-gate 			state = GOTONE;
2228*7c478bd9Sstevel@tonic-gate 			byte = new;
2229*7c478bd9Sstevel@tonic-gate 			continue;
2230*7c478bd9Sstevel@tonic-gate 		case GOTONE | DIGIT:
2231*7c478bd9Sstevel@tonic-gate 			state = GOTTWO;
2232*7c478bd9Sstevel@tonic-gate 			byte = new + (byte << 4);
2233*7c478bd9Sstevel@tonic-gate 			continue;
2234*7c478bd9Sstevel@tonic-gate 		default: /* | DELIM */
2235*7c478bd9Sstevel@tonic-gate 			state = RESET;
2236*7c478bd9Sstevel@tonic-gate 			*cp++ = byte;
2237*7c478bd9Sstevel@tonic-gate 			byte = 0;
2238*7c478bd9Sstevel@tonic-gate 			continue;
2239*7c478bd9Sstevel@tonic-gate 		case GOTONE | END:
2240*7c478bd9Sstevel@tonic-gate 		case GOTTWO | END:
2241*7c478bd9Sstevel@tonic-gate 			*cp++ = byte;
2242*7c478bd9Sstevel@tonic-gate 			/* FALLTHROUGH */
2243*7c478bd9Sstevel@tonic-gate 		case RESET | END:
2244*7c478bd9Sstevel@tonic-gate 			break;
2245*7c478bd9Sstevel@tonic-gate 		}
2246*7c478bd9Sstevel@tonic-gate 		break;
2247*7c478bd9Sstevel@tonic-gate 	} while (cp < cplim);
2248*7c478bd9Sstevel@tonic-gate 	sdl->sdl_alen = cp - LLADDR(sdl);
2249*7c478bd9Sstevel@tonic-gate }
2250*7c478bd9Sstevel@tonic-gate 
2251*7c478bd9Sstevel@tonic-gate static char hexlist[] = "0123456789abcdef";
2252*7c478bd9Sstevel@tonic-gate 
2253*7c478bd9Sstevel@tonic-gate char *
2254*7c478bd9Sstevel@tonic-gate link_ntoa(const struct sockaddr_dl *sdl)
2255*7c478bd9Sstevel@tonic-gate {
2256*7c478bd9Sstevel@tonic-gate 	static char obuf[64];
2257*7c478bd9Sstevel@tonic-gate 	char *out = obuf;
2258*7c478bd9Sstevel@tonic-gate 	int i;
2259*7c478bd9Sstevel@tonic-gate 	uchar_t *in = (uchar_t *)LLADDR(sdl);
2260*7c478bd9Sstevel@tonic-gate 	uchar_t *inlim = in + sdl->sdl_alen;
2261*7c478bd9Sstevel@tonic-gate 	boolean_t firsttime = B_TRUE;
2262*7c478bd9Sstevel@tonic-gate 
2263*7c478bd9Sstevel@tonic-gate 	if (sdl->sdl_nlen) {
2264*7c478bd9Sstevel@tonic-gate 		(void) memcpy(obuf, sdl->sdl_data, sdl->sdl_nlen);
2265*7c478bd9Sstevel@tonic-gate 		out += sdl->sdl_nlen;
2266*7c478bd9Sstevel@tonic-gate 		if (sdl->sdl_alen)
2267*7c478bd9Sstevel@tonic-gate 			*out++ = ':';
2268*7c478bd9Sstevel@tonic-gate 	}
2269*7c478bd9Sstevel@tonic-gate 	while (in < inlim) {
2270*7c478bd9Sstevel@tonic-gate 		if (firsttime)
2271*7c478bd9Sstevel@tonic-gate 			firsttime = B_FALSE;
2272*7c478bd9Sstevel@tonic-gate 		else
2273*7c478bd9Sstevel@tonic-gate 			*out++ = '.';
2274*7c478bd9Sstevel@tonic-gate 		i = *in++;
2275*7c478bd9Sstevel@tonic-gate 		if (i > 0xf) {
2276*7c478bd9Sstevel@tonic-gate 			out[1] = hexlist[i & 0xf];
2277*7c478bd9Sstevel@tonic-gate 			i >>= 4;
2278*7c478bd9Sstevel@tonic-gate 			out[0] = hexlist[i];
2279*7c478bd9Sstevel@tonic-gate 			out += 2;
2280*7c478bd9Sstevel@tonic-gate 		} else {
2281*7c478bd9Sstevel@tonic-gate 			*out++ = hexlist[i];
2282*7c478bd9Sstevel@tonic-gate 		}
2283*7c478bd9Sstevel@tonic-gate 	}
2284*7c478bd9Sstevel@tonic-gate 	*out = 0;
2285*7c478bd9Sstevel@tonic-gate 	return (obuf);
2286*7c478bd9Sstevel@tonic-gate }
2287*7c478bd9Sstevel@tonic-gate 
2288*7c478bd9Sstevel@tonic-gate static mib_item_t *
2289*7c478bd9Sstevel@tonic-gate mibget(int sd)
2290*7c478bd9Sstevel@tonic-gate {
2291*7c478bd9Sstevel@tonic-gate 	intmax_t		buf[512 / sizeof (intmax_t)];
2292*7c478bd9Sstevel@tonic-gate 	int			flags;
2293*7c478bd9Sstevel@tonic-gate 	int			i, j, getcode;
2294*7c478bd9Sstevel@tonic-gate 	struct strbuf		ctlbuf, databuf;
2295*7c478bd9Sstevel@tonic-gate 	struct T_optmgmt_req	*tor = (struct T_optmgmt_req *)buf;
2296*7c478bd9Sstevel@tonic-gate 	struct T_optmgmt_ack	*toa = (struct T_optmgmt_ack *)buf;
2297*7c478bd9Sstevel@tonic-gate 	struct T_error_ack	*tea = (struct T_error_ack *)buf;
2298*7c478bd9Sstevel@tonic-gate 	struct opthdr		*req;
2299*7c478bd9Sstevel@tonic-gate 	mib_item_t		*first_item = NULL;
2300*7c478bd9Sstevel@tonic-gate 	mib_item_t		*last_item  = NULL;
2301*7c478bd9Sstevel@tonic-gate 	mib_item_t		*temp;
2302*7c478bd9Sstevel@tonic-gate 
2303*7c478bd9Sstevel@tonic-gate 	tor->PRIM_type = T_SVR4_OPTMGMT_REQ;
2304*7c478bd9Sstevel@tonic-gate 	tor->OPT_offset = sizeof (struct T_optmgmt_req);
2305*7c478bd9Sstevel@tonic-gate 	tor->OPT_length = sizeof (struct opthdr);
2306*7c478bd9Sstevel@tonic-gate 	tor->MGMT_flags = T_CURRENT;
2307*7c478bd9Sstevel@tonic-gate 	req = (struct opthdr *)&tor[1];
2308*7c478bd9Sstevel@tonic-gate 	req->level = MIB2_IP;		/* any MIB2_xxx value ok here */
2309*7c478bd9Sstevel@tonic-gate 	req->name  = 0;
2310*7c478bd9Sstevel@tonic-gate 	req->len   = 0;
2311*7c478bd9Sstevel@tonic-gate 
2312*7c478bd9Sstevel@tonic-gate 	ctlbuf.buf = (char *)buf;
2313*7c478bd9Sstevel@tonic-gate 	ctlbuf.len = tor->OPT_length + tor->OPT_offset;
2314*7c478bd9Sstevel@tonic-gate 	flags = 0;
2315*7c478bd9Sstevel@tonic-gate 	if (putmsg(sd, &ctlbuf, NULL, flags) < 0) {
2316*7c478bd9Sstevel@tonic-gate 		perror("mibget: putmsg (ctl)");
2317*7c478bd9Sstevel@tonic-gate 		return (NULL);
2318*7c478bd9Sstevel@tonic-gate 	}
2319*7c478bd9Sstevel@tonic-gate 	/*
2320*7c478bd9Sstevel@tonic-gate 	 * each reply consists of a ctl part for one fixed structure
2321*7c478bd9Sstevel@tonic-gate 	 * or table, as defined in mib2.h.  The format is a T_OPTMGMT_ACK,
2322*7c478bd9Sstevel@tonic-gate 	 * containing an opthdr structure.  level/name identify the entry,
2323*7c478bd9Sstevel@tonic-gate 	 * len is the size of the data part of the message.
2324*7c478bd9Sstevel@tonic-gate 	 */
2325*7c478bd9Sstevel@tonic-gate 	req = (struct opthdr *)&toa[1];
2326*7c478bd9Sstevel@tonic-gate 	ctlbuf.maxlen = sizeof (buf);
2327*7c478bd9Sstevel@tonic-gate 	for (j = 1; ; j++) {
2328*7c478bd9Sstevel@tonic-gate 		flags = 0;
2329*7c478bd9Sstevel@tonic-gate 		getcode = getmsg(sd, &ctlbuf, NULL, &flags);
2330*7c478bd9Sstevel@tonic-gate 		if (getcode < 0) {
2331*7c478bd9Sstevel@tonic-gate 			perror("mibget: getmsg (ctl)");
2332*7c478bd9Sstevel@tonic-gate 			if (verbose) {
2333*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
2334*7c478bd9Sstevel@tonic-gate 				    "#   level   name    len\n");
2335*7c478bd9Sstevel@tonic-gate 				i = 0;
2336*7c478bd9Sstevel@tonic-gate 				for (last_item = first_item; last_item != NULL;
2337*7c478bd9Sstevel@tonic-gate 				    last_item = last_item->next_item) {
2338*7c478bd9Sstevel@tonic-gate 					(void) printf("%d  %4ld   %5ld   %ld\n",
2339*7c478bd9Sstevel@tonic-gate 					    ++i, last_item->group,
2340*7c478bd9Sstevel@tonic-gate 					    last_item->mib_id,
2341*7c478bd9Sstevel@tonic-gate 					    last_item->length);
2342*7c478bd9Sstevel@tonic-gate 				}
2343*7c478bd9Sstevel@tonic-gate 			}
2344*7c478bd9Sstevel@tonic-gate 			break;
2345*7c478bd9Sstevel@tonic-gate 		}
2346*7c478bd9Sstevel@tonic-gate 		if (getcode == 0 &&
2347*7c478bd9Sstevel@tonic-gate 		    ctlbuf.len >= sizeof (struct T_optmgmt_ack) &&
2348*7c478bd9Sstevel@tonic-gate 		    toa->PRIM_type == T_OPTMGMT_ACK &&
2349*7c478bd9Sstevel@tonic-gate 		    toa->MGMT_flags == T_SUCCESS &&
2350*7c478bd9Sstevel@tonic-gate 		    req->len == 0) {
2351*7c478bd9Sstevel@tonic-gate 			if (verbose) {
2352*7c478bd9Sstevel@tonic-gate 				(void) printf("mibget getmsg() %d returned EOD "
2353*7c478bd9Sstevel@tonic-gate 				    "(level %lu, name %lu)\n", j, req->level,
2354*7c478bd9Sstevel@tonic-gate 				    req->name);
2355*7c478bd9Sstevel@tonic-gate 			}
2356*7c478bd9Sstevel@tonic-gate 			return (first_item);		/* this is EOD msg */
2357*7c478bd9Sstevel@tonic-gate 		}
2358*7c478bd9Sstevel@tonic-gate 
2359*7c478bd9Sstevel@tonic-gate 		if (ctlbuf.len >= sizeof (struct T_error_ack) &&
2360*7c478bd9Sstevel@tonic-gate 		    tea->PRIM_type == T_ERROR_ACK) {
2361*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("mibget %d gives "
2362*7c478bd9Sstevel@tonic-gate 			    "T_ERROR_ACK: TLI_error = 0x%lx, UNIX_error = "
2363*7c478bd9Sstevel@tonic-gate 			    "0x%lx\n"), j, tea->TLI_error, tea->UNIX_error);
2364*7c478bd9Sstevel@tonic-gate 			errno = (tea->TLI_error == TSYSERR)
2365*7c478bd9Sstevel@tonic-gate 				? tea->UNIX_error : EPROTO;
2366*7c478bd9Sstevel@tonic-gate 			break;
2367*7c478bd9Sstevel@tonic-gate 		}
2368*7c478bd9Sstevel@tonic-gate 
2369*7c478bd9Sstevel@tonic-gate 		if (getcode != MOREDATA ||
2370*7c478bd9Sstevel@tonic-gate 		    ctlbuf.len < sizeof (struct T_optmgmt_ack) ||
2371*7c478bd9Sstevel@tonic-gate 		    toa->PRIM_type != T_OPTMGMT_ACK ||
2372*7c478bd9Sstevel@tonic-gate 		    toa->MGMT_flags != T_SUCCESS) {
2373*7c478bd9Sstevel@tonic-gate 			(void) printf("mibget getmsg(ctl) %d returned %d, "
2374*7c478bd9Sstevel@tonic-gate 			    "ctlbuf.len = %d, PRIM_type = %ld\n",
2375*7c478bd9Sstevel@tonic-gate 			    j, getcode, ctlbuf.len, toa->PRIM_type);
2376*7c478bd9Sstevel@tonic-gate 			if (toa->PRIM_type == T_OPTMGMT_ACK) {
2377*7c478bd9Sstevel@tonic-gate 				(void) printf("T_OPTMGMT_ACK: "
2378*7c478bd9Sstevel@tonic-gate 				    "MGMT_flags = 0x%lx, req->len = %ld\n",
2379*7c478bd9Sstevel@tonic-gate 				    toa->MGMT_flags, req->len);
2380*7c478bd9Sstevel@tonic-gate 			}
2381*7c478bd9Sstevel@tonic-gate 			errno = ENOMSG;
2382*7c478bd9Sstevel@tonic-gate 			break;
2383*7c478bd9Sstevel@tonic-gate 		}
2384*7c478bd9Sstevel@tonic-gate 
2385*7c478bd9Sstevel@tonic-gate 		temp = malloc(sizeof (mib_item_t));
2386*7c478bd9Sstevel@tonic-gate 		if (temp == NULL) {
2387*7c478bd9Sstevel@tonic-gate 			perror("mibget: malloc");
2388*7c478bd9Sstevel@tonic-gate 			break;
2389*7c478bd9Sstevel@tonic-gate 		}
2390*7c478bd9Sstevel@tonic-gate 		if (last_item != NULL)
2391*7c478bd9Sstevel@tonic-gate 			last_item->next_item = temp;
2392*7c478bd9Sstevel@tonic-gate 		else
2393*7c478bd9Sstevel@tonic-gate 			first_item = temp;
2394*7c478bd9Sstevel@tonic-gate 		last_item = temp;
2395*7c478bd9Sstevel@tonic-gate 		last_item->next_item = NULL;
2396*7c478bd9Sstevel@tonic-gate 		last_item->group = req->level;
2397*7c478bd9Sstevel@tonic-gate 		last_item->mib_id = req->name;
2398*7c478bd9Sstevel@tonic-gate 		last_item->length = req->len;
2399*7c478bd9Sstevel@tonic-gate 		last_item->valp = malloc(req->len);
2400*7c478bd9Sstevel@tonic-gate 		if (verbose) {
2401*7c478bd9Sstevel@tonic-gate 			(void) printf("msg %d:  group = %4ld   mib_id = %5ld   "
2402*7c478bd9Sstevel@tonic-gate 			    "length = %ld\n",
2403*7c478bd9Sstevel@tonic-gate 			    j, last_item->group, last_item->mib_id,
2404*7c478bd9Sstevel@tonic-gate 			    last_item->length);
2405*7c478bd9Sstevel@tonic-gate 		}
2406*7c478bd9Sstevel@tonic-gate 
2407*7c478bd9Sstevel@tonic-gate 		databuf.maxlen = last_item->length;
2408*7c478bd9Sstevel@tonic-gate 		databuf.buf    = (char *)last_item->valp;
2409*7c478bd9Sstevel@tonic-gate 		databuf.len    = 0;
2410*7c478bd9Sstevel@tonic-gate 		flags = 0;
2411*7c478bd9Sstevel@tonic-gate 		getcode = getmsg(sd, NULL, &databuf, &flags);
2412*7c478bd9Sstevel@tonic-gate 		if (getcode < 0) {
2413*7c478bd9Sstevel@tonic-gate 			perror("mibget: getmsg (data)");
2414*7c478bd9Sstevel@tonic-gate 			break;
2415*7c478bd9Sstevel@tonic-gate 		} else if (getcode != 0) {
2416*7c478bd9Sstevel@tonic-gate 			(void) printf("mibget getmsg(data) returned %d, "
2417*7c478bd9Sstevel@tonic-gate 			    "databuf.maxlen = %d, databuf.len = %d\n",
2418*7c478bd9Sstevel@tonic-gate 			    getcode, databuf.maxlen, databuf.len);
2419*7c478bd9Sstevel@tonic-gate 			break;
2420*7c478bd9Sstevel@tonic-gate 		}
2421*7c478bd9Sstevel@tonic-gate 	}
2422*7c478bd9Sstevel@tonic-gate 
2423*7c478bd9Sstevel@tonic-gate 	/*
2424*7c478bd9Sstevel@tonic-gate 	 * On error, free all the allocated mib_item_t objects.
2425*7c478bd9Sstevel@tonic-gate 	 */
2426*7c478bd9Sstevel@tonic-gate 	while (first_item != NULL) {
2427*7c478bd9Sstevel@tonic-gate 		last_item = first_item;
2428*7c478bd9Sstevel@tonic-gate 		first_item = first_item->next_item;
2429*7c478bd9Sstevel@tonic-gate 		free(last_item);
2430*7c478bd9Sstevel@tonic-gate 	}
2431*7c478bd9Sstevel@tonic-gate 	return (NULL);
2432*7c478bd9Sstevel@tonic-gate }
2433