GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/tcpdump/print-icmp6.c Lines: 0 446 0.0 %
Date: 2017-11-07 Branches: 0 340 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: print-icmp6.c,v 1.21 2016/07/28 13:05:52 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/time.h>
29
#include <sys/types.h>
30
#include <sys/socket.h>
31
32
#include <net/if.h>
33
34
#include <netinet/in.h>
35
#include <netinet/if_ether.h>
36
#include <netinet/ip.h>
37
#include <netinet/ip_icmp.h>
38
#include <netinet/ip_var.h>
39
#include <netinet/udp.h>
40
#include <netinet/udp_var.h>
41
#include <netinet/tcp.h>
42
43
#include <arpa/inet.h>
44
45
#include <stdio.h>
46
#include <stdlib.h>
47
#include <string.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
#include "extract.h"
56
57
void icmp6_opt_print(const u_char *, int);
58
void mld6_print(const u_char *);
59
void mldv2_query_print(const u_char *, u_int);
60
void mldv2_report_print(const u_char *, u_int);
61
62
/* mldv2 report types */
63
static struct tok mldv2report2str[] = {
64
	{ 1,	"is_in" },
65
	{ 2,	"is_ex" },
66
	{ 3,	"to_in" },
67
	{ 4,	"to_ex" },
68
	{ 5,	"allow" },
69
	{ 6,	"block" },
70
	{ 0,	NULL }
71
};
72
73
#define MLDV2_QUERY_QRV			24
74
#define MLDV2_QUERY_QQIC 		25
75
#define MLDV2_QUERY_NSRCS		26
76
#define MLDV2_QUERY_SRC0		28
77
78
#define MLDV2_QUERY_QRV_SFLAG	(1 << 3)
79
80
#define MLD_V1_QUERY_MINLEN		24
81
82
#define MLDV2_REPORT_GROUP0		8
83
84
#define MLDV2_REPORT_MINLEN		8
85
#define MLDV2_REPORT_MINGRPLEN	20
86
87
#define MLDV2_RGROUP_NSRCS		2
88
#define MLDV2_RGROUP_MADDR		4
89
90
#define MLDV2_MRC_FLOAT			(1 << 15)
91
#define MLDV2_MRD(mant, exp)	((mant | 0x1000) << (exp + 3))
92
93
#define MLDV2_QQIC_FLOAT		(1 << 7)
94
#define MLDV2_QQI(mant, exp)	((mant | 0x10) << (exp + 3))
95
96
static int
97
icmp6_cksum(const struct ip6_hdr *ip6, const struct icmp6_hdr *icmp6,
98
    u_int len)
