1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License").  You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22/*
23 * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27#pragma ident	"%Z%%M%	%I%	%E% SMI"
28
29#include <stdio.h>
30#include <ctype.h>
31#include <string.h>
32#include <fcntl.h>
33#include <string.h>
34#include <sys/types.h>
35#include <sys/time.h>
36#include <sys/socket.h>
37#include <sys/sockio.h>
38#include <net/if.h>
39#include <netinet/in_systm.h>
40#include <netinet/in.h>
41#include <netinet/ip.h>
42#include <netinet/if_ether.h>
43#include <arpa/inet.h>
44#include "snoop.h"
45#include "snoop_ospf.h"
46#include "snoop_ospf6.h"
47
48extern char *dlc_header;
49static char *sum_line;
50extern const struct bits ospf_db_flags_bits[];
51extern const struct bits ospf_rla_flag_bits[];
52extern const struct bits ospf_option_bits[];
53
54const struct bits ospf6_option_bits[] = {
55	{ OSPF_OPTION_V6,	"V6" },
56	{ OSPF_OPTION_E,	"E" },
57	{ OSPF_OPTION_MC,	"MC" },
58	{ OSPF_OPTION_N,	"N" },
59	{ OSPF_OPTION_R,	"R" },
60	{ OSPF_OPTION_DC,	"DC" },
61	{ 0,			NULL }
62};
63
64/*
65 * return a printable string in dotted-decimal notation
66 * for id.
67 */
68static char *
69print_ipaddr(uint32_t id)
70{
71	struct in_addr tmp;
72
73	tmp.s_addr = id;
74	return (inet_ntoa(tmp));
75}
76
77static int
78interpret_ospf6_hello(int flags, struct ospf6hdr *op, int fraglen)
79{
80	uint32_t *nbr;
81	int j;
82
83	if (fraglen < OSPF6_MIN_HEADER_SIZE + OSPF_MIN_HELLO_HEADER_SIZE)
84		return (-1); /* truncated packet */
85
86	if (flags & F_SUM) {
87		if (op->ospf6_hello.hello_dr != 0) {
88			(void) sprintf(sum_line, "DR=%s ",
89			    print_ipaddr(op->ospf6_hello.hello_dr));
90		}
91		sum_line += strlen(sum_line);
92		if (op->ospf6_hello.hello_bdr != 0) {
93			(void) sprintf(sum_line, "BDR=%s ",
94			    print_ipaddr(op->ospf6_hello.hello_bdr));
95		}
96		sum_line += strlen(sum_line);
97		j = 0;
98		nbr = op->ospf6_hello.hello_neighbor;
99		while ((uchar_t *)nbr < ((uchar_t *)op + fraglen)) {
100			if ((uchar_t *)nbr + sizeof (struct in_addr) >
101			    ((uchar_t *)op + fraglen))
102				return (-1); /* truncated */
103			++nbr;
104			j++;
105		}
106		(void) sprintf(sum_line, "%d nbrs", j);
107		sum_line += strlen(sum_line);
108
109	}
110	if (flags & F_DTAIL) {
111		show_header("OSPF HELLO:  ", "Hello Packet",
112		    ntohs(op->ospf6_len));
113		show_space();
114		(void) snprintf(get_line(0, 0), get_line_remain(),
115		    "Options = %s", ospf_print_bits(ospf6_option_bits,
116		    op->ospf6_hello.hello6_options));
117		(void) snprintf(get_line(0, 0), get_line_remain(),
118		    "Interface ID = %s",
119		    print_ipaddr(op->ospf6_hello.hello_ifid));
120		(void) snprintf(get_line(0, 0), get_line_remain(),
121		    "Hello interval = %d",
122		    ntohs(op->ospf6_hello.hello_helloint));
123		(void) snprintf(get_line(0, 0), get_line_remain(),
124		    "Priority = %d", op->ospf6_hello.hello6_priority);
125		(void) snprintf(get_line(0, 0), get_line_remain(),
126		    "Dead interval = %u", ntohl(op->ospf6_hello.hello_deadint));
127		if (op->ospf6_hello.hello_dr != 0) {
128			(void) snprintf(get_line(0, 0), get_line_remain(),
129			    "Designated Router = %s",
130			    print_ipaddr(op->ospf6_hello.hello_dr));
131		}
132		if (op->ospf6_hello.hello_bdr != 0) {
133			(void) snprintf(get_line(0, 0), get_line_remain(),
134			    "Backup Designated Router = %s",
135			    print_ipaddr(op->ospf6_hello.hello_bdr));
136		}
137		nbr = op->ospf6_hello.hello_neighbor;
138		while ((uchar_t *)nbr < ((uchar_t *)op + fraglen)) {
139			if ((uchar_t *)nbr + sizeof (struct in_addr) >
140			    ((uchar_t *)op + fraglen))
141				return (-1); /* truncated */
142			(void) snprintf(get_line(0, 0), get_line_remain(),
143			    "Neigbor: %s", print_ipaddr(*nbr));
144			++nbr;
145		}
146	}
147	return (fraglen);
148}
149
150static void
151ospf6_print_ls_type(int flags, uint_t ls6_type, uint32_t ls6_stateid,
152    uint32_t ls6_router)
153{
154	char scope[15];
155
156	if (flags & F_SUM)
157		return;
158
159	switch (ls6_type & LS6_SCOPE_MASK) {
160	case LS6_SCOPE_LINKLOCAL:
161		snprintf(scope, sizeof (scope), "linklocal");
162		break;
163	case LS6_SCOPE_AREA:
164		snprintf(scope, sizeof (scope), "area");
165		break;
166	case LS6_SCOPE_AS:
167		snprintf(scope, sizeof (scope), "AS");
168		break;
169	default:
170		snprintf(scope, sizeof (scope), "");
171		break;
172	}
173	switch (ls6_type & LS_TYPE_MASK) {
174	case LS_TYPE_ROUTER:
175		if (flags & F_DTAIL) {
176			(void) snprintf(get_line(0, 0), get_line_remain(),
177			    "%s Router = %s", scope, print_ipaddr(ls6_router));
178		}
179		break;
180	case LS_TYPE_NETWORK:
181		if (flags & F_DTAIL) {
182			(void) snprintf(get_line(0, 0), get_line_remain(),
183			    "%s Net DR %s IF %s", scope,
184			    print_ipaddr(ls6_router),
185			    print_ipaddr(ls6_stateid));
186		}
187		break;
188	case LS_TYPE_INTER_AP:
189		if (flags & F_DTAIL) {
190			(void) snprintf(get_line(0, 0), get_line_remain(),
191			    "%s Inter-area-prefix = %s ABR %s", scope,
192			    print_ipaddr(ls6_stateid),
193			    print_ipaddr(ls6_router));
194		}
195		break;
196	case LS_TYPE_INTER_AR:
197		if (flags & F_DTAIL) {
198			(void) snprintf(get_line(0, 0), get_line_remain(),
199			    "%s Inter-area-router = %s Router %s", scope,
200			    print_ipaddr(ls6_router),
201			    print_ipaddr(ls6_stateid));
202		}
203		break;
204	case LS_TYPE_ASE:
205		if (flags & F_DTAIL) {
206			(void) snprintf(get_line(0, 0), get_line_remain(),
207			    "%s ASE = %s ASBR %s", scope,
208			    print_ipaddr(ls6_stateid),
209			    print_ipaddr(ls6_router));
210		}
211		break;
212	case LS_TYPE_GROUP:
213		if (flags & F_DTAIL) {
214			(void) snprintf(get_line(0, 0), get_line_remain(),
215			    "%s group = %s Router %s", scope,
216			    print_ipaddr(ls6_stateid),
217			    print_ipaddr(ls6_router));
218		}
219		break;
220	case LS_TYPE_TYPE7:
221		if (flags & F_DTAIL) {
222			(void) snprintf(get_line(0, 0), get_line_remain(),
223			    "%s Type 7 = %s Router %s", scope,
224			    print_ipaddr(ls6_stateid),
225			    print_ipaddr(ls6_router));
226		}
227		break;
228	case LS_TYPE_LINK:
229		if (flags & F_DTAIL) {
230			(void) snprintf(get_line(0, 0), get_line_remain(),
231			    "%s link = %s Router %s", scope,
232			    print_ipaddr(ls6_stateid),
233			    print_ipaddr(ls6_router));
234		}
235		break;
236	case LS_TYPE_INTRA_AP:
237		if (flags & F_DTAIL) {
238			(void) snprintf(get_line(0, 0), get_line_remain(),
239			    "%s Inter-area-prefix = %s Router %s", scope,
240			    print_ipaddr(ls6_stateid),
241			    print_ipaddr(ls6_router));
242		}
243		break;
244	default:
245		if (flags & F_DTAIL) {
246			(void) snprintf(get_line(0, 0), get_line_remain(),
247			    "%s Unknown type = 0x%x", ls6_type);
248		}
249		break;
250	}
251}
252
253static int
254ospf6_print_lsaprefix(int flags, struct lsa6_prefix *lpfx)
255{
256	int k;
257	struct in6_addr prefix;
258	char prefixstr[INET6_ADDRSTRLEN];
259
260	k = (lpfx->lsa6_plen + 31)/32;
261	if (k * 4 > sizeof (struct in6_addr)) {
262		if (flags & F_SUM) {
263			sprintf(sum_line, "Unknown prefix len %d",
264			    lpfx->lsa6_plen);
265			sum_line += strlen(sum_line);
266		}
267		if (flags & F_DTAIL) {
268			(void) snprintf(get_line(0, 0), get_line_remain(),
269			    "Unknown prefix len %d", lpfx->lsa6_plen);
270		}
271	}
272	memset((void *)&prefix, 0, sizeof (prefix));
273	memcpy((void *)&prefix, lpfx->lsa6_pfx, k * 4);
274	(void) inet_ntop(AF_INET6, (char *)&prefix, prefixstr,
275	    INET6_ADDRSTRLEN);
276	if (flags & F_SUM) {
277		sprintf(sum_line, "%s/%d", prefixstr, lpfx->lsa6_plen);
278		sum_line += strlen(sum_line);
279	}
280	if (flags & F_DTAIL) {
281		(void) snprintf(get_line(0, 0), get_line_remain(),
282		    "%s/%d", prefixstr, lpfx->lsa6_plen);
283	}
284	if (lpfx->lsa6_popt != 0) {
285		if (flags & F_SUM) {
286			sprintf(sum_line, "(opt = %x)", lpfx->lsa6_popt);
287			sum_line += strlen(sum_line);
288		}
289		if (flags & F_DTAIL) {
290			(void) snprintf(get_line(0, 0), get_line_remain(),
291			    "(opt = %x)", lpfx->lsa6_popt);
292		}
293	}
294	return (sizeof (*lpfx) - 4 + k * 4);
295}
296
297static void
298interpret_ospf6_lsa_hdr(int flags, struct lsa6_hdr *lsah)
299{
300	if (flags & F_SUM)
301		return;
302
303	if (flags & F_DTAIL) {
304		(void) snprintf(get_line(0, 0), get_line_remain(),
305		    "Sequence = %X ", ntohl(lsah->ls6_seq));
306		(void) snprintf(get_line(0, 0), get_line_remain(),
307		    "Age = %X ", ospf_print_lsa_age(ntohl(lsah->ls6_age)));
308	}
309
310	ospf6_print_ls_type(flags, lsah->ls6_type, lsah->ls6_stateid,
311	    lsah->ls6_router);
312
313}
314
315#define	TRUNC(addr)	((uchar_t *)(addr) > fragend)
316static int
317interpret_ospf6_lsa(int flags, struct lsa6 *lsa, uchar_t *fragend)
318{
319	uchar_t *ls_end;
320	int  k, j;
321	struct rla6link *rl;
322	uint32_t *addr;
323	struct lsa6_prefix *lpfx;
324	struct llsa *llsa;
325	char addrstr[INET6_ADDRSTRLEN];
326
327	interpret_ospf6_lsa_hdr(flags, &lsa->ls6_hdr);
328
329	ls_end = (uchar_t *)lsa + ntohs(lsa->ls6_hdr.ls6_length);
330
331	if (TRUNC(ls_end))
332		return (-1);
333
334	switch (ntohs(lsa->ls6_hdr.ls6_type)) {
335
336	case LS_TYPE_ROUTER|LS6_SCOPE_AREA:
337		if (TRUNC(&lsa->lsa_un.un_rla.rla6_flags))
338			return (-1);
339
340		(void) ospf_print_bits(ospf_rla_flag_bits,
341		    lsa->lsa_un.un_rla.rla6_flags);
342
343		if (TRUNC(&lsa->lsa_un.un_rla.rla6_options))
344			return (-1);
345		(void) ospf_print_bits(ospf_option_bits,
346		    ntohl(lsa->lsa_un.un_rla.rla6_options));
347
348		rl = lsa->lsa_un.un_rla.rla_link;
349		if (TRUNC(rl))
350			return (-1);
351
352		while (rl + sizeof (*rl) <= (struct rla6link *)ls_end) {
353			if (TRUNC((uchar_t *)rl + sizeof (*rl)))
354				return (-1);
355			if (flags & F_SUM) {
356				sprintf(sum_line, "{");		/* } (ctags) */
357				sum_line += strlen(sum_line);
358			}
359			switch (rl->link_type) {
360			case RLA_TYPE_VIRTUAL:
361				if (flags & F_SUM) {
362					sprintf(sum_line, "virt ");
363					sum_line += strlen(sum_line);
364				}
365				if (flags & F_DTAIL) {
366					(void) snprintf(get_line(0, 0),
367					    get_line_remain(), "Virtual Link");
368				}
369				/* FALLTHROUGH */
370			case RLA_TYPE_ROUTER:
371				if (flags & F_SUM) {
372					sprintf(sum_line, "nbrid %s",
373					    print_ipaddr(rl->link_nrtid));
374					sum_line += strlen(sum_line);
375					sprintf(sum_line, " nbrif %s",
376					    print_ipaddr(rl->link_nifid));
377					sum_line += strlen(sum_line);
378					sprintf(sum_line, " if %s",
379					    print_ipaddr(rl->link_ifid));
380					sum_line += strlen(sum_line);
381				}
382				if (flags & F_DTAIL) {
383					(void) snprintf(get_line(0, 0),
384					    get_line_remain(), "Neighbor = %s",
385					    print_ipaddr(rl->link_nrtid));
386					(void) snprintf(get_line(0, 0),
387					    get_line_remain(),
388					    "Interface = %s id %s",
389					    print_ipaddr(rl->link_nifid),
390					    print_ipaddr(rl->link_ifid));
391				}
392				break;
393			case RLA_TYPE_TRANSIT:
394				if (flags & F_SUM) {
395					sprintf(sum_line, "dr %s",
396					    print_ipaddr(rl->link_nrtid));
397					sum_line += strlen(sum_line);
398					sprintf(sum_line, " drif %s",
399					    print_ipaddr(rl->link_nifid));
400					sum_line += strlen(sum_line);
401					sprintf(sum_line, " if %s",
402					    print_ipaddr(rl->link_ifid));
403					sum_line += strlen(sum_line);
404				}
405				if (flags & F_DTAIL) {
406					(void) snprintf(get_line(0, 0),
407					    get_line_remain(),
408					    "Designated Router = %s",
409					    print_ipaddr(rl->link_nrtid));
410					(void) snprintf(get_line(0, 0),
411					    get_line_remain(),
412					    "DR Interface = %s id %s",
413					    print_ipaddr(rl->link_nifid),
414					    print_ipaddr(rl->link_ifid));
415				}
416				break;
417			default:
418				if (flags & F_SUM) {
419					sprintf(sum_line,
420					    "Unknown link type %d",
421					    rl->link_type);
422					sum_line += strlen(sum_line);
423				}
424				if (flags & F_DTAIL) {
425					(void) snprintf(get_line(0, 0),
426					    get_line_remain(),
427					    "Unknown link type %d",
428					    rl->link_type);
429				}
430
431			}
432			if (flags & F_SUM) {
433				sprintf(sum_line, " metric %d",
434				    ntohs(rl->link_metric));
435				sum_line += strlen(sum_line);
436			}
437			if (flags & F_DTAIL) {
438				(void) snprintf(get_line(0, 0),
439				    get_line_remain(), " metric = %d",
440				    ntohs(rl->link_metric));
441			}
442			if (flags & F_SUM) { 			/* { (ctags) */
443				sprintf(sum_line,  " }");
444				sum_line += strlen(sum_line);
445			}
446			rl++;
447			if ((uchar_t *)rl > fragend)
448				return (-1); /* truncated */
449		}
450		break;
451	case LS_TYPE_NETWORK | LS6_SCOPE_AREA:
452
453		if (TRUNC(&lsa->lsa_un.un_nla.nla_options))
454			return (-1);
455
456		(void) ospf_print_bits(ospf6_option_bits,
457		    ntohl(lsa->lsa_un.un_nla.nla_options));
458
459		if (flags & F_SUM) {
460			sprintf(sum_line, " rtrs");
461			sum_line += strlen(sum_line);
462		}
463		if (flags & F_DTAIL) {
464			snprintf(get_line(0, 0), get_line_remain(),
465			    "Routers:");
466		}
467		addr = lsa->lsa_un.un_nla.nla_router;
468		while ((uchar_t *)addr < ls_end) {
469			if ((uchar_t *)addr + sizeof (struct in_addr) > ls_end)
470				return (-1); /* truncated */
471			if (flags & F_SUM) {
472				sprintf(sum_line, " %s", print_ipaddr(*addr));
473				sum_line += strlen(sum_line);
474			}
475			if (flags & F_DTAIL) {
476				snprintf(get_line(0, 0), get_line_remain(),
477				    "\t%s", print_ipaddr(*addr));
478			}
479			++addr;
480		}
481		break;
482	case LS_TYPE_INTER_AP | LS6_SCOPE_AREA:
483
484		if (TRUNC(&lsa->lsa_un.un_inter_ap.inter_ap_metric))
485			return (-1);
486
487		if (flags & F_SUM) {
488			sprintf(sum_line, " metric %s",
489			    ntohl(lsa->lsa_un.un_inter_ap.inter_ap_metric) &
490			    SLA_MASK_METRIC);
491			sum_line += strlen(sum_line);
492		}
493		if (flags & F_DTAIL) {
494			snprintf(get_line(0, 0), get_line_remain(),
495			    "Metric = %s",
496			    ntohl(lsa->lsa_un.un_inter_ap.inter_ap_metric) &
497			    SLA_MASK_METRIC);
498		}
499		lpfx = lsa->lsa_un.un_inter_ap.inter_ap_prefix;
500		if (lpfx > (struct lsa6_prefix *)ls_end)
501			return (-1);
502		while (lpfx + sizeof (*lpfx) <= (struct lsa6_prefix *)ls_end) {
503			k = ospf6_print_lsaprefix(flags, lpfx);
504			lpfx = (struct lsa6_prefix *)(((uchar_t *)lpfx) + k);
505			if (lpfx > (struct lsa6_prefix *)ls_end)
506				return (-1);
507		}
508		break;
509	case LS_TYPE_LINK:
510		llsa = &lsa->lsa_un.un_llsa;
511		if (TRUNC(llsa->llsa_options))
512			return (-1);
513		ospf_print_bits(ospf6_option_bits, ntohl(llsa->llsa_options));
514		if (TRUNC(llsa->llsa_nprefix))
515			return (-1);
516		(void) inet_ntop(AF_INET6, &llsa->llsa_lladdr,
517		    addrstr, INET6_ADDRSTRLEN);
518		if (flags & F_SUM)  {
519			sprintf(sum_line, " pri %d lladdr %s npref %d",
520			    ntohl(llsa->llsa_priority), addrstr,
521			    ntohl(llsa->llsa_nprefix));
522			sum_line += strlen(sum_line);
523		}
524		if (flags & F_DTAIL)  {
525			snprintf(get_line(0, 0), get_line_remain(),
526			    "Priority %d", ntohl(llsa->llsa_priority));
527			snprintf(get_line(0, 0), get_line_remain(),
528			    "Link Local addr %d", addrstr);
529			snprintf(get_line(0, 0), get_line_remain(),
530			    "npref %d", ntohl(llsa->llsa_nprefix));
531		}
532		lpfx = llsa->llsa_prefix;
533		for (j = 0; j < ntohl(llsa->llsa_nprefix); j++) {
534			if (TRUNC(lpfx))
535				return (-1);
536			k = ospf6_print_lsaprefix(flags, lpfx);
537			lpfx = (struct lsa6_prefix *)(((uchar_t *)lpfx) + k);
538		}
539		break;
540
541	case LS_TYPE_INTRA_AP | LS6_SCOPE_AREA:
542		if (TRUNC(&lsa->lsa_un.un_intra_ap.intra_ap_rtid))
543			return (-1);
544		ospf6_print_ls_type(flags,
545		    ntohs(lsa->lsa_un.un_intra_ap.intra_ap_lstype),
546		    lsa->lsa_un.un_intra_ap.intra_ap_lsid,
547		    lsa->lsa_un.un_intra_ap.intra_ap_rtid);
548		if (TRUNC(&lsa->lsa_un.un_intra_ap.intra_ap_nprefix))
549			return (-1);
550		if (flags & F_SUM) {
551			sprintf(sum_line, " npref %d",
552			    ntohs(lsa->lsa_un.un_intra_ap.intra_ap_nprefix));
553			sum_line += strlen(sum_line);
554		}
555		if (flags & F_DTAIL) {
556			snprintf(get_line(0, 0), get_line_remain(), "NPref %d",
557			    ntohs(lsa->lsa_un.un_intra_ap.intra_ap_nprefix));
558		}
559
560		lpfx = lsa->lsa_un.un_intra_ap.intra_ap_prefix;
561		for (j = 0;
562		    j < ntohs(lsa->lsa_un.un_intra_ap.intra_ap_nprefix); j++) {
563			if (TRUNC(lpfx))
564				return (-1);
565			k = ospf6_print_lsaprefix(flags, lpfx);
566			lpfx = (struct lsa6_prefix *)(((uchar_t *)lpfx) + k);
567		}
568		break;
569
570	default:
571		if (flags & F_SUM)  {
572			sprintf(sum_line, " Unknown LSA type (%d)",
573			    lsa->ls6_hdr.ls6_type);
574			sum_line += strlen(sum_line);
575		}
576		if (flags & F_DTAIL)  {
577			snprintf(get_line(0, 0), get_line_remain(),
578			    " Unknown LSA type %d", lsa->ls6_hdr.ls6_type);
579
580		}
581		break;
582	}
583	return (0);
584}
585#undef TRUNC
586int
587interpret_ospf6(int flags, struct ospf6hdr *ospf, int iplen, int fraglen)
588{
589	boolean_t trunc = B_FALSE;
590	struct lsa6_hdr *lsah;
591	struct lsr6 *lsr;
592	struct lsa6 *lsa;
593	int nlsa, nlsah;
594
595	if ((fraglen < OSPF6_MIN_HEADER_SIZE) ||
596	    (fraglen < ntohs(ospf->ospf6_len)))
597		return (fraglen);	/* incomplete header */
598
599	if (ospf->ospf6_version != 3) {
600		if (ospf->ospf6_version == 2) {
601			if (flags & F_DTAIL)
602				snprintf(get_line(0, 0), get_line_remain(),
603				    "ospfv2 packet in ipv6 header");
604			return (interpret_ospf(flags, ospf, iplen, fraglen));
605		} else  {
606			return (fraglen);
607		}
608	}
609
610	if (fraglen > ntohs(ospf->ospf6_len))
611		fraglen = ntohs(ospf->ospf6_len);
612
613	if (ospf->ospf6_type > OSPF_TYPE_MAX) {
614		if (flags & F_SUM) {
615			(void) sprintf(sum_line, "Unknown OSPF TYPE %d \n",
616			    ospf->ospf6_type);
617			sum_line += strlen(sum_line);
618		}
619		if (flags & F_SUM) {
620			show_header("OSPFv3:  ", "OSPFv3 Header", fraglen);
621			show_space();
622			(void) snprintf(get_line(0, 0), get_line_remain(),
623			    "Unknown OSPF Type = %d", ospf->ospf6_type);
624		}
625		return (fraglen);
626	}
627
628	if (flags & F_SUM) {
629		sum_line = (char *)get_sum_line();
630		(void) sprintf(sum_line, "OSPFv3 %s RTRID=%s ",
631		    ospf_types[ospf->ospf6_type],
632		    print_ipaddr(ospf->ospf6_routerid));
633		sum_line += strlen(sum_line);
634		(void) sprintf(sum_line, "AREA=%s LEN=%d instance %u ",
635		    print_ipaddr(ospf->ospf6_areaid),
636		    ntohs((ushort_t)ospf->ospf6_len), ospf->ospf6_instanceid);
637		sum_line += strlen(sum_line);
638	}
639
640	if (flags & F_DTAIL) {
641		show_header("OSPFv3:  ", "OSPF Header", fraglen);
642		show_space();
643		(void) snprintf(get_line(0, 0), get_line_remain(),
644		    "Version = %d", ospf->ospf6_version);
645		(void) snprintf(get_line(0, 0), get_line_remain(),
646		    "Type = %s", ospf_types[ospf->ospf6_type]);
647		(void) snprintf(get_line(0, 0), get_line_remain(),
648		    "Router ID = %s", print_ipaddr(ospf->ospf6_routerid));
649		(void) snprintf(get_line(0, 0), get_line_remain(),
650		    "Area ID = %s", print_ipaddr(ospf->ospf6_areaid));
651		(void) snprintf(get_line(0, 0), get_line_remain(),
652		    "Checksum = 0x%x", ospf->ospf6_chksum);
653		(void) snprintf(get_line(0, 0), get_line_remain(),
654		    "Instance = %u", ospf->ospf6_instanceid);
655	}
656
657	switch (ospf->ospf6_type) {
658	case OSPF_TYPE_HELLO:
659		if (interpret_ospf6_hello(flags, ospf, fraglen) < 0)
660			trunc = B_TRUE;
661		break;
662
663	case OSPF_TYPE_DB:
664		if (fraglen < OSPF6_MIN_HEADER_SIZE +
665		    OSPF6_MIN_DB_HEADER_SIZE) {
666			trunc = B_TRUE;
667			break;
668		}
669		if (flags & F_SUM) {
670			sprintf(sum_line, " %s %s mtu %u S %X", ospf_print_bits(
671			    ospf6_option_bits,
672			    ntohl(ospf->ospf6_db.db_options)),
673			    ospf_print_bits(ospf_db_flags_bits,
674			    ospf->ospf6_db.db_flags),
675			    ntohs(ospf->ospf6_db.db_mtu),
676			    ntohl(ospf->ospf6_db.db_seq));
677			sum_line += strlen(sum_line);
678		}
679		if (flags & F_DTAIL) {
680			show_header("OSPF DB:  ", "Database Description Packet",
681			    fraglen);
682			show_space();
683			snprintf(get_line(0, 0), get_line_remain(),
684			    "Options = %s", ospf_print_bits(
685			    ospf6_option_bits, ospf->ospf6_db.db_options));
686			snprintf(get_line(0, 0), get_line_remain(),
687			    "Flags = %s", ospf_print_bits(
688			    ospf_db_flags_bits, ospf->ospf6_db.db_flags));
689			snprintf(get_line(0, 0), get_line_remain(),
690			    "MTU = %u", ntohl(ospf->ospf6_db.db_seq));
691			snprintf(get_line(0, 0), get_line_remain(),
692			    "Sequence = 0x%X", ntohl(ospf->ospf6_db.db_seq));
693			/*  Print all the LS advs */
694			lsah = ospf->ospf6_db.db_lshdr;
695			while ((uchar_t *)lsah < ((uchar_t *)ospf + fraglen)) {
696				if ((uchar_t *)lsah + sizeof (struct lsa6_hdr) >
697				    ((uchar_t *)ospf + fraglen)) {
698					trunc = B_TRUE;
699					break;
700				}
701				interpret_ospf6_lsa_hdr(flags, lsah);
702				++lsah;
703			}
704		}
705		break;
706
707	case OSPF_TYPE_LSR:
708		if (fraglen < OSPF6_MIN_HEADER_SIZE +
709		    OSPF_MIN_LSR_HEADER_SIZE) {
710			trunc = B_TRUE;
711			break;
712		}
713		if (flags & F_DTAIL) {
714			show_header("OSPF LSR:  ", "Link State Request Packet",
715			    fraglen);
716			show_space();
717		}
718		lsr = ospf->ospf6_lsr;
719		nlsah = 0;
720		while ((uchar_t *)lsr < ((uchar_t *)ospf + fraglen)) {
721			if ((uchar_t *)lsr + sizeof (struct lsr6) >
722			    ((uchar_t *)ospf + fraglen)) {
723				trunc = B_TRUE;
724				break;
725			}
726			nlsah++;
727			if (flags & F_DTAIL) {
728				ospf6_print_ls_type(flags, ntohl(lsr->ls_type),
729				    lsr->ls_stateid, lsr->ls_router);
730			}
731			++lsr;
732		}
733		if (flags & F_SUM) {
734			sprintf(sum_line, "%d LSAs", nlsah);
735			sum_line += strlen(sum_line);
736		}
737		break;
738
739	case OSPF_TYPE_LSU:
740		if (fraglen < OSPF6_MIN_HEADER_SIZE +
741		    OSPF_MIN_LSU_HEADER_SIZE) {
742			trunc = B_TRUE;
743			break;
744		}
745		if (flags & F_DTAIL) {
746			show_header("OSPF LSU:  ", "Link State Update Packet",
747			    fraglen);
748			show_space();
749		}
750		lsa = ospf->ospf6_lsu.lsu_lsa;
751		nlsa = ntohl(ospf->ospf6_lsu.lsu_count);
752		if (flags & F_SUM) {
753			sprintf(sum_line, "%d LSAs", nlsa);
754			sum_line += strlen(sum_line);
755			break;
756		}
757		while (nlsa-- != 0) {
758			uchar_t *fragend = (uchar_t *)ospf + fraglen;
759			if (((uchar_t *)lsa >= fragend) ||
760			    ((uchar_t *)lsa + sizeof (struct lsa_hdr) >
761			    fragend) ||
762			    ((uchar_t *)lsa + ntohs(lsa->ls6_hdr.ls6_length) >
763			    fragend)) {
764				trunc = B_TRUE;
765				break;
766			}
767
768			if (interpret_ospf6_lsa(flags, lsa, fragend) < 0) {
769				trunc = B_TRUE;
770				break;
771			}
772			lsa = (struct lsa6 *)((uchar_t *)lsa +
773			    ntohs(lsa->ls6_hdr.ls6_length));
774		}
775		break;
776
777	case OSPF_TYPE_LSA:
778		if (flags & F_DTAIL) {
779			show_header("OSPF LSA:  ", "Link State Ack Packet",
780			    fraglen);
781			show_space();
782		}
783		lsah = ospf->ospf6_lsa.lsa_lshdr;
784		nlsah = 0;
785		while ((uchar_t *)lsah < ((uchar_t *)ospf + fraglen)) {
786			if ((uchar_t *)lsah + sizeof (struct lsa6_hdr) >
787			    ((uchar_t *)ospf + fraglen)) {
788				trunc = B_TRUE;
789				break;
790			}
791			nlsah++;
792			if (flags & F_DTAIL)
793				interpret_ospf6_lsa_hdr(flags, lsah);
794			++lsah;
795		}
796		if (flags & F_SUM) {
797			sprintf(sum_line, "%d LSAs", nlsah);
798			sum_line += strlen(sum_line);
799		}
800		break;
801
802	default:
803		/* NOTREACHED */
804		break;
805	}
806	if (trunc) {
807		if (flags & F_SUM)
808			sprintf(sum_line, "--truncated");
809		if (flags & F_DTAIL)
810			snprintf(get_line(0, 0), get_line_remain(),
811			    "--truncated");
812	}
813
814	return (fraglen);
815}
816