175115Sfenner/* 275115Sfenner * Copyright (c) 1992, 1993, 1994, 1995, 1996, 1997 375115Sfenner * The Regents of the University of California. All rights reserved. 475115Sfenner * 575115Sfenner * Redistribution and use in source and binary forms, with or without 675115Sfenner * modification, are permitted provided that: (1) source code distributions 775115Sfenner * retain the above copyright notice and this paragraph in its entirety, (2) 875115Sfenner * distributions including binary code include the above copyright notice and 975115Sfenner * this paragraph in its entirety in the documentation or other materials 1075115Sfenner * provided with the distribution, and (3) all advertising materials mentioning 1175115Sfenner * features or use of this software display the following acknowledgement: 1275115Sfenner * ``This product includes software developed by the University of California, 1375115Sfenner * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 1475115Sfenner * the University nor the names of its contributors may be used to endorse 1575115Sfenner * or promote products derived from this software without specific prior 1675115Sfenner * written permission. 1775115Sfenner * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 1875115Sfenner * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 1975115Sfenner * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 2075115Sfenner * 2175115Sfenner * Code by Gert Doering, SpaceNet GmbH, gert@space.net 2275115Sfenner * 2375115Sfenner * Reference documentation: 2475115Sfenner * http://www.cisco.com/univercd/cc/td/doc/product/lan/trsrb/frames.htm 2575115Sfenner */ 2675115Sfenner 2775115Sfenner#ifndef lint 28127668Sbmsstatic const char rcsid[] _U_ = 29190207Srpaulo "@(#) $Header: /tcpdump/master/tcpdump/print-cdp.c,v 1.25 2004-10-07 14:53:11 hannes Exp $"; 3075115Sfenner#endif 3175115Sfenner 3275115Sfenner#ifdef HAVE_CONFIG_H 3375115Sfenner#include "config.h" 3475115Sfenner#endif 3575115Sfenner 36127668Sbms#include <tcpdump-stdinc.h> 3775115Sfenner 3875115Sfenner#include <stdio.h> 3975115Sfenner#include <string.h> 4075115Sfenner 4175115Sfenner#include "interface.h" 4275115Sfenner#include "addrtoname.h" 4375115Sfenner#include "extract.h" /* must come after interface.h */ 44146773Ssam#include "nlpid.h" 4575115Sfenner 46127668Sbms#define CDP_HEADER_LEN 4 47127668Sbms 48127668Sbmsstatic struct tok cdp_tlv_values[] = { 49127668Sbms { 0x01, "Device-ID"}, 50127668Sbms { 0x02, "Address"}, 51127668Sbms { 0x03, "Port-ID"}, 52127668Sbms { 0x04, "Capability"}, 53127668Sbms { 0x05, "Version String"}, 54127668Sbms { 0x06, "Platform"}, 55127668Sbms { 0x07, "Prefixes"}, 56127668Sbms { 0x08, "Protocol-Hello option"}, 57127668Sbms { 0x09, "VTP Management Domain"}, 58127668Sbms { 0x0a, "Native VLAN ID"}, 59127668Sbms { 0x0b, "Duplex"}, 60127668Sbms { 0x0e, "ATA-186 VoIP VLAN request"}, 61127668Sbms { 0x0f, "ATA-186 VoIP VLAN assignment"}, 62127668Sbms { 0x10, "power consumption"}, 63127668Sbms { 0x11, "MTU"}, 64127668Sbms { 0x12, "AVVID trust bitmap"}, 65127668Sbms { 0x13, "AVVID untrusted ports CoS"}, 66127668Sbms { 0x14, "System Name"}, 67127668Sbms { 0x15, "System Object ID (not decoded)"}, 68127668Sbms { 0x16, "Management Addresses"}, 69127668Sbms { 0x17, "Physical Location"}, 70127668Sbms { 0, NULL} 71127668Sbms}; 72127668Sbms 73127668Sbmsstatic struct tok cdp_capability_values[] = { 74127668Sbms { 0x01, "Router" }, 75127668Sbms { 0x02, "Transparent Bridge" }, 76127668Sbms { 0x04, "Source Route Bridge" }, 77127668Sbms { 0x08, "L2 Switch" }, 78127668Sbms { 0x10, "L3 capable" }, 79127668Sbms { 0x20, "IGMP snooping" }, 80127668Sbms { 0x40, "L1 capable" }, 81127668Sbms { 0, NULL } 82127668Sbms}; 83127668Sbms 8498524Sfennerstatic int cdp_print_addr(const u_char *, int); 8598524Sfennerstatic int cdp_print_prefixes(const u_char *, int); 86127668Sbmsstatic unsigned long cdp_get_number(const u_char *, int); 8775115Sfenner 8875115Sfennervoid 89127668Sbmscdp_print(const u_char *pptr, u_int length, u_int caplen) 9075115Sfenner{ 91127668Sbms int type, len, i, j; 92127668Sbms const u_char *tptr; 9375115Sfenner 94127668Sbms if (caplen < CDP_HEADER_LEN) { 9575115Sfenner (void)printf("[|cdp]"); 9675115Sfenner return; 9775115Sfenner } 9875115Sfenner 99127668Sbms tptr = pptr; /* temporary pointer */ 10075115Sfenner 101127668Sbms if (!TTEST2(*tptr, CDP_HEADER_LEN)) 102127668Sbms goto trunc; 103127668Sbms printf("CDPv%u, ttl: %us", *tptr, *(tptr+1)); 104127668Sbms if (vflag) 105127668Sbms printf(", checksum: %u (unverified), length %u", EXTRACT_16BITS(tptr), length); 106127668Sbms tptr += CDP_HEADER_LEN; 10775115Sfenner 108127668Sbms while (tptr < (pptr+length)) { 10975115Sfenner 110127668Sbms if (!TTEST2(*tptr, 4)) /* read out Type and Length */ 111127668Sbms goto trunc; 112127668Sbms type = EXTRACT_16BITS(tptr); 113127668Sbms len = EXTRACT_16BITS(tptr+2); /* object length includes the 4 bytes header length */ 114127668Sbms tptr += 4; 115127668Sbms len -= 4; 11675115Sfenner 117127668Sbms if (!TTEST2(*tptr, len)) 11898524Sfenner goto trunc; 11975115Sfenner 120127668Sbms if (vflag || type == 1) { /* in non-verbose mode just print Device-ID */ 121127668Sbms 122127668Sbms if (vflag) 123127668Sbms printf("\n\t%s (0x%02x), length: %u byte%s: ", 124127668Sbms tok2str(cdp_tlv_values,"unknown field type", type), 125127668Sbms type, 126127668Sbms len, 127235530Sdelphij PLURAL_SUFFIX(len)); /* plural */ 128127668Sbms 129127668Sbms switch (type) { 130127668Sbms 131127668Sbms case 0x01: /* Device-ID */ 132127668Sbms if (!vflag) 133214478Srpaulo printf(", Device-ID "); 134214478Srpaulo printf("'"); 135214478Srpaulo fn_printn(tptr, len, NULL); 136214478Srpaulo printf("'"); 13798524Sfenner break; 138127668Sbms case 0x02: /* Address */ 139127668Sbms if (cdp_print_addr(tptr, len) < 0) 140127668Sbms goto trunc; 14198524Sfenner break; 142127668Sbms case 0x03: /* Port-ID */ 143214478Srpaulo printf("'"); 144214478Srpaulo fn_printn(tptr, len, NULL); 145214478Srpaulo printf("'"); 14698524Sfenner break; 147127668Sbms case 0x04: /* Capabilities */ 148127668Sbms printf("(0x%08x): %s", 149127668Sbms EXTRACT_32BITS(tptr), 150127668Sbms bittok2str(cdp_capability_values, "none",EXTRACT_32BITS(tptr))); 15198524Sfenner break; 152127668Sbms case 0x05: /* Version */ 153127668Sbms printf("\n\t "); 154127668Sbms for (i=0;i<len;i++) { 155127668Sbms j = *(tptr+i); 156127668Sbms putchar(j); 157127668Sbms if (j == 0x0a) /* lets rework the version string to get a nice identation */ 158127668Sbms printf("\t "); 159127668Sbms } 16098524Sfenner break; 161127668Sbms case 0x06: /* Platform */ 162214478Srpaulo printf("'"); 163214478Srpaulo fn_printn(tptr, len, NULL); 164214478Srpaulo printf("'"); 16598524Sfenner break; 166127668Sbms case 0x07: /* Prefixes */ 167127668Sbms if (cdp_print_prefixes(tptr, len) < 0) 168127668Sbms goto trunc; 16998524Sfenner break; 170127668Sbms case 0x08: /* Protocol Hello Option - not documented */ 17198524Sfenner break; 172127668Sbms case 0x09: /* VTP Mgmt Domain - not documented */ 173214478Srpaulo printf("'"); 174214478Srpaulo fn_printn(tptr, len, NULL); 175214478Srpaulo printf("'"); 17698524Sfenner break; 177127668Sbms case 0x0a: /* Native VLAN ID - not documented */ 178127668Sbms printf("%d",EXTRACT_16BITS(tptr)); 17998524Sfenner break; 180127668Sbms case 0x0b: /* Duplex - not documented */ 181127668Sbms printf("%s", *(tptr) ? "full": "half"); 18298524Sfenner break; 183127668Sbms 184127668Sbms /* http://www.cisco.com/univercd/cc/td/doc/product/voice/ata/atarn/186rn21m.htm 185127668Sbms * plus more details from other sources 186127668Sbms */ 187127668Sbms case 0x0e: /* ATA-186 VoIP VLAN request - incomplete doc. */ 188127668Sbms printf("app %d, vlan %d", 189127668Sbms *(tptr), EXTRACT_16BITS(tptr+1)); 19098524Sfenner break; 191127668Sbms case 0x10: /* ATA-186 VoIP VLAN assignment - incomplete doc. */ 192127668Sbms printf("%1.2fW", 193127668Sbms cdp_get_number(tptr, len)/1000.0 ); 194127668Sbms break; 195127668Sbms case 0x11: /* MTU - not documented */ 196127668Sbms printf("%u bytes", EXTRACT_32BITS(tptr)); 197127668Sbms break; 198127668Sbms case 0x12: /* AVVID trust bitmap - not documented */ 199127668Sbms printf("0x%02x", *(tptr) ); 200127668Sbms break; 201127668Sbms case 0x13: /* AVVID untrusted port CoS - not documented */ 202127668Sbms printf("0x%02x", *(tptr)); 203127668Sbms break; 204127668Sbms case 0x14: /* System Name - not documented */ 205214478Srpaulo printf("'"); 206214478Srpaulo fn_printn(tptr, len, NULL); 207214478Srpaulo printf("'"); 208127668Sbms break; 209127668Sbms case 0x16: /* System Object ID - not documented */ 210127668Sbms if (cdp_print_addr(tptr, len) < 0) 211127668Sbms goto trunc; 212127668Sbms break; 213127668Sbms case 0x17: /* Physical Location - not documented */ 214214478Srpaulo printf("0x%02x", *(tptr)); 215214478Srpaulo if (len > 1) { 216214478Srpaulo printf("/"); 217214478Srpaulo fn_printn(tptr + 1, len - 1, NULL); 218214478Srpaulo } 219127668Sbms break; 220127668Sbms default: 221127668Sbms print_unknown_data(tptr,"\n\t ",len); 222127668Sbms break; 223127668Sbms } 224127668Sbms } 22598524Sfenner /* avoid infinite loop */ 22698524Sfenner if (len == 0) 22798524Sfenner break; 228127668Sbms tptr = tptr+len; 22975115Sfenner } 230127668Sbms if (vflag < 1) 231127668Sbms printf(", length %u",caplen); 23298524Sfenner 23398524Sfenner return; 23498524Sfennertrunc: 23598524Sfenner printf("[|cdp]"); 23675115Sfenner} 23775115Sfenner 23898524Sfenner/* 23998524Sfenner * Protocol type values. 24098524Sfenner * 24198524Sfenner * PT_NLPID means that the protocol type field contains an OSI NLPID. 24298524Sfenner * 24398524Sfenner * PT_IEEE_802_2 means that the protocol type field contains an IEEE 802.2 24498524Sfenner * LLC header that specifies that the payload is for that protocol. 24598524Sfenner */ 24698524Sfenner#define PT_NLPID 1 /* OSI NLPID */ 24798524Sfenner#define PT_IEEE_802_2 2 /* IEEE 802.2 LLC header */ 24898524Sfenner 24998524Sfennerstatic int 25098524Sfennercdp_print_addr(const u_char * p, int l) 25175115Sfenner{ 25298524Sfenner int pt, pl, al, num; 25398524Sfenner const u_char *endp = p + l; 25498524Sfenner#ifdef INET6 25598524Sfenner static u_char prot_ipv6[] = { 25698524Sfenner 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00, 0x86, 0xdd 25798524Sfenner }; 25898524Sfenner#endif 25975115Sfenner 260127668Sbms TCHECK2(*p, 2); 26198524Sfenner num = EXTRACT_32BITS(p); 26298524Sfenner p += 4; 26375115Sfenner 26498524Sfenner while (p < endp && num >= 0) { 265127668Sbms TCHECK2(*p, 2); 26698524Sfenner if (p + 2 > endp) 26798524Sfenner goto trunc; 26898524Sfenner pt = p[0]; /* type of "protocol" field */ 26998524Sfenner pl = p[1]; /* length of "protocol" field */ 27098524Sfenner p += 2; 27175115Sfenner 272127668Sbms TCHECK2(p[pl], 2); 27398524Sfenner if (p + pl + 2 > endp) 27498524Sfenner goto trunc; 27598524Sfenner al = EXTRACT_16BITS(&p[pl]); /* address length */ 27675115Sfenner 277146773Ssam if (pt == PT_NLPID && pl == 1 && *p == NLPID_IP && al == 4) { 27898524Sfenner /* 27998524Sfenner * IPv4: protocol type = NLPID, protocol length = 1 28098524Sfenner * (1-byte NLPID), protocol = 0xcc (NLPID for IPv4), 28198524Sfenner * address length = 4 28298524Sfenner */ 28398524Sfenner p += 3; 28498524Sfenner 285127668Sbms TCHECK2(*p, 4); 28698524Sfenner if (p + 4 > endp) 28798524Sfenner goto trunc; 288127668Sbms printf("IPv4 (%u) %s", 289127668Sbms num, 290127668Sbms ipaddr_string(p)); 29198524Sfenner p += 4; 29275115Sfenner } 29398524Sfenner#ifdef INET6 29498524Sfenner else if (pt == PT_IEEE_802_2 && pl == 8 && 29598524Sfenner memcmp(p, prot_ipv6, 8) == 0 && al == 16) { 29698524Sfenner /* 29798524Sfenner * IPv6: protocol type = IEEE 802.2 header, 29898524Sfenner * protocol length = 8 (size of LLC+SNAP header), 29998524Sfenner * protocol = LLC+SNAP header with the IPv6 30098524Sfenner * Ethertype, address length = 16 30198524Sfenner */ 302127668Sbms p += 10; 303127668Sbms TCHECK2(*p, al); 30498524Sfenner if (p + al > endp) 30598524Sfenner goto trunc; 30698524Sfenner 307127668Sbms printf("IPv6 (%u) %s", 308127668Sbms num, 309127668Sbms ip6addr_string(p)); 31098524Sfenner p += al; 31198524Sfenner } 31298524Sfenner#endif 31398524Sfenner else { 31498524Sfenner /* 31598524Sfenner * Generic case: just print raw data 31698524Sfenner */ 317127668Sbms TCHECK2(*p, pl); 31898524Sfenner if (p + pl > endp) 31998524Sfenner goto trunc; 32098524Sfenner printf("pt=0x%02x, pl=%d, pb=", *(p - 2), pl); 32198524Sfenner while (pl-- > 0) 32298524Sfenner printf(" %02x", *p++); 323127668Sbms TCHECK2(*p, 2); 32498524Sfenner if (p + 2 > endp) 32598524Sfenner goto trunc; 32698524Sfenner al = (*p << 8) + *(p + 1); 32798524Sfenner printf(", al=%d, a=", al); 32898524Sfenner p += 2; 329127668Sbms TCHECK2(*p, al); 33098524Sfenner if (p + al > endp) 33198524Sfenner goto trunc; 33298524Sfenner while (al-- > 0) 33398524Sfenner printf(" %02x", *p++); 33498524Sfenner } 33575115Sfenner num--; 33698524Sfenner if (num) 33798524Sfenner printf(" "); 33875115Sfenner } 33998524Sfenner 34098524Sfenner return 0; 34198524Sfenner 34298524Sfennertrunc: 34398524Sfenner return -1; 34475115Sfenner} 34575115Sfenner 34675115Sfenner 34798524Sfennerstatic int 34898524Sfennercdp_print_prefixes(const u_char * p, int l) 34975115Sfenner{ 35098524Sfenner if (l % 5) 35198524Sfenner goto trunc; 35275115Sfenner 35398524Sfenner printf(" IPv4 Prefixes (%d):", l / 5); 35498524Sfenner 35598524Sfenner while (l > 0) { 35698524Sfenner printf(" %u.%u.%u.%u/%u", p[0], p[1], p[2], p[3], p[4]); 35798524Sfenner l -= 5; 35898524Sfenner p += 5; 35998524Sfenner } 36098524Sfenner 36198524Sfenner return 0; 36298524Sfenner 36398524Sfennertrunc: 36498524Sfenner return -1; 36575115Sfenner} 366127668Sbms 367127668Sbms/* read in a <n>-byte number, MSB first 368127668Sbms * (of course this can handle max sizeof(long)) 369127668Sbms */ 370127668Sbmsstatic unsigned long cdp_get_number(const u_char * p, int l) 371127668Sbms{ 372127668Sbms unsigned long res=0; 373127668Sbms while( l>0 ) 374127668Sbms { 375127668Sbms res = (res<<8) + *p; 376127668Sbms p++; l--; 377127668Sbms } 378127668Sbms return res; 379127668Sbms} 380