99
{
100
	union {
101
		struct {
102
			struct in6_addr ph_src;
103
			struct in6_addr ph_dst;
104
			u_int32_t       ph_len;
105
			u_int8_t        ph_zero[3];
106
			u_int8_t        ph_nxt;
107
		} ph;
108
		u_int16_t pa[20];
109
	} phu;
110
	size_t i;
111
	u_int32_t sum = 0;
112
113
	/* pseudo-header */
114
	memset(&phu, 0, sizeof(phu));
115
	phu.ph.ph_src = ip6->ip6_src;
116
	phu.ph.ph_dst = ip6->ip6_dst;
117
	phu.ph.ph_len = htonl(len);
118
	phu.ph.ph_nxt = IPPROTO_ICMPV6;
119
120
	for (i = 0; i < sizeof(phu.pa) / sizeof(phu.pa[0]); i++)
121
		sum += phu.pa[i];
122
123
	return in_cksum((u_short *)icmp6, len, sum);
124
}
125
126
void
127
icmp6_print(const u_char *bp, u_int length, const u_char *bp2)
128
{
129
	const struct icmp6_hdr *dp;
130
	const struct ip6_hdr *ip;
131
	const char *str;
132
	const struct ip6_hdr *oip;
133
	const struct udphdr *ouh;
134
	int hlen, dport;
135
	const u_char *ep;
136
	char buf[256];
137
	int icmp6len;
138
139
#if 0
140
#define TCHECK(var) if ((u_char *)&(var) > ep - sizeof(var)) goto trunc
141
#endif
142
143
	dp = (struct icmp6_hdr *)bp;
144
	ip = (struct ip6_hdr *)bp2;
145
	oip = (struct ip6_hdr *)(dp + 1);
146
	str = buf;
147
	/* 'ep' points to the end of avaible data. */
148
	ep = snapend;
149
	if (ip->ip6_plen)
150
		icmp6len = (ntohs(ip->ip6_plen) + sizeof(struct ip6_hdr) -
151
			    (bp - bp2));
152
	else			/* XXX: jumbo payload case... */
153
		icmp6len = snapend - bp;
154
155
#if 0
156
        (void)printf("%s > %s: ",
157
		ip6addr_string(&ip->ip6_src),
158
		ip6addr_string(&ip->ip6_dst));
159
#endif
160
161
	TCHECK(dp->icmp6_code);
162
	switch (dp->icmp6_type) {
163
	case ICMP6_DST_UNREACH:
164
		TCHECK(oip->ip6_dst);
165
		switch (dp->icmp6_code) {
166
		case ICMP6_DST_UNREACH_NOROUTE:
167
			printf("icmp6: %s unreachable route",
168
			       ip6addr_string(&oip->ip6_dst));
169
			break;
170
		case ICMP6_DST_UNREACH_ADMIN:
171
			printf("icmp6: %s unreachable prohibited",
172
			       ip6addr_string(&oip->ip6_dst));
173
			break;
174
#ifdef ICMP6_DST_UNREACH_BEYONDSCOPE
175
		case ICMP6_DST_UNREACH_BEYONDSCOPE:
176
#else
177
		case ICMP6_DST_UNREACH_NOTNEIGHBOR:
178
#endif
179
			printf("icmp6: %s beyond scope of source address %s",
180
			       ip6addr_string(&oip->ip6_dst),
181
			       ip6addr_string(&oip->ip6_src));
182
			break;
183
		case ICMP6_DST_UNREACH_ADDR:
184
			printf("icmp6: %s unreachable address",
185
			       ip6addr_string(&oip->ip6_dst));
186
			break;
187
		case ICMP6_DST_UNREACH_NOPORT:
188
			TCHECK(oip->ip6_nxt);
189
			hlen = sizeof(struct ip6_hdr);
190
			ouh = (struct udphdr *)(((u_char *)oip) + hlen);
191
			TCHECK(ouh->uh_dport);
192
			dport = ntohs(ouh->uh_dport);
193
			switch (oip->ip6_nxt) {
194
			case IPPROTO_TCP:
195
				printf("icmp6: %s tcp port %s unreachable",
196
					ip6addr_string(&oip->ip6_dst),
197
					tcpport_string(dport));
198
				break;
199
			case IPPROTO_UDP:
200
				printf("icmp6: %s udp port %s unreachable",
201
					ip6addr_string(&oip->ip6_dst),
202
					udpport_string(dport));
203
				break;
204
			default:
205
				printf("icmp6: %s protocol %d port %d unreachable",
206
					ip6addr_string(&oip->ip6_dst),
207
					oip->ip6_nxt, dport);
208
				break;
209
			}
210
			break;
211
		default:
212
			printf("icmp6: %s unreachable code-#%d",
213
				ip6addr_string(&oip->ip6_dst),
214
				dp->icmp6_code);
215
			break;
216
		}
217
		break;
218
	case ICMP6_PACKET_TOO_BIG:
219
		TCHECK(dp->icmp6_mtu);
220
		printf("icmp6: too big %u", (u_int32_t)ntohl(dp->icmp6_mtu));
221
		break;
222
	case ICMP6_TIME_EXCEEDED:
223
		TCHECK(oip->ip6_dst);
224
		switch (dp->icmp6_code) {
225
		case ICMP6_TIME_EXCEED_TRANSIT:
226
			printf("icmp6: time exceeded in-transit for %s",
227
				ip6addr_string(&oip->ip6_dst));
228
			break;
229
		case ICMP6_TIME_EXCEED_REASSEMBLY:
230
			printf("icmp6: ip6 reassembly time exceeded");
231
			break;
232
		default:
233
			printf("icmp6: time exceeded code-#%d",
234
				dp->icmp6_code);
235
			break;
236
		}
237
		break;
238
	case ICMP6_PARAM_PROB:
239
		TCHECK(oip->ip6_dst);
240
		switch (dp->icmp6_code) {
241
		case ICMP6_PARAMPROB_HEADER:
242
			printf("icmp6: parameter problem errorneous - octet %u",
243
				(u_int32_t)ntohl(dp->icmp6_pptr));
244
			break;
245
		case ICMP6_PARAMPROB_NEXTHEADER:
246
			printf("icmp6: parameter problem next header - octet %u",
247
				(u_int32_t)ntohl(dp->icmp6_pptr));
248
			break;
249
		case ICMP6_PARAMPROB_OPTION:
250
			printf("icmp6: parameter problem option - octet %u",
251
				(u_int32_t)ntohl(dp->icmp6_pptr));
252
			break;
253
		default:
254
			printf("icmp6: parameter problem code-#%d",
255
			       dp->icmp6_code);
256
			break;
257
		}
258
		break;
259
	case ICMP6_ECHO_REQUEST:
260
	case ICMP6_ECHO_REPLY:
261
		printf("icmp6: echo %s", dp->icmp6_type == ICMP6_ECHO_REQUEST ?
262
		    "request" : "reply");
263
		if (vflag) {
264
			TCHECK(dp->icmp6_seq);
265
			printf(" (id:%04x seq:%u)",
266
			    ntohs(dp->icmp6_id), ntohs(dp->icmp6_seq));
267
		}
268
		break;
269
	case ICMP6_MEMBERSHIP_QUERY:
270
		printf("icmp6: multicast listener query ");
271
		if (length == MLD_V1_QUERY_MINLEN) {
272
			mld6_print((const u_char *)dp);
273
		} else if (length >= MLD_V2_QUERY_MINLEN) {
274
			printf("v2 ");
275
			mldv2_query_print((const u_char *)dp, length);
276
		} else {
277
			printf("unknown-version (len %u) ", length);
278
		}
279
		break;
280
	case ICMP6_MEMBERSHIP_REPORT:
281
		printf("icmp6: multicast listener report ");
282
		mld6_print((const u_char *)dp);
283
		break;
284
	case ICMP6_MEMBERSHIP_REDUCTION:
285
		printf("icmp6: multicast listener done ");
286
		mld6_print((const u_char *)dp);
287
		break;
288
	case ND_ROUTER_SOLICIT:
289
		printf("icmp6: router solicitation ");
290
		if (vflag) {
291
#define RTSOLLEN 8
292
		        icmp6_opt_print((const u_char *)dp + RTSOLLEN,
293
					icmp6len - RTSOLLEN);
294
		}
295
		break;
296
	case ND_ROUTER_ADVERT:
297
		printf("icmp6: router advertisement");
298
		if (vflag) {
299
			struct nd_router_advert *p;
300
301
			p = (struct nd_router_advert *)dp;
302
			TCHECK(p->nd_ra_retransmit);
303
			printf("(chlim=%d, ", (int)p->nd_ra_curhoplimit);
304
			if (p->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED)
305
				printf("M");
306
			if (p->nd_ra_flags_reserved & ND_RA_FLAG_OTHER)
307
				printf("O");
308
			if (p->nd_ra_flags_reserved &
309
			    (ND_RA_FLAG_MANAGED|ND_RA_FLAG_OTHER))
310
				printf(", ");
311
			switch (p->nd_ra_flags_reserved
312
			    & ND_RA_FLAG_RTPREF_MASK) {
313
			case ND_RA_FLAG_RTPREF_HIGH:
314
				printf("pref=high, ");
315
				break;
316
			case ND_RA_FLAG_RTPREF_MEDIUM:
317
				printf("pref=medium, ");
318
				break;
319
			case ND_RA_FLAG_RTPREF_LOW:
320
				printf("pref=low, ");
321
				break;
322
			case ND_RA_FLAG_RTPREF_RSV:
323
				printf("pref=rsv, ");
324
				break;
325
			}
326
			printf("router_ltime=%d, ", ntohs(p->nd_ra_router_lifetime));
327
			printf("reachable_time=%u, ",
328
				(u_int32_t)ntohl(p->nd_ra_reachable));
329
			printf("retrans_time=%u)",
330
				(u_int32_t)ntohl(p->nd_ra_retransmit));
331
#define RTADVLEN 16
332
		        icmp6_opt_print((const u_char *)dp + RTADVLEN,
333
					icmp6len - RTADVLEN);
334
		}
335
		break;
336
	case ND_NEIGHBOR_SOLICIT:
337
	    {
338
		struct nd_neighbor_solicit *p;
339
		p = (struct nd_neighbor_solicit *)dp;
340
		TCHECK(p->nd_ns_target);
341
		printf("icmp6: neighbor sol: who has %s",
342
			ip6addr_string(&p->nd_ns_target));
343
		if (vflag) {
344
#define NDSOLLEN 24
345
		        icmp6_opt_print((const u_char *)dp + NDSOLLEN,
346
					icmp6len - NDSOLLEN);
347
		}
348
	    }
349
		break;
350
	case ND_NEIGHBOR_ADVERT:
351
	    {
352
		struct nd_neighbor_advert *p;
353
354
		p = (struct nd_neighbor_advert *)dp;
355
		TCHECK(p->nd_na_target);
356
		printf("icmp6: neighbor adv: tgt is %s",
357
			ip6addr_string(&p->nd_na_target));
358
                if (vflag) {
359
#define ND_NA_FLAG_ALL	\
360
	(ND_NA_FLAG_ROUTER|ND_NA_FLAG_SOLICITED|ND_NA_FLAG_OVERRIDE)
361
			/* we don't need ntohl() here.  see advanced-api-04. */
362
			if (p->nd_na_flags_reserved &  ND_NA_FLAG_ALL) {
363
#undef ND_NA_FLAG_ALL
364
				u_int32_t flags;
365
366
				flags = p->nd_na_flags_reserved;
367
				printf("(");
368
				if (flags & ND_NA_FLAG_ROUTER)
369
					printf("R");
370
				if (flags & ND_NA_FLAG_SOLICITED)
371
					printf("S");
372
				if (flags & ND_NA_FLAG_OVERRIDE)
373
					printf("O");
374
				printf(")");
375
			}
376
#define NDADVLEN 24
377
		        icmp6_opt_print((const u_char *)dp + NDADVLEN,
378
					icmp6len - NDADVLEN);
379
		}
380
	    }
381
		break;
382
	case ND_REDIRECT:
383
	{
384
#define RDR(i) ((struct nd_redirect *)(i))
385
		char tgtbuf[INET6_ADDRSTRLEN], dstbuf[INET6_ADDRSTRLEN];
386
387
		TCHECK(RDR(dp)->nd_rd_dst);
388
		inet_ntop(AF_INET6, &RDR(dp)->nd_rd_target,
389
			  tgtbuf, INET6_ADDRSTRLEN);
390
		inet_ntop(AF_INET6, &RDR(dp)->nd_rd_dst,
391
			  dstbuf, INET6_ADDRSTRLEN);
392
		printf("icmp6: redirect %s to %s", dstbuf, tgtbuf);
393
#define REDIRECTLEN 40
394
		if (vflag) {
395
			icmp6_opt_print((const u_char *)dp + REDIRECTLEN,
396
					icmp6len - REDIRECTLEN);
397
		}
398
		break;
399
	}
400
	case ICMP6_ROUTER_RENUMBERING:
401
		switch (dp->icmp6_code) {
402
		case ICMP6_ROUTER_RENUMBERING_COMMAND:
403
			printf("icmp6: router renum command");
404
			break;
405
		case ICMP6_ROUTER_RENUMBERING_RESULT:
406
			printf("icmp6: router renum result");
407
			break;
408
		default:
409
			printf("icmp6: router renum code-#%d", dp->icmp6_code);
410
			break;
411
		}
412
		break;
413
#ifdef ICMP6_WRUREQUEST
414
	case ICMP6_WRUREQUEST:	/*ICMP6_FQDN_QUERY*/
415
	    {
416
		int siz;
417
		siz = ep - (u_char *)(dp + 1);
418
		if (siz == 4)
419
			printf("icmp6: who-are-you request");
420
		else {
421
			printf("icmp6: FQDN request");
422
			if (vflag) {
423
				if (siz < 8)
424
					printf("?(icmp6_data %d bytes)", siz);
425
				else if (8 < siz)
426
					printf("?(extra %d bytes)", siz - 8);
427
			}
428
		}
429
		break;
430
	    }
431
#endif /*ICMP6_WRUREQUEST*/
432
#ifdef ICMP6_WRUREPLY
433
	case ICMP6_WRUREPLY:	/*ICMP6_FQDN_REPLY*/
434
	    {
435
		enum { UNKNOWN, WRU, FQDN } mode = UNKNOWN;
436
		u_char const *buf;
437
		u_char const *cp = NULL;
438
439
		buf = (u_char *)(dp + 1);
440
441
		/* fair guess */
442
		if (buf[12] == ep - buf - 13)
443
			mode = FQDN;
444
		else if (dp->icmp6_code == 1)
445
			mode = FQDN;
446
447
		/* wild guess */
448
		if (mode == UNKNOWN) {
449
			cp = buf + 4;
450
			while (cp < ep) {
451
				if (!isprint(*cp++))
452
					mode = FQDN;
453
			}
454
		}
455
		if (mode == UNKNOWN && 2 < labs(buf[12] - (ep - buf - 13)))
456
			mode = WRU;
457
		if (mode == UNKNOWN)
458
			mode = FQDN;
459
460
		if (mode == WRU) {
461
			cp = buf + 4;
462
			printf("icmp6: who-are-you reply(\"");
463
		} else if (mode == FQDN) {
464
			cp = buf + 13;
465
			printf("icmp6: FQDN reply(\"");
466
		}
467
		for (; cp < ep; cp++)
468
			printf((isprint(*cp) ? "%c" : "\\%03o"), *cp);
469
		printf("\"");
470
		if (vflag) {
471
			printf(",%s", mode == FQDN ? "FQDN" : "WRU");
472
			if (mode == FQDN) {
473
				int ttl;
474
				ttl = (int)ntohl(*(u_int32_t *)&buf[8]);
475
				if (dp->icmp6_code == 1)
476
					printf(",TTL=unknown");
477
				else if (ttl < 0)
478
					printf(",TTL=%d:invalid", ttl);
479
				else
480
					printf(",TTL=%d", ttl);
481
				if (buf[12] != ep - buf - 13) {
482
					(void)printf(",invalid namelen:%d/%u",
483
						buf[12],
484
						(unsigned int)(ep - buf - 13));
485
				}
486
			}
487
		}
488
		printf(")");
489
		break;
490
	    }
491
#endif /*ICMP6_WRUREPLY*/
492
	case MLDV2_LISTENER_REPORT:
493
		printf("multicast listener report v2");
494
		mldv2_report_print((const u_char *) dp, length);
495
		break;
496
	default:
497
		printf("icmp6: type-#%d", dp->icmp6_type);
498
		break;
499
	}
500
	if (vflag) {
501
		if (TTEST2(dp->icmp6_type, length)) {
502
			u_int16_t sum, icmp6_sum;
503
			sum = icmp6_cksum(ip, dp, length);
504
			if (sum != 0) {
505
				icmp6_sum = EXTRACT_16BITS(&dp->icmp6_cksum);
506
				printf(" [bad icmp6 cksum %x! -> %x]", icmp6_sum,
507
				    in_cksum_shouldbe(icmp6_sum, sum));
508
			} else
509
				printf(" [icmp6 cksum ok]");
510
		}
511
	}
512
	return;
513
trunc:
514
	fputs("[|icmp6]", stdout);
515
#if 0
516
#undef TCHECK
517
#endif
518
}
519
520
void
521
icmp6_opt_print(const u_char *bp, int resid)
522
{
523
	const struct nd_opt_hdr *op;
524
	const struct nd_opt_hdr *opl;	/* why there's no struct? */
525
	const struct nd_opt_prefix_info *opp;
526
	const struct icmp6_opts_redirect *opr;
527
	const struct nd_opt_mtu *opm;
528
	const struct nd_opt_rdnss *oprd;
529
	const struct nd_opt_route_info *opri;
530
	const u_char *ep;
531
	const struct in6_addr *in6p;
532
	struct in6_addr in6;
533
	int	i, opts_len;
534
#if 0
535
	const struct ip6_hdr *ip;
536
	const char *str;
537
	const struct ip6_hdr *oip;
538
	const struct udphdr *ouh;
539
	int hlen, dport;
540
	char buf[256];
541
#endif
542
543
#if 0
544
#define TCHECK(var) if ((u_char *)&(var) > ep - sizeof(var)) goto trunc
545
#endif
546
#define ECHECK(var) if ((u_char *)&(var) > ep - sizeof(var)) return
547
548
	op = (struct nd_opt_hdr *)bp;
549
#if 0
550
	ip = (struct ip6_hdr *)bp2;
551
	oip = &dp->icmp6_ip6;
552
	str = buf;
553
#endif
554
	/* 'ep' points to the end of avaible data. */
555
	ep = snapend;
556
557
	ECHECK(op->nd_opt_len);
558
	if (resid <= 0)
559
		return;
560
	if (op->nd_opt_len == 0)
561
		goto trunc;
562
	if (bp + (op->nd_opt_len << 3) > ep)
563
		goto trunc;
564
	switch (op->nd_opt_type) {
565
	case ND_OPT_SOURCE_LINKADDR:
566
		opl = (struct nd_opt_hdr *)op;
567
#if 1
568
		if ((u_char *)opl + (opl->nd_opt_len << 3) > ep)
569
			goto trunc;
570
#else
571
		TCHECK((u_char *)opl + (opl->nd_opt_len << 3) - 1);
572
#endif
573
		printf("(src lladdr: %s",
574
			etheraddr_string((u_char *)(opl + 1)));
575
		if (opl->nd_opt_len != 1)
576
			printf("!");
577
		printf(")");
578
		icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3),
579
				resid - (op->nd_opt_len << 3));
