1/*
2 * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
3 * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
4 * Copyright (c) 2003 Henning Brauer <henning@openbsd.org>
5 * Copyright (c) 2020 Richard Chivers <r.chivers@zengenti.com>
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20#include <sys/types.h>
21#include <sys/socket.h>
22#include <sys/un.h>
23#include <netinet/in.h>
24#include <arpa/inet.h>
25#include <net/if_media.h>
26#include <net/if_types.h>
27
28#include <err.h>
29#include <errno.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 "ospfctl.h"
38#include "ospfe.h"
39#include "parser.h"
40
41static void
42show_head(struct parse_result *res)
43{
44	switch (res->action) {
45	case SHOW_IFACE:
46		printf("%-11s %-18s %-6s %-10s %-10s %-8s %3s %3s\n",
47		    "Interface", "Address", "State", "HelloTimer", "Linkstate",
48		    "Uptime", "nc", "ac");
49		break;
50	case SHOW_FIB:
51		printf("flags: * = valid, O = OSPF, C = Connected, "
52		    "S = Static\n");
53		printf("%-6s %-4s %-20s %-17s\n", "Flags", "Prio",
54		    "Destination", "Nexthop");
55		break;
56	case SHOW_FIB_IFACE:
57		printf("%-15s%-15s%s\n", "Interface", "Flags", "Link state");
58		break;
59	case SHOW_NBR:
60		printf("%-15s %-3s %-12s %-8s %-15s %-9s %s\n", "ID", "Pri",
61		    "State", "DeadTime", "Address", "Iface","Uptime");
62		break;
63	case SHOW_RIB:
64		printf("%-20s %-17s %-12s %-9s %-7s %-8s\n", "Destination",
65		    "Nexthop", "Path Type", "Type", "Cost", "Uptime");
66		break;
67	default:
68		break;
69	}
70}
71
72static void
73show_summary(struct ctl_sum *sum)
74{
75	printf("Router ID: %s\n", inet_ntoa(sum->rtr_id));
76	printf("Uptime: %s\n", fmt_timeframe_core(sum->uptime));
77	printf("RFC1583 compatibility flag is ");
78	if (sum->rfc1583compat)
79		printf("enabled\n");
80	else
81		printf("disabled\n");
82
83	printf("SPF delay is %d msec(s), hold time between two SPFs "
84	    "is %d msec(s)\n", sum->spf_delay, sum->spf_hold_time);
85	printf("Number of external LSA(s) %d (Checksum sum 0x%x)\n",
86	    sum->num_ext_lsa, sum->ext_lsa_cksum);
87	printf("Number of areas attached to this router: %d\n",
88	    sum->num_area);
89}
90
91static void
92show_summary_area(struct ctl_sum_area *sumarea)
93{
94	printf("\nArea ID: %s\n", inet_ntoa(sumarea->area));
95	printf("  Number of interfaces in this area: %d\n",
96	    sumarea->num_iface);
97	printf("  Number of fully adjacent neighbors in this "
98	    "area: %d\n", sumarea->num_adj_nbr);
99	printf("  SPF algorithm executed %d time(s)\n",
100	    sumarea->num_spf_calc);
101	printf("  Number LSA(s) %d (Checksum sum 0x%x)\n",
102	    sumarea->num_lsa, sumarea->lsa_cksum);
103}
104
105static void
106show_rib_head(struct in_addr aid, u_int8_t d_type, u_int8_t p_type)
107{
108	char	*header, *format, *format2;
109
110	switch (p_type) {
111	case PT_INTRA_AREA:
112	case PT_INTER_AREA:
113		switch (d_type) {
114		case DT_NET:
115			format = "Network Routing Table";
116			format2 = "";
117			break;
118		case DT_RTR:
119			format = "Router Routing Table";
120			format2 = "Type";
121			break;
122		default:
123			errx(1, "unknown route type");
124		}
125		break;
126	case PT_TYPE1_EXT:
127	case PT_TYPE2_EXT:
128		format = NULL;
129		format2 = "Cost 2";
130		if ((header = strdup("External Routing Table")) == NULL)
131			err(1, NULL);
132		break;
133	default:
134		errx(1, "unknown route type");
135	}
136
137	if (p_type != PT_TYPE1_EXT && p_type != PT_TYPE2_EXT)
138		if (asprintf(&header, "%s (Area %s)", format,
139		    inet_ntoa(aid)) == -1)
140			err(1, NULL);
141
142	printf("\n%-18s %s\n", "", header);
143	free(header);
144
145	printf("\n%-18s %-15s %-15s %-12s %-7s %-7s\n", "Destination",
146	    "Nexthop", "Adv Router", "Path type", "Cost", format2);
147}
148
149static void
150show_interface(struct ctl_iface	*iface, int detail)
151{
152	char	*netid;
153
154	/* XXX This wasn't previously executed on detail call */
155	if (asprintf(&netid, "%s/%d", inet_ntoa(iface->addr),
156	    mask2prefixlen(iface->mask.s_addr)) == -1)
157			err(1, NULL);
158
159	if (detail) {
160		printf("\n");
161		printf("Interface %s, line protocol is %s\n",
162		    iface->name, print_link(iface->flags));
163		printf("  Internet address %s/%d, ",
164		    inet_ntoa(iface->addr),
165		    mask2prefixlen(iface->mask.s_addr));
166		printf("Area %s\n", inet_ntoa(iface->area));
167		printf("  Linkstate %s,",
168		    get_linkstate(iface->if_type, iface->linkstate));
169		printf(" mtu %d\n", iface->mtu);
170		printf("  Router ID %s, network type %s, cost: %d\n",
171		    inet_ntoa(iface->rtr_id),
172		    if_type_name(iface->type), iface->metric);
173		if (iface->dependon[0] != '\0') {
174			printf("  Depends on %s, %s\n", iface->dependon,
175			    iface->depend_ok ? "up" : "down");
176		}
177		printf("  Transmit delay is %d sec(s), state %s, priority %d\n",
178		    iface->transmit_delay, if_state_name(iface->state),
179		    iface->priority);
180		printf("  Designated Router (ID) %s, ",
181		    inet_ntoa(iface->dr_id));
182		printf("interface address %s\n", inet_ntoa(iface->dr_addr));
183		printf("  Backup Designated Router (ID) %s, ",
184		    inet_ntoa(iface->bdr_id));
185		printf("interface address %s\n", inet_ntoa(iface->bdr_addr));
186		if (iface->dead_interval == FAST_RTR_DEAD_TIME) {
187			printf("  Timer intervals configured, "
188			    "hello %d msec, dead %d, wait %d, retransmit %d\n",
189			    iface->fast_hello_interval, iface->dead_interval,
190			    iface->dead_interval, iface->rxmt_interval);
191
192		} else {
193			printf("  Timer intervals configured, "
194			    "hello %d, dead %d, wait %d, retransmit %d\n",
195			    iface->hello_interval, iface->dead_interval,
196			    iface->dead_interval, iface->rxmt_interval);
197		}
198
199		if (iface->passive)
200			printf("    Passive interface (No Hellos)\n");
201		else if (iface->hello_timer.tv_sec < 0)
202			printf("    Hello timer not running\n");
203		else
204			printf("    Hello timer due in %s+%ldmsec\n",
205			    fmt_timeframe_core(iface->hello_timer.tv_sec),
206			    iface->hello_timer.tv_usec / 1000);
207		printf("    Uptime %s\n", fmt_timeframe_core(iface->uptime));
208		printf("  Neighbor count is %d, adjacent neighbor count is "
209		    "%d\n", iface->nbr_cnt, iface->adj_cnt);
210
211		if (iface->auth_type > 0) {
212			switch (iface->auth_type) {
213			case AUTH_SIMPLE:
214				printf("  Simple password authentication "
215				    "enabled\n");
216				break;
217			case AUTH_CRYPT:
218				printf("  Message digest authentication "
219				    "enabled\n");
220				printf("    Primary key id is %d\n",
221				    iface->auth_keyid);
222				break;
223			default:
224				break;
225			}
226		}
227	} else {
228		printf("%-11s %-18s %-6s %-10s %-10s %s %3d %3d\n",
229		    iface->name, netid, if_state_name(iface->state),
230		    iface->hello_timer.tv_sec < 0 ? "-" :
231		    fmt_timeframe_core(iface->hello_timer.tv_sec),
232		    get_linkstate(iface->if_type, iface->linkstate),
233		    fmt_timeframe_core(iface->uptime),
234		    iface->nbr_cnt, iface->adj_cnt);
235	}
236	free(netid);
237}
238
239
240static void
241show_neighbor(struct ctl_nbr *nbr, int detail)
242{
243	char	*state;
244
245	if (asprintf(&state, "%s/%s", nbr_state_name(nbr->nbr_state),
246	    if_state_name(nbr->iface_state)) == -1)
247		err(1, NULL);
248
249	if (detail) {
250		printf("\nNeighbor %s, ", inet_ntoa(nbr->id));
251		printf("interface address %s\n", inet_ntoa(nbr->addr));
252		printf("  Area %s, interface %s\n", inet_ntoa(nbr->area),
253		    nbr->name);
254		printf("  Neighbor priority is %d, "
255		    "State is %s, %d state changes\n",
256		    nbr->priority, nbr_state_name(nbr->nbr_state),
257		    nbr->state_chng_cnt);
258		printf("  DR is %s, ", inet_ntoa(nbr->dr));
259		printf("BDR is %s\n", inet_ntoa(nbr->bdr));
260		printf("  Options %s\n", print_ospf_options(nbr->options));
261		printf("  Dead timer due in %s\n",
262		    fmt_timeframe_core(nbr->dead_timer));
263		printf("  Uptime %s\n", fmt_timeframe_core(nbr->uptime));
264		printf("  Database Summary List %d\n", nbr->db_sum_lst_cnt);
265		printf("  Link State Request List %d\n", nbr->ls_req_lst_cnt);
266		printf("  Link State Retransmission List %d\n",
267		    nbr->ls_retrans_lst_cnt);
268	} else {
269		printf("%-15s %-3d %-12s %-9s", inet_ntoa(nbr->id),
270		    nbr->priority, state, fmt_timeframe_core(nbr->dead_timer));
271		printf("%-15s %-9s %s\n", inet_ntoa(nbr->addr), nbr->name,
272		    nbr->uptime == 0 ? "-" : fmt_timeframe_core(nbr->uptime));
273	}
274	free(state);
275}
276
277static void
278show_rib(struct ctl_rt *rt, int detail)
279{
280	char		*dstnet;
281	static u_int8_t	 lasttype;
282
283	if (detail) {
284		switch (rt->p_type) {
285		case PT_INTRA_AREA:
286		case PT_INTER_AREA:
287			switch (rt->d_type) {
288			case DT_NET:
289				if (lasttype != RIB_NET)
290					show_rib_head(rt->area, rt->d_type,
291					    rt->p_type);
292				if (asprintf(&dstnet, "%s/%d",
293				    inet_ntoa(rt->prefix), rt->prefixlen) == -1)
294					err(1, NULL);
295				lasttype = RIB_NET;
296				break;
297			case DT_RTR:
298				if (lasttype != RIB_RTR)
299					show_rib_head(rt->area, rt->d_type,
300					    rt->p_type);
301				if (asprintf(&dstnet, "%s",
302					inet_ntoa(rt->prefix)) == -1)
303					err(1, NULL);
304				lasttype = RIB_RTR;
305				break;
306			default:
307				errx(1, "unknown route type");
308			}
309			printf("%-18s %-15s ", dstnet, inet_ntoa(rt->nexthop));
310			printf("%-15s %-12s %-7d", inet_ntoa(rt->adv_rtr),
311			    path_type_name(rt->p_type), rt->cost);
312			free(dstnet);
313
314			if (rt->d_type == DT_RTR)
315				printf(" %-7s", print_ospf_rtr_flags(rt->flags));
316
317			printf("\n");
318			break;
319		case PT_TYPE1_EXT:
320		case PT_TYPE2_EXT:
321			if (lasttype != RIB_EXT)
322				show_rib_head(rt->area, rt->d_type, rt->p_type);
323
324			if (asprintf(&dstnet, "%s/%d", inet_ntoa(rt->prefix),
325			    rt->prefixlen) == -1)
326				err(1, NULL);
327
328			printf("%-18s %-15s ", dstnet, inet_ntoa(rt->nexthop));
329			printf("%-15s %-12s %-7d %-7d\n", inet_ntoa(rt->adv_rtr),
330			    path_type_name(rt->p_type), rt->cost, rt->cost2);
331
332			free(dstnet);
333
334			lasttype = RIB_EXT;
335			break;
336		default:
337			errx(1, "unknown route type");
338		}
339	} else {
340		switch (rt->d_type) {
341		case DT_NET:
342			if (asprintf(&dstnet, "%s/%d", inet_ntoa(rt->prefix),
343			    rt->prefixlen) == -1)
344				err(1, NULL);
345			break;
346		case DT_RTR:
347			if (asprintf(&dstnet, "%s",
348			    inet_ntoa(rt->prefix)) == -1)
349				err(1, NULL);
350			break;
351		default:
352			errx(1, "Invalid route type");
353		}
354
355		printf("%-20s %-16s%s %-12s %-9s %-7d %s\n", dstnet,
356		    inet_ntoa(rt->nexthop), rt->connected ? "C" : " ",
357		    path_type_name(rt->p_type),
358		    dst_type_name(rt->d_type), rt->cost,
359		    rt->uptime == 0 ? "-" : fmt_timeframe_core(rt->uptime));
360
361		free(dstnet);
362	}
363}
364
365static void
366show_fib(struct kroute *k)
367{
368	char	*p;
369
370	if (k->flags & F_DOWN)
371		printf(" ");
372	else
373		printf("*");
374
375	if (!(k->flags & F_KERNEL))
376		printf("O");
377	else if (k->flags & F_CONNECTED)
378		printf("C");
379	else if (k->flags & F_STATIC)
380		printf("S");
381	else
382		printf(" ");
383
384	printf("     ");
385	printf("%4d ", k->priority);
386	if (asprintf(&p, "%s/%u", inet_ntoa(k->prefix), k->prefixlen) == -1)
387		err(1, NULL);
388
389	printf("%-20s ", p);
390	free(p);
391
392	if (k->nexthop.s_addr)
393		printf("%s", inet_ntoa(k->nexthop));
394	else if (k->flags & F_CONNECTED)
395		printf("link#%u", k->ifindex);
396
397	printf("\n");
398}
399
400static void
401show_fib_interface(struct kif *k)
402{
403	uint64_t	ifms_type;
404
405	printf("%-15s", k->ifname);
406	printf("%-15s", k->flags & IFF_UP ? "UP" : "");
407	ifms_type = get_ifms_type(k->if_type);
408	if (ifms_type)
409		printf("%s, ", get_media_descr(ifms_type));
410
411	printf("%s", get_linkstate(k->if_type, k->link_state));
412
413	if (k->link_state != LINK_STATE_DOWN && k->baudrate > 0) {
414		printf(", ");
415		printf("%s", print_baudrate(k->baudrate));
416	}
417	printf("\n");
418}
419
420static void
421show_database_head(struct in_addr aid, char *ifname, u_int8_t type)
422{
423	char	*header, *format;
424	int	 cleanup = 0;
425
426	switch (type) {
427	case LSA_TYPE_ROUTER:
428		format = "Router Link States";
429		break;
430	case LSA_TYPE_NETWORK:
431		format = "Net Link States";
432		break;
433	case LSA_TYPE_SUM_NETWORK:
434		format = "Summary Net Link States";
435		break;
436	case LSA_TYPE_SUM_ROUTER:
437		format = "Summary Router Link States";
438		break;
439	case LSA_TYPE_EXTERNAL:
440		format = NULL;
441		if ((header = strdup("Type-5 AS External Link States")) == NULL)
442			err(1, NULL);
443		break;
444	case LSA_TYPE_LINK_OPAQ:
445		format = "Type-9 Link Local Opaque Link States";
446		break;
447	case LSA_TYPE_AREA_OPAQ:
448		format = "Type-10 Area Local Opaque Link States";
449		break;
450	case LSA_TYPE_AS_OPAQ:
451		format = NULL;
452		if ((header = strdup("Type-11 AS Wide Opaque Link States")) ==
453			NULL)
454			err(1, NULL);
455		break;
456	default:
457		if (asprintf(&format, "LSA type %x", ntohs(type)) == -1)
458			err(1, NULL);
459		cleanup = 1;
460		break;
461	}
462	if (type == LSA_TYPE_LINK_OPAQ) {
463		if (asprintf(&header, "%s (Area %s Interface %s)", format,
464		    inet_ntoa(aid), ifname) == -1)
465			err(1, NULL);
466	} else if (type != LSA_TYPE_EXTERNAL && type != LSA_TYPE_AS_OPAQ)
467		if (asprintf(&header, "%s (Area %s)", format,
468		    inet_ntoa(aid)) == -1)
469			err(1, NULL);
470
471	printf("\n%-15s %s\n\n", "", header);
472	free(header);
473	if (cleanup)
474		free(format);
475}
476
477static void
478show_db_hdr_msg_detail(struct lsa_hdr *lsa)
479{
480	printf("LS age: %d\n", ntohs(lsa->age));
481	printf("Options: %s\n", print_ospf_options(lsa->opts));
482	printf("LS Type: %s\n", print_ls_type(lsa->type));
483
484	switch (lsa->type) {
485	case LSA_TYPE_ROUTER:
486		printf("Link State ID: %s\n", log_id(lsa->ls_id));
487		break;
488	case LSA_TYPE_NETWORK:
489		printf("Link State ID: %s (address of Designated Router)\n",
490		    log_id(lsa->ls_id));
491		break;
492	case LSA_TYPE_SUM_NETWORK:
493		printf("Link State ID: %s (Network ID)\n", log_id(lsa->ls_id));
494		break;
495	case LSA_TYPE_SUM_ROUTER:
496		printf("Link State ID: %s (ASBR Router ID)\n",
497		    log_id(lsa->ls_id));
498		break;
499	case LSA_TYPE_EXTERNAL:
500		printf("Link State ID: %s (External Network Number)\n",
501		    log_id(lsa->ls_id));
502		break;
503	case LSA_TYPE_LINK_OPAQ:
504	case LSA_TYPE_AREA_OPAQ:
505	case LSA_TYPE_AS_OPAQ:
506		printf("Link State ID: %s Type %d ID %d\n", log_id(lsa->ls_id),
507		    LSA_24_GETHI(ntohl(lsa->ls_id)),
508		    LSA_24_GETLO(ntohl(lsa->ls_id)));
509		break;
510	}
511
512	printf("Advertising Router: %s\n", log_adv_rtr(lsa->adv_rtr));
513	printf("LS Seq Number: 0x%08x\n", ntohl(lsa->seq_num));
514	printf("Checksum: 0x%04x\n", ntohs(lsa->ls_chksum));
515	printf("Length: %d\n", ntohs(lsa->len));
516}
517
518static void
519show_db_simple(struct lsa_hdr *lsa, struct in_addr area_id, u_int8_t lasttype,
520    char *ifname)
521{
522	if (lsa->type != lasttype) {
523		show_database_head(area_id, ifname, lsa->type);
524		printf("%-15s %-15s %-4s %-10s %-8s\n", "Link ID",
525		    "Adv Router", "Age", "Seq#", "Checksum");
526	}
527	printf("%-15s %-15s %-4d 0x%08x 0x%04x\n",
528	    log_id(lsa->ls_id), log_adv_rtr(lsa->adv_rtr),
529	    ntohs(lsa->age), ntohl(lsa->seq_num),
530	    ntohs(lsa->ls_chksum));
531}
532static void
533show_db(struct lsa *lsa, struct in_addr	area_id, u_int8_t lasttype,
534	char *ifname)
535{
536	struct in_addr		 addr, data;
537	struct lsa_asext	*asext;
538	struct lsa_rtr_link	*rtr_link;
539	u_int16_t		 i, nlinks, off;
540
541	if (lsa->hdr.type != lasttype)
542		show_database_head(area_id, ifname, lsa->hdr.type);
543	show_db_hdr_msg_detail(&lsa->hdr);
544
545	switch (lsa->hdr.type) {
546	case LSA_TYPE_EXTERNAL:
547		addr.s_addr = lsa->data.asext.mask;
548		printf("Network Mask: %s\n", inet_ntoa(addr));
549
550		asext = (struct lsa_asext *)((char *)lsa + sizeof(lsa->hdr));
551
552		printf("    Metric type: ");
553		if (ntohl(lsa->data.asext.metric) & LSA_ASEXT_E_FLAG)
554			printf("2\n");
555		else
556			printf("1\n");
557		printf("    Metric: %d\n", ntohl(asext->metric) &
558		    LSA_METRIC_MASK);
559		addr.s_addr = asext->fw_addr;
560		printf("    Forwarding Address: %s\n", inet_ntoa(addr));
561		printf("    External Route Tag: %d\n\n", ntohl(asext->ext_tag));
562		break;
563	case LSA_TYPE_NETWORK:
564		addr.s_addr = lsa->data.net.mask;
565		printf("Network Mask: %s\n", inet_ntoa(addr));
566
567		nlinks = (ntohs(lsa->hdr.len) - sizeof(struct lsa_hdr)
568		    - sizeof(u_int32_t)) / sizeof(struct lsa_net_link);
569		off = sizeof(lsa->hdr) + sizeof(u_int32_t);
570		printf("Number of Routers: %d\n", nlinks);
571
572		for (i = 0; i < nlinks; i++) {
573			addr.s_addr = lsa->data.net.att_rtr[i];
574			printf("    Attached Router: %s\n", inet_ntoa(addr));
575		}
576
577		printf("\n");
578		break;
579	case LSA_TYPE_ROUTER:
580		printf("Flags: %s\n", print_ospf_flags(lsa->data.rtr.flags));
581		nlinks = ntohs(lsa->data.rtr.nlinks);
582		printf("Number of Links: %d\n\n", nlinks);
583
584		off = sizeof(lsa->hdr) + sizeof(struct lsa_rtr);
585
586		for (i = 0; i < nlinks; i++) {
587			rtr_link = (struct lsa_rtr_link *)((char *)lsa + off);
588
589			printf("    Link connected to: %s\n",
590			    print_rtr_link_type(rtr_link->type));
591
592			addr.s_addr = rtr_link->id;
593			data.s_addr = rtr_link->data;
594
595			switch (rtr_link->type) {
596			case LINK_TYPE_POINTTOPOINT:
597			case LINK_TYPE_VIRTUAL:
598				printf("    Link ID (Neighbors Router ID): "
599				    "%s\n", inet_ntoa(addr));
600				printf("    Link Data (Router Interface "
601				    "address): %s\n", inet_ntoa(data));
602				break;
603			case LINK_TYPE_TRANSIT_NET:
604				printf("    Link ID (Designated Router "
605				    "address): %s\n", inet_ntoa(addr));
606				printf("    Link Data (Router Interface "
607				    "address): %s\n", inet_ntoa(data));
608				break;
609			case LINK_TYPE_STUB_NET:
610				printf("    Link ID (Network ID): %s\n",
611				    inet_ntoa(addr));
612				printf("    Link Data (Network Mask): %s\n",
613				    inet_ntoa(data));
614				break;
615			default:
616				printf("    Link ID (Unknown): %s\n",
617				    inet_ntoa(addr));
618				printf("    Link Data (Unknown): %s\n",
619				    inet_ntoa(data));
620				break;
621			}
622
623			printf("    Metric: %d\n\n", ntohs(rtr_link->metric));
624
625			off += sizeof(struct lsa_rtr_link) +
626			    rtr_link->num_tos * sizeof(u_int32_t);
627		}
628		break;
629	case LSA_TYPE_SUM_ROUTER:
630		if (lsa->hdr.type != lasttype)
631			show_database_head(area_id, ifname, lsa->hdr.type);
632
633		show_db_hdr_msg_detail(&lsa->hdr);
634		addr.s_addr = lsa->data.sum.mask;
635		printf("Network Mask: %s\n", inet_ntoa(addr));
636		printf("Metric: %d\n\n", ntohl(lsa->data.sum.metric) &
637		    LSA_METRIC_MASK);
638		break;
639	case LSA_TYPE_LINK_OPAQ:
640	case LSA_TYPE_AREA_OPAQ:
641	case LSA_TYPE_AS_OPAQ:
642		if (lsa->hdr.type != lasttype)
643			show_database_head(area_id, ifname, lsa->hdr.type);
644
645		show_db_hdr_msg_detail(&lsa->hdr);
646		break;
647	}
648}
649
650static void
651show_tail(void)
652{
653	/* nothing */
654}
655
656const struct output show_output = {
657	.head = show_head,
658	.summary = show_summary,
659	.summary_area = show_summary_area,
660	.interface = show_interface,
661	.neighbor = show_neighbor,
662	.rib = show_rib,
663	.fib = show_fib,
664	.fib_interface = show_fib_interface,
665	.db = show_db,
666	.db_simple = show_db_simple,
667	.tail = show_tail
668};
669