xref: /openbsd-src/usr.sbin/tcpdump/print-lldp.c (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
1 /*	$OpenBSD: print-lldp.c,v 1.8 2015/01/16 06:40:21 deraadt Exp $	*/
2 
3 /*
4  * Copyright (c) 2006 Reyk Floeter <reyk@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/time.h>
20 #include <sys/socket.h>
21 
22 #include <net/if.h>
23 
24 #include <netinet/in.h>
25 #include <netinet/if_ether.h>
26 #include <arpa/inet.h>
27 
28 #include <ctype.h>
29 #include <stdio.h>
30 #include <string.h>
31 
32 #include "addrtoname.h"
33 #include "extract.h"
34 #include "interface.h"
35 #include "afnum.h"
36 
37 enum {
38 	LLDP_TLV_END			= 0,
39 	LLDP_TLV_CHASSIS_ID		= 1,
40 	LLDP_TLV_PORT_ID		= 2,
41 	LLDP_TLV_TTL			= 3,
42 	LLDP_TLV_PORT_DESCR		= 4,
43 	LLDP_TLV_SYSTEM_NAME		= 5,
44 	LLDP_TLV_SYSTEM_DESCR		= 6,
45 	LLDP_TLV_SYSTEM_CAP		= 7,
46 	LLDP_TLV_MANAGEMENT_ADDR	= 8,
47 	LLDP_TLV_ORG			= 127
48 };
49 
50 enum {
51 	LLDP_CHASSISID_SUBTYPE_CHASSIS	= 1,
52 	LLDP_CHASSISID_SUBTYPE_IFALIAS	= 2,
53 	LLDP_CHASSISID_SUBTYPE_PORT	= 3,
54 	LLDP_CHASSISID_SUBTYPE_LLADDR	= 4,
55 	LLDP_CHASSISID_SUBTYPE_ADDR	= 5,
56 	LLDP_CHASSISID_SUBTYPE_IFNAME	= 6,
57 	LLDP_CHASSISID_SUBTYPE_LOCAL	= 7
58 };
59 
60 enum {
61 	LLDP_PORTID_SUBTYPE_IFALIAS	= 1,
62 	LLDP_PORTID_SUBTYPE_PORT	= 2,
63 	LLDP_PORTID_SUBTYPE_LLADDR	= 3,
64 	LLDP_PORTID_SUBTYPE_ADDR	= 4,
65 	LLDP_PORTID_SUBTYPE_IFNAME	= 5,
66 	LLDP_PORTID_SUBTYPE_AGENTCID	= 6,
67 	LLDP_PORTID_SUBTYPE_LOCAL	= 7
68 };
69 
70 #define LLDP_CAP_OTHER          0x01
71 #define LLDP_CAP_REPEATER       0x02
72 #define LLDP_CAP_BRIDGE         0x04
73 #define LLDP_CAP_WLAN           0x08
74 #define LLDP_CAP_ROUTER         0x10
75 #define LLDP_CAP_TELEPHONE      0x20
76 #define LLDP_CAP_DOCSIS         0x40
77 #define LLDP_CAP_STATION        0x80
78 #define LLDP_CAP_BITS								\
79 	"\20\01OTHER\02REPEATER\03BRIDGE\04WLAN\05ROUTER\06TELEPHONE"		\
80 	"\07DOCSIS\10STATION"
81 
82 enum {
83 	LLDP_MGMT_IFACE_UNKNOWN	= 1,
84 	LLDP_MGMT_IFACE_IFINDEX	= 2,
85 	LLDP_MGMT_IFACE_SYSPORT	= 3
86 };
87 
88 static const char *afnumber[] = AFNUM_NAME_STR;
89 
90 void		 lldp_print_str(u_int8_t *, int);
91 const char	*lldp_print_addr(int, const void *);
92 void		 lldp_print_id(int, u_int8_t *, int);
93 
94 void
95 lldp_print_str(u_int8_t *str, int len)
96 {
97 	int i;
98 	printf("\"");
99 	for (i = 0; i < len; i++)
100 		printf("%c", isprint(str[i]) ? str[i] : '.');
101 	printf("\"");
102 }
103 
104 const char *
105 lldp_print_addr(int af, const void *addr)
106 {
107 	static char buf[48];
108 	if (inet_ntop(af, addr, buf, sizeof(buf)) == NULL)
109 		return ("?");
110 	return (buf);
111 }
112 
113 void
114 lldp_print_id(int type, u_int8_t *ptr, int len)
115 {
116 	u_int8_t id;
117 	u_int8_t *data;
118 
119 	id = *(u_int8_t *)ptr;
120 	len -= sizeof(u_int8_t);
121 	data = ptr + sizeof(u_int8_t);
122 	if (len <= 0)
123 		return;
124 
125 	if (type == LLDP_TLV_CHASSIS_ID) {
126 		switch (id) {
127 		case LLDP_CHASSISID_SUBTYPE_CHASSIS:
128 			printf("chassis ");
129 			lldp_print_str(data, len);
130 			break;
131 		case LLDP_CHASSISID_SUBTYPE_IFALIAS:
132 			printf("ifalias");
133 			break;
134 		case LLDP_CHASSISID_SUBTYPE_PORT:
135 			printf("port");
136 			break;
137 		case LLDP_CHASSISID_SUBTYPE_LLADDR:
138 			printf("lladdr %s",
139 			    ether_ntoa((struct ether_addr *)data));
140 			break;
141 		case LLDP_CHASSISID_SUBTYPE_ADDR:
142 			printf("addr");
143 			break;
144 		case LLDP_CHASSISID_SUBTYPE_IFNAME:
145 			printf("ifname ");
146 			lldp_print_str(data, len);
147 			break;
148 		case LLDP_CHASSISID_SUBTYPE_LOCAL:
149 			printf("local ");
150 			lldp_print_str(data, len);
151 			break;
152 		default:
153 			printf("unknown 0x%02x", id);
154 			break;
155 		}
156 
157 	} else if (type == LLDP_TLV_PORT_ID) {
158 		switch (id) {
159 		case LLDP_PORTID_SUBTYPE_IFALIAS:
160 			printf("ifalias");
161 			break;
162 		case LLDP_PORTID_SUBTYPE_PORT:
163 			printf("port");
164 			break;
165 		case LLDP_PORTID_SUBTYPE_LLADDR:
166 			printf("lladdr %s",
167 			    ether_ntoa((struct ether_addr *)data));
168 			break;
169 		case LLDP_PORTID_SUBTYPE_ADDR:
170 			printf("addr");
171 			break;
172 		case LLDP_PORTID_SUBTYPE_IFNAME:
173 			printf("ifname ");
174 			lldp_print_str(data, len);
175 			break;
176 		case LLDP_PORTID_SUBTYPE_AGENTCID:
177 			printf("agentcid");
178 			break;
179 		case LLDP_PORTID_SUBTYPE_LOCAL:
180 			printf("local ");
181 			lldp_print_str(data, len);
182 			break;
183 		default:
184 			printf("unknown 0x%02x", id);
185 			break;
186 		}
187 	}
188 }
189 
190 void
191 lldp_print(const u_char *p, u_int len)
192 {
193 	u_int16_t tlv;
194 	u_int8_t *ptr = (u_int8_t *)p, v = 0;
195 	int n, type, vlen, alen;
196 
197 	printf("LLDP");
198 
199 #define _ptrinc(_v)	ptr += (_v); vlen -= (_v);
200 
201 	for (n = 0; n < len;) {
202 		TCHECK2(*ptr, sizeof(tlv));
203 
204 		tlv = EXTRACT_16BITS(ptr);
205 		type = (tlv & 0xfe00) >> 9;
206 		vlen = tlv & 0x1ff;
207 		n += vlen;
208 
209 		ptr += sizeof(tlv);
210 		TCHECK2(*ptr, vlen);
211 
212 		switch (type) {
213 		case LLDP_TLV_END:
214 			goto done;
215 			break;
216 
217 		case LLDP_TLV_CHASSIS_ID:
218 			printf(", ChassisId: ");
219 			lldp_print_id(type, ptr, vlen);
220 			break;
221 
222 		case LLDP_TLV_PORT_ID:
223 			printf(", PortId: ");
224 			lldp_print_id(type, ptr, vlen);
225 			break;
226 
227 		case LLDP_TLV_TTL:
228 			printf(", TTL: ");
229 			TCHECK2(*ptr, 2);
230 			printf("%ds", EXTRACT_16BITS(ptr));
231 			break;
232 
233 		case LLDP_TLV_PORT_DESCR:
234 			printf(", PortDescr: ");
235 			lldp_print_str(ptr, vlen);
236 			break;
237 
238 		case LLDP_TLV_SYSTEM_NAME:
239 			printf(", SysName: ");
240 			lldp_print_str(ptr, vlen);
241 			break;
242 
243 		case LLDP_TLV_SYSTEM_DESCR:
244 			printf(", SysDescr: ");
245 			lldp_print_str(ptr, vlen);
246 			break;
247 
248 		case LLDP_TLV_SYSTEM_CAP:
249 			printf(", CAP:");
250 			TCHECK2(*ptr, 4);
251 			printb(" available", EXTRACT_16BITS(ptr),
252 			    LLDP_CAP_BITS);
253 			_ptrinc(sizeof(u_int16_t));
254 			printb(" enabled", EXTRACT_16BITS(ptr),
255 			    LLDP_CAP_BITS);
256 			break;
257 
258 		case LLDP_TLV_MANAGEMENT_ADDR:
259 			printf(", MgmtAddr:");
260 			TCHECK2(*ptr, 2);
261 			alen = *ptr - sizeof(u_int8_t);
262 			_ptrinc(sizeof(u_int8_t));
263 			v = *ptr;
264 			_ptrinc(sizeof(u_int8_t));
265 			if (v < AFNUM_MAX)
266 				printf(" %s", afnumber[v]);
267 			else
268 				printf(" type %d", v);
269 			TCHECK2(*ptr, alen);
270 			switch (v) {
271 			case AFNUM_INET:
272 				if (alen != sizeof(struct in_addr))
273 					goto trunc;
274 				printf(" %s",
275 				    lldp_print_addr(AF_INET, ptr));
276 				break;
277 			case AFNUM_INET6:
278 				if (alen != sizeof(struct in6_addr))
279 					goto trunc;
280 				printf(" %s",
281 				    lldp_print_addr(AF_INET6, ptr));
282 				break;
283 			}
284 			_ptrinc(alen);
285 			v = *(u_int8_t *)ptr;
286 			break;
287 
288 		case LLDP_TLV_ORG:
289 			printf(", Org");
290 			break;
291 
292 		default:
293 			printf(", type %d length %d", type, vlen);
294 			break;
295 		}
296 		ptr += vlen;
297 	}
298 
299  done:
300 	return;
301 
302  trunc:
303 	printf(" [|LLDP]");
304 }
305 
306