build: prevent redefinition of _FORTIFY_SOURCE in gentoo
[netsniff-ng.git] / proto_lldp.c
blob9301281935133fb03fc50836b1cc9e35b4bdabf3
1 /*
2 * netsniff-ng - the packet sniffing beast
3 * Copyright 2012, 2013 Tobias Klauser <tklauser@distanz.ch>
4 * Subject to the GPL, version 2.
5 */
7 #include <stdint.h>
8 #include <arpa/inet.h> /* for inet_ntop() */
9 #include <netinet/in.h> /* for ntohs()/ntohl() */
11 #include "built_in.h"
12 #include "oui.h"
13 #include "pkt_buff.h"
14 #include "proto.h"
15 #include "protos.h"
17 #define EXTRACT_16BIT(x) ntohs(*((uint16_t *) (x)))
18 #define EXTRACT_32BIT(x) ntohl(*((uint32_t *) (x)))
20 #define LLDP_TLV_TYPE(tlv) (((tlv) & 0xFE00) >> 9)
21 #define LLDP_TLV_LENGTH(tlv) ((tlv) & 0x01FF)
24 * LLDP TLV types
26 #define LLDP_TLV_END 0
27 #define LLDP_TLV_CHASSIS_ID 1
28 #define LLDP_TLV_PORT_ID 2
29 #define LLDP_TLV_TTL 3
30 #define LLDP_TLV_PORT_DESC 4
31 #define LLDP_TLV_SYSTEM_NAME 5
32 #define LLDP_TLV_SYSTEM_DESC 6
33 #define LLDP_TLV_SYSTEM_CAP 7
34 #define LLDP_TLV_MGMT_ADDR 8
35 #define LLDP_TLV_ORG_SPECIFIC 127
38 * Chassis ID subtypes
40 #define LLDP_CHASSIS_SUBTYPE_CHASSIS 1
41 #define LLDP_CHASSIS_SUBTYPE_IF_ALIAS 2
42 #define LLDP_CHASSIS_SUBTYPE_PORT 3
43 #define LLDP_CHASSIS_SUBTYPE_MAC_ADDR 4
44 #define LLDP_CHASSIS_SUBTYPE_NET_ADDR 5
45 #define LLDP_CHASSIS_SUBTYPE_IF_NAME 6
46 #define LLDP_CHASSIS_SUBTYPE_LOCAL 7
49 * Port ID subtypes
51 #define LLDP_PORT_SUBTYPE_IF_ALIAS 1
52 #define LLDP_PORT_SUBTYPE_PORT_COMP 2
53 #define LLDP_PORT_SUBTYPE_MAC_ADDR 3
54 #define LLDP_PORT_SUBTYPE_NET_ADDR 4
55 #define LLDP_PORT_SUBTYPE_IF_NAME 5
56 #define LLDP_PORT_SUBTYPE_AGENT_CIRC_ID 6
57 #define LLDP_PORT_SUBTYPE_LOCAL 7
60 * System capabilits bit masks
62 #define LLDP_SYSTEM_CAP_OTHER (1 << 0)
63 #define LLDP_SYSTEM_CAP_REPEATER (1 << 1)
64 #define LLDP_SYSTEM_CAP_BRIDGE (1 << 2)
65 #define LLDP_SYSTEM_CAP_WLAN_AP (1 << 3)
66 #define LLDP_SYSTEM_CAP_ROUTER (1 << 4)
67 #define LLDP_SYSTEM_CAP_TELEPHONE (1 << 5)
68 #define LLDP_SYSTEM_CAP_DOCSIS (1 << 6)
69 #define LLDP_SYSTEM_CAP_STATION_ONLY (1 << 7)
72 * Interface number subtypes (for Management addres TLV)
74 #define LLDP_IFACE_NUM_SUBTYPE_UNKNOWN 1
75 #define LLDP_IFACE_NUM_SUBTYPE_IF_INDEX 2
76 #define LLDP_IFACE_NUM_SUBTYPE_SYS_PORT 3
79 * IANA address family numbers (only the ones we actually use)
80 * http://www.iana.org/assignments/address-family-numbers/address-family-numbers.txt
82 * TODO: Move these into own header if there are other users?
84 #define IANA_AF_IPV4 1
85 #define IANA_AF_IPV6 2
86 #define IANA_AF_802 6
88 static int lldp_print_net_addr(const uint8_t *addr, size_t addrlen)
90 uint8_t af;
91 char buf[64];
93 if (addrlen < 1)
94 return -EINVAL;
96 af = *addr++;
97 addrlen--;
98 switch (af) {
99 case IANA_AF_IPV4:
100 if (addrlen < 4)
101 return -EINVAL;
102 inet_ntop(AF_INET, addr, buf, sizeof(buf));
103 tprintf("%s", buf);
104 break;
105 case IANA_AF_IPV6:
106 if (addrlen < 16)
107 return -EINVAL;
108 inet_ntop(AF_INET6, addr, buf, sizeof(buf));
109 tprintf("%s", buf);
110 break;
111 case IANA_AF_802:
112 if (addrlen < 6)
113 return -EINVAL;
114 tprintf("%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",
115 addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
116 break;
117 default:
118 tprintf("unknown address family");
119 break;
122 return 0;
125 static inline void lldp_print_cap_one(const char *cap, unsigned int *prev)
127 tprintf("%s%s", *prev ? ", " : "", cap);
128 (*prev)++;
131 static void lldp_print_cap(uint16_t cap)
133 unsigned int prev = 0;
135 if (cap & LLDP_SYSTEM_CAP_OTHER)
136 lldp_print_cap_one("Other", &prev);
137 if (cap & LLDP_SYSTEM_CAP_REPEATER)
138 lldp_print_cap_one("Repeater", &prev);
139 if (cap & LLDP_SYSTEM_CAP_BRIDGE)
140 lldp_print_cap_one("Bridge", &prev);
141 if (cap & LLDP_SYSTEM_CAP_WLAN_AP)
142 lldp_print_cap_one("WLAN AP", &prev);
143 if (cap & LLDP_SYSTEM_CAP_ROUTER)
144 lldp_print_cap_one("Router", &prev);
145 if (cap & LLDP_SYSTEM_CAP_TELEPHONE)
146 lldp_print_cap_one("Telephone", &prev);
147 if (cap & LLDP_SYSTEM_CAP_DOCSIS)
148 lldp_print_cap_one("DOCSIS", &prev);
149 if (cap & LLDP_SYSTEM_CAP_STATION_ONLY)
150 lldp_print_cap_one("Station only", &prev);
153 static void lldp(struct pkt_buff *pkt)
155 unsigned int n_tlv = 0;
156 uint8_t subtype, mgmt_alen, mgmt_oidlen;
157 uint16_t tlv_hdr;
158 unsigned int tlv_type, tlv_len;
159 unsigned int len;
160 uint8_t *tlv_info_str;
161 uint16_t sys_cap, en_cap;
162 uint32_t oui;
164 len = pkt_len(pkt);
165 if (len == 0)
166 return;
168 tprintf(" [ LLDP ");
170 while (len >= sizeof(tlv_hdr)) {
171 uint8_t *data = pkt_pull(pkt, sizeof(tlv_hdr));
172 if (data == NULL)
173 goto out_invalid;
175 tlv_hdr = EXTRACT_16BIT(data);
176 tlv_type = LLDP_TLV_TYPE(tlv_hdr);
177 tlv_len = LLDP_TLV_LENGTH(tlv_hdr);
179 len -= sizeof(tlv_hdr);
181 if (tlv_type == LLDP_TLV_END && tlv_len == 0) {
182 /* Chassis ID, Port ID and TTL are mandatory */
183 if (n_tlv < 3)
184 goto out_invalid;
185 else
186 break;
188 if (len < tlv_len)
189 goto out_invalid;
191 switch (tlv_type) {
192 case LLDP_TLV_CHASSIS_ID:
194 * The mandatory chassis ID shall be the first TLV and
195 * shall appear exactly once.
197 if (n_tlv != 0)
198 goto out_invalid;
200 tprintf("Chassis ID");
202 if (tlv_len < 2)
203 goto out_invalid;
205 tlv_info_str = pkt_pull(pkt, tlv_len);
206 if (tlv_info_str == NULL)
207 goto out_invalid;
209 subtype = *tlv_info_str++;
210 tprintf(" (Subtype %u => ", subtype);
212 switch (subtype) {
213 case LLDP_CHASSIS_SUBTYPE_MAC_ADDR:
214 if (tlv_len < 7)
215 goto out_invalid;
217 tprintf("%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",
218 tlv_info_str[0], tlv_info_str[1],
219 tlv_info_str[2], tlv_info_str[3],
220 tlv_info_str[4], tlv_info_str[5]);
221 break;
222 case LLDP_CHASSIS_SUBTYPE_NET_ADDR:
223 if (lldp_print_net_addr(tlv_info_str, tlv_len))
224 goto out_invalid;
225 break;
226 case LLDP_CHASSIS_SUBTYPE_CHASSIS:
227 case LLDP_CHASSIS_SUBTYPE_IF_ALIAS:
228 case LLDP_CHASSIS_SUBTYPE_PORT:
229 case LLDP_CHASSIS_SUBTYPE_IF_NAME:
230 case LLDP_CHASSIS_SUBTYPE_LOCAL:
231 tputs_safe((const char *) tlv_info_str, tlv_len - 1);
232 break;
233 default:
234 tprintf("Reserved");
235 break;
238 tprintf(")");
239 break;
240 case LLDP_TLV_PORT_ID:
242 * The mandatory port ID shall be the second TLV and
243 * shall appear exactly once.
245 if (n_tlv != 1)
246 goto out_invalid;
248 tprintf(", Port ID");
250 if (tlv_len < 2)
251 goto out_invalid;
253 tlv_info_str = pkt_pull(pkt, tlv_len);
254 if (tlv_info_str == NULL)
255 goto out_invalid;
257 subtype = *tlv_info_str++;
258 tprintf(" (Subtype %u => ", subtype);
260 switch (subtype) {
261 case LLDP_PORT_SUBTYPE_MAC_ADDR:
262 if (tlv_len < 7)
263 goto out_invalid;
265 tprintf("%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",
266 tlv_info_str[0], tlv_info_str[1],
267 tlv_info_str[2], tlv_info_str[3],
268 tlv_info_str[4], tlv_info_str[5]);
269 break;
270 case LLDP_PORT_SUBTYPE_NET_ADDR:
271 if (lldp_print_net_addr(tlv_info_str, tlv_len))
272 goto out_invalid;
273 break;
274 case LLDP_PORT_SUBTYPE_IF_ALIAS:
275 case LLDP_PORT_SUBTYPE_PORT_COMP:
276 case LLDP_PORT_SUBTYPE_IF_NAME:
277 case LLDP_PORT_SUBTYPE_AGENT_CIRC_ID:
278 case LLDP_PORT_SUBTYPE_LOCAL:
279 tputs_safe((const char *) tlv_info_str, tlv_len - 1);
280 break;
281 default:
282 tprintf("Reserved");
283 break;
286 tprintf(")");
287 break;
288 case LLDP_TLV_TTL:
290 * The mandatory TTL shall be the third TLV and
291 * shall appear exactly once.
293 if (n_tlv != 2)
294 goto out_invalid;
296 tprintf(", TTL");
298 if (tlv_len != 2)
299 goto out_invalid;
301 tlv_info_str = pkt_pull(pkt, tlv_len);
302 if (tlv_info_str == NULL)
303 goto out_invalid;
305 tprintf(" (%u)", EXTRACT_16BIT(tlv_info_str));
306 break;
307 case LLDP_TLV_PORT_DESC:
308 tprintf(", Port desc (");
310 tlv_info_str = pkt_pull(pkt, tlv_len);
311 if (tlv_info_str == NULL)
312 tprintf("none");
313 else
314 tputs_safe((const char *) tlv_info_str, tlv_len);
316 tprintf(")");
317 break;
318 case LLDP_TLV_SYSTEM_NAME:
319 tprintf(", Sys name (");
321 tlv_info_str = pkt_pull(pkt, tlv_len);
322 if (tlv_info_str == NULL)
323 tprintf("none");
324 else
325 tputs_safe((const char *) tlv_info_str, tlv_len);
327 tprintf(")");
328 break;
329 case LLDP_TLV_SYSTEM_DESC:
330 tprintf(", Sys desc (");
332 tlv_info_str = pkt_pull(pkt, tlv_len);
333 if (tlv_info_str == NULL)
334 tprintf("none");
335 else
336 tputs_safe((const char *) tlv_info_str, tlv_len);
338 tprintf(")");
339 break;
340 case LLDP_TLV_SYSTEM_CAP:
341 tprintf(", Sys Cap");
343 if (tlv_len != 4)
344 goto out_invalid;
346 tlv_info_str = pkt_pull(pkt, tlv_len);
347 if (tlv_info_str == NULL)
348 goto out_invalid;
350 sys_cap = EXTRACT_16BIT(tlv_info_str);
351 tlv_info_str += sizeof(uint32_t);
352 en_cap = EXTRACT_16BIT(tlv_info_str);
354 tprintf(" (");
355 lldp_print_cap(sys_cap);
356 tprintf(")");
357 tprintf(" Ena Cap (");
358 lldp_print_cap(en_cap);
359 tprintf(")");
360 break;
361 case LLDP_TLV_MGMT_ADDR:
362 tprintf(", Mgmt Addr (");
364 if (tlv_len < 9 || tlv_len > 167)
365 goto out_invalid;
367 tlv_info_str = pkt_pull(pkt, tlv_len);
368 if (tlv_info_str == NULL)
369 goto out_invalid;
371 mgmt_alen = *tlv_info_str;
372 tlv_info_str++;
373 if (tlv_len - 1 < mgmt_alen)
374 goto out_invalid;
376 if (lldp_print_net_addr(tlv_info_str, mgmt_alen))
377 goto out_invalid;
378 tlv_info_str += mgmt_alen;
380 tprintf(", Iface Subtype %d/", *tlv_info_str);
381 switch (*tlv_info_str) {
382 case LLDP_IFACE_NUM_SUBTYPE_IF_INDEX:
383 tprintf("ifIndex");
384 break;
385 case LLDP_IFACE_NUM_SUBTYPE_SYS_PORT:
386 tprintf("System Port Number");
387 break;
388 default:
389 tprintf("Unknown");
390 break;
393 tlv_info_str++;
394 tprintf(", Iface Number %u", EXTRACT_32BIT(tlv_info_str));
396 tlv_info_str += 4;
397 mgmt_oidlen = *tlv_info_str;
398 if (tlv_len - mgmt_alen - sizeof(uint32_t) - 3 < mgmt_oidlen)
399 goto out_invalid;
400 if (mgmt_oidlen > 0) {
401 tprintf(", OID ");
402 tputs_safe((const char *) tlv_info_str + 1, mgmt_oidlen);
405 tprintf(")");
406 break;
407 case LLDP_TLV_ORG_SPECIFIC:
408 tprintf(", Org specific");
410 if (tlv_len < 4)
411 goto out_invalid;
413 tlv_info_str = pkt_pull(pkt, 4);
414 if (tlv_info_str == NULL)
415 goto out_invalid;
417 oui = ntohl(*((uint32_t *) tlv_info_str));
418 subtype = oui & 0xff;
419 oui >>= 8;
420 tprintf(" (OUI %s, Subtype %u)", lookup_vendor_str(oui),
421 subtype);
423 /* Just eat it up, we don't know how to interpret it */
424 pkt_pull(pkt, tlv_len - 4);
425 break;
426 default:
427 tprintf(", Unknown TLV %u", tlv_type);
428 pkt_pull(pkt, tlv_len);
429 break;
432 n_tlv++;
435 len -= tlv_len;
437 tprintf(" ]\n");
438 return;
440 out_invalid:
441 tprintf(" %sINVALID%s ]\n", colorize_start_full(black, red),
442 colorize_end());
445 static void lldp_less(struct pkt_buff *pkt)
447 unsigned int len, n_tlv = 0;
448 unsigned int tlv_type, tlv_len;
449 uint16_t tlv_hdr;
451 len = pkt_len(pkt);
453 while (len >= sizeof(tlv_hdr)) {
454 uint8_t *data = pkt_pull(pkt, sizeof(tlv_hdr));
455 if (data == NULL)
456 break;
458 tlv_hdr = EXTRACT_16BIT(data);
459 tlv_type = LLDP_TLV_TYPE(tlv_hdr);
460 tlv_len = LLDP_TLV_LENGTH(tlv_hdr);
462 n_tlv++;
463 len -= sizeof(tlv_hdr);
465 if (tlv_type == LLDP_TLV_END || tlv_len == 0)
466 break;
467 if (len < tlv_len)
468 break;
470 pkt_pull(pkt, tlv_len);
472 len -= tlv_len;
475 tprintf(" %u TLV%s", n_tlv, n_tlv == 1 ? "" : "s");
478 struct protocol lldp_ops = {
479 .key = 0x88cc,
480 .print_full = lldp,
481 .print_less = lldp_less,