]> The Tcpdump Group git mirrors - tcpdump/blob - print-pim.c
corrected offset check and calculation for the RP holdtime and
[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 #ifndef lint
23 static const char rcsid[] =
24 "@(#) $Header: /tcpdump/master/tcpdump/print-pim.c,v 1.12 1999-11-17 14:58:13 itojun Exp $ (LBL)";
25 #endif
26
27 #include <sys/param.h>
28 #include <sys/time.h>
29 #include <sys/socket.h>
30
31 #include <netinet/in.h>
32 #include <netinet/in_systm.h>
33 #include <netinet/ip.h>
34 #include <netinet/ip_var.h>
35 #include <netinet/udp.h>
36 #include <netinet/udp_var.h>
37 #include <netinet/tcp.h>
38
39 /*
40 * XXX: We consider a case where IPv6 is not ready yet for portability,
41 * but PIM dependent defintions should be independent of IPv6...
42 */
43 #ifdef INET6
44 #include <netinet6/pim6.h>
45 #else
46 struct pim {
47 #if defined(WORDS_BIGENDIAN) || (defined(BYTE_ORDER) && (BYTE_ORDER == LITTLE_ENDIAN))
48 u_int pim_type:4, /* the PIM message type, currently they are:
49 * Hello, Register, Register-Stop, Join/Prune,
50 * Bootstrap, Assert, Graft (PIM-DM only),
51 * Graft-Ack (PIM-DM only), C-RP-Adv
52 */
53 pim_ver:4; /* PIM version number; 2 for PIMv2 */
54 #else
55 u_int pim_ver:4, /* PIM version */
56 pim_type:4; /* PIM type */
57 #endif
58 u_char pim_rsv; /* Reserved */
59 u_short pim_cksum; /* IP style check sum */
60 };
61 #endif
62
63
64 #include <stdio.h>
65 #include <stdlib.h>
66 #include <unistd.h>
67
68 #include "interface.h"
69 #include "addrtoname.h"
70
71 static void pimv2_print(register const u_char *bp, register u_int len);
72
73 void
74 igmp_pim_print(register const u_char *bp, register u_int len)
75 {
76 register const u_char *ep;
77 register u_char type;
78
79 ep = (const u_char *)snapend;
80 if (bp >= ep)
81 return;
82
83 type = bp[1];
84
85 switch (type) {
86 case 0:
87 (void)printf(" Query");
88 break;
89
90 case 1:
91 (void)printf(" Register");
92 break;
93
94 case 2:
95 (void)printf(" Register-Stop");
96 break;
97
98 case 3:
99 (void)printf(" Join/Prune");
100 break;
101
102 case 4:
103 (void)printf(" RP-reachable");
104 break;
105
106 case 5:
107 (void)printf(" Assert");
108 break;
109
110 case 6:
111 (void)printf(" Graft");
112 break;
113
114 case 7:
115 (void)printf(" Graft-ACK");
116 break;
117
118 case 8:
119 (void)printf(" Mode");
120 break;
121
122 default:
123 (void)printf(" [type %d]", type);
124 break;
125 }
126 }
127
128 void
129 pim_print(register const u_char *bp, register u_int len)
130 {
131 register const u_char *ep;
132 register struct pim *pim = (struct pim *)bp;
133
134 ep = (const u_char *)snapend;
135 if (bp >= ep)
136 return;
137 #ifdef notyet /* currently we see only version and type */
138 TCHECK(pim->pim_rsv);
139 #endif
140
141 switch(pim->pim_ver) {
142 case 2: /* avoid hardcoding? */
143 (void)printf("v2");
144 pimv2_print(bp, len);
145 break;
146 default:
147 (void)printf("v%d", pim->pim_ver);
148 break;
149 }
150 return;
151 }
152
153 enum pimv2_addrtype {
154 pimv2_unicast, pimv2_group, pimv2_source
155 };
156 #if 0
157 static char *addrtypestr[] = {
158 "unicast", "group", "source"
159 };
160 #endif
161
162 static int
163 pimv2_addr_print(const u_char *bp, enum pimv2_addrtype at, int silent)
164 {
165 const u_char *ep;
166 int af;
167 char *afstr;
168 int len;
169
170 ep = (const u_char *)snapend;
171 if (bp >= ep)
172 return -1;
173
174 switch (bp[0]) {
175 case 1:
176 af = AF_INET;
177 afstr = "IPv4";
178 break;
179 #ifdef INET6
180 case 2:
181 af = AF_INET6;
182 afstr = "IPv6";
183 break;
184 #endif
185 default:
186 return -1;
187 }
188
189 if (bp[1] != 0)
190 return -1;
191
192 switch (at) {
193 case pimv2_unicast:
194 if (af == AF_INET) {
195 len = 4;
196 if (bp + 2 + len > ep)
197 return -1;
198 if (!silent)
199 (void)printf("%s", ipaddr_string(bp + 2));
200 }
201 #ifdef INET6
202 else if (af == AF_INET6) {
203 len = 16;
204 if (bp + 2 + len > ep)
205 return -1;
206 if (!silent)
207 (void)printf("%s", ip6addr_string(bp + 2));
208 }
209 #endif
210 return 2 + len;
211 case pimv2_group:
212 if (af == AF_INET) {
213 len = 4;
214 if (bp + 4 + len > ep)
215 return -1;
216 if (!silent)
217 (void)printf("%s/%u", ipaddr_string(bp + 4), bp[3]);
218 }
219 #ifdef INET6
220 else if (af == AF_INET6) {
221 len = 16;
222 if (bp + 4 + len > ep)
223 return -1;
224 if (!silent)
225 (void)printf("%s/%u", ip6addr_string(bp + 4), bp[3]);
226 }
227 #endif
228 return 4 + len;
229 case pimv2_source:
230 if (af == AF_INET) {
231 len = 4;
232 if (bp + 4 + len > ep)
233 return -1;
234 if (!silent)
235 (void)printf("%s/%u", ipaddr_string(bp + 4), bp[3]);
236 }
237 #ifdef INET6
238 else if (af == AF_INET6) {
239 len = 16;
240 if (bp + 4 + len > ep)
241 return -1;
242 if (!silent)
243 (void)printf("%s/%u", ip6addr_string(bp + 4), bp[3]);
244 }
245 #endif
246 if (vflag && bp[2] && !silent) {
247 (void)printf("(%s%s%s)",
248 bp[2] & 0x04 ? "S" : "",
249 bp[2] & 0x02 ? "W" : "",
250 bp[2] & 0x01 ? "R" : "");
251 }
252 return 4 + len;
253 default:
254 return -1;
255 }
256 }
257
258 static void
259 pimv2_print(register const u_char *bp, register u_int len)
260 {
261 register const u_char *ep;
262 register struct pim *pim = (struct pim *)bp;
263 int advance;
264
265 ep = (const u_char *)snapend;
266 if (bp >= ep)
267 return;
268 #ifdef notyet /* currently we see only version and type */
269 TCHECK(pim->pim_rsv);
270 #endif
271
272 switch (pim->pim_type) {
273 case 0:
274 {
275 u_int16_t otype, olen;
276 (void)printf(" Hello");
277 bp += 4;
278 while (bp < ep) {
279 otype = ntohs(*(u_int16_t *)(bp + 0));
280 olen = ntohs(*(u_int16_t *)(bp + 2));
281 if (otype == 1 && olen == 2 && bp + 4 + olen <= ep) {
282 u_int16_t value;
283 (void)printf(" holdtime=");
284 value = ntohs(*(u_int16_t *)(bp + 4));
285 if (value == 0xffff)
286 (void)printf("infty");
287 else
288 (void)printf("%u", value);
289 bp += 4 + olen;
290 } else
291 break;
292 }
293 break;
294 }
295
296 case 1:
297 {
298 struct ip *ip;
299
300 (void)printf(" Register");
301 if (vflag && bp + 8 <= ep) {
302 (void)printf(" %s%s", bp[4] & 0x80 ? "B" : "",
303 bp[4] & 0x40 ? "N" : "");
304 }
305 bp += 8; len -= 8;
306
307 /* encapsulated multicast packet */
308 if (bp >= ep)
309 break;
310 ip = (struct ip *)bp;
311 switch(ip->ip_v) {
312 case 4: /* IPv4 */
313 printf(" ");
314 ip_print(bp, len);
315 break;
316 #ifdef INET6
317 case 6: /* IPv6 */
318 printf(" ");
319 ip6_print(bp, len);
320 break;
321 #endif
322 default:
323 (void)printf(" IP ver %d", ip->ip_v);
324 break;
325 }
326 break;
327 }
328
329 case 2:
330 (void)printf(" Register-Stop");
331 bp += 4; len -= 4;
332 if (bp >= ep)
333 break;
334 (void)printf(" group=");
335 if ((advance = pimv2_addr_print(bp, pimv2_group, 0)) < 0) {
336 (void)printf("...");
337 break;
338 }
339 bp += advance; len -= advance;
340 if (bp >= ep)
341 break;
342 (void)printf(" source=");
343 if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) {
344 (void)printf("...");
345 break;
346 }
347 bp += advance; len -= advance;
348 break;
349
350 case 3:
351 case 6:
352 case 7:
353 {
354 u_int8_t ngroup;
355 u_int16_t holdtime;
356 u_int16_t njoin;
357 u_int16_t nprune;
358 int i, j;
359
360 switch (pim->pim_type) {
361 case 3:
362 (void)printf(" Join/Prune");
363 break;
364 case 6:
365 (void)printf(" Graft");
366 break;
367 case 7:
368 (void)printf(" Graft-ACK");
369 break;
370 }
371 bp += 4; len -= 4;
372 if (pim->pim_type != 7) { /*not for Graft-ACK*/
373 if (bp >= ep)
374 break;
375 (void)printf(" upstream-neighbor=");
376 if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) {
377 (void)printf("...");
378 break;
379 }
380 bp += advance; len -= advance;
381 }
382 if (bp + 4 > ep)
383 break;
384 ngroup = bp[1];
385 holdtime = ntohs(*(u_int16_t *)(bp + 2));
386 (void)printf(" groups=%u", ngroup);
387 if (pim->pim_type != 7) { /*not for Graft-ACK*/
388 (void)printf(" holdtime=");
389 if (holdtime == 0xffff)
390 (void)printf("infty");
391 else
392 (void)printf("%u", holdtime);
393 }
394 bp += 4; len -= 4;
395 for (i = 0; i < ngroup; i++) {
396 if (bp >= ep)
397 goto jp_done;
398 (void)printf(" (group%d: ", i);
399 if ((advance = pimv2_addr_print(bp, pimv2_group, 0)) < 0) {
400 (void)printf("...)");
401 goto jp_done;
402 }
403 bp += advance; len -= advance;
404 if (bp + 4 > ep) {
405 (void)printf("...)");
406 goto jp_done;
407 }
408 njoin = ntohs(*(u_int16_t *)(bp + 0));
409 nprune = ntohs(*(u_int16_t *)(bp + 2));
410 (void)printf(" join=%u", njoin);
411 bp += 4; len -= 4;
412 for (j = 0; j < njoin; j++) {
413 (void)printf(" ");
414 if ((advance = pimv2_addr_print(bp, pimv2_source, 0)) < 0) {
415 (void)printf("...)");
416 goto jp_done;
417 }
418 bp += advance; len -= advance;
419 }
420 (void)printf(" prune=%u", nprune);
421 for (j = 0; j < nprune; j++) {
422 (void)printf(" ");
423 if ((advance = pimv2_addr_print(bp, pimv2_source, 0)) < 0) {
424 (void)printf("...)");
425 goto jp_done;
426 }
427 bp += advance; len -= advance;
428 }
429 (void)printf(")");
430 }
431 jp_done:
432 break;
433 }
434
435 case 4:
436 {
437 int i, j, frpcnt;
438
439 (void)printf(" Bootstrap");
440 bp += 4;
441
442 /* Fragment Tag, Hash Mask len, and BSR-priority */
443 if (bp + sizeof(u_int16_t) >= ep) break;
444 (void)printf(" tag=%x", ntohs(*(u_int16_t *)bp));
445 bp += sizeof(u_int16_t);
446 if (bp >= ep) break;
447 (void)printf(" hashmlen=%d", bp[0]);
448 if (bp + 1 >= ep) break;
449 (void)printf(" BSRprio=%d", bp[1]);
450 bp += 2;
451
452 /* Encoded-Unicast-BSR-Address */
453 if (bp >= ep) break;
454 (void)printf(" BSR=");
455 if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) {
456 (void)printf("...");
457 break;
458 }
459 bp += advance;
460
461 for (i = 0; bp < ep; i++) {
462 /* Encoded-Group Address */
463 (void)printf(" (group%d: ", i);
464 if ((advance = pimv2_addr_print(bp, pimv2_group, 0))
465 < 0) {
466 (void)printf("...)");
467 goto bs_done;
468 }
469 bp += advance;
470
471 /* RP-Count, Frag RP-Cnt, and rsvd */
472 if (bp >= ep) {
473 (void)printf("...)");
474 goto bs_done;
475 }
476 (void)printf(" RPcnt=%d", frpcnt = bp[0]);
477 if (bp + 1 >= ep) {
478 (void)printf("...)");
479 goto bs_done;
480 }
481 (void)printf(" FRPcnt=%d", bp[1]);
482 bp += 4;
483
484 for (j = 0; j < frpcnt && bp < ep; j++) {
485 /* each RP info */
486 (void)printf(" RP%d=", j);
487 if ((advance = pimv2_addr_print(bp,
488 pimv2_unicast,
489 0)) < 0) {
490 (void)printf("...)");
491 goto bs_done;
492 }
493 bp += advance;
494
495 if (bp + 1 >= ep) {
496 (void)printf("...)");
497 goto bs_done;
498 }
499 (void)printf(",holdtime=%d",
500 ntohs(*(u_int16_t *)bp));
501 if (bp + 2 >= ep) {
502 (void)printf("...)");
503 goto bs_done;
504 }
505 (void)printf(",prio=%d", bp[2]);
506 bp += 4;
507 }
508 (void)printf(")");
509 }
510 bs_done:
511 break;
512 }
513 case 5:
514 (void)printf(" Assert");
515 bp += 4; len -= 4;
516 if (bp >= ep)
517 break;
518 (void)printf(" group=");
519 if ((advance = pimv2_addr_print(bp, pimv2_group, 0)) < 0) {
520 (void)printf("...");
521 break;
522 }
523 bp += advance; len -= advance;
524 if (bp >= ep)
525 break;
526 (void)printf(" src=");
527 if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) {
528 (void)printf("...");
529 break;
530 }
531 bp += advance; len -= advance;
532 if (bp + 8 > ep)
533 break;
534 if (ntohl(*(u_int32_t *)bp) & 0x80000000)
535 (void)printf(" RPT");
536 (void)printf(" pref=%u", ntohl(*(u_int32_t *)bp & 0x7fffffff));
537 (void)printf(" metric=%u", ntohl(*(u_int32_t *)(bp + 4)));
538 break;
539
540 case 8:
541 {
542 int i, pfxcnt;
543
544 (void)printf(" Candidate-RP-Advertisement");
545 bp += 4;
546
547 /* Prefix-Cnt, Priority, and Holdtime */
548 if (bp >= ep) break;
549 (void)printf(" prefix-cnt=%d", bp[0]);
550 pfxcnt = bp[0];
551 if (bp + 1 >= ep) break;
552 (void)printf(" prio=%d", bp[1]);
553 if (bp + 3 >= ep) break;
554 (void)printf(" holdtime=%d", ntohs(*(u_int16_t *)(bp + 2)));
555 bp += 4;
556
557 /* Encoded-Unicast-RP-Address */
558 if (bp >= ep) break;
559 (void)printf(" RP=");
560 if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) {
561 (void)printf("...");
562 break;
563 }
564 bp += advance;
565
566 /* Encoded-Group Addresses */
567 for (i = 0; i < pfxcnt && bp < ep; i++) {
568 (void)printf(" Group%d=", i);
569 if ((advance = pimv2_addr_print(bp, pimv2_group, 0))
570 < 0) {
571 (void)printf("...");
572 break;
573 }
574 bp += advance;
575 }
576 break;
577 }
578
579 default:
580 (void)printf(" [type %d]", pim->pim_type);
581 break;
582 }
583
584 return;
585 }