580
		break;
581
	case ND_OPT_TARGET_LINKADDR:
582
		opl = (struct nd_opt_hdr *)op;
583
#if 1
584
		if ((u_char *)opl + (opl->nd_opt_len << 3) > ep)
585
			goto trunc;
586
#else
587
		TCHECK((u_char *)opl + (opl->nd_opt_len << 3) - 1);
588
#endif
589
		printf("(tgt lladdr: %s",
590
			etheraddr_string((u_char *)(opl + 1)));
591
		if (opl->nd_opt_len != 1)
592
			printf("!");
593
		printf(")");
594
		icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3),
595
				resid - (op->nd_opt_len << 3));
596
		break;
597
	case ND_OPT_PREFIX_INFORMATION:
598
		opp = (struct nd_opt_prefix_info *)op;
599
		TCHECK(opp->nd_opt_pi_prefix);
600
		printf("(prefix info: ");
601
		if (opp->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK)
602
		       printf("L");
603
		if (opp->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_AUTO)
604
		       printf("A");
605
		if (opp->nd_opt_pi_flags_reserved)
606
			printf(" ");
607
		printf("valid_ltime=");
608
		if ((u_int32_t)ntohl(opp->nd_opt_pi_valid_time) == ~0U)
609
			printf("infinity");
