1/*	$NetBSD$	*/
2
3/*
4 * Copyright (c) 1983, 1989, 1991, 1993
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 *    may be used to endorse or promote products derived from this software
17 *    without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32#include <sys/cdefs.h>
33#ifndef lint
34__COPYRIGHT("@(#) Copyright (c) 1983, 1989, 1991, 1993\
35 The Regents of the University of California.  All rights reserved.");
36#endif /* not lint */
37
38#ifndef lint
39#if 0
40static char sccsid[] = "@(#)route.c	8.6 (Berkeley) 4/28/95";
41#else
42__RCSID("$NetBSD$");
43#endif
44#endif /* not lint */
45
46#include <sys/param.h>
47#include <sys/file.h>
48#include <sys/socket.h>
49#include <sys/ioctl.h>
50#include <sys/mbuf.h>
51#include <sys/sysctl.h>
52
53#include <net/if.h>
54#include <net/route.h>
55#include <net/if_dl.h>
56#include <net80211/ieee80211_netbsd.h>
57#include <netinet/in.h>
58#include <netatalk/at.h>
59#include <netiso/iso.h>
60#include <netmpls/mpls.h>
61#include <arpa/inet.h>
62#include <netdb.h>
63
64#include <errno.h>
65#include <unistd.h>
66#include <stdio.h>
67#include <ctype.h>
68#include <stdlib.h>
69#include <string.h>
70#include <time.h>
71#include <paths.h>
72#include <err.h>
73
74#include <rump/rump.h>
75#include <rump/rump_syscalls.h>
76#include <rump/rumpclient.h>
77
78#include "keywords.h"
79#include "extern.h"
80#include "prog_ops.h"
81
82union sockunion {
83	struct	sockaddr sa;
84	struct	sockaddr_in sin;
85#ifdef INET6
86	struct	sockaddr_in6 sin6;
87#endif
88	struct	sockaddr_at sat;
89	struct	sockaddr_dl sdl;
90#ifndef SMALL
91	struct	sockaddr_iso siso;
92	struct	sockaddr_mpls smpls;
93#endif /* SMALL */
94	struct	sockaddr_storage sstorage;
95};
96
97typedef union sockunion *sup;
98
99struct sou {
100	union sockunion *so_dst, *so_gate, *so_mask, *so_genmask, *so_ifa,
101		*so_ifp, *so_mpls;
102};
103
104static char *any_ntoa(const struct sockaddr *);
105static const char *route_strerror(int);
106static void set_metric(const char *, int);
107static int newroute(int, char *const *);
108static void inet_makenetandmask(u_int32_t, struct sockaddr_in *, struct sou *);
109#ifdef INET6
110static int inet6_makenetandmask(const struct sockaddr_in6 *, struct sou *);
111#endif
112static int getaddr(int, const char *, struct hostent **, struct sou *);
113static int flushroutes(int, char *const [], int);
114static int prefixlen(const char *, struct sou *);
115#ifndef SMALL
116static void interfaces(void);
117__dead static void monitor(void);
118static int print_getmsg(struct rt_msghdr *, int, struct sou *);
119static const char *linkstate(struct if_msghdr *);
120static sup readtag(sup, const char *);
121static void addtag(sup, const char *, int);
122#endif /* SMALL */
123static int rtmsg(int, int, struct sou *);
124static void mask_addr(struct sou *);
125static void print_rtmsg(struct rt_msghdr *, int);
126static void pmsg_common(struct rt_msghdr *);
127static void pmsg_addrs(const char *, int);
128static void bprintf(FILE *, int, const char *);
129static void sodump(sup, const char *);
130static void sockaddr(const char *, struct sockaddr *);
131
132int	pid, rtm_addrs;
133int	sock;
134int	forcehost, forcenet, doflush, nflag, af, qflag, tflag, Sflag;
135int	iflag, verbose, aflen = sizeof(struct sockaddr_in), rtag;
136int	locking, lockrest, debugonly, shortoutput;
137struct	rt_metrics rt_metrics;
138int	rtm_inits;
139short ns_nullh[] = {0,0,0};
140short ns_bh[] = {-1,-1,-1};
141
142
143void
144usage(const char *cp)
145{
146
147	if (cp)
148		warnx("botched keyword: %s", cp);
149	(void)fprintf(stderr,
150	    "Usage: %s [ -fnqSsv ] cmd [[ -<qualifers> ] args ]\n",
151	    getprogname());
152	exit(1);
153	/* NOTREACHED */
154}
155
156#define	PRIETHER	"02x:%02x:%02x:%02x:%02x:%02x"
157#define	PRIETHER_ARGS(__enaddr)	(__enaddr)[0], (__enaddr)[1], (__enaddr)[2], \
158				(__enaddr)[3], (__enaddr)[4], (__enaddr)[5]
159
160int
161main(int argc, char * const *argv)
162{
163	int ch;
164
165	if (argc < 2)
166		usage(NULL);
167
168	while ((ch = getopt(argc, argv, "dfnqSstv")) != -1)
169		switch (ch) {
170		case 'd':
171			debugonly = 1;
172			break;
173		case 'f':
174			doflush = 1;
175			break;
176		case 'n':
177			nflag = 1;
178			break;
179		case 'q':
180			qflag = 1;
181			break;
182		case 'S':
183			Sflag = 1;
184			break;
185		case 's':
186			shortoutput = 1;
187			break;
188		case 't':
189			tflag = 1;
190			break;
191		case 'v':
192			verbose = 1;
193			break;
194		case '?':
195		default:
196			usage(NULL);
197			/*NOTREACHED*/
198		}
199	argc -= optind;
200	argv += optind;
201
202	if (prog_init && prog_init() == -1)
203		err(1, "init failed");
204
205	pid = prog_getpid();
206	if (tflag)
207		sock = prog_open("/dev/null", O_WRONLY, 0);
208	else
209		sock = prog_socket(PF_ROUTE, SOCK_RAW, 0);
210	if (sock < 0)
211		err(EXIT_FAILURE, "socket");
212
213	if (*argv == NULL) {
214		if (doflush)
215			ch = K_FLUSH;
216		else
217			goto no_cmd;
218	} else
219		ch = keyword(*argv);
220
221	switch (ch) {
222#ifndef SMALL
223	case K_GET:
224#endif /* SMALL */
225	case K_CHANGE:
226	case K_ADD:
227	case K_DELETE:
228		if (doflush)
229			(void)flushroutes(1, argv, 0);
230		return newroute(argc, argv);
231
232	case K_SHOW:
233		show(argc, argv);
234		return 0;
235
236#ifndef SMALL
237	case K_MONITOR:
238		monitor();
239		return 0;
240
241#endif /* SMALL */
242	case K_FLUSH:
243		return flushroutes(argc, argv, 0);
244
245	case K_FLUSHALL:
246		return flushroutes(argc, argv, 1);
247	no_cmd:
248	default:
249		usage(*argv);
250		/*NOTREACHED*/
251	}
252}
253
254/*
255 * Purge all entries in the routing tables not
256 * associated with network interfaces.
257 */
258static int
259flushroutes(int argc, char * const argv[], int doall)
260{
261	struct sockaddr *sa;
262	size_t needed;
263	int flags, mib[6], rlen, seqno;
264	char *buf, *next, *lim;
265	const char *afname;
266	struct rt_msghdr *rtm;
267
268	flags = 0;
269	af = AF_UNSPEC;
270	/* Don't want to read back our messages */
271	prog_shutdown(sock, SHUT_RD);
272	parse_show_opts(argc, argv, &af, &flags, &afname, false);
273	mib[0] = CTL_NET;
274	mib[1] = PF_ROUTE;
275	mib[2] = 0;		/* protocol */
276	mib[3] = 0;		/* wildcard address family */
277	mib[4] = NET_RT_DUMP;
278	mib[5] = 0;		/* no flags */
279	if (prog_sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
280		err(EXIT_FAILURE, "route-sysctl-estimate");
281	buf = lim = NULL;
282	if (needed) {
283		if ((buf = malloc(needed)) == NULL)
284			err(EXIT_FAILURE, "malloc");
285		if (prog_sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
286			err(EXIT_FAILURE, "actual retrieval of routing table");
287		lim = buf + needed;
288	}
289	if (verbose) {
290		(void)printf("Examining routing table from sysctl\n");
291		if (af != AF_UNSPEC)
292			printf("(address family %s)\n", afname);
293	}
294	if (needed == 0)
295		return 0;
296	seqno = 0;		/* ??? */
297	for (next = buf; next < lim; next += rtm->rtm_msglen) {
298		rtm = (struct rt_msghdr *)next;
299		sa = (struct sockaddr *)(rtm + 1);
300		if (verbose)
301			print_rtmsg(rtm, rtm->rtm_msglen);
302		if ((rtm->rtm_flags & flags) != flags)
303			continue;
304		if (!(rtm->rtm_flags & (RTF_GATEWAY | RTF_STATIC |
305					RTF_LLINFO)) && !doall)
306			continue;
307		if (af != AF_UNSPEC && sa->sa_family != af)
308			continue;
309		if (debugonly)
310			continue;
311		rtm->rtm_type = RTM_DELETE;
312		rtm->rtm_seq = seqno;
313		if ((rlen = prog_write(sock, next,
314		    rtm->rtm_msglen)) < 0) {
315			warnx("writing to routing socket: %s",
316			    route_strerror(errno));
317			return 1;
318		}
319		if (rlen < (int)rtm->rtm_msglen) {
320			warnx("write to routing socket, got %d for rlen", rlen);
321			return 1;
322		}
323		seqno++;
324		if (qflag)
325			continue;
326		if (verbose)
327			print_rtmsg(rtm, rlen);
328		else {
329			(void)printf("%-20.20s ",
330			    routename(sa, NULL, rtm->rtm_flags));
331			sa = (struct sockaddr *)(RT_ROUNDUP(sa->sa_len) +
332			    (char *)sa);
333			(void)printf("%-20.20s ",
334			    routename(sa, NULL, RTF_HOST));
335			(void)printf("done\n");
336		}
337	}
338	free(buf);
339	return 0;
340}
341
342
343static char hexlist[] = "0123456789abcdef";
344
345static char *
346any_ntoa(const struct sockaddr *sa)
347{
348	static char obuf[3 * 256];
349	const char *in;
350	char *out;
351	int len;
352
353#if __GNUC__ > 2
354	len = sa->sa_len - offsetof(struct sockaddr, sa_data);
355#else
356	len = sa->sa_len - ((struct sockaddr*)&sa->sa_data - sa);
357#endif
358	in  = sa->sa_data;
359	out = obuf;
360
361	do {
362		*out++ = hexlist[(*in >> 4) & 15];
363		*out++ = hexlist[(*in++)    & 15];
364		*out++ = '.';
365	} while (--len > 0);
366	out[-1] = '\0';
367	return obuf;
368}
369
370int
371netmask_length(struct sockaddr *nm, int family)
372{
373	static int
374	    /* number of bits in a nibble */
375	    _t[] = { 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4 },
376	    /* good nibbles are 1111, 1110, 1100, 1000, 0000 */
377	    _g[] = { 1,0,0,0,0,0,0,0,1,0,0,0,1,0,1,1 };
378	int mask, good, zeroes, maskbytes, bit, i;
379	unsigned char *maskdata;
380
381	if (nm == NULL)
382		return 0;
383
384	mask = 0;
385	good = 1;
386	zeroes = 0;
387
388	switch (family) {
389	case AF_INET: {
390		struct sockaddr_in *nsin = (struct sockaddr_in *)nm;
391		maskdata = (unsigned char *)&nsin->sin_addr;
392		maskbytes = nsin->sin_len -
393		    ((caddr_t)&nsin->sin_addr - (caddr_t)nsin);
394		break;
395	}
396	case AF_INET6: {
397		struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)nm;
398		maskdata = (unsigned char *)&sin6->sin6_addr;
399		maskbytes = sin6->sin6_len -
400		    ((caddr_t)&sin6->sin6_addr - (caddr_t)sin6);
401		break;
402	}
403	default:
404		return 0;
405	}
406
407	/*
408	 * Count the bits in the nibbles of the mask, and marking the
409	 * netmask as not good (or at best, non-standard and very
410	 * discouraged, in the case of AF_INET) if we find either of
411	 * a nibble with non-contiguous bits, or a non-zero nibble
412	 * after we've found a zero nibble.
413	 */
414	for (i = 0; i < maskbytes; i++) {
415		/* high nibble */
416		mask += bit = _t[maskdata[i] >> 4];
417		good &= _g[maskdata[i] >> 4];
418		if (zeroes && bit)
419			good = 0;
420		if (bit == 0)
421			zeroes = 1;
422		/* low nibble */
423		mask += bit = _t[maskdata[i] & 0xf];
424		good &= _g[maskdata[i] & 0xf];
425		if (zeroes && bit)
426			good = 0;
427		if (bit == 0)
428			zeroes = 1;
429	}
430
431	/*
432	 * Always return the number of bits found, but as a negative
433	 * if the mask wasn't one we like.
434	 */
435	return good ? mask : -mask;
436}
437
438char *
439netmask_string(const struct sockaddr *mask, int len, int family)
440{
441	static char smask[INET6_ADDRSTRLEN];
442	struct sockaddr_in nsin;
443	struct sockaddr_in6 nsin6;
444
445	if (len >= 0)
446		snprintf(smask, sizeof(smask), "%d", len);
447	else {
448		switch (family) {
449		case AF_INET:
450			memset(&nsin, 0, sizeof(nsin));
451			memcpy(&nsin, mask, mask->sa_len);
452			snprintf(smask, sizeof(smask), "%s",
453			    inet_ntoa(nsin.sin_addr));
454			break;
455		case AF_INET6:
456			memset(&nsin6, 0, sizeof(nsin6));
457			memcpy(&nsin6, mask, mask->sa_len);
458			inet_ntop(family, &nsin6.sin6_addr, smask,
459			    sizeof(smask));
460			break;
461		default:
462			snprintf(smask, sizeof(smask), "%s", any_ntoa(mask));
463		}
464	}
465
466	return smask;
467}
468
469const char *
470routename(const struct sockaddr *sa, struct sockaddr *nm, int flags)
471{
472	const char *cp;
473	static char line[50];
474	struct hostent *hp;
475	static char domain[MAXHOSTNAMELEN + 1];
476	static int first = 1;
477	struct in_addr in;
478	int nml;
479
480	if ((flags & RTF_HOST) == 0)
481		return netname(sa, nm);
482
483	if (first) {
484		first = 0;
485		if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
486		    (cp = strchr(domain, '.')))
487			(void)strlcpy(domain, cp + 1, sizeof(domain));
488		else
489			domain[0] = 0;
490	}
491
492	if (sa->sa_len == 0)
493		strlcpy(line, "default", sizeof(line));
494	else switch (sa->sa_family) {
495
496	case AF_INET:
497		in = ((const struct sockaddr_in *)sa)->sin_addr;
498		nml = netmask_length(nm, AF_INET);
499
500		cp = 0;
501		if (in.s_addr == INADDR_ANY || sa->sa_len < 4) {
502			if (nml == 0)
503				cp = "default";
504			else {
505				static char notdefault[sizeof(NOTDEFSTRING)];
506
507				snprintf(notdefault, sizeof(notdefault),
508				    "0.0.0.0/%s",
509				    netmask_string(nm, nml, AF_INET));
510				cp = notdefault;
511			}
512		}
513		if (cp == 0 && !nflag) {
514			hp = gethostbyaddr((char *)&in, sizeof(struct in_addr),
515				AF_INET);
516			if (hp) {
517				char *ccp;
518				if ((ccp = strchr(hp->h_name, '.')) &&
519				    !strcmp(ccp + 1, domain))
520					*ccp = '\0';
521				cp = hp->h_name;
522			}
523		}
524		if (cp)
525			(void)strlcpy(line, cp, sizeof(line));
526		else
527			(void)strlcpy(line, inet_ntoa(in), sizeof(line));
528		break;
529
530	case AF_LINK:
531		return link_ntoa((const struct sockaddr_dl *)sa);
532
533#ifdef INET6
534	case AF_INET6:
535	    {
536		struct sockaddr_in6 sin6;
537		int niflags;
538		char nihost[NI_MAXHOST];
539
540		niflags = 0;
541		if (nflag)
542			niflags |= NI_NUMERICHOST;
543		memset(&sin6, 0, sizeof(sin6));
544		memcpy(&sin6, sa, sa->sa_len);
545		sin6.sin6_len = sizeof(struct sockaddr_in6);
546		sin6.sin6_family = AF_INET6;
547#ifdef __KAME__
548		if (sa->sa_len == sizeof(struct sockaddr_in6) &&
549		    (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr) ||
550		     IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr)) &&
551		    sin6.sin6_scope_id == 0) {
552			sin6.sin6_scope_id =
553			    ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]);
554			sin6.sin6_addr.s6_addr[2] = 0;
555			sin6.sin6_addr.s6_addr[3] = 0;
556		}
557#endif
558		nml = netmask_length(nm, AF_INET6);
559		if (IN6_IS_ADDR_UNSPECIFIED(&sin6.sin6_addr)) {
560			if (nml == 0)
561				strlcpy(line, "::", sizeof(line));
562			else
563				/* noncontiguous never happens in ipv6 */
564				snprintf(line, sizeof(line), "::/%d", nml);
565		}
566		else if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
567		    nihost, sizeof(nihost), NULL, 0, niflags) != 0)
568			strlcpy(line, "invalid", sizeof(line));
569		else {
570			char *ccp;
571			if (!nflag && (ccp = strchr(nihost, '.')) &&
572			    strcmp(ccp + 1, domain) == 0)
573				*ccp = '\0';
574			strlcpy(line, nihost, sizeof(line));
575		}
576		break;
577	    }
578#endif
579
580#ifndef SMALL
581	case AF_ISO:
582		(void)snprintf(line, sizeof line, "iso %s",
583		    iso_ntoa(&((const struct sockaddr_iso *)sa)->siso_addr));
584		break;
585
586	case AF_APPLETALK:
587		(void)snprintf(line, sizeof(line), "atalk %d.%d",
588		    ((const struct sockaddr_at *)sa)->sat_addr.s_net,
589		    ((const struct sockaddr_at *)sa)->sat_addr.s_node);
590		break;
591	case AF_MPLS:
592		{
593		union mpls_shim ms;
594		const union mpls_shim *pms;
595		size_t psize = sizeof(struct sockaddr_mpls), len;
596
597		ms.s_addr =((const struct sockaddr_mpls*)sa)->smpls_addr.s_addr;
598		ms.s_addr = ntohl(ms.s_addr);
599
600		len = snprintf(line, sizeof(line), "%u", ms.shim.label);
601		if (len >= sizeof(line))
602			errx(1, "snprintf");
603		pms = &((const struct sockaddr_mpls*)sa)->smpls_addr;
604		while (psize < sa->sa_len) {
605			size_t alen;
606			pms++;
607			ms.s_addr = ntohl(pms->s_addr);
608			alen = snprintf(line + len, sizeof(line) - len, " %u",
609			    ms.shim.label);
610			if (alen >= sizeof(line) - len)
611				errx(1, "snprintf");
612			len += alen;
613			psize += sizeof(ms);
614		}
615		break;
616		}
617#endif /* SMALL */
618
619	default:
620		(void)snprintf(line, sizeof line, "(%d) %s",
621			sa->sa_family, any_ntoa(sa));
622		break;
623
624	}
625	return line;
626}
627
628/*
629 * Return the name of the network whose address is given.
630 * The address is assumed to be that of a net or subnet, not a host.
631 */
632const char *
633netname(const struct sockaddr *sa, struct sockaddr *nm)
634{
635	const char *cp = 0;
636	static char line[50];
637	struct netent *np = 0;
638	u_int32_t net, mask;
639	u_int32_t i;
640	int subnetshift, nml;
641	struct in_addr in;
642
643	switch (sa->sa_family) {
644
645	case AF_INET:
646		in = ((const struct sockaddr_in *)sa)->sin_addr;
647		i = ntohl(in.s_addr);
648		nml = netmask_length(nm, AF_INET);
649		if (i == 0) {
650			if (nml == 0)
651				cp = "default";
652			else {
653				static char notdefault[sizeof(NOTDEFSTRING)];
654
655				snprintf(notdefault, sizeof(notdefault),
656				    "0.0.0.0/%s",
657				    netmask_string(nm, nml, AF_INET));
658				cp = notdefault;
659			}
660		}
661		else if (!nflag) {
662			if (IN_CLASSA(i)) {
663				mask = IN_CLASSA_NET;
664				subnetshift = 8;
665			} else if (IN_CLASSB(i)) {
666				mask = IN_CLASSB_NET;
667				subnetshift = 8;
668			} else {
669				mask = IN_CLASSC_NET;
670				subnetshift = 4;
671			}
672			/*
673			 * If there are more bits than the standard mask
674			 * would suggest, subnets must be in use.
675			 * Guess at the subnet mask, assuming reasonable
676			 * width subnet fields.
677			 */
678			while (i &~ mask)
679				mask = (int32_t)mask >> subnetshift;
680			net = i & mask;
681			while ((mask & 1) == 0)
682				mask >>= 1, net >>= 1;
683			np = getnetbyaddr(net, AF_INET);
684			if (np)
685				cp = np->n_name;
686		}
687		if (cp)
688			(void)strlcpy(line, cp, sizeof(line));
689		else {
690			if (nml == 0)
691				strlcpy(line, inet_ntoa(in), sizeof(line));
692			else if (nml < 0) {
693				snprintf(line, sizeof(line), "%s&%s",
694				    inet_ntoa(in),
695				    netmask_string(nm, nml, AF_INET));
696			} else {
697				snprintf(line, sizeof(line), "%s/%d",
698				    inet_ntoa(in), nml);
699			}
700		}
701		break;
702
703	case AF_LINK:
704		return link_ntoa((const struct sockaddr_dl *)sa);
705
706#ifdef INET6
707	case AF_INET6:
708	    {
709		struct sockaddr_in6 sin6;
710		int niflags;
711
712		niflags = 0;
713		if (nflag)
714			niflags |= NI_NUMERICHOST;
715		memset(&sin6, 0, sizeof(sin6));
716		memcpy(&sin6, sa, sa->sa_len);
717		sin6.sin6_len = sizeof(struct sockaddr_in6);
718		sin6.sin6_family = AF_INET6;
719#ifdef __KAME__
720		if (sa->sa_len == sizeof(struct sockaddr_in6) &&
721		    (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr) ||
722		     IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr)) &&
723		    sin6.sin6_scope_id == 0) {
724			sin6.sin6_scope_id =
725			    ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]);
726			sin6.sin6_addr.s6_addr[2] = 0;
727			sin6.sin6_addr.s6_addr[3] = 0;
728		}
729#endif
730		nml = netmask_length(nm, AF_INET6);
731		if (IN6_IS_ADDR_UNSPECIFIED(&sin6.sin6_addr)) {
732			if (nml == 0)
733				strlcpy(line, "::", sizeof(line));
734			else
735				/* noncontiguous never happens in ipv6 */
736				snprintf(line, sizeof(line), "::/%d", nml);
737		}
738		else if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
739		    line, sizeof(line), NULL, 0, niflags) != 0)
740			strlcpy(line, "invalid", sizeof(line));
741		break;
742	    }
743#endif
744
745#ifndef SMALL
746	case AF_ISO:
747		(void)snprintf(line, sizeof line, "iso %s",
748		    iso_ntoa(&((const struct sockaddr_iso *)sa)->siso_addr));
749		break;
750
751	case AF_APPLETALK:
752		(void)snprintf(line, sizeof(line), "atalk %d.%d",
753		    ((const struct sockaddr_at *)sa)->sat_addr.s_net,
754		    ((const struct sockaddr_at *)sa)->sat_addr.s_node);
755		break;
756#endif /* SMALL */
757
758	default:
759		(void)snprintf(line, sizeof line, "af %d: %s",
760			sa->sa_family, any_ntoa(sa));
761		break;
762	}
763	return line;
764}
765
766static const char *
767route_strerror(int error)
768{
769
770	switch (error) {
771	case ESRCH:
772		return "not in table";
773	case EBUSY:
774		return "entry in use";
775	case ENOBUFS:
776		return "routing table overflow";
777	default:
778		return strerror(error);
779	}
780}
781
782static void
783set_metric(const char *value, int key)
784{
785	int flag = 0;
786	uint64_t noval, *valp = &noval;
787
788	switch (key) {
789#define caseof(x, y, z) \
790	case x: valp = (uint64_t *)&rt_metrics.z; flag = y; break
791	caseof(K_MTU, RTV_MTU, rmx_mtu);
792	caseof(K_HOPCOUNT, RTV_HOPCOUNT, rmx_hopcount);
793	caseof(K_EXPIRE, RTV_EXPIRE, rmx_expire);
794	caseof(K_RECVPIPE, RTV_RPIPE, rmx_recvpipe);
795	caseof(K_SENDPIPE, RTV_SPIPE, rmx_sendpipe);
796	caseof(K_SSTHRESH, RTV_SSTHRESH, rmx_ssthresh);
797	caseof(K_RTT, RTV_RTT, rmx_rtt);
798	caseof(K_RTTVAR, RTV_RTTVAR, rmx_rttvar);
799	}
800	rtm_inits |= flag;
801	if (lockrest || locking)
802		rt_metrics.rmx_locks |= flag;
803	if (locking)
804		locking = 0;
805	*valp = strtoul(value, NULL, 0);
806}
807
808static int
809newroute(int argc, char *const *argv)
810{
811	const char *cmd, *dest = "", *gateway = "";
812	int ishost = 0, ret, attempts, oerrno, flags = RTF_STATIC;
813	int key;
814	struct hostent *hp = 0;
815	struct sou sou, *soup = &sou;
816
817	sou.so_dst = calloc(1, sizeof(union sockunion));
818	sou.so_gate = calloc(1, sizeof(union sockunion));
819	sou.so_mask = calloc(1, sizeof(union sockunion));
820	sou.so_genmask = calloc(1, sizeof(union sockunion));
821	sou.so_ifa = calloc(1, sizeof(union sockunion));
822	sou.so_ifp = calloc(1, sizeof(union sockunion));
823	sou.so_mpls = calloc(1, sizeof(union sockunion));
824
825	if (sou.so_dst == NULL || sou.so_gate == NULL || sou.so_mask == NULL ||
826	    sou.so_genmask == NULL || sou.so_ifa == NULL || sou.so_ifp == NULL ||
827	    sou.so_mpls == NULL)
828		errx(EXIT_FAILURE, "Cannot allocate memory");
829
830	cmd = argv[0];
831	af = AF_UNSPEC;
832	if (*cmd != 'g') {
833		/* Don't want to read back our messages */
834		prog_shutdown(sock, SHUT_RD);
835	}
836	while (--argc > 0) {
837		if (**(++argv)== '-') {
838			switch (key = keyword(1 + *argv)) {
839
840			case K_SA:
841				af = PF_ROUTE;
842				aflen = sizeof(union sockunion);
843				break;
844
845#ifndef SMALL
846			case K_ATALK:
847				af = AF_APPLETALK;
848				aflen = sizeof(struct sockaddr_at);
849				break;
850#endif
851
852			case K_INET:
853				af = AF_INET;
854				aflen = sizeof(struct sockaddr_in);
855				break;
856
857#ifdef INET6
858			case K_INET6:
859				af = AF_INET6;
860				aflen = sizeof(struct sockaddr_in6);
861				break;
862#endif
863
864			case K_LINK:
865				af = AF_LINK;
866				aflen = sizeof(struct sockaddr_dl);
867				break;
868
869#ifndef SMALL
870			case K_OSI:
871			case K_ISO:
872				af = AF_ISO;
873				aflen = sizeof(struct sockaddr_iso);
874				break;
875			case K_MPLS:
876				af = AF_MPLS;
877				aflen = sizeof(struct sockaddr_mpls);
878				break;
879			case K_TAG:
880				if (!--argc)
881					usage(1+*argv);
882				af = AF_MPLS;
883				aflen = sizeof(struct sockaddr_mpls);
884				(void)getaddr(RTA_TAG, *++argv, 0, soup);
885				break;
886#endif /* SMALL */
887
888			case K_IFACE:
889			case K_INTERFACE:
890				iflag++;
891				break;
892			case K_NOSTATIC:
893				flags &= ~RTF_STATIC;
894				break;
895			case K_LLINFO:
896				flags |= RTF_LLINFO;
897				break;
898			case K_LOCK:
899				locking = 1;
900				break;
901			case K_LOCKREST:
902				lockrest = 1;
903				break;
904			case K_HOST:
905				forcehost++;
906				break;
907			case K_REJECT:
908				flags |= RTF_REJECT;
909				break;
910			case K_NOREJECT:
911				flags &= ~RTF_REJECT;
912				break;
913			case K_BLACKHOLE:
914				flags |= RTF_BLACKHOLE;
915				break;
916			case K_NOBLACKHOLE:
917				flags &= ~RTF_BLACKHOLE;
918				break;
919			case K_CLONED:
920				flags |= RTF_CLONED;
921				break;
922			case K_NOCLONED:
923				flags &= ~RTF_CLONED;
924				break;
925			case K_PROTO1:
926				flags |= RTF_PROTO1;
927				break;
928			case K_PROTO2:
929				flags |= RTF_PROTO2;
930				break;
931			case K_PROXY:
932				flags |= RTF_ANNOUNCE;
933				break;
934			case K_CLONING:
935				flags |= RTF_CLONING;
936				break;
937			case K_NOCLONING:
938				flags &= ~RTF_CLONING;
939				break;
940			case K_XRESOLVE:
941				flags |= RTF_XRESOLVE;
942				break;
943			case K_STATIC:
944				flags |= RTF_STATIC;
945				break;
946			case K_IFA:
947				if (!--argc)
948					usage(1+*argv);
949				(void)getaddr(RTA_IFA, *++argv, 0, soup);
950				break;
951			case K_IFP:
952				if (!--argc)
953					usage(1+*argv);
954				(void)getaddr(RTA_IFP, *++argv, 0, soup);
955				break;
956			case K_GENMASK:
957				if (!--argc)
958					usage(1+*argv);
959				(void)getaddr(RTA_GENMASK, *++argv, 0, soup);
960				break;
961			case K_GATEWAY:
962				if (!--argc)
963					usage(1+*argv);
964				(void)getaddr(RTA_GATEWAY, *++argv, 0, soup);
965				break;
966			case K_DST:
967				if (!--argc)
968					usage(1+*argv);
969				ishost = getaddr(RTA_DST, *++argv, &hp, soup);
970				dest = *argv;
971				break;
972			case K_NETMASK:
973				if (!--argc)
974					usage(1+*argv);
975				(void)getaddr(RTA_NETMASK, *++argv, 0, soup);
976				/* FALLTHROUGH */
977			case K_NET:
978				forcenet++;
979				break;
980			case K_PREFIXLEN:
981				if (!--argc)
982					usage(1+*argv);
983				ishost = prefixlen(*++argv, soup);
984				break;
985			case K_MTU:
986			case K_HOPCOUNT:
987			case K_EXPIRE:
988			case K_RECVPIPE:
989			case K_SENDPIPE:
990			case K_SSTHRESH:
991			case K_RTT:
992			case K_RTTVAR:
993				if (!--argc)
994					usage(1+*argv);
995				set_metric(*++argv, key);
996				break;
997			default:
998				usage(1+*argv);
999			}
1000		} else {
1001			if ((rtm_addrs & RTA_DST) == 0) {
1002				dest = *argv;
1003				ishost = getaddr(RTA_DST, *argv, &hp, soup);
1004			} else if ((rtm_addrs & RTA_GATEWAY) == 0) {
1005				gateway = *argv;
1006				(void)getaddr(RTA_GATEWAY, *argv, &hp, soup);
1007			} else {
1008				ret = atoi(*argv);
1009
1010				if (ret == 0) {
1011				    if (strcmp(*argv, "0") == 0) {
1012					if (!qflag)  {
1013					    warnx("%s, %s",
1014						"old usage of trailing 0",
1015						"assuming route to if");
1016					}
1017				    } else
1018					usage(NULL);
1019				    iflag = 1;
1020				    continue;
1021				} else if (ret > 0 && ret < 10) {
1022				    if (!qflag) {
1023					warnx("%s, %s",
1024					    "old usage of trailing digit",
1025					    "assuming route via gateway");
1026				    }
1027				    iflag = 0;
1028				    continue;
1029				}
1030				(void)getaddr(RTA_NETMASK, *argv, 0, soup);
1031			}
1032		}
1033	}
1034	if (forcehost && forcenet)
1035		errx(EXIT_FAILURE, "-host and -net conflict");
1036	else if (forcehost)
1037		ishost = 1;
1038	else if (forcenet)
1039		ishost = 0;
1040	flags |= RTF_UP;
1041	if (ishost)
1042		flags |= RTF_HOST;
1043	if (iflag == 0)
1044		flags |= RTF_GATEWAY;
1045	for (attempts = 1; ; attempts++) {
1046		errno = 0;
1047		if ((ret = rtmsg(*cmd, flags, soup)) == 0)
1048			break;
1049		if (errno != ENETUNREACH && errno != ESRCH)
1050			break;
1051		if (af == AF_INET && *gateway && hp && hp->h_addr_list[1]) {
1052			hp->h_addr_list++;
1053			memmove(&soup->so_gate->sin.sin_addr, hp->h_addr_list[0],
1054			    hp->h_length);
1055		} else
1056			break;
1057	}
1058	if (*cmd == 'g')
1059		return ret != 0;
1060	if (!qflag) {
1061		oerrno = errno;
1062		(void)printf("%s %s %s", cmd, ishost? "host" : "net", dest);
1063		if (*gateway) {
1064			(void)printf(": gateway %s", gateway);
1065			if (attempts > 1 && ret == 0 && af == AF_INET)
1066			    (void)printf(" (%s)",
1067			        inet_ntoa(soup->so_gate->sin.sin_addr));
1068		}
1069		if (ret == 0)
1070			(void)printf("\n");
1071		else
1072			(void)printf(": %s\n", route_strerror(oerrno));
1073	}
1074	free(sou.so_dst);
1075	free(sou.so_gate);
1076	free(sou.so_mask);
1077	free(sou.so_genmask);
1078	free(sou.so_ifa);
1079	free(sou.so_ifp);
1080	free(sou.so_mpls);
1081
1082	return ret != 0;
1083}
1084
1085static void
1086inet_makenetandmask(const u_int32_t net, struct sockaddr_in * const isin,
1087    struct sou *soup)
1088{
1089	struct sockaddr_in *sin;
1090	u_int32_t addr, mask = 0;
1091	char *cp;
1092
1093	rtm_addrs |= RTA_NETMASK;
1094	if (net == 0)
1095		mask = addr = 0;
1096	else if (net < 128) {
1097		addr = net << IN_CLASSA_NSHIFT;
1098		mask = IN_CLASSA_NET;
1099	} else if (net < 192) {
1100		addr = net << IN_CLASSA_NSHIFT;
1101		mask = IN_CLASSB_NET;
1102	} else if (net < 224) {
1103		addr = net << IN_CLASSA_NSHIFT;
1104		mask = IN_CLASSC_NET;
1105	} else if (net < 256) {
1106		addr = net << IN_CLASSA_NSHIFT;
1107		mask = IN_CLASSD_NET;
1108	} else if (net < 49152) { /* 192 * 256 */
1109		addr = net << IN_CLASSB_NSHIFT;
1110		mask = IN_CLASSB_NET;
1111	} else if (net < 57344) { /* 224 * 256 */
1112		addr = net << IN_CLASSB_NSHIFT;
1113		mask = IN_CLASSC_NET;
1114	} else if (net < 65536) {
1115		addr = net << IN_CLASSB_NSHIFT;
1116		mask = IN_CLASSB_NET;
1117	} else if (net < 14680064L) { /* 224 * 65536 */
1118		addr = net << IN_CLASSC_NSHIFT;
1119		mask = IN_CLASSC_NET;
1120	} else if (net < 16777216L) {
1121		addr = net << IN_CLASSC_NSHIFT;
1122		mask = IN_CLASSD_NET;
1123	} else {
1124		addr = net;
1125		if ((addr & IN_CLASSA_HOST) == 0)
1126			mask =  IN_CLASSA_NET;
1127		else if ((addr & IN_CLASSB_HOST) == 0)
1128			mask =  IN_CLASSB_NET;
1129		else if ((addr & IN_CLASSC_HOST) == 0)
1130			mask =  IN_CLASSC_NET;
1131		else
1132			mask = -1;
1133	}
1134	isin->sin_addr.s_addr = htonl(addr);
1135	sin = &soup->so_mask->sin;
1136	sin->sin_addr.s_addr = htonl(mask);
1137	sin->sin_len = 0;
1138	sin->sin_family = 0;
1139	cp = (char *)(&sin->sin_addr + 1);
1140	while (*--cp == 0 && cp > (char *)sin)
1141		;
1142	sin->sin_len = 1 + cp - (char *)sin;
1143	sin->sin_family = AF_INET;
1144}
1145
1146#ifdef INET6
1147/*
1148 * XXX the function may need more improvement...
1149 */
1150static int
1151inet6_makenetandmask(const struct sockaddr_in6 * const sin6, struct sou *soup)
1152{
1153	const char *plen;
1154	struct in6_addr in6;
1155
1156	plen = NULL;
1157	if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) &&
1158	    sin6->sin6_scope_id == 0) {
1159		plen = "0";
1160	} else if ((sin6->sin6_addr.s6_addr[0] & 0xe0) == 0x20) {
1161		/* aggregatable global unicast - RFC2374 */
1162		memset(&in6, 0, sizeof(in6));
1163		if (!memcmp(&sin6->sin6_addr.s6_addr[8], &in6.s6_addr[8], 8))
1164			plen = "64";
1165	}
1166
1167	if (!plen || strcmp(plen, "128") == 0)
1168		return 1;
1169	else {
1170		rtm_addrs |= RTA_NETMASK;
1171		(void)prefixlen(plen, soup);
1172		return 0;
1173	}
1174}
1175#endif
1176
1177/*
1178 * Interpret an argument as a network address of some kind,
1179 * returning 1 if a host address, 0 if a network address.
1180 */
1181static int
1182getaddr(int which, const char *s, struct hostent **hpp, struct sou *soup)
1183{
1184	sup su;
1185	struct hostent *hp;
1186	struct netent *np;
1187	u_int32_t val;
1188	char *t;
1189	int afamily;  /* local copy of af so we can change it */
1190
1191	if (af == AF_UNSPEC) {
1192		af = AF_INET;
1193		aflen = sizeof(struct sockaddr_in);
1194	}
1195	afamily = af;
1196	rtm_addrs |= which;
1197	switch (which) {
1198	case RTA_DST:
1199		su = soup->so_dst;
1200		break;
1201	case RTA_GATEWAY:
1202		su = soup->so_gate;
1203		break;
1204	case RTA_NETMASK:
1205		su = soup->so_mask;
1206		break;
1207	case RTA_GENMASK:
1208		su = soup->so_genmask;
1209		break;
1210	case RTA_IFP:
1211		su = soup->so_ifp;
1212		afamily = AF_LINK;
1213		break;
1214	case RTA_IFA:
1215		su = soup->so_ifa;
1216		su->sa.sa_family = af;
1217		break;
1218#ifndef SMALL
1219	case RTA_TAG:
1220		su = soup->so_mpls;
1221		afamily = AF_MPLS;
1222		break;
1223#endif
1224	default:
1225		su = NULL;
1226		usage("Internal Error");
1227		/*NOTREACHED*/
1228	}
1229	su->sa.sa_len = aflen;
1230	su->sa.sa_family = afamily; /* cases that don't want it have left already */
1231	if (strcmp(s, "default") == 0) {
1232		switch (which) {
1233		case RTA_DST:
1234			forcenet++;
1235			(void)getaddr(RTA_NETMASK, s, 0, soup);
1236			break;
1237		case RTA_NETMASK:
1238		case RTA_GENMASK:
1239			su->sa.sa_len = 0;
1240		}
1241		return 0;
1242	}
1243	switch (afamily) {
1244#ifdef INET6
1245	case AF_INET6:
1246	    {
1247		struct addrinfo hints, *res;
1248		char *slash = 0;
1249
1250		if (which == RTA_DST && (slash = (strrchr(s, '/'))) != 0)
1251			*slash = '\0';
1252		memset(&hints, 0, sizeof(hints));
1253		hints.ai_family = afamily;	/*AF_INET6*/
1254		hints.ai_flags = AI_NUMERICHOST;
1255		hints.ai_socktype = SOCK_DGRAM;		/*dummy*/
1256		if (getaddrinfo(s, "0", &hints, &res) != 0) {
1257			hints.ai_flags = 0;
1258			if (slash) {
1259				*slash = '/';
1260				slash = 0;
1261			}
1262			if (getaddrinfo(s, "0", &hints, &res) != 0)
1263				errx(EXIT_FAILURE, "%s: bad value", s);
1264		}
1265		if (slash)
1266			*slash = '/';
1267		if (sizeof(su->sin6) != res->ai_addrlen)
1268			errx(EXIT_FAILURE, "%s: bad value", s);
1269		if (res->ai_next) {
1270			errx(EXIT_FAILURE,
1271			    "%s: address resolved to multiple values", s);
1272		}
1273		memcpy(&su->sin6, res->ai_addr, sizeof(su->sin6));
1274		freeaddrinfo(res);
1275#ifdef __KAME__
1276		if ((IN6_IS_ADDR_LINKLOCAL(&su->sin6.sin6_addr) ||
1277		     IN6_IS_ADDR_MC_LINKLOCAL(&su->sin6.sin6_addr)) &&
1278		    su->sin6.sin6_scope_id) {
1279			*(u_int16_t *)&su->sin6.sin6_addr.s6_addr[2] =
1280				htons(su->sin6.sin6_scope_id);
1281			su->sin6.sin6_scope_id = 0;
1282		}
1283#endif
1284		if (hints.ai_flags == AI_NUMERICHOST) {
1285			if (slash)
1286				return prefixlen(slash + 1, soup);
1287			if (which == RTA_DST)
1288				return inet6_makenetandmask(&su->sin6, soup);
1289			return 0;
1290		} else
1291			return 1;
1292	    }
1293#endif
1294
1295#ifndef SMALL
1296	case AF_OSI:
1297		su->siso.siso_addr = *iso_addr(s);
1298		if (which == RTA_NETMASK || which == RTA_GENMASK) {
1299			const char *cp = TSEL(&su->siso);
1300			su->siso.siso_nlen = 0;
1301			do {--cp ;} while ((cp > (char *)su) && (*cp == 0));
1302			su->siso.siso_len = 1 + cp - (char *)su;
1303		}
1304		return 1;
1305#endif /* SMALL */
1306
1307	case PF_ROUTE:
1308		su->sa.sa_len = sizeof(*su);
1309		sockaddr(s, &su->sa);
1310		return 1;
1311
1312#ifndef SMALL
1313	case AF_APPLETALK:
1314		t = strchr (s, '.');
1315		if (!t) {
1316badataddr:
1317			errx(EXIT_FAILURE, "bad address: %s", s);
1318		}
1319		val = atoi (s);
1320		if (val > 65535)
1321			goto badataddr;
1322		su->sat.sat_addr.s_net = val;
1323		val = atoi (t);
1324		if (val > 256)
1325			goto badataddr;
1326		su->sat.sat_addr.s_node = val;
1327		rtm_addrs |= RTA_NETMASK;
1328		return(forcehost || su->sat.sat_addr.s_node != 0);
1329	case AF_MPLS:
1330		if (which == RTA_DST)
1331			soup->so_dst = readtag(su, s);
1332		else if (which == RTA_TAG)
1333			soup->so_mpls = readtag(su, s);
1334		else
1335			errx(EXIT_FAILURE, "MPLS can be used only as "
1336			    "DST or TAG");
1337		return 1;
1338#endif
1339
1340	case AF_LINK:
1341		link_addr(s, &su->sdl);
1342		return 1;
1343
1344	case AF_INET:
1345	default:
1346		break;
1347	}
1348
1349	if (hpp == NULL)
1350		hpp = &hp;
1351	*hpp = NULL;
1352
1353	if ((t = strchr(s, '/')) != NULL && which == RTA_DST) {
1354		*t = '\0';
1355		if (forcenet == 0) {
1356			if ((val = inet_addr(s)) != INADDR_NONE) {
1357				inet_makenetandmask(htonl(val), &su->sin, soup);
1358				return prefixlen(&t[1], soup);
1359			}
1360		} else {
1361			if ((val = inet_network(s)) != INADDR_NONE) {
1362				inet_makenetandmask(val, &su->sin, soup);
1363				return prefixlen(&t[1], soup);
1364			}
1365		}
1366		*t = '/';
1367	}
1368	if (inet_aton(s, &su->sin.sin_addr) &&
1369	    (which != RTA_DST || forcenet == 0)) {
1370		val = su->sin.sin_addr.s_addr;
1371		if (inet_lnaof(su->sin.sin_addr) != INADDR_ANY)
1372			return 1;
1373		else {
1374			val = ntohl(val);
1375			goto netdone;
1376		}
1377	}
1378	if ((val = inet_network(s)) != INADDR_NONE ||
1379	    ((np = getnetbyname(s)) != NULL && (val = np->n_net) != 0)) {
1380netdone:
1381		if (which == RTA_DST)
1382			inet_makenetandmask(val, &su->sin, soup);
1383		return 0;
1384	}
1385	hp = gethostbyname(s);
1386	if (hp) {
1387		*hpp = hp;
1388		su->sin.sin_family = hp->h_addrtype;
1389		memmove(&su->sin.sin_addr, hp->h_addr, hp->h_length);
1390		return 1;
1391	}
1392	errx(EXIT_FAILURE, "%s: bad value", s);
1393	/*NOTREACHED*/
1394}
1395
1396#ifndef SMALL
1397static sup
1398readtag(sup su, const char *s)
1399{
1400	char *p, *n, *norig;
1401	int mplssize = 0;
1402	sup retsu = su;
1403
1404	n = strdup(s);
1405	if (n == NULL)
1406		errx(EXIT_FAILURE, "%s: Cannot allocate memory", s);
1407	norig = n;
1408	for (uint i = 0; i < strlen(n); i++)
1409		if(n[i] == ',')
1410			mplssize++;
1411
1412#define MPLS_NEW_SIZE (sizeof(struct sockaddr_mpls) + \
1413    mplssize * sizeof(union mpls_shim))
1414
1415	if (mplssize != 0 && sizeof(union sockunion) < MPLS_NEW_SIZE) {
1416		free(su);
1417		retsu = malloc(MPLS_NEW_SIZE);
1418		retsu->smpls.smpls_family = AF_MPLS;
1419	}
1420	retsu->smpls.smpls_len = MPLS_NEW_SIZE;
1421	mplssize = 0;
1422	while ((p = strchr(n, ',')) != NULL) {
1423		p[0] = '\0';
1424		addtag(retsu, n, mplssize);
1425		n = p + 1;
1426		mplssize++;
1427	}
1428	addtag(retsu, n, mplssize);
1429
1430	free(norig);
1431	return retsu;
1432}
1433
1434static void
1435addtag(sup su, const char *s, int where)
1436{
1437	union mpls_shim *ms = &su->smpls.smpls_addr;
1438
1439	if (atoi(s) < 0 || atoi(s) >= (1 << 20))
1440		errx(EXIT_FAILURE, "%s: Bad tag", s);
1441	ms[where].s_addr = 0;
1442	ms[where].shim.label = atoi(s);
1443	ms[where].s_addr = htonl(ms[where].s_addr);
1444}
1445#endif	/* SMALL */
1446
1447int
1448prefixlen(const char *s, struct sou *soup)
1449{
1450	int len = atoi(s), q, r;
1451	int max;
1452
1453	switch (af) {
1454	case AF_INET:
1455		max = sizeof(struct in_addr) * 8;
1456		break;
1457#ifdef INET6
1458	case AF_INET6:
1459		max = sizeof(struct in6_addr) * 8;
1460		break;
1461#endif
1462	default:
1463		errx(EXIT_FAILURE, "prefixlen is not supported with af %d", af);
1464		/*NOTREACHED*/
1465	}
1466
1467	rtm_addrs |= RTA_NETMASK;
1468	if (len < -1 || len > max)
1469		errx(EXIT_FAILURE, "%s: bad value", s);
1470
1471	q = len >> 3;
1472	r = len & 7;
1473	switch (af) {
1474	case AF_INET:
1475		memset(soup->so_mask, 0, sizeof(*soup->so_mask));
1476		soup->so_mask->sin.sin_family = AF_INET;
1477		soup->so_mask->sin.sin_len = sizeof(struct sockaddr_in);
1478		soup->so_mask->sin.sin_addr.s_addr = (len == 0 ? 0
1479				: htonl(0xffffffff << (32 - len)));
1480		break;
1481#ifdef INET6
1482	case AF_INET6:
1483		soup->so_mask->sin6.sin6_family = AF_INET6;
1484		soup->so_mask->sin6.sin6_len = sizeof(struct sockaddr_in6);
1485		memset(&soup->so_mask->sin6.sin6_addr, 0,
1486			sizeof(soup->so_mask->sin6.sin6_addr));
1487		if (q > 0)
1488			memset(&soup->so_mask->sin6.sin6_addr, 0xff, q);
1489		if (r > 0)
1490			*((u_char *)&soup->so_mask->sin6.sin6_addr + q) =
1491			    (0xff00 >> r) & 0xff;
1492		break;
1493#endif
1494	}
1495	return len == max;
1496}
1497
1498#ifndef SMALL
1499static void
1500interfaces(void)
1501{
1502	size_t needed;
1503	int mib[6];
1504	char *buf, *lim, *next;
1505	struct rt_msghdr *rtm;
1506
1507	mib[0] = CTL_NET;
1508	mib[1] = PF_ROUTE;
1509	mib[2] = 0;		/* protocol */
1510	mib[3] = 0;		/* wildcard address family */
1511	mib[4] = NET_RT_IFLIST;
1512	mib[5] = 0;		/* no flags */
1513	if (prog_sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
1514		err(EXIT_FAILURE, "route-sysctl-estimate");
1515	if (needed) {
1516		if ((buf = malloc(needed)) == NULL)
1517			err(EXIT_FAILURE, "malloc");
1518		if (prog_sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
1519			err(EXIT_FAILURE,
1520			    "actual retrieval of interface table");
1521		}
1522		lim = buf + needed;
1523		for (next = buf; next < lim; next += rtm->rtm_msglen) {
1524			rtm = (struct rt_msghdr *)next;
1525			print_rtmsg(rtm, rtm->rtm_msglen);
1526		}
1527		free(buf);
1528	}
1529}
1530
1531static void
1532monitor(void)
1533{
1534	int n;
1535	union {
1536		char msg[2048];
1537		struct rt_msghdr hdr;
1538	} u;
1539
1540	verbose = 1;
1541	if (debugonly) {
1542		interfaces();
1543		exit(0);
1544	}
1545	for(;;) {
1546		time_t now;
1547		n = prog_read(sock, &u, sizeof(u));
1548		now = time(NULL);
1549		(void)printf("got message of size %d on %s", n, ctime(&now));
1550		print_rtmsg(&u.hdr, n);
1551	}
1552}
1553
1554#endif /* SMALL */
1555
1556
1557struct {
1558	struct	rt_msghdr m_rtm;
1559	char	m_space[512];
1560} m_rtmsg;
1561
1562static int
1563rtmsg(int cmd, int flags, struct sou *soup)
1564{
1565	static int seq;
1566	int rlen;
1567	char *cp = m_rtmsg.m_space;
1568	int l;
1569
1570#define NEXTADDR(w, u) \
1571	if (rtm_addrs & (w)) {\
1572	    l = RT_ROUNDUP(u->sa.sa_len); memmove(cp, u, l); cp += l;\
1573	    if (verbose && ! shortoutput) sodump(u,#u);\
1574	}
1575
1576	errno = 0;
1577	memset(&m_rtmsg, 0, sizeof(m_rtmsg));
1578	if (cmd == 'a')
1579		cmd = RTM_ADD;
1580	else if (cmd == 'c')
1581		cmd = RTM_CHANGE;
1582	else if (cmd == 'g') {
1583#ifdef	SMALL
1584		return -1;
1585#else	/* SMALL */
1586		cmd = RTM_GET;
1587		if (soup->so_ifp->sa.sa_family == AF_UNSPEC) {
1588			soup->so_ifp->sa.sa_family = AF_LINK;
1589			soup->so_ifp->sa.sa_len = sizeof(struct sockaddr_dl);
1590			rtm_addrs |= RTA_IFP;
1591		}
1592#endif	/* SMALL */
1593	} else
1594		cmd = RTM_DELETE;
1595#define rtm m_rtmsg.m_rtm
1596	rtm.rtm_type = cmd;
1597	rtm.rtm_flags = flags;
1598	rtm.rtm_version = RTM_VERSION;
1599	rtm.rtm_seq = ++seq;
1600	rtm.rtm_addrs = rtm_addrs;
1601	rtm.rtm_rmx = rt_metrics;
1602	rtm.rtm_inits = rtm_inits;
1603
1604	if (rtm_addrs & RTA_NETMASK)
1605		mask_addr(soup);
1606	NEXTADDR(RTA_DST, soup->so_dst);
1607	NEXTADDR(RTA_GATEWAY, soup->so_gate);
1608	NEXTADDR(RTA_NETMASK, soup->so_mask);
1609	NEXTADDR(RTA_GENMASK, soup->so_genmask);
1610	NEXTADDR(RTA_IFP, soup->so_ifp);
1611	NEXTADDR(RTA_IFA, soup->so_ifa);
1612#ifndef SMALL
1613	NEXTADDR(RTA_TAG, soup->so_mpls);
1614#endif
1615	rtm.rtm_msglen = l = cp - (char *)&m_rtmsg;
1616	if (verbose && ! shortoutput) {
1617		if (rtm_addrs)
1618			putchar('\n');
1619		print_rtmsg(&rtm, l);
1620	}
1621	if (debugonly)
1622		return 0;
1623	if ((rlen = prog_write(sock, (char *)&m_rtmsg, l)) < 0) {
1624		warnx("writing to routing socket: %s", route_strerror(errno));
1625		return -1;
1626	}
1627	if (rlen < l) {
1628		warnx("write to routing socket, got %d for rlen", rlen);
1629		return 1;
1630	}
1631#ifndef	SMALL
1632	if (cmd == RTM_GET) {
1633		do {
1634			l = prog_read(sock,
1635			    (char *)&m_rtmsg, sizeof(m_rtmsg));
1636		} while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid));
1637		if (l < 0)
1638			err(EXIT_FAILURE, "read from routing socket");
1639		else
1640			return print_getmsg(&rtm, l, soup);
1641	}
1642#endif	/* SMALL */
1643#undef rtm
1644	return 0;
1645}
1646
1647static void
1648mask_addr(struct sou *soup)
1649{
1650	int olen = soup->so_mask->sa.sa_len;
1651	char *cp1 = olen + (char *)soup->so_mask, *cp2;
1652
1653	for (soup->so_mask->sa.sa_len = 0; cp1 > (char *)soup->so_mask; )
1654		if (*--cp1 != 0) {
1655			soup->so_mask->sa.sa_len = 1 + cp1 - (char *)soup->so_mask;
1656			break;
1657		}
1658	if ((rtm_addrs & RTA_DST) == 0)
1659		return;
1660	switch (soup->so_dst->sa.sa_family) {
1661	case AF_INET:
1662#ifdef INET6
1663	case AF_INET6:
1664#endif
1665#ifndef SMALL
1666	case AF_APPLETALK:
1667#endif /* SMALL */
1668	case 0:
1669		return;
1670#ifndef SMALL
1671	case AF_ISO:
1672		olen = MIN(soup->so_dst->siso.siso_nlen,
1673			   MAX(soup->so_mask->sa.sa_len - 6, 0));
1674		break;
1675#endif /* SMALL */
1676	}
1677	cp1 = soup->so_mask->sa.sa_len + 1 + (char *)soup->so_dst;
1678	cp2 = soup->so_dst->sa.sa_len + 1 + (char *)soup->so_dst;
1679	while (cp2 > cp1)
1680		*--cp2 = 0;
1681	cp2 = soup->so_mask->sa.sa_len + 1 + (char *)soup->so_mask;
1682	while (cp1 > soup->so_dst->sa.sa_data)
1683		*--cp1 &= *--cp2;
1684#ifndef SMALL
1685	switch (soup->so_dst->sa.sa_family) {
1686	case AF_ISO:
1687		soup->so_dst->siso.siso_nlen = olen;
1688		break;
1689	}
1690#endif /* SMALL */
1691}
1692
1693const char * const msgtypes[] = {
1694	[RTM_ADD] = "RTM_ADD: Add Route",
1695	[RTM_DELETE] = "RTM_DELETE: Delete Route",
1696	[RTM_CHANGE] = "RTM_CHANGE: Change Metrics or flags",
1697	[RTM_GET] = "RTM_GET: Report Metrics",
1698	[RTM_LOSING] = "RTM_LOSING: Kernel Suspects Partitioning",
1699	[RTM_REDIRECT] = "RTM_REDIRECT: Told to use different route",
1700	[RTM_MISS] = "RTM_MISS: Lookup failed on this address",
1701	[RTM_LOCK] = "RTM_LOCK: fix specified metrics",
1702	[RTM_OLDADD] = "RTM_OLDADD: caused by SIOCADDRT",
1703	[RTM_OLDDEL] = "RTM_OLDDEL: caused by SIOCDELRT",
1704	[RTM_RESOLVE] = "RTM_RESOLVE: Route created by cloning",
1705	[RTM_NEWADDR] = "RTM_NEWADDR: address being added to iface",
1706	[RTM_DELADDR] = "RTM_DELADDR: address being removed from iface",
1707	[RTM_OOIFINFO] = "RTM_OOIFINFO: iface status change (pre-1.5)",
1708	[RTM_OIFINFO] = "RTM_OIFINFO: iface status change (pre-64bit time)",
1709	[RTM_IFANNOUNCE] = "RTM_IFANNOUNCE: iface arrival/departure",
1710	[RTM_IEEE80211] = "RTM_IEEE80211: IEEE80211 wireless event",
1711	[RTM_IFINFO] = "RTM_IFINFO: iface status change",
1712	[RTM_CHGADDR] = "RTM_CHGADDR: address being changed on iface",
1713};
1714
1715const char metricnames[] =
1716"\011pksent\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire\2hopcount\1mtu";
1717const char routeflags[] =
1718"\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE\010MASK_PRESENT\011CLONING\012XRESOLVE\013LLINFO\014STATIC\015BLACKHOLE\016CLONED\017PROTO2\020PROTO1";
1719const char ifnetflags[] =
1720"\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6NOTRAILERS\7RUNNING\010NOARP\011PPROMISC\012ALLMULTI\013OACTIVE\014SIMPLEX\015LINK0\016LINK1\017LINK2\020MULTICAST";
1721const char addrnames[] =
1722"\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD\011TAG";
1723
1724
1725#ifndef SMALL
1726static const char *
1727linkstate(struct if_msghdr *ifm)
1728{
1729	static char buf[64];
1730
1731	switch (ifm->ifm_data.ifi_link_state) {
1732	case LINK_STATE_UNKNOWN:
1733		return "carrier: unknown";
1734	case LINK_STATE_DOWN:
1735		return "carrier: no carrier";
1736	case LINK_STATE_UP:
1737		return "carrier: active";
1738	default:
1739		(void)snprintf(buf, sizeof(buf), "carrier: 0x%x",
1740		    ifm->ifm_data.ifi_link_state);
1741		return buf;
1742	}
1743}
1744#endif /* SMALL */
1745
1746static void
1747print_rtmsg(struct rt_msghdr *rtm, int msglen)
1748{
1749	struct if_msghdr *ifm;
1750	struct ifa_msghdr *ifam;
1751	struct if_announcemsghdr *ifan;
1752	union {
1753		struct ieee80211_join_event join;
1754		struct ieee80211_leave_event leave;
1755		struct ieee80211_replay_event replay;
1756		struct ieee80211_michael_event michael;
1757	} ev;
1758	size_t evlen = 0;
1759
1760	if (verbose == 0)
1761		return;
1762	if (rtm->rtm_version != RTM_VERSION) {
1763		(void)printf("routing message version %d not understood\n",
1764		    rtm->rtm_version);
1765		return;
1766	}
1767	if (msgtypes[rtm->rtm_type])
1768		(void)printf("%s: ", msgtypes[rtm->rtm_type]);
1769	else
1770		(void)printf("#%d: ", rtm->rtm_type);
1771	(void)printf("len %d, ", rtm->rtm_msglen);
1772	switch (rtm->rtm_type) {
1773	case RTM_IFINFO:
1774		ifm = (struct if_msghdr *)rtm;
1775		(void)printf("if# %d, %s, flags: ", ifm->ifm_index,
1776#ifdef SMALL
1777		    ""
1778#else
1779		    linkstate(ifm)
1780#endif /* SMALL */
1781		    );
1782		bprintf(stdout, ifm->ifm_flags, ifnetflags);
1783		pmsg_addrs((char *)(ifm + 1), ifm->ifm_addrs);
1784		break;
1785	case RTM_NEWADDR:
1786	case RTM_DELADDR:
1787	case RTM_CHGADDR:
1788		ifam = (struct ifa_msghdr *)rtm;
1789		(void)printf("metric %d, flags: ", ifam->ifam_metric);
1790		bprintf(stdout, ifam->ifam_flags, routeflags);
1791		pmsg_addrs((char *)(ifam + 1), ifam->ifam_addrs);
1792		break;
1793	case RTM_IEEE80211:
1794		ifan = (struct if_announcemsghdr *)rtm;
1795		(void)printf("if# %d, what: ", ifan->ifan_index);
1796		switch (ifan->ifan_what) {
1797		case RTM_IEEE80211_ASSOC:
1798			printf("associate");
1799			break;
1800		case RTM_IEEE80211_REASSOC:
1801			printf("re-associate");
1802			break;
1803		case RTM_IEEE80211_DISASSOC:
1804			printf("disassociate");
1805			break;
1806		case RTM_IEEE80211_SCAN:
1807			printf("scan complete");
1808			break;
1809		case RTM_IEEE80211_JOIN:
1810			evlen = sizeof(ev.join);
1811			printf("join");
1812			break;
1813		case RTM_IEEE80211_LEAVE:
1814			evlen = sizeof(ev.leave);
1815			printf("leave");
1816			break;
1817		case RTM_IEEE80211_MICHAEL:
1818			evlen = sizeof(ev.michael);
1819			printf("michael");
1820			break;
1821		case RTM_IEEE80211_REPLAY:
1822			evlen = sizeof(ev.replay);
1823			printf("replay");
1824			break;
1825		default:
1826			evlen = 0;
1827			printf("#%d", ifan->ifan_what);
1828			break;
1829		}
1830		if (sizeof(*ifan) + evlen > ifan->ifan_msglen) {
1831			printf(" (truncated)\n");
1832			break;
1833		}
1834		(void)memcpy(&ev, (ifan + 1), evlen);
1835		switch (ifan->ifan_what) {
1836		case RTM_IEEE80211_JOIN:
1837		case RTM_IEEE80211_LEAVE:
1838			printf(" mac %" PRIETHER,
1839			    PRIETHER_ARGS(ev.join.iev_addr));
1840			break;
1841		case RTM_IEEE80211_REPLAY:
1842		case RTM_IEEE80211_MICHAEL:
1843			printf(" src %" PRIETHER " dst %" PRIETHER
1844			       " cipher %" PRIu8 " keyix %" PRIu8,
1845			       PRIETHER_ARGS(ev.replay.iev_src),
1846			       PRIETHER_ARGS(ev.replay.iev_dst),
1847			       ev.replay.iev_cipher,
1848			       ev.replay.iev_keyix);
1849			if (ifan->ifan_what == RTM_IEEE80211_REPLAY) {
1850				printf(" key rsc %#" PRIx64
1851				       " frame rsc %#" PRIx64,
1852				       ev.replay.iev_keyrsc, ev.replay.iev_rsc);
1853			}
1854			break;
1855		default:
1856			break;
1857		}
1858		printf("\n");
1859		break;
1860	case RTM_IFANNOUNCE:
1861		ifan = (struct if_announcemsghdr *)rtm;
1862		(void)printf("if# %d, what: ", ifan->ifan_index);
1863		switch (ifan->ifan_what) {
1864		case IFAN_ARRIVAL:
1865			printf("arrival");
1866			break;
1867		case IFAN_DEPARTURE:
1868			printf("departure");
1869			break;
1870		default:
1871			printf("#%d", ifan->ifan_what);
1872			break;
1873		}
1874		printf("\n");
1875		break;
1876	default:
1877		(void)printf("pid %d, seq %d, errno %d, flags: ",
1878			rtm->rtm_pid, rtm->rtm_seq, rtm->rtm_errno);
1879		bprintf(stdout, rtm->rtm_flags, routeflags);
1880		pmsg_common(rtm);
1881	}
1882}
1883
1884#ifndef	SMALL
1885static int
1886print_getmsg(struct rt_msghdr *rtm, int msglen, struct sou *soup)
1887{
1888	struct sockaddr *dst = NULL, *gate = NULL, *mask = NULL, *ifa = NULL, *mpls = NULL;
1889	struct sockaddr_dl *ifp = NULL;
1890	struct sockaddr *sa;
1891	char *cp;
1892	int i;
1893
1894	if (! shortoutput) {
1895		(void)printf("   route to: %s\n",
1896		    routename(&soup->so_dst->sa, NULL, RTF_HOST));
1897	}
1898	if (rtm->rtm_version != RTM_VERSION) {
1899		warnx("routing message version %d not understood",
1900		    rtm->rtm_version);
1901		return 1;
1902	}
1903	if (rtm->rtm_msglen > msglen) {
1904		warnx("message length mismatch, in packet %d, returned %d",
1905		    rtm->rtm_msglen, msglen);
1906	}
1907	if (rtm->rtm_errno)  {
1908		warnx("RTM_GET: %s (errno %d)",
1909		    strerror(rtm->rtm_errno), rtm->rtm_errno);
1910		return 1;
1911	}
1912	cp = ((char *)(rtm + 1));
1913	if (rtm->rtm_addrs)
1914		for (i = 1; i; i <<= 1)
1915			if (i & rtm->rtm_addrs) {
1916				sa = (struct sockaddr *)cp;
1917				switch (i) {
1918				case RTA_DST:
1919					dst = sa;
1920					break;
1921				case RTA_GATEWAY:
1922					gate = sa;
1923					break;
1924				case RTA_NETMASK:
1925					mask = sa;
1926					break;
1927				case RTA_IFP:
1928					if (sa->sa_family == AF_LINK &&
1929					   ((struct sockaddr_dl *)sa)->sdl_nlen)
1930						ifp = (struct sockaddr_dl *)sa;
1931					break;
1932				case RTA_IFA:
1933					ifa = sa;
1934					break;
1935				case RTA_TAG:
1936					mpls = sa;
1937					break;
1938				}
1939				RT_ADVANCE(cp, sa);
1940			}
1941	if (dst && mask)
1942		mask->sa_family = dst->sa_family;	/* XXX */
1943	if (dst && ! shortoutput)
1944		(void)printf("destination: %s\n",
1945		    routename(dst, mask, RTF_HOST));
1946	if (mask && ! shortoutput) {
1947		int savenflag = nflag;
1948
1949		nflag = 1;
1950		(void)printf("       mask: %s\n",
1951		    routename(mask, NULL, RTF_HOST));
1952		nflag = savenflag;
1953	}
1954	if (gate && rtm->rtm_flags & RTF_GATEWAY) {
1955		const char *name;
1956
1957		name = routename(gate, NULL, RTF_HOST);
1958		if (shortoutput) {
1959			if (*name == '\0')
1960				return 1;
1961			(void)printf("%s\n", name);
1962		} else
1963			(void)printf("    gateway: %s\n", name);
1964	}
1965	if (mpls) {
1966		const char *name;
1967		name = routename(mpls, NULL, RTF_HOST);
1968		if(shortoutput) {
1969			if (*name == '\0')
1970				return 1;
1971			printf("%s\n", name);
1972		} else
1973			printf("        Tag: %s\n", name);
1974	}
1975
1976	if (ifa && ! shortoutput)
1977		(void)printf(" local addr: %s\n",
1978		    routename(ifa, NULL, RTF_HOST));
1979	if (ifp && ! shortoutput)
1980		(void)printf("  interface: %.*s\n",
1981		    ifp->sdl_nlen, ifp->sdl_data);
1982	if (! shortoutput) {
1983		(void)printf("      flags: ");
1984		bprintf(stdout, rtm->rtm_flags, routeflags);
1985	}
1986
1987#define lock(f)	((rtm->rtm_rmx.rmx_locks & __CONCAT(RTV_,f)) ? 'L' : ' ')
1988#define msec(u)	(((u) + 500) / 1000)		/* usec to msec */
1989
1990	if (! shortoutput) {
1991		(void)printf("\n%s\n", "\
1992 recvpipe  sendpipe  ssthresh  rtt,msec    rttvar  hopcount      mtu     expire");
1993		printf("%8"PRId64"%c ", rtm->rtm_rmx.rmx_recvpipe, lock(RPIPE));
1994		printf("%8"PRId64"%c ", rtm->rtm_rmx.rmx_sendpipe, lock(SPIPE));
1995		printf("%8"PRId64"%c ", rtm->rtm_rmx.rmx_ssthresh, lock(SSTHRESH));
1996		printf("%8"PRId64"%c ", msec(rtm->rtm_rmx.rmx_rtt), lock(RTT));
1997		printf("%8"PRId64"%c ", msec(rtm->rtm_rmx.rmx_rttvar), lock(RTTVAR));
1998		printf("%8"PRId64"%c ", rtm->rtm_rmx.rmx_hopcount, lock(HOPCOUNT));
1999		printf("%8"PRId64"%c ", rtm->rtm_rmx.rmx_mtu, lock(MTU));
2000		if (rtm->rtm_rmx.rmx_expire)
2001			rtm->rtm_rmx.rmx_expire -= time(0);
2002		printf("%8"PRId64"%c\n", rtm->rtm_rmx.rmx_expire, lock(EXPIRE));
2003	}
2004#undef lock
2005#undef msec
2006#define	RTA_IGN	(RTA_DST|RTA_GATEWAY|RTA_NETMASK|RTA_IFP|RTA_IFA|RTA_BRD)
2007
2008	if (shortoutput)
2009		return (rtm->rtm_addrs & RTF_GATEWAY) == 0;
2010	else if (verbose)
2011		pmsg_common(rtm);
2012	else if (rtm->rtm_addrs &~ RTA_IGN) {
2013		(void)printf("sockaddrs: ");
2014		bprintf(stdout, rtm->rtm_addrs, addrnames);
2015		putchar('\n');
2016	}
2017	return 0;
2018#undef	RTA_IGN
2019}
2020#endif	/* SMALL */
2021
2022void
2023pmsg_common(struct rt_msghdr *rtm)
2024{
2025	(void)printf("\nlocks: ");
2026	bprintf(stdout, rtm->rtm_rmx.rmx_locks, metricnames);
2027	(void)printf(" inits: ");
2028	bprintf(stdout, rtm->rtm_inits, metricnames);
2029	pmsg_addrs((char *)(rtm + 1), rtm->rtm_addrs);
2030}
2031
2032static void
2033extract_addrs(const char *cp, int addrs, const struct sockaddr *sa[], int *nmfp)
2034{
2035	int i, nmf = -1;
2036
2037	for (i = 0; i < RTAX_MAX; i++) {
2038		if ((1 << i) & addrs) {
2039			sa[i] = (const struct sockaddr *)cp;
2040			if ((i == RTAX_DST || i == RTAX_IFA) &&
2041			    nmf == -1)
2042				nmf = sa[i]->sa_family;
2043			RT_ADVANCE(cp, sa[i]);
2044		} else
2045			sa[i] = NULL;
2046	}
2047
2048	if (nmfp != NULL)
2049		*nmfp = nmf;
2050}
2051
2052static void
2053pmsg_addrs(const char *cp, int addrs)
2054{
2055	const struct sockaddr *sa[RTAX_MAX];
2056	int i, nmf;
2057
2058	if (addrs != 0) {
2059		(void)printf("\nsockaddrs: ");
2060		bprintf(stdout, addrs, addrnames);
2061		(void)putchar('\n');
2062		extract_addrs(cp, addrs, sa, &nmf);
2063		for (i = 0; i < RTAX_MAX; i++) {
2064			if (sa[i] == NULL)
2065				continue;
2066
2067			if (i == RTAX_NETMASK && sa[i]->sa_len)
2068				(void)printf(" %s",
2069				    netmask_string(sa[i], -1, nmf));
2070			else
2071				(void)printf(" %s",
2072				    routename(sa[i], NULL, RTF_HOST));
2073		}
2074	}
2075	(void)putchar('\n');
2076	(void)fflush(stdout);
2077}
2078
2079static void
2080bprintf(FILE *fp, int b, const char *f)
2081{
2082	int i;
2083	int gotsome = 0;
2084	const uint8_t *s = (const uint8_t *)f;
2085
2086	if (b == 0) {
2087		fputs("none", fp);
2088		return;
2089	}
2090	while ((i = *s++) != 0) {
2091		if (b & (1 << (i-1))) {
2092			if (gotsome == 0)
2093				i = '<';
2094			else
2095				i = ',';
2096			(void)putc(i, fp);
2097			gotsome = 1;
2098			for (; (i = *s) > 32; s++)
2099				(void)putc(i, fp);
2100		} else
2101			while (*s > 32)
2102				s++;
2103	}
2104	if (gotsome)
2105		(void)putc('>', fp);
2106}
2107
2108int
2109keyword(const char *cp)
2110{
2111	struct keytab *kt = keywords;
2112
2113	while (kt->kt_cp && strcmp(kt->kt_cp, cp))
2114		kt++;
2115	return kt->kt_i;
2116}
2117
2118static void
2119sodump(sup su, const char *which)
2120{
2121#ifdef INET6
2122	char ntop_buf[NI_MAXHOST];
2123#endif
2124
2125	switch (su->sa.sa_family) {
2126	case AF_INET:
2127		(void)printf("%s: inet %s; ",
2128		    which, inet_ntoa(su->sin.sin_addr));
2129		break;
2130#ifndef SMALL
2131	case AF_APPLETALK:
2132		(void)printf("%s: atalk %d.%d; ",
2133		    which, su->sat.sat_addr.s_net, su->sat.sat_addr.s_node);
2134		break;
2135#endif
2136	case AF_LINK:
2137		(void)printf("%s: link %s; ",
2138		    which, link_ntoa(&su->sdl));
2139		break;
2140#ifdef INET6
2141	case AF_INET6:
2142		(void)printf("%s: inet6 %s; ",
2143		    which, inet_ntop(AF_INET6, &su->sin6.sin6_addr,
2144				     ntop_buf, sizeof(ntop_buf)));
2145		break;
2146#endif
2147#ifndef SMALL
2148	case AF_ISO:
2149		(void)printf("%s: iso %s; ",
2150		    which, iso_ntoa(&su->siso.siso_addr));
2151		break;
2152	case AF_MPLS:
2153	    {
2154		union mpls_shim ms;
2155		const union mpls_shim *pms;
2156		int psize = sizeof(struct sockaddr_mpls);
2157
2158		ms.s_addr = ntohl(su->smpls.smpls_addr.s_addr);
2159		printf("%s: mpls %u; ",
2160		    which, ms.shim.label);
2161
2162		pms = &su->smpls.smpls_addr;
2163		while(psize < su->smpls.smpls_len) {
2164			pms++;
2165			ms.s_addr = ntohl(pms->s_addr);
2166			printf("%u; ", ms.shim.label);
2167			psize += sizeof(ms);
2168		}
2169		break;
2170	    }
2171#endif /* SMALL */
2172	default:
2173		(void)printf("%s: (%d) %s; ",
2174		    which, su->sa.sa_family, any_ntoa(&su->sa));
2175	}
2176	(void)fflush(stdout);
2177}
2178
2179/* States*/
2180#define VIRGIN	0
2181#define GOTONE	1
2182#define GOTTWO	2
2183/* Inputs */
2184#define	DIGIT	(4*0)
2185#define	END	(4*1)
2186#define DELIM	(4*2)
2187
2188static void
2189sockaddr(const char *addr, struct sockaddr *sa)
2190{
2191	char *cp = (char *)sa;
2192	int size = sa->sa_len;
2193	char *cplim = cp + size;
2194	int byte = 0, state = VIRGIN, new = 0;
2195
2196	(void)memset(cp, 0, size);
2197	cp++;
2198	do {
2199		if ((*addr >= '0') && (*addr <= '9')) {
2200			new = *addr - '0';
2201		} else if ((*addr >= 'a') && (*addr <= 'f')) {
2202			new = *addr - 'a' + 10;
2203		} else if ((*addr >= 'A') && (*addr <= 'F')) {
2204			new = *addr - 'A' + 10;
2205		} else if (*addr == 0)
2206			state |= END;
2207		else
2208			state |= DELIM;
2209		addr++;
2210		switch (state /* | INPUT */) {
2211		case GOTTWO | DIGIT:
2212			*cp++ = byte; /*FALLTHROUGH*/
2213		case VIRGIN | DIGIT:
2214			state = GOTONE; byte = new; continue;
2215		case GOTONE | DIGIT:
2216			state = GOTTWO; byte = new + (byte << 4); continue;
2217		default: /* | DELIM */
2218			state = VIRGIN; *cp++ = byte; byte = 0; continue;
2219		case GOTONE | END:
2220		case GOTTWO | END:
2221			*cp++ = byte; /* FALLTHROUGH */
2222		case VIRGIN | END:
2223			break;
2224		}
2225		break;
2226	} while (cp < cplim);
2227	sa->sa_len = cp - (char *)sa;
2228}
2229