xref: /titanic_44/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_ospf.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
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 
48 extern char *dlc_header;
49 static char *sum_line;
50 
51 char *ospf_types[] = {
52 	"umd", 		/* 0 */
53 	"Hello",	/* 1 */
54 	"DD",		/* 2 */
55 	"LSReq",	/* 3 */
56 	"LSUpd",	/* 4 */
57 	"LSAck",	/* 5 */
58 };
59 
60 static char *ospf_authtypes[] = {
61 	"None", 	/* 0 */
62 	"simple",	/* 1 */
63 	"md5",		/* 2 */
64 };
65 
66 const struct bits ospf_rla_flag_bits[] = {
67 	{ RLA_FLAG_B,		"B" },
68 	{ RLA_FLAG_E,		"E" },
69 	{ RLA_FLAG_V,		"V" },
70 	{ RLA_FLAG_W,		"W" },
71 	{ 0, 			NULL }
72 };
73 
74 const struct bits ospf_db_flags_bits[] = {
75 	{ OSPF_DB_INIT,		"I" },
76 	{ OSPF_DB_MORE,		"M" },
77 	{ OSPF_DB_MASTER,	"MS" },
78 	{ 0, 			NULL }
79 };
80 
81 const struct bits ospf_option_bits[] = {
82 	{ OSPF_OPTION_T,	"T" },
83 	{ OSPF_OPTION_E,	"E" },
84 	{ OSPF_OPTION_MC,	"MC" },
85 	{ 0,			NULL }
86 };
87 
88 static int interpret_ospf_hello(int, struct ospfhdr *, int);
89 static void ospf_print_ls_type(int, uint32_t, struct in_addr, struct in_addr);
90 static void interpret_ospf_lsa_hdr(int, struct lsa_hdr *);
91 static int interpret_ospf_lsa(int flags, struct lsa *lsa, uchar_t *);
92 
93 char *
ospf_print_bits(const struct bits * bp,uchar_t options)94 ospf_print_bits(const struct bits *bp, uchar_t options)
95 {
96 	static char bitstring[32];
97 
98 	bitstring[0] = '\0';
99 	do {
100 		if (options & bp->bit) {
101 			strcat(bitstring, bp->str);
102 			strcat(bitstring, "/");
103 		}
104 	} while ((++bp)->bit);
105 
106 	/* wipe out the trailing "/" */
107 	bitstring[strlen(bitstring) - 1] = '\0';
108 	return (bitstring);
109 }
110 
111 char *
ospf_print_lsa_age(long age)112 ospf_print_lsa_age(long age)
113 {
114 	long sec, mins, hour;
115 	static char lsa_age[16];
116 
117 	sec = age % 60;
118 	mins = (age / 60) % 60;
119 	hour = age / 3600;
120 	if (hour != 0)
121 		snprintf(lsa_age, sizeof (lsa_age), "%u:%02u:%02u",
122 		    hour, mins, sec);
123 	else if (mins != 0)
124 		snprintf(lsa_age, sizeof (lsa_age), "%u:%02u", mins, sec);
125 	else
126 		snprintf(lsa_age, sizeof (lsa_age), "%u", sec);
127 	return (lsa_age);
128 }
129 
130 static int
interpret_ospf_hello(int flags,struct ospfhdr * op,int fraglen)131 interpret_ospf_hello(int flags, struct ospfhdr *op, int fraglen)
132 {
133 	struct in_addr *nbr;
134 	int j;
135 
136 	if (fraglen < OSPF_MIN_HEADER_SIZE + OSPF_MIN_HELLO_HEADER_SIZE)
137 		return (-1); /* truncated packet */
138 
139 	if (flags & F_SUM) {
140 		if (op->ospf_hello.hello_dr.s_addr != 0) {
141 			(void) sprintf(sum_line, "DR=%s ",
142 			    inet_ntoa(op->ospf_hello.hello_dr));
143 		}
144 		sum_line += strlen(sum_line);
145 		if (op->ospf_hello.hello_bdr.s_addr != 0) {
146 			(void) sprintf(sum_line, "BDR=%s ",
147 			    inet_ntoa(op->ospf_hello.hello_bdr));
148 		}
149 		sum_line += strlen(sum_line);
150 		nbr = op->ospf_hello.hello_neighbor;
151 		j = 0;
152 		while ((uchar_t *)nbr < ((uchar_t *)op + fraglen)) {
153 			if ((uchar_t *)nbr + sizeof (struct in_addr) >
154 			    ((uchar_t *)op + fraglen))
155 				return (-1); /* truncated */
156 			j++;
157 			++nbr;
158 		}
159 		(void) sprintf(sum_line, "%d nbrs", j);
160 		sum_line += strlen(sum_line);
161 
162 	}
163 	if (flags & F_DTAIL) {
164 		show_header("OSPF HELLO:  ", "Hello Packet",
165 		    ntohs(op->ospf_len));
166 		show_space();
167 		(void) snprintf(get_line(0, 0), get_line_remain(),
168 		    "Options = %s", ospf_print_bits(ospf_option_bits,
169 		    op->ospf_hello.hello_options));
170 		(void) snprintf(get_line(0, 0), get_line_remain(), "Mask = %s",
171 		    inet_ntoa(op->ospf_hello.hello_mask));
172 		(void) snprintf(get_line(0, 0), get_line_remain(),
173 		    "Hello interval = %d",
174 		    ntohs(op->ospf_hello.hello_helloint));
175 		(void) snprintf(get_line(0, 0), get_line_remain(),
176 		    "Priority = %d", op->ospf_hello.hello_priority);
177 		(void) snprintf(get_line(0, 0), get_line_remain(),
178 		    "Dead interval = %u", ntohl(op->ospf_hello.hello_deadint));
179 		if (op->ospf_hello.hello_dr.s_addr != 0) {
180 			(void) snprintf(get_line(0, 0), get_line_remain(),
181 			    "Designated Router = %s",
182 			    inet_ntoa(op->ospf_hello.hello_dr));
183 		}
184 		if (op->ospf_hello.hello_bdr.s_addr != 0) {
185 			(void) snprintf(get_line(0, 0), get_line_remain(),
186 			    "Backup Designated Router = %s",
187 			    inet_ntoa(op->ospf_hello.hello_bdr));
188 		}
189 		nbr = op->ospf_hello.hello_neighbor;
190 		while ((uchar_t *)nbr < ((uchar_t *)op + fraglen)) {
191 			if ((uchar_t *)nbr + sizeof (struct in_addr) >
192 			    ((uchar_t *)op + fraglen))
193 				return (-1); /* truncated */
194 			(void) snprintf(get_line(0, 0), get_line_remain(),
195 			    "Neighbor: %s", inet_ntoa(*nbr));
196 			++nbr;
197 		}
198 	}
199 	return (fraglen);
200 }
201 
202 static void
ospf_print_ls_type(int flags,uint32_t ls_type,struct in_addr ls_stateid,struct in_addr ls_router)203 ospf_print_ls_type(int flags, uint32_t ls_type, struct in_addr ls_stateid,
204     struct in_addr ls_router)
205 {
206 	switch (ls_type) {
207 	case LS_TYPE_ROUTER:
208 		if (flags & F_SUM) {
209 			sprintf(sum_line, " rtr %s ", inet_ntoa(ls_router));
210 			sum_line += strlen(sum_line);
211 		}
212 		if (flags & F_DTAIL) {
213 			(void) snprintf(get_line(0, 0), get_line_remain(),
214 			    "Router LSA; Router = %s ", inet_ntoa(ls_router));
215 		}
216 		break;
217 	case LS_TYPE_NETWORK:
218 		if (flags & F_SUM) {
219 			sprintf(sum_line, " net dr %s ", inet_ntoa(ls_router));
220 			sum_line += strlen(sum_line);
221 			sprintf(sum_line, "if %s ", inet_ntoa(ls_stateid));
222 			sum_line += strlen(sum_line);
223 		}
224 		if (flags & F_DTAIL) {
225 			(void) snprintf(get_line(0, 0), get_line_remain(),
226 			    "Network LSA Router = %s ", inet_ntoa(ls_router));
227 			(void) snprintf(get_line(0, 0), get_line_remain(),
228 			    "            Interface = %s ",
229 			    inet_ntoa(ls_stateid));
230 		}
231 		break;
232 	case LS_TYPE_SUM_IP:
233 		if (flags & F_SUM) {
234 			sprintf(sum_line, " sum %s ", inet_ntoa(ls_stateid));
235 			sum_line += strlen(sum_line);
236 			sprintf(sum_line, "abr %s ", inet_ntoa(ls_router));
237 			sum_line += strlen(sum_line);
238 		}
239 		if (flags & F_DTAIL) {
240 			(void) snprintf(get_line(0, 0), get_line_remain(),
241 			    "Summary LSA IP = %s ", inet_ntoa(ls_stateid));
242 			(void) snprintf(get_line(0, 0), get_line_remain(),
243 			    "            Area Border Router = %s ",
244 			    inet_ntoa(ls_router));
245 		}
246 		break;
247 	case LS_TYPE_SUM_ABR:
248 		if (flags & F_SUM) {
249 			sprintf(sum_line, "abr %s ", inet_ntoa(ls_stateid));
250 			sum_line += strlen(sum_line);
251 			sprintf(sum_line, "asbr %s ", inet_ntoa(ls_router));
252 			sum_line += strlen(sum_line);
253 		}
254 		if (flags & F_DTAIL) {
255 			(void) snprintf(get_line(0, 0), get_line_remain(),
256 			    "ASBR Summary abr = %s ", inet_ntoa(ls_stateid));
257 			(void) snprintf(get_line(0, 0), get_line_remain(),
258 			    "             asbr = %s ", inet_ntoa(ls_router));
259 		}
260 		break;
261 	case LS_TYPE_ASE:
262 		if (flags & F_SUM) {
263 			sprintf(sum_line, " ase %s", inet_ntoa(ls_stateid));
264 			sum_line += strlen(sum_line);
265 			sprintf(sum_line, " asbr %s", inet_ntoa(ls_router));
266 			sum_line += strlen(sum_line);
267 		}
268 		if (flags & F_DTAIL) {
269 			(void) snprintf(get_line(0, 0), get_line_remain(),
270 			    "AS External LSA ase = %s ", inet_ntoa(ls_stateid));
271 			(void) snprintf(get_line(0, 0), get_line_remain(),
272 			    "                asbr = %s ", inet_ntoa(ls_router));
273 		}
274 
275 		break;
276 	case LS_TYPE_GROUP:
277 		if (flags & F_SUM) {
278 			sprintf(sum_line, " group %s", inet_ntoa(ls_stateid));
279 			sum_line += strlen(sum_line);
280 			sprintf(sum_line, " rtr %s", inet_ntoa(ls_router));
281 			sum_line += strlen(sum_line);
282 		}
283 		if (flags & F_DTAIL) {
284 			(void) snprintf(get_line(0, 0), get_line_remain(),
285 			    "Group LSA %s ", inet_ntoa(ls_stateid));
286 			(void) snprintf(get_line(0, 0), get_line_remain(),
287 			    "          rtr = %s ", inet_ntoa(ls_router));
288 		}
289 		break;
290 	default:
291 		if (flags & F_SUM) {
292 			sprintf(sum_line, " unknown LSA type %d", ls_type);
293 			sum_line += strlen(sum_line);
294 		}
295 		if (flags & F_DTAIL) {
296 			(void) snprintf(get_line(0, 0), get_line_remain(),
297 			    "Unknown LSA type %d", ls_type);
298 		}
299 		break;
300 	}
301 }
302 
303 static void
interpret_ospf_lsa_hdr(int flags,struct lsa_hdr * lsah)304 interpret_ospf_lsa_hdr(int flags, struct lsa_hdr *lsah)
305 {
306 	if (flags & F_SUM)
307 		return;
308 
309 	if (flags & F_DTAIL) {
310 		(void) snprintf(get_line(0, 0), get_line_remain(),
311 		    "Options = %s",
312 		    ospf_print_bits(ospf_option_bits, lsah->ls_options));
313 		(void) snprintf(get_line(0, 0), get_line_remain(),
314 		    "Sequence = %X ", ntohl(lsah->ls_seq));
315 		(void) snprintf(get_line(0, 0), get_line_remain(),
316 		    "Age = %X ", ospf_print_lsa_age(ntohs(lsah->ls_age)));
317 	}
318 
319 	ospf_print_ls_type(flags, lsah->ls_type, lsah->ls_stateid,
320 	    lsah->ls_router);
321 
322 }
323 
324 #define	TRUNC(addr)	((uchar_t *)(addr) > fragend)
325 static int
interpret_ospf_lsa(int flags,struct lsa * lsa,uchar_t * fragend)326 interpret_ospf_lsa(int flags, struct lsa *lsa, uchar_t *fragend)
327 {
328 	uchar_t *ls_end;
329 	int rla_count, k;
330 	struct rlalink *rl;
331 	struct tos_metric *tosp;
332 	struct in_addr *addr;
333 	uint32_t *tosmetric;
334 	struct aslametric *am;
335 	uint32_t tm;
336 	int tos, metric;
337 
338 	interpret_ospf_lsa_hdr(flags, &lsa->ls_hdr);
339 
340 	ls_end = (uchar_t *)lsa + ntohs(lsa->ls_hdr.ls_length);
341 
342 	if (TRUNC(ls_end))
343 		return (-1);
344 
345 	switch (lsa->ls_hdr.ls_type) {
346 
347 	case LS_TYPE_ROUTER:
348 		if (TRUNC(&lsa->lsa_un.un_rla.rla_flags))
349 			return (-1);
350 
351 		if (flags & F_DTAIL) {
352 			(void) ospf_print_bits(ospf_rla_flag_bits,
353 			    lsa->lsa_un.un_rla.rla_flags);
354 		}
355 
356 		if (TRUNC(&lsa->lsa_un.un_rla.rla_count))
357 			return (-1);
358 		rla_count = ntohs(lsa->lsa_un.un_rla.rla_count);
359 
360 		rl = lsa->lsa_un.un_rla.rla_link;
361 		if (TRUNC(rl))
362 			return (-1);
363 
364 		while (rla_count-- != 0) {
365 			if (TRUNC((uchar_t *)rl + sizeof (*rl)))
366 				return (-1);
367 			switch (rl->link_type) {
368 			case RLA_TYPE_VIRTUAL:
369 				if (flags & F_DTAIL) {
370 					(void) snprintf(get_line(0, 0),
371 					    get_line_remain(), "Virtual Link");
372 				}
373 				/* fall through */
374 			case RLA_TYPE_ROUTER:
375 				if (flags & F_DTAIL) {
376 					(void) snprintf(get_line(0, 0),
377 					    get_line_remain(), "Neighbor = %s",
378 					    inet_ntoa(rl->link_id));
379 					(void) snprintf(get_line(0, 0),
380 					    get_line_remain(), "Interface = %s",
381 					    inet_ntoa(rl->link_data));
382 				}
383 				break;
384 			case RLA_TYPE_TRANSIT:
385 				if (flags & F_DTAIL) {
386 					(void) snprintf(get_line(0, 0),
387 					    get_line_remain(),
388 					    "Designated Router = %s",
389 					    inet_ntoa(rl->link_id));
390 					(void) snprintf(get_line(0, 0),
391 					    get_line_remain(), "Interface = %s",
392 					    inet_ntoa(rl->link_data));
393 				}
394 				break;
395 			case RLA_TYPE_STUB:
396 				if (flags & F_DTAIL) {
397 					(void) snprintf(get_line(0, 0),
398 					    get_line_remain(), "Network = %s",
399 					    inet_ntoa(rl->link_id));
400 					(void) snprintf(get_line(0, 0),
401 					    get_line_remain(), "Mask = %s",
402 					    inet_ntoa(rl->link_data));
403 				}
404 				break;
405 			default:
406 				if (flags & F_DTAIL) {
407 					(void) snprintf(get_line(0, 0),
408 					    get_line_remain(),
409 					    "Unknown link type %d",
410 					    rl->link_type);
411 				}
412 
413 			}
414 			if (flags & F_DTAIL) {
415 				(void) snprintf(get_line(0, 0),
416 				    get_line_remain(), "TOS 0 metric = %d",
417 				    ntohs(rl->link_tos0metric));
418 			}
419 			tosp = (struct tos_metric *)(
420 				(uchar_t *)rl + sizeof (rl->link_tos0metric));
421 			for (k = 0; k > (int)rl->link_toscount; ++k, ++tosp) {
422 				if (TRUNC(tosp))
423 					return (-1);
424 				if (flags & F_DTAIL) {
425 					(void) snprintf(get_line(0, 0),
426 					    get_line_remain(),
427 					    "TOS %d metric = %d",
428 					    tosp->tos_type,
429 					    ntohs(tosp->tos_metric));
430 				}
431 
432 			}
433 			rl = (struct rlalink *)((uchar_t *)(rl + 1) +
434 			    ((rl->link_toscount) * sizeof (*tosp)));
435 			if (TRUNC(rl))
436 				return (-1); /* truncated */
437 		}
438 		break;
439 	case LS_TYPE_NETWORK:
440 
441 		if (TRUNC(&lsa->lsa_un.un_nla.nla_mask))
442 			return (-1);
443 
444 		if (flags & F_DTAIL) {
445 			snprintf(get_line(0, 0), get_line_remain(),
446 			    "Mask = %s",
447 			    inet_ntoa(lsa->lsa_un.un_nla.nla_mask));
448 			snprintf(get_line(0, 0), get_line_remain(),
449 			    "Routers:");
450 		}
451 		addr = lsa->lsa_un.un_nla.nla_router;
452 		while ((uchar_t *)addr < ls_end) {
453 			if ((uchar_t *)addr + sizeof (struct in_addr) > ls_end)
454 				return (-1); /* truncated */
455 			if (flags & F_DTAIL) {
456 				snprintf(get_line(0, 0), get_line_remain(),
457 				    "\t%s", inet_ntoa(*addr));
458 			}
459 			++addr;
460 		}
461 		break;
462 	case LS_TYPE_SUM_IP:
463 
464 		if (TRUNC((uchar_t *)&lsa->lsa_un.un_sla.sla_mask +
465 		    sizeof (struct in_addr)))
466 			return (-1);
467 
468 		if (flags & F_DTAIL) {
469 			snprintf(get_line(0, 0), get_line_remain(), "Mask = %s",
470 			    inet_ntoa(lsa->lsa_un.un_sla.sla_mask));
471 		}
472 		/* FALLTHROUGH */
473 	case LS_TYPE_SUM_ABR:
474 		if (TRUNC(&lsa->lsa_un.un_sla.sla_tosmetric))
475 			return (-1);
476 		tosmetric = lsa->lsa_un.un_sla.sla_tosmetric;
477 		while ((uchar_t *)tosmetric < ls_end) {
478 			if ((uchar_t *)tosmetric + sizeof (tm) > fragend)
479 				return (-1); /* truncated */
480 			tm = ntohl(*tosmetric);
481 			tos = (tm & SLA_MASK_TOS) >> SLA_SHIFT_TOS;
482 			metric = tm & SLA_MASK_METRIC;
483 			if (flags & F_DTAIL) {
484 				snprintf(get_line(0, 0), get_line_remain(),
485 				    " tos %d metric %d", tos, metric);
486 			}
487 			++tosmetric;
488 		}
489 		break;
490 	case LS_TYPE_ASE:
491 		if (TRUNC(&lsa->lsa_un.un_asla.asla_mask))
492 			return (-1);
493 		if (flags & F_DTAIL) {
494 			snprintf(get_line(0, 0), get_line_remain(), "Mask = %s",
495 			    inet_ntoa(lsa->lsa_un.un_asla.asla_mask));
496 		}
497 		am = lsa->lsa_un.un_asla.asla_metric;
498 		while ((uchar_t *)am < ls_end) {
499 			if ((uchar_t *)am + sizeof (tm) > fragend)
500 				return (-1); /* truncated */
501 			tm = ntohl(am->asla_tosmetric);
502 			tos = (tm & ASLA_MASK_TOS) >> ASLA_SHIFT_TOS;
503 			metric = tm & ASLA_MASK_METRIC;
504 			if (flags & F_DTAIL) {
505 				snprintf(get_line(0, 0), get_line_remain(),
506 				    " type %d tos %d metric %d",
507 				    (tm & ASLA_FLAG_EXTERNAL) ? 2 : 1,
508 				    tos, metric);
509 			}
510 			if (am->asla_forward.s_addr != 0) {
511 				if (flags & F_DTAIL)  {
512 					snprintf(get_line(0, 0),
513 					    get_line_remain(), " Forward %s",
514 					    inet_ntoa(am->asla_forward));
515 				}
516 			}
517 			if (am->asla_tag.s_addr != 0) {
518 				if (flags & F_DTAIL)  {
519 					snprintf(get_line(0, 0),
520 					    get_line_remain(), " Tag %s",
521 					    inet_ntoa(am->asla_tag));
522 				}
523 			}
524 			++am;
525 		}
526 		break;
527 	default:
528 		if (flags & F_DTAIL)  {
529 			snprintf(get_line(0, 0), get_line_remain(),
530 			    " Unknown LSA type %d", lsa->ls_hdr.ls_type);
531 
532 		}
533 		break;
534 	}
535 	return (0);
536 }
537 #undef TRUNC
538 
539 int
interpret_ospf(int flags,struct ospfhdr * ospf,int iplen,int fraglen)540 interpret_ospf(int flags, struct ospfhdr *ospf, int iplen, int fraglen)
541 {
542 	int nlsa, nlsah = 0;
543 	struct lsa_hdr *lsah;
544 	struct lsr *lsr;
545 	struct lsa *lsa;
546 	boolean_t trunc = B_FALSE;
547 
548 	if ((fraglen < OSPF_MIN_HEADER_SIZE) ||
549 	    (fraglen < ntohs(ospf->ospf_len)))
550 		return (fraglen);	/* incomplete header */
551 
552 	if (fraglen > ntohs(ospf->ospf_len))
553 		fraglen = ntohs(ospf->ospf_len);
554 
555 
556 	if (ospf->ospf_type > OSPF_TYPE_MAX) {
557 		if (flags & F_SUM) {
558 			(void) sprintf(sum_line, "Unknown OSPF TYPE %d \n",
559 			    ospf->ospf_type);
560 			sum_line += strlen(sum_line);
561 		}
562 		if (flags & F_SUM) {
563 			show_header("OSPF:  ", "OSPF Header", fraglen);
564 			show_space();
565 			(void) snprintf(get_line(0, 0), get_line_remain(),
566 			    "Unknown OSPF Type = %d", ospf->ospf_type);
567 		}
568 		return (fraglen);
569 	}
570 
571 	if (flags & F_SUM) {
572 		sum_line = (char *)get_sum_line();
573 		(void) sprintf(sum_line, "OSPF %s RTRID=%s ",
574 		    ospf_types[ospf->ospf_type],
575 		    inet_ntoa(ospf->ospf_routerid));
576 		sum_line += strlen(sum_line);
577 		(void) sprintf(sum_line, "AREA=%s LEN=%d ",
578 		    inet_ntoa(ospf->ospf_areaid),
579 		    ntohs((ushort_t)ospf->ospf_len));
580 		sum_line += strlen(sum_line);
581 	}
582 
583 	if (flags & F_DTAIL) {
584 		show_header("OSPF:  ", "OSPF Header", fraglen);
585 		show_space();
586 		(void) snprintf(get_line(0, 0), get_line_remain(),
587 		    "Version = %d", ospf->ospf_version);
588 		(void) snprintf(get_line(0, 0), get_line_remain(),
589 		    "Type = %s", ospf_types[ospf->ospf_type]);
590 		(void) snprintf(get_line(0, 0), get_line_remain(),
591 		    "Router ID = %s", inet_ntoa(ospf->ospf_routerid));
592 		(void) snprintf(get_line(0, 0), get_line_remain(),
593 		    "Area ID = %s", inet_ntoa(ospf->ospf_areaid));
594 		(void) snprintf(get_line(0, 0), get_line_remain(),
595 		    "Checksum = 0x%x", ospf->ospf_chksum);
596 
597 		if (ospf->ospf_authtype > OSPF_AUTH_TYPE_MAX) {
598 			(void) snprintf(get_line(0, 0), get_line_remain(),
599 			    "Auth = %d (unknown auth type)",
600 			    ospf->ospf_authtype);
601 		} else {
602 			(void) snprintf(get_line(0, 0), get_line_remain(),
603 			    "Auth = %s", ospf_authtypes[ospf->ospf_authtype]);
604 		}
605 	}
606 
607 	if (ospf->ospf_version != 2) {
608 		if (ospf->ospf_version == 3) {
609 			if (flags & F_DTAIL)
610 				snprintf(get_line(0, 0), get_line_remain(),
611 				    "ospfv3 packet in ipv4 header");
612 			return (interpret_ospf6(flags, ospf, iplen, fraglen));
613 		} else  {
614 			return (fraglen);
615 		}
616 	}
617 
618 	switch (ospf->ospf_type) {
619 	case OSPF_TYPE_HELLO:
620 		if (interpret_ospf_hello(flags, ospf, fraglen) < 0)
621 			trunc = B_TRUE;
622 		break;
623 
624 	case OSPF_TYPE_DB:
625 		if (fraglen < OSPF_MIN_HEADER_SIZE + OSPF_MIN_DB_HEADER_SIZE) {
626 			trunc = B_TRUE;
627 			break;
628 		}
629 		if (flags & F_SUM) {
630 			sprintf(sum_line, " %s %s S %X", ospf_print_bits(
631 			    ospf_option_bits, ospf->ospf_db.db_options),
632 			    ospf_print_bits(ospf_db_flags_bits,
633 			    ospf->ospf_db.db_flags),
634 			    ntohl(ospf->ospf_db.db_seq));
635 			sum_line += strlen(sum_line);
636 		}
637 		if (flags & F_DTAIL) {
638 			show_header("OSPF DB:  ", "Database Description Packet",
639 			    fraglen);
640 			show_space();
641 			snprintf(get_line(0, 0), get_line_remain(),
642 			    "Options = %s", ospf_print_bits(
643 			    ospf_option_bits, ospf->ospf_db.db_options));
644 			snprintf(get_line(0, 0), get_line_remain(),
645 			    "Flags = %s", ospf_print_bits(
646 			    ospf_db_flags_bits, ospf->ospf_db.db_flags));
647 			snprintf(get_line(0, 0), get_line_remain(),
648 			    "Sequence = 0x%X", ntohl(ospf->ospf_db.db_seq));
649 			/*  Print all the LS advs */
650 			lsah = ospf->ospf_db.db_lshdr;
651 			while ((uchar_t *)lsah < ((uchar_t *)ospf + fraglen)) {
652 				if ((uchar_t *)lsah + sizeof (struct lsa_hdr) >
653 				    ((uchar_t *)ospf + fraglen)) {
654 					trunc = B_TRUE;
655 					break;
656 				}
657 				interpret_ospf_lsa_hdr(flags, lsah);
658 				++lsah;
659 			}
660 		}
661 		break;
662 
663 	case OSPF_TYPE_LSR:
664 		if (fraglen < OSPF_MIN_HEADER_SIZE + OSPF_MIN_LSR_HEADER_SIZE) {
665 			trunc = B_TRUE;
666 			break;
667 		}
668 		if (flags & F_DTAIL) {
669 			snprintf(get_line(0, 0), get_line_remain(),
670 			    "Link State Request Packet");
671 		}
672 		lsr = ospf->ospf_lsr;
673 		while ((uchar_t *)lsr < ((uchar_t *)ospf + fraglen)) {
674 			if ((uchar_t *)lsr + sizeof (struct lsr) >
675 			    ((uchar_t *)ospf + fraglen)) {
676 				trunc = B_TRUE;
677 				break;
678 			}
679 			if (flags & F_SUM) {
680 				nlsah++;
681 			}
682 			if (flags & F_DTAIL) {
683 				ospf_print_ls_type(flags, ntohl(lsr->ls_type),
684 				    lsr->ls_stateid, lsr->ls_router);
685 			}
686 			++lsr;
687 		}
688 		if (flags & F_SUM) {
689 			sprintf(sum_line, " %d LSAs", nlsah);
690 			sum_line += strlen(sum_line);
691 		}
692 		break;
693 
694 	case OSPF_TYPE_LSU:
695 		if (fraglen < OSPF_MIN_HEADER_SIZE + OSPF_MIN_LSU_HEADER_SIZE) {
696 			trunc = B_TRUE;
697 			break;
698 		}
699 		if (flags & F_DTAIL) {
700 			show_header("OSPF LSU:  ", "Link State Update Packet",
701 			    fraglen);
702 			show_space();
703 		}
704 		lsa = ospf->ospf_lsu.lsu_lsa;
705 		nlsa = ntohl(ospf->ospf_lsu.lsu_count);
706 		if (flags & F_SUM) {
707 			sprintf(sum_line, "%d LSAs", nlsa);
708 			sum_line += strlen(sum_line);
709 			break;
710 		}
711 		while (nlsa-- != 0) {
712 			uchar_t *fragend = (uchar_t *)ospf + fraglen;
713 			if (((uchar_t *)lsa >= fragend) ||
714 			    ((uchar_t *)lsa + sizeof (struct lsa_hdr) >
715 			    fragend) ||
716 			    ((uchar_t *)lsa + ntohs(lsa->ls_hdr.ls_length) >
717 			    fragend)) {
718 				trunc = B_TRUE;
719 				break;
720 			}
721 
722 			if (interpret_ospf_lsa(flags, lsa, fragend) < 0) {
723 				trunc = B_TRUE;
724 				break;
725 			}
726 			lsa = (struct lsa *)((uchar_t *)lsa +
727 			    ntohs(lsa->ls_hdr.ls_length));
728 		}
729 
730 		break;
731 
732 	case OSPF_TYPE_LSA:
733 		if (flags & F_DTAIL) {
734 			show_header("OSPF LSA:  ", "Link State Ack Packet",
735 			    fraglen);
736 			show_space();
737 		}
738 		lsah = ospf->ospf_lsa.lsa_lshdr;
739 		nlsah = 0;
740 		while ((uchar_t *)lsah < ((uchar_t *)ospf + fraglen)) {
741 			if ((uchar_t *)lsah + sizeof (struct lsa_hdr) >
742 			    ((uchar_t *)ospf + fraglen)) {
743 				trunc = B_TRUE;
744 				break;
745 			}
746 			nlsah++;
747 			if (flags & F_DTAIL)
748 				interpret_ospf_lsa_hdr(flags, lsah);
749 			++lsah;
750 		}
751 		if (flags & F_SUM) {
752 			sprintf(sum_line, "%d LSAs", nlsah);
753 			sum_line += strlen(sum_line);
754 		}
755 		break;
756 
757 	default:
758 		/* NOTREACHED */
759 		break;
760 	}
761 	if (trunc) {
762 		if (flags & F_SUM) {
763 			sprintf(sum_line, "--truncated");
764 			sum_line += strlen(sum_line);
765 		}
766 		if (flags & F_DTAIL)
767 			snprintf(get_line(0, 0), get_line_remain(),
768 			    "--truncated");
769 	}
770 
771 	return (fraglen);
772 }
773