610
		else {
611
			printf("%u", (u_int32_t)ntohl(opp->nd_opt_pi_valid_time));
612
		}
613
		printf(", ");
614
		printf("preferred_ltime=");
615
		if ((u_int32_t)ntohl(opp->nd_opt_pi_preferred_time) == ~0U)
616
			printf("infinity");
617
		else {
618
			printf("%u", (u_int32_t)ntohl(opp->nd_opt_pi_preferred_time));
619
		}
620
		printf(", ");
621
		printf("prefix=%s/%d", ip6addr_string(&opp->nd_opt_pi_prefix),
622
			opp->nd_opt_pi_prefix_len);
623
		if (opp->nd_opt_pi_len != 4)
624
			printf("!");
625
		printf(")");
626
		icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3),
627
				resid - (op->nd_opt_len << 3));
628
		break;
629
	case ND_OPT_REDIRECTED_HEADER:
630
		opr = (struct icmp6_opts_redirect *)op;
631
		printf("(redirect)");
632
		/* xxx */
633
		icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3),
634
				resid - (op->nd_opt_len << 3));
635
		break;
636
	case ND_OPT_MTU:
637
		opm = (struct nd_opt_mtu *)op;
638
		TCHECK(opm->nd_opt_mtu_mtu);
639
		printf("(mtu: ");
