netsniff-ng: Add __maybe_unused attribute to timer functions
[netsniff-ng.git] / proto_lldp.c
blob4e33048bb38855ba221038d12a2229b2c88b8ab0
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"
16 #include "xutils.h"
18 #define EXTRACT_16BIT(x) ntohs(*((uint16_t *) (x)))
19 #define EXTRACT_32BIT(x) ntohl(*((uint32_t *) (x)))
21 #define LLDP_TLV_TYPE(tlv) (((tlv) & 0xFE00) >> 9)
22 #define LLDP_TLV_LENGTH(tlv) ((tlv) & 0x01FF)
25 * LLDP TLV types
27 #define LLDP_TLV_END 0
28 #define LLDP_TLV_CHASSIS_ID 1
29 #define LLDP_TLV_PORT_ID 2
30 #define LLDP_TLV_TTL 3
31 #define LLDP_TLV_PORT_DESC 4
32 #define LLDP_TLV_SYSTEM_NAME 5
33 #define LLDP_TLV_SYSTEM_DESC 6
34 #define LLDP_TLV_SYSTEM_CAP 7
35 #define LLDP_TLV_MGMT_ADDR 8
36 #define LLDP_TLV_ORG_SPECIFIC 127
39 * Chassis ID subtypes
41 #define LLDP_CHASSIS_SUBTYPE_CHASSIS 1
42 #define LLDP_CHASSIS_SUBTYPE_IF_ALIAS 2
43 #define LLDP_CHASSIS_SUBTYPE_PORT 3
44 #define LLDP_CHASSIS_SUBTYPE_MAC_ADDR 4
45 #define LLDP_CHASSIS_SUBTYPE_NET_ADDR 5
46 #define LLDP_CHASSIS_SUBTYPE_IF_NAME 6
47 #define LLDP_CHASSIS_SUBTYPE_LOCAL 7
50 * Port ID subtypes
52 #define LLDP_PORT_SUBTYPE_IF_ALIAS 1
53 #define LLDP_PORT_SUBTYPE_PORT_COMP 2
54 #define LLDP_PORT_SUBTYPE_MAC_ADDR 3
55 #define LLDP_PORT_SUBTYPE_NET_ADDR 4
56 #define LLDP_PORT_SUBTYPE_IF_NAME 5
57 #define LLDP_PORT_SUBTYPE_AGENT_CIRC_ID 6
58 #define LLDP_PORT_SUBTYPE_LOCAL 7
61 * System capabilits bit masks
63 #define LLDP_SYSTEM_CAP_OTHER (1 << 0)
64 #define LLDP_SYSTEM_CAP_REPEATER (1 << 1)
65 #define LLDP_SYSTEM_CAP_BRIDGE (1 << 2)
66 #define LLDP_SYSTEM_CAP_WLAN_AP (1 << 3)
67 #define LLDP_SYSTEM_CAP_ROUTER (1 << 4)
68 #define LLDP_SYSTEM_CAP_TELEPHONE (1 << 5)
69 #define LLDP_SYSTEM_CAP_DOCSIS (1 << 6)
70 #define LLDP_SYSTEM_CAP_STATION_ONLY (1 << 7)
73 * Interface number subtypes (for Management addres TLV)
75 #define LLDP_IFACE_NUM_SUBTYPE_UNKNOWN 1
76 #define LLDP_IFACE_NUM_SUBTYPE_IF_INDEX 2
77 #define LLDP_IFACE_NUM_SUBTYPE_SYS_PORT 3
80 * IANA address family numbers (only the ones we actually use)
81 * http://www.iana.org/assignments/address-family-numbers/address-family-numbers.txt
83 * TODO: Move these into own header if there are other users?
85 #define IANA_AF_IPV4 1
86 #define IANA_AF_IPV6 2
87 #define IANA_AF_802 6
89 static int lldp_print_net_addr(const uint8_t *addr, size_t addrlen)
91 uint8_t af;
92 char buf[64];
94 if (addrlen < 1)
95 return -EINVAL;
97 af = *addr++;
98 addrlen--;
99 switch (af) {
100 case IANA_AF_IPV4:
101 if (addrlen < 4)
102 return -EINVAL;
103 inet_ntop(AF_INET, addr, buf, sizeof(buf));
104 tprintf("%s", buf);
105 break;
106 case IANA_AF_IPV6:
107 if (addrlen < 16)
108 return -EINVAL;
109 inet_ntop(AF_INET6, addr, buf, sizeof(buf));
110 tprintf("%s", buf);
111 break;
112 case IANA_AF_802:
113 if (addrlen < 6)
114 return -EINVAL;
115 tprintf("%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",
116 addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
117 break;
118 default:
119 tprintf("unknown address family");
120 break;
123 return 0;
126 static void lldp_print_cap(uint16_t cap)
128 unsigned int prev = 0;
130 if (cap & LLDP_SYSTEM_CAP_OTHER)
131 tprintf("%sOther", prev++ ? ", " : "");
132 if (cap & LLDP_SYSTEM_CAP_REPEATER)
133 tprintf("%sRepeater", prev++ ? ", " : "");
134 if (cap & LLDP_SYSTEM_CAP_BRIDGE)
135 tprintf("%sBridge", prev++ ? ", " : "");
136 if (cap & LLDP_SYSTEM_CAP_WLAN_AP)
137 tprintf("%sWLAN AP", prev++ ? ", " : "");
138 if (cap & LLDP_SYSTEM_CAP_ROUTER)
139 tprintf("%sRouter", prev++ ? ", " : "");
140 if (cap & LLDP_SYSTEM_CAP_TELEPHONE)
141 tprintf("%sTelephone", prev++ ? ", " : "");
142 if (cap & LLDP_SYSTEM_CAP_DOCSIS)
143 tprintf("%sDOCSIS", prev++ ? ", " : "");
144 if (cap & LLDP_SYSTEM_CAP_STATION_ONLY)
145 tprintf("%sStation only", prev++ ? ", " : "");
148 static void lldp(struct pkt_buff *pkt)
150 unsigned int n_tlv = 0;
151 uint8_t subtype, mgmt_alen, mgmt_oidlen;
152 uint16_t tlv_hdr;
153 unsigned int tlv_type, tlv_len;
154 unsigned int len;
155 uint8_t *tlv_info_str;
156 uint16_t sys_cap, en_cap;
157 uint32_t oui;
159 len = pkt_len(pkt);
160 if (len == 0)
161 return;
163 tprintf(" [ LLDP ");
165 while (len >= sizeof(tlv_hdr)) {
166 uint8_t *data = pkt_pull(pkt, sizeof(tlv_hdr));
167 if (data == NULL)
168 goto out_invalid;
170 tlv_hdr = EXTRACT_16BIT(data);
171 tlv_type = LLDP_TLV_TYPE(tlv_hdr);
172 tlv_len = LLDP_TLV_LENGTH(tlv_hdr);
174 len -= sizeof(tlv_hdr);
176 if (tlv_type == LLDP_TLV_END && tlv_len == 0) {
177 /* Chassis ID, Port ID and TTL are mandatory */
178 if (n_tlv < 3)
179 goto out_invalid;
180 else
181 break;
183 if (len < tlv_len)
184 goto out_invalid;
186 switch (tlv_type) {
187 case LLDP_TLV_CHASSIS_ID:
189 * The mandatory chassis ID shall be the first TLV and
190 * shall appear exactly once.
192 if (n_tlv != 0)
193 goto out_invalid;
195 tprintf("Chassis ID");
197 if (tlv_len < 2)
198 goto out_invalid;
200 tlv_info_str = pkt_pull(pkt, tlv_len);
201 if (tlv_info_str == NULL)
202 goto out_invalid;
204 subtype = *tlv_info_str++;
205 tprintf(" (Subtype %u => ", subtype);
207 switch (subtype) {
208 case LLDP_CHASSIS_SUBTYPE_MAC_ADDR:
209 if (tlv_len < 7)
210 goto out_invalid;
212 tprintf("%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",
213 tlv_info_str[0], tlv_info_str[1],
214 tlv_info_str[2], tlv_info_str[3],
215 tlv_info_str[4], tlv_info_str[5]);
216 break;
217 case LLDP_CHASSIS_SUBTYPE_NET_ADDR:
218 if (lldp_print_net_addr(tlv_info_str, tlv_len))
219 goto out_invalid;
220 break;
221 case LLDP_CHASSIS_SUBTYPE_CHASSIS:
222 case LLDP_CHASSIS_SUBTYPE_IF_ALIAS:
223 case LLDP_CHASSIS_SUBTYPE_PORT:
224 case LLDP_CHASSIS_SUBTYPE_IF_NAME:
225 case LLDP_CHASSIS_SUBTYPE_LOCAL:
226 tputs_safe((const char *) tlv_info_str, tlv_len - 1);
227 break;
228 default:
229 tprintf("Reserved");
230 break;
233 tprintf(")");
234 break;
235 case LLDP_TLV_PORT_ID:
237 * The mandatory port ID shall be the second TLV and
238 * shall appear exactly once.
240 if (n_tlv != 1)
241 goto out_invalid;
243 tprintf(", Port ID");
245 if (tlv_len < 2)
246 goto out_invalid;
248 tlv_info_str = pkt_pull(pkt, tlv_len);
249 if (tlv_info_str == NULL)
250 goto out_invalid;
252 subtype = *tlv_info_str++;
253 tprintf(" (Subtype %u => ", subtype);
255 switch (subtype) {
256 case LLDP_PORT_SUBTYPE_MAC_ADDR:
257 if (tlv_len < 7)
258 goto out_invalid;
260 tprintf("%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",
261 tlv_info_str[0], tlv_info_str[1],
262 tlv_info_str[2], tlv_info_str[3],
263 tlv_info_str[4], tlv_info_str[5]);
264 break;
265 case LLDP_PORT_SUBTYPE_NET_ADDR:
266 if (lldp_print_net_addr(tlv_info_str, tlv_len))
267 goto out_invalid;
268 break;
269 case LLDP_PORT_SUBTYPE_IF_ALIAS:
270 case LLDP_PORT_SUBTYPE_PORT_COMP:
271 case LLDP_PORT_SUBTYPE_IF_NAME:
272 case LLDP_PORT_SUBTYPE_AGENT_CIRC_ID:
273 case LLDP_PORT_SUBTYPE_LOCAL:
274 tputs_safe((const char *) tlv_info_str, tlv_len - 1);
275 break;
276 default:
277 tprintf("Reserved");
278 break;
281 tprintf(")");
282 break;
283 case LLDP_TLV_TTL:
285 * The mandatory TTL shall be the third TLV and
286 * shall appear exactly once.
288 if (n_tlv != 2)
289 goto out_invalid;
291 tprintf(", TTL");
293 if (tlv_len != 2)
294 goto out_invalid;
296 tlv_info_str = pkt_pull(pkt, tlv_len);
297 if (tlv_info_str == NULL)
298 goto out_invalid;
300 tprintf(" (%u)", EXTRACT_16BIT(tlv_info_str));
301 break;
302 case LLDP_TLV_PORT_DESC:
303 tprintf(", Port desc (");
305 tlv_info_str = pkt_pull(pkt, tlv_len);
306 if (tlv_info_str == NULL)
307 tprintf("none");
308 else
309 tputs_safe((const char *) tlv_info_str, tlv_len);
311 tprintf(")");
312 break;
313 case LLDP_TLV_SYSTEM_NAME:
314 tprintf(", Sys name (");
316 tlv_info_str = pkt_pull(pkt, tlv_len);
317 if (tlv_info_str == NULL)
318 tprintf("none");
319 else
320 tputs_safe((const char *) tlv_info_str, tlv_len);
322 tprintf(")");
323 break;
324 case LLDP_TLV_SYSTEM_DESC:
325 tprintf(", Sys desc (");
327 tlv_info_str = pkt_pull(pkt, tlv_len);
328 if (tlv_info_str == NULL)
329 tprintf("none");
330 else
331 tputs_safe((const char *) tlv_info_str, tlv_len);
333 tprintf(")");
334 break;
335 case LLDP_TLV_SYSTEM_CAP:
336 tprintf(", Sys Cap");
338 if (tlv_len != 4)
339 goto out_invalid;
341 tlv_info_str = pkt_pull(pkt, tlv_len);
342 if (tlv_info_str == NULL)
343 goto out_invalid;
345 sys_cap = EXTRACT_16BIT(tlv_info_str);
346 tlv_info_str += sizeof(uint32_t);
347 en_cap = EXTRACT_16BIT(tlv_info_str);
349 tprintf(" (");
350 lldp_print_cap(sys_cap);
351 tprintf(")");
352 tprintf(" Ena Cap (");
353 lldp_print_cap(en_cap);
354 tprintf(")");
355 break;
356 case LLDP_TLV_MGMT_ADDR:
357 tprintf(", Mgmt Addr (");
359 if (tlv_len < 9 || tlv_len > 167)
360 goto out_invalid;
362 tlv_info_str = pkt_pull(pkt, tlv_len);
363 if (tlv_info_str == NULL)
364 goto out_invalid;
366 mgmt_alen = *tlv_info_str;
367 tlv_info_str++;
368 if (tlv_len - 1 < mgmt_alen)
369 goto out_invalid;
371 if (lldp_print_net_addr(tlv_info_str, mgmt_alen))
372 goto out_invalid;
373 tlv_info_str += mgmt_alen;
375 tprintf(", Iface Subtype %d/", *tlv_info_str);
376 switch (*tlv_info_str) {
377 case LLDP_IFACE_NUM_SUBTYPE_IF_INDEX:
378 tprintf("ifIndex");
379 break;
380 case LLDP_IFACE_NUM_SUBTYPE_SYS_PORT:
381 tprintf("System Port Number");
382 break;
383 default:
384 tprintf("Unknown");
385 break;
388 tlv_info_str++;
389 tprintf(", Iface Number %u", EXTRACT_32BIT(tlv_info_str));
391 tlv_info_str += 4;
392 mgmt_oidlen = *tlv_info_str;
393 if (tlv_len - mgmt_alen - sizeof(uint32_t) - 3 < mgmt_oidlen)
394 goto out_invalid;
395 if (mgmt_oidlen > 0) {
396 tprintf(", OID ");
397 tputs_safe((const char *) tlv_info_str + 1, mgmt_oidlen);
400 tprintf(")");
401 break;
402 case LLDP_TLV_ORG_SPECIFIC:
403 tprintf(", Org specific");
405 if (tlv_len < 4)
406 goto out_invalid;
408 tlv_info_str = pkt_pull(pkt, 4);
409 if (tlv_info_str == NULL)
410 goto out_invalid;
412 oui = ntohl(*((uint32_t *) tlv_info_str));
413 subtype = oui & 0xff;
414 oui >>= 8;
415 tprintf(" (OUI %s, Subtype %u)", lookup_vendor_str(oui),
416 subtype);
418 /* Just eat it up, we don't know how to interpret it */
419 pkt_pull(pkt, tlv_len - 4);
420 break;
421 default:
422 tprintf(", Unknown TLV %u", tlv_type);
423 pkt_pull(pkt, tlv_len);
424 break;
427 n_tlv++;
430 len -= tlv_len;
432 tprintf(" ]\n");
433 return;
435 out_invalid:
436 tprintf(" %sINVALID%s ]\n", colorize_start_full(black, red),
437 colorize_end());
440 static void lldp_less(struct pkt_buff *pkt)
442 unsigned int len, n_tlv = 0;
443 unsigned int tlv_type, tlv_len;
444 uint16_t tlv_hdr;
446 len = pkt_len(pkt);
448 while (len >= sizeof(tlv_hdr)) {
449 uint8_t *data = pkt_pull(pkt, sizeof(tlv_hdr));
450 if (data == NULL)
451 break;
453 tlv_hdr = EXTRACT_16BIT(data);
454 tlv_type = LLDP_TLV_TYPE(tlv_hdr);
455 tlv_len = LLDP_TLV_LENGTH(tlv_hdr);
457 n_tlv++;
458 len -= sizeof(tlv_hdr);
460 if (tlv_type == LLDP_TLV_END || tlv_len == 0)
461 break;
462 if (len < tlv_len)
463 break;
465 pkt_pull(pkt, tlv_len);
467 len -= tlv_len;
470 tprintf(" %u TLV%s", n_tlv, n_tlv == 1 ? "" : "s");
473 struct protocol lldp_ops = {
474 .key = 0x88cc,
475 .print_full = lldp,
476 .print_less = lldp_less,