1/*
2 * Copyright (c) 1995, 1996
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that: (1) source code distributions
7 * retain the above copyright notice and this paragraph in its entirety, (2)
8 * distributions including binary code include the above copyright notice and
9 * this paragraph in its entirety in the documentation or other materials
10 * provided with the distribution, and (3) all advertising materials mentioning
11 * features or use of this software display the following acknowledgement:
12 * ``This product includes software developed by the University of California,
13 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14 * the University nor the names of its contributors may be used to endorse
15 * or promote products derived from this software without specific prior
16 * written permission.
17 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20 */
21
22/* \summary: Protocol Independent Multicast (PIM) printer */
23
24#ifdef HAVE_CONFIG_H
25#include "config.h"
26#endif
27
28#include <netdissect-stdinc.h>
29
30#include "netdissect.h"
31#include "addrtoname.h"
32#include "extract.h"
33
34#include "ip.h"
35#include "ip6.h"
36#include "ipproto.h"
37
38#define PIMV1_TYPE_QUERY           0
39#define PIMV1_TYPE_REGISTER        1
40#define PIMV1_TYPE_REGISTER_STOP   2
41#define PIMV1_TYPE_JOIN_PRUNE      3
42#define PIMV1_TYPE_RP_REACHABILITY 4
43#define PIMV1_TYPE_ASSERT          5
44#define PIMV1_TYPE_GRAFT           6
45#define PIMV1_TYPE_GRAFT_ACK       7
46
47static const struct tok pimv1_type_str[] = {
48	{ PIMV1_TYPE_QUERY,           "Query"         },
49	{ PIMV1_TYPE_REGISTER,        "Register"      },
50	{ PIMV1_TYPE_REGISTER_STOP,   "Register-Stop" },
51	{ PIMV1_TYPE_JOIN_PRUNE,      "Join/Prune"    },
52	{ PIMV1_TYPE_RP_REACHABILITY, "RP-reachable"  },
53	{ PIMV1_TYPE_ASSERT,          "Assert"        },
54	{ PIMV1_TYPE_GRAFT,           "Graft"         },
55	{ PIMV1_TYPE_GRAFT_ACK,       "Graft-ACK"     },
56	{ 0, NULL }
57};
58
59#define PIMV2_TYPE_HELLO         0
60#define PIMV2_TYPE_REGISTER      1
61#define PIMV2_TYPE_REGISTER_STOP 2
62#define PIMV2_TYPE_JOIN_PRUNE    3
63#define PIMV2_TYPE_BOOTSTRAP     4
64#define PIMV2_TYPE_ASSERT        5
65#define PIMV2_TYPE_GRAFT         6
66#define PIMV2_TYPE_GRAFT_ACK     7
67#define PIMV2_TYPE_CANDIDATE_RP  8
68#define PIMV2_TYPE_PRUNE_REFRESH 9
69#define PIMV2_TYPE_DF_ELECTION   10
70#define PIMV2_TYPE_ECMP_REDIRECT 11
71
72static const struct tok pimv2_type_values[] = {
73    { PIMV2_TYPE_HELLO,         "Hello" },
74    { PIMV2_TYPE_REGISTER,      "Register" },
75    { PIMV2_TYPE_REGISTER_STOP, "Register Stop" },
76    { PIMV2_TYPE_JOIN_PRUNE,    "Join / Prune" },
77    { PIMV2_TYPE_BOOTSTRAP,     "Bootstrap" },
78    { PIMV2_TYPE_ASSERT,        "Assert" },
79    { PIMV2_TYPE_GRAFT,         "Graft" },
80    { PIMV2_TYPE_GRAFT_ACK,     "Graft Acknowledgement" },
81    { PIMV2_TYPE_CANDIDATE_RP,  "Candidate RP Advertisement" },
82    { PIMV2_TYPE_PRUNE_REFRESH, "Prune Refresh" },
83    { PIMV2_TYPE_DF_ELECTION,   "DF Election" },
84    { PIMV2_TYPE_ECMP_REDIRECT, "ECMP Redirect" },
85    { 0, NULL}
86};
87
88#define PIMV2_HELLO_OPTION_HOLDTIME             1
89#define PIMV2_HELLO_OPTION_LANPRUNEDELAY        2
90#define PIMV2_HELLO_OPTION_DR_PRIORITY_OLD     18
91#define PIMV2_HELLO_OPTION_DR_PRIORITY         19
92#define PIMV2_HELLO_OPTION_GENID               20
93#define PIMV2_HELLO_OPTION_REFRESH_CAP         21
94#define PIMV2_HELLO_OPTION_BIDIR_CAP           22
95#define PIMV2_HELLO_OPTION_ADDRESS_LIST        24
96#define PIMV2_HELLO_OPTION_ADDRESS_LIST_OLD 65001
97
98static const struct tok pimv2_hello_option_values[] = {
99    { PIMV2_HELLO_OPTION_HOLDTIME,         "Hold Time" },
100    { PIMV2_HELLO_OPTION_LANPRUNEDELAY,    "LAN Prune Delay" },
101    { PIMV2_HELLO_OPTION_DR_PRIORITY_OLD,  "DR Priority (Old)" },
102    { PIMV2_HELLO_OPTION_DR_PRIORITY,      "DR Priority" },
103    { PIMV2_HELLO_OPTION_GENID,            "Generation ID" },
104    { PIMV2_HELLO_OPTION_REFRESH_CAP,      "State Refresh Capability" },
105    { PIMV2_HELLO_OPTION_BIDIR_CAP,        "Bi-Directional Capability" },
106    { PIMV2_HELLO_OPTION_ADDRESS_LIST,     "Address List" },
107    { PIMV2_HELLO_OPTION_ADDRESS_LIST_OLD, "Address List (Old)" },
108    { 0, NULL}
109};
110
111#define PIMV2_REGISTER_FLAG_LEN      4
112#define PIMV2_REGISTER_FLAG_BORDER 0x80000000
113#define PIMV2_REGISTER_FLAG_NULL   0x40000000
114
115static const struct tok pimv2_register_flag_values[] = {
116    { PIMV2_REGISTER_FLAG_BORDER, "Border" },
117    { PIMV2_REGISTER_FLAG_NULL, "Null" },
118    { 0, NULL}
119};
120
121/*
122 * XXX: We consider a case where IPv6 is not ready yet for portability,
123 * but PIM dependent defintions should be independent of IPv6...
124 */
125
126struct pim {
127	uint8_t pim_typever;
128			/* upper 4bit: PIM version number; 2 for PIMv2 */
129			/* lower 4bit: the PIM message type, currently they are:
130			 * Hello, Register, Register-Stop, Join/Prune,
131			 * Bootstrap, Assert, Graft (PIM-DM only),
132			 * Graft-Ack (PIM-DM only), C-RP-Adv
133			 */
134#define PIM_VER(x)	(((x) & 0xf0) >> 4)
135#define PIM_TYPE(x)	((x) & 0x0f)
136	u_char  pim_rsv;	/* Reserved */
137	u_short	pim_cksum;	/* IP style check sum */
138};
139
140static void pimv2_print(netdissect_options *, register const u_char *bp, register u_int len, const u_char *);
141
142static void
143pimv1_join_prune_print(netdissect_options *ndo,
144                       register const u_char *bp, register u_int len)
145{
146	int ngroups, njoin, nprune;
147	int njp;
148
149	/* If it's a single group and a single source, use 1-line output. */
150	if (ND_TTEST2(bp[0], 30) && bp[11] == 1 &&
151	    ((njoin = EXTRACT_16BITS(&bp[20])) + EXTRACT_16BITS(&bp[22])) == 1) {
152		int hold;
153
154		ND_PRINT((ndo, " RPF %s ", ipaddr_string(ndo, bp)));
155		hold = EXTRACT_16BITS(&bp[6]);
156		if (hold != 180) {
157			ND_PRINT((ndo, "Hold "));
158			unsigned_relts_print(ndo, hold);
159		}
160		ND_PRINT((ndo, "%s (%s/%d, %s", njoin ? "Join" : "Prune",
161		ipaddr_string(ndo, &bp[26]), bp[25] & 0x3f,
162		ipaddr_string(ndo, &bp[12])));
163		if (EXTRACT_32BITS(&bp[16]) != 0xffffffff)
164			ND_PRINT((ndo, "/%s", ipaddr_string(ndo, &bp[16])));
165		ND_PRINT((ndo, ") %s%s %s",
166		    (bp[24] & 0x01) ? "Sparse" : "Dense",
167		    (bp[25] & 0x80) ? " WC" : "",
168		    (bp[25] & 0x40) ? "RP" : "SPT"));
169		return;
170	}
171
172	if (len < sizeof(struct in_addr))
173		goto trunc;
174	ND_TCHECK2(bp[0], sizeof(struct in_addr));
175	if (ndo->ndo_vflag > 1)
176		ND_PRINT((ndo, "\n"));
177	ND_PRINT((ndo, " Upstream Nbr: %s", ipaddr_string(ndo, bp)));
178	bp += 4;
179	len -= 4;
180	if (len < 4)
181		goto trunc;
182	ND_TCHECK2(bp[2], 2);
183	if (ndo->ndo_vflag > 1)
184		ND_PRINT((ndo, "\n"));
185	ND_PRINT((ndo, " Hold time: "));
186	unsigned_relts_print(ndo, EXTRACT_16BITS(&bp[2]));
187	if (ndo->ndo_vflag < 2)
188		return;
189	bp += 4;
190	len -= 4;
191
192	if (len < 4)
193		goto trunc;
194	ND_TCHECK2(bp[0], 4);
195	ngroups = bp[3];
196	bp += 4;
197	len -= 4;
198	while (ngroups--) {
199		/*
200		 * XXX - does the address have length "addrlen" and the
201		 * mask length "maddrlen"?
202		 */
203		if (len < 4)
204			goto trunc;
205		ND_TCHECK2(bp[0], sizeof(struct in_addr));
206		ND_PRINT((ndo, "\n\tGroup: %s", ipaddr_string(ndo, bp)));
207		bp += 4;
208		len -= 4;
209		if (len < 4)
210			goto trunc;
211		ND_TCHECK2(bp[0], sizeof(struct in_addr));
212		if (EXTRACT_32BITS(&bp[0]) != 0xffffffff)
213			ND_PRINT((ndo, "/%s", ipaddr_string(ndo, &bp[0])));
214		bp += 4;
215		len -= 4;
216		if (len < 4)
217			goto trunc;
218		ND_TCHECK2(bp[0], 4);
219		njoin = EXTRACT_16BITS(&bp[0]);
220		nprune = EXTRACT_16BITS(&bp[2]);
221		ND_PRINT((ndo, " joined: %d pruned: %d", njoin, nprune));
222		bp += 4;
223		len -= 4;
224		for (njp = 0; njp < (njoin + nprune); njp++) {
225			const char *type;
226
227			if (njp < njoin)
228				type = "Join ";
229			else
230				type = "Prune";
231			if (len < 6)
232				goto trunc;
233			ND_TCHECK2(bp[0], 6);
234			ND_PRINT((ndo, "\n\t%s %s%s%s%s/%d", type,
235			    (bp[0] & 0x01) ? "Sparse " : "Dense ",
236			    (bp[1] & 0x80) ? "WC " : "",
237			    (bp[1] & 0x40) ? "RP " : "SPT ",
238			    ipaddr_string(ndo, &bp[2]),
239			    bp[1] & 0x3f));
240			bp += 6;
241			len -= 6;
242		}
243	}
244	return;
245trunc:
246	ND_PRINT((ndo, "[|pim]"));
247	return;
248}
249
250void
251pimv1_print(netdissect_options *ndo,
252            register const u_char *bp, register u_int len)
253{
254	register u_char type;
255
256	ND_TCHECK(bp[1]);
257	type = bp[1];
258
259	ND_PRINT((ndo, " %s", tok2str(pimv1_type_str, "[type %u]", type)));
260	switch (type) {
261	case PIMV1_TYPE_QUERY:
262		if (ND_TTEST(bp[8])) {
263			switch (bp[8] >> 4) {
264			case 0:
265				ND_PRINT((ndo, " Dense-mode"));
266				break;
267			case 1:
268				ND_PRINT((ndo, " Sparse-mode"));
269				break;
270			case 2:
271				ND_PRINT((ndo, " Sparse-Dense-mode"));
272				break;
273			default:
274				ND_PRINT((ndo, " mode-%d", bp[8] >> 4));
275				break;
276			}
277		}
278		if (ndo->ndo_vflag) {
279			ND_TCHECK2(bp[10],2);
280			ND_PRINT((ndo, " (Hold-time "));
281			unsigned_relts_print(ndo, EXTRACT_16BITS(&bp[10]));
282			ND_PRINT((ndo, ")"));
283		}
284		break;
285
286	case PIMV1_TYPE_REGISTER:
287		ND_TCHECK2(bp[8], 20);			/* ip header */
288		ND_PRINT((ndo, " for %s > %s", ipaddr_string(ndo, &bp[20]),
289		    ipaddr_string(ndo, &bp[24])));
290		break;
291	case PIMV1_TYPE_REGISTER_STOP:
292		ND_TCHECK2(bp[12], sizeof(struct in_addr));
293		ND_PRINT((ndo, " for %s > %s", ipaddr_string(ndo, &bp[8]),
294		    ipaddr_string(ndo, &bp[12])));
295		break;
296	case PIMV1_TYPE_RP_REACHABILITY:
297		if (ndo->ndo_vflag) {
298			ND_TCHECK2(bp[22], 2);
299			ND_PRINT((ndo, " group %s", ipaddr_string(ndo, &bp[8])));
300			if (EXTRACT_32BITS(&bp[12]) != 0xffffffff)
301				ND_PRINT((ndo, "/%s", ipaddr_string(ndo, &bp[12])));
302			ND_PRINT((ndo, " RP %s hold ", ipaddr_string(ndo, &bp[16])));
303			unsigned_relts_print(ndo, EXTRACT_16BITS(&bp[22]));
304		}
305		break;
306	case PIMV1_TYPE_ASSERT:
307		ND_TCHECK2(bp[16], sizeof(struct in_addr));
308		ND_PRINT((ndo, " for %s > %s", ipaddr_string(ndo, &bp[16]),
309		    ipaddr_string(ndo, &bp[8])));
310		if (EXTRACT_32BITS(&bp[12]) != 0xffffffff)
311			ND_PRINT((ndo, "/%s", ipaddr_string(ndo, &bp[12])));
312		ND_TCHECK2(bp[24], 4);
313		ND_PRINT((ndo, " %s pref %d metric %d",
314		    (bp[20] & 0x80) ? "RP-tree" : "SPT",
315		EXTRACT_32BITS(&bp[20]) & 0x7fffffff,
316		EXTRACT_32BITS(&bp[24])));
317		break;
318	case PIMV1_TYPE_JOIN_PRUNE:
319	case PIMV1_TYPE_GRAFT:
320	case PIMV1_TYPE_GRAFT_ACK:
321		if (ndo->ndo_vflag) {
322			if (len < 8)
323				goto trunc;
324			pimv1_join_prune_print(ndo, &bp[8], len - 8);
325		}
326		break;
327	}
328	ND_TCHECK(bp[4]);
329	if ((bp[4] >> 4) != 1)
330		ND_PRINT((ndo, " [v%d]", bp[4] >> 4));
331	return;
332
333trunc:
334	ND_PRINT((ndo, "[|pim]"));
335	return;
336}
337
338/*
339 * auto-RP is a cisco protocol, documented at
340 * ftp://ftpeng.cisco.com/ipmulticast/specs/pim-autorp-spec01.txt
341 *
342 * This implements version 1+, dated Sept 9, 1998.
343 */
344void
345cisco_autorp_print(netdissect_options *ndo,
346                   register const u_char *bp, register u_int len)
347{
348	int type;
349	int numrps;
350	int hold;
351
352	if (len < 8)
353		goto trunc;
354	ND_TCHECK(bp[0]);
355	ND_PRINT((ndo, " auto-rp "));
356	type = bp[0];
357	switch (type) {
358	case 0x11:
359		ND_PRINT((ndo, "candidate-advert"));
360		break;
361	case 0x12:
362		ND_PRINT((ndo, "mapping"));
363		break;
364	default:
365		ND_PRINT((ndo, "type-0x%02x", type));
366		break;
367	}
368
369	ND_TCHECK(bp[1]);
370	numrps = bp[1];
371
372	ND_TCHECK2(bp[2], 2);
373	ND_PRINT((ndo, " Hold "));
374	hold = EXTRACT_16BITS(&bp[2]);
375	if (hold)
376		unsigned_relts_print(ndo, EXTRACT_16BITS(&bp[2]));
377	else
378		ND_PRINT((ndo, "FOREVER"));
379
380	/* Next 4 bytes are reserved. */
381
382	bp += 8; len -= 8;
383
384	/*XXX skip unless -v? */
385
386	/*
387	 * Rest of packet:
388	 * numrps entries of the form:
389	 * 32 bits: RP
390	 * 6 bits: reserved
391	 * 2 bits: PIM version supported, bit 0 is "supports v1", 1 is "v2".
392	 * 8 bits: # of entries for this RP
393	 * each entry: 7 bits: reserved, 1 bit: negative,
394	 *	       8 bits: mask 32 bits: source
395	 * lather, rinse, repeat.
396	 */
397	while (numrps--) {
398		int nentries;
399		char s;
400
401		if (len < 4)
402			goto trunc;
403		ND_TCHECK2(bp[0], 4);
404		ND_PRINT((ndo, " RP %s", ipaddr_string(ndo, bp)));
405		bp += 4;
406		len -= 4;
407		if (len < 1)
408			goto trunc;
409		ND_TCHECK(bp[0]);
410		switch (bp[0] & 0x3) {
411		case 0: ND_PRINT((ndo, " PIMv?"));
412			break;
413		case 1:	ND_PRINT((ndo, " PIMv1"));
414			break;
415		case 2:	ND_PRINT((ndo, " PIMv2"));
416			break;
417		case 3:	ND_PRINT((ndo, " PIMv1+2"));
418			break;
419		}
420		if (bp[0] & 0xfc)
421			ND_PRINT((ndo, " [rsvd=0x%02x]", bp[0] & 0xfc));
422		bp += 1;
423		len -= 1;
424		if (len < 1)
425			goto trunc;
426		ND_TCHECK(bp[0]);
427		nentries = bp[0];
428		bp += 1;
429		len -= 1;
430		s = ' ';
431		for (; nentries; nentries--) {
432			if (len < 6)
433				goto trunc;
434			ND_TCHECK2(bp[0], 6);
435			ND_PRINT((ndo, "%c%s%s/%d", s, bp[0] & 1 ? "!" : "",
436			          ipaddr_string(ndo, &bp[2]), bp[1]));
437			if (bp[0] & 0x02) {
438				ND_PRINT((ndo, " bidir"));
439			}
440			if (bp[0] & 0xfc) {
441				ND_PRINT((ndo, "[rsvd=0x%02x]", bp[0] & 0xfc));
442			}
443			s = ',';
444			bp += 6; len -= 6;
445		}
446	}
447	return;
448
449trunc:
450	ND_PRINT((ndo, "[|autorp]"));
451	return;
452}
453
454void
455pim_print(netdissect_options *ndo,
456          register const u_char *bp, register u_int len, const u_char *bp2)
457{
458	register const struct pim *pim = (const struct pim *)bp;
459
460#ifdef notyet			/* currently we see only version and type */
461	ND_TCHECK(pim->pim_rsv);
462#endif
463
464	ND_TCHECK(pim->pim_typever);
465	switch (PIM_VER(pim->pim_typever)) {
466	case 2:
467		if (!ndo->ndo_vflag) {
468			ND_PRINT((ndo, "PIMv%u, %s, length %u",
469			          PIM_VER(pim->pim_typever),
470			          tok2str(pimv2_type_values,"Unknown Type",PIM_TYPE(pim->pim_typever)),
471			          len));
472			return;
473		} else {
474			ND_PRINT((ndo, "PIMv%u, length %u\n\t%s",
475			          PIM_VER(pim->pim_typever),
476			          len,
477			          tok2str(pimv2_type_values,"Unknown Type",PIM_TYPE(pim->pim_typever))));
478			pimv2_print(ndo, bp, len, bp2);
479		}
480		break;
481	default:
482		ND_PRINT((ndo, "PIMv%u, length %u",
483		          PIM_VER(pim->pim_typever),
484		          len));
485		break;
486	}
487	return;
488
489trunc:
490	ND_PRINT((ndo, "[|pim]"));
491	return;
492}
493
494/*
495 * PIMv2 uses encoded address representations.
496 *
497 * The last PIM-SM I-D before RFC2117 was published specified the
498 * following representation for unicast addresses.  However, RFC2117
499 * specified no encoding for unicast addresses with the unicast
500 * address length specified in the header.  Therefore, we have to
501 * guess which encoding is being used (Cisco's PIMv2 implementation
502 * uses the non-RFC encoding).  RFC2117 turns a previously "Reserved"
503 * field into a 'unicast-address-length-in-bytes' field.  We guess
504 * that it's the draft encoding if this reserved field is zero.
505 *
506 * RFC2362 goes back to the encoded format, and calls the addr length
507 * field "reserved" again.
508 *
509 * The first byte is the address family, from:
510 *
511 *    0    Reserved
512 *    1    IP (IP version 4)
513 *    2    IP6 (IP version 6)
514 *    3    NSAP
515 *    4    HDLC (8-bit multidrop)
516 *    5    BBN 1822
517 *    6    802 (includes all 802 media plus Ethernet "canonical format")
518 *    7    E.163
519 *    8    E.164 (SMDS, Frame Relay, ATM)
520 *    9    F.69 (Telex)
521 *   10    X.121 (X.25, Frame Relay)
522 *   11    IPX
523 *   12    Appletalk
524 *   13    Decnet IV
525 *   14    Banyan Vines
526 *   15    E.164 with NSAP format subaddress
527 *
528 * In addition, the second byte is an "Encoding".  0 is the default
529 * encoding for the address family, and no other encodings are currently
530 * specified.
531 *
532 */
533
534enum pimv2_addrtype {
535	pimv2_unicast, pimv2_group, pimv2_source
536};
537
538/*  0                   1                   2                   3
539 *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
540 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
541 * | Addr Family   | Encoding Type |     Unicast Address           |
542 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+++++++
543 *  0                   1                   2                   3
544 *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
545 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
546 * | Addr Family   | Encoding Type |   Reserved    |  Mask Len     |
547 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
548 * |                Group multicast Address                        |
549 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
550 *  0                   1                   2                   3
551 *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
552 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
553 * | Addr Family   | Encoding Type | Rsrvd   |S|W|R|  Mask Len     |
554 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
555 * |                        Source Address                         |
556 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
557 */
558static int
559pimv2_addr_print(netdissect_options *ndo,
560                 const u_char *bp, u_int len, enum pimv2_addrtype at,
561                 u_int addr_len, int silent)
562{
563	int af;
564	int hdrlen;
565
566	if (addr_len == 0) {
567		if (len < 2)
568			goto trunc;
569		ND_TCHECK(bp[1]);
570		switch (bp[0]) {
571		case 1:
572			af = AF_INET;
573			addr_len = (u_int)sizeof(struct in_addr);
574			break;
575		case 2:
576			af = AF_INET6;
577			addr_len = (u_int)sizeof(struct in6_addr);
578			break;
579		default:
580			return -1;
581		}
582		if (bp[1] != 0)
583			return -1;
584		hdrlen = 2;
585	} else {
586		switch (addr_len) {
587		case sizeof(struct in_addr):
588			af = AF_INET;
589			break;
590		case sizeof(struct in6_addr):
591			af = AF_INET6;
592			break;
593		default:
594			return -1;
595			break;
596		}
597		hdrlen = 0;
598	}
599
600	bp += hdrlen;
601	len -= hdrlen;
602	switch (at) {
603	case pimv2_unicast:
604		if (len < addr_len)
605			goto trunc;
606		ND_TCHECK2(bp[0], addr_len);
607		if (af == AF_INET) {
608			if (!silent)
609				ND_PRINT((ndo, "%s", ipaddr_string(ndo, bp)));
610		}
611		else if (af == AF_INET6) {
612			if (!silent)
613				ND_PRINT((ndo, "%s", ip6addr_string(ndo, bp)));
614		}
615		return hdrlen + addr_len;
616	case pimv2_group:
617	case pimv2_source:
618		if (len < addr_len + 2)
619			goto trunc;
620		ND_TCHECK2(bp[0], addr_len + 2);
621		if (af == AF_INET) {
622			if (!silent) {
623				ND_PRINT((ndo, "%s", ipaddr_string(ndo, bp + 2)));
624				if (bp[1] != 32)
625					ND_PRINT((ndo, "/%u", bp[1]));
626			}
627		}
628		else if (af == AF_INET6) {
629			if (!silent) {
630				ND_PRINT((ndo, "%s", ip6addr_string(ndo, bp + 2)));
631				if (bp[1] != 128)
632					ND_PRINT((ndo, "/%u", bp[1]));
633			}
634		}
635		if (bp[0] && !silent) {
636			if (at == pimv2_group) {
637				ND_PRINT((ndo, "(0x%02x)", bp[0]));
638			} else {
639				ND_PRINT((ndo, "(%s%s%s",
640					bp[0] & 0x04 ? "S" : "",
641					bp[0] & 0x02 ? "W" : "",
642					bp[0] & 0x01 ? "R" : ""));
643				if (bp[0] & 0xf8) {
644					ND_PRINT((ndo, "+0x%02x", bp[0] & 0xf8));
645				}
646				ND_PRINT((ndo, ")"));
647			}
648		}
649		return hdrlen + 2 + addr_len;
650	default:
651		return -1;
652	}
653trunc:
654	return -1;
655}
656
657enum checksum_status {
658	CORRECT,
659	INCORRECT,
660	UNVERIFIED
661};
662
663static enum checksum_status
664pimv2_check_checksum(netdissect_options *ndo, const u_char *bp,
665		     const u_char *bp2, u_int len)
666{
667	const struct ip *ip;
668	u_int cksum;
669
670	if (!ND_TTEST2(bp[0], len)) {
671		/* We don't have all the data. */
672		return (UNVERIFIED);
673	}
674	ip = (const struct ip *)bp2;
675	if (IP_V(ip) == 4) {
676		struct cksum_vec vec[1];
677
678		vec[0].ptr = bp;
679		vec[0].len = len;
680		cksum = in_cksum(vec, 1);
681		return (cksum ? INCORRECT : CORRECT);
682	} else if (IP_V(ip) == 6) {
683		const struct ip6_hdr *ip6;
684
685		ip6 = (const struct ip6_hdr *)bp2;
686		cksum = nextproto6_cksum(ndo, ip6, bp, len, len, IPPROTO_PIM);
687		return (cksum ? INCORRECT : CORRECT);
688	} else {
689		return (UNVERIFIED);
690	}
691}
692
693static void
694pimv2_print(netdissect_options *ndo,
695            register const u_char *bp, register u_int len, const u_char *bp2)
696{
697	register const struct pim *pim = (const struct pim *)bp;
698	int advance;
699	enum checksum_status cksum_status;
700	int pimv2_addr_len;
701
702	if (len < 2)
703		goto trunc;
704	ND_TCHECK(pim->pim_rsv);
705	pimv2_addr_len = pim->pim_rsv;
706	if (pimv2_addr_len != 0)
707		ND_PRINT((ndo, ", RFC2117-encoding"));
708
709	if (len < 4)
710		goto trunc;
711	ND_TCHECK(pim->pim_cksum);
712	ND_PRINT((ndo, ", cksum 0x%04x ", EXTRACT_16BITS(&pim->pim_cksum)));
713	if (EXTRACT_16BITS(&pim->pim_cksum) == 0) {
714		ND_PRINT((ndo, "(unverified)"));
715	} else {
716		if (PIM_TYPE(pim->pim_typever) == PIMV2_TYPE_REGISTER) {
717			/*
718			 * The checksum only covers the packet header,
719			 * not the encapsulated packet.
720			 */
721			cksum_status = pimv2_check_checksum(ndo, bp, bp2, 8);
722			if (cksum_status == INCORRECT) {
723				/*
724				 * To quote RFC 4601, "For interoperability
725				 * reasons, a message carrying a checksum
726				 * calculated over the entire PIM Register
727				 * message should also be accepted."
728				 */
729				cksum_status = pimv2_check_checksum(ndo, bp, bp2, len);
730			}
731		} else {
732			/*
733			 * The checksum covers the entire packet.
734			 */
735			cksum_status = pimv2_check_checksum(ndo, bp, bp2, len);
736		}
737		switch (cksum_status) {
738
739		case CORRECT:
740			ND_PRINT((ndo, "(correct)"));
741			break;
742
743		case INCORRECT:
744			ND_PRINT((ndo, "(incorrect)"));
745			break;
746
747		case UNVERIFIED:
748			ND_PRINT((ndo, "(unverified)"));
749			break;
750		}
751	}
752	bp += 4;
753	len -= 4;
754
755	switch (PIM_TYPE(pim->pim_typever)) {
756	case PIMV2_TYPE_HELLO:
757	    {
758		uint16_t otype, olen;
759		while (len > 0) {
760			if (len < 4)
761				goto trunc;
762			ND_TCHECK2(bp[0], 4);
763			otype = EXTRACT_16BITS(&bp[0]);
764			olen = EXTRACT_16BITS(&bp[2]);
765			ND_PRINT((ndo, "\n\t  %s Option (%u), length %u, Value: ",
766			          tok2str(pimv2_hello_option_values, "Unknown", otype),
767			          otype,
768			          olen));
769			bp += 4;
770			len -= 4;
771
772			if (len < olen)
773				goto trunc;
774			ND_TCHECK2(bp[0], olen);
775			switch (otype) {
776			case PIMV2_HELLO_OPTION_HOLDTIME:
777				if (olen != 2) {
778					ND_PRINT((ndo, "ERROR: Option Length != 2 Bytes (%u)", olen));
779				} else {
780					unsigned_relts_print(ndo, EXTRACT_16BITS(bp));
781				}
782				break;
783
784			case PIMV2_HELLO_OPTION_LANPRUNEDELAY:
785				if (olen != 4) {
786					ND_PRINT((ndo, "ERROR: Option Length != 4 Bytes (%u)", olen));
787				} else {
788					char t_bit;
789					uint16_t lan_delay, override_interval;
790					lan_delay = EXTRACT_16BITS(bp);
791					override_interval = EXTRACT_16BITS(bp+2);
792					t_bit = (lan_delay & 0x8000)? 1 : 0;
793					lan_delay &= ~0x8000;
794					ND_PRINT((ndo, "\n\t    T-bit=%d, LAN delay %dms, Override interval %dms",
795					t_bit, lan_delay, override_interval));
796				}
797				break;
798
799			case PIMV2_HELLO_OPTION_DR_PRIORITY_OLD:
800			case PIMV2_HELLO_OPTION_DR_PRIORITY:
801				switch (olen) {
802				case 0:
803					ND_PRINT((ndo, "Bi-Directional Capability (Old)"));
804					break;
805				case 4:
806					ND_PRINT((ndo, "%u", EXTRACT_32BITS(bp)));
807					break;
808				default:
809					ND_PRINT((ndo, "ERROR: Option Length != 4 Bytes (%u)", olen));
810					break;
811				}
812				break;
813
814			case PIMV2_HELLO_OPTION_GENID:
815				if (olen != 4) {
816					ND_PRINT((ndo, "ERROR: Option Length != 4 Bytes (%u)", olen));
817				} else {
818					ND_PRINT((ndo, "0x%08x", EXTRACT_32BITS(bp)));
819				}
820				break;
821
822			case PIMV2_HELLO_OPTION_REFRESH_CAP:
823				if (olen != 4) {
824					ND_PRINT((ndo, "ERROR: Option Length != 4 Bytes (%u)", olen));
825				} else {
826					ND_PRINT((ndo, "v%d", *bp));
827					if (*(bp+1) != 0) {
828						ND_PRINT((ndo, ", interval "));
829						unsigned_relts_print(ndo, *(bp+1));
830					}
831					if (EXTRACT_16BITS(bp+2) != 0) {
832						ND_PRINT((ndo, " ?0x%04x?", EXTRACT_16BITS(bp+2)));
833					}
834				}
835				break;
836
837			case  PIMV2_HELLO_OPTION_BIDIR_CAP:
838				break;
839
840			case PIMV2_HELLO_OPTION_ADDRESS_LIST_OLD:
841			case PIMV2_HELLO_OPTION_ADDRESS_LIST:
842				if (ndo->ndo_vflag > 1) {
843					const u_char *ptr = bp;
844					u_int plen = len;
845					while (ptr < (bp+olen)) {
846						ND_PRINT((ndo, "\n\t    "));
847						advance = pimv2_addr_print(ndo, ptr, plen, pimv2_unicast, pimv2_addr_len, 0);
848						if (advance < 0)
849							goto trunc;
850						ptr += advance;
851						plen -= advance;
852					}
853				}
854				break;
855			default:
856				if (ndo->ndo_vflag <= 1)
857					print_unknown_data(ndo, bp, "\n\t    ", olen);
858				break;
859			}
860			/* do we want to see an additionally hexdump ? */
861			if (ndo->ndo_vflag> 1)
862				print_unknown_data(ndo, bp, "\n\t    ", olen);
863			bp += olen;
864			len -= olen;
865		}
866		break;
867	    }
868
869	case PIMV2_TYPE_REGISTER:
870	{
871		const struct ip *ip;
872
873		if (len < 4)
874			goto trunc;
875		ND_TCHECK2(*bp, PIMV2_REGISTER_FLAG_LEN);
876
877		ND_PRINT((ndo, ", Flags [ %s ]\n\t",
878		          tok2str(pimv2_register_flag_values,
879		          "none",
880		          EXTRACT_32BITS(bp))));
881
882		bp += 4; len -= 4;
883		/* encapsulated multicast packet */
884		if (len == 0)
885			goto trunc;
886		ip = (const struct ip *)bp;
887		ND_TCHECK(ip->ip_vhl);
888		switch (IP_V(ip)) {
889                case 0: /* Null header */
890			ND_TCHECK(ip->ip_dst);
891			ND_PRINT((ndo, "IP-Null-header %s > %s",
892			          ipaddr_string(ndo, &ip->ip_src),
893			          ipaddr_string(ndo, &ip->ip_dst)));
894			break;
895
896		case 4:	/* IPv4 */
897			ip_print(ndo, bp, len);
898			break;
899
900		case 6:	/* IPv6 */
901			ip6_print(ndo, bp, len);
902			break;
903
904		default:
905			ND_PRINT((ndo, "IP ver %d", IP_V(ip)));
906			break;
907		}
908		break;
909	}
910
911	case PIMV2_TYPE_REGISTER_STOP:
912		ND_PRINT((ndo, " group="));
913		if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_group, pimv2_addr_len, 0)) < 0)
914			goto trunc;
915		bp += advance; len -= advance;
916		ND_PRINT((ndo, " source="));
917		if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_unicast, pimv2_addr_len, 0)) < 0)
918			goto trunc;
919		bp += advance; len -= advance;
920		break;
921
922	case PIMV2_TYPE_JOIN_PRUNE:
923	case PIMV2_TYPE_GRAFT:
924	case PIMV2_TYPE_GRAFT_ACK:
925
926
927        /*
928         * 0                   1                   2                   3
929         *   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
930         *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
931         *  |PIM Ver| Type  | Addr length   |           Checksum            |
932         *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
933         *  |             Unicast-Upstream Neighbor Address                 |
934         *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
935         *  |  Reserved     | Num groups    |          Holdtime             |
936         *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
937         *  |            Encoded-Multicast Group Address-1                  |
938         *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
939         *  |   Number of Joined  Sources   |   Number of Pruned Sources    |
940         *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
941         *  |               Encoded-Joined Source Address-1                 |
942         *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
943         *  |                             .                                 |
944         *  |                             .                                 |
945         *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
946         *  |               Encoded-Joined Source Address-n                 |
947         *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
948         *  |               Encoded-Pruned Source Address-1                 |
949         *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
950         *  |                             .                                 |
951         *  |                             .                                 |
952         *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
953         *  |               Encoded-Pruned Source Address-n                 |
954         *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
955         *  |                           .                                   |
956         *  |                           .                                   |
957         *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
958         *  |                Encoded-Multicast Group Address-n              |
959         *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
960         */
961
962	    {
963		uint8_t ngroup;
964		uint16_t holdtime;
965		uint16_t njoin;
966		uint16_t nprune;
967		int i, j;
968
969		if (PIM_TYPE(pim->pim_typever) != 7) {	/*not for Graft-ACK*/
970			ND_PRINT((ndo, ", upstream-neighbor: "));
971			if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_unicast, pimv2_addr_len, 0)) < 0)
972				goto trunc;
973			bp += advance; len -= advance;
974		}
975		if (len < 4)
976			goto trunc;
977		ND_TCHECK2(*bp, 4);
978		ngroup = bp[1];
979		holdtime = EXTRACT_16BITS(&bp[2]);
980		ND_PRINT((ndo, "\n\t  %u group(s)", ngroup));
981		if (PIM_TYPE(pim->pim_typever) != 7) {	/*not for Graft-ACK*/
982			ND_PRINT((ndo, ", holdtime: "));
983			if (holdtime == 0xffff)
984				ND_PRINT((ndo, "infinite"));
985			else
986				unsigned_relts_print(ndo, holdtime);
987		}
988		bp += 4; len -= 4;
989		for (i = 0; i < ngroup; i++) {
990			ND_PRINT((ndo, "\n\t    group #%u: ", i+1));
991			if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_group, pimv2_addr_len, 0)) < 0)
992				goto trunc;
993			bp += advance; len -= advance;
994			if (len < 4)
995				goto trunc;
996			ND_TCHECK2(*bp, 4);
997			njoin = EXTRACT_16BITS(&bp[0]);
998			nprune = EXTRACT_16BITS(&bp[2]);
999			ND_PRINT((ndo, ", joined sources: %u, pruned sources: %u", njoin, nprune));
1000			bp += 4; len -= 4;
1001			for (j = 0; j < njoin; j++) {
1002				ND_PRINT((ndo, "\n\t      joined source #%u: ", j+1));
1003				if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_source, pimv2_addr_len, 0)) < 0)
1004					goto trunc;
1005				bp += advance; len -= advance;
1006			}
1007			for (j = 0; j < nprune; j++) {
1008				ND_PRINT((ndo, "\n\t      pruned source #%u: ", j+1));
1009				if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_source, pimv2_addr_len, 0)) < 0)
1010					goto trunc;
1011				bp += advance; len -= advance;
1012			}
1013		}
1014		break;
1015	    }
1016
1017	case PIMV2_TYPE_BOOTSTRAP:
1018	{
1019		int i, j, frpcnt;
1020
1021		/* Fragment Tag, Hash Mask len, and BSR-priority */
1022		if (len < 2)
1023			goto trunc;
1024		ND_TCHECK_16BITS(bp);
1025		ND_PRINT((ndo, " tag=%x", EXTRACT_16BITS(bp)));
1026		bp += 2;
1027		len -= 2;
1028		if (len < 1)
1029			goto trunc;
1030		ND_TCHECK(bp[0]);
1031		ND_PRINT((ndo, " hashmlen=%d", bp[0]));
1032		if (len < 2)
1033			goto trunc;
1034		ND_TCHECK(bp[2]);
1035		ND_PRINT((ndo, " BSRprio=%d", bp[1]));
1036		bp += 2;
1037		len -= 2;
1038
1039		/* Encoded-Unicast-BSR-Address */
1040		ND_PRINT((ndo, " BSR="));
1041		if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_unicast, pimv2_addr_len, 0)) < 0)
1042			goto trunc;
1043		bp += advance;
1044		len -= advance;
1045
1046		for (i = 0; len > 0; i++) {
1047			/* Encoded-Group Address */
1048			ND_PRINT((ndo, " (group%d: ", i));
1049			if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_group, pimv2_addr_len, 0)) < 0)
1050				goto trunc;
1051			bp += advance;
1052			len -= advance;
1053
1054			/* RP-Count, Frag RP-Cnt, and rsvd */
1055			if (len < 1)
1056				goto trunc;
1057			ND_TCHECK(bp[0]);
1058			ND_PRINT((ndo, " RPcnt=%d", bp[0]));
1059			if (len < 2)
1060				goto trunc;
1061			ND_TCHECK(bp[1]);
1062			ND_PRINT((ndo, " FRPcnt=%d", frpcnt = bp[1]));
1063			if (len < 4)
1064				goto trunc;
1065			bp += 4;
1066			len -= 4;
1067
1068			for (j = 0; j < frpcnt && len > 0; j++) {
1069				/* each RP info */
1070				ND_PRINT((ndo, " RP%d=", j));
1071				if ((advance = pimv2_addr_print(ndo, bp, len,
1072								pimv2_unicast,
1073								pimv2_addr_len,
1074								0)) < 0)
1075					goto trunc;
1076				bp += advance;
1077				len -= advance;
1078
1079				if (len < 2)
1080					goto trunc;
1081				ND_TCHECK_16BITS(bp);
1082				ND_PRINT((ndo, ",holdtime="));
1083				unsigned_relts_print(ndo, EXTRACT_16BITS(bp));
1084				if (len < 3)
1085					goto trunc;
1086				ND_TCHECK(bp[2]);
1087				ND_PRINT((ndo, ",prio=%d", bp[2]));
1088				if (len < 4)
1089					goto trunc;
1090				bp += 4;
1091				len -= 4;
1092			}
1093			ND_PRINT((ndo, ")"));
1094		}
1095		break;
1096	}
1097	case PIMV2_TYPE_ASSERT:
1098		ND_PRINT((ndo, " group="));
1099		if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_group, pimv2_addr_len, 0)) < 0)
1100			goto trunc;
1101		bp += advance; len -= advance;
1102		ND_PRINT((ndo, " src="));
1103		if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_unicast, pimv2_addr_len, 0)) < 0)
1104			goto trunc;
1105		bp += advance; len -= advance;
1106		if (len < 8)
1107			goto trunc;
1108		ND_TCHECK2(*bp, 8);
1109		if (bp[0] & 0x80)
1110			ND_PRINT((ndo, " RPT"));
1111		ND_PRINT((ndo, " pref=%u", EXTRACT_32BITS(&bp[0]) & 0x7fffffff));
1112		ND_PRINT((ndo, " metric=%u", EXTRACT_32BITS(&bp[4])));
1113		break;
1114
1115	case PIMV2_TYPE_CANDIDATE_RP:
1116	{
1117		int i, pfxcnt;
1118
1119		/* Prefix-Cnt, Priority, and Holdtime */
1120		if (len < 1)
1121			goto trunc;
1122		ND_TCHECK(bp[0]);
1123		ND_PRINT((ndo, " prefix-cnt=%d", bp[0]));
1124		pfxcnt = bp[0];
1125		if (len < 2)
1126			goto trunc;
1127		ND_TCHECK(bp[1]);
1128		ND_PRINT((ndo, " prio=%d", bp[1]));
1129		if (len < 4)
1130			goto trunc;
1131		ND_TCHECK_16BITS(&bp[2]);
1132		ND_PRINT((ndo, " holdtime="));
1133		unsigned_relts_print(ndo, EXTRACT_16BITS(&bp[2]));
1134		bp += 4;
1135		len -= 4;
1136
1137		/* Encoded-Unicast-RP-Address */
1138		ND_PRINT((ndo, " RP="));
1139		if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_unicast, pimv2_addr_len, 0)) < 0)
1140			goto trunc;
1141		bp += advance;
1142		len -= advance;
1143
1144		/* Encoded-Group Addresses */
1145		for (i = 0; i < pfxcnt && len > 0; i++) {
1146			ND_PRINT((ndo, " Group%d=", i));
1147			if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_group, pimv2_addr_len, 0)) < 0)
1148				goto trunc;
1149			bp += advance;
1150			len -= advance;
1151		}
1152		break;
1153	}
1154
1155	case PIMV2_TYPE_PRUNE_REFRESH:
1156		ND_PRINT((ndo, " src="));
1157		if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_unicast, pimv2_addr_len, 0)) < 0)
1158			goto trunc;
1159		bp += advance;
1160		len -= advance;
1161		ND_PRINT((ndo, " grp="));
1162		if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_group, pimv2_addr_len, 0)) < 0)
1163			goto trunc;
1164		bp += advance;
1165		len -= advance;
1166		ND_PRINT((ndo, " forwarder="));
1167		if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_unicast, pimv2_addr_len, 0)) < 0)
1168			goto trunc;
1169		bp += advance;
1170		len -= advance;
1171		if (len < 2)
1172			goto trunc;
1173		ND_TCHECK_16BITS(bp);
1174		ND_PRINT((ndo, " TUNR "));
1175		unsigned_relts_print(ndo, EXTRACT_16BITS(bp));
1176		break;
1177
1178
1179	 default:
1180		ND_PRINT((ndo, " [type %d]", PIM_TYPE(pim->pim_typever)));
1181		break;
1182	}
1183
1184	return;
1185
1186trunc:
1187	ND_PRINT((ndo, "[|pim]"));
1188}
1189
1190/*
1191 * Local Variables:
1192 * c-style: whitesmith
1193 * c-basic-offset: 8
1194 * End:
1195 */
1196