1/*
2 * Copyright (c) 1992, 1993, 1994, 1995, 1996, 1997
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that: (1) source code distributions
7 * retain the above copyright notice and this paragraph in its entirety, (2)
8 * distributions including binary code include the above copyright notice and
9 * this paragraph in its entirety in the documentation or other materials
10 * provided with the distribution, and (3) all advertising materials mentioning
11 * features or use of this software display the following acknowledgement:
12 * ``This product includes software developed by the University of California,
13 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14 * the University nor the names of its contributors may be used to endorse
15 * or promote products derived from this software without specific prior
16 * written permission.
17 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20 *
21 * OSPF support contributed by Jeffrey Honig (jch@mitchell.cit.cornell.edu)
22 */
23
24#ifndef lint
25static const char rcsid[] _U_ =
26    "@(#) $Header: /tcpdump/master/tcpdump/print-ospf6.c,v 1.15 2006-09-13 06:31:11 guy Exp $ (LBL)";
27#endif
28
29#ifdef HAVE_CONFIG_H
30#include "config.h"
31#endif
32
33#include <tcpdump-stdinc.h>
34
35#include <stdio.h>
36#include <string.h>
37
38#include "interface.h"
39#include "addrtoname.h"
40#include "extract.h"
41
42#include "ospf.h"
43#include "ospf6.h"
44
45static const struct tok ospf6_option_values[] = {
46	{ OSPF6_OPTION_V6,	"V6" },
47	{ OSPF6_OPTION_E,	"External" },
48	{ OSPF6_OPTION_MC,	"Multicast" },
49	{ OSPF6_OPTION_N,	"NSSA" },
50	{ OSPF6_OPTION_R,	"Router" },
51	{ OSPF6_OPTION_DC,	"Demand Circuit" },
52	{ 0,			NULL }
53};
54
55static const struct tok ospf6_rla_flag_values[] = {
56	{ RLA_FLAG_B,		"ABR" },
57	{ RLA_FLAG_E,		"External" },
58	{ RLA_FLAG_V,		"Virtual-Link Endpoint" },
59	{ RLA_FLAG_W,		"Wildcard Receiver" },
60        { RLA_FLAG_N,           "NSSA Translator" },
61	{ 0,			NULL }
62};
63
64static const struct tok ospf6_asla_flag_values[] = {
65	{ ASLA_FLAG_EXTERNAL,	"External Type 2" },
66	{ ASLA_FLAG_FWDADDR,	"Fforwarding" },
67	{ ASLA_FLAG_ROUTETAG,	"Tag" },
68	{ 0,			NULL }
69};
70
71static struct tok ospf6_type_values[] = {
72	{ OSPF_TYPE_HELLO,	"Hello" },
73	{ OSPF_TYPE_DD,		"Database Description" },
74	{ OSPF_TYPE_LS_REQ,	"LS-Request" },
75	{ OSPF_TYPE_LS_UPDATE,	"LS-Update" },
76	{ OSPF_TYPE_LS_ACK,	"LS-Ack" },
77	{ 0,			NULL }
78};
79
80static struct tok ospf6_lsa_values[] = {
81	{ LS_TYPE_ROUTER,       "Router" },
82	{ LS_TYPE_NETWORK,      "Network" },
83	{ LS_TYPE_INTER_AP,     "Inter-Area Prefix" },
84	{ LS_TYPE_INTER_AR,     "Inter-Area Router" },
85	{ LS_TYPE_ASE,          "External" },
86	{ LS_TYPE_GROUP,        "Multicast Group" },
87	{ LS_TYPE_NSSA,         "NSSA" },
88	{ LS_TYPE_LINK,         "Link" },
89	{ LS_TYPE_INTRA_AP,     "Intra-Area Prefix" },
90        { LS_TYPE_INTRA_ATE,    "Intra-Area TE" },
91        { LS_TYPE_GRACE,        "Grace" },
92	{ 0,			NULL }
93};
94
95static struct tok ospf6_ls_scope_values[] = {
96	{ LS_SCOPE_LINKLOCAL,   "Link Local" },
97	{ LS_SCOPE_AREA,        "Area Local" },
98	{ LS_SCOPE_AS,          "Domain Wide" },
99	{ 0,			NULL }
100};
101
102static struct tok ospf6_dd_flag_values[] = {
103	{ OSPF6_DB_INIT,	"Init" },
104	{ OSPF6_DB_MORE,	"More" },
105	{ OSPF6_DB_MASTER,	"Master" },
106	{ 0,			NULL }
107};
108
109static struct tok ospf6_lsa_prefix_option_values[] = {
110        { LSA_PREFIX_OPT_NU, "No Unicast" },
111        { LSA_PREFIX_OPT_LA, "Local address" },
112        { LSA_PREFIX_OPT_MC, "Multicast" },
113        { LSA_PREFIX_OPT_P, "Propagate" },
114        { LSA_PREFIX_OPT_DN, "Down" },
115	{ 0, NULL }
116};
117
118static char tstr[] = " [|ospf3]";
119
120#ifdef WIN32
121#define inline __inline
122#endif /* WIN32 */
123
124/* Forwards */
125static void ospf6_print_ls_type(u_int, const rtrid_t *);
126static int ospf6_print_lshdr(const struct lsa6_hdr *);
127static int ospf6_print_lsa(const struct lsa6 *);
128static int ospf6_decode_v3(const struct ospf6hdr *, const u_char *);
129
130
131static void
132ospf6_print_ls_type(register u_int ls_type, register const rtrid_t *ls_stateid)
133{
134        printf("\n\t    %s LSA (%d), %s Scope%s, LSA-ID %s",
135               tok2str(ospf6_lsa_values, "Unknown", ls_type & LS_TYPE_MASK),
136               ls_type & LS_TYPE_MASK,
137               tok2str(ospf6_ls_scope_values, "Unknown", ls_type & LS_SCOPE_MASK),
138               ls_type &0x8000 ? ", transitive" : "", /* U-bit */
139               ipaddr_string(ls_stateid));
140}
141
142static int
143ospf6_print_lshdr(register const struct lsa6_hdr *lshp)
144{
145
146	TCHECK(lshp->ls_type);
147	TCHECK(lshp->ls_seq);
148
149	printf("\n\t  Advertising Router %s, seq 0x%08x, age %us, length %u",
150               ipaddr_string(&lshp->ls_router),
151               EXTRACT_32BITS(&lshp->ls_seq),
152               EXTRACT_16BITS(&lshp->ls_age),
153               EXTRACT_16BITS(&lshp->ls_length)-(u_int)sizeof(struct lsa6_hdr));
154
155	ospf6_print_ls_type(EXTRACT_16BITS(&lshp->ls_type), &lshp->ls_stateid);
156
157	return (0);
158trunc:
159	return (1);
160}
161
162static int
163ospf6_print_lsaprefix(const u_int8_t *tptr, u_int lsa_length)
164{
165	const struct lsa6_prefix *lsapp = (struct lsa6_prefix *)tptr;
166	u_int wordlen;
167	struct in6_addr prefix;
168
169	if (lsa_length < sizeof (*lsapp) - 4)
170		goto trunc;
171	lsa_length -= sizeof (*lsapp) - 4;
172	TCHECK2(*lsapp, sizeof (*lsapp) - 4);
173	wordlen = (lsapp->lsa_p_len + 31) / 32;
174	if (wordlen * 4 > sizeof(struct in6_addr)) {
175		printf(" bogus prefixlen /%d", lsapp->lsa_p_len);
176		goto trunc;
177	}
178	if (lsa_length < wordlen * 4)
179		goto trunc;
180	lsa_length -= wordlen * 4;
181	TCHECK2(lsapp->lsa_p_prefix, wordlen * 4);
182	memset(&prefix, 0, sizeof(prefix));
183	memcpy(&prefix, lsapp->lsa_p_prefix, wordlen * 4);
184	printf("\n\t\t%s/%d", ip6addr_string(&prefix),
185		lsapp->lsa_p_len);
186        if (lsapp->lsa_p_opt) {
187            printf(", Options [%s]",
188                   bittok2str(ospf6_lsa_prefix_option_values,
189                              "none", lsapp->lsa_p_opt));
190        }
191        printf(", metric %u", EXTRACT_16BITS(&lsapp->lsa_p_metric));
192	return sizeof(*lsapp) - 4 + wordlen * 4;
193
194trunc:
195	return -1;
196}
197
198
199/*
200 * Print a single link state advertisement.  If truncated return 1, else 0.
201 */
202static int
203ospf6_print_lsa(register const struct lsa6 *lsap)
204{
205	register const struct rlalink6 *rlp;
206#if 0
207	register const struct tos_metric *tosp;
208#endif
209	register const rtrid_t *ap;
210#if 0
211	register const struct aslametric *almp;
212	register const struct mcla *mcp;
213#endif
214	register const struct llsa *llsap;
215	register const struct lsa6_prefix *lsapp;
216#if 0
217	register const u_int32_t *lp;
218#endif
219	register u_int prefixes;
220	register int bytelen;
221	register u_int length, lsa_length;
222	u_int32_t flags32;
223	const u_int8_t *tptr;
224
225	if (ospf6_print_lshdr(&lsap->ls_hdr))
226		return (1);
227	TCHECK(lsap->ls_hdr.ls_length);
228        length = EXTRACT_16BITS(&lsap->ls_hdr.ls_length);
229
230	/*
231	 * The LSA length includes the length of the header;
232	 * it must have a value that's at least that length.
233	 * If it does, find the length of what follows the
234	 * header.
235	 */
236        if (length < sizeof(struct lsa6_hdr))
237        	return (1);
238        lsa_length = length - sizeof(struct lsa6_hdr);
239        tptr = (u_int8_t *)lsap+sizeof(struct lsa6_hdr);
240
241	switch (EXTRACT_16BITS(&lsap->ls_hdr.ls_type)) {
242	case LS_TYPE_ROUTER | LS_SCOPE_AREA:
243		if (lsa_length < sizeof (lsap->lsa_un.un_rla.rla_options))
244			return (1);
245		lsa_length -= sizeof (lsap->lsa_un.un_rla.rla_options);
246		TCHECK(lsap->lsa_un.un_rla.rla_options);
247                printf("\n\t      Options [%s]",
248                       bittok2str(ospf6_option_values, "none",
249                                  EXTRACT_32BITS(&lsap->lsa_un.un_rla.rla_options)));
250                printf(", RLA-Flags [%s]",
251                       bittok2str(ospf6_rla_flag_values, "none",
252                                  lsap->lsa_un.un_rla.rla_flags));
253
254		rlp = lsap->lsa_un.un_rla.rla_link;
255		while (lsa_length != 0) {
256			if (lsa_length < sizeof (*rlp))
257				return (1);
258			lsa_length -= sizeof (*rlp);
259			TCHECK(*rlp);
260			switch (rlp->link_type) {
261
262			case RLA_TYPE_VIRTUAL:
263				printf("\n\t      Virtual Link: Neighbor Router-ID %s"
264                                       "\n\t      Neighbor Interface-ID %s, Interface %s",
265                                       ipaddr_string(&rlp->link_nrtid),
266                                       ipaddr_string(&rlp->link_nifid),
267                                       ipaddr_string(&rlp->link_ifid));
268                                break;
269
270			case RLA_TYPE_ROUTER:
271				printf("\n\t      Neighbor Router-ID %s"
272                                       "\n\t      Neighbor Interface-ID %s, Interface %s",
273                                       ipaddr_string(&rlp->link_nrtid),
274                                       ipaddr_string(&rlp->link_nifid),
275                                       ipaddr_string(&rlp->link_ifid));
276				break;
277
278			case RLA_TYPE_TRANSIT:
279				printf("\n\t      Neighbor Network-ID %s"
280                                       "\n\t      Neighbor Interface-ID %s, Interface %s",
281				    ipaddr_string(&rlp->link_nrtid),
282				    ipaddr_string(&rlp->link_nifid),
283				    ipaddr_string(&rlp->link_ifid));
284				break;
285
286			default:
287				printf("\n\t      Unknown Router Links Type 0x%02x",
288				    rlp->link_type);
289				return (0);
290			}
291			printf(", metric %d", EXTRACT_16BITS(&rlp->link_metric));
292			rlp++;
293		}
294		break;
295
296	case LS_TYPE_NETWORK | LS_SCOPE_AREA:
297		if (lsa_length < sizeof (lsap->lsa_un.un_nla.nla_options))
298			return (1);
299		lsa_length -= sizeof (lsap->lsa_un.un_nla.nla_options);
300		TCHECK(lsap->lsa_un.un_nla.nla_options);
301                printf("\n\t      Options [%s]",
302                       bittok2str(ospf6_option_values, "none",
303                                  EXTRACT_32BITS(&lsap->lsa_un.un_nla.nla_options)));
304
305		printf("\n\t      Connected Routers:");
306		ap = lsap->lsa_un.un_nla.nla_router;
307		while (lsa_length != 0) {
308			if (lsa_length < sizeof (*ap))
309				return (1);
310			lsa_length -= sizeof (*ap);
311			TCHECK(*ap);
312			printf("\n\t\t%s", ipaddr_string(ap));
313			++ap;
314		}
315		break;
316
317	case LS_TYPE_INTER_AP | LS_SCOPE_AREA:
318		if (lsa_length < sizeof (lsap->lsa_un.un_inter_ap.inter_ap_metric))
319			return (1);
320		lsa_length -= sizeof (lsap->lsa_un.un_inter_ap.inter_ap_metric);
321		TCHECK(lsap->lsa_un.un_inter_ap.inter_ap_metric);
322		printf(", metric %u",
323			EXTRACT_32BITS(&lsap->lsa_un.un_inter_ap.inter_ap_metric) & SLA_MASK_METRIC);
324
325		tptr = (u_int8_t *)lsap->lsa_un.un_inter_ap.inter_ap_prefix;
326		while (lsa_length != 0) {
327			bytelen = ospf6_print_lsaprefix(tptr, lsa_length);
328			if (bytelen < 0)
329				goto trunc;
330			lsa_length -= bytelen;
331			tptr += bytelen;
332		}
333		break;
334
335	case LS_TYPE_ASE | LS_SCOPE_AS:
336		if (lsa_length < sizeof (lsap->lsa_un.un_asla.asla_metric))
337			return (1);
338		lsa_length -= sizeof (lsap->lsa_un.un_asla.asla_metric);
339		TCHECK(lsap->lsa_un.un_asla.asla_metric);
340		flags32 = EXTRACT_32BITS(&lsap->lsa_un.un_asla.asla_metric);
341                printf("\n\t     Flags [%s]",
342                       bittok2str(ospf6_asla_flag_values, "none", flags32));
343		printf(" metric %u",
344		       EXTRACT_32BITS(&lsap->lsa_un.un_asla.asla_metric) &
345		       ASLA_MASK_METRIC);
346
347		tptr = (u_int8_t *)lsap->lsa_un.un_asla.asla_prefix;
348		lsapp = (struct lsa6_prefix *)tptr;
349		bytelen = ospf6_print_lsaprefix(tptr, lsa_length);
350		if (bytelen < 0)
351			goto trunc;
352		lsa_length -= bytelen;
353		tptr += bytelen;
354
355		if ((flags32 & ASLA_FLAG_FWDADDR) != 0) {
356			struct in6_addr *fwdaddr6;
357
358			fwdaddr6 = (struct in6_addr *)tptr;
359			if (lsa_length < sizeof (*fwdaddr6))
360				return (1);
361			lsa_length -= sizeof (*fwdaddr6);
362			TCHECK(*fwdaddr6);
363			printf(" forward %s",
364			       ip6addr_string(fwdaddr6));
365			tptr += sizeof(*fwdaddr6);
366		}
367
368		if ((flags32 & ASLA_FLAG_ROUTETAG) != 0) {
369			if (lsa_length < sizeof (u_int32_t))
370				return (1);
371			lsa_length -= sizeof (u_int32_t);
372			TCHECK(*(u_int32_t *)tptr);
373			printf(" tag %s",
374			       ipaddr_string((u_int32_t *)tptr));
375			tptr += sizeof(u_int32_t);
376		}
377
378		if (lsapp->lsa_p_metric) {
379			if (lsa_length < sizeof (u_int32_t))
380				return (1);
381			lsa_length -= sizeof (u_int32_t);
382			TCHECK(*(u_int32_t *)tptr);
383			printf(" RefLSID: %s",
384			       ipaddr_string((u_int32_t *)tptr));
385			tptr += sizeof(u_int32_t);
386		}
387		break;
388
389	case LS_TYPE_LINK:
390		/* Link LSA */
391		llsap = &lsap->lsa_un.un_llsa;
392		if (lsa_length < sizeof (llsap->llsa_priandopt))
393			return (1);
394		lsa_length -= sizeof (llsap->llsa_priandopt);
395		TCHECK(llsap->llsa_priandopt);
396                printf("\n\t      Options [%s]",
397                       bittok2str(ospf6_option_values, "none",
398                                  EXTRACT_32BITS(&llsap->llsa_options)));
399
400		if (lsa_length < sizeof (llsap->llsa_lladdr) + sizeof (llsap->llsa_nprefix))
401			return (1);
402		lsa_length -= sizeof (llsap->llsa_lladdr) + sizeof (llsap->llsa_nprefix);
403                prefixes = EXTRACT_32BITS(&llsap->llsa_nprefix);
404		printf("\n\t      Priority %d, Link-local address %s, Prefixes %d:",
405                       llsap->llsa_priority,
406                       ip6addr_string(&llsap->llsa_lladdr),
407                       prefixes);
408
409		tptr = (u_int8_t *)llsap->llsa_prefix;
410		while (prefixes > 0) {
411			bytelen = ospf6_print_lsaprefix(tptr, lsa_length);
412			if (bytelen < 0)
413				goto trunc;
414			prefixes--;
415			lsa_length -= bytelen;
416			tptr += bytelen;
417		}
418		break;
419
420	case LS_TYPE_INTRA_AP | LS_SCOPE_AREA:
421		/* Intra-Area-Prefix LSA */
422		if (lsa_length < sizeof (lsap->lsa_un.un_intra_ap.intra_ap_rtid))
423			return (1);
424		lsa_length -= sizeof (lsap->lsa_un.un_intra_ap.intra_ap_rtid);
425		TCHECK(lsap->lsa_un.un_intra_ap.intra_ap_rtid);
426		ospf6_print_ls_type(
427			EXTRACT_16BITS(&lsap->lsa_un.un_intra_ap.intra_ap_lstype),
428			&lsap->lsa_un.un_intra_ap.intra_ap_lsid);
429
430		if (lsa_length < sizeof (lsap->lsa_un.un_intra_ap.intra_ap_nprefix))
431			return (1);
432		lsa_length -= sizeof (lsap->lsa_un.un_intra_ap.intra_ap_nprefix);
433		TCHECK(lsap->lsa_un.un_intra_ap.intra_ap_nprefix);
434                prefixes = EXTRACT_16BITS(&lsap->lsa_un.un_intra_ap.intra_ap_nprefix);
435		printf("\n\t      Prefixes %d:", prefixes);
436
437		tptr = (u_int8_t *)lsap->lsa_un.un_intra_ap.intra_ap_prefix;
438		while (prefixes > 0) {
439			bytelen = ospf6_print_lsaprefix(tptr, lsa_length);
440			if (bytelen < 0)
441				goto trunc;
442			prefixes--;
443			lsa_length -= bytelen;
444			tptr += bytelen;
445		}
446		break;
447
448        case LS_TYPE_GRACE | LS_SCOPE_LINKLOCAL:
449                if (ospf_print_grace_lsa(tptr, lsa_length) == -1) {
450                    return 1;
451                }
452                break;
453
454        case LS_TYPE_INTRA_ATE | LS_SCOPE_LINKLOCAL:
455                if (ospf_print_te_lsa(tptr, lsa_length) == -1) {
456                    return 1;
457                }
458                break;
459
460	default:
461                if(!print_unknown_data(tptr,
462                                       "\n\t      ",
463                                       lsa_length)) {
464                    return (1);
465                }
466                break;
467	}
468
469	return (0);
470trunc:
471	return (1);
472}
473
474static int
475ospf6_decode_v3(register const struct ospf6hdr *op,
476    register const u_char *dataend)
477{
478	register const rtrid_t *ap;
479	register const struct lsr6 *lsrp;
480	register const struct lsa6_hdr *lshp;
481	register const struct lsa6 *lsap;
482	register int i;
483
484	switch (op->ospf6_type) {
485
486	case OSPF_TYPE_HELLO:
487                printf("\n\tOptions [%s]",
488                       bittok2str(ospf6_option_values, "none",
489                                  EXTRACT_32BITS(&op->ospf6_hello.hello_options)));
490
491                TCHECK(op->ospf6_hello.hello_deadint);
492                printf("\n\t  Hello Timer %us, Dead Timer %us, Interface-ID %s, Priority %u",
493                       EXTRACT_16BITS(&op->ospf6_hello.hello_helloint),
494                       EXTRACT_16BITS(&op->ospf6_hello.hello_deadint),
495                       ipaddr_string(&op->ospf6_hello.hello_ifid),
496                       op->ospf6_hello.hello_priority);
497
498		TCHECK(op->ospf6_hello.hello_dr);
499		if (op->ospf6_hello.hello_dr != 0)
500			printf("\n\t  Designated Router %s",
501			    ipaddr_string(&op->ospf6_hello.hello_dr));
502		TCHECK(op->ospf6_hello.hello_bdr);
503		if (op->ospf6_hello.hello_bdr != 0)
504			printf(", Backup Designated Router %s",
505			    ipaddr_string(&op->ospf6_hello.hello_bdr));
506		if (vflag) {
507			printf("\n\t  Neighbor List:");
508			ap = op->ospf6_hello.hello_neighbor;
509			while ((u_char *)ap < dataend) {
510				TCHECK(*ap);
511				printf("\n\t    %s", ipaddr_string(ap));
512				++ap;
513			}
514		}
515		break;	/* HELLO */
516
517	case OSPF_TYPE_DD:
518		TCHECK(op->ospf6_db.db_options);
519                printf("\n\tOptions [%s]",
520                       bittok2str(ospf6_option_values, "none",
521                                  EXTRACT_32BITS(&op->ospf6_db.db_options)));
522		TCHECK(op->ospf6_db.db_flags);
523                printf(", DD Flags [%s]",
524                       bittok2str(ospf6_dd_flag_values,"none",op->ospf6_db.db_flags));
525
526		TCHECK(op->ospf6_db.db_seq);
527		printf(", MTU %u, DD-Sequence 0x%08x",
528                       EXTRACT_16BITS(&op->ospf6_db.db_mtu),
529                       EXTRACT_32BITS(&op->ospf6_db.db_seq));
530
531                /* Print all the LS adv's */
532                lshp = op->ospf6_db.db_lshdr;
533                while (!ospf6_print_lshdr(lshp)) {
534                    ++lshp;
535                }
536		break;
537
538	case OSPF_TYPE_LS_REQ:
539		if (vflag) {
540			lsrp = op->ospf6_lsr;
541			while ((u_char *)lsrp < dataend) {
542				TCHECK(*lsrp);
543                                printf("\n\t  Advertising Router %s",
544                                       ipaddr_string(&lsrp->ls_router));
545				ospf6_print_ls_type(EXTRACT_16BITS(&lsrp->ls_type),
546                                                    &lsrp->ls_stateid);
547				++lsrp;
548			}
549		}
550		break;
551
552	case OSPF_TYPE_LS_UPDATE:
553		if (vflag) {
554			lsap = op->ospf6_lsu.lsu_lsa;
555			TCHECK(op->ospf6_lsu.lsu_count);
556			i = EXTRACT_32BITS(&op->ospf6_lsu.lsu_count);
557			while (i--) {
558				if (ospf6_print_lsa(lsap))
559					goto trunc;
560				lsap = (struct lsa6 *)((u_char *)lsap +
561				    EXTRACT_16BITS(&lsap->ls_hdr.ls_length));
562			}
563		}
564		break;
565
566
567	case OSPF_TYPE_LS_ACK:
568		if (vflag) {
569			lshp = op->ospf6_lsa.lsa_lshdr;
570
571			while (!ospf6_print_lshdr(lshp)) {
572				++lshp;
573			}
574		}
575		break;
576
577	default:
578		break;
579	}
580	return (0);
581trunc:
582	return (1);
583}
584
585void
586ospf6_print(register const u_char *bp, register u_int length)
587{
588	register const struct ospf6hdr *op;
589	register const u_char *dataend;
590	register const char *cp;
591
592	op = (struct ospf6hdr *)bp;
593
594	/* If the type is valid translate it, or just print the type */
595	/* value.  If it's not valid, say so and return */
596	TCHECK(op->ospf6_type);
597	cp = tok2str(ospf6_type_values, "unknown LS-type", op->ospf6_type);
598	printf("OSPFv%u, %s, length %d", op->ospf6_version, cp, length);
599	if (*cp == 'u') {
600		return;
601        }
602
603        if(!vflag) { /* non verbose - so lets bail out here */
604                return;
605        }
606
607	TCHECK(op->ospf6_len);
608	if (length != EXTRACT_16BITS(&op->ospf6_len)) {
609		printf(" [len %d]", EXTRACT_16BITS(&op->ospf6_len));
610		return;
611	}
612	dataend = bp + length;
613
614	/* Print the routerid if it is not the same as the source */
615	TCHECK(op->ospf6_routerid);
616	printf("\n\tRouter-ID %s", ipaddr_string(&op->ospf6_routerid));
617
618	TCHECK(op->ospf6_areaid);
619	if (op->ospf6_areaid != 0)
620		printf(", Area %s", ipaddr_string(&op->ospf6_areaid));
621	else
622		printf(", Backbone Area");
623	TCHECK(op->ospf6_instanceid);
624	if (op->ospf6_instanceid)
625		printf(", Instance %u", op->ospf6_instanceid);
626
627	/* Do rest according to version.	 */
628	switch (op->ospf6_version) {
629
630	case 3:
631		/* ospf version 3 */
632		if (ospf6_decode_v3(op, dataend))
633			goto trunc;
634		break;
635
636	default:
637		printf(" ospf [version %d]", op->ospf6_version);
638		break;
639	}			/* end switch on version */
640
641	return;
642trunc:
643	fputs(tstr, stdout);
644}
645