xref: /freebsd/contrib/tcpdump/print-cdp.c (revision b52b9d56d4e96089873a75f9e29062eec19fabba)
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