xref: /openbsd/usr.sbin/tcpdump/print-icmp6.c (revision 898184e3)
1 /*	$OpenBSD: print-icmp6.c,v 1.10 2011/09/17 19:56:19 bluhm Exp $	*/
2 
3 /*
4  * Copyright (c) 1988, 1989, 1990, 1991, 1993, 1994
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that: (1) source code distributions
9  * retain the above copyright notice and this paragraph in its entirety, (2)
10  * distributions including binary code include the above copyright notice and
11  * this paragraph in its entirety in the documentation or other materials
12  * provided with the distribution, and (3) all advertising materials mentioning
13  * features or use of this software display the following acknowledgement:
14  * ``This product includes software developed by the University of California,
15  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
16  * the University nor the names of its contributors may be used to endorse
17  * or promote products derived from this software without specific prior
18  * written permission.
19  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
20  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
21  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
22  */
23 
24 #ifdef INET6
25 
26 #include <ctype.h>
27 
28 #include <sys/param.h>
29 #include <sys/time.h>
30 #include <sys/types.h>
31 #include <sys/socket.h>
32 
33 #include <net/if.h>
34 
35 #include <netinet/in.h>
36 #include <netinet/if_ether.h>
37 #include <netinet/in_systm.h>
38 #include <netinet/ip.h>
39 #include <netinet/ip_icmp.h>
40 #include <netinet/ip_var.h>
41 #include <netinet/udp.h>
42 #include <netinet/udp_var.h>
43 #include <netinet/tcp.h>
44 
45 #include <arpa/inet.h>
46 
47 #include <stdio.h>
48 
49 #include <netinet/ip6.h>
50 #include <netinet/icmp6.h>
51 #include <netinet6/mld6.h>
52 
53 #include "interface.h"
54 #include "addrtoname.h"
55 
56 void icmp6_opt_print(const u_char *, int);
57 void mld6_print(const u_char *);
58 void mldv2_query_print(const u_char *, u_int);
59 void mldv2_report_print(const u_char *, u_int);
60 
61 /* mldv2 report types */
62 static struct tok mldv2report2str[] = {
63 	{ 1,	"is_in" },
64 	{ 2,	"is_ex" },
65 	{ 3,	"to_in" },
66 	{ 4,	"to_ex" },
67 	{ 5,	"allow" },
68 	{ 6,	"block" },
69 	{ 0,	NULL }
70 };
71 
72 #define MLDV2_QUERY_QRV			24
73 #define MLDV2_QUERY_QQIC 		25
74 #define MLDV2_QUERY_NSRCS		26
75 #define MLDV2_QUERY_SRC0		28
76 
77 #define MLDV2_QUERY_QRV_SFLAG	(1 << 3)
78 
79 #define MLD_V1_QUERY_MINLEN		24
80 
81 #define MLDV2_REPORT_GROUP0		8
82 
83 #define MLDV2_REPORT_MINLEN		8
84 #define MLDV2_REPORT_MINGRPLEN	20
85 
86 #define MLDV2_RGROUP_NSRCS		2
87 #define MLDV2_RGROUP_MADDR		4
88 
89 #define MLDV2_MRC_FLOAT			(1 << 15)
90 #define MLDV2_MRD(mant, exp)	((mant | 0x1000) << (exp + 3))
91 
92 #define MLDV2_QQIC_FLOAT		(1 << 7)
93 #define MLDV2_QQI(mant, exp)	((mant | 0x10) << (exp + 3))
94 
95 void
96 icmp6_print(const u_char *bp, u_int length, const u_char *bp2)
97 {
98 	register const struct icmp6_hdr *dp;
99 	register const struct ip6_hdr *ip;
100 	register const char *str;
101 	register const struct ip6_hdr *oip;
102 	register const struct udphdr *ouh;
103 	register int hlen, dport;
104 	register const u_char *ep;
105 	char buf[256];
106 	int icmp6len;
107 
108 #if 0
109 #define TCHECK(var) if ((u_char *)&(var) > ep - sizeof(var)) goto trunc
110 #endif
111 
112 	dp = (struct icmp6_hdr *)bp;
113 	ip = (struct ip6_hdr *)bp2;
114 	oip = (struct ip6_hdr *)(dp + 1);
115 	str = buf;
116 	/* 'ep' points to the end of avaible data. */
117 	ep = snapend;
118 	if (ip->ip6_plen)
119 		icmp6len = (ntohs(ip->ip6_plen) + sizeof(struct ip6_hdr) -
120 			    (bp - bp2));
121 	else			/* XXX: jumbo payload case... */
122 		icmp6len = snapend - bp;
123 
124 #if 0
125         (void)printf("%s > %s: ",
126 		ip6addr_string(&ip->ip6_src),
127 		ip6addr_string(&ip->ip6_dst));
128 #endif
129 
130 	TCHECK(dp->icmp6_code);
131 	switch (dp->icmp6_type) {
132 	case ICMP6_DST_UNREACH:
133 		TCHECK(oip->ip6_dst);
134 		switch (dp->icmp6_code) {
135 		case ICMP6_DST_UNREACH_NOROUTE:
136 			printf("icmp6: %s unreachable route",
137 			       ip6addr_string(&oip->ip6_dst));
138 			break;
139 		case ICMP6_DST_UNREACH_ADMIN:
140 			printf("icmp6: %s unreachable prohibited",
141 			       ip6addr_string(&oip->ip6_dst));
142 			break;
143 #ifdef ICMP6_DST_UNREACH_BEYONDSCOPE
144 		case ICMP6_DST_UNREACH_BEYONDSCOPE:
145 #else
146 		case ICMP6_DST_UNREACH_NOTNEIGHBOR:
147 #endif
148 			printf("icmp6: %s beyond scope of source address %s",
149 			       ip6addr_string(&oip->ip6_dst),
150 			       ip6addr_string(&oip->ip6_src));
151 			break;
152 		case ICMP6_DST_UNREACH_ADDR:
153 			printf("icmp6: %s unreachable address",
154 			       ip6addr_string(&oip->ip6_dst));
155 			break;
156 		case ICMP6_DST_UNREACH_NOPORT:
157 			TCHECK(oip->ip6_nxt);
158 			hlen = sizeof(struct ip6_hdr);
159 			ouh = (struct udphdr *)(((u_char *)oip) + hlen);
160 			TCHECK(ouh->uh_dport);
161 			dport = ntohs(ouh->uh_dport);
162 			switch (oip->ip6_nxt) {
163 			case IPPROTO_TCP:
164 				printf("icmp6: %s tcp port %s unreachable",
165 					ip6addr_string(&oip->ip6_dst),
166 					tcpport_string(dport));
167 				break;
168 			case IPPROTO_UDP:
169 				printf("icmp6: %s udp port %s unreachable",
170 					ip6addr_string(&oip->ip6_dst),
171 					udpport_string(dport));
172 				break;
173 			default:
174 				printf("icmp6: %s protocol %d port %d unreachable",
175 					ip6addr_string(&oip->ip6_dst),
176 					oip->ip6_nxt, dport);
177 				break;
178 			}
179 			break;
180 		default:
181 			printf("icmp6: %s unreachable code-#%d",
182 				ip6addr_string(&oip->ip6_dst),
183 				dp->icmp6_code);
184 			break;
185 		}
186 		break;
187 	case ICMP6_PACKET_TOO_BIG:
188 		TCHECK(dp->icmp6_mtu);
189 		printf("icmp6: too big %u", (u_int32_t)ntohl(dp->icmp6_mtu));
190 		break;
191 	case ICMP6_TIME_EXCEEDED:
192 		TCHECK(oip->ip6_dst);
193 		switch (dp->icmp6_code) {
194 		case ICMP6_TIME_EXCEED_TRANSIT:
195 			printf("icmp6: time exceeded in-transit for %s",
196 				ip6addr_string(&oip->ip6_dst));
197 			break;
198 		case ICMP6_TIME_EXCEED_REASSEMBLY:
199 			printf("icmp6: ip6 reassembly time exceeded");
200 			break;
201 		default:
202 			printf("icmp6: time exceeded code-#%d",
203 				dp->icmp6_code);
204 			break;
205 		}
206 		break;
207 	case ICMP6_PARAM_PROB:
208 		TCHECK(oip->ip6_dst);
209 		switch (dp->icmp6_code) {
210 		case ICMP6_PARAMPROB_HEADER:
211 			printf("icmp6: parameter problem errorneous - octet %u",
212 				(u_int32_t)ntohl(dp->icmp6_pptr));
213 			break;
214 		case ICMP6_PARAMPROB_NEXTHEADER:
215 			printf("icmp6: parameter problem next header - octet %u",
216 				(u_int32_t)ntohl(dp->icmp6_pptr));
217 			break;
218 		case ICMP6_PARAMPROB_OPTION:
219 			printf("icmp6: parameter problem option - octet %u",
220 				(u_int32_t)ntohl(dp->icmp6_pptr));
221 			break;
222 		default:
223 			printf("icmp6: parameter problem code-#%d",
224 			       dp->icmp6_code);
225 			break;
226 		}
227 		break;
228 	case ICMP6_ECHO_REQUEST:
229 	case ICMP6_ECHO_REPLY:
230 		printf("icmp6: echo %s", dp->icmp6_type == ICMP6_ECHO_REQUEST ?
231 		    "request" : "reply");
232 		if (vflag) {
233 			TCHECK(dp->icmp6_seq);
234 			printf(" (id:%04x seq:%u)",
235 			    ntohs(dp->icmp6_id), ntohs(dp->icmp6_seq));
236 		}
237 		break;
238 	case ICMP6_MEMBERSHIP_QUERY:
239 		printf("icmp6: multicast listener query ");
240 		if (length == MLD_V1_QUERY_MINLEN) {
241 			mld6_print((const u_char *)dp);
242 		} else if (length >= MLD_V2_QUERY_MINLEN) {
243 			printf("v2 ");
244 			mldv2_query_print((const u_char *)dp, length);
245 		} else {
246 			printf("unknown-version (len %u) ", length);
247 		}
248 		break;
249 	case ICMP6_MEMBERSHIP_REPORT:
250 		printf("icmp6: multicast listener report ");
251 		mld6_print((const u_char *)dp);
252 		break;
253 	case ICMP6_MEMBERSHIP_REDUCTION:
254 		printf("icmp6: multicast listener done ");
255 		mld6_print((const u_char *)dp);
256 		break;
257 	case ND_ROUTER_SOLICIT:
258 		printf("icmp6: router solicitation ");
259 		if (vflag) {
260 #define RTSOLLEN 8
261 		        icmp6_opt_print((const u_char *)dp + RTSOLLEN,
262 					icmp6len - RTSOLLEN);
263 		}
264 		break;
265 	case ND_ROUTER_ADVERT:
266 		printf("icmp6: router advertisement");
267 		if (vflag) {
268 			struct nd_router_advert *p;
269 
270 			p = (struct nd_router_advert *)dp;
271 			TCHECK(p->nd_ra_retransmit);
272 			printf("(chlim=%d, ", (int)p->nd_ra_curhoplimit);
273 			if (p->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED)
274 				printf("M");
275 			if (p->nd_ra_flags_reserved & ND_RA_FLAG_OTHER)
276 				printf("O");
277 			if (p->nd_ra_flags_reserved != 0)
278 				printf(" ");
279 			printf("router_ltime=%d, ", ntohs(p->nd_ra_router_lifetime));
280 			printf("reachable_time=%u, ",
281 				(u_int32_t)ntohl(p->nd_ra_reachable));
282 			printf("retrans_time=%u)",
283 				(u_int32_t)ntohl(p->nd_ra_retransmit));
284 #define RTADVLEN 16
285 		        icmp6_opt_print((const u_char *)dp + RTADVLEN,
286 					icmp6len - RTADVLEN);
287 		}
288 		break;
289 	case ND_NEIGHBOR_SOLICIT:
290 	    {
291 		struct nd_neighbor_solicit *p;
292 		p = (struct nd_neighbor_solicit *)dp;
293 		TCHECK(p->nd_ns_target);
294 		printf("icmp6: neighbor sol: who has %s",
295 			ip6addr_string(&p->nd_ns_target));
296 		if (vflag) {
297 #define NDSOLLEN 24
298 		        icmp6_opt_print((const u_char *)dp + NDSOLLEN,
299 					icmp6len - NDSOLLEN);
300 		}
301 	    }
302 		break;
303 	case ND_NEIGHBOR_ADVERT:
304 	    {
305 		struct nd_neighbor_advert *p;
306 
307 		p = (struct nd_neighbor_advert *)dp;
308 		TCHECK(p->nd_na_target);
309 		printf("icmp6: neighbor adv: tgt is %s",
310 			ip6addr_string(&p->nd_na_target));
311                 if (vflag) {
312 #define ND_NA_FLAG_ALL	\
313 	(ND_NA_FLAG_ROUTER|ND_NA_FLAG_SOLICITED|ND_NA_FLAG_OVERRIDE)
314 			/* we don't need ntohl() here.  see advanced-api-04. */
315 			if (p->nd_na_flags_reserved &  ND_NA_FLAG_ALL) {
316 #undef ND_NA_FLAG_ALL
317 				u_int32_t flags;
318 
319 				flags = p->nd_na_flags_reserved;
320 				printf("(");
321 				if (flags & ND_NA_FLAG_ROUTER)
322 					printf("R");
323 				if (flags & ND_NA_FLAG_SOLICITED)
324 					printf("S");
325 				if (flags & ND_NA_FLAG_OVERRIDE)
326 					printf("O");
327 				printf(")");
328 			}
329 #define NDADVLEN 24
330 		        icmp6_opt_print((const u_char *)dp + NDADVLEN,
331 					icmp6len - NDADVLEN);
332 		}
333 	    }
334 		break;
335 	case ND_REDIRECT:
336 	{
337 #define RDR(i) ((struct nd_redirect *)(i))
338 		char tgtbuf[INET6_ADDRSTRLEN], dstbuf[INET6_ADDRSTRLEN];
339 
340 		TCHECK(RDR(dp)->nd_rd_dst);
341 		inet_ntop(AF_INET6, &RDR(dp)->nd_rd_target,
342 			  tgtbuf, INET6_ADDRSTRLEN);
343 		inet_ntop(AF_INET6, &RDR(dp)->nd_rd_dst,
344 			  dstbuf, INET6_ADDRSTRLEN);
345 		printf("icmp6: redirect %s to %s", dstbuf, tgtbuf);
346 #define REDIRECTLEN 40
347 		if (vflag) {
348 			icmp6_opt_print((const u_char *)dp + REDIRECTLEN,
349 					icmp6len - REDIRECTLEN);
350 		}
351 		break;
352 	}
353 	case ICMP6_ROUTER_RENUMBERING:
354 		switch (dp->icmp6_code) {
355 		case ICMP6_ROUTER_RENUMBERING_COMMAND:
356 			printf("icmp6: router renum command");
357 			break;
358 		case ICMP6_ROUTER_RENUMBERING_RESULT:
359 			printf("icmp6: router renum result");
360 			break;
361 		default:
362 			printf("icmp6: router renum code-#%d", dp->icmp6_code);
363 			break;
364 		}
365 		break;
366 #ifdef ICMP6_WRUREQUEST
367 	case ICMP6_WRUREQUEST:	/*ICMP6_FQDN_QUERY*/
368 	    {
369 		int siz;
370 		siz = ep - (u_char *)(dp + 1);
371 		if (siz == 4)
372 			printf("icmp6: who-are-you request");
373 		else {
374 			printf("icmp6: FQDN request");
375 			if (vflag) {
376 				if (siz < 8)
377 					printf("?(icmp6_data %d bytes)", siz);
378 				else if (8 < siz)
379 					printf("?(extra %d bytes)", siz - 8);
380 			}
381 		}
382 		break;
383 	    }
384 #endif /*ICMP6_WRUREQUEST*/
385 #ifdef ICMP6_WRUREPLY
386 	case ICMP6_WRUREPLY:	/*ICMP6_FQDN_REPLY*/
387 	    {
388 		enum { UNKNOWN, WRU, FQDN } mode = UNKNOWN;
389 		u_char const *buf;
390 		u_char const *cp = NULL;
391 
392 		buf = (u_char *)(dp + 1);
393 
394 		/* fair guess */
395 		if (buf[12] == ep - buf - 13)
396 			mode = FQDN;
397 		else if (dp->icmp6_code == 1)
398 			mode = FQDN;
399 
400 		/* wild guess */
401 		if (mode == UNKNOWN) {
402 			cp = buf + 4;
403 			while (cp < ep) {
404 				if (!isprint(*cp++))
405 					mode = FQDN;
406 			}
407 		}
408 #ifndef abs
409 #define abs(a)	((0 < (a)) ? (a) : -(a))
410 #endif
411 		if (mode == UNKNOWN && 2 < abs(buf[12] - (ep - buf - 13)))
412 			mode = WRU;
413 		if (mode == UNKNOWN)
414 			mode = FQDN;
415 
416 		if (mode == WRU) {
417 			cp = buf + 4;
418 			printf("icmp6: who-are-you reply(\"");
419 		} else if (mode == FQDN) {
420 			cp = buf + 13;
421 			printf("icmp6: FQDN reply(\"");
422 		}
423 		for (; cp < ep; cp++)
424 			printf((isprint(*cp) ? "%c" : "\\%03o"), *cp);
425 		printf("\"");
426 		if (vflag) {
427 			printf(",%s", mode == FQDN ? "FQDN" : "WRU");
428 			if (mode == FQDN) {
429 				int ttl;
430 				ttl = (int)ntohl(*(u_int32_t *)&buf[8]);
431 				if (dp->icmp6_code == 1)
432 					printf(",TTL=unknown");
433 				else if (ttl < 0)
434 					printf(",TTL=%d:invalid", ttl);
435 				else
436 					printf(",TTL=%d", ttl);
437 				if (buf[12] != ep - buf - 13) {
438 					(void)printf(",invalid namelen:%d/%u",
439 						buf[12],
440 						(unsigned int)(ep - buf - 13));
441 				}
442 			}
443 		}
444 		printf(")");
445 		break;
446 	    }
447 #endif /*ICMP6_WRUREPLY*/
448 	case MLDV2_LISTENER_REPORT:
449 		printf("multicast listener report v2");
450 		mldv2_report_print((const u_char *) dp, length);
451 		break;
452 	default:
453 		printf("icmp6: type-#%d", dp->icmp6_type);
454 		break;
455 	}
456 	return;
457 trunc:
458 	fputs("[|icmp6]", stdout);
459 #if 0
460 #undef TCHECK
461 #endif
462 }
463 
464 void
465 icmp6_opt_print(register const u_char *bp, int resid)
466 {
467 	register const struct nd_opt_hdr *op;
468 	register const struct nd_opt_hdr *opl;	/* why there's no struct? */
469 	register const struct nd_opt_prefix_info *opp;
470 	register const struct icmp6_opts_redirect *opr;
471 	register const struct nd_opt_mtu *opm;
472 	register const u_char *ep;
473 	int	opts_len;
474 #if 0
475 	register const struct ip6_hdr *ip;
476 	register const char *str;
477 	register const struct ip6_hdr *oip;
478 	register const struct udphdr *ouh;
479 	register int hlen, dport;
480 	char buf[256];
481 #endif
482 
483 #if 0
484 #define TCHECK(var) if ((u_char *)&(var) > ep - sizeof(var)) goto trunc
485 #endif
486 #define ECHECK(var) if ((u_char *)&(var) > ep - sizeof(var)) return
487 
488 	op = (struct nd_opt_hdr *)bp;
489 #if 0
490 	ip = (struct ip6_hdr *)bp2;
491 	oip = &dp->icmp6_ip6;
492 	str = buf;
493 #endif
494 	/* 'ep' points to the end of avaible data. */
495 	ep = snapend;
496 
497 	ECHECK(op->nd_opt_len);
498 	if (resid <= 0)
499 		return;
500 	if (op->nd_opt_len == 0)
501 		goto trunc;
502 	if (bp + (op->nd_opt_len << 3) > ep)
503 		goto trunc;
504 	switch (op->nd_opt_type) {
505 	case ND_OPT_SOURCE_LINKADDR:
506 		opl = (struct nd_opt_hdr *)op;
507 #if 1
508 		if ((u_char *)opl + (opl->nd_opt_len << 3) > ep)
509 			goto trunc;
510 #else
511 		TCHECK((u_char *)opl + (opl->nd_opt_len << 3) - 1);
512 #endif
513 		printf("(src lladdr: %s",
514 			etheraddr_string((u_char *)(opl + 1)));
515 		if (opl->nd_opt_len != 1)
516 			printf("!");
517 		printf(")");
518 		icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3),
519 				resid - (op->nd_opt_len << 3));
520 		break;
521 	case ND_OPT_TARGET_LINKADDR:
522 		opl = (struct nd_opt_hdr *)op;
523 #if 1
524 		if ((u_char *)opl + (opl->nd_opt_len << 3) > ep)
525 			goto trunc;
526 #else
527 		TCHECK((u_char *)opl + (opl->nd_opt_len << 3) - 1);
528 #endif
529 		printf("(tgt lladdr: %s",
530 			etheraddr_string((u_char *)(opl + 1)));
531 		if (opl->nd_opt_len != 1)
532 			printf("!");
533 		printf(")");
534 		icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3),
535 				resid - (op->nd_opt_len << 3));
536 		break;
537 	case ND_OPT_PREFIX_INFORMATION:
538 		opp = (struct nd_opt_prefix_info *)op;
539 		TCHECK(opp->nd_opt_pi_prefix);
540 		printf("(prefix info: ");
541 		if (opp->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK)
542 		       printf("L");
543 		if (opp->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_AUTO)
544 		       printf("A");
545 		if (opp->nd_opt_pi_flags_reserved)
546 			printf(" ");
547 		printf("valid_ltime=");
548 		if ((u_int32_t)ntohl(opp->nd_opt_pi_valid_time) == ~0U)
549 			printf("infinity");
550 		else {
551 			printf("%u", (u_int32_t)ntohl(opp->nd_opt_pi_valid_time));
552 		}
553 		printf(", ");
554 		printf("preferred_ltime=");
555 		if ((u_int32_t)ntohl(opp->nd_opt_pi_preferred_time) == ~0U)
556 			printf("infinity");
557 		else {
558 			printf("%u", (u_int32_t)ntohl(opp->nd_opt_pi_preferred_time));
559 		}
560 		printf(", ");
561 		printf("prefix=%s/%d", ip6addr_string(&opp->nd_opt_pi_prefix),
562 			opp->nd_opt_pi_prefix_len);
563 		if (opp->nd_opt_pi_len != 4)
564 			printf("!");
565 		printf(")");
566 		icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3),
567 				resid - (op->nd_opt_len << 3));
568 		break;
569 	case ND_OPT_REDIRECTED_HEADER:
570 		opr = (struct icmp6_opts_redirect *)op;
571 		printf("(redirect)");
572 		/* xxx */
573 		icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3),
574 				resid - (op->nd_opt_len << 3));
575 		break;
576 	case ND_OPT_MTU:
577 		opm = (struct nd_opt_mtu *)op;
578 		TCHECK(opm->nd_opt_mtu_mtu);
579 		printf("(mtu: ");
580 		printf("mtu=%u", (u_int32_t)ntohl(opm->nd_opt_mtu_mtu));
581 		if (opm->nd_opt_mtu_len != 1)
582 			printf("!");
583 		printf(")");
584 		icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3),
585 				resid - (op->nd_opt_len << 3));
586 		break;
587 	default:
588 		opts_len = op->nd_opt_len;
589 		printf("(unknown opt_type=%d, opt_len=%d)",
590 		       op->nd_opt_type, opts_len);
591 		if (opts_len == 0)
592 			opts_len = 1; /* XXX */
593 		icmp6_opt_print((const u_char *)op + (opts_len << 3),
594 				resid - (opts_len << 3));
595 		break;
596 	}
597 	return;
598  trunc:
599 	fputs("[ndp opt]", stdout);
600 	return;
601 #if 0
602 #undef TCHECK
603 #endif
604 #undef ECHECK
605 }
606 
607 void
608 mld6_print(register const u_char *bp)
609 {
610 	register struct mld6_hdr *mp = (struct mld6_hdr *)bp;
611 	register const u_char *ep;
612 
613 	/* 'ep' points to the end of avaible data. */
614 	ep = snapend;
615 
616 	if ((u_char *)mp + sizeof(*mp) > ep)
617 		return;
618 
619 	printf("max resp delay: %d ", ntohs(mp->mld6_maxdelay));
620 	printf("addr: %s", ip6addr_string(&mp->mld6_addr));
621 
622 	return;
623 }
624 
625 void
626 mldv2_report_print(const u_char *bp, u_int len)
627 {
628 	struct icmp6_hdr *icp = (struct icmp6_hdr *) bp;
629 	u_int group, nsrcs, ngroups;
630 	u_int i, j;
631 
632 	if (len < MLDV2_REPORT_MINLEN) {
633 		printf(" [invalid len %d]", len);
634 		return;
635 	}
636 
637 	TCHECK(icp->icmp6_data16[1]);
638 	ngroups = ntohs(icp->icmp6_data16[1]);
639 	printf(", %d group record(s)", ngroups);
640 	if (vflag > 0) {
641 		/* Print the group records */
642 		group = MLDV2_REPORT_GROUP0;
643 		for (i = 0; i < ngroups; i++) {
644 			/* type(1) + auxlen(1) + numsrc(2) + grp(16) */
645 			if (len < group + MLDV2_REPORT_MINGRPLEN) {
646 				printf(" [invalid number of groups]");
647 				return;
648 			}
649 			TCHECK2(bp[group + MLDV2_RGROUP_MADDR],
650 			    sizeof(struct in6_addr));
651 			printf(" [gaddr %s",
652 			    ip6addr_string(&bp[group + MLDV2_RGROUP_MADDR]));
653 			printf(" %s", tok2str(mldv2report2str,
654 			    " [v2-report-#%d]", bp[group]));
655 			nsrcs = (bp[group + MLDV2_RGROUP_NSRCS] << 8) +
656 			    bp[group + MLDV2_RGROUP_NSRCS + 1];
657 			/* Check the number of sources and print them */
658 			if (len < group + MLDV2_REPORT_MINGRPLEN +
659 				    (nsrcs * sizeof(struct in6_addr))) {
660 				printf(" [invalid number of sources %d]", nsrcs);
661 				return;
662 			}
663 			if (vflag == 1)
664 				printf(", %d source(s)", nsrcs);
665 			else {
666 				/* Print the sources */
667 				(void)printf(" {");
668 				for (j = 0; j < nsrcs; j++) {
669 					TCHECK2(bp[group +
670 					    MLDV2_REPORT_MINGRPLEN +
671 					    j * sizeof(struct in6_addr)],
672 					    sizeof(struct in6_addr));
673 					printf(" %s", ip6addr_string(&bp[group +
674 					    MLDV2_REPORT_MINGRPLEN + j *
675 					    sizeof(struct in6_addr)]));
676 				}
677 				(void)printf(" }");
678 			}
679 			/* Next group record */
680 			group += MLDV2_REPORT_MINGRPLEN + nsrcs *
681 			    sizeof(struct in6_addr);
682 			printf("]");
683 		}
684 	}
685 	return;
686 trunc:
687 	(void)printf("[|icmp6]");
688 	return;
689 }
690 
691 void
692 mldv2_query_print(const u_char *bp, u_int len)
693 {
694 	struct icmp6_hdr *icp = (struct icmp6_hdr *) bp;
695 	u_int mrc, qqic;
696 	int mrd, qqi;
697 	int mant, exp;
698 	u_int nsrcs;
699 	u_int i;
700 
701 	if (len < MLD_V2_QUERY_MINLEN) {
702 		printf(" [invalid len %d]", len);
703 		return;
704 	}
705 	TCHECK(icp->icmp6_data16[0]);
706 	mrc = ntohs(icp->icmp6_data16[0]);
707 	if (mrc & MLDV2_MRC_FLOAT) {
708 		mant = MLD_MRC_MANT(mrc);
709 		exp = MLD_MRC_EXP(mrc);
710 		mrd = MLDV2_MRD(mant, exp);
711 	} else {
712 		mrd = mrc;
713 	}
714 	if (vflag) {
715 		(void)printf(" [max resp delay=%d]", mrd);
716 	}
717 	TCHECK2(bp[8], sizeof(struct in6_addr));
718 	printf(" [gaddr %s", ip6addr_string(&bp[8]));
719 
720 	if (vflag) {
721 		TCHECK(bp[MLDV2_QUERY_QQIC]);
722 		if (bp[MLDV2_QUERY_QRV] & MLDV2_QUERY_QRV_SFLAG) {
723 			printf(" sflag");
724 		}
725 		if (MLD_QRV(bp[MLDV2_QUERY_QRV])) {
726 			printf(" robustness=%d", MLD_QRV(bp[MLDV2_QUERY_QRV]));
727 		}
728 		qqic = bp[MLDV2_QUERY_QQIC];
729 		if (qqic & MLDV2_QQIC_FLOAT) {
730 			mant = MLD_QQIC_MANT(qqic);
731 			exp = MLD_QQIC_EXP(qqic);
732 			qqi = MLDV2_QQI(mant, exp);
733 		} else {
734 			qqi = bp[MLDV2_QUERY_QQIC];
735 		}
736 		printf(" qqi=%d", qqi);
737 	}
738 
739 	TCHECK2(bp[MLDV2_QUERY_NSRCS], 2);
740 	nsrcs = ntohs(*(u_short *)&bp[MLDV2_QUERY_NSRCS]);
741 	if (nsrcs > 0) {
742 		if (len < MLD_V2_QUERY_MINLEN + nsrcs * sizeof(struct in6_addr))
743 			printf(" [invalid number of sources]");
744 		else if (vflag > 1) {
745 			printf(" {");
746 			for (i = 0; i < nsrcs; i++) {
747 				TCHECK2(bp[MLDV2_QUERY_SRC0 + i *
748 				    sizeof(struct in6_addr)],
749 				    sizeof(struct in6_addr));
750 				printf(" %s",
751 				    ip6addr_string(&bp[MLDV2_QUERY_SRC0 + i *
752 				    sizeof(struct in6_addr)]));
753 			}
754 			printf(" }");
755 		} else
756 			printf(", %d source(s)", nsrcs);
757 	}
758 	printf("]");
759 	return;
760 trunc:
761 	(void)printf("[|icmp6]");
762 	return;
763 }
764 
765 
766 #endif /* INET6 */
767