print-cdp.c revision 98524
1289261Sbapt/*
2289261Sbapt * Copyright (c) 1992, 1993, 1994, 1995, 1996, 1997
3289261Sbapt *	The Regents of the University of California.  All rights reserved.
4289261Sbapt *
5289261Sbapt * Redistribution and use in source and binary forms, with or without
6289261Sbapt * modification, are permitted provided that: (1) source code distributions
7289261Sbapt * retain the above copyright notice and this paragraph in its entirety, (2)
8289261Sbapt * distributions including binary code include the above copyright notice and
9289261Sbapt * this paragraph in its entirety in the documentation or other materials
10289261Sbapt * provided with the distribution, and (3) all advertising materials mentioning
11289261Sbapt * features or use of this software display the following acknowledgement:
12289261Sbapt * ``This product includes software developed by the University of California,
13289261Sbapt * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14289261Sbapt * the University nor the names of its contributors may be used to endorse
15289261Sbapt * or promote products derived from this software without specific prior
16289261Sbapt * written permission.
17289261Sbapt * 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
28static 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
50static int cdp_print_addr(const u_char *, int);
51static int cdp_print_prefixes(const u_char *, int);
52
53void
54cdp_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
141trunc:
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
156static int
157cdp_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
239trunc:
240	return -1;
241}
242
243
244static int
245cdp_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
260trunc:
261	return -1;
262}
263