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