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