156893Sfenner/*
256893Sfenner * Copyright (c) 1992, 1993, 1994, 1995, 1996, 1997
356893Sfenner *	The Regents of the University of California.  All rights reserved.
456893Sfenner *
556893Sfenner * Redistribution and use in source and binary forms, with or without
656893Sfenner * modification, are permitted provided that: (1) source code distributions
756893Sfenner * retain the above copyright notice and this paragraph in its entirety, (2)
856893Sfenner * distributions including binary code include the above copyright notice and
956893Sfenner * this paragraph in its entirety in the documentation or other materials
1056893Sfenner * provided with the distribution, and (3) all advertising materials mentioning
1156893Sfenner * features or use of this software display the following acknowledgement:
1256893Sfenner * ``This product includes software developed by the University of California,
1356893Sfenner * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
1456893Sfenner * the University nor the names of its contributors may be used to endorse
1556893Sfenner * or promote products derived from this software without specific prior
1656893Sfenner * written permission.
1756893Sfenner * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
1856893Sfenner * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
1956893Sfenner * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
2056893Sfenner *
2156893Sfenner * OSPF support contributed by Jeffrey Honig (jch@mitchell.cit.cornell.edu)
2256893Sfenner */
2356893Sfenner
24313537Sglebius/* \summary: IPv6 Open Shortest Path First (OSPFv3) printer */
25313537Sglebius
2656893Sfenner#ifdef HAVE_CONFIG_H
2756893Sfenner#include "config.h"
2856893Sfenner#endif
2956893Sfenner
30313537Sglebius#include <netdissect-stdinc.h>
3156893Sfenner
3256893Sfenner#include <string.h>
3356893Sfenner
34313537Sglebius#include "netdissect.h"
3556893Sfenner#include "addrtoname.h"
36127668Sbms#include "extract.h"
3756893Sfenner
38190207Srpaulo#include "ospf.h"
3956893Sfenner
40276788Sdelphij#define	OSPF_TYPE_HELLO         1	/* Hello */
41276788Sdelphij#define	OSPF_TYPE_DD            2	/* Database Description */
42276788Sdelphij#define	OSPF_TYPE_LS_REQ        3	/* Link State Request */
43276788Sdelphij#define	OSPF_TYPE_LS_UPDATE     4	/* Link State Update */
44276788Sdelphij#define	OSPF_TYPE_LS_ACK        5	/* Link State Ack */
45276788Sdelphij
46276788Sdelphij/* Options *_options	*/
47276788Sdelphij#define OSPF6_OPTION_V6	0x01	/* V6 bit: A bit for peeping tom */
48276788Sdelphij#define OSPF6_OPTION_E	0x02	/* E bit: External routes advertised	*/
49276788Sdelphij#define OSPF6_OPTION_MC	0x04	/* MC bit: Multicast capable */
50276788Sdelphij#define OSPF6_OPTION_N	0x08	/* N bit: For type-7 LSA */
51276788Sdelphij#define OSPF6_OPTION_R	0x10	/* R bit: Router bit */
52276788Sdelphij#define OSPF6_OPTION_DC	0x20	/* DC bit: Demand circuits */
53276788Sdelphij/* The field is actually 24-bit (RFC5340 Section A.2). */
54276788Sdelphij#define OSPF6_OPTION_AF	0x0100	/* AF bit: Multiple address families */
55276788Sdelphij#define OSPF6_OPTION_L	0x0200	/* L bit: Link-local signaling (LLS) */
56276788Sdelphij#define OSPF6_OPTION_AT	0x0400	/* AT bit: Authentication trailer */
57276788Sdelphij
58276788Sdelphij
59276788Sdelphij/* db_flags	*/
60276788Sdelphij#define	OSPF6_DB_INIT		0x04	    /*	*/
61276788Sdelphij#define	OSPF6_DB_MORE		0x02
62276788Sdelphij#define	OSPF6_DB_MASTER		0x01
63276788Sdelphij#define	OSPF6_DB_M6		0x10  /* IPv6 MTU */
64276788Sdelphij
65276788Sdelphij/* ls_type	*/
66276788Sdelphij#define	LS_TYPE_ROUTER		1   /* router link */
67276788Sdelphij#define	LS_TYPE_NETWORK		2   /* network link */
68276788Sdelphij#define	LS_TYPE_INTER_AP	3   /* Inter-Area-Prefix */
69276788Sdelphij#define	LS_TYPE_INTER_AR	4   /* Inter-Area-Router */
70276788Sdelphij#define	LS_TYPE_ASE		5   /* ASE */
71276788Sdelphij#define	LS_TYPE_GROUP		6   /* Group membership */
72276788Sdelphij#define	LS_TYPE_NSSA		7   /* NSSA */
73276788Sdelphij#define	LS_TYPE_LINK		8   /* Link LSA */
74276788Sdelphij#define	LS_TYPE_INTRA_AP	9   /* Intra-Area-Prefix */
75276788Sdelphij#define LS_TYPE_INTRA_ATE       10  /* Intra-Area-TE */
76276788Sdelphij#define LS_TYPE_GRACE           11  /* Grace LSA */
77276788Sdelphij#define LS_TYPE_RI		12  /* Router information */
78276788Sdelphij#define LS_TYPE_INTER_ASTE	13  /* Inter-AS-TE */
79276788Sdelphij#define LS_TYPE_L1VPN		14  /* L1VPN */
80276788Sdelphij#define LS_TYPE_MASK		0x1fff
81276788Sdelphij
82276788Sdelphij#define LS_SCOPE_LINKLOCAL	0x0000
83276788Sdelphij#define LS_SCOPE_AREA		0x2000
84276788Sdelphij#define LS_SCOPE_AS		0x4000
85276788Sdelphij#define LS_SCOPE_MASK		0x6000
86276788Sdelphij#define LS_SCOPE_U              0x8000
87276788Sdelphij
88276788Sdelphij/* rla_link.link_type	*/
89276788Sdelphij#define	RLA_TYPE_ROUTER		1   /* point-to-point to another router	*/
90276788Sdelphij#define	RLA_TYPE_TRANSIT	2   /* connection to transit network	*/
91276788Sdelphij#define RLA_TYPE_VIRTUAL	4   /* virtual link			*/
92276788Sdelphij
93276788Sdelphij/* rla_flags	*/
94276788Sdelphij#define	RLA_FLAG_B	0x01
95276788Sdelphij#define	RLA_FLAG_E	0x02
96276788Sdelphij#define	RLA_FLAG_V	0x04
97276788Sdelphij#define	RLA_FLAG_W	0x08
98276788Sdelphij#define RLA_FLAG_N      0x10
99276788Sdelphij
100276788Sdelphij/* lsa_prefix options */
101276788Sdelphij#define LSA_PREFIX_OPT_NU 0x01
102276788Sdelphij#define LSA_PREFIX_OPT_LA 0x02
103276788Sdelphij#define LSA_PREFIX_OPT_MC 0x04
104276788Sdelphij#define LSA_PREFIX_OPT_P  0x08
105276788Sdelphij#define LSA_PREFIX_OPT_DN 0x10
106276788Sdelphij
107276788Sdelphij/* sla_tosmetric breakdown	*/
108276788Sdelphij#define	SLA_MASK_TOS		0x7f000000
109276788Sdelphij#define	SLA_MASK_METRIC		0x00ffffff
110276788Sdelphij#define SLA_SHIFT_TOS		24
111276788Sdelphij
112276788Sdelphij/* asla_metric */
113276788Sdelphij#define ASLA_FLAG_FWDADDR	0x02000000
114276788Sdelphij#define ASLA_FLAG_ROUTETAG	0x01000000
115276788Sdelphij#define	ASLA_MASK_METRIC	0x00ffffff
116276788Sdelphij
117276788Sdelphij/* RFC6506 Section 4.1 */
118276788Sdelphij#define OSPF6_AT_HDRLEN             16U
119276788Sdelphij#define OSPF6_AUTH_TYPE_HMAC        0x0001
120276788Sdelphij
121276788Sdelphijtypedef uint32_t rtrid_t;
122276788Sdelphij
123276788Sdelphij/* link state advertisement header */
124276788Sdelphijstruct lsa6_hdr {
125276788Sdelphij    uint16_t ls_age;
126276788Sdelphij    uint16_t ls_type;
127276788Sdelphij    rtrid_t ls_stateid;
128276788Sdelphij    rtrid_t ls_router;
129276788Sdelphij    uint32_t ls_seq;
130276788Sdelphij    uint16_t ls_chksum;
131276788Sdelphij    uint16_t ls_length;
132276788Sdelphij};
133276788Sdelphij
134276788Sdelphij/* Length of an IPv6 address, in bytes. */
135276788Sdelphij#define IPV6_ADDR_LEN_BYTES (128/8)
136276788Sdelphij
137276788Sdelphijstruct lsa6_prefix {
138276788Sdelphij    uint8_t lsa_p_len;
139276788Sdelphij    uint8_t lsa_p_opt;
140276788Sdelphij    uint16_t lsa_p_metric;
141276788Sdelphij    uint8_t lsa_p_prefix[IPV6_ADDR_LEN_BYTES]; /* maximum length */
142276788Sdelphij};
143276788Sdelphij
144276788Sdelphij/* link state advertisement */
145276788Sdelphijstruct lsa6 {
146276788Sdelphij    struct lsa6_hdr ls_hdr;
147276788Sdelphij
148276788Sdelphij    /* Link state types */
149276788Sdelphij    union {
150276788Sdelphij	/* Router links advertisements */
151276788Sdelphij	struct {
152276788Sdelphij	    union {
153276788Sdelphij		uint8_t flg;
154276788Sdelphij		uint32_t opt;
155276788Sdelphij	    } rla_flgandopt;
156276788Sdelphij#define rla_flags	rla_flgandopt.flg
157276788Sdelphij#define rla_options	rla_flgandopt.opt
158276788Sdelphij	    struct rlalink6 {
159276788Sdelphij		uint8_t link_type;
160276788Sdelphij		uint8_t link_zero[1];
161276788Sdelphij		uint16_t link_metric;
162276788Sdelphij		uint32_t link_ifid;
163276788Sdelphij		uint32_t link_nifid;
164276788Sdelphij		rtrid_t link_nrtid;
165276788Sdelphij	    } rla_link[1];		/* may repeat	*/
166276788Sdelphij	} un_rla;
167276788Sdelphij
168276788Sdelphij	/* Network links advertisements */
169276788Sdelphij	struct {
170276788Sdelphij	    uint32_t nla_options;
171276788Sdelphij	    rtrid_t nla_router[1];	/* may repeat	*/
172276788Sdelphij	} un_nla;
173276788Sdelphij
174276788Sdelphij	/* Inter Area Prefix LSA */
175276788Sdelphij	struct {
176276788Sdelphij	    uint32_t inter_ap_metric;
177276788Sdelphij	    struct lsa6_prefix inter_ap_prefix[1];
178276788Sdelphij	} un_inter_ap;
179276788Sdelphij
180276788Sdelphij	/* AS external links advertisements */
181276788Sdelphij	struct {
182276788Sdelphij	    uint32_t asla_metric;
183276788Sdelphij	    struct lsa6_prefix asla_prefix[1];
184276788Sdelphij	    /* some optional fields follow */
185276788Sdelphij	} un_asla;
186276788Sdelphij
187276788Sdelphij#if 0
188276788Sdelphij	/* Summary links advertisements */
189276788Sdelphij	struct {
190276788Sdelphij	    struct in_addr sla_mask;
191276788Sdelphij	    uint32_t sla_tosmetric[1];	/* may repeat	*/
192276788Sdelphij	} un_sla;
193276788Sdelphij
194276788Sdelphij	/* Multicast group membership */
195276788Sdelphij	struct mcla {
196276788Sdelphij	    uint32_t mcla_vtype;
197276788Sdelphij	    struct in_addr mcla_vid;
198276788Sdelphij	} un_mcla[1];
199276788Sdelphij#endif
200276788Sdelphij
201276788Sdelphij	/* Type 7 LSA */
202276788Sdelphij
203276788Sdelphij	/* Link LSA */
204276788Sdelphij	struct llsa {
205276788Sdelphij	    union {
206276788Sdelphij		uint8_t pri;
207276788Sdelphij		uint32_t opt;
208276788Sdelphij	    } llsa_priandopt;
209276788Sdelphij#define llsa_priority	llsa_priandopt.pri
210276788Sdelphij#define llsa_options	llsa_priandopt.opt
211276788Sdelphij	    struct in6_addr llsa_lladdr;
212276788Sdelphij	    uint32_t llsa_nprefix;
213276788Sdelphij	    struct lsa6_prefix llsa_prefix[1];
214276788Sdelphij	} un_llsa;
215276788Sdelphij
216276788Sdelphij	/* Intra-Area-Prefix */
217276788Sdelphij	struct {
218276788Sdelphij	    uint16_t intra_ap_nprefix;
219276788Sdelphij	    uint16_t intra_ap_lstype;
220276788Sdelphij	    rtrid_t intra_ap_lsid;
221276788Sdelphij	    rtrid_t intra_ap_rtid;
222276788Sdelphij	    struct lsa6_prefix intra_ap_prefix[1];
223276788Sdelphij	} un_intra_ap;
224276788Sdelphij    } lsa_un;
225276788Sdelphij};
226276788Sdelphij
227276788Sdelphij/*
228276788Sdelphij * the main header
229276788Sdelphij */
230276788Sdelphijstruct ospf6hdr {
231276788Sdelphij    uint8_t ospf6_version;
232276788Sdelphij    uint8_t ospf6_type;
233276788Sdelphij    uint16_t ospf6_len;
234276788Sdelphij    rtrid_t ospf6_routerid;
235276788Sdelphij    rtrid_t ospf6_areaid;
236276788Sdelphij    uint16_t ospf6_chksum;
237276788Sdelphij    uint8_t ospf6_instanceid;
238276788Sdelphij    uint8_t ospf6_rsvd;
239276788Sdelphij};
240276788Sdelphij
241276788Sdelphij/*
242276788Sdelphij * The OSPF6 header length is 16 bytes, regardless of how your compiler
243276788Sdelphij * might choose to pad the above structure.
244276788Sdelphij */
245276788Sdelphij#define OSPF6HDR_LEN    16
246276788Sdelphij
247276788Sdelphij/* Hello packet */
248276788Sdelphijstruct hello6 {
249276788Sdelphij    uint32_t hello_ifid;
250276788Sdelphij    union {
251276788Sdelphij	uint8_t pri;
252276788Sdelphij	uint32_t opt;
253276788Sdelphij    } hello_priandopt;
254276788Sdelphij#define hello_priority	hello_priandopt.pri
255276788Sdelphij#define hello_options	hello_priandopt.opt
256276788Sdelphij    uint16_t hello_helloint;
257276788Sdelphij    uint16_t hello_deadint;
258276788Sdelphij    rtrid_t hello_dr;
259276788Sdelphij    rtrid_t hello_bdr;
260276788Sdelphij    rtrid_t hello_neighbor[1]; /* may repeat	*/
261276788Sdelphij};
262276788Sdelphij
263276788Sdelphij/* Database Description packet */
264276788Sdelphijstruct dd6 {
265276788Sdelphij    uint32_t db_options;
266276788Sdelphij    uint16_t db_mtu;
267276788Sdelphij    uint8_t db_mbz;
268276788Sdelphij    uint8_t db_flags;
269276788Sdelphij    uint32_t db_seq;
270276788Sdelphij    struct lsa6_hdr db_lshdr[1]; /* may repeat	*/
271276788Sdelphij};
272276788Sdelphij
273276788Sdelphij/* Link State Request */
274276788Sdelphijstruct lsr6 {
275276788Sdelphij    uint16_t ls_mbz;
276276788Sdelphij    uint16_t ls_type;
277276788Sdelphij    rtrid_t ls_stateid;
278276788Sdelphij    rtrid_t ls_router;
279276788Sdelphij};
280276788Sdelphij
281276788Sdelphij/* Link State Update */
282276788Sdelphijstruct lsu6 {
283276788Sdelphij    uint32_t lsu_count;
284276788Sdelphij    struct lsa6 lsu_lsa[1]; /* may repeat	*/
285276788Sdelphij};
286276788Sdelphij
287276788Sdelphijstatic const char tstr[] = " [|ospf3]";
288276788Sdelphij
289190207Srpaulostatic const struct tok ospf6_option_values[] = {
290190207Srpaulo	{ OSPF6_OPTION_V6,	"V6" },
291190207Srpaulo	{ OSPF6_OPTION_E,	"External" },
292276788Sdelphij	{ OSPF6_OPTION_MC,	"Deprecated" },
293190207Srpaulo	{ OSPF6_OPTION_N,	"NSSA" },
294190207Srpaulo	{ OSPF6_OPTION_R,	"Router" },
295190207Srpaulo	{ OSPF6_OPTION_DC,	"Demand Circuit" },
296276788Sdelphij	{ OSPF6_OPTION_AF,	"AFs Support" },
297276788Sdelphij	{ OSPF6_OPTION_L,	"LLS" },
298276788Sdelphij	{ OSPF6_OPTION_AT,	"Authentication Trailer" },
299190207Srpaulo	{ 0,			NULL }
30056893Sfenner};
30156893Sfenner
302190207Srpaulostatic const struct tok ospf6_rla_flag_values[] = {
303190207Srpaulo	{ RLA_FLAG_B,		"ABR" },
304190207Srpaulo	{ RLA_FLAG_E,		"External" },
305190207Srpaulo	{ RLA_FLAG_V,		"Virtual-Link Endpoint" },
306190207Srpaulo	{ RLA_FLAG_W,		"Wildcard Receiver" },
307190207Srpaulo        { RLA_FLAG_N,           "NSSA Translator" },
30856893Sfenner	{ 0,			NULL }
30956893Sfenner};
31056893Sfenner
311190207Srpaulostatic const struct tok ospf6_asla_flag_values[] = {
312190207Srpaulo	{ ASLA_FLAG_EXTERNAL,	"External Type 2" },
313276788Sdelphij	{ ASLA_FLAG_FWDADDR,	"Forwarding" },
314190207Srpaulo	{ ASLA_FLAG_ROUTETAG,	"Tag" },
31556893Sfenner	{ 0,			NULL }
31656893Sfenner};
31756893Sfenner
318276788Sdelphijstatic const struct tok ospf6_type_values[] = {
319190207Srpaulo	{ OSPF_TYPE_HELLO,	"Hello" },
320190207Srpaulo	{ OSPF_TYPE_DD,		"Database Description" },
321190207Srpaulo	{ OSPF_TYPE_LS_REQ,	"LS-Request" },
322190207Srpaulo	{ OSPF_TYPE_LS_UPDATE,	"LS-Update" },
323190207Srpaulo	{ OSPF_TYPE_LS_ACK,	"LS-Ack" },
32475115Sfenner	{ 0,			NULL }
32575115Sfenner};
32675115Sfenner
327276788Sdelphijstatic const struct tok ospf6_lsa_values[] = {
328190207Srpaulo	{ LS_TYPE_ROUTER,       "Router" },
329190207Srpaulo	{ LS_TYPE_NETWORK,      "Network" },
330190207Srpaulo	{ LS_TYPE_INTER_AP,     "Inter-Area Prefix" },
331190207Srpaulo	{ LS_TYPE_INTER_AR,     "Inter-Area Router" },
332190207Srpaulo	{ LS_TYPE_ASE,          "External" },
333276788Sdelphij	{ LS_TYPE_GROUP,        "Deprecated" },
334190207Srpaulo	{ LS_TYPE_NSSA,         "NSSA" },
335190207Srpaulo	{ LS_TYPE_LINK,         "Link" },
336190207Srpaulo	{ LS_TYPE_INTRA_AP,     "Intra-Area Prefix" },
337190207Srpaulo        { LS_TYPE_INTRA_ATE,    "Intra-Area TE" },
338190207Srpaulo        { LS_TYPE_GRACE,        "Grace" },
339276788Sdelphij	{ LS_TYPE_RI,           "Router Information" },
340276788Sdelphij	{ LS_TYPE_INTER_ASTE,   "Inter-AS-TE" },
341276788Sdelphij	{ LS_TYPE_L1VPN,        "Layer 1 VPN" },
34256893Sfenner	{ 0,			NULL }
34356893Sfenner};
34456893Sfenner
345276788Sdelphijstatic const struct tok ospf6_ls_scope_values[] = {
346190207Srpaulo	{ LS_SCOPE_LINKLOCAL,   "Link Local" },
347190207Srpaulo	{ LS_SCOPE_AREA,        "Area Local" },
348190207Srpaulo	{ LS_SCOPE_AS,          "Domain Wide" },
349190207Srpaulo	{ 0,			NULL }
350190207Srpaulo};
35156893Sfenner
352276788Sdelphijstatic const struct tok ospf6_dd_flag_values[] = {
353190207Srpaulo	{ OSPF6_DB_INIT,	"Init" },
354190207Srpaulo	{ OSPF6_DB_MORE,	"More" },
355190207Srpaulo	{ OSPF6_DB_MASTER,	"Master" },
356276788Sdelphij	{ OSPF6_DB_M6,		"IPv6 MTU" },
357190207Srpaulo	{ 0,			NULL }
358190207Srpaulo};
359190207Srpaulo
360276788Sdelphijstatic const struct tok ospf6_lsa_prefix_option_values[] = {
361190207Srpaulo        { LSA_PREFIX_OPT_NU, "No Unicast" },
362190207Srpaulo        { LSA_PREFIX_OPT_LA, "Local address" },
363276788Sdelphij        { LSA_PREFIX_OPT_MC, "Deprecated" },
364190207Srpaulo        { LSA_PREFIX_OPT_P, "Propagate" },
365190207Srpaulo        { LSA_PREFIX_OPT_DN, "Down" },
366190207Srpaulo	{ 0, NULL }
367190207Srpaulo};
368190207Srpaulo
369276788Sdelphijstatic const struct tok ospf6_auth_type_str[] = {
370276788Sdelphij	{ OSPF6_AUTH_TYPE_HMAC,        "HMAC" },
371276788Sdelphij	{ 0, NULL }
372276788Sdelphij};
373190207Srpaulo
37456893Sfennerstatic void
375276788Sdelphijospf6_print_ls_type(netdissect_options *ndo,
376276788Sdelphij                    register u_int ls_type, register const rtrid_t *ls_stateid)
37756893Sfenner{
378276788Sdelphij        ND_PRINT((ndo, "\n\t    %s LSA (%d), %s Scope%s, LSA-ID %s",
379190207Srpaulo               tok2str(ospf6_lsa_values, "Unknown", ls_type & LS_TYPE_MASK),
380190207Srpaulo               ls_type & LS_TYPE_MASK,
381190207Srpaulo               tok2str(ospf6_ls_scope_values, "Unknown", ls_type & LS_SCOPE_MASK),
382190207Srpaulo               ls_type &0x8000 ? ", transitive" : "", /* U-bit */
383276788Sdelphij               ipaddr_string(ndo, ls_stateid)));
38456893Sfenner}
38556893Sfenner
38656893Sfennerstatic int
387276788Sdelphijospf6_print_lshdr(netdissect_options *ndo,
388276788Sdelphij                  register const struct lsa6_hdr *lshp, const u_char *dataend)
38956893Sfenner{
390313537Sglebius	if ((const u_char *)(lshp + 1) > dataend)
391276788Sdelphij		goto trunc;
392356341Scy	ND_TCHECK(lshp->ls_length);	/* last field of struct lsa6_hdr */
39356893Sfenner
394276788Sdelphij	ND_PRINT((ndo, "\n\t  Advertising Router %s, seq 0x%08x, age %us, length %u",
395276788Sdelphij               ipaddr_string(ndo, &lshp->ls_router),
396190207Srpaulo               EXTRACT_32BITS(&lshp->ls_seq),
397190207Srpaulo               EXTRACT_16BITS(&lshp->ls_age),
398276788Sdelphij               EXTRACT_16BITS(&lshp->ls_length)-(u_int)sizeof(struct lsa6_hdr)));
399190207Srpaulo
400276788Sdelphij	ospf6_print_ls_type(ndo, EXTRACT_16BITS(&lshp->ls_type), &lshp->ls_stateid);
401190207Srpaulo
40256893Sfenner	return (0);
40356893Sfennertrunc:
40456893Sfenner	return (1);
40556893Sfenner}
40656893Sfenner
40756893Sfennerstatic int
408276788Sdelphijospf6_print_lsaprefix(netdissect_options *ndo,
409276788Sdelphij                      const uint8_t *tptr, u_int lsa_length)
41056893Sfenner{
411313537Sglebius	const struct lsa6_prefix *lsapp = (const struct lsa6_prefix *)tptr;
412190207Srpaulo	u_int wordlen;
41356893Sfenner	struct in6_addr prefix;
41456893Sfenner
415276788Sdelphij	if (lsa_length < sizeof (*lsapp) - IPV6_ADDR_LEN_BYTES)
416241235Sdelphij		goto trunc;
417276788Sdelphij	lsa_length -= sizeof (*lsapp) - IPV6_ADDR_LEN_BYTES;
418276788Sdelphij	ND_TCHECK2(*lsapp, sizeof (*lsapp) - IPV6_ADDR_LEN_BYTES);
419190207Srpaulo	wordlen = (lsapp->lsa_p_len + 31) / 32;
420190207Srpaulo	if (wordlen * 4 > sizeof(struct in6_addr)) {
421276788Sdelphij		ND_PRINT((ndo, " bogus prefixlen /%d", lsapp->lsa_p_len));
42256893Sfenner		goto trunc;
42356893Sfenner	}
424241235Sdelphij	if (lsa_length < wordlen * 4)
425241235Sdelphij		goto trunc;
426241235Sdelphij	lsa_length -= wordlen * 4;
427276788Sdelphij	ND_TCHECK2(lsapp->lsa_p_prefix, wordlen * 4);
42856893Sfenner	memset(&prefix, 0, sizeof(prefix));
429190207Srpaulo	memcpy(&prefix, lsapp->lsa_p_prefix, wordlen * 4);
430276788Sdelphij	ND_PRINT((ndo, "\n\t\t%s/%d", ip6addr_string(ndo, &prefix),
431276788Sdelphij		lsapp->lsa_p_len));
432190207Srpaulo        if (lsapp->lsa_p_opt) {
433276788Sdelphij            ND_PRINT((ndo, ", Options [%s]",
434190207Srpaulo                   bittok2str(ospf6_lsa_prefix_option_values,
435276788Sdelphij                              "none", lsapp->lsa_p_opt)));
436190207Srpaulo        }
437276788Sdelphij        ND_PRINT((ndo, ", metric %u", EXTRACT_16BITS(&lsapp->lsa_p_metric)));
438276788Sdelphij	return sizeof(*lsapp) - IPV6_ADDR_LEN_BYTES + wordlen * 4;
43956893Sfenner
44056893Sfennertrunc:
44156893Sfenner	return -1;
44256893Sfenner}
44356893Sfenner
44456893Sfenner
44556893Sfenner/*
44656893Sfenner * Print a single link state advertisement.  If truncated return 1, else 0.
44756893Sfenner */
44856893Sfennerstatic int
449276788Sdelphijospf6_print_lsa(netdissect_options *ndo,
450276788Sdelphij                register const struct lsa6 *lsap, const u_char *dataend)
45156893Sfenner{
452190207Srpaulo	register const struct rlalink6 *rlp;
45356893Sfenner#if 0
45456893Sfenner	register const struct tos_metric *tosp;
45556893Sfenner#endif
45656893Sfenner	register const rtrid_t *ap;
45756893Sfenner#if 0
45856893Sfenner	register const struct aslametric *almp;
45956893Sfenner	register const struct mcla *mcp;
46056893Sfenner#endif
46156893Sfenner	register const struct llsa *llsap;
462190207Srpaulo	register const struct lsa6_prefix *lsapp;
46356893Sfenner#if 0
464276788Sdelphij	register const uint32_t *lp;
46556893Sfenner#endif
466190207Srpaulo	register u_int prefixes;
467241235Sdelphij	register int bytelen;
468241235Sdelphij	register u_int length, lsa_length;
469276788Sdelphij	uint32_t flags32;
470276788Sdelphij	const uint8_t *tptr;
47156893Sfenner
472276788Sdelphij	if (ospf6_print_lshdr(ndo, &lsap->ls_hdr, dataend))
47356893Sfenner		return (1);
474276788Sdelphij	ND_TCHECK(lsap->ls_hdr.ls_length);
475190207Srpaulo        length = EXTRACT_16BITS(&lsap->ls_hdr.ls_length);
476241235Sdelphij
477241235Sdelphij	/*
478241235Sdelphij	 * The LSA length includes the length of the header;
479241235Sdelphij	 * it must have a value that's at least that length.
480241235Sdelphij	 * If it does, find the length of what follows the
481241235Sdelphij	 * header.
482241235Sdelphij	 */
483313537Sglebius        if (length < sizeof(struct lsa6_hdr) || (const u_char *)lsap + length > dataend)
484241235Sdelphij        	return (1);
485190207Srpaulo        lsa_length = length - sizeof(struct lsa6_hdr);
486313537Sglebius        tptr = (const uint8_t *)lsap+sizeof(struct lsa6_hdr);
487190207Srpaulo
488127668Sbms	switch (EXTRACT_16BITS(&lsap->ls_hdr.ls_type)) {
48956893Sfenner	case LS_TYPE_ROUTER | LS_SCOPE_AREA:
490241235Sdelphij		if (lsa_length < sizeof (lsap->lsa_un.un_rla.rla_options))
491241235Sdelphij			return (1);
492241235Sdelphij		lsa_length -= sizeof (lsap->lsa_un.un_rla.rla_options);
493276788Sdelphij		ND_TCHECK(lsap->lsa_un.un_rla.rla_options);
494276788Sdelphij		ND_PRINT((ndo, "\n\t      Options [%s]",
495276788Sdelphij		          bittok2str(ospf6_option_values, "none",
496276788Sdelphij		          EXTRACT_32BITS(&lsap->lsa_un.un_rla.rla_options))));
497276788Sdelphij		ND_PRINT((ndo, ", RLA-Flags [%s]",
498276788Sdelphij		          bittok2str(ospf6_rla_flag_values, "none",
499276788Sdelphij		          lsap->lsa_un.un_rla.rla_flags)));
500190207Srpaulo
50156893Sfenner		rlp = lsap->lsa_un.un_rla.rla_link;
502241235Sdelphij		while (lsa_length != 0) {
503241235Sdelphij			if (lsa_length < sizeof (*rlp))
504241235Sdelphij				return (1);
505241235Sdelphij			lsa_length -= sizeof (*rlp);
506276788Sdelphij			ND_TCHECK(*rlp);
50756893Sfenner			switch (rlp->link_type) {
50856893Sfenner
50956893Sfenner			case RLA_TYPE_VIRTUAL:
510276788Sdelphij				ND_PRINT((ndo, "\n\t      Virtual Link: Neighbor Router-ID %s"
511190207Srpaulo                                       "\n\t      Neighbor Interface-ID %s, Interface %s",
512276788Sdelphij                                       ipaddr_string(ndo, &rlp->link_nrtid),
513276788Sdelphij                                       ipaddr_string(ndo, &rlp->link_nifid),
514276788Sdelphij                                       ipaddr_string(ndo, &rlp->link_ifid)));
515190207Srpaulo                                break;
51656893Sfenner
51756893Sfenner			case RLA_TYPE_ROUTER:
518276788Sdelphij				ND_PRINT((ndo, "\n\t      Neighbor Router-ID %s"
519190207Srpaulo                                       "\n\t      Neighbor Interface-ID %s, Interface %s",
520276788Sdelphij                                       ipaddr_string(ndo, &rlp->link_nrtid),
521276788Sdelphij                                       ipaddr_string(ndo, &rlp->link_nifid),
522276788Sdelphij                                       ipaddr_string(ndo, &rlp->link_ifid)));
52356893Sfenner				break;
52456893Sfenner
52556893Sfenner			case RLA_TYPE_TRANSIT:
526276788Sdelphij				ND_PRINT((ndo, "\n\t      Neighbor Network-ID %s"
527190207Srpaulo                                       "\n\t      Neighbor Interface-ID %s, Interface %s",
528276788Sdelphij				    ipaddr_string(ndo, &rlp->link_nrtid),
529276788Sdelphij				    ipaddr_string(ndo, &rlp->link_nifid),
530276788Sdelphij				    ipaddr_string(ndo, &rlp->link_ifid)));
53156893Sfenner				break;
53256893Sfenner
53356893Sfenner			default:
534276788Sdelphij				ND_PRINT((ndo, "\n\t      Unknown Router Links Type 0x%02x",
535276788Sdelphij				    rlp->link_type));
53656893Sfenner				return (0);
53756893Sfenner			}
538276788Sdelphij			ND_PRINT((ndo, ", metric %d", EXTRACT_16BITS(&rlp->link_metric)));
53956893Sfenner			rlp++;
54056893Sfenner		}
54156893Sfenner		break;
54256893Sfenner
54356893Sfenner	case LS_TYPE_NETWORK | LS_SCOPE_AREA:
544241235Sdelphij		if (lsa_length < sizeof (lsap->lsa_un.un_nla.nla_options))
545241235Sdelphij			return (1);
546241235Sdelphij		lsa_length -= sizeof (lsap->lsa_un.un_nla.nla_options);
547276788Sdelphij		ND_TCHECK(lsap->lsa_un.un_nla.nla_options);
548276788Sdelphij		ND_PRINT((ndo, "\n\t      Options [%s]",
549276788Sdelphij		          bittok2str(ospf6_option_values, "none",
550276788Sdelphij		          EXTRACT_32BITS(&lsap->lsa_un.un_nla.nla_options))));
551241235Sdelphij
552276788Sdelphij		ND_PRINT((ndo, "\n\t      Connected Routers:"));
55356893Sfenner		ap = lsap->lsa_un.un_nla.nla_router;
554241235Sdelphij		while (lsa_length != 0) {
555241235Sdelphij			if (lsa_length < sizeof (*ap))
556241235Sdelphij				return (1);
557241235Sdelphij			lsa_length -= sizeof (*ap);
558276788Sdelphij			ND_TCHECK(*ap);
559276788Sdelphij			ND_PRINT((ndo, "\n\t\t%s", ipaddr_string(ndo, ap)));
56056893Sfenner			++ap;
56156893Sfenner		}
56256893Sfenner		break;
56356893Sfenner
56456893Sfenner	case LS_TYPE_INTER_AP | LS_SCOPE_AREA:
565241235Sdelphij		if (lsa_length < sizeof (lsap->lsa_un.un_inter_ap.inter_ap_metric))
566241235Sdelphij			return (1);
567241235Sdelphij		lsa_length -= sizeof (lsap->lsa_un.un_inter_ap.inter_ap_metric);
568276788Sdelphij		ND_TCHECK(lsap->lsa_un.un_inter_ap.inter_ap_metric);
569276788Sdelphij		ND_PRINT((ndo, ", metric %u",
570276788Sdelphij			EXTRACT_32BITS(&lsap->lsa_un.un_inter_ap.inter_ap_metric) & SLA_MASK_METRIC));
571241235Sdelphij
572313537Sglebius		tptr = (const uint8_t *)lsap->lsa_un.un_inter_ap.inter_ap_prefix;
573241235Sdelphij		while (lsa_length != 0) {
574276788Sdelphij			bytelen = ospf6_print_lsaprefix(ndo, tptr, lsa_length);
575241235Sdelphij			if (bytelen < 0)
57656893Sfenner				goto trunc;
577241235Sdelphij			lsa_length -= bytelen;
578241235Sdelphij			tptr += bytelen;
57956893Sfenner		}
58056893Sfenner		break;
581241235Sdelphij
582241235Sdelphij	case LS_TYPE_ASE | LS_SCOPE_AS:
583241235Sdelphij		if (lsa_length < sizeof (lsap->lsa_un.un_asla.asla_metric))
584241235Sdelphij			return (1);
585241235Sdelphij		lsa_length -= sizeof (lsap->lsa_un.un_asla.asla_metric);
586276788Sdelphij		ND_TCHECK(lsap->lsa_un.un_asla.asla_metric);
587127668Sbms		flags32 = EXTRACT_32BITS(&lsap->lsa_un.un_asla.asla_metric);
588276788Sdelphij		ND_PRINT((ndo, "\n\t     Flags [%s]",
589276788Sdelphij		          bittok2str(ospf6_asla_flag_values, "none", flags32)));
590276788Sdelphij		ND_PRINT((ndo, " metric %u",
591127668Sbms		       EXTRACT_32BITS(&lsap->lsa_un.un_asla.asla_metric) &
592276788Sdelphij		       ASLA_MASK_METRIC));
593241235Sdelphij
594313537Sglebius		tptr = (const uint8_t *)lsap->lsa_un.un_asla.asla_prefix;
595313537Sglebius		lsapp = (const struct lsa6_prefix *)tptr;
596276788Sdelphij		bytelen = ospf6_print_lsaprefix(ndo, tptr, lsa_length);
597190207Srpaulo		if (bytelen < 0)
59875115Sfenner			goto trunc;
599241235Sdelphij		lsa_length -= bytelen;
600241235Sdelphij		tptr += bytelen;
601241235Sdelphij
602241235Sdelphij		if ((flags32 & ASLA_FLAG_FWDADDR) != 0) {
603313537Sglebius			const struct in6_addr *fwdaddr6;
60456893Sfenner
605313537Sglebius			fwdaddr6 = (const struct in6_addr *)tptr;
606241235Sdelphij			if (lsa_length < sizeof (*fwdaddr6))
607241235Sdelphij				return (1);
608241235Sdelphij			lsa_length -= sizeof (*fwdaddr6);
609276788Sdelphij			ND_TCHECK(*fwdaddr6);
610276788Sdelphij			ND_PRINT((ndo, " forward %s",
611276788Sdelphij			       ip6addr_string(ndo, fwdaddr6)));
612241235Sdelphij			tptr += sizeof(*fwdaddr6);
613241235Sdelphij		}
61475115Sfenner
615241235Sdelphij		if ((flags32 & ASLA_FLAG_ROUTETAG) != 0) {
616276788Sdelphij			if (lsa_length < sizeof (uint32_t))
617241235Sdelphij				return (1);
618276788Sdelphij			lsa_length -= sizeof (uint32_t);
619313537Sglebius			ND_TCHECK(*(const uint32_t *)tptr);
620276788Sdelphij			ND_PRINT((ndo, " tag %s",
621313537Sglebius			       ipaddr_string(ndo, (const uint32_t *)tptr)));
622276788Sdelphij			tptr += sizeof(uint32_t);
623241235Sdelphij		}
62475115Sfenner
625241235Sdelphij		if (lsapp->lsa_p_metric) {
626276788Sdelphij			if (lsa_length < sizeof (uint32_t))
627241235Sdelphij				return (1);
628276788Sdelphij			lsa_length -= sizeof (uint32_t);
629313537Sglebius			ND_TCHECK(*(const uint32_t *)tptr);
630276788Sdelphij			ND_PRINT((ndo, " RefLSID: %s",
631313537Sglebius			       ipaddr_string(ndo, (const uint32_t *)tptr)));
632276788Sdelphij			tptr += sizeof(uint32_t);
63375115Sfenner		}
63475115Sfenner		break;
63556893Sfenner
63656893Sfenner	case LS_TYPE_LINK:
63756893Sfenner		/* Link LSA */
63856893Sfenner		llsap = &lsap->lsa_un.un_llsa;
639241235Sdelphij		if (lsa_length < sizeof (llsap->llsa_priandopt))
640241235Sdelphij			return (1);
641241235Sdelphij		lsa_length -= sizeof (llsap->llsa_priandopt);
642276788Sdelphij		ND_TCHECK(llsap->llsa_priandopt);
643276788Sdelphij		ND_PRINT((ndo, "\n\t      Options [%s]",
644276788Sdelphij		          bittok2str(ospf6_option_values, "none",
645276788Sdelphij		          EXTRACT_32BITS(&llsap->llsa_options))));
646241235Sdelphij
647241235Sdelphij		if (lsa_length < sizeof (llsap->llsa_lladdr) + sizeof (llsap->llsa_nprefix))
648241235Sdelphij			return (1);
649241235Sdelphij		lsa_length -= sizeof (llsap->llsa_lladdr) + sizeof (llsap->llsa_nprefix);
650327234Semaste                ND_TCHECK(llsap->llsa_nprefix);
651190207Srpaulo                prefixes = EXTRACT_32BITS(&llsap->llsa_nprefix);
652276788Sdelphij		ND_PRINT((ndo, "\n\t      Priority %d, Link-local address %s, Prefixes %d:",
653190207Srpaulo                       llsap->llsa_priority,
654276788Sdelphij                       ip6addr_string(ndo, &llsap->llsa_lladdr),
655276788Sdelphij                       prefixes));
656190207Srpaulo
657313537Sglebius		tptr = (const uint8_t *)llsap->llsa_prefix;
658241235Sdelphij		while (prefixes > 0) {
659276788Sdelphij			bytelen = ospf6_print_lsaprefix(ndo, tptr, lsa_length);
660241235Sdelphij			if (bytelen < 0)
661241235Sdelphij				goto trunc;
662241235Sdelphij			prefixes--;
663241235Sdelphij			lsa_length -= bytelen;
664241235Sdelphij			tptr += bytelen;
665241235Sdelphij		}
66656893Sfenner		break;
66756893Sfenner
66856893Sfenner	case LS_TYPE_INTRA_AP | LS_SCOPE_AREA:
66956893Sfenner		/* Intra-Area-Prefix LSA */
670241235Sdelphij		if (lsa_length < sizeof (lsap->lsa_un.un_intra_ap.intra_ap_rtid))
671241235Sdelphij			return (1);
672241235Sdelphij		lsa_length -= sizeof (lsap->lsa_un.un_intra_ap.intra_ap_rtid);
673276788Sdelphij		ND_TCHECK(lsap->lsa_un.un_intra_ap.intra_ap_rtid);
674276788Sdelphij		ospf6_print_ls_type(ndo,
675127668Sbms			EXTRACT_16BITS(&lsap->lsa_un.un_intra_ap.intra_ap_lstype),
676190207Srpaulo			&lsap->lsa_un.un_intra_ap.intra_ap_lsid);
677241235Sdelphij
678241235Sdelphij		if (lsa_length < sizeof (lsap->lsa_un.un_intra_ap.intra_ap_nprefix))
679241235Sdelphij			return (1);
680241235Sdelphij		lsa_length -= sizeof (lsap->lsa_un.un_intra_ap.intra_ap_nprefix);
681276788Sdelphij		ND_TCHECK(lsap->lsa_un.un_intra_ap.intra_ap_nprefix);
682190207Srpaulo                prefixes = EXTRACT_16BITS(&lsap->lsa_un.un_intra_ap.intra_ap_nprefix);
683276788Sdelphij		ND_PRINT((ndo, "\n\t      Prefixes %d:", prefixes));
68456893Sfenner
685313537Sglebius		tptr = (const uint8_t *)lsap->lsa_un.un_intra_ap.intra_ap_prefix;
686241235Sdelphij		while (prefixes > 0) {
687276788Sdelphij			bytelen = ospf6_print_lsaprefix(ndo, tptr, lsa_length);
688241235Sdelphij			if (bytelen < 0)
689241235Sdelphij				goto trunc;
690241235Sdelphij			prefixes--;
691241235Sdelphij			lsa_length -= bytelen;
692241235Sdelphij			tptr += bytelen;
693241235Sdelphij		}
69456893Sfenner		break;
69556893Sfenner
696190207Srpaulo        case LS_TYPE_GRACE | LS_SCOPE_LINKLOCAL:
697276788Sdelphij                if (ospf_print_grace_lsa(ndo, tptr, lsa_length) == -1) {
698190207Srpaulo                    return 1;
699190207Srpaulo                }
700241235Sdelphij                break;
701190207Srpaulo
702190207Srpaulo        case LS_TYPE_INTRA_ATE | LS_SCOPE_LINKLOCAL:
703276788Sdelphij                if (ospf_print_te_lsa(ndo, tptr, lsa_length) == -1) {
704241235Sdelphij                    return 1;
705241235Sdelphij                }
706241235Sdelphij                break;
707190207Srpaulo
70856893Sfenner	default:
709276788Sdelphij                if(!print_unknown_data(ndo,tptr,
710241235Sdelphij                                       "\n\t      ",
711241235Sdelphij                                       lsa_length)) {
712241235Sdelphij                    return (1);
713241235Sdelphij                }
714241235Sdelphij                break;
71556893Sfenner	}
71656893Sfenner
71756893Sfenner	return (0);
71856893Sfennertrunc:
71956893Sfenner	return (1);
72056893Sfenner}
72156893Sfenner
72256893Sfennerstatic int
723276788Sdelphijospf6_decode_v3(netdissect_options *ndo,
724276788Sdelphij                register const struct ospf6hdr *op,
725276788Sdelphij                register const u_char *dataend)
72656893Sfenner{
72756893Sfenner	register const rtrid_t *ap;
728190207Srpaulo	register const struct lsr6 *lsrp;
729190207Srpaulo	register const struct lsa6_hdr *lshp;
730190207Srpaulo	register const struct lsa6 *lsap;
73156893Sfenner	register int i;
73256893Sfenner
73356893Sfenner	switch (op->ospf6_type) {
73456893Sfenner
735276788Sdelphij	case OSPF_TYPE_HELLO: {
736313537Sglebius		register const struct hello6 *hellop = (const struct hello6 *)((const uint8_t *)op + OSPF6HDR_LEN);
73756893Sfenner
738327234Semaste		ND_TCHECK_32BITS(&hellop->hello_options);
739276788Sdelphij		ND_PRINT((ndo, "\n\tOptions [%s]",
740276788Sdelphij		          bittok2str(ospf6_option_values, "none",
741276788Sdelphij		          EXTRACT_32BITS(&hellop->hello_options))));
742190207Srpaulo
743276788Sdelphij		ND_TCHECK(hellop->hello_deadint);
744276788Sdelphij		ND_PRINT((ndo, "\n\t  Hello Timer %us, Dead Timer %us, Interface-ID %s, Priority %u",
745276788Sdelphij		          EXTRACT_16BITS(&hellop->hello_helloint),
746276788Sdelphij		          EXTRACT_16BITS(&hellop->hello_deadint),
747276788Sdelphij		          ipaddr_string(ndo, &hellop->hello_ifid),
748276788Sdelphij		          hellop->hello_priority));
749276788Sdelphij
750276788Sdelphij		ND_TCHECK(hellop->hello_dr);
751276788Sdelphij		if (EXTRACT_32BITS(&hellop->hello_dr) != 0)
752276788Sdelphij			ND_PRINT((ndo, "\n\t  Designated Router %s",
753276788Sdelphij			    ipaddr_string(ndo, &hellop->hello_dr)));
754276788Sdelphij		ND_TCHECK(hellop->hello_bdr);
755276788Sdelphij		if (EXTRACT_32BITS(&hellop->hello_bdr) != 0)
756276788Sdelphij			ND_PRINT((ndo, ", Backup Designated Router %s",
757276788Sdelphij			    ipaddr_string(ndo, &hellop->hello_bdr)));
758276788Sdelphij		if (ndo->ndo_vflag > 1) {
759276788Sdelphij			ND_PRINT((ndo, "\n\t  Neighbor List:"));
760276788Sdelphij			ap = hellop->hello_neighbor;
761313537Sglebius			while ((const u_char *)ap < dataend) {
762276788Sdelphij				ND_TCHECK(*ap);
763276788Sdelphij				ND_PRINT((ndo, "\n\t    %s", ipaddr_string(ndo, ap)));
76456893Sfenner				++ap;
76556893Sfenner			}
76656893Sfenner		}
76756893Sfenner		break;	/* HELLO */
768276788Sdelphij	}
76956893Sfenner
770276788Sdelphij	case OSPF_TYPE_DD: {
771313537Sglebius		register const struct dd6 *ddp = (const struct dd6 *)((const uint8_t *)op + OSPF6HDR_LEN);
772190207Srpaulo
773276788Sdelphij		ND_TCHECK(ddp->db_options);
774276788Sdelphij		ND_PRINT((ndo, "\n\tOptions [%s]",
775276788Sdelphij		          bittok2str(ospf6_option_values, "none",
776276788Sdelphij		          EXTRACT_32BITS(&ddp->db_options))));
777276788Sdelphij		ND_TCHECK(ddp->db_flags);
778276788Sdelphij		ND_PRINT((ndo, ", DD Flags [%s]",
779276788Sdelphij		          bittok2str(ospf6_dd_flag_values,"none",ddp->db_flags)));
78056893Sfenner
781276788Sdelphij		ND_TCHECK(ddp->db_seq);
782276788Sdelphij		ND_PRINT((ndo, ", MTU %u, DD-Sequence 0x%08x",
783276788Sdelphij                       EXTRACT_16BITS(&ddp->db_mtu),
784276788Sdelphij                       EXTRACT_32BITS(&ddp->db_seq)));
785276788Sdelphij		if (ndo->ndo_vflag > 1) {
786276788Sdelphij			/* Print all the LS adv's */
787276788Sdelphij			lshp = ddp->db_lshdr;
788313537Sglebius			while ((const u_char *)lshp < dataend) {
789276788Sdelphij				if (ospf6_print_lshdr(ndo, lshp++, dataend))
790276788Sdelphij					goto trunc;
791276788Sdelphij			}
792276788Sdelphij		}
79356893Sfenner		break;
794276788Sdelphij	}
79556893Sfenner
796190207Srpaulo	case OSPF_TYPE_LS_REQ:
797276788Sdelphij		if (ndo->ndo_vflag > 1) {
798313537Sglebius			lsrp = (const struct lsr6 *)((const uint8_t *)op + OSPF6HDR_LEN);
799313537Sglebius			while ((const u_char *)lsrp < dataend) {
800276788Sdelphij				ND_TCHECK(*lsrp);
801276788Sdelphij				ND_PRINT((ndo, "\n\t  Advertising Router %s",
802276788Sdelphij				          ipaddr_string(ndo, &lsrp->ls_router)));
803276788Sdelphij				ospf6_print_ls_type(ndo, EXTRACT_16BITS(&lsrp->ls_type),
804190207Srpaulo                                                    &lsrp->ls_stateid);
80556893Sfenner				++lsrp;
80656893Sfenner			}
80756893Sfenner		}
80856893Sfenner		break;
80956893Sfenner
810190207Srpaulo	case OSPF_TYPE_LS_UPDATE:
811276788Sdelphij		if (ndo->ndo_vflag > 1) {
812313537Sglebius			register const struct lsu6 *lsup = (const struct lsu6 *)((const uint8_t *)op + OSPF6HDR_LEN);
813276788Sdelphij
814276788Sdelphij			ND_TCHECK(lsup->lsu_count);
815276788Sdelphij			i = EXTRACT_32BITS(&lsup->lsu_count);
816276788Sdelphij			lsap = lsup->lsu_lsa;
817313537Sglebius			while ((const u_char *)lsap < dataend && i--) {
818276788Sdelphij				if (ospf6_print_lsa(ndo, lsap, dataend))
81956893Sfenner					goto trunc;
820313537Sglebius				lsap = (const struct lsa6 *)((const u_char *)lsap +
821127668Sbms				    EXTRACT_16BITS(&lsap->ls_hdr.ls_length));
82256893Sfenner			}
82356893Sfenner		}
82456893Sfenner		break;
82556893Sfenner
826190207Srpaulo	case OSPF_TYPE_LS_ACK:
827276788Sdelphij		if (ndo->ndo_vflag > 1) {
828313537Sglebius			lshp = (const struct lsa6_hdr *)((const uint8_t *)op + OSPF6HDR_LEN);
829313537Sglebius			while ((const u_char *)lshp < dataend) {
830276788Sdelphij				if (ospf6_print_lshdr(ndo, lshp++, dataend))
831276788Sdelphij					goto trunc;
83256893Sfenner			}
83356893Sfenner		}
83456893Sfenner		break;
83556893Sfenner
83656893Sfenner	default:
83756893Sfenner		break;
83856893Sfenner	}
83956893Sfenner	return (0);
84056893Sfennertrunc:
84156893Sfenner	return (1);
84256893Sfenner}
84356893Sfenner
844276788Sdelphij/* RFC5613 Section 2.2 (w/o the TLVs) */
845276788Sdelphijstatic int
846276788Sdelphijospf6_print_lls(netdissect_options *ndo,
847276788Sdelphij                const u_char *cp, const u_int len)
848276788Sdelphij{
849276788Sdelphij	uint16_t llsdatalen;
850276788Sdelphij
851276788Sdelphij	if (len == 0)
852276788Sdelphij		return 0;
853276788Sdelphij	if (len < OSPF_LLS_HDRLEN)
854276788Sdelphij		goto trunc;
855276788Sdelphij	/* Checksum */
856276788Sdelphij	ND_TCHECK2(*cp, 2);
857276788Sdelphij	ND_PRINT((ndo, "\n\tLLS Checksum 0x%04x", EXTRACT_16BITS(cp)));
858276788Sdelphij	cp += 2;
859276788Sdelphij	/* LLS Data Length */
860276788Sdelphij	ND_TCHECK2(*cp, 2);
861276788Sdelphij	llsdatalen = EXTRACT_16BITS(cp);
862276788Sdelphij	ND_PRINT((ndo, ", Data Length %u", llsdatalen));
863276788Sdelphij	if (llsdatalen < OSPF_LLS_HDRLEN || llsdatalen > len)
864276788Sdelphij		goto trunc;
865276788Sdelphij	cp += 2;
866276788Sdelphij	/* LLS TLVs */
867276788Sdelphij	ND_TCHECK2(*cp, llsdatalen - OSPF_LLS_HDRLEN);
868276788Sdelphij	/* FIXME: code in print-ospf.c can be reused to decode the TLVs */
869276788Sdelphij
870276788Sdelphij	return llsdatalen;
871276788Sdelphijtrunc:
872276788Sdelphij	return -1;
873276788Sdelphij}
874276788Sdelphij
875276788Sdelphij/* RFC6506 Section 4.1 */
876276788Sdelphijstatic int
877276788Sdelphijospf6_decode_at(netdissect_options *ndo,
878276788Sdelphij                const u_char *cp, const u_int len)
879276788Sdelphij{
880276788Sdelphij	uint16_t authdatalen;
881276788Sdelphij
882276788Sdelphij	if (len == 0)
883276788Sdelphij		return 0;
884276788Sdelphij	if (len < OSPF6_AT_HDRLEN)
885276788Sdelphij		goto trunc;
886276788Sdelphij	/* Authentication Type */
887276788Sdelphij	ND_TCHECK2(*cp, 2);
888276788Sdelphij	ND_PRINT((ndo, "\n\tAuthentication Type %s", tok2str(ospf6_auth_type_str, "unknown (0x%04x)", EXTRACT_16BITS(cp))));
889276788Sdelphij	cp += 2;
890276788Sdelphij	/* Auth Data Len */
891276788Sdelphij	ND_TCHECK2(*cp, 2);
892276788Sdelphij	authdatalen = EXTRACT_16BITS(cp);
893276788Sdelphij	ND_PRINT((ndo, ", Length %u", authdatalen));
894276788Sdelphij	if (authdatalen < OSPF6_AT_HDRLEN || authdatalen > len)
895276788Sdelphij		goto trunc;
896276788Sdelphij	cp += 2;
897276788Sdelphij	/* Reserved */
898276788Sdelphij	ND_TCHECK2(*cp, 2);
899276788Sdelphij	cp += 2;
900276788Sdelphij	/* Security Association ID */
901276788Sdelphij	ND_TCHECK2(*cp, 2);
902276788Sdelphij	ND_PRINT((ndo, ", SAID %u", EXTRACT_16BITS(cp)));
903276788Sdelphij	cp += 2;
904276788Sdelphij	/* Cryptographic Sequence Number (High-Order 32 Bits) */
905276788Sdelphij	ND_TCHECK2(*cp, 4);
906276788Sdelphij	ND_PRINT((ndo, ", CSN 0x%08x", EXTRACT_32BITS(cp)));
907276788Sdelphij	cp += 4;
908276788Sdelphij	/* Cryptographic Sequence Number (Low-Order 32 Bits) */
909276788Sdelphij	ND_TCHECK2(*cp, 4);
910276788Sdelphij	ND_PRINT((ndo, ":%08x", EXTRACT_32BITS(cp)));
911276788Sdelphij	cp += 4;
912276788Sdelphij	/* Authentication Data */
913276788Sdelphij	ND_TCHECK2(*cp, authdatalen - OSPF6_AT_HDRLEN);
914276788Sdelphij	if (ndo->ndo_vflag > 1)
915276788Sdelphij		print_unknown_data(ndo,cp, "\n\tAuthentication Data ", authdatalen - OSPF6_AT_HDRLEN);
916276788Sdelphij	return 0;
917276788Sdelphij
918276788Sdelphijtrunc:
919276788Sdelphij	return 1;
920276788Sdelphij}
921276788Sdelphij
922276788Sdelphij/* The trailing data may include LLS and/or AT data (in this specific order).
923276788Sdelphij * LLS data may be present only in Hello and DBDesc packets with the L-bit set.
924276788Sdelphij * AT data may be present in Hello and DBDesc packets with the AT-bit set or in
925276788Sdelphij * any other packet type, thus decode the AT data regardless of the AT-bit.
926276788Sdelphij */
927276788Sdelphijstatic int
928276788Sdelphijospf6_decode_v3_trailer(netdissect_options *ndo,
929276788Sdelphij                        const struct ospf6hdr *op, const u_char *cp, const unsigned len)
930276788Sdelphij{
931276788Sdelphij	int llslen = 0;
932276788Sdelphij	int lls_hello = 0;
933276788Sdelphij	int lls_dd = 0;
934276788Sdelphij
935276788Sdelphij	if (op->ospf6_type == OSPF_TYPE_HELLO) {
936313537Sglebius		const struct hello6 *hellop = (const struct hello6 *)((const uint8_t *)op + OSPF6HDR_LEN);
937327234Semaste		ND_TCHECK(hellop->hello_options);
938276788Sdelphij		if (EXTRACT_32BITS(&hellop->hello_options) & OSPF6_OPTION_L)
939276788Sdelphij			lls_hello = 1;
940276788Sdelphij	} else if (op->ospf6_type == OSPF_TYPE_DD) {
941313537Sglebius		const struct dd6 *ddp = (const struct dd6 *)((const uint8_t *)op + OSPF6HDR_LEN);
942327234Semaste		ND_TCHECK(ddp->db_options);
943276788Sdelphij		if (EXTRACT_32BITS(&ddp->db_options) & OSPF6_OPTION_L)
944276788Sdelphij			lls_dd = 1;
945276788Sdelphij	}
946276788Sdelphij	if ((lls_hello || lls_dd) && (llslen = ospf6_print_lls(ndo, cp, len)) < 0)
947276788Sdelphij		goto trunc;
948276788Sdelphij	return ospf6_decode_at(ndo, cp + llslen, len - llslen);
949276788Sdelphij
950276788Sdelphijtrunc:
951276788Sdelphij	return 1;
952276788Sdelphij}
953276788Sdelphij
95456893Sfennervoid
955276788Sdelphijospf6_print(netdissect_options *ndo,
956276788Sdelphij            register const u_char *bp, register u_int length)
95756893Sfenner{
95856893Sfenner	register const struct ospf6hdr *op;
95956893Sfenner	register const u_char *dataend;
96056893Sfenner	register const char *cp;
961276788Sdelphij	uint16_t datalen;
96256893Sfenner
963313537Sglebius	op = (const struct ospf6hdr *)bp;
96456893Sfenner
96556893Sfenner	/* If the type is valid translate it, or just print the type */
96656893Sfenner	/* value.  If it's not valid, say so and return */
967276788Sdelphij	ND_TCHECK(op->ospf6_type);
968276788Sdelphij	cp = tok2str(ospf6_type_values, "unknown packet type (%u)", op->ospf6_type);
969276788Sdelphij	ND_PRINT((ndo, "OSPFv%u, %s, length %d", op->ospf6_version, cp, length));
970190207Srpaulo	if (*cp == 'u') {
97156893Sfenner		return;
972276788Sdelphij	}
97356893Sfenner
974276788Sdelphij	if(!ndo->ndo_vflag) { /* non verbose - so lets bail out here */
975276788Sdelphij		return;
976276788Sdelphij	}
977190207Srpaulo
978276788Sdelphij	/* OSPFv3 data always comes first and optional trailing data may follow. */
979276788Sdelphij	ND_TCHECK(op->ospf6_len);
980276788Sdelphij	datalen = EXTRACT_16BITS(&op->ospf6_len);
981276788Sdelphij	if (datalen > length) {
982276788Sdelphij		ND_PRINT((ndo, " [len %d]", datalen));
98356893Sfenner		return;
98456893Sfenner	}
985276788Sdelphij	dataend = bp + datalen;
98656893Sfenner
987276788Sdelphij	ND_TCHECK(op->ospf6_routerid);
988276788Sdelphij	ND_PRINT((ndo, "\n\tRouter-ID %s", ipaddr_string(ndo, &op->ospf6_routerid)));
98956893Sfenner
990276788Sdelphij	ND_TCHECK(op->ospf6_areaid);
991276788Sdelphij	if (EXTRACT_32BITS(&op->ospf6_areaid) != 0)
992276788Sdelphij		ND_PRINT((ndo, ", Area %s", ipaddr_string(ndo, &op->ospf6_areaid)));
99356893Sfenner	else
994276788Sdelphij		ND_PRINT((ndo, ", Backbone Area"));
995276788Sdelphij	ND_TCHECK(op->ospf6_instanceid);
99656893Sfenner	if (op->ospf6_instanceid)
997276788Sdelphij		ND_PRINT((ndo, ", Instance %u", op->ospf6_instanceid));
99856893Sfenner
99956893Sfenner	/* Do rest according to version.	 */
100056893Sfenner	switch (op->ospf6_version) {
100156893Sfenner
100256893Sfenner	case 3:
100356893Sfenner		/* ospf version 3 */
1004276788Sdelphij		if (ospf6_decode_v3(ndo, op, dataend) ||
1005276788Sdelphij		    ospf6_decode_v3_trailer(ndo, op, dataend, length - datalen))
100656893Sfenner			goto trunc;
100756893Sfenner		break;
100856893Sfenner	}			/* end switch on version */
100956893Sfenner
101056893Sfenner	return;
101156893Sfennertrunc:
1012276788Sdelphij	ND_PRINT((ndo, "%s", tstr));
101356893Sfenner}
1014