640
		printf("mtu=%u", (u_int32_t)ntohl(opm->nd_opt_mtu_mtu));
641
		if (opm->nd_opt_mtu_len != 1)
642
			printf("!");
643
		printf(")");
644
		icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3),
645
				resid - (op->nd_opt_len << 3));
646
		break;
647
	case ND_OPT_ROUTE_INFO:
648
		opri = (struct nd_opt_route_info *)op;
649
		TCHECK(opri->nd_opt_rti_lifetime);
650
		printf("(route-info: ");
651
		memset(&in6, 0, sizeof(in6));
652
		in6p = (const struct in6_addr *)(opri + 1);
653
		switch (op->nd_opt_len) {
654
		case 1:
655
			break;
656
		case 2:
657
			TCHECK2(*in6p, 8);
658
			memcpy(&in6, opri + 1, 8);
659
			break;
660
		case 3:
661
			TCHECK(*in6p);
662
			memcpy(&in6, opri + 1, sizeof(in6));
663
			break;
664
		default:
665
			goto trunc;
666
		}
667
		printf("%s/%u, ", ip6addr_string(&in6),
668
		    opri->nd_opt_rti_prefixlen);
669
		switch (opri->nd_opt_rti_flags & ND_RA_FLAG_RTPREF_MASK) {
670
		case ND_RA_FLAG_RTPREF_HIGH:
671
			printf("pref=high, ");
672
			break;
673
		case ND_RA_FLAG_RTPREF_MEDIUM:
674
			printf("pref=medium, ");
675
			break;
676
		case ND_RA_FLAG_RTPREF_LOW:
677
			printf("pref=low, ");
678
			break;
679
		case ND_RA_FLAG_RTPREF_RSV:
680
			printf("pref=rsv, ");
681
			break;
682
		}
