print-pim.c revision 56893
117680Spst/* 217680Spst * Copyright (c) 1995, 1996 317680Spst * The Regents of the University of California. All rights reserved. 417680Spst * 517680Spst * Redistribution and use in source and binary forms, with or without 617680Spst * modification, are permitted provided that: (1) source code distributions 717680Spst * retain the above copyright notice and this paragraph in its entirety, (2) 817680Spst * distributions including binary code include the above copyright notice and 917680Spst * this paragraph in its entirety in the documentation or other materials 1017680Spst * provided with the distribution, and (3) all advertising materials mentioning 1117680Spst * features or use of this software display the following acknowledgement: 1217680Spst * ``This product includes software developed by the University of California, 1317680Spst * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 1417680Spst * the University nor the names of its contributors may be used to endorse 1517680Spst * or promote products derived from this software without specific prior 1617680Spst * written permission. 1717680Spst * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 1817680Spst * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 1917680Spst * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 2017680Spst */ 2117680Spst 2217680Spst#ifndef lint 2326180Sfennerstatic const char rcsid[] = 2456893Sfenner "@(#) $Header: /tcpdump/master/tcpdump/print-pim.c,v 1.15.2.1 2000/01/25 18:29:05 itojun Exp $ (LBL)"; 2517680Spst#endif 2617680Spst 2756893Sfenner#ifdef HAVE_CONFIG_H 2856893Sfenner#include "config.h" 2956893Sfenner#endif 3056893Sfenner 3117680Spst#include <sys/param.h> 3217680Spst#include <sys/time.h> 3317680Spst#include <sys/socket.h> 3417680Spst 3517680Spst#include <netinet/in.h> 3617680Spst#include <netinet/in_systm.h> 3717680Spst#include <netinet/ip.h> 3817680Spst 3956893Sfenner/* 4056893Sfenner * XXX: We consider a case where IPv6 is not ready yet for portability, 4156893Sfenner * but PIM dependent defintions should be independent of IPv6... 4256893Sfenner */ 4356893Sfenner 4456893Sfennerstruct pim { 4556893Sfenner u_int8_t pim_typever; 4656893Sfenner /* upper 4bit: the PIM message type, currently they are: 4756893Sfenner * Hello, Register, Register-Stop, Join/Prune, 4856893Sfenner * Bootstrap, Assert, Graft (PIM-DM only), 4956893Sfenner * Graft-Ack (PIM-DM only), C-RP-Adv 5056893Sfenner */ 5156893Sfenner /* lower 4bit: PIM version number; 2 for PIMv2 */ 5256893Sfenner#define PIM_TYPE(x) (((x) & 0xf0) >> 4) 5356893Sfenner#define PIM_VER(x) ((x) & 0x0f) 5456893Sfenner u_char pim_rsv; /* Reserved */ 5556893Sfenner u_short pim_cksum; /* IP style check sum */ 5656893Sfenner}; 5756893Sfenner 5856893Sfenner 5917680Spst#include <stdio.h> 6017680Spst#include <stdlib.h> 6117680Spst#include <unistd.h> 6217680Spst 6317680Spst#include "interface.h" 6417680Spst#include "addrtoname.h" 6556893Sfenner#include "extract.h" 6617680Spst 6756893Sfennerstatic void pimv2_print(register const u_char *bp, register u_int len); 6856893Sfenner 6956893Sfennerstatic void 7056893Sfennerpimv1_join_prune_print(register const u_char *bp, register u_int len) 7156893Sfenner{ 7256893Sfenner int maddrlen, addrlen, ngroups, njoin, nprune; 7356893Sfenner int njp; 7456893Sfenner 7556893Sfenner /* If it's a single group and a single source, use 1-line output. */ 7656893Sfenner if (TTEST2(bp[0], 30) && bp[11] == 1 && 7756893Sfenner ((njoin = EXTRACT_16BITS(&bp[20])) + EXTRACT_16BITS(&bp[22])) == 1) { 7856893Sfenner int hold; 7956893Sfenner 8056893Sfenner (void)printf(" RPF %s ", ipaddr_string(bp)); 8156893Sfenner hold = EXTRACT_16BITS(&bp[6]); 8256893Sfenner if (hold != 180) { 8356893Sfenner (void)printf("Hold "); 8456893Sfenner relts_print(hold); 8556893Sfenner } 8656893Sfenner (void)printf("%s (%s/%d, %s", njoin ? "Join" : "Prune", 8756893Sfenner ipaddr_string(&bp[26]), bp[25] & 0x3f, 8856893Sfenner ipaddr_string(&bp[12])); 8956893Sfenner if (EXTRACT_32BITS(&bp[16]) != 0xffffffff) 9056893Sfenner (void)printf("/%s", ipaddr_string(&bp[16])); 9156893Sfenner (void)printf(") %s%s %s", 9256893Sfenner (bp[24] & 0x01) ? "Sparse" : "Dense", 9356893Sfenner (bp[25] & 0x80) ? " WC" : "", 9456893Sfenner (bp[25] & 0x40) ? "RP" : "SPT"); 9556893Sfenner return; 9656893Sfenner } 9756893Sfenner 9856893Sfenner TCHECK2(bp[0], 4); 9956893Sfenner (void)printf("\n Upstream Nbr: %s", ipaddr_string(bp)); 10056893Sfenner TCHECK2(bp[6], 2); 10156893Sfenner (void)printf("\n Hold time: "); 10256893Sfenner relts_print(EXTRACT_16BITS(&bp[6])); 10356893Sfenner bp += 8; len -= 8; 10456893Sfenner 10556893Sfenner TCHECK2(bp[0], 4); 10656893Sfenner maddrlen = bp[1]; 10756893Sfenner addrlen = bp[2]; 10856893Sfenner ngroups = bp[3]; 10956893Sfenner bp += 4; len -= 4; 11056893Sfenner while (ngroups--) { 11156893Sfenner TCHECK2(bp[0], 4); 11256893Sfenner (void)printf("\n\tGroup: %s", ipaddr_string(bp)); 11356893Sfenner if (EXTRACT_32BITS(&bp[4]) != 0xffffffff) 11456893Sfenner (void)printf("/%s", ipaddr_string(&bp[4])); 11556893Sfenner TCHECK2(bp[8], 4); 11656893Sfenner njoin = EXTRACT_16BITS(&bp[8]); 11756893Sfenner nprune = EXTRACT_16BITS(&bp[10]); 11856893Sfenner (void)printf(" joined: %d pruned: %d", njoin, nprune); 11956893Sfenner bp += 12; len -= 12; 12056893Sfenner for (njp = 0; njp < (njoin + nprune); njp++) { 12156893Sfenner char *type; 12256893Sfenner 12356893Sfenner if (njp < njoin) { 12456893Sfenner type = "Join "; 12556893Sfenner } else { 12656893Sfenner type = "Prune"; 12756893Sfenner } 12856893Sfenner TCHECK2(bp[0], 6); 12956893Sfenner (void)printf("\n\t%s %s%s%s%s/%d", type, 13056893Sfenner (bp[0] & 0x01) ? "Sparse " : "Dense ", 13156893Sfenner (bp[1] & 0x80) ? "WC " : "", 13256893Sfenner (bp[1] & 0x40) ? "RP " : "SPT ", 13356893Sfenner ipaddr_string(&bp[2]), bp[1] & 0x3f); 13456893Sfenner bp += 6; len -= 6; 13556893Sfenner } 13656893Sfenner } 13756893Sfenner return; 13856893Sfennertrunc: 13956893Sfenner (void)printf("[|pim]"); 14056893Sfenner return; 14156893Sfenner} 14256893Sfenner 14317680Spstvoid 14456893Sfennerpimv1_print(register const u_char *bp, register u_int len) 14517680Spst{ 14617680Spst register const u_char *ep; 14717680Spst register u_char type; 14817680Spst 14917680Spst ep = (const u_char *)snapend; 15017680Spst if (bp >= ep) 15117680Spst return; 15217680Spst 15317680Spst type = bp[1]; 15417680Spst 15517680Spst switch (type) { 15617680Spst case 0: 15717680Spst (void)printf(" Query"); 15856893Sfenner if (TTEST(bp[8])) { 15956893Sfenner switch (bp[8] >> 4) { 16056893Sfenner case 0: (void)printf(" Dense-mode"); 16156893Sfenner break; 16256893Sfenner case 1: (void)printf(" Sparse-mode"); 16356893Sfenner break; 16456893Sfenner case 2: (void)printf(" Sparse-Dense-mode"); 16556893Sfenner break; 16656893Sfenner default: (void)printf(" mode-%d", bp[8] >> 4); 16756893Sfenner break; 16856893Sfenner } 16956893Sfenner } 17056893Sfenner if (vflag) { 17156893Sfenner TCHECK2(bp[10],2); 17256893Sfenner (void)printf(" (Hold-time "); 17356893Sfenner relts_print(EXTRACT_16BITS(&bp[10])); 17456893Sfenner (void)printf(")"); 17556893Sfenner } 17617680Spst break; 17717680Spst 17817680Spst case 1: 17917680Spst (void)printf(" Register"); 18056893Sfenner TCHECK2(bp[8], 20); /* ip header */ 18156893Sfenner (void)printf(" for %s > %s", ipaddr_string(&bp[20]), 18256893Sfenner ipaddr_string(&bp[24])); 18317680Spst break; 18417680Spst 18517680Spst case 2: 18617680Spst (void)printf(" Register-Stop"); 18756893Sfenner TCHECK2(bp[12], 4); 18856893Sfenner (void)printf(" for %s > %s", ipaddr_string(&bp[8]), 18956893Sfenner ipaddr_string(&bp[12])); 19017680Spst break; 19117680Spst 19217680Spst case 3: 19317680Spst (void)printf(" Join/Prune"); 19456893Sfenner if (vflag) { 19556893Sfenner pimv1_join_prune_print(&bp[8], len - 8); 19656893Sfenner } 19717680Spst break; 19817680Spst 19917680Spst case 4: 20017680Spst (void)printf(" RP-reachable"); 20156893Sfenner if (vflag) { 20256893Sfenner TCHECK2(bp[22], 2); 20356893Sfenner (void)printf(" group %s", 20456893Sfenner ipaddr_string(&bp[8])); 20556893Sfenner if (EXTRACT_32BITS(&bp[12]) != 0xffffffff) 20656893Sfenner (void)printf("/%s", ipaddr_string(&bp[12])); 20756893Sfenner (void)printf(" RP %s hold ", 20856893Sfenner ipaddr_string(&bp[16])); 20956893Sfenner relts_print(EXTRACT_16BITS(&bp[22])); 21056893Sfenner } 21117680Spst break; 21217680Spst 21317680Spst case 5: 21417680Spst (void)printf(" Assert"); 21556893Sfenner TCHECK2(bp[16], 4); 21656893Sfenner (void)printf(" for %s > %s", ipaddr_string(&bp[16]), 21756893Sfenner ipaddr_string(&bp[8])); 21856893Sfenner if (EXTRACT_32BITS(&bp[12]) != 0xffffffff) 21956893Sfenner (void)printf("/%s", ipaddr_string(&bp[12])); 22056893Sfenner TCHECK2(bp[24], 4); 22156893Sfenner (void)printf(" %s pref %d metric %d", 22256893Sfenner (bp[20] & 0x80) ? "RP-tree" : "SPT", 22356893Sfenner EXTRACT_32BITS(&bp[20]) & 0x7fffffff, 22456893Sfenner EXTRACT_32BITS(&bp[24])); 22517680Spst break; 22617680Spst 22717680Spst case 6: 22817680Spst (void)printf(" Graft"); 22956893Sfenner if (vflag) { 23056893Sfenner pimv1_join_prune_print(&bp[8], len - 8); 23156893Sfenner } 23217680Spst break; 23317680Spst 23417680Spst case 7: 23517680Spst (void)printf(" Graft-ACK"); 23656893Sfenner if (vflag) { 23756893Sfenner pimv1_join_prune_print(&bp[8], len - 8); 23856893Sfenner } 23917680Spst break; 24017680Spst 24117680Spst case 8: 24217680Spst (void)printf(" Mode"); 24317680Spst break; 24417680Spst 24517680Spst default: 24617680Spst (void)printf(" [type %d]", type); 24717680Spst break; 24817680Spst } 24956893Sfenner if ((bp[4] >> 4) != 1) 25056893Sfenner (void)printf(" [v%d]", bp[4] >> 4); 25156893Sfenner return; 25256893Sfenner 25356893Sfennertrunc: 25456893Sfenner (void)printf("[|pim]"); 25556893Sfenner return; 25617680Spst} 25756893Sfenner 25856893Sfenner/* 25956893Sfenner * auto-RP is a cisco protocol, documented at 26056893Sfenner * ftp://ftpeng.cisco.com/ipmulticast/pim-autorp-spec01.txt 26156893Sfenner */ 26256893Sfennervoid 26356893Sfennercisco_autorp_print(register const u_char *bp, register u_int len) 26456893Sfenner{ 26556893Sfenner int type; 26656893Sfenner int numrps; 26756893Sfenner int hold; 26856893Sfenner 26956893Sfenner TCHECK(bp[0]); 27056893Sfenner (void)printf(" auto-rp "); 27156893Sfenner type = bp[0]; 27256893Sfenner switch (type) { 27356893Sfenner case 0x11: 27456893Sfenner (void)printf("candidate-advert"); 27556893Sfenner break; 27656893Sfenner case 0x12: 27756893Sfenner (void)printf("mapping"); 27856893Sfenner break; 27956893Sfenner default: 28056893Sfenner (void)printf("type-0x%02x", type); 28156893Sfenner break; 28256893Sfenner } 28356893Sfenner 28456893Sfenner TCHECK(bp[1]); 28556893Sfenner numrps = bp[1]; 28656893Sfenner 28756893Sfenner TCHECK2(bp[2], 2); 28856893Sfenner (void)printf(" Hold "); 28956893Sfenner hold = EXTRACT_16BITS(&bp[2]); 29056893Sfenner if (hold) 29156893Sfenner relts_print(EXTRACT_16BITS(&bp[2])); 29256893Sfenner else 29356893Sfenner printf("FOREVER"); 29456893Sfenner 29556893Sfenner /* Next 4 bytes are reserved. */ 29656893Sfenner 29756893Sfenner bp += 8; len -= 8; 29856893Sfenner 29956893Sfenner /*XXX skip unless -v? */ 30056893Sfenner 30156893Sfenner /* 30256893Sfenner * Rest of packet: 30356893Sfenner * numrps entries of the form: 30456893Sfenner * 32 bits: RP 30556893Sfenner * 6 bits: reserved 30656893Sfenner * 2 bits: PIM version supported, bit 0 is "supports v1", 1 is "v2". 30756893Sfenner * 8 bits: # of entries for this RP 30856893Sfenner * each entry: 7 bits: reserved, 1 bit: negative, 30956893Sfenner * 8 bits: mask 32 bits: source 31056893Sfenner * lather, rinse, repeat. 31156893Sfenner */ 31256893Sfenner while (numrps--) { 31356893Sfenner int nentries; 31456893Sfenner char s; 31556893Sfenner 31656893Sfenner TCHECK2(bp[0], 4); 31756893Sfenner (void)printf(" RP %s", ipaddr_string(bp)); 31856893Sfenner TCHECK(bp[4]); 31956893Sfenner switch(bp[4] & 0x3) { 32056893Sfenner case 0: printf(" PIMv?"); 32156893Sfenner break; 32256893Sfenner case 1: printf(" PIMv1"); 32356893Sfenner break; 32456893Sfenner case 2: printf(" PIMv2"); 32556893Sfenner break; 32656893Sfenner case 3: printf(" PIMv1+2"); 32756893Sfenner break; 32856893Sfenner } 32956893Sfenner TCHECK(bp[5]); 33056893Sfenner nentries = bp[5]; 33156893Sfenner bp += 6; len -= 6; 33256893Sfenner s = ' '; 33356893Sfenner for (; nentries; nentries--) { 33456893Sfenner TCHECK2(bp[0], 6); 33556893Sfenner (void)printf("%c%s%s/%d", s, bp[0] & 1 ? "!" : "", 33656893Sfenner ipaddr_string(&bp[2]), bp[1]); 33756893Sfenner s = ','; 33856893Sfenner bp += 6; len -= 6; 33956893Sfenner } 34056893Sfenner } 34156893Sfenner return; 34256893Sfenner 34356893Sfennertrunc: 34456893Sfenner (void)printf("[|autorp]"); 34556893Sfenner return; 34656893Sfenner} 34756893Sfenner 34856893Sfennervoid 34956893Sfennerpim_print(register const u_char *bp, register u_int len) 35056893Sfenner{ 35156893Sfenner register const u_char *ep; 35256893Sfenner register struct pim *pim = (struct pim *)bp; 35356893Sfenner 35456893Sfenner ep = (const u_char *)snapend; 35556893Sfenner if (bp >= ep) 35656893Sfenner return; 35756893Sfenner#ifdef notyet /* currently we see only version and type */ 35856893Sfenner TCHECK(pim->pim_rsv); 35956893Sfenner#endif 36056893Sfenner 36156893Sfenner switch(PIM_VER(pim->pim_typever)) { 36256893Sfenner case 2: /* avoid hardcoding? */ 36356893Sfenner (void)printf("v2"); 36456893Sfenner pimv2_print(bp, len); 36556893Sfenner break; 36656893Sfenner default: 36756893Sfenner (void)printf("v%d", PIM_VER(pim->pim_typever)); 36856893Sfenner break; 36956893Sfenner } 37056893Sfenner return; 37156893Sfenner} 37256893Sfenner 37356893Sfenner/* 37456893Sfenner * PIMv2 uses encoded address representations. 37556893Sfenner * 37656893Sfenner * The last PIM-SM I-D before RFC2117 was published specified the 37756893Sfenner * following representation for unicast addresses. However, RFC2117 37856893Sfenner * specified no encoding for unicast addresses with the unicast 37956893Sfenner * address length specified in the header. Therefore, we have to 38056893Sfenner * guess which encoding is being used (Cisco's PIMv2 implementation 38156893Sfenner * uses the non-RFC encoding). RFC2117 turns a previously "Reserved" 38256893Sfenner * field into a 'unicast-address-length-in-bytes' field. We guess 38356893Sfenner * that it's the draft encoding if this reserved field is zero. 38456893Sfenner * 38556893Sfenner * RFC2362 goes back to the encoded format, and calls the addr length 38656893Sfenner * field "reserved" again. 38756893Sfenner * 38856893Sfenner * The first byte is the address family, from: 38956893Sfenner * 39056893Sfenner * 0 Reserved 39156893Sfenner * 1 IP (IP version 4) 39256893Sfenner * 2 IP6 (IP version 6) 39356893Sfenner * 3 NSAP 39456893Sfenner * 4 HDLC (8-bit multidrop) 39556893Sfenner * 5 BBN 1822 39656893Sfenner * 6 802 (includes all 802 media plus Ethernet "canonical format") 39756893Sfenner * 7 E.163 39856893Sfenner * 8 E.164 (SMDS, Frame Relay, ATM) 39956893Sfenner * 9 F.69 (Telex) 40056893Sfenner * 10 X.121 (X.25, Frame Relay) 40156893Sfenner * 11 IPX 40256893Sfenner * 12 Appletalk 40356893Sfenner * 13 Decnet IV 40456893Sfenner * 14 Banyan Vines 40556893Sfenner * 15 E.164 with NSAP format subaddress 40656893Sfenner * 40756893Sfenner * In addition, the second byte is an "Encoding". 0 is the default 40856893Sfenner * encoding for the address family, and no other encodings are currently 40956893Sfenner * specified. 41056893Sfenner * 41156893Sfenner */ 41256893Sfenner 41356893Sfennerstatic int pimv2_addr_len; 41456893Sfenner 41556893Sfennerenum pimv2_addrtype { 41656893Sfenner pimv2_unicast, pimv2_group, pimv2_source 41756893Sfenner}; 41856893Sfenner#if 0 41956893Sfennerstatic char *addrtypestr[] = { 42056893Sfenner "unicast", "group", "source" 42156893Sfenner}; 42256893Sfenner#endif 42356893Sfenner 42456893Sfenner/* 0 1 2 3 42556893Sfenner * 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 42656893Sfenner * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 42756893Sfenner * | Addr Family | Encoding Type | Unicast Address | 42856893Sfenner * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+++++++ 42956893Sfenner * 0 1 2 3 43056893Sfenner * 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 43156893Sfenner * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 43256893Sfenner * | Addr Family | Encoding Type | Reserved | Mask Len | 43356893Sfenner * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 43456893Sfenner * | Group multicast Address | 43556893Sfenner * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 43656893Sfenner * 0 1 2 3 43756893Sfenner * 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 43856893Sfenner * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 43956893Sfenner * | Addr Family | Encoding Type | Rsrvd |S|W|R| Mask Len | 44056893Sfenner * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 44156893Sfenner * | Source Address | 44256893Sfenner * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 44356893Sfenner */ 44456893Sfennerstatic int 44556893Sfennerpimv2_addr_print(const u_char *bp, enum pimv2_addrtype at, int silent) 44656893Sfenner{ 44756893Sfenner int af; 44856893Sfenner char *afstr; 44956893Sfenner int len, hdrlen; 45056893Sfenner 45156893Sfenner TCHECK(bp[0]); 45256893Sfenner 45356893Sfenner if (pimv2_addr_len == 0) { 45456893Sfenner TCHECK(bp[1]); 45556893Sfenner switch (bp[0]) { 45656893Sfenner case 1: 45756893Sfenner af = AF_INET; 45856893Sfenner afstr = "IPv4"; 45956893Sfenner len = 4; 46056893Sfenner break; 46156893Sfenner#ifdef INET6 46256893Sfenner case 2: 46356893Sfenner af = AF_INET6; 46456893Sfenner afstr = "IPv6"; 46556893Sfenner len = 16; 46656893Sfenner break; 46756893Sfenner#endif 46856893Sfenner default: 46956893Sfenner return -1; 47056893Sfenner } 47156893Sfenner if (bp[1] != 0) 47256893Sfenner return -1; 47356893Sfenner hdrlen = 2; 47456893Sfenner } else { 47556893Sfenner switch (pimv2_addr_len) { 47656893Sfenner case 4: 47756893Sfenner af = AF_INET; 47856893Sfenner afstr = "IPv4"; 47956893Sfenner break; 48056893Sfenner#ifdef INET6 48156893Sfenner case 16: 48256893Sfenner af = AF_INET6; 48356893Sfenner afstr = "IPv6"; 48456893Sfenner break; 48556893Sfenner#endif 48656893Sfenner default: 48756893Sfenner return -1; 48856893Sfenner break; 48956893Sfenner } 49056893Sfenner len = pimv2_addr_len; 49156893Sfenner hdrlen = 0; 49256893Sfenner } 49356893Sfenner 49456893Sfenner bp += hdrlen; 49556893Sfenner switch (at) { 49656893Sfenner case pimv2_unicast: 49756893Sfenner TCHECK2(bp[0], len); 49856893Sfenner if (af == AF_INET) { 49956893Sfenner if (!silent) 50056893Sfenner (void)printf("%s", ipaddr_string(bp)); 50156893Sfenner } 50256893Sfenner#ifdef INET6 50356893Sfenner else if (af == AF_INET6) { 50456893Sfenner if (!silent) 50556893Sfenner (void)printf("%s", ip6addr_string(bp)); 50656893Sfenner } 50756893Sfenner#endif 50856893Sfenner return hdrlen + len; 50956893Sfenner case pimv2_group: 51056893Sfenner case pimv2_source: 51156893Sfenner TCHECK2(bp[0], len + 2); 51256893Sfenner if (af == AF_INET) { 51356893Sfenner if (!silent) { 51456893Sfenner (void)printf("%s", ipaddr_string(bp + 2)); 51556893Sfenner if (bp[1] != 32) 51656893Sfenner (void)printf("/%u", bp[1]); 51756893Sfenner } 51856893Sfenner } 51956893Sfenner#ifdef INET6 52056893Sfenner else if (af == AF_INET6) { 52156893Sfenner if (!silent) { 52256893Sfenner (void)printf("%s", ip6addr_string(bp + 2)); 52356893Sfenner if (bp[1] != 128) 52456893Sfenner (void)printf("/%u", bp[1]); 52556893Sfenner } 52656893Sfenner } 52756893Sfenner#endif 52856893Sfenner if (bp[0] && !silent) { 52956893Sfenner if (at == pimv2_group) { 53056893Sfenner (void)printf("(0x%02x)", bp[0]); 53156893Sfenner } else { 53256893Sfenner (void)printf("(%s%s%s", 53356893Sfenner bp[0] & 0x04 ? "S" : "", 53456893Sfenner bp[0] & 0x02 ? "W" : "", 53556893Sfenner bp[0] & 0x01 ? "R" : ""); 53656893Sfenner if (bp[0] & 0xf8) { 53756893Sfenner (void) printf("+0x%02x", bp[0] & 0xf8); 53856893Sfenner } 53956893Sfenner (void)printf(")"); 54056893Sfenner } 54156893Sfenner } 54256893Sfenner return hdrlen + 2 + len; 54356893Sfenner default: 54456893Sfenner return -1; 54556893Sfenner } 54656893Sfennertrunc: 54756893Sfenner return -1; 54856893Sfenner} 54956893Sfenner 55056893Sfennerstatic void 55156893Sfennerpimv2_print(register const u_char *bp, register u_int len) 55256893Sfenner{ 55356893Sfenner register const u_char *ep; 55456893Sfenner register struct pim *pim = (struct pim *)bp; 55556893Sfenner int advance; 55656893Sfenner 55756893Sfenner ep = (const u_char *)snapend; 55856893Sfenner if (bp >= ep) 55956893Sfenner return; 56056893Sfenner TCHECK(pim->pim_rsv); 56156893Sfenner pimv2_addr_len = pim->pim_rsv; 56256893Sfenner if (pimv2_addr_len != 0) 56356893Sfenner (void)printf("[RFC2117-encoding] "); 56456893Sfenner 56556893Sfenner switch (PIM_TYPE(pim->pim_typever)) { 56656893Sfenner case 0: 56756893Sfenner { 56856893Sfenner u_int16_t otype, olen; 56956893Sfenner (void)printf(" Hello"); 57056893Sfenner bp += 4; 57156893Sfenner while (bp < ep) { 57256893Sfenner TCHECK2(bp[0], 4); 57356893Sfenner otype = EXTRACT_16BITS(&bp[0]); 57456893Sfenner olen = EXTRACT_16BITS(&bp[2]); 57556893Sfenner TCHECK2(bp[0], 4 + olen); 57656893Sfenner switch (otype) { 57756893Sfenner case 1: /* Hold time */ 57856893Sfenner (void)printf(" (Hold-time "); 57956893Sfenner relts_print(EXTRACT_16BITS(&bp[4])); 58056893Sfenner (void)printf(")"); 58156893Sfenner break; 58256893Sfenner 58356893Sfenner /* XXX 58456893Sfenner * draft-ietf-idmr-pimv2-dr-priority-00.txt 58556893Sfenner * says that DR-Priority is option 19. 58656893Sfenner * draft-ietf-pim-v2-sm-00.txt says it's 18. 58756893Sfenner */ 58856893Sfenner case 18: /* DR-Priority */ 58956893Sfenner (void)printf(" (DR-Priority: %d)", EXTRACT_32BITS(&bp[4])); 59056893Sfenner break; 59156893Sfenner 59256893Sfenner case 19: /* Bidir-Capable */ 59356893Sfenner if (olen == 4) 59456893Sfenner (void)printf(" (OLD-DR-Priority: %d)", EXTRACT_32BITS(&bp[4])); 59556893Sfenner else 59656893Sfenner (void)printf(" (bidir-capable)"); 59756893Sfenner break; 59856893Sfenner 59956893Sfenner case 20: 60056893Sfenner (void)printf(" (Genid: 0x%08x)", EXTRACT_32BITS(&bp[4])); 60156893Sfenner break; 60256893Sfenner 60356893Sfenner case 21: 60456893Sfenner (void)printf(" (State Refresh Capable"); 60556893Sfenner if (EXTRACT_32BITS(&bp[4]) != 1) { 60656893Sfenner (void)printf(" ?0x%x?", EXTRACT_32BITS(&bp[4])); 60756893Sfenner } 60856893Sfenner (void)printf(")"); 60956893Sfenner break; 61056893Sfenner 61156893Sfenner default: 61256893Sfenner if (vflag) 61356893Sfenner (void)printf(" [Hello option %d]", otype); 61456893Sfenner } 61556893Sfenner bp += 4 + olen; 61656893Sfenner } 61756893Sfenner break; 61856893Sfenner } 61956893Sfenner 62056893Sfenner case 1: 62156893Sfenner { 62256893Sfenner struct ip *ip; 62356893Sfenner 62456893Sfenner (void)printf(" Register"); 62556893Sfenner if (vflag && bp + 8 <= ep) { 62656893Sfenner (void)printf(" %s%s", bp[4] & 0x80 ? "B" : "", 62756893Sfenner bp[4] & 0x40 ? "N" : ""); 62856893Sfenner } 62956893Sfenner bp += 8; len -= 8; 63056893Sfenner 63156893Sfenner /* encapsulated multicast packet */ 63256893Sfenner if (bp >= ep) 63356893Sfenner break; 63456893Sfenner ip = (struct ip *)bp; 63556893Sfenner switch(ip->ip_v) { 63656893Sfenner case 4: /* IPv4 */ 63756893Sfenner printf(" "); 63856893Sfenner ip_print(bp, len); 63956893Sfenner break; 64056893Sfenner#ifdef INET6 64156893Sfenner case 6: /* IPv6 */ 64256893Sfenner printf(" "); 64356893Sfenner ip6_print(bp, len); 64456893Sfenner break; 64556893Sfenner#endif 64656893Sfenner default: 64756893Sfenner (void)printf(" IP ver %d", ip->ip_v); 64856893Sfenner break; 64956893Sfenner } 65056893Sfenner break; 65156893Sfenner } 65256893Sfenner 65356893Sfenner case 2: 65456893Sfenner (void)printf(" Register-Stop"); 65556893Sfenner bp += 4; len -= 4; 65656893Sfenner if (bp >= ep) 65756893Sfenner break; 65856893Sfenner (void)printf(" group="); 65956893Sfenner if ((advance = pimv2_addr_print(bp, pimv2_group, 0)) < 0) { 66056893Sfenner (void)printf("..."); 66156893Sfenner break; 66256893Sfenner } 66356893Sfenner bp += advance; len -= advance; 66456893Sfenner if (bp >= ep) 66556893Sfenner break; 66656893Sfenner (void)printf(" source="); 66756893Sfenner if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) { 66856893Sfenner (void)printf("..."); 66956893Sfenner break; 67056893Sfenner } 67156893Sfenner bp += advance; len -= advance; 67256893Sfenner break; 67356893Sfenner 67456893Sfenner case 3: 67556893Sfenner case 6: 67656893Sfenner case 7: 67756893Sfenner { 67856893Sfenner u_int8_t ngroup; 67956893Sfenner u_int16_t holdtime; 68056893Sfenner u_int16_t njoin; 68156893Sfenner u_int16_t nprune; 68256893Sfenner int i, j; 68356893Sfenner 68456893Sfenner switch (PIM_TYPE(pim->pim_typever)) { 68556893Sfenner case 3: 68656893Sfenner (void)printf(" Join/Prune"); 68756893Sfenner break; 68856893Sfenner case 6: 68956893Sfenner (void)printf(" Graft"); 69056893Sfenner break; 69156893Sfenner case 7: 69256893Sfenner (void)printf(" Graft-ACK"); 69356893Sfenner break; 69456893Sfenner } 69556893Sfenner bp += 4; len -= 4; 69656893Sfenner if (PIM_TYPE(pim->pim_typever) != 7) { /*not for Graft-ACK*/ 69756893Sfenner if (bp >= ep) 69856893Sfenner break; 69956893Sfenner (void)printf(" upstream-neighbor="); 70056893Sfenner if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) { 70156893Sfenner (void)printf("..."); 70256893Sfenner break; 70356893Sfenner } 70456893Sfenner bp += advance; len -= advance; 70556893Sfenner } 70656893Sfenner if (bp + 4 > ep) 70756893Sfenner break; 70856893Sfenner ngroup = bp[1]; 70956893Sfenner holdtime = EXTRACT_16BITS(&bp[2]); 71056893Sfenner (void)printf(" groups=%u", ngroup); 71156893Sfenner if (PIM_TYPE(pim->pim_typever) != 7) { /*not for Graft-ACK*/ 71256893Sfenner (void)printf(" holdtime="); 71356893Sfenner if (holdtime == 0xffff) 71456893Sfenner (void)printf("infty"); 71556893Sfenner else 71656893Sfenner relts_print(holdtime); 71756893Sfenner } 71856893Sfenner bp += 4; len -= 4; 71956893Sfenner for (i = 0; i < ngroup; i++) { 72056893Sfenner if (bp >= ep) 72156893Sfenner goto jp_done; 72256893Sfenner (void)printf(" (group%d: ", i); 72356893Sfenner if ((advance = pimv2_addr_print(bp, pimv2_group, 0)) < 0) { 72456893Sfenner (void)printf("...)"); 72556893Sfenner goto jp_done; 72656893Sfenner } 72756893Sfenner bp += advance; len -= advance; 72856893Sfenner if (bp + 4 > ep) { 72956893Sfenner (void)printf("...)"); 73056893Sfenner goto jp_done; 73156893Sfenner } 73256893Sfenner njoin = EXTRACT_16BITS(&bp[0]); 73356893Sfenner nprune = EXTRACT_16BITS(&bp[2]); 73456893Sfenner (void)printf(" join=%u", njoin); 73556893Sfenner bp += 4; len -= 4; 73656893Sfenner for (j = 0; j < njoin; j++) { 73756893Sfenner (void)printf(" "); 73856893Sfenner if ((advance = pimv2_addr_print(bp, pimv2_source, 0)) < 0) { 73956893Sfenner (void)printf("...)"); 74056893Sfenner goto jp_done; 74156893Sfenner } 74256893Sfenner bp += advance; len -= advance; 74356893Sfenner } 74456893Sfenner (void)printf(" prune=%u", nprune); 74556893Sfenner for (j = 0; j < nprune; j++) { 74656893Sfenner (void)printf(" "); 74756893Sfenner if ((advance = pimv2_addr_print(bp, pimv2_source, 0)) < 0) { 74856893Sfenner (void)printf("...)"); 74956893Sfenner goto jp_done; 75056893Sfenner } 75156893Sfenner bp += advance; len -= advance; 75256893Sfenner } 75356893Sfenner (void)printf(")"); 75456893Sfenner } 75556893Sfenner jp_done: 75656893Sfenner break; 75756893Sfenner } 75856893Sfenner 75956893Sfenner case 4: 76056893Sfenner { 76156893Sfenner int i, j, frpcnt; 76256893Sfenner 76356893Sfenner (void)printf(" Bootstrap"); 76456893Sfenner bp += 4; 76556893Sfenner 76656893Sfenner /* Fragment Tag, Hash Mask len, and BSR-priority */ 76756893Sfenner if (bp + sizeof(u_int16_t) >= ep) break; 76856893Sfenner (void)printf(" tag=%x", EXTRACT_16BITS(bp)); 76956893Sfenner bp += sizeof(u_int16_t); 77056893Sfenner if (bp >= ep) break; 77156893Sfenner (void)printf(" hashmlen=%d", bp[0]); 77256893Sfenner if (bp + 1 >= ep) break; 77356893Sfenner (void)printf(" BSRprio=%d", bp[1]); 77456893Sfenner bp += 2; 77556893Sfenner 77656893Sfenner /* Encoded-Unicast-BSR-Address */ 77756893Sfenner if (bp >= ep) break; 77856893Sfenner (void)printf(" BSR="); 77956893Sfenner if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) { 78056893Sfenner (void)printf("..."); 78156893Sfenner break; 78256893Sfenner } 78356893Sfenner bp += advance; 78456893Sfenner 78556893Sfenner for (i = 0; bp < ep; i++) { 78656893Sfenner /* Encoded-Group Address */ 78756893Sfenner (void)printf(" (group%d: ", i); 78856893Sfenner if ((advance = pimv2_addr_print(bp, pimv2_group, 0)) 78956893Sfenner < 0) { 79056893Sfenner (void)printf("...)"); 79156893Sfenner goto bs_done; 79256893Sfenner } 79356893Sfenner bp += advance; 79456893Sfenner 79556893Sfenner /* RP-Count, Frag RP-Cnt, and rsvd */ 79656893Sfenner if (bp >= ep) { 79756893Sfenner (void)printf("...)"); 79856893Sfenner goto bs_done; 79956893Sfenner } 80056893Sfenner (void)printf(" RPcnt=%d", frpcnt = bp[0]); 80156893Sfenner if (bp + 1 >= ep) { 80256893Sfenner (void)printf("...)"); 80356893Sfenner goto bs_done; 80456893Sfenner } 80556893Sfenner (void)printf(" FRPcnt=%d", bp[1]); 80656893Sfenner bp += 4; 80756893Sfenner 80856893Sfenner for (j = 0; j < frpcnt && bp < ep; j++) { 80956893Sfenner /* each RP info */ 81056893Sfenner (void)printf(" RP%d=", j); 81156893Sfenner if ((advance = pimv2_addr_print(bp, 81256893Sfenner pimv2_unicast, 81356893Sfenner 0)) < 0) { 81456893Sfenner (void)printf("...)"); 81556893Sfenner goto bs_done; 81656893Sfenner } 81756893Sfenner bp += advance; 81856893Sfenner 81956893Sfenner if (bp + 1 >= ep) { 82056893Sfenner (void)printf("...)"); 82156893Sfenner goto bs_done; 82256893Sfenner } 82356893Sfenner (void)printf(",holdtime="); 82456893Sfenner relts_print(EXTRACT_16BITS(bp)); 82556893Sfenner if (bp + 2 >= ep) { 82656893Sfenner (void)printf("...)"); 82756893Sfenner goto bs_done; 82856893Sfenner } 82956893Sfenner (void)printf(",prio=%d", bp[2]); 83056893Sfenner bp += 4; 83156893Sfenner } 83256893Sfenner (void)printf(")"); 83356893Sfenner } 83456893Sfenner bs_done: 83556893Sfenner break; 83656893Sfenner } 83756893Sfenner case 5: 83856893Sfenner (void)printf(" Assert"); 83956893Sfenner bp += 4; len -= 4; 84056893Sfenner if (bp >= ep) 84156893Sfenner break; 84256893Sfenner (void)printf(" group="); 84356893Sfenner if ((advance = pimv2_addr_print(bp, pimv2_group, 0)) < 0) { 84456893Sfenner (void)printf("..."); 84556893Sfenner break; 84656893Sfenner } 84756893Sfenner bp += advance; len -= advance; 84856893Sfenner if (bp >= ep) 84956893Sfenner break; 85056893Sfenner (void)printf(" src="); 85156893Sfenner if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) { 85256893Sfenner (void)printf("..."); 85356893Sfenner break; 85456893Sfenner } 85556893Sfenner bp += advance; len -= advance; 85656893Sfenner if (bp + 8 > ep) 85756893Sfenner break; 85856893Sfenner if (bp[0] & 0x80) 85956893Sfenner (void)printf(" RPT"); 86056893Sfenner (void)printf(" pref=%u", EXTRACT_32BITS(&bp[0]) & 0x7fffffff); 86156893Sfenner (void)printf(" metric=%u", EXTRACT_32BITS(&bp[4])); 86256893Sfenner break; 86356893Sfenner 86456893Sfenner case 8: 86556893Sfenner { 86656893Sfenner int i, pfxcnt; 86756893Sfenner 86856893Sfenner (void)printf(" Candidate-RP-Advertisement"); 86956893Sfenner bp += 4; 87056893Sfenner 87156893Sfenner /* Prefix-Cnt, Priority, and Holdtime */ 87256893Sfenner if (bp >= ep) break; 87356893Sfenner (void)printf(" prefix-cnt=%d", bp[0]); 87456893Sfenner pfxcnt = bp[0]; 87556893Sfenner if (bp + 1 >= ep) break; 87656893Sfenner (void)printf(" prio=%d", bp[1]); 87756893Sfenner if (bp + 3 >= ep) break; 87856893Sfenner (void)printf(" holdtime="); 87956893Sfenner relts_print(EXTRACT_16BITS(&bp[2])); 88056893Sfenner bp += 4; 88156893Sfenner 88256893Sfenner /* Encoded-Unicast-RP-Address */ 88356893Sfenner if (bp >= ep) break; 88456893Sfenner (void)printf(" RP="); 88556893Sfenner if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) { 88656893Sfenner (void)printf("..."); 88756893Sfenner break; 88856893Sfenner } 88956893Sfenner bp += advance; 89056893Sfenner 89156893Sfenner /* Encoded-Group Addresses */ 89256893Sfenner for (i = 0; i < pfxcnt && bp < ep; i++) { 89356893Sfenner (void)printf(" Group%d=", i); 89456893Sfenner if ((advance = pimv2_addr_print(bp, pimv2_group, 0)) 89556893Sfenner < 0) { 89656893Sfenner (void)printf("..."); 89756893Sfenner break; 89856893Sfenner } 89956893Sfenner bp += advance; 90056893Sfenner } 90156893Sfenner break; 90256893Sfenner } 90356893Sfenner 90456893Sfenner case 9: 90556893Sfenner (void)printf(" Prune-Refresh"); 90656893Sfenner (void)printf(" src="); 90756893Sfenner if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) { 90856893Sfenner (void)printf("..."); 90956893Sfenner break; 91056893Sfenner } 91156893Sfenner bp += advance; 91256893Sfenner (void)printf(" grp="); 91356893Sfenner if ((advance = pimv2_addr_print(bp, pimv2_group, 0)) < 0) { 91456893Sfenner (void)printf("..."); 91556893Sfenner break; 91656893Sfenner } 91756893Sfenner bp += advance; 91856893Sfenner (void)printf(" forwarder="); 91956893Sfenner if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) { 92056893Sfenner (void)printf("..."); 92156893Sfenner break; 92256893Sfenner } 92356893Sfenner bp += advance; 92456893Sfenner TCHECK2(bp[0], 2); 92556893Sfenner (void)printf(" TUNR "); 92656893Sfenner relts_print(EXTRACT_16BITS(bp)); 92756893Sfenner break; 92856893Sfenner 92956893Sfenner 93056893Sfenner default: 93156893Sfenner (void)printf(" [type %d]", PIM_TYPE(pim->pim_typever)); 93256893Sfenner break; 93356893Sfenner } 93456893Sfenner 93556893Sfenner return; 93656893Sfenner 93756893Sfennertrunc: 93856893Sfenner (void)printf("[|pim]"); 93956893Sfenner} 940