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