683
		printf("lifetime=%us)",
684
		    (u_int32_t)ntohl(opri->nd_opt_rti_lifetime));
685
		icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3),
686
				resid - (op->nd_opt_len << 3));
687
		break;
688
	case ND_OPT_RDNSS:
689
		oprd = (const struct nd_opt_rdnss *)op;
690
		printf("(rdnss: ");
691
		TCHECK(oprd->nd_opt_rdnss_lifetime);
692
		printf("lifetime=%us",
693
		    (u_int32_t)ntohl(oprd->nd_opt_rdnss_lifetime));
694
		if (oprd->nd_opt_rdnss_len < 3) {
695
			printf("!");
696
		} else for (i = 0; i < ((oprd->nd_opt_rdnss_len - 1) / 2); i++) {
697
			struct in6_addr *addr = (struct in6_addr *)(oprd + 1) + i;
698
			TCHECK2(*addr, sizeof(struct in6_addr));
699
			printf(", addr=%s", ip6addr_string(addr));
700
		}
701
		printf(")");
702
		icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3),
703
				resid - (op->nd_opt_len << 3));
704
		break;
705
	case ND_OPT_DNSSL:
706
		printf("(dnssl: opt_len=%d)", op->nd_opt_len);
707
		/* XXX */
708
		icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3),
709
				resid - (op->nd_opt_len << 3));
710
		break;
711
	default:
712
		opts_len = op->nd_opt_len;
713
		printf("(unknown opt_type=%d, opt_len=%d)",
714
		       op->nd_opt_type, opts_len);
715
		if (opts_len == 0)
716
			opts_len = 1; /* XXX */
717
		icmp6_opt_print((const u_char *)op + (opts_len << 3),
718
				resid - (opts_len << 3));
719
		break;
720
	}
721
	return;
722
 trunc:
723
	fputs("[ndp opt]", stdout);
724
	return;
725
#if 0
726
#undef TCHECK
727
#endif
728
#undef ECHECK
729
}
730
731
void
732
mld6_print(const u_char *bp)
733
{
734
	struct mld_hdr *mp = (struct mld_hdr *)bp;
735
	const u_char *ep;
736
737
	/* 'ep' points to the end of avaible data. */
738
	ep = snapend;
739
740
	if ((u_char *)mp + sizeof(*mp) > ep)
741
		return;
742
743
	printf("max resp delay: %d ", ntohs(mp->mld_maxdelay));
744
	printf("addr: %s", ip6addr_string(&mp->mld_addr));
745
746
	return;
747
}
748
749
void
750
mldv2_report_print(const u_char *bp, u_int len)
751
{
752
	struct icmp6_hdr *icp = (struct icmp6_hdr *) bp;
753
	u_int group, nsrcs, ngroups;
754
	u_int i, j;
755
756
	if (len < MLDV2_REPORT_MINLEN) {
757
		printf(" [invalid len %d]", len);
758
		return;
759
	}
760
761
	TCHECK(icp->icmp6_data16[1]);
762
	ngroups = ntohs(icp->icmp6_data16[1]);
763
	printf(", %d group record(s)", ngroups);
764
	if (vflag > 0) {
765
		/* Print the group records */
766
		group = MLDV2_REPORT_GROUP0;
767
		for (i = 0; i < ngroups; i++) {
768
			/* type(1) + auxlen(1) + numsrc(2) + grp(16) */
769
			if (len < group + MLDV2_REPORT_MINGRPLEN) {
770
				printf(" [invalid number of groups]");
771
				return;
772
			}
773
			TCHECK2(bp[group + MLDV2_RGROUP_MADDR],
774
			    sizeof(struct in6_addr));
775
			printf(" [gaddr %s",
776
			    ip6addr_string(&bp[group + MLDV2_RGROUP_MADDR]));
777
			printf(" %s", tok2str(mldv2report2str,
778
			    " [v2-report-#%d]", bp[group]));
779
			nsrcs = (bp[group + MLDV2_RGROUP_NSRCS] << 8) +
780
			    bp[group + MLDV2_RGROUP_NSRCS + 1];
781
			/* Check the number of sources and print them */
782
			if (len < group + MLDV2_REPORT_MINGRPLEN +
783
				    (nsrcs * sizeof(struct in6_addr))) {
784
				printf(" [invalid number of sources %d]", nsrcs);
785
				return;
786
			}
787
			if (vflag == 1)
788
				printf(", %d source(s)", nsrcs);
789
			else {
790
				/* Print the sources */
791
				(void)printf(" {");
792
				for (j = 0; j < nsrcs; j++) {
793
					TCHECK2(bp[group +
794
					    MLDV2_REPORT_MINGRPLEN +
795
					    j * sizeof(struct in6_addr)],
796
					    sizeof(struct in6_addr));
797
					printf(" %s", ip6addr_string(&bp[group +
798
					    MLDV2_REPORT_MINGRPLEN + j *
799
					    sizeof(struct in6_addr)]));
800
				}
801
				(void)printf(" }");
802
			}
803
			/* Next group record */
804
			group += MLDV2_REPORT_MINGRPLEN + nsrcs *
805
			    sizeof(struct in6_addr);
806
			printf("]");
807
		}
808
	}
809
	return;
810
trunc:
811
	(void)printf("[|icmp6]");
812
	return;
813
}
814
815
void
816
mldv2_query_print(const u_char *bp, u_int len)
817
{
818
	struct icmp6_hdr *icp = (struct icmp6_hdr *) bp;
819
	u_int mrc, qqic;
820
	int mrd, qqi;
821
	int mant, exp;
822
	u_int nsrcs;
823
	u_int i;
824
825
	if (len < MLD_V2_QUERY_MINLEN) {
826
		printf(" [invalid len %d]", len);
827
		return;
828
	}
829
	TCHECK(icp->icmp6_data16[0]);
830
	mrc = ntohs(icp->icmp6_data16[0]);
831
	if (mrc & MLDV2_MRC_FLOAT) {
832
		mant = MLD_MRC_MANT(mrc);
833
		exp = MLD_MRC_EXP(mrc);
834
		mrd = MLDV2_MRD(mant, exp);
835
	} else {
836
		mrd = mrc;
837
	}
838
	if (vflag) {
839
		(void)printf(" [max resp delay=%d]", mrd);
840
	}
841
	TCHECK2(bp[8], sizeof(struct in6_addr));
842
	printf(" [gaddr %s", ip6addr_string(&bp[8]));
843
844
	if (vflag) {
845
		TCHECK(bp[MLDV2_QUERY_QQIC]);
846
		if (bp[MLDV2_QUERY_QRV] & MLDV2_QUERY_QRV_SFLAG) {
847
			printf(" sflag");
848
		}
849
		if (MLD_QRV(bp[MLDV2_QUERY_QRV])) {
850
			printf(" robustness=%d", MLD_QRV(bp[MLDV2_QUERY_QRV]));
851
		}
852
		qqic = bp[MLDV2_QUERY_QQIC];
853
		if (qqic & MLDV2_QQIC_FLOAT) {
854
			mant = MLD_QQIC_MANT(qqic);
855
			exp = MLD_QQIC_EXP(qqic);
856
			qqi = MLDV2_QQI(mant, exp);
857
		} else {
858
			qqi = bp[MLDV2_QUERY_QQIC];
859
		}
860
		printf(" qqi=%d", qqi);
861
	}
862
863
	TCHECK2(bp[MLDV2_QUERY_NSRCS], 2);
864
	nsrcs = ntohs(*(u_short *)&bp[MLDV2_QUERY_NSRCS]);
865
	if (nsrcs > 0) {
866
		if (len < MLD_V2_QUERY_MINLEN + nsrcs * sizeof(struct in6_addr))
867
			printf(" [invalid number of sources]");
868
		else if (vflag > 1) {
869
			printf(" {");
870
			for (i = 0; i < nsrcs; i++) {
871
				TCHECK2(bp[MLDV2_QUERY_SRC0 + i *
872
				    sizeof(struct in6_addr)],
873
				    sizeof(struct in6_addr));
874
				printf(" %s",
875
				    ip6addr_string(&bp[MLDV2_QUERY_SRC0 + i *
876
				    sizeof(struct in6_addr)]));
877
			}
878
			printf(" }");
879
		} else
880
			printf(", %d source(s)", nsrcs);
881
	}
882
	printf("]");
883
	return;
884
trunc:
885
	(void)printf("[|icmp6]");
886
	return;
887
}
888
889
890
#endif /* INET6 */