1 /* 2 * Copyright (c) 1992, 1993, 1994, 1995, 1996, 1997 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 * Code by Gert Doering, SpaceNet GmbH, gert@space.net 22 * 23 * Reference documentation: 24 * http://www.cisco.com/univercd/cc/td/doc/product/lan/trsrb/frames.htm 25 */ 26 27 #ifndef lint 28 static const char rcsid[] = 29 "@(#) $Header: /tcpdump/master/tcpdump/print-cdp.c,v 1.11 2001/09/17 21:57:56 fenner Exp $"; 30 #endif 31 32 #ifdef HAVE_CONFIG_H 33 #include "config.h" 34 #endif 35 36 #include <sys/param.h> 37 #include <sys/time.h> 38 39 #include <netinet/in.h> 40 41 #include <ctype.h> 42 #include <netdb.h> 43 #include <stdio.h> 44 #include <string.h> 45 46 #include "interface.h" 47 #include "addrtoname.h" 48 #include "extract.h" /* must come after interface.h */ 49 50 static int cdp_print_addr(const u_char *, int); 51 static int cdp_print_prefixes(const u_char *, int); 52 53 void 54 cdp_print(const u_char *p, u_int length, u_int caplen, 55 const u_char *esrc, const u_char *edst) 56 { 57 u_int i; 58 int type, len; 59 60 /* Cisco Discovery Protocol */ 61 62 if (caplen < 4) { 63 (void)printf("[|cdp]"); 64 return; 65 } 66 67 i = 0; /* CDP data starts at offset 0 */ 68 printf("CDP v%u, ttl=%us", p[i], p[i + 1]); 69 i += 4; /* skip version, TTL and chksum */ 70 71 while (i < length) { 72 if (i + 4 > caplen) 73 goto trunc; 74 type = (p[i] << 8) + p[i + 1]; 75 len = (p[i + 2] << 8) + p[i + 3]; 76 77 if (vflag > 1) 78 printf("\n\t"); 79 80 if (vflag) 81 printf(" %02x/%02x", type, len); 82 83 if (i + len > caplen) 84 goto trunc; 85 86 switch (type) { 87 case 0x00: 88 printf(" Goodbye"); 89 break; 90 case 0x01: 91 printf(" DevID '%.*s'", len - 4, p + i + 4); 92 break; 93 case 0x02: 94 printf(" Addr"); 95 if (cdp_print_addr(p + i + 4, len - 4) < 0) 96 goto trunc; 97 break; 98 case 0x03: 99 printf(" PortID '%.*s'", len - 4, p + i + 4); 100 break; 101 case 0x04: 102 printf(" CAP 0x%02x", (unsigned) p[i + 7]); 103 break; 104 case 0x05: 105 if (vflag > 1) 106 printf(" Version:\n%.*s", len - 4, p + i + 4); 107 else 108 printf(" Version: (suppressed)"); 109 break; 110 case 0x06: 111 printf(" Platform: '%.*s'", len - 4, p + i + 4); 112 break; 113 case 0x07: 114 if (cdp_print_prefixes(p + i + 4, len - 4) < 0) 115 goto trunc; 116 break; 117 case 0x09: /* guess - not documented */ 118 printf(" VTP Management Domain: '%.*s'", len - 4, 119 p + i + 4); 120 break; 121 case 0x0a: /* guess - not documented */ 122 printf(" Native VLAN ID: %d", 123 (p[i + 4] << 8) + p[i + 4 + 1] - 1); 124 break; 125 case 0x0b: /* guess - not documented */ 126 printf(" Duplex: %s", p[i + 4] ? "full": "half"); 127 break; 128 default: 129 printf(" unknown field type %02x, len %d", type, len); 130 break; 131 } 132 133 /* avoid infinite loop */ 134 if (len == 0) 135 break; 136 i += len; 137 } 138 139 return; 140 141 trunc: 142 printf("[|cdp]"); 143 } 144 145 /* 146 * Protocol type values. 147 * 148 * PT_NLPID means that the protocol type field contains an OSI NLPID. 149 * 150 * PT_IEEE_802_2 means that the protocol type field contains an IEEE 802.2 151 * LLC header that specifies that the payload is for that protocol. 152 */ 153 #define PT_NLPID 1 /* OSI NLPID */ 154 #define PT_IEEE_802_2 2 /* IEEE 802.2 LLC header */ 155 156 static int 157 cdp_print_addr(const u_char * p, int l) 158 { 159 int pt, pl, al, num; 160 const u_char *endp = p + l; 161 #ifdef INET6 162 static u_char prot_ipv6[] = { 163 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00, 0x86, 0xdd 164 }; 165 #endif 166 167 num = EXTRACT_32BITS(p); 168 p += 4; 169 170 printf(" (%d): ", num); 171 172 while (p < endp && num >= 0) { 173 if (p + 2 > endp) 174 goto trunc; 175 pt = p[0]; /* type of "protocol" field */ 176 pl = p[1]; /* length of "protocol" field */ 177 p += 2; 178 179 if (p + pl + 2 > endp) 180 goto trunc; 181 al = EXTRACT_16BITS(&p[pl]); /* address length */ 182 183 if (pt == PT_NLPID && pl == 1 && *p == 0xcc && al == 4) { 184 /* 185 * IPv4: protocol type = NLPID, protocol length = 1 186 * (1-byte NLPID), protocol = 0xcc (NLPID for IPv4), 187 * address length = 4 188 */ 189 p += 3; 190 191 if (p + 4 > endp) 192 goto trunc; 193 printf("IPv4 %u.%u.%u.%u", p[0], p[1], p[2], p[3]); 194 p += 4; 195 } 196 #ifdef INET6 197 else if (pt == PT_IEEE_802_2 && pl == 8 && 198 memcmp(p, prot_ipv6, 8) == 0 && al == 16) { 199 /* 200 * IPv6: protocol type = IEEE 802.2 header, 201 * protocol length = 8 (size of LLC+SNAP header), 202 * protocol = LLC+SNAP header with the IPv6 203 * Ethertype, address length = 16 204 */ 205 p += 10; 206 if (p + al > endp) 207 goto trunc; 208 209 printf("IPv6 %s", ip6addr_string(p)); 210 p += al; 211 } 212 #endif 213 else { 214 /* 215 * Generic case: just print raw data 216 */ 217 if (p + pl > endp) 218 goto trunc; 219 printf("pt=0x%02x, pl=%d, pb=", *(p - 2), pl); 220 while (pl-- > 0) 221 printf(" %02x", *p++); 222 if (p + 2 > endp) 223 goto trunc; 224 al = (*p << 8) + *(p + 1); 225 printf(", al=%d, a=", al); 226 p += 2; 227 if (p + al > endp) 228 goto trunc; 229 while (al-- > 0) 230 printf(" %02x", *p++); 231 } 232 num--; 233 if (num) 234 printf(" "); 235 } 236 237 return 0; 238 239 trunc: 240 return -1; 241 } 242 243 244 static int 245 cdp_print_prefixes(const u_char * p, int l) 246 { 247 if (l % 5) 248 goto trunc; 249 250 printf(" IPv4 Prefixes (%d):", l / 5); 251 252 while (l > 0) { 253 printf(" %u.%u.%u.%u/%u", p[0], p[1], p[2], p[3], p[4]); 254 l -= 5; 255 p += 5; 256 } 257 258 return 0; 259 260 trunc: 261 return -1; 262 } 263