xref: /openbsd-src/usr.sbin/ospf6ctl/ospf6ctl.c (revision fc405d53b73a2d73393cb97f684863d17b583e38)
1 /*	$OpenBSD: ospf6ctl.c,v 1.53 2022/12/27 12:11:39 claudio Exp $ */
2 
3 /*
4  * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
5  * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
6  * Copyright (c) 2003 Henning Brauer <henning@openbsd.org>
7  *
8  * Permission to use, copy, modify, and distribute this software for any
9  * purpose with or without fee is hereby granted, provided that the above
10  * copyright notice and this permission notice appear in all copies.
11  *
12  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19  */
20 
21 #include <sys/types.h>
22 #include <sys/socket.h>
23 #include <sys/un.h>
24 #include <netinet/in.h>
25 #include <arpa/inet.h>
26 #include <net/if_media.h>
27 #include <net/if_types.h>
28 
29 #include <err.h>
30 #include <errno.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <unistd.h>
35 
36 #include "ospf6.h"
37 #include "ospf6d.h"
38 #include "ospfe.h"
39 #include "parser.h"
40 #include "log.h"
41 
42 __dead void	 usage(void);
43 int		 show_summary_msg(struct imsg *);
44 uint64_t	 get_ifms_type(uint8_t);
45 int		 show_interface_msg(struct imsg *);
46 int		 show_interface_detail_msg(struct imsg *);
47 const char	*print_link(int);
48 const char	*fmt_timeframe(time_t t);
49 const char	*fmt_timeframe_core(time_t t);
50 const char	*log_id(u_int32_t );
51 const char	*log_adv_rtr(u_int32_t);
52 void		 show_database_head(struct in_addr, char *, u_int16_t);
53 int		 show_database_msg(struct imsg *);
54 char		*print_ls_type(u_int16_t);
55 void		 show_db_hdr_msg_detail(struct lsa_hdr *);
56 char		*print_rtr_link_type(u_int8_t);
57 const char	*print_ospf_flags(u_int8_t);
58 const char	*print_asext_flags(u_int32_t);
59 const char	*print_prefix_opt(u_int8_t);
60 int		 show_db_msg_detail(struct imsg *imsg);
61 int		 show_nbr_msg(struct imsg *);
62 const char	*print_ospf_options(u_int32_t);
63 int		 show_nbr_detail_msg(struct imsg *);
64 int		 show_rib_msg(struct imsg *);
65 void		 show_rib_head(struct in_addr, u_int8_t, u_int8_t);
66 const char	*print_ospf_rtr_flags(u_int8_t);
67 int		 show_rib_detail_msg(struct imsg *);
68 void		 show_fib_head(void);
69 int		 show_fib_msg(struct imsg *);
70 const char *	 get_media_descr(uint64_t);
71 const char *	 get_linkstate(uint8_t, int);
72 void		 print_baudrate(u_int64_t);
73 
74 struct imsgbuf	*ibuf;
75 
76 __dead void
77 usage(void)
78 {
79 	extern char *__progname;
80 
81 	fprintf(stderr, "usage: %s [-s socket] command [argument ...]\n",
82 	    __progname);
83 	exit(1);
84 }
85 
86 int
87 main(int argc, char *argv[])
88 {
89 	struct sockaddr_un	 sun;
90 	struct parse_result	*res;
91 	struct imsg		 imsg;
92 	unsigned int		 ifidx = 0;
93 	int			 ctl_sock, r;
94 	int			 done = 0, verbose = 0;
95 	int			 n;
96 	int			 ch;
97 	char			*sockname;
98 
99 	r = getrtable();
100 	if (asprintf(&sockname, "%s.%d", OSPF6D_SOCKET, r) == -1)
101 		err(1, "asprintf");
102 
103 	while ((ch = getopt(argc, argv, "s:")) != -1) {
104 		switch (ch) {
105 		case 's':
106 			sockname = optarg;
107 			break;
108 		default:
109 			usage();
110 			/* NOTREACHED */
111 		}
112 	}
113 	argc -= optind;
114 	argv += optind;
115 
116 	/* parse options */
117 	if ((res = parse(argc, argv)) == NULL)
118 		exit(1);
119 
120 	/* connect to ospf6d control socket */
121 	if ((ctl_sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
122 		err(1, "socket");
123 
124 	bzero(&sun, sizeof(sun));
125 	sun.sun_family = AF_UNIX;
126 	strlcpy(sun.sun_path, sockname, sizeof(sun.sun_path));
127 	if (connect(ctl_sock, (struct sockaddr *)&sun, sizeof(sun)) == -1)
128 		err(1, "connect: %s", sockname);
129 
130 	if (pledge("stdio", NULL) == -1)
131 		err(1, "pledge");
132 
133 	if ((ibuf = malloc(sizeof(struct imsgbuf))) == NULL)
134 		err(1, NULL);
135 	imsg_init(ibuf, ctl_sock);
136 	done = 0;
137 
138 	/* process user request */
139 	switch (res->action) {
140 	case NONE:
141 		usage();
142 		/* not reached */
143 	case SHOW:
144 	case SHOW_SUM:
145 		imsg_compose(ibuf, IMSG_CTL_SHOW_SUM, 0, 0, -1, NULL, 0);
146 		break;
147 	case SHOW_IFACE:
148 		printf("%-11s %-29s %-6s %-10s %-10s %-8s\n",
149 		    "Interface", "Address", "State", "HelloTimer", "Linkstate",
150 		    "Uptime");
151 		/*FALLTHROUGH*/
152 	case SHOW_IFACE_DTAIL:
153 		if (*res->ifname) {
154 			ifidx = if_nametoindex(res->ifname);
155 			if (ifidx == 0)
156 				errx(1, "no such interface %s", res->ifname);
157 		}
158 		imsg_compose(ibuf, IMSG_CTL_SHOW_INTERFACE, 0, 0, -1,
159 		    &ifidx, sizeof(ifidx));
160 		break;
161 	case SHOW_NBR:
162 		printf("%-15s %-3s %-12s %-9s %-11s %s\n", "ID", "Pri",
163 		    "State", "DeadTime", "Iface","Uptime");
164 		/*FALLTHROUGH*/
165 	case SHOW_NBR_DTAIL:
166 		imsg_compose(ibuf, IMSG_CTL_SHOW_NBR, 0, 0, -1, NULL, 0);
167 		break;
168 	case SHOW_DB:
169 		imsg_compose(ibuf, IMSG_CTL_SHOW_DATABASE, 0, 0, -1, NULL, 0);
170 		break;
171 	case SHOW_DBBYAREA:
172 		imsg_compose(ibuf, IMSG_CTL_SHOW_DATABASE, 0, 0, -1,
173 		    &res->area, sizeof(res->area));
174 		break;
175 	case SHOW_DBEXT:
176 		imsg_compose(ibuf, IMSG_CTL_SHOW_DB_EXT, 0, 0, -1, NULL, 0);
177 		break;
178 	case SHOW_DBLINK:
179 		imsg_compose(ibuf, IMSG_CTL_SHOW_DB_LINK, 0, 0, -1, NULL, 0);
180 		break;
181 	case SHOW_DBNET:
182 		imsg_compose(ibuf, IMSG_CTL_SHOW_DB_NET, 0, 0, -1, NULL, 0);
183 		break;
184 	case SHOW_DBRTR:
185 		imsg_compose(ibuf, IMSG_CTL_SHOW_DB_RTR, 0, 0, -1, NULL, 0);
186 		break;
187 	case SHOW_DBINTRA:
188 		imsg_compose(ibuf, IMSG_CTL_SHOW_DB_INTRA, 0, 0, -1, NULL, 0);
189 		break;
190 	case SHOW_DBSELF:
191 		imsg_compose(ibuf, IMSG_CTL_SHOW_DB_SELF, 0, 0, -1, NULL, 0);
192 		break;
193 	case SHOW_DBSUM:
194 		imsg_compose(ibuf, IMSG_CTL_SHOW_DB_SUM, 0, 0, -1, NULL, 0);
195 		break;
196 	case SHOW_DBASBR:
197 		imsg_compose(ibuf, IMSG_CTL_SHOW_DB_ASBR, 0, 0, -1, NULL, 0);
198 		break;
199 	case SHOW_RIB:
200 		printf("%-20s %-17s %-12s %-9s %-7s %-8s\n", "Destination",
201 		    "Nexthop", "Path Type", "Type", "Cost", "Uptime");
202 		/*FALLTHROUGH*/
203 	case SHOW_RIB_DTAIL:
204 		imsg_compose(ibuf, IMSG_CTL_SHOW_RIB, 0, 0, -1, NULL, 0);
205 		break;
206 	case SHOW_FIB:
207 		if (IN6_IS_ADDR_UNSPECIFIED(&res->addr))
208 			imsg_compose(ibuf, IMSG_CTL_KROUTE, 0, 0, -1,
209 			    &res->flags, sizeof(res->flags));
210 		else
211 			imsg_compose(ibuf, IMSG_CTL_KROUTE_ADDR, 0, 0, -1,
212 			    &res->addr, sizeof(res->addr));
213 		show_fib_head();
214 		break;
215 	case FIB:
216 		errx(1, "fib couple|decouple");
217 		break;
218 	case FIB_COUPLE:
219 		imsg_compose(ibuf, IMSG_CTL_FIB_COUPLE, 0, 0, -1, NULL, 0);
220 		printf("couple request sent.\n");
221 		done = 1;
222 		break;
223 	case FIB_DECOUPLE:
224 		imsg_compose(ibuf, IMSG_CTL_FIB_DECOUPLE, 0, 0, -1, NULL, 0);
225 		printf("decouple request sent.\n");
226 		done = 1;
227 		break;
228 	case LOG_VERBOSE:
229 		verbose = 1;
230 		/* FALLTHROUGH */
231 	case LOG_BRIEF:
232 		imsg_compose(ibuf, IMSG_CTL_LOG_VERBOSE, 0, 0, -1,
233 		    &verbose, sizeof(verbose));
234 		printf("logging request sent.\n");
235 		done = 1;
236 		break;
237 	case RELOAD:
238 #ifdef notyet
239 		imsg_compose(ibuf, IMSG_CTL_RELOAD, 0, 0, -1, NULL, 0);
240 		printf("reload request sent.\n");
241 		done = 1;
242 		break;
243 #else
244 		errx(1, "reload not supported");
245 #endif
246 	}
247 
248 	while (ibuf->w.queued)
249 		if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN)
250 			err(1, "write error");
251 
252 	while (!done) {
253 		if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
254 			errx(1, "imsg_read error");
255 		if (n == 0)
256 			errx(1, "pipe closed");
257 
258 		while (!done) {
259 			if ((n = imsg_get(ibuf, &imsg)) == -1)
260 				errx(1, "imsg_get error");
261 			if (n == 0)
262 				break;
263 			switch (res->action) {
264 			case SHOW:
265 			case SHOW_SUM:
266 				done = show_summary_msg(&imsg);
267 				break;
268 			case SHOW_IFACE:
269 				done = show_interface_msg(&imsg);
270 				break;
271 			case SHOW_IFACE_DTAIL:
272 				done = show_interface_detail_msg(&imsg);
273 				break;
274 			case SHOW_NBR:
275 				done = show_nbr_msg(&imsg);
276 				break;
277 			case SHOW_NBR_DTAIL:
278 				done = show_nbr_detail_msg(&imsg);
279 				break;
280 			case SHOW_DB:
281 			case SHOW_DBBYAREA:
282 			case SHOW_DBSELF:
283 				done = show_database_msg(&imsg);
284 				break;
285 			case SHOW_DBEXT:
286 			case SHOW_DBLINK:
287 			case SHOW_DBNET:
288 			case SHOW_DBRTR:
289 			case SHOW_DBINTRA:
290 			case SHOW_DBSUM:
291 			case SHOW_DBASBR:
292 				done = show_db_msg_detail(&imsg);
293 				break;
294 			case SHOW_RIB:
295 				done = show_rib_msg(&imsg);
296 				break;
297 			case SHOW_RIB_DTAIL:
298 				done = show_rib_detail_msg(&imsg);
299 				break;
300 			case SHOW_FIB:
301 				done = show_fib_msg(&imsg);
302 				break;
303 			case NONE:
304 			case FIB:
305 			case FIB_COUPLE:
306 			case FIB_DECOUPLE:
307 			case LOG_VERBOSE:
308 			case LOG_BRIEF:
309 			case RELOAD:
310 				break;
311 			}
312 			imsg_free(&imsg);
313 		}
314 	}
315 	close(ctl_sock);
316 	free(ibuf);
317 
318 	return (0);
319 }
320 
321 int
322 show_summary_msg(struct imsg *imsg)
323 {
324 	struct ctl_sum		*sum;
325 	struct ctl_sum_area	*sumarea;
326 
327 	switch (imsg->hdr.type) {
328 	case IMSG_CTL_SHOW_SUM:
329 		sum = imsg->data;
330 		printf("Router ID: %s\n", inet_ntoa(sum->rtr_id));
331 		printf("Uptime: %s\n", fmt_timeframe_core(sum->uptime));
332 
333 		printf("SPF delay is %d sec(s), hold time between two SPFs "
334 		    "is %d sec(s)\n", sum->spf_delay, sum->spf_hold_time);
335 		printf("Number of external LSA(s) %d\n", sum->num_ext_lsa);
336 		printf("Number of areas attached to this router: %d\n",
337 		    sum->num_area);
338 		break;
339 	case IMSG_CTL_SHOW_SUM_AREA:
340 		sumarea = imsg->data;
341 		printf("\nArea ID: %s\n", inet_ntoa(sumarea->area));
342 		printf("  Number of interfaces in this area: %d\n",
343 		    sumarea->num_iface);
344 		printf("  Number of fully adjacent neighbors in this "
345 		    "area: %d\n", sumarea->num_adj_nbr);
346 		printf("  SPF algorithm executed %d time(s)\n",
347 		    sumarea->num_spf_calc);
348 		printf("  Number LSA(s) %d\n", sumarea->num_lsa);
349 		break;
350 	case IMSG_CTL_END:
351 		printf("\n");
352 		return (1);
353 	default:
354 		break;
355 	}
356 
357 	return (0);
358 }
359 
360 uint64_t
361 get_ifms_type(uint8_t if_type)
362 {
363 	switch (if_type) {
364 	case IFT_ETHER:
365 		return (IFM_ETHER);
366 	case IFT_FDDI:
367 		return (IFM_FDDI);
368 	case IFT_CARP:
369 		return (IFM_CARP);
370 	case IFT_PPP:
371 		return (IFM_TDM);
372 	default:
373 		return (0);
374 	}
375 }
376 
377 int
378 show_interface_msg(struct imsg *imsg)
379 {
380 	struct ctl_iface	*iface;
381 	char			*netid;
382 
383 	switch (imsg->hdr.type) {
384 	case IMSG_CTL_SHOW_INTERFACE:
385 		iface = imsg->data;
386 
387 		if (asprintf(&netid, "%s", log_in6addr(&iface->addr)) == -1)
388 			err(1, NULL);
389 		printf("%-11s %-29s %-6s %-10s %-10s %s\n",
390 		    iface->name, netid, if_state_name(iface->state),
391 		    iface->hello_timer < 0 ? "-" :
392 		    fmt_timeframe_core(iface->hello_timer),
393 		    get_linkstate(iface->if_type, iface->linkstate),
394 		    fmt_timeframe_core(iface->uptime));
395 		free(netid);
396 		break;
397 	case IMSG_CTL_END:
398 		printf("\n");
399 		return (1);
400 	default:
401 		break;
402 	}
403 
404 	return (0);
405 }
406 
407 int
408 show_interface_detail_msg(struct imsg *imsg)
409 {
410 	struct ctl_iface	*iface;
411 
412 	switch (imsg->hdr.type) {
413 	case IMSG_CTL_SHOW_INTERFACE:
414 		iface = imsg->data;
415 		printf("\n");
416 		printf("Interface %s, line protocol is %s\n",
417 		    iface->name, print_link(iface->flags));
418 		printf("  Internet address %s Area %s\n",
419 		    log_in6addr(&iface->addr), inet_ntoa(iface->area));
420 		printf("  Link type %s, state %s, mtu %d",
421 		    get_media_descr(get_ifms_type(iface->if_type)),
422 		    get_linkstate(iface->if_type, iface->linkstate),
423 		    iface->mtu);
424 		if (iface->linkstate != LINK_STATE_DOWN &&
425 		    iface->baudrate > 0) {
426 		    printf(", ");
427 		    print_baudrate(iface->baudrate);
428 		}
429 		printf("\n");
430 		printf("  Router ID %s, network type %s, cost: %d\n",
431 		    inet_ntoa(iface->rtr_id),
432 		    if_type_name(iface->type), iface->metric);
433 		printf("  Transmit delay is %d sec(s), state %s, priority %d\n",
434 		    iface->transmit_delay, if_state_name(iface->state),
435 		    iface->priority);
436 		printf("  Designated Router (ID) %s\n",
437 		    inet_ntoa(iface->dr_id));
438 		printf("    Interface address %s\n",
439 		    log_in6addr(&iface->dr_addr));
440 		printf("  Backup Designated Router (ID) %s\n",
441 		    inet_ntoa(iface->bdr_id));
442 		printf("    Interface address %s\n",
443 		    log_in6addr(&iface->bdr_addr));
444 		printf("  Timer intervals configured, "
445 		    "hello %d, dead %d, wait %d, retransmit %d\n",
446 		     iface->hello_interval, iface->dead_interval,
447 		     iface->dead_interval, iface->rxmt_interval);
448 		if (iface->passive)
449 			printf("    Passive interface (No Hellos)\n");
450 		else if (iface->hello_timer < 0)
451 			printf("    Hello timer not running\n");
452 		else
453 			printf("    Hello timer due in %s\n",
454 			    fmt_timeframe_core(iface->hello_timer));
455 		printf("    Uptime %s\n", fmt_timeframe_core(iface->uptime));
456 		printf("  Neighbor count is %d, adjacent neighbor count is "
457 		    "%d\n", iface->nbr_cnt, iface->adj_cnt);
458 		break;
459 	case IMSG_CTL_END:
460 		printf("\n");
461 		return (1);
462 	default:
463 		break;
464 	}
465 
466 	return (0);
467 }
468 
469 const char *
470 print_link(int state)
471 {
472 	if (state & IFF_UP)
473 		return ("UP");
474 	else
475 		return ("DOWN");
476 }
477 
478 #define TF_BUFS	8
479 #define TF_LEN	9
480 
481 const char *
482 fmt_timeframe(time_t t)
483 {
484 	if (t == 0)
485 		return ("Never");
486 	else
487 		return (fmt_timeframe_core(time(NULL) - t));
488 }
489 
490 const char *
491 fmt_timeframe_core(time_t t)
492 {
493 	char		*buf;
494 	static char	 tfbuf[TF_BUFS][TF_LEN];	/* ring buffer */
495 	static int	 idx = 0;
496 	unsigned int	 sec, min, hrs, day, week;
497 
498 	if (t == 0)
499 		return ("00:00:00");
500 
501 	buf = tfbuf[idx++];
502 	if (idx == TF_BUFS)
503 		idx = 0;
504 
505 	week = t;
506 
507 	sec = week % 60;
508 	week /= 60;
509 	min = week % 60;
510 	week /= 60;
511 	hrs = week % 24;
512 	week /= 24;
513 	day = week % 7;
514 	week /= 7;
515 
516 	if (week > 0)
517 		snprintf(buf, TF_LEN, "%02uw%01ud%02uh", week, day, hrs);
518 	else if (day > 0)
519 		snprintf(buf, TF_LEN, "%01ud%02uh%02um", day, hrs, min);
520 	else
521 		snprintf(buf, TF_LEN, "%02u:%02u:%02u", hrs, min, sec);
522 
523 	return (buf);
524 }
525 
526 const char *
527 log_id(u_int32_t id)
528 {
529 	static char	buf[48];
530 	struct in_addr	addr;
531 
532 	addr.s_addr = id;
533 
534 	if (inet_ntop(AF_INET, &addr, buf, sizeof(buf)) == NULL)
535 		return ("?");
536 	else
537 		return (buf);
538 }
539 
540 const char *
541 log_adv_rtr(u_int32_t adv_rtr)
542 {
543 	static char	buf[48];
544 	struct in_addr	addr;
545 
546 	addr.s_addr = adv_rtr;
547 
548 	if (inet_ntop(AF_INET, &addr, buf, sizeof(buf)) == NULL)
549 		return ("?");
550 	else
551 		return (buf);
552 }
553 
554 void
555 show_database_head(struct in_addr aid, char *ifname, u_int16_t type)
556 {
557 	char	*header, *format;
558 	int	cleanup = 0;
559 
560 	switch (ntohs(type)) {
561 	case LSA_TYPE_LINK:
562 		format = "Link (Type-8) Link States";
563 		break;
564 	case LSA_TYPE_ROUTER:
565 		format = "Router Link States";
566 		break;
567 	case LSA_TYPE_NETWORK:
568 		format = "Net Link States";
569 		break;
570 	case LSA_TYPE_INTER_A_PREFIX:
571 		format = "Inter Area Prefix Link States";
572 		break;
573 	case LSA_TYPE_INTER_A_ROUTER:
574 		format = "Inter Area Router Link States";
575 		break;
576 	case LSA_TYPE_INTRA_A_PREFIX:
577 		format = "Intra Area Prefix Link States";
578 		break;
579 	case LSA_TYPE_EXTERNAL:
580 		printf("\n%-15s %s\n\n", "", "Type-5 AS External Link States");
581 		return;
582 	default:
583 		if (asprintf(&format, "LSA type %x", ntohs(type)) == -1)
584 			err(1, NULL);
585 		cleanup = 1;
586 		break;
587 	}
588 	if (LSA_IS_SCOPE_AREA(ntohs(type))) {
589 		if (asprintf(&header, "%s (Area %s)", format,
590 		    inet_ntoa(aid)) == -1)
591 			err(1, NULL);
592 	} else if (LSA_IS_SCOPE_LLOCAL(ntohs(type))) {
593 		if (asprintf(&header, "%s (Area %s Interface %s)", format,
594 		    inet_ntoa(aid), ifname) == -1)
595 			err(1, NULL);
596 	} else {
597 		if (asprintf(&header, "%s", format) == -1)
598 			err(1, NULL);
599 	}
600 
601 	printf("\n%-15s %s\n\n", "", header);
602 	free(header);
603 	if (cleanup)
604 		free(format);
605 }
606 
607 int
608 show_database_msg(struct imsg *imsg)
609 {
610 	static struct in_addr	 area_id;
611 	static char		 ifname[IF_NAMESIZE];
612 	static u_int16_t	 lasttype;
613 	struct area		*area;
614 	struct iface		*iface;
615 	struct lsa_hdr		*lsa;
616 
617 	switch (imsg->hdr.type) {
618 	case IMSG_CTL_SHOW_DATABASE:
619 	case IMSG_CTL_SHOW_DB_SELF:
620 		lsa = imsg->data;
621 		if (lsa->type != lasttype) {
622 			show_database_head(area_id, ifname, lsa->type);
623 			printf("%-15s %-15s %-4s %-10s %-8s\n", "Link ID",
624 			    "Adv Router", "Age", "Seq#", "Checksum");
625 		}
626 		printf("%-15s %-15s %-4d 0x%08x 0x%04x\n",
627 		    log_id(lsa->ls_id), log_adv_rtr(lsa->adv_rtr),
628 		    ntohs(lsa->age), ntohl(lsa->seq_num),
629 		    ntohs(lsa->ls_chksum));
630 		lasttype = lsa->type;
631 		break;
632 	case IMSG_CTL_AREA:
633 		area = imsg->data;
634 		area_id = area->id;
635 		lasttype = 0;
636 		break;
637 	case IMSG_CTL_IFACE:
638 		iface = imsg->data;
639 		strlcpy(ifname, iface->name, sizeof(ifname));
640 		lasttype = 0;
641 		break;
642 	case IMSG_CTL_END:
643 		printf("\n");
644 		return (1);
645 	default:
646 		break;
647 	}
648 
649 	return (0);
650 }
651 
652 char *
653 print_ls_type(u_int16_t type)
654 {
655 	switch (ntohs(type)) {
656 	case LSA_TYPE_LINK:
657 		return ("Link");
658 	case LSA_TYPE_ROUTER:
659 		return ("Router");
660 	case LSA_TYPE_NETWORK:
661 		return ("Network");
662 	case LSA_TYPE_INTER_A_PREFIX:
663 		return ("Inter Area (Prefix)");
664 	case LSA_TYPE_INTER_A_ROUTER:
665 		return ("Inter Area (Router)");
666 	case LSA_TYPE_INTRA_A_PREFIX:
667 		return ("Intra Area (Prefix)");
668 	case LSA_TYPE_EXTERNAL:
669 		return ("AS External");
670 	default:
671 		return ("Unknown");
672 	}
673 }
674 
675 void
676 show_db_hdr_msg_detail(struct lsa_hdr *lsa)
677 {
678 	printf("LS age: %d\n", ntohs(lsa->age));
679 	printf("LS Type: %s\n", print_ls_type(lsa->type));
680 
681 	switch (ntohs(lsa->type)) {
682 	case LSA_TYPE_ROUTER:
683 	case LSA_TYPE_INTER_A_PREFIX:
684 	case LSA_TYPE_INTER_A_ROUTER:
685 	case LSA_TYPE_INTRA_A_PREFIX:
686 	case LSA_TYPE_EXTERNAL:
687 		printf("Link State ID: %s\n", log_id(lsa->ls_id));
688 		break;
689 	case LSA_TYPE_LINK:
690 		printf("Link State ID: %s (Interface ID of Advertising "
691 		    "Router)\n", log_id(lsa->ls_id));
692 		break;
693 	case LSA_TYPE_NETWORK:
694 		printf("Link State ID: %s (Interface ID of Designated "
695 		    "Router)\n", log_id(lsa->ls_id));
696 		break;
697 	}
698 
699 	printf("Advertising Router: %s\n", log_adv_rtr(lsa->adv_rtr));
700 	printf("LS Seq Number: 0x%08x\n", ntohl(lsa->seq_num));
701 	printf("Checksum: 0x%04x\n", ntohs(lsa->ls_chksum));
702 	printf("Length: %d\n", ntohs(lsa->len));
703 }
704 
705 char *
706 print_rtr_link_type(u_int8_t type)
707 {
708 	switch (type) {
709 	case LINK_TYPE_POINTTOPOINT:
710 		return ("Point-to-Point");
711 	case LINK_TYPE_TRANSIT_NET:
712 		return ("Transit Network");
713 	case LINK_TYPE_RESERVED:
714 		return ("Reserved");
715 	case LINK_TYPE_VIRTUAL:
716 		return ("Virtual Link");
717 	default:
718 		return ("Unknown");
719 	}
720 }
721 
722 const char *
723 print_ospf_flags(u_int8_t opts)
724 {
725 	static char	optbuf[32];
726 
727 	snprintf(optbuf, sizeof(optbuf), "*|*|*|*|*|%s|%s|%s",
728 	    opts & OSPF_RTR_V ? "V" : "-",
729 	    opts & OSPF_RTR_E ? "E" : "-",
730 	    opts & OSPF_RTR_B ? "B" : "-");
731 	return (optbuf);
732 }
733 
734 const char *
735 print_asext_flags(u_int32_t opts)
736 {
737 	static char	optbuf[32];
738 
739 	snprintf(optbuf, sizeof(optbuf), "*|*|*|*|*|%s|%s|%s",
740 	    opts & LSA_ASEXT_E_FLAG ? "E" : "-",
741 	    opts & LSA_ASEXT_F_FLAG ? "F" : "-",
742 	    opts & LSA_ASEXT_T_FLAG ? "T" : "-");
743 	return (optbuf);
744 }
745 
746 const char *
747 print_prefix_opt(u_int8_t opts)
748 {
749 	static char	optbuf[32];
750 
751 	if (opts) {
752 		snprintf(optbuf, sizeof(optbuf),
753 		    " Options: *|*|*|%s|%s|x|%s|%s",
754 		    opts & OSPF_PREFIX_DN ? "DN" : "-",
755 		    opts & OSPF_PREFIX_P ? "P" : "-",
756 		    opts & OSPF_PREFIX_LA ? "LA" : "-",
757 		    opts & OSPF_PREFIX_NU ? "NU" : "-");
758 		return (optbuf);
759 	}
760 	return ("");
761 }
762 
763 int
764 show_db_msg_detail(struct imsg *imsg)
765 {
766 	static struct in_addr	 area_id;
767 	static char		 ifname[IF_NAMESIZE];
768 	static u_int16_t	 lasttype;
769 	struct in6_addr		 ia6;
770 	struct in_addr		 addr, data;
771 	struct area		*area;
772 	struct iface		*iface;
773 	struct lsa		*lsa;
774 	struct lsa_rtr_link	*rtr_link;
775 	struct lsa_net_link	*net_link;
776 	struct lsa_prefix	*prefix;
777 	struct lsa_asext	*asext;
778 	u_int32_t		 ext_tag;
779 	u_int16_t		 i, nlinks, off;
780 
781 	/* XXX sanity checks! */
782 
783 	switch (imsg->hdr.type) {
784 	case IMSG_CTL_SHOW_DB_EXT:
785 		lsa = imsg->data;
786 		if (lsa->hdr.type != lasttype)
787 			show_database_head(area_id, ifname, lsa->hdr.type);
788 		show_db_hdr_msg_detail(&lsa->hdr);
789 
790 		asext = (struct lsa_asext *)((char *)lsa + sizeof(lsa->hdr));
791 
792 		printf("    Flags: %s\n",
793 		    print_asext_flags(ntohl(lsa->data.asext.metric)));
794 		printf("    Metric: %d Type: ", ntohl(asext->metric)
795 		    & LSA_METRIC_MASK);
796 		if (ntohl(lsa->data.asext.metric) & LSA_ASEXT_E_FLAG)
797 			printf("2\n");
798 		else
799 			printf("1\n");
800 
801 		prefix = &asext->prefix;
802 		bzero(&ia6, sizeof(ia6));
803 		bcopy(prefix + 1, &ia6, LSA_PREFIXSIZE(prefix->prefixlen));
804 		printf("    Prefix: %s/%d%s\n", log_in6addr(&ia6),
805 		    prefix->prefixlen, print_prefix_opt(prefix->options));
806 
807 		off = sizeof(*asext) + LSA_PREFIXSIZE(prefix->prefixlen);
808 		if (ntohl(lsa->data.asext.metric) & LSA_ASEXT_F_FLAG) {
809 			bcopy((char *)asext + off, &ia6, sizeof(ia6));
810 			printf("    Forwarding Address: %s\n",
811 			    log_in6addr(&ia6));
812 			off += sizeof(ia6);
813 		}
814 		if (ntohl(lsa->data.asext.metric) & LSA_ASEXT_T_FLAG) {
815 			bcopy((char *)asext + off, &ext_tag, sizeof(ext_tag));
816 			printf("    External Route Tag: %d\n", ntohl(ext_tag));
817 		}
818 		printf("\n");
819 		lasttype = lsa->hdr.type;
820 		break;
821 	case IMSG_CTL_SHOW_DB_LINK:
822 		lsa = imsg->data;
823 		if (lsa->hdr.type != lasttype)
824 			show_database_head(area_id, ifname, lsa->hdr.type);
825 		show_db_hdr_msg_detail(&lsa->hdr);
826 		printf("Options: %s\n", print_ospf_options(LSA_24_GETLO(
827 		    ntohl(lsa->data.link.opts))));
828 		printf("Link Local Address: %s\n",
829 		    log_in6addr(&lsa->data.link.lladdr));
830 
831 		nlinks = ntohl(lsa->data.link.numprefix);
832 		printf("Number of Prefixes: %d\n", nlinks);
833 		off = sizeof(lsa->hdr) + sizeof(struct lsa_link);
834 
835 		for (i = 0; i < nlinks; i++) {
836 			prefix = (struct lsa_prefix *)((char *)lsa + off);
837 			bzero(&ia6, sizeof(ia6));
838 			bcopy(prefix + 1, &ia6,
839 			    LSA_PREFIXSIZE(prefix->prefixlen));
840 
841 			printf("    Prefix: %s/%d%s\n", log_in6addr(&ia6),
842 			    prefix->prefixlen,
843 			    print_prefix_opt(prefix->options));
844 
845 			off += sizeof(struct lsa_prefix)
846 			    + LSA_PREFIXSIZE(prefix->prefixlen);
847 		}
848 
849 		printf("\n");
850 		lasttype = lsa->hdr.type;
851 		break;
852 	case IMSG_CTL_SHOW_DB_NET:
853 		lsa = imsg->data;
854 		if (lsa->hdr.type != lasttype)
855 			show_database_head(area_id, ifname, lsa->hdr.type);
856 		show_db_hdr_msg_detail(&lsa->hdr);
857 		printf("Options: %s\n",
858 		    print_ospf_options(LSA_24_GETLO(ntohl(lsa->data.net.opts))));
859 
860 		nlinks = (ntohs(lsa->hdr.len) - sizeof(struct lsa_hdr) -
861 		    sizeof(struct lsa_net)) / sizeof(struct lsa_net_link);
862 		net_link = (struct lsa_net_link *)((char *)lsa +
863 		    sizeof(lsa->hdr) + sizeof(lsa->data.net));
864 		printf("Number of Routers: %d\n", nlinks);
865 
866 		for (i = 0; i < nlinks; i++) {
867 			addr.s_addr = net_link->att_rtr;
868 			printf("    Attached Router: %s\n", inet_ntoa(addr));
869 			net_link++;
870 		}
871 
872 		printf("\n");
873 		lasttype = lsa->hdr.type;
874 		break;
875 	case IMSG_CTL_SHOW_DB_RTR:
876 		lsa = imsg->data;
877 		if (lsa->hdr.type != lasttype)
878 			show_database_head(area_id, ifname, lsa->hdr.type);
879 		show_db_hdr_msg_detail(&lsa->hdr);
880 		printf("Flags: %s\n",
881 		    print_ospf_flags(LSA_24_GETHI(ntohl(lsa->data.rtr.opts))));
882 		printf("Options: %s\n",
883 		    print_ospf_options(LSA_24_GETLO(ntohl(lsa->data.rtr.opts))));
884 
885 		nlinks = (ntohs(lsa->hdr.len) - sizeof(struct lsa_hdr)
886 		    - sizeof(u_int32_t)) / sizeof(struct lsa_rtr_link);
887 		printf("Number of Links: %d\n\n", nlinks);
888 
889 		off = sizeof(lsa->hdr) + sizeof(struct lsa_rtr);
890 
891 		for (i = 0; i < nlinks; i++) {
892 			rtr_link = (struct lsa_rtr_link *)((char *)lsa + off);
893 
894 			printf("    Link (Interface ID %s) connected to: %s\n",
895 			    log_id(rtr_link->iface_id),
896 			    print_rtr_link_type(rtr_link->type));
897 
898 			addr.s_addr = rtr_link->nbr_rtr_id;
899 			data.s_addr = rtr_link->nbr_iface_id;
900 
901 			switch (rtr_link->type) {
902 			case LINK_TYPE_POINTTOPOINT:
903 			case LINK_TYPE_VIRTUAL:
904 				printf("    Router ID: %s\n", inet_ntoa(addr));
905 				printf("    Interface ID: %s\n",
906 				    inet_ntoa(data));
907 				break;
908 			case LINK_TYPE_TRANSIT_NET:
909 				printf("    Designated Router ID: %s\n",
910 				    inet_ntoa(addr));
911 				printf("    DR Interface ID: %s\n",
912 				    inet_ntoa(data));
913 				break;
914 			default:
915 				printf("    Link ID (Unknown type %d): %s\n",
916 				    rtr_link->type, inet_ntoa(addr));
917 				printf("    Link Data (Unknown): %s\n",
918 				    inet_ntoa(data));
919 				break;
920 			}
921 
922 			printf("    Metric: %d\n\n", ntohs(rtr_link->metric));
923 
924 			off += sizeof(struct lsa_rtr_link);
925 		}
926 
927 		lasttype = lsa->hdr.type;
928 		break;
929 	case IMSG_CTL_SHOW_DB_INTRA:
930 		lsa = imsg->data;
931 		if (lsa->hdr.type != lasttype)
932 			show_database_head(area_id, ifname, lsa->hdr.type);
933 		show_db_hdr_msg_detail(&lsa->hdr);
934 		printf("Referenced LS Type: %s\n",
935 		    print_ls_type(lsa->data.pref_intra.ref_type));
936 		addr.s_addr = lsa->data.pref_intra.ref_ls_id;
937 		printf("Referenced Link State ID: %s\n", inet_ntoa(addr));
938 		addr.s_addr = lsa->data.pref_intra.ref_adv_rtr;
939 		printf("Referenced Advertising Router: %s\n", inet_ntoa(addr));
940 		nlinks = ntohs(lsa->data.pref_intra.numprefix);
941 		printf("Number of Prefixes: %d\n", nlinks);
942 
943 		off = sizeof(lsa->hdr) + sizeof(struct lsa_intra_prefix);
944 
945 		for (i = 0; i < nlinks; i++) {
946 			prefix = (struct lsa_prefix *)((char *)lsa + off);
947 			bzero(&ia6, sizeof(ia6));
948 			bcopy(prefix + 1, &ia6,
949 			    LSA_PREFIXSIZE(prefix->prefixlen));
950 
951 			printf("    Prefix: %s/%d%s Metric: %d\n",
952 			    log_in6addr(&ia6), prefix->prefixlen,
953 			    print_prefix_opt(prefix->options),
954 			    ntohs(prefix->metric));
955 
956 			off += sizeof(struct lsa_prefix)
957 			    + LSA_PREFIXSIZE(prefix->prefixlen);
958 		}
959 
960 		printf("\n");
961 		lasttype = lsa->hdr.type;
962 		break;
963 	case IMSG_CTL_SHOW_DB_SUM:
964 		lsa = imsg->data;
965 		if (lsa->hdr.type != lasttype)
966 			show_database_head(area_id, ifname, lsa->hdr.type);
967 		show_db_hdr_msg_detail(&lsa->hdr);
968 		printf("Prefix: XXX\n");
969 		printf("Metric: %d\n", ntohl(lsa->data.pref_sum.metric) &
970 		    LSA_METRIC_MASK);
971 		lasttype = lsa->hdr.type;
972 		break;
973 	case IMSG_CTL_SHOW_DB_ASBR:
974 		lsa = imsg->data;
975 		if (lsa->hdr.type != lasttype)
976 			show_database_head(area_id, ifname, lsa->hdr.type);
977 		show_db_hdr_msg_detail(&lsa->hdr);
978 
979 		addr.s_addr = lsa->data.rtr_sum.dest_rtr_id;
980 		printf("Destination Router ID: %s\n", inet_ntoa(addr));
981 		printf("Options: %s\n",
982 		    print_ospf_options(ntohl(lsa->data.rtr_sum.opts)));
983 		printf("Metric: %d\n\n", ntohl(lsa->data.rtr_sum.metric) &
984 		    LSA_METRIC_MASK);
985 	case IMSG_CTL_AREA:
986 		area = imsg->data;
987 		area_id = area->id;
988 		lasttype = 0;
989 		break;
990 	case IMSG_CTL_IFACE:
991 		iface = imsg->data;
992 		strlcpy(ifname, iface->name, sizeof(ifname));
993 		lasttype = 0;
994 		break;
995 	case IMSG_CTL_END:
996 		return (1);
997 	default:
998 		break;
999 	}
1000 
1001 	return (0);
1002 }
1003 
1004 int
1005 show_nbr_msg(struct imsg *imsg)
1006 {
1007 	struct ctl_nbr	*nbr;
1008 	char		*state;
1009 
1010 	switch (imsg->hdr.type) {
1011 	case IMSG_CTL_SHOW_NBR:
1012 		nbr = imsg->data;
1013 		if (asprintf(&state, "%s/%s", nbr_state_name(nbr->nbr_state),
1014 		    if_state_name(nbr->iface_state)) == -1)
1015 			err(1, NULL);
1016 		printf("%-15s %-3d %-12s %-10s", inet_ntoa(nbr->id),
1017 		    nbr->priority, state, fmt_timeframe_core(nbr->dead_timer));
1018 		printf("%-11s %s\n", nbr->name,
1019 		    nbr->uptime == 0 ? "-" : fmt_timeframe_core(nbr->uptime));
1020 		free(state);
1021 		break;
1022 	case IMSG_CTL_END:
1023 		printf("\n");
1024 		return (1);
1025 	default:
1026 		break;
1027 	}
1028 
1029 	return (0);
1030 }
1031 
1032 const char *
1033 print_ospf_options(u_int32_t opts)
1034 {
1035 	static char	optbuf[32];
1036 
1037 	snprintf(optbuf, sizeof(optbuf), "*|*|%s|%s|%s|*|%s|%s",
1038 	    opts & OSPF_OPTION_DC ? "DC" : "-",
1039 	    opts & OSPF_OPTION_R ? "R" : "-",
1040 	    opts & OSPF_OPTION_N ? "N" : "-",
1041 	    opts & OSPF_OPTION_E ? "E" : "-",
1042 	    opts & OSPF_OPTION_V6 ? "V6" : "-");
1043 	return (optbuf);
1044 }
1045 
1046 int
1047 show_nbr_detail_msg(struct imsg *imsg)
1048 {
1049 	struct ctl_nbr	*nbr;
1050 
1051 	switch (imsg->hdr.type) {
1052 	case IMSG_CTL_SHOW_NBR:
1053 		nbr = imsg->data;
1054 		printf("\nNeighbor %s, ", inet_ntoa(nbr->id));
1055 		printf("interface address %s\n", log_in6addr(&nbr->addr));
1056 		printf("  Area %s, interface %s\n", inet_ntoa(nbr->area),
1057 		    nbr->name);
1058 		printf("  Neighbor priority is %d, "
1059 		    "State is %s, %d state changes\n",
1060 		    nbr->priority, nbr_state_name(nbr->nbr_state),
1061 		    nbr->state_chng_cnt);
1062 		printf("  DR is %s, ", inet_ntoa(nbr->dr));
1063 		printf("BDR is %s\n", inet_ntoa(nbr->bdr));
1064 		printf("  Options %s\n", print_ospf_options(nbr->options));
1065 		printf("  Dead timer due in %s\n",
1066 		    fmt_timeframe_core(nbr->dead_timer));
1067 		printf("  Uptime %s\n", fmt_timeframe_core(nbr->uptime));
1068 		printf("  Database Summary List %d\n", nbr->db_sum_lst_cnt);
1069 		printf("  Link State Request List %d\n", nbr->ls_req_lst_cnt);
1070 		printf("  Link State Retransmission List %d\n",
1071 		    nbr->ls_retrans_lst_cnt);
1072 		break;
1073 	case IMSG_CTL_END:
1074 		printf("\n");
1075 		return (1);
1076 	default:
1077 		break;
1078 	}
1079 
1080 	return (0);
1081 }
1082 
1083 int
1084 show_rib_msg(struct imsg *imsg)
1085 {
1086 	struct ctl_rt	*rt;
1087 	char		*dstnet;
1088 
1089 	switch (imsg->hdr.type) {
1090 	case IMSG_CTL_SHOW_RIB:
1091 		rt = imsg->data;
1092 		switch (rt->d_type) {
1093 		case DT_NET:
1094 			if (asprintf(&dstnet, "%s/%d", log_in6addr(&rt->prefix),
1095 			    rt->prefixlen) == -1)
1096 				err(1, NULL);
1097 			break;
1098 		case DT_RTR:
1099 			if (asprintf(&dstnet, "%s",
1100 			    log_in6addr(&rt->prefix)) == -1)
1101 				err(1, NULL);
1102 			break;
1103 		default:
1104 			errx(1, "Invalid route type");
1105 		}
1106 
1107 		printf("%-20s %-16s%s %-12s %-9s %-7d %s\n", dstnet,
1108 		    log_in6addr_scope(&rt->nexthop, rt->ifindex),
1109 		    rt->connected ? "C" : " ", path_type_name(rt->p_type),
1110 		    dst_type_name(rt->d_type), rt->cost,
1111 		    rt->uptime == 0 ? "-" : fmt_timeframe_core(rt->uptime));
1112 		free(dstnet);
1113 		break;
1114 	case IMSG_CTL_END:
1115 		printf("\n");
1116 		return (1);
1117 	default:
1118 		break;
1119 	}
1120 
1121 	return (0);
1122 }
1123 
1124 void
1125 show_rib_head(struct in_addr aid, u_int8_t d_type, u_int8_t p_type)
1126 {
1127 	char	*header, *format, *format2;
1128 
1129 	switch (p_type) {
1130 	case PT_INTRA_AREA:
1131 	case PT_INTER_AREA:
1132 		switch (d_type) {
1133 		case DT_NET:
1134 			format = "Network Routing Table";
1135 			format2 = "";
1136 			break;
1137 		case DT_RTR:
1138 			format = "Router Routing Table";
1139 			format2 = "Type";
1140 			break;
1141 		default:
1142 			errx(1, "unknown route type");
1143 		}
1144 		break;
1145 	case PT_TYPE1_EXT:
1146 	case PT_TYPE2_EXT:
1147 		format = NULL;
1148 		format2 = "Cost 2";
1149 		if ((header = strdup("External Routing Table")) == NULL)
1150 			err(1, NULL);
1151 		break;
1152 	default:
1153 		errx(1, "unknown route type");
1154 	}
1155 
1156 	if (p_type != PT_TYPE1_EXT && p_type != PT_TYPE2_EXT)
1157 		if (asprintf(&header, "%s (Area %s)", format,
1158 		    inet_ntoa(aid)) == -1)
1159 			err(1, NULL);
1160 
1161 	printf("\n%-18s %s\n", "", header);
1162 	free(header);
1163 
1164 	printf("\n%-18s %-15s %-15s %-12s %-7s %-7s\n", "Destination",
1165 	    "Nexthop", "Adv Router", "Path type", "Cost", format2);
1166 }
1167 
1168 const char *
1169 print_ospf_rtr_flags(u_int8_t opts)
1170 {
1171 	static char	optbuf[32];
1172 
1173 	snprintf(optbuf, sizeof(optbuf), "%s%s%s",
1174 	    opts & OSPF_RTR_E ? "AS" : "",
1175 	    opts & OSPF_RTR_E && opts & OSPF_RTR_B ? "+" : "",
1176 	    opts & OSPF_RTR_B ? "ABR" : "");
1177 	return (optbuf);
1178 }
1179 
1180 int
1181 show_rib_detail_msg(struct imsg *imsg)
1182 {
1183 	struct ctl_rt		*rt;
1184 	char			*dstnet;
1185 	static u_int8_t		 lasttype;
1186 
1187 	switch (imsg->hdr.type) {
1188 	case IMSG_CTL_SHOW_RIB:
1189 		rt = imsg->data;
1190 
1191 		switch (rt->p_type) {
1192 		case PT_INTRA_AREA:
1193 		case PT_INTER_AREA:
1194 			switch (rt->d_type) {
1195 			case DT_NET:
1196 				if (lasttype != RIB_NET)
1197 					show_rib_head(rt->area, rt->d_type,
1198 					     rt->p_type);
1199 				if (asprintf(&dstnet, "%s/%d",
1200 				    log_in6addr(&rt->prefix),
1201 				    rt->prefixlen) == -1)
1202 					err(1, NULL);
1203 				lasttype = RIB_NET;
1204 				break;
1205 			case DT_RTR:
1206 				if (lasttype != RIB_RTR)
1207 					show_rib_head(rt->area, rt->d_type,
1208 					     rt->p_type);
1209 				if (asprintf(&dstnet, "%s",
1210 				    log_in6addr(&rt->prefix)) == -1)
1211 					err(1, NULL);
1212 				lasttype = RIB_RTR;
1213 				break;
1214 			default:
1215 				errx(1, "unknown route type");
1216 			}
1217 			printf("%-18s %-15s ", dstnet,
1218 			    log_in6addr_scope(&rt->nexthop, rt->ifindex));
1219 			printf("%-15s %-12s %-7d", inet_ntoa(rt->adv_rtr),
1220 			    path_type_name(rt->p_type), rt->cost);
1221 			free(dstnet);
1222 
1223 			if (rt->d_type == DT_RTR)
1224 				printf(" %-7s",
1225 				    print_ospf_rtr_flags(rt->flags));
1226 
1227 			printf("\n");
1228 			break;
1229 		case PT_TYPE1_EXT:
1230 		case PT_TYPE2_EXT:
1231 			if (lasttype != RIB_EXT)
1232 				show_rib_head(rt->area, rt->d_type, rt->p_type);
1233 
1234 			if (asprintf(&dstnet, "%s/%d",
1235 			    log_in6addr(&rt->prefix), rt->prefixlen) == -1)
1236 				err(1, NULL);
1237 
1238 			printf("%-18s %-15s ", dstnet,
1239 			    log_in6addr_scope(&rt->nexthop, rt->ifindex));
1240 			printf("%-15s %-12s %-7d %-7d\n",
1241 			    inet_ntoa(rt->adv_rtr), path_type_name(rt->p_type),
1242 			    rt->cost, rt->cost2);
1243 			free(dstnet);
1244 
1245 			lasttype = RIB_EXT;
1246 			break;
1247 		default:
1248 			errx(1, "unknown route type");
1249 		}
1250 		break;
1251 	case IMSG_CTL_AREA:
1252 		break;
1253 	case IMSG_CTL_END:
1254 		printf("\n");
1255 		return (1);
1256 	default:
1257 		break;
1258 	}
1259 
1260 	return (0);
1261 }
1262 
1263 void
1264 show_fib_head(void)
1265 {
1266 	printf("flags: * = valid, O = OSPF, C = Connected, S = Static\n");
1267 	printf("%-6s %-4s %-20s %-17s\n",
1268 	    "Flags", "Prio", "Destination", "Nexthop");
1269 }
1270 
1271 int
1272 show_fib_msg(struct imsg *imsg)
1273 {
1274 	struct kroute		*k;
1275 	char			*p;
1276 
1277 	switch (imsg->hdr.type) {
1278 	case IMSG_CTL_KROUTE:
1279 		if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(struct kroute))
1280 			errx(1, "wrong imsg len");
1281 		k = imsg->data;
1282 
1283 		if (k->flags & F_DOWN)
1284 			printf(" ");
1285 		else
1286 			printf("*");
1287 
1288 		if (!(k->flags & F_KERNEL))
1289 			printf("O");
1290 		else if (k->flags & F_CONNECTED)
1291 			printf("C");
1292 		else if (k->flags & F_STATIC)
1293 			printf("S");
1294 		else
1295 			printf(" ");
1296 
1297 		printf("     ");
1298 		printf("%4d ", k->priority);
1299 		if (asprintf(&p, "%s/%u", log_in6addr(&k->prefix),
1300 		    k->prefixlen) == -1)
1301 			err(1, NULL);
1302 		printf("%-20s ", p);
1303 		free(p);
1304 
1305 		if (!IN6_IS_ADDR_UNSPECIFIED(&k->nexthop))
1306 			printf("%s", log_in6addr_scope(&k->nexthop, k->scope));
1307 		else if (k->flags & F_CONNECTED)
1308 			printf("link#%u", k->ifindex);
1309 		printf("\n");
1310 
1311 		break;
1312 	case IMSG_CTL_END:
1313 		printf("\n");
1314 		return (1);
1315 	default:
1316 		break;
1317 	}
1318 
1319 	return (0);
1320 }
1321 
1322 const struct if_status_description
1323 		if_status_descriptions[] = LINK_STATE_DESCRIPTIONS;
1324 const struct ifmedia_description
1325 		ifm_type_descriptions[] = IFM_TYPE_DESCRIPTIONS;
1326 
1327 const char *
1328 get_media_descr(uint64_t media_type)
1329 {
1330 	const struct ifmedia_description	*p;
1331 
1332 	for (p = ifm_type_descriptions; p->ifmt_string != NULL; p++)
1333 		if (media_type == p->ifmt_word)
1334 			return (p->ifmt_string);
1335 
1336 	return ("unknown");
1337 }
1338 
1339 const char *
1340 get_linkstate(uint8_t if_type, int link_state)
1341 {
1342 	const struct if_status_description *p;
1343 	static char buf[8];
1344 
1345 	for (p = if_status_descriptions; p->ifs_string != NULL; p++) {
1346 		if (LINK_STATE_DESC_MATCH(p, if_type, link_state))
1347 			return (p->ifs_string);
1348 	}
1349 	snprintf(buf, sizeof(buf), "[#%d]", link_state);
1350 	return (buf);
1351 }
1352 
1353 void
1354 print_baudrate(u_int64_t baudrate)
1355 {
1356 	if (baudrate > IF_Gbps(1))
1357 		printf("%llu GBit/s", baudrate / IF_Gbps(1));
1358 	else if (baudrate > IF_Mbps(1))
1359 		printf("%llu MBit/s", baudrate / IF_Mbps(1));
1360 	else if (baudrate > IF_Kbps(1))
1361 		printf("%llu KBit/s", baudrate / IF_Kbps(1));
1362 	else
1363 		printf("%llu Bit/s", baudrate);
1364 }
1365