2 * netsniff-ng - the packet sniffing beast
3 * Copyright 2012, 2013 Tobias Klauser <tklauser@distanz.ch>
4 * Subject to the GPL, version 2.
8 #include <arpa/inet.h> /* for inet_ntop() */
9 #include <netinet/in.h> /* for ntohs()/ntohl() */
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)
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
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
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
89 static int lldp_print_net_addr(const uint8_t *addr
, size_t addrlen
)
103 inet_ntop(AF_INET
, addr
, buf
, sizeof(buf
));
109 inet_ntop(AF_INET6
, addr
, buf
, sizeof(buf
));
115 tprintf("%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",
116 addr
[0], addr
[1], addr
[2], addr
[3], addr
[4], addr
[5]);
119 tprintf("unknown address family");
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
;
153 unsigned int tlv_type
, tlv_len
;
155 uint8_t *tlv_info_str
;
156 uint16_t sys_cap
, en_cap
;
165 while (len
>= sizeof(tlv_hdr
)) {
166 tlv_hdr
= EXTRACT_16BIT(pkt_pull(pkt
, sizeof(tlv_hdr
)));
167 tlv_type
= LLDP_TLV_TYPE(tlv_hdr
);
168 tlv_len
= LLDP_TLV_LENGTH(tlv_hdr
);
170 len
-= sizeof(tlv_hdr
);
172 if (tlv_type
== LLDP_TLV_END
&& tlv_len
== 0) {
173 /* Chassis ID, Port ID and TTL are mandatory */
183 case LLDP_TLV_CHASSIS_ID
:
185 * The mandatory chassis ID shall be the first TLV and
186 * shall appear exactly once.
191 tprintf("Chassis ID");
196 tlv_info_str
= pkt_pull(pkt
, tlv_len
);
197 if (tlv_info_str
== NULL
)
200 subtype
= *tlv_info_str
++;
201 tprintf(" (Subtype %u => ", subtype
);
204 case LLDP_CHASSIS_SUBTYPE_MAC_ADDR
:
208 tprintf("%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",
209 tlv_info_str
[0], tlv_info_str
[1],
210 tlv_info_str
[2], tlv_info_str
[3],
211 tlv_info_str
[4], tlv_info_str
[5]);
213 case LLDP_CHASSIS_SUBTYPE_NET_ADDR
:
214 if (lldp_print_net_addr(tlv_info_str
, tlv_len
))
217 case LLDP_CHASSIS_SUBTYPE_CHASSIS
:
218 case LLDP_CHASSIS_SUBTYPE_IF_ALIAS
:
219 case LLDP_CHASSIS_SUBTYPE_PORT
:
220 case LLDP_CHASSIS_SUBTYPE_IF_NAME
:
221 case LLDP_CHASSIS_SUBTYPE_LOCAL
:
222 tputs_safe((const char *) tlv_info_str
, tlv_len
- 1);
231 case LLDP_TLV_PORT_ID
:
233 * The mandatory port ID shall be the second TLV and
234 * shall appear exactly once.
239 tprintf(", Port ID");
244 tlv_info_str
= pkt_pull(pkt
, tlv_len
);
245 if (tlv_info_str
== NULL
)
248 subtype
= *tlv_info_str
++;
249 tprintf(" (Subtype %u => ", subtype
);
252 case LLDP_PORT_SUBTYPE_MAC_ADDR
:
256 tprintf("%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",
257 tlv_info_str
[0], tlv_info_str
[1],
258 tlv_info_str
[2], tlv_info_str
[3],
259 tlv_info_str
[4], tlv_info_str
[5]);
261 case LLDP_PORT_SUBTYPE_NET_ADDR
:
262 if (lldp_print_net_addr(tlv_info_str
, tlv_len
))
265 case LLDP_PORT_SUBTYPE_IF_ALIAS
:
266 case LLDP_PORT_SUBTYPE_PORT_COMP
:
267 case LLDP_PORT_SUBTYPE_IF_NAME
:
268 case LLDP_PORT_SUBTYPE_AGENT_CIRC_ID
:
269 case LLDP_PORT_SUBTYPE_LOCAL
:
270 tputs_safe((const char *) tlv_info_str
, tlv_len
- 1);
281 * The mandatory TTL shall be the third TLV and
282 * shall appear exactly once.
292 tlv_info_str
= pkt_pull(pkt
, tlv_len
);
293 if (tlv_info_str
== NULL
)
296 tprintf(" (%u)", EXTRACT_16BIT(tlv_info_str
));
298 case LLDP_TLV_PORT_DESC
:
299 tprintf(", Port desc (");
301 tlv_info_str
= pkt_pull(pkt
, tlv_len
);
302 if (tlv_info_str
== NULL
)
305 tputs_safe((const char *) tlv_info_str
, tlv_len
);
309 case LLDP_TLV_SYSTEM_NAME
:
310 tprintf(", Sys name (");
312 tlv_info_str
= pkt_pull(pkt
, tlv_len
);
313 if (tlv_info_str
== NULL
)
316 tputs_safe((const char *) tlv_info_str
, tlv_len
);
320 case LLDP_TLV_SYSTEM_DESC
:
321 tprintf(", Sys desc (");
323 tlv_info_str
= pkt_pull(pkt
, tlv_len
);
324 if (tlv_info_str
== NULL
)
327 tputs_safe((const char *) tlv_info_str
, tlv_len
);
331 case LLDP_TLV_SYSTEM_CAP
:
332 tprintf(", Sys Cap");
337 tlv_info_str
= pkt_pull(pkt
, tlv_len
);
338 if (tlv_info_str
== NULL
)
341 sys_cap
= EXTRACT_16BIT(tlv_info_str
);
342 tlv_info_str
+= sizeof(uint32_t);
343 en_cap
= EXTRACT_16BIT(tlv_info_str
);
346 lldp_print_cap(sys_cap
);
348 tprintf(" Ena Cap (");
349 lldp_print_cap(en_cap
);
352 case LLDP_TLV_MGMT_ADDR
:
353 tprintf(", Mgmt Addr (");
355 if (tlv_len
< 9 || tlv_len
> 167)
358 tlv_info_str
= pkt_pull(pkt
, tlv_len
);
359 if (tlv_info_str
== NULL
)
362 mgmt_alen
= *tlv_info_str
;
364 if (tlv_len
- 1 < mgmt_alen
)
367 if (lldp_print_net_addr(tlv_info_str
, mgmt_alen
))
369 tlv_info_str
+= mgmt_alen
;
371 tprintf(", Iface Subtype %d/", *tlv_info_str
);
372 switch (*tlv_info_str
) {
373 case LLDP_IFACE_NUM_SUBTYPE_IF_INDEX
:
376 case LLDP_IFACE_NUM_SUBTYPE_SYS_PORT
:
377 tprintf("System Port Number");
385 tprintf(", Iface Number %u", EXTRACT_32BIT(tlv_info_str
));
388 mgmt_oidlen
= *tlv_info_str
;
389 if (tlv_len
- mgmt_alen
- sizeof(uint32_t) - 3 < mgmt_oidlen
)
391 if (mgmt_oidlen
> 0) {
393 tputs_safe((const char *) tlv_info_str
+ 1, mgmt_oidlen
);
398 case LLDP_TLV_ORG_SPECIFIC
:
399 tprintf(", Org specific");
404 tlv_info_str
= pkt_pull(pkt
, 4);
405 if (tlv_info_str
== NULL
)
408 oui
= ntohl(*((uint32_t *) tlv_info_str
));
409 subtype
= oui
& 0xff;
411 tprintf(" (OUI %s, Subtype %u)", lookup_vendor_str(oui
),
414 /* Just eat it up, we don't know how to interpret it */
415 pkt_pull(pkt
, tlv_len
- 4);
418 tprintf(", Unknown TLV %u", tlv_type
);
419 pkt_pull(pkt
, tlv_len
);
432 tprintf(" %sINVALID%s ]\n", colorize_start_full(black
, red
),
436 static void lldp_less(struct pkt_buff
*pkt
)
438 unsigned int len
, n_tlv
= 0;
439 unsigned int tlv_type
, tlv_len
;
444 while (len
>= sizeof(tlv_hdr
)) {
445 tlv_hdr
= EXTRACT_16BIT(pkt_pull(pkt
, sizeof(tlv_hdr
)));
446 tlv_type
= LLDP_TLV_TYPE(tlv_hdr
);
447 tlv_len
= LLDP_TLV_LENGTH(tlv_hdr
);
450 len
-= sizeof(tlv_hdr
);
452 if (tlv_type
== LLDP_TLV_END
|| tlv_len
== 0)
457 pkt_pull(pkt
, tlv_len
);
462 tprintf(" %u TLV%s", n_tlv
, n_tlv
== 1 ? "" : "s");
465 struct protocol lldp_ops
= {
468 .print_less
= lldp_less
,