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