xref: /openbsd-src/usr.sbin/ospfctl/output.c (revision 27198fece99bdcb6d984ac315c4c48ba580fc30f)
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 
41 static void
show_head(struct parse_result * res)42 show_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 
72 static void
show_summary(struct ctl_sum * sum)73 show_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 
91 static void
show_summary_area(struct ctl_sum_area * sumarea)92 show_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 
105 static void
show_rib_head(struct in_addr aid,u_int8_t d_type,u_int8_t p_type)106 show_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 
149 static void
show_interface(struct ctl_iface * iface,int detail)150 show_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 
240 static void
show_neighbor(struct ctl_nbr * nbr,int detail)241 show_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 
277 static void
show_rib(struct ctl_rt * rt,int detail)278 show_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 
365 static void
show_fib(struct kroute * k)366 show_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 
400 static void
show_fib_interface(struct kif * k)401 show_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 
420 static void
show_database_head(struct in_addr aid,char * ifname,u_int8_t type)421 show_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 
477 static void
show_db_hdr_msg_detail(struct lsa_hdr * lsa)478 show_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 
518 static void
show_db_simple(struct lsa_hdr * lsa,struct in_addr area_id,u_int8_t lasttype,char * ifname)519 show_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 }
532 static void
show_db(struct lsa * lsa,struct in_addr area_id,u_int8_t lasttype,char * ifname)533 show_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 
650 static void
show_tail(void)651 show_tail(void)
652 {
653 	/* nothing */
654 }
655 
656 const 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