1/*
2 * Copyright (c) 1998-2007 The TCPDUMP project
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that: (1) source code
6 * distributions retain the above copyright notice and this paragraph
7 * in its entirety, and (2) distributions including binary code include
8 * the above copyright notice and this paragraph in its entirety in
9 * the documentation or other materials provided with the distribution.
10 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
11 * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
12 * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
13 * FOR A PARTICULAR PURPOSE.
14 *
15 * support for the IEEE Link Discovery Protocol as per 802.1AB
16 *
17 * Original code by Hannes Gredler (hannes@juniper.net)
18 * IEEE and TIA extensions by Carles Kishimoto <carles.kishimoto@gmail.com>
19 * DCBX extensions by Kaladhar Musunuru <kaladharm@sourceforge.net>
20 */
21
22#ifndef lint
23static const char rcsid[] _U_ =
24"@(#) $Header: /tcpdump/master/tcpdump/print-lldp.c,v 1.10 2008-03-20 09:30:56 hannes Exp $";
25#endif
26
27#ifdef HAVE_CONFIG_H
28#include "config.h"
29#endif
30
31#include <tcpdump-stdinc.h>
32
33#include <stdio.h>
34#include <stdlib.h>
35#include <string.h>
36
37#include "interface.h"
38#include "extract.h"
39#include "addrtoname.h"
40#include "af.h"
41#include "oui.h"
42
43#define	LLDP_EXTRACT_TYPE(x) (((x)&0xfe00)>>9)
44#define	LLDP_EXTRACT_LEN(x) ((x)&0x01ff)
45
46/*
47 * TLV type codes
48 */
49#define LLDP_END_TLV             0
50#define LLDP_CHASSIS_ID_TLV      1
51#define LLDP_PORT_ID_TLV         2
52#define LLDP_TTL_TLV             3
53#define LLDP_PORT_DESCR_TLV      4
54#define LLDP_SYSTEM_NAME_TLV     5
55#define LLDP_SYSTEM_DESCR_TLV    6
56#define LLDP_SYSTEM_CAP_TLV      7
57#define LLDP_MGMT_ADDR_TLV       8
58#define LLDP_PRIVATE_TLV       127
59
60static const struct tok lldp_tlv_values[] = {
61    { LLDP_END_TLV, "End" },
62    { LLDP_CHASSIS_ID_TLV, "Chassis ID" },
63    { LLDP_PORT_ID_TLV, "Port ID" },
64    { LLDP_TTL_TLV, "Time to Live" },
65    { LLDP_PORT_DESCR_TLV, "Port Description" },
66    { LLDP_SYSTEM_NAME_TLV, "System Name" },
67    { LLDP_SYSTEM_DESCR_TLV, "System Description" },
68    { LLDP_SYSTEM_CAP_TLV, "System Capabilities" },
69    { LLDP_MGMT_ADDR_TLV, "Management Address" },
70    { LLDP_PRIVATE_TLV, "Organization specific" },
71    { 0, NULL}
72};
73
74/*
75 * Chassis ID subtypes
76 */
77#define LLDP_CHASSIS_CHASSIS_COMP_SUBTYPE  1
78#define LLDP_CHASSIS_INTF_ALIAS_SUBTYPE    2
79#define LLDP_CHASSIS_PORT_COMP_SUBTYPE     3
80#define LLDP_CHASSIS_MAC_ADDR_SUBTYPE      4
81#define LLDP_CHASSIS_NETWORK_ADDR_SUBTYPE  5
82#define LLDP_CHASSIS_INTF_NAME_SUBTYPE     6
83#define LLDP_CHASSIS_LOCAL_SUBTYPE         7
84
85static const struct tok lldp_chassis_subtype_values[] = {
86    { LLDP_CHASSIS_CHASSIS_COMP_SUBTYPE, "Chassis component"},
87    { LLDP_CHASSIS_INTF_ALIAS_SUBTYPE, "Interface alias"},
88    { LLDP_CHASSIS_PORT_COMP_SUBTYPE, "Port component"},
89    { LLDP_CHASSIS_MAC_ADDR_SUBTYPE, "MAC address"},
90    { LLDP_CHASSIS_NETWORK_ADDR_SUBTYPE, "Network address"},
91    { LLDP_CHASSIS_INTF_NAME_SUBTYPE, "Interface name"},
92    { LLDP_CHASSIS_LOCAL_SUBTYPE, "Local"},
93    { 0, NULL}
94};
95
96/*
97 * Port ID subtypes
98 */
99#define LLDP_PORT_INTF_ALIAS_SUBTYPE       1
100#define LLDP_PORT_PORT_COMP_SUBTYPE        2
101#define LLDP_PORT_MAC_ADDR_SUBTYPE         3
102#define LLDP_PORT_NETWORK_ADDR_SUBTYPE     4
103#define LLDP_PORT_INTF_NAME_SUBTYPE        5
104#define LLDP_PORT_AGENT_CIRC_ID_SUBTYPE    6
105#define LLDP_PORT_LOCAL_SUBTYPE            7
106
107static const struct tok lldp_port_subtype_values[] = {
108    { LLDP_PORT_INTF_ALIAS_SUBTYPE, "Interface alias"},
109    { LLDP_PORT_PORT_COMP_SUBTYPE, "Port component"},
110    { LLDP_PORT_MAC_ADDR_SUBTYPE, "MAC address"},
111    { LLDP_PORT_NETWORK_ADDR_SUBTYPE, "Network Address"},
112    { LLDP_PORT_INTF_NAME_SUBTYPE, "Interface Name"},
113    { LLDP_PORT_AGENT_CIRC_ID_SUBTYPE, "Agent circuit ID"},
114    { LLDP_PORT_LOCAL_SUBTYPE, "Local"},
115    { 0, NULL}
116};
117
118/*
119 * System Capabilities
120 */
121#define LLDP_CAP_OTHER              (1 <<  0)
122#define LLDP_CAP_REPEATER           (1 <<  1)
123#define LLDP_CAP_BRIDGE             (1 <<  2)
124#define LLDP_CAP_WLAN_AP            (1 <<  3)
125#define LLDP_CAP_ROUTER             (1 <<  4)
126#define LLDP_CAP_PHONE              (1 <<  5)
127#define LLDP_CAP_DOCSIS             (1 <<  6)
128#define LLDP_CAP_STATION_ONLY       (1 <<  7)
129
130static const struct tok lldp_cap_values[] = {
131    { LLDP_CAP_OTHER, "Other"},
132    { LLDP_CAP_REPEATER, "Repeater"},
133    { LLDP_CAP_BRIDGE, "Bridge"},
134    { LLDP_CAP_WLAN_AP, "WLAN AP"},
135    { LLDP_CAP_ROUTER, "Router"},
136    { LLDP_CAP_PHONE, "Telephone"},
137    { LLDP_CAP_DOCSIS, "Docsis"},
138    { LLDP_CAP_STATION_ONLY, "Station Only"},
139    { 0, NULL}
140};
141
142#define LLDP_PRIVATE_8021_SUBTYPE_PORT_VLAN_ID		1
143#define LLDP_PRIVATE_8021_SUBTYPE_PROTOCOL_VLAN_ID	2
144#define LLDP_PRIVATE_8021_SUBTYPE_VLAN_NAME		3
145#define LLDP_PRIVATE_8021_SUBTYPE_PROTOCOL_IDENTITY	4
146
147static const struct tok lldp_8021_subtype_values[] = {
148    { LLDP_PRIVATE_8021_SUBTYPE_PORT_VLAN_ID, "Port VLAN Id"},
149    { LLDP_PRIVATE_8021_SUBTYPE_PROTOCOL_VLAN_ID, "Port and Protocol VLAN ID"},
150    { LLDP_PRIVATE_8021_SUBTYPE_VLAN_NAME, "VLAN name"},
151    { LLDP_PRIVATE_8021_SUBTYPE_PROTOCOL_IDENTITY, "Protocol Identity"},
152    { 0, NULL}
153};
154
155#define LLDP_8021_PORT_PROTOCOL_VLAN_SUPPORT       (1 <<  1)
156#define LLDP_8021_PORT_PROTOCOL_VLAN_STATUS        (1 <<  2)
157
158static const struct tok lldp_8021_port_protocol_id_values[] = {
159    { LLDP_8021_PORT_PROTOCOL_VLAN_SUPPORT, "supported"},
160    { LLDP_8021_PORT_PROTOCOL_VLAN_STATUS, "enabled"},
161    { 0, NULL}
162};
163
164#define LLDP_PRIVATE_8023_SUBTYPE_MACPHY        1
165#define LLDP_PRIVATE_8023_SUBTYPE_MDIPOWER      2
166#define LLDP_PRIVATE_8023_SUBTYPE_LINKAGGR      3
167#define LLDP_PRIVATE_8023_SUBTYPE_MTU           4
168
169static const struct tok lldp_8023_subtype_values[] = {
170    { LLDP_PRIVATE_8023_SUBTYPE_MACPHY,	"MAC/PHY configuration/status"},
171    { LLDP_PRIVATE_8023_SUBTYPE_MDIPOWER, "Power via MDI"},
172    { LLDP_PRIVATE_8023_SUBTYPE_LINKAGGR, "Link aggregation"},
173    { LLDP_PRIVATE_8023_SUBTYPE_MTU, "Max frame size"},
174    { 0, NULL}
175};
176
177#define LLDP_PRIVATE_TIA_SUBTYPE_CAPABILITIES                   1
178#define LLDP_PRIVATE_TIA_SUBTYPE_NETWORK_POLICY                 2
179#define LLDP_PRIVATE_TIA_SUBTYPE_LOCAL_ID                       3
180#define LLDP_PRIVATE_TIA_SUBTYPE_EXTENDED_POWER_MDI             4
181#define LLDP_PRIVATE_TIA_SUBTYPE_INVENTORY_HARDWARE_REV         5
182#define LLDP_PRIVATE_TIA_SUBTYPE_INVENTORY_FIRMWARE_REV         6
183#define LLDP_PRIVATE_TIA_SUBTYPE_INVENTORY_SOFTWARE_REV         7
184#define LLDP_PRIVATE_TIA_SUBTYPE_INVENTORY_SERIAL_NUMBER        8
185#define LLDP_PRIVATE_TIA_SUBTYPE_INVENTORY_MANUFACTURER_NAME    9
186#define LLDP_PRIVATE_TIA_SUBTYPE_INVENTORY_MODEL_NAME           10
187#define LLDP_PRIVATE_TIA_SUBTYPE_INVENTORY_ASSET_ID             11
188
189static const struct tok lldp_tia_subtype_values[] = {
190    { LLDP_PRIVATE_TIA_SUBTYPE_CAPABILITIES, "LLDP-MED Capabilities" },
191    { LLDP_PRIVATE_TIA_SUBTYPE_NETWORK_POLICY, "Network policy" },
192    { LLDP_PRIVATE_TIA_SUBTYPE_LOCAL_ID, "Location identification" },
193    { LLDP_PRIVATE_TIA_SUBTYPE_EXTENDED_POWER_MDI, "Extended power-via-MDI" },
194    { LLDP_PRIVATE_TIA_SUBTYPE_INVENTORY_HARDWARE_REV, "Inventory - hardware revision" },
195    { LLDP_PRIVATE_TIA_SUBTYPE_INVENTORY_FIRMWARE_REV, "Inventory - firmware revision" },
196    { LLDP_PRIVATE_TIA_SUBTYPE_INVENTORY_SOFTWARE_REV, "Inventory - software revision" },
197    { LLDP_PRIVATE_TIA_SUBTYPE_INVENTORY_SERIAL_NUMBER, "Inventory - serial number" },
198    { LLDP_PRIVATE_TIA_SUBTYPE_INVENTORY_MANUFACTURER_NAME, "Inventory - manufacturer name" },
199    { LLDP_PRIVATE_TIA_SUBTYPE_INVENTORY_MODEL_NAME, "Inventory - model name" },
200    { LLDP_PRIVATE_TIA_SUBTYPE_INVENTORY_ASSET_ID, "Inventory - asset ID" },
201    { 0, NULL}
202};
203
204#define LLDP_PRIVATE_TIA_LOCATION_ALTITUDE_METERS       1
205#define LLDP_PRIVATE_TIA_LOCATION_ALTITUDE_FLOORS       2
206
207static const struct tok lldp_tia_location_altitude_type_values[] = {
208    { LLDP_PRIVATE_TIA_LOCATION_ALTITUDE_METERS, "meters"},
209    { LLDP_PRIVATE_TIA_LOCATION_ALTITUDE_FLOORS, "floors"},
210    { 0, NULL}
211};
212
213/* ANSI/TIA-1057 - Annex B */
214#define LLDP_PRIVATE_TIA_LOCATION_LCI_CATYPE_A1		1
215#define LLDP_PRIVATE_TIA_LOCATION_LCI_CATYPE_A2		2
216#define LLDP_PRIVATE_TIA_LOCATION_LCI_CATYPE_A3		3
217#define LLDP_PRIVATE_TIA_LOCATION_LCI_CATYPE_A4		4
218#define LLDP_PRIVATE_TIA_LOCATION_LCI_CATYPE_A5		5
219#define LLDP_PRIVATE_TIA_LOCATION_LCI_CATYPE_A6		6
220
221static const struct tok lldp_tia_location_lci_catype_values[] = {
222    { LLDP_PRIVATE_TIA_LOCATION_LCI_CATYPE_A1, "national subdivisions (state,canton,region,province,prefecture)"},
223    { LLDP_PRIVATE_TIA_LOCATION_LCI_CATYPE_A2, "county, parish, gun, district"},
224    { LLDP_PRIVATE_TIA_LOCATION_LCI_CATYPE_A3, "city, township, shi"},
225    { LLDP_PRIVATE_TIA_LOCATION_LCI_CATYPE_A4, "city division, borough, city district, ward chou"},
226    { LLDP_PRIVATE_TIA_LOCATION_LCI_CATYPE_A5, "neighborhood, block"},
227    { LLDP_PRIVATE_TIA_LOCATION_LCI_CATYPE_A6, "street"},
228    { 0, NULL}
229};
230
231static const struct tok lldp_tia_location_lci_what_values[] = {
232    { 0, "location of DHCP server"},
233    { 1, "location of the network element believed to be closest to the client"},
234    { 2, "location of the client"},
235    { 0, NULL}
236};
237
238/*
239 * From RFC 3636 - dot3MauType
240 */
241#define		LLDP_MAU_TYPE_UNKNOWN		0
242#define		LLDP_MAU_TYPE_AUI		1
243#define		LLDP_MAU_TYPE_10BASE_5		2
244#define		LLDP_MAU_TYPE_FOIRL		3
245#define		LLDP_MAU_TYPE_10BASE_2		4
246#define		LLDP_MAU_TYPE_10BASE_T		5
247#define		LLDP_MAU_TYPE_10BASE_FP		6
248#define		LLDP_MAU_TYPE_10BASE_FB		7
249#define		LLDP_MAU_TYPE_10BASE_FL		8
250#define		LLDP_MAU_TYPE_10BROAD36		9
251#define		LLDP_MAU_TYPE_10BASE_T_HD	10
252#define		LLDP_MAU_TYPE_10BASE_T_FD	11
253#define		LLDP_MAU_TYPE_10BASE_FL_HD	12
254#define		LLDP_MAU_TYPE_10BASE_FL_FD	13
255#define		LLDP_MAU_TYPE_100BASE_T4	14
256#define		LLDP_MAU_TYPE_100BASE_TX_HD	15
257#define		LLDP_MAU_TYPE_100BASE_TX_FD	16
258#define		LLDP_MAU_TYPE_100BASE_FX_HD	17
259#define		LLDP_MAU_TYPE_100BASE_FX_FD	18
260#define		LLDP_MAU_TYPE_100BASE_T2_HD	19
261#define		LLDP_MAU_TYPE_100BASE_T2_FD	20
262#define		LLDP_MAU_TYPE_1000BASE_X_HD	21
263#define		LLDP_MAU_TYPE_1000BASE_X_FD	22
264#define		LLDP_MAU_TYPE_1000BASE_LX_HD	23
265#define		LLDP_MAU_TYPE_1000BASE_LX_FD	24
266#define		LLDP_MAU_TYPE_1000BASE_SX_HD	25
267#define		LLDP_MAU_TYPE_1000BASE_SX_FD	26
268#define		LLDP_MAU_TYPE_1000BASE_CX_HD	27
269#define		LLDP_MAU_TYPE_1000BASE_CX_FD	28
270#define		LLDP_MAU_TYPE_1000BASE_T_HD	29
271#define		LLDP_MAU_TYPE_1000BASE_T_FD	30
272#define		LLDP_MAU_TYPE_10GBASE_X		31
273#define		LLDP_MAU_TYPE_10GBASE_LX4	32
274#define		LLDP_MAU_TYPE_10GBASE_R		33
275#define		LLDP_MAU_TYPE_10GBASE_ER	34
276#define		LLDP_MAU_TYPE_10GBASE_LR	35
277#define		LLDP_MAU_TYPE_10GBASE_SR	36
278#define		LLDP_MAU_TYPE_10GBASE_W		37
279#define		LLDP_MAU_TYPE_10GBASE_EW	38
280#define		LLDP_MAU_TYPE_10GBASE_LW	39
281#define		LLDP_MAU_TYPE_10GBASE_SW	40
282
283static const struct tok lldp_mau_types_values[] = {
284    { LLDP_MAU_TYPE_UNKNOWN,            "Unknown"},
285    { LLDP_MAU_TYPE_AUI,                "AUI"},
286    { LLDP_MAU_TYPE_10BASE_5,           "10BASE_5"},
287    { LLDP_MAU_TYPE_FOIRL,              "FOIRL"},
288    { LLDP_MAU_TYPE_10BASE_2,           "10BASE2"},
289    { LLDP_MAU_TYPE_10BASE_T,           "10BASET duplex mode unknown"},
290    { LLDP_MAU_TYPE_10BASE_FP,          "10BASEFP"},
291    { LLDP_MAU_TYPE_10BASE_FB,          "10BASEFB"},
292    { LLDP_MAU_TYPE_10BASE_FL,          "10BASEFL duplex mode unknown"},
293    { LLDP_MAU_TYPE_10BROAD36,          "10BROAD36"},
294    { LLDP_MAU_TYPE_10BASE_T_HD,        "10BASET hdx"},
295    { LLDP_MAU_TYPE_10BASE_T_FD,        "10BASET fdx"},
296    { LLDP_MAU_TYPE_10BASE_FL_HD,       "10BASEFL hdx"},
297    { LLDP_MAU_TYPE_10BASE_FL_FD,       "10BASEFL fdx"},
298    { LLDP_MAU_TYPE_100BASE_T4,         "100BASET4"},
299    { LLDP_MAU_TYPE_100BASE_TX_HD,      "100BASETX hdx"},
300    { LLDP_MAU_TYPE_100BASE_TX_FD,      "100BASETX fdx"},
301    { LLDP_MAU_TYPE_100BASE_FX_HD,      "100BASEFX hdx"},
302    { LLDP_MAU_TYPE_100BASE_FX_FD,      "100BASEFX fdx"},
303    { LLDP_MAU_TYPE_100BASE_T2_HD,      "100BASET2 hdx"},
304    { LLDP_MAU_TYPE_100BASE_T2_FD,      "100BASET2 fdx"},
305    { LLDP_MAU_TYPE_1000BASE_X_HD,      "1000BASEX hdx"},
306    { LLDP_MAU_TYPE_1000BASE_X_FD,      "1000BASEX fdx"},
307    { LLDP_MAU_TYPE_1000BASE_LX_HD,     "1000BASELX hdx"},
308    { LLDP_MAU_TYPE_1000BASE_LX_FD,     "1000BASELX fdx"},
309    { LLDP_MAU_TYPE_1000BASE_SX_HD,     "1000BASESX hdx"},
310    { LLDP_MAU_TYPE_1000BASE_SX_FD,     "1000BASESX fdx"},
311    { LLDP_MAU_TYPE_1000BASE_CX_HD,     "1000BASECX hdx"},
312    { LLDP_MAU_TYPE_1000BASE_CX_FD,     "1000BASECX fdx"},
313    { LLDP_MAU_TYPE_1000BASE_T_HD,      "1000BASET hdx"},
314    { LLDP_MAU_TYPE_1000BASE_T_FD,      "1000BASET fdx"},
315    { LLDP_MAU_TYPE_10GBASE_X,          "10GBASEX"},
316    { LLDP_MAU_TYPE_10GBASE_LX4,        "10GBASELX4"},
317    { LLDP_MAU_TYPE_10GBASE_R,          "10GBASER"},
318    { LLDP_MAU_TYPE_10GBASE_ER,         "10GBASEER"},
319    { LLDP_MAU_TYPE_10GBASE_LR,         "10GBASELR"},
320    { LLDP_MAU_TYPE_10GBASE_SR,         "10GBASESR"},
321    { LLDP_MAU_TYPE_10GBASE_W,          "10GBASEW"},
322    { LLDP_MAU_TYPE_10GBASE_EW,         "10GBASEEW"},
323    { LLDP_MAU_TYPE_10GBASE_LW,         "10GBASELW"},
324    { LLDP_MAU_TYPE_10GBASE_SW,         "10GBASESW"},
325    { 0, NULL}
326};
327
328#define LLDP_8023_AUTONEGOTIATION_SUPPORT       (1 <<  0)
329#define LLDP_8023_AUTONEGOTIATION_STATUS        (1 <<  1)
330
331static const struct tok lldp_8023_autonegotiation_values[] = {
332    { LLDP_8023_AUTONEGOTIATION_SUPPORT, "supported"},
333    { LLDP_8023_AUTONEGOTIATION_STATUS, "enabled"},
334    { 0, NULL}
335};
336
337#define LLDP_TIA_CAPABILITY_MED                         (1 <<  0)
338#define LLDP_TIA_CAPABILITY_NETWORK_POLICY              (1 <<  1)
339#define LLDP_TIA_CAPABILITY_LOCATION_IDENTIFICATION     (1 <<  2)
340#define LLDP_TIA_CAPABILITY_EXTENDED_POWER_MDI_PSE      (1 <<  3)
341#define LLDP_TIA_CAPABILITY_EXTENDED_POWER_MDI_PD       (1 <<  4)
342#define LLDP_TIA_CAPABILITY_INVENTORY                   (1 <<  5)
343
344static const struct tok lldp_tia_capabilities_values[] = {
345    { LLDP_TIA_CAPABILITY_MED, "LLDP-MED capabilities"},
346    { LLDP_TIA_CAPABILITY_NETWORK_POLICY, "network policy"},
347    { LLDP_TIA_CAPABILITY_LOCATION_IDENTIFICATION, "location identification"},
348    { LLDP_TIA_CAPABILITY_EXTENDED_POWER_MDI_PSE, "extended power via MDI-PSE"},
349    { LLDP_TIA_CAPABILITY_EXTENDED_POWER_MDI_PD, "extended power via MDI-PD"},
350    { LLDP_TIA_CAPABILITY_INVENTORY, "Inventory"},
351    { 0, NULL}
352};
353
354#define LLDP_TIA_DEVICE_TYPE_ENDPOINT_CLASS_1           1
355#define LLDP_TIA_DEVICE_TYPE_ENDPOINT_CLASS_2           2
356#define LLDP_TIA_DEVICE_TYPE_ENDPOINT_CLASS_3           3
357#define LLDP_TIA_DEVICE_TYPE_NETWORK_CONNECTIVITY       4
358
359static const struct tok lldp_tia_device_type_values[] = {
360    { LLDP_TIA_DEVICE_TYPE_ENDPOINT_CLASS_1, "endpoint class 1"},
361    { LLDP_TIA_DEVICE_TYPE_ENDPOINT_CLASS_2, "endpoint class 2"},
362    { LLDP_TIA_DEVICE_TYPE_ENDPOINT_CLASS_3, "endpoint class 3"},
363    { LLDP_TIA_DEVICE_TYPE_NETWORK_CONNECTIVITY, "network connectivity"},
364    { 0, NULL}
365};
366
367#define LLDP_TIA_APPLICATION_TYPE_VOICE                 1
368#define LLDP_TIA_APPLICATION_TYPE_VOICE_SIGNALING       2
369#define LLDP_TIA_APPLICATION_TYPE_GUEST_VOICE           3
370#define LLDP_TIA_APPLICATION_TYPE_GUEST_VOICE_SIGNALING 4
371#define LLDP_TIA_APPLICATION_TYPE_SOFTPHONE_VOICE       5
372#define LLDP_TIA_APPLICATION_TYPE_VIDEO_CONFERENCING    6
373#define LLDP_TIA_APPLICATION_TYPE_STREAMING_VIDEO       7
374#define LLDP_TIA_APPLICATION_TYPE_VIDEO_SIGNALING       8
375
376static const struct tok lldp_tia_application_type_values[] = {
377    { LLDP_TIA_APPLICATION_TYPE_VOICE, "voice"},
378    { LLDP_TIA_APPLICATION_TYPE_VOICE_SIGNALING, "voice signaling"},
379    { LLDP_TIA_APPLICATION_TYPE_GUEST_VOICE, "guest voice"},
380    { LLDP_TIA_APPLICATION_TYPE_GUEST_VOICE_SIGNALING, "guest voice signaling"},
381    { LLDP_TIA_APPLICATION_TYPE_SOFTPHONE_VOICE, "softphone voice"},
382    { LLDP_TIA_APPLICATION_TYPE_VIDEO_CONFERENCING, "video conferencing"},
383    { LLDP_TIA_APPLICATION_TYPE_STREAMING_VIDEO, "streaming video"},
384    { LLDP_TIA_APPLICATION_TYPE_VIDEO_SIGNALING, "video signaling"},
385    { 0, NULL}
386};
387
388#define LLDP_TIA_NETWORK_POLICY_X_BIT           (1 << 5)
389#define LLDP_TIA_NETWORK_POLICY_T_BIT           (1 << 6)
390#define LLDP_TIA_NETWORK_POLICY_U_BIT           (1 << 7)
391
392static const struct tok lldp_tia_network_policy_bits_values[] = {
393    { LLDP_TIA_NETWORK_POLICY_U_BIT, "Unknown"},
394    { LLDP_TIA_NETWORK_POLICY_T_BIT, "Tagged"},
395    { LLDP_TIA_NETWORK_POLICY_X_BIT, "reserved"},
396    { 0, NULL}
397};
398
399#define LLDP_EXTRACT_NETWORK_POLICY_VLAN(x)           (((x)&0x1ffe)>>1)
400#define LLDP_EXTRACT_NETWORK_POLICY_L2_PRIORITY(x)    (((x)&0x01ff)>>6)
401#define LLDP_EXTRACT_NETWORK_POLICY_DSCP(x)           ((x)&0x003f)
402
403#define LLDP_TIA_LOCATION_DATA_FORMAT_COORDINATE_BASED  1
404#define LLDP_TIA_LOCATION_DATA_FORMAT_CIVIC_ADDRESS     2
405#define LLDP_TIA_LOCATION_DATA_FORMAT_ECS_ELIN          3
406
407static const struct tok lldp_tia_location_data_format_values[] = {
408    { LLDP_TIA_LOCATION_DATA_FORMAT_COORDINATE_BASED, "coordinate-based LCI"},
409    { LLDP_TIA_LOCATION_DATA_FORMAT_CIVIC_ADDRESS, "civic address LCI"},
410    { LLDP_TIA_LOCATION_DATA_FORMAT_ECS_ELIN, "ECS ELIN"},
411    { 0, NULL}
412};
413
414#define LLDP_TIA_LOCATION_DATUM_WGS_84          1
415#define LLDP_TIA_LOCATION_DATUM_NAD_83_NAVD_88  2
416#define LLDP_TIA_LOCATION_DATUM_NAD_83_MLLW     3
417
418static const struct tok lldp_tia_location_datum_type_values[] = {
419    { LLDP_TIA_LOCATION_DATUM_WGS_84, "World Geodesic System 1984"},
420    { LLDP_TIA_LOCATION_DATUM_NAD_83_NAVD_88, "North American Datum 1983 (NAVD88)"},
421    { LLDP_TIA_LOCATION_DATUM_NAD_83_MLLW, "North American Datum 1983 (MLLW)"},
422    { 0, NULL}
423};
424
425#define LLDP_TIA_POWER_SOURCE_PSE               1
426#define LLDP_TIA_POWER_SOURCE_LOCAL             2
427#define LLDP_TIA_POWER_SOURCE_PSE_AND_LOCAL     3
428
429static const struct tok lldp_tia_power_source_values[] = {
430    { LLDP_TIA_POWER_SOURCE_PSE, "PSE - primary power source"},
431    { LLDP_TIA_POWER_SOURCE_LOCAL, "local - backup power source"},
432    { LLDP_TIA_POWER_SOURCE_PSE_AND_LOCAL, "PSE+local - reserved"},
433    { 0, NULL}
434};
435
436#define LLDP_TIA_POWER_PRIORITY_CRITICAL        1
437#define LLDP_TIA_POWER_PRIORITY_HIGH            2
438#define LLDP_TIA_POWER_PRIORITY_LOW             3
439
440static const struct tok lldp_tia_power_priority_values[] = {
441    { LLDP_TIA_POWER_PRIORITY_CRITICAL, "critical"},
442    { LLDP_TIA_POWER_PRIORITY_HIGH, "high"},
443    { LLDP_TIA_POWER_PRIORITY_LOW, "low"},
444    { 0, NULL}
445};
446
447#define LLDP_TIA_POWER_VAL_MAX               1024
448
449static const struct tok lldp_tia_inventory_values[] = {
450    { LLDP_PRIVATE_TIA_SUBTYPE_INVENTORY_HARDWARE_REV, "Hardware revision" },
451    { LLDP_PRIVATE_TIA_SUBTYPE_INVENTORY_FIRMWARE_REV, "Firmware revision" },
452    { LLDP_PRIVATE_TIA_SUBTYPE_INVENTORY_SOFTWARE_REV, "Software revision" },
453    { LLDP_PRIVATE_TIA_SUBTYPE_INVENTORY_SERIAL_NUMBER, "Serial number" },
454    { LLDP_PRIVATE_TIA_SUBTYPE_INVENTORY_MANUFACTURER_NAME, "Manufacturer name" },
455    { LLDP_PRIVATE_TIA_SUBTYPE_INVENTORY_MODEL_NAME, "Model name" },
456    { LLDP_PRIVATE_TIA_SUBTYPE_INVENTORY_ASSET_ID, "Asset ID" },
457    { 0, NULL}
458};
459
460/*
461 * From RFC 3636 - ifMauAutoNegCapAdvertisedBits
462 */
463#define	 LLDP_MAU_PMD_OTHER			(1 <<  15)
464#define	 LLDP_MAU_PMD_10BASE_T			(1 <<  14)
465#define	 LLDP_MAU_PMD_10BASE_T_FD		(1 <<  13)
466#define	 LLDP_MAU_PMD_100BASE_T4		(1 <<  12)
467#define	 LLDP_MAU_PMD_100BASE_TX		(1 <<  11)
468#define	 LLDP_MAU_PMD_100BASE_TX_FD		(1 <<  10)
469#define	 LLDP_MAU_PMD_100BASE_T2		(1 <<  9)
470#define	 LLDP_MAU_PMD_100BASE_T2_FD		(1 <<  8)
471#define	 LLDP_MAU_PMD_FDXPAUSE			(1 <<  7)
472#define	 LLDP_MAU_PMD_FDXAPAUSE			(1 <<  6)
473#define	 LLDP_MAU_PMD_FDXSPAUSE			(1 <<  5)
474#define	 LLDP_MAU_PMD_FDXBPAUSE			(1 <<  4)
475#define	 LLDP_MAU_PMD_1000BASE_X		(1 <<  3)
476#define	 LLDP_MAU_PMD_1000BASE_X_FD		(1 <<  2)
477#define	 LLDP_MAU_PMD_1000BASE_T		(1 <<  1)
478#define	 LLDP_MAU_PMD_1000BASE_T_FD		(1 <<  0)
479
480static const struct tok lldp_pmd_capability_values[] = {
481    { LLDP_MAU_PMD_10BASE_T,		"10BASE-T hdx"},
482    { LLDP_MAU_PMD_10BASE_T_FD,	        "10BASE-T fdx"},
483    { LLDP_MAU_PMD_100BASE_T4,		"100BASE-T4"},
484    { LLDP_MAU_PMD_100BASE_TX,		"100BASE-TX hdx"},
485    { LLDP_MAU_PMD_100BASE_TX_FD,	"100BASE-TX fdx"},
486    { LLDP_MAU_PMD_100BASE_T2,		"100BASE-T2 hdx"},
487    { LLDP_MAU_PMD_100BASE_T2_FD,	"100BASE-T2 fdx"},
488    { LLDP_MAU_PMD_FDXPAUSE,		"Pause for fdx links"},
489    { LLDP_MAU_PMD_FDXAPAUSE,		"Asym PAUSE for fdx"},
490    { LLDP_MAU_PMD_FDXSPAUSE,		"Sym PAUSE for fdx"},
491    { LLDP_MAU_PMD_FDXBPAUSE,		"Asym and Sym PAUSE for fdx"},
492    { LLDP_MAU_PMD_1000BASE_X,		"1000BASE-{X LX SX CX} hdx"},
493    { LLDP_MAU_PMD_1000BASE_X_FD,	"1000BASE-{X LX SX CX} fdx"},
494    { LLDP_MAU_PMD_1000BASE_T,		"1000BASE-T hdx"},
495    { LLDP_MAU_PMD_1000BASE_T_FD,	"1000BASE-T fdx"},
496    { 0, NULL}
497};
498
499#define	LLDP_MDI_PORT_CLASS			(1 <<  0)
500#define	LLDP_MDI_POWER_SUPPORT			(1 <<  1)
501#define LLDP_MDI_POWER_STATE			(1 <<  2)
502#define LLDP_MDI_PAIR_CONTROL_ABILITY		(1 <<  3)
503
504static const struct tok lldp_mdi_values[] = {
505    { LLDP_MDI_PORT_CLASS, 		"PSE"},
506    { LLDP_MDI_POWER_SUPPORT, 		"supported"},
507    { LLDP_MDI_POWER_STATE, 		"enabled"},
508    { LLDP_MDI_PAIR_CONTROL_ABILITY, 	"can be controlled"},
509    { 0, NULL}
510};
511
512#define LLDP_MDI_PSE_PORT_POWER_PAIRS_SIGNAL	1
513#define LLDP_MDI_PSE_PORT_POWER_PAIRS_SPARE	2
514
515static const struct tok lldp_mdi_power_pairs_values[] = {
516    { LLDP_MDI_PSE_PORT_POWER_PAIRS_SIGNAL,	"signal"},
517    { LLDP_MDI_PSE_PORT_POWER_PAIRS_SPARE,	"spare"},
518    { 0, NULL}
519};
520
521#define LLDP_MDI_POWER_CLASS0		1
522#define LLDP_MDI_POWER_CLASS1		2
523#define LLDP_MDI_POWER_CLASS2		3
524#define LLDP_MDI_POWER_CLASS3		4
525#define LLDP_MDI_POWER_CLASS4		5
526
527static const struct tok lldp_mdi_power_class_values[] = {
528    { LLDP_MDI_POWER_CLASS0,     "class0"},
529    { LLDP_MDI_POWER_CLASS1,     "class1"},
530    { LLDP_MDI_POWER_CLASS2,     "class2"},
531    { LLDP_MDI_POWER_CLASS3,     "class3"},
532    { LLDP_MDI_POWER_CLASS4,     "class4"},
533    { 0, NULL}
534};
535
536#define LLDP_AGGREGATION_CAPABILTIY     (1 <<  0)
537#define LLDP_AGGREGATION_STATUS         (1 <<  1)
538
539static const struct tok lldp_aggregation_values[] = {
540    { LLDP_AGGREGATION_CAPABILTIY, "supported"},
541    { LLDP_AGGREGATION_STATUS, "enabled"},
542    { 0, NULL}
543};
544
545/*
546 * DCBX protocol subtypes.
547 */
548#define LLDP_DCBX_SUBTYPE_1                1
549#define LLDP_DCBX_SUBTYPE_2                2
550
551static const struct tok lldp_dcbx_subtype_values[] = {
552    { LLDP_DCBX_SUBTYPE_1, "DCB Capability Exchange Protocol Rev 1" },
553    { LLDP_DCBX_SUBTYPE_2, "DCB Capability Exchange Protocol Rev 1.01" },
554    { 0, NULL}
555};
556
557#define LLDP_DCBX_CONTROL_TLV                1
558#define LLDP_DCBX_PRIORITY_GROUPS_TLV        2
559#define LLDP_DCBX_PRIORITY_FLOW_CONTROL_TLV  3
560#define LLDP_DCBX_APPLICATION_TLV            4
561
562/*
563 * Interface numbering subtypes.
564 */
565#define LLDP_INTF_NUMB_IFX_SUBTYPE         2
566#define LLDP_INTF_NUMB_SYSPORT_SUBTYPE     3
567
568static const struct tok lldp_intf_numb_subtype_values[] = {
569    { LLDP_INTF_NUMB_IFX_SUBTYPE, "Interface Index" },
570    { LLDP_INTF_NUMB_SYSPORT_SUBTYPE, "System Port Number" },
571    { 0, NULL}
572};
573
574#define LLDP_INTF_NUM_LEN                  5
575
576/*
577 * Print IEEE 802.1 private extensions. (802.1AB annex E)
578 */
579static int
580lldp_private_8021_print(const u_char *tptr, u_int tlv_len)
581{
582    int subtype, hexdump = FALSE;
583    u_int sublen;
584
585    if (tlv_len < 4) {
586        return hexdump;
587    }
588    subtype = *(tptr+3);
589
590    printf("\n\t  %s Subtype (%u)",
591           tok2str(lldp_8021_subtype_values, "unknown", subtype),
592           subtype);
593
594    switch (subtype) {
595    case LLDP_PRIVATE_8021_SUBTYPE_PORT_VLAN_ID:
596        if (tlv_len < 6) {
597            return hexdump;
598        }
599        printf("\n\t    port vlan id (PVID): %u",
600               EXTRACT_16BITS(tptr+4));
601        break;
602    case LLDP_PRIVATE_8021_SUBTYPE_PROTOCOL_VLAN_ID:
603        if (tlv_len < 7) {
604            return hexdump;
605        }
606        printf("\n\t    port and protocol vlan id (PPVID): %u, flags [%s] (0x%02x)",
607               EXTRACT_16BITS(tptr+5),
608	       bittok2str(lldp_8021_port_protocol_id_values, "none", *(tptr+4)),
609	       *(tptr+4));
610        break;
611    case LLDP_PRIVATE_8021_SUBTYPE_VLAN_NAME:
612        if (tlv_len < 6) {
613            return hexdump;
614        }
615        printf("\n\t    vlan id (VID): %u",
616               EXTRACT_16BITS(tptr+4));
617        if (tlv_len < 7) {
618            return hexdump;
619        }
620        sublen = *(tptr+6);
621        if (tlv_len < 7+sublen) {
622            return hexdump;
623        }
624        printf("\n\t    vlan name: ");
625        safeputs((const char *)tptr+7, sublen);
626        break;
627    case LLDP_PRIVATE_8021_SUBTYPE_PROTOCOL_IDENTITY:
628        if (tlv_len < 5) {
629            return hexdump;
630        }
631        sublen = *(tptr+4);
632        if (tlv_len < 5+sublen) {
633            return hexdump;
634        }
635        printf("\n\t    protocol identity: ");
636        safeputs((const char *)tptr+5, sublen);
637        break;
638
639    default:
640        hexdump = TRUE;
641        break;
642    }
643
644    return hexdump;
645}
646
647/*
648 * Print IEEE 802.3 private extensions. (802.3bc)
649 */
650static int
651lldp_private_8023_print(const u_char *tptr, u_int tlv_len)
652{
653    int subtype, hexdump = FALSE;
654
655    if (tlv_len < 4) {
656        return hexdump;
657    }
658    subtype = *(tptr+3);
659
660    printf("\n\t  %s Subtype (%u)",
661           tok2str(lldp_8023_subtype_values, "unknown", subtype),
662           subtype);
663
664    switch (subtype) {
665    case LLDP_PRIVATE_8023_SUBTYPE_MACPHY:
666        if (tlv_len < 9) {
667            return hexdump;
668        }
669        printf("\n\t    autonegotiation [%s] (0x%02x)",
670               bittok2str(lldp_8023_autonegotiation_values, "none", *(tptr+4)),
671               *(tptr+4));
672        printf("\n\t    PMD autoneg capability [%s] (0x%04x)",
673               bittok2str(lldp_pmd_capability_values,"unknown", EXTRACT_16BITS(tptr+5)),
674               EXTRACT_16BITS(tptr+5));
675        printf("\n\t    MAU type %s (0x%04x)",
676               tok2str(lldp_mau_types_values, "unknown", EXTRACT_16BITS(tptr+7)),
677               EXTRACT_16BITS(tptr+7));
678        break;
679
680    case LLDP_PRIVATE_8023_SUBTYPE_MDIPOWER:
681        if (tlv_len < 7) {
682            return hexdump;
683        }
684        printf("\n\t    MDI power support [%s], power pair %s, power class %s",
685               bittok2str(lldp_mdi_values, "none", *(tptr+4)),
686               tok2str(lldp_mdi_power_pairs_values, "unknown", *(tptr+5)),
687               tok2str(lldp_mdi_power_class_values, "unknown", *(tptr+6)));
688        break;
689
690    case LLDP_PRIVATE_8023_SUBTYPE_LINKAGGR:
691        if (tlv_len < 9) {
692            return hexdump;
693        }
694        printf("\n\t    aggregation status [%s], aggregation port ID %u",
695               bittok2str(lldp_aggregation_values, "none", *(tptr+4)),
696               EXTRACT_32BITS(tptr+5));
697        break;
698
699    case LLDP_PRIVATE_8023_SUBTYPE_MTU:
700        printf("\n\t    MTU size %u", EXTRACT_16BITS(tptr+4));
701        break;
702
703    default:
704        hexdump = TRUE;
705        break;
706    }
707
708    return hexdump;
709}
710
711/*
712 * Extract 34bits of latitude/longitude coordinates.
713 */
714static u_int64_t
715lldp_extract_latlon(const u_char *tptr)
716{
717    u_int64_t latlon;
718
719    latlon = *tptr & 0x3;
720    latlon = (latlon << 32) | EXTRACT_32BITS(tptr+1);
721
722    return latlon;
723}
724
725/*
726 * Print private TIA extensions.
727 */
728static int
729lldp_private_tia_print(const u_char *tptr, u_int tlv_len)
730{
731    int subtype, hexdump = FALSE;
732    u_int8_t location_format;
733    u_int16_t power_val;
734    u_int lci_len;
735    u_int8_t ca_type, ca_len;
736
737    if (tlv_len < 4) {
738        return hexdump;
739    }
740    subtype = *(tptr+3);
741
742    printf("\n\t  %s Subtype (%u)",
743           tok2str(lldp_tia_subtype_values, "unknown", subtype),
744           subtype);
745
746    switch (subtype) {
747    case LLDP_PRIVATE_TIA_SUBTYPE_CAPABILITIES:
748        if (tlv_len < 7) {
749            return hexdump;
750        }
751        printf("\n\t    Media capabilities [%s] (0x%04x)",
752               bittok2str(lldp_tia_capabilities_values, "none",
753                          EXTRACT_16BITS(tptr+4)), EXTRACT_16BITS(tptr+4));
754        printf("\n\t    Device type [%s] (0x%02x)",
755               tok2str(lldp_tia_device_type_values, "unknown", *(tptr+6)),
756               *(tptr+6));
757        break;
758
759    case LLDP_PRIVATE_TIA_SUBTYPE_NETWORK_POLICY:
760        if (tlv_len < 8) {
761            return hexdump;
762        }
763        printf("\n\t    Application type [%s] (0x%02x)",
764               tok2str(lldp_tia_application_type_values, "none", *(tptr+4)),
765               *(tptr+4));
766        printf(", Flags [%s]", bittok2str(
767                   lldp_tia_network_policy_bits_values, "none", *(tptr+5)));
768        printf("\n\t    Vlan id %u",
769               LLDP_EXTRACT_NETWORK_POLICY_VLAN(EXTRACT_16BITS(tptr+5)));
770        printf(", L2 priority %u",
771               LLDP_EXTRACT_NETWORK_POLICY_L2_PRIORITY(EXTRACT_16BITS(tptr+6)));
772        printf(", DSCP value %u",
773               LLDP_EXTRACT_NETWORK_POLICY_DSCP(EXTRACT_16BITS(tptr+6)));
774        break;
775
776    case LLDP_PRIVATE_TIA_SUBTYPE_LOCAL_ID:
777        if (tlv_len < 5) {
778            return hexdump;
779        }
780        location_format = *(tptr+4);
781        printf("\n\t    Location data format %s (0x%02x)",
782               tok2str(lldp_tia_location_data_format_values, "unknown", location_format),
783               location_format);
784
785        switch (location_format) {
786        case LLDP_TIA_LOCATION_DATA_FORMAT_COORDINATE_BASED:
787            if (tlv_len < 21) {
788                return hexdump;
789            }
790            printf("\n\t    Latitude resolution %u, latitude value %" PRIu64,
791                   (*(tptr+5)>>2), lldp_extract_latlon(tptr+5));
792            printf("\n\t    Longitude resolution %u, longitude value %" PRIu64,
793                   (*(tptr+10)>>2), lldp_extract_latlon(tptr+10));
794            printf("\n\t    Altitude type %s (%u)",
795                   tok2str(lldp_tia_location_altitude_type_values, "unknown",(*(tptr+15)>>4)),
796                   (*(tptr+15)>>4));
797            printf("\n\t    Altitude resolution %u, altitude value 0x%x",
798                   (EXTRACT_16BITS(tptr+15)>>6)&0x3f,
799                   ((EXTRACT_32BITS(tptr+16)&0x3fffffff)));
800            printf("\n\t    Datum %s (0x%02x)",
801                   tok2str(lldp_tia_location_datum_type_values, "unknown", *(tptr+20)),
802                   *(tptr+20));
803            break;
804
805        case LLDP_TIA_LOCATION_DATA_FORMAT_CIVIC_ADDRESS:
806            if (tlv_len < 6) {
807                return hexdump;
808            }
809            lci_len = *(tptr+5);
810            if (lci_len < 3) {
811                return hexdump;
812            }
813            if (tlv_len < 7+lci_len) {
814                return hexdump;
815            }
816            printf("\n\t    LCI length %u, LCI what %s (0x%02x), Country-code ",
817                   lci_len,
818                   tok2str(lldp_tia_location_lci_what_values, "unknown", *(tptr+6)),
819                   *(tptr+6));
820
821            /* Country code */
822            safeputs((const char *)(tptr+7), 2);
823
824            lci_len = lci_len-3;
825            tptr = tptr + 9;
826
827            /* Decode each civic address element */
828            while (lci_len > 0) {
829                if (lci_len < 2) {
830                    return hexdump;
831                }
832		ca_type = *(tptr);
833                ca_len = *(tptr+1);
834
835		tptr += 2;
836                lci_len -= 2;
837
838                printf("\n\t      CA type \'%s\' (%u), length %u: ",
839                       tok2str(lldp_tia_location_lci_catype_values, "unknown", ca_type),
840                       ca_type, ca_len);
841
842		/* basic sanity check */
843		if ( ca_type == 0 || ca_len == 0) {
844                    return hexdump;
845		}
846		if (lci_len < ca_len) {
847		    return hexdump;
848		}
849
850                safeputs((const char *)tptr, ca_len);
851                tptr += ca_len;
852                lci_len -= ca_len;
853            }
854            break;
855
856        case LLDP_TIA_LOCATION_DATA_FORMAT_ECS_ELIN:
857            printf("\n\t    ECS ELIN id ");
858            safeputs((const char *)tptr+5, tlv_len-5);
859            break;
860
861        default:
862            printf("\n\t    Location ID ");
863            print_unknown_data(tptr+5, "\n\t      ", tlv_len-5);
864        }
865        break;
866
867    case LLDP_PRIVATE_TIA_SUBTYPE_EXTENDED_POWER_MDI:
868        if (tlv_len < 7) {
869            return hexdump;
870        }
871        printf("\n\t    Power type [%s]",
872               (*(tptr+4)&0xC0>>6) ? "PD device" : "PSE device");
873        printf(", Power source [%s]",
874               tok2str(lldp_tia_power_source_values, "none", (*(tptr+4)&0x30)>>4));
875        printf("\n\t    Power priority [%s] (0x%02x)",
876               tok2str(lldp_tia_power_priority_values, "none", *(tptr+4)&0x0f),
877               *(tptr+4)&0x0f);
878        power_val = EXTRACT_16BITS(tptr+5);
879        if (power_val < LLDP_TIA_POWER_VAL_MAX) {
880            printf(", Power %.1f Watts", ((float)power_val)/10);
881        } else {
882            printf(", Power %u (Reserved)", power_val);
883        }
884        break;
885
886    case LLDP_PRIVATE_TIA_SUBTYPE_INVENTORY_HARDWARE_REV:
887    case LLDP_PRIVATE_TIA_SUBTYPE_INVENTORY_FIRMWARE_REV:
888    case LLDP_PRIVATE_TIA_SUBTYPE_INVENTORY_SOFTWARE_REV:
889    case LLDP_PRIVATE_TIA_SUBTYPE_INVENTORY_SERIAL_NUMBER:
890    case LLDP_PRIVATE_TIA_SUBTYPE_INVENTORY_MANUFACTURER_NAME:
891    case LLDP_PRIVATE_TIA_SUBTYPE_INVENTORY_MODEL_NAME:
892    case LLDP_PRIVATE_TIA_SUBTYPE_INVENTORY_ASSET_ID:
893        printf("\n\t  %s ",
894               tok2str(lldp_tia_inventory_values, "unknown", subtype));
895        safeputs((const char *)tptr+4, tlv_len-4);
896        break;
897
898    default:
899        hexdump = TRUE;
900        break;
901    }
902
903    return hexdump;
904}
905
906/*
907 * Print DCBX Protocol fields (V 1.01).
908 */
909static int
910lldp_private_dcbx_print(const u_char *pptr, u_int len)
911{
912    int subtype, hexdump = FALSE;
913    u_int8_t tval;
914    u_int16_t tlv;
915    u_int32_t i, pgval, uval;
916    u_int tlen, tlv_type, tlv_len;
917    const u_char *tptr, *mptr;
918
919    if (len < 4) {
920        return hexdump;
921    }
922    subtype = *(pptr+3);
923
924    printf("\n\t  %s Subtype (%u)",
925           tok2str(lldp_dcbx_subtype_values, "unknown", subtype),
926           subtype);
927
928    /* by passing old version */
929    if (subtype == LLDP_DCBX_SUBTYPE_1)
930	return TRUE;
931
932    tptr = pptr + 4;
933    tlen = len - 4;
934
935    while (tlen >= sizeof(tlv)) {
936
937        TCHECK2(*tptr, sizeof(tlv));
938
939        tlv = EXTRACT_16BITS(tptr);
940
941        tlv_type = LLDP_EXTRACT_TYPE(tlv);
942        tlv_len = LLDP_EXTRACT_LEN(tlv);
943        hexdump = FALSE;
944
945        tlen -= sizeof(tlv);
946        tptr += sizeof(tlv);
947
948        /* loop check */
949        if (!tlv_type || !tlv_len) {
950            break;
951        }
952
953        TCHECK2(*tptr, tlv_len);
954        if (tlen < tlv_len) {
955            goto trunc;
956        }
957
958	/* decode every tlv */
959        switch (tlv_type) {
960        case LLDP_DCBX_CONTROL_TLV:
961            if (tlv_len < 10) {
962                goto trunc;
963            }
964	    printf("\n\t    Control - Protocol Control (type 0x%x, length %d)",
965		LLDP_DCBX_CONTROL_TLV, tlv_len);
966	    printf("\n\t      Oper_Version: %d", *tptr);
967	    printf("\n\t      Max_Version: %d", *(tptr+1));
968	    printf("\n\t      Sequence Number: %d", EXTRACT_32BITS(tptr+2));
969	    printf("\n\t      Acknowledgement Number: %d",
970					EXTRACT_32BITS(tptr+6));
971	    break;
972        case LLDP_DCBX_PRIORITY_GROUPS_TLV:
973            if (tlv_len < 17) {
974                goto trunc;
975            }
976	    printf("\n\t    Feature - Priority Group (type 0x%x, length %d)",
977		LLDP_DCBX_PRIORITY_GROUPS_TLV, tlv_len);
978	    printf("\n\t      Oper_Version: %d", *tptr);
979	    printf("\n\t      Max_Version: %d", *(tptr+1));
980	    printf("\n\t      Info block(0x%02X): ", *(tptr+2));
981	    tval = *(tptr+2);
982	    printf("Enable bit: %d, Willing bit: %d, Error Bit: %d",
983		(tval &  0x80) ? 1 : 0, (tval &  0x40) ? 1 : 0,
984		(tval &  0x20) ? 1 : 0);
985	    printf("\n\t      SubType: %d", *(tptr+3));
986	    printf("\n\t      Priority Allocation");
987
988	    pgval = EXTRACT_32BITS(tptr+4);
989	    for (i = 0; i <= 7; i++) {
990		tval = *(tptr+4+(i/2));
991		printf("\n\t          PgId_%d: %d",
992			i, (pgval >> (28-4*i)) & 0xF);
993	    }
994	    printf("\n\t      Priority Group Allocation");
995	    for (i = 0; i <= 7; i++)
996		printf("\n\t          Pg percentage[%d]: %d", i, *(tptr+8+i));
997	    printf("\n\t      NumTCsSupported: %d", *(tptr+8+8));
998	    break;
999        case LLDP_DCBX_PRIORITY_FLOW_CONTROL_TLV:
1000            if (tlv_len < 6) {
1001                goto trunc;
1002            }
1003	    printf("\n\t    Feature - Priority Flow Control");
1004	    printf(" (type 0x%x, length %d)",
1005		LLDP_DCBX_PRIORITY_FLOW_CONTROL_TLV, tlv_len);
1006	    printf("\n\t      Oper_Version: %d", *tptr);
1007	    printf("\n\t      Max_Version: %d", *(tptr+1));
1008	    printf("\n\t      Info block(0x%02X): ", *(tptr+2));
1009	    tval = *(tptr+2);
1010	    printf("Enable bit: %d, Willing bit: %d, Error Bit: %d",
1011		(tval &  0x80) ? 1 : 0, (tval &  0x40) ? 1 : 0,
1012		(tval &  0x20) ? 1 : 0);
1013	    printf("\n\t      SubType: %d", *(tptr+3));
1014	    tval = *(tptr+4);
1015	    printf("\n\t      PFC Config (0x%02X)", *(tptr+4));
1016	    for (i = 0; i <= 7; i++)
1017		printf("\n\t          Priority Bit %d: %s",
1018		    i, (tval & (1 << i)) ? "Enabled" : "Disabled");
1019	    printf("\n\t      NumTCPFCSupported: %d", *(tptr+5));
1020	    break;
1021        case LLDP_DCBX_APPLICATION_TLV:
1022            if (tlv_len < 4) {
1023                goto trunc;
1024            }
1025	    printf("\n\t    Feature - Application (type 0x%x, length %d)",
1026		LLDP_DCBX_APPLICATION_TLV, tlv_len);
1027	    printf("\n\t      Oper_Version: %d", *tptr);
1028	    printf("\n\t      Max_Version: %d", *(tptr+1));
1029	    printf("\n\t      Info block(0x%02X): ", *(tptr+2));
1030	    tval = *(tptr+2);
1031	    printf("Enable bit: %d, Willing bit: %d, Error Bit: %d",
1032		(tval &  0x80) ? 1 : 0, (tval &  0x40) ? 1 : 0,
1033		(tval &  0x20) ? 1 : 0);
1034	    printf("\n\t      SubType: %d", *(tptr+3));
1035	    tval = tlv_len - 4;
1036	    mptr = tptr + 4;
1037	    while (tval >= 6) {
1038		printf("\n\t      Application Value");
1039		printf("\n\t          Application Protocol ID: 0x%04x",
1040			EXTRACT_16BITS(mptr));
1041		uval = EXTRACT_24BITS(mptr+2);
1042		printf("\n\t          SF (0x%x) Application Protocol ID is %s",
1043			(uval >> 22),
1044			(uval >> 22) ? "Socket Number" : "L2 EtherType");
1045		printf("\n\t          OUI: 0x%06x", uval & 0x3fffff);
1046		printf("\n\t          User Priority Map: 0x%02x", *(mptr+5));
1047		tval = tval - 6;
1048		mptr = mptr + 6;
1049	    }
1050	    break;
1051	default:
1052	    hexdump = TRUE;
1053	    break;
1054	}
1055
1056        /* do we also want to see a hex dump ? */
1057        if (vflag > 1 || (vflag && hexdump)) {
1058	    print_unknown_data(tptr,"\n\t    ", tlv_len);
1059        }
1060
1061        tlen -= tlv_len;
1062        tptr += tlv_len;
1063    }
1064
1065 trunc:
1066    return hexdump;
1067}
1068
1069static char *
1070lldp_network_addr_print(const u_char *tptr, u_int len) {
1071
1072    u_int8_t af;
1073    static char buf[BUFSIZE];
1074    const char * (*pfunc)(const u_char *);
1075
1076    if (len < 1)
1077      return NULL;
1078    len--;
1079    af = *tptr;
1080    switch (af) {
1081    case AFNUM_INET:
1082        if (len < 4)
1083          return NULL;
1084        pfunc = getname;
1085        break;
1086#ifdef INET6
1087    case AFNUM_INET6:
1088        if (len < 16)
1089          return NULL;
1090        pfunc = getname6;
1091        break;
1092#endif
1093    case AFNUM_802:
1094        if (len < 6)
1095          return NULL;
1096        pfunc = etheraddr_string;
1097        break;
1098    default:
1099        pfunc = NULL;
1100        break;
1101    }
1102
1103    if (!pfunc) {
1104        snprintf(buf, sizeof(buf), "AFI %s (%u), no AF printer !",
1105                 tok2str(af_values, "Unknown", af), af);
1106    } else {
1107        snprintf(buf, sizeof(buf), "AFI %s (%u): %s",
1108                 tok2str(af_values, "Unknown", af), af, (*pfunc)(tptr+1));
1109    }
1110
1111    return buf;
1112}
1113
1114static int
1115lldp_mgmt_addr_tlv_print(const u_char *pptr, u_int len) {
1116
1117    u_int8_t mgmt_addr_len, intf_num_subtype, oid_len;
1118    const u_char *tptr;
1119    u_int tlen;
1120    char *mgmt_addr;
1121
1122    tlen = len;
1123    tptr = pptr;
1124
1125    if (tlen < 1) {
1126        return 0;
1127    }
1128    mgmt_addr_len = *tptr++;
1129    tlen--;
1130
1131    if (tlen < mgmt_addr_len) {
1132        return 0;
1133    }
1134
1135    mgmt_addr = lldp_network_addr_print(tptr, mgmt_addr_len);
1136    if (mgmt_addr == NULL) {
1137        return 0;
1138    }
1139    printf("\n\t  Management Address length %u, %s",
1140           mgmt_addr_len, mgmt_addr);
1141    tptr += mgmt_addr_len;
1142    tlen -= mgmt_addr_len;
1143
1144    if (tlen < LLDP_INTF_NUM_LEN) {
1145        return 0;
1146    }
1147
1148    intf_num_subtype = *tptr;
1149    printf("\n\t  %s Interface Numbering (%u): %u",
1150           tok2str(lldp_intf_numb_subtype_values, "Unknown", intf_num_subtype),
1151           intf_num_subtype,
1152           EXTRACT_32BITS(tptr+1));
1153
1154    tptr += LLDP_INTF_NUM_LEN;
1155    tlen -= LLDP_INTF_NUM_LEN;
1156
1157    /*
1158     * The OID is optional.
1159     */
1160    if (tlen) {
1161        oid_len = *tptr;
1162
1163        if (tlen < oid_len) {
1164            return 0;
1165        }
1166        if (oid_len) {
1167            printf("\n\t  OID length %u", oid_len);
1168            safeputs((const char *)tptr+1, oid_len);
1169        }
1170    }
1171
1172    return 1;
1173}
1174
1175void
1176lldp_print(register const u_char *pptr, register u_int len) {
1177
1178    u_int8_t subtype;
1179    u_int16_t tlv, cap, ena_cap;
1180    u_int oui, tlen, hexdump, tlv_type, tlv_len;
1181    const u_char *tptr;
1182    char *network_addr;
1183
1184    tptr = pptr;
1185    tlen = len;
1186
1187    printf("LLDP, length %u", len);
1188
1189    while (tlen >= sizeof(tlv)) {
1190
1191        TCHECK2(*tptr, sizeof(tlv));
1192
1193        tlv = EXTRACT_16BITS(tptr);
1194
1195        tlv_type = LLDP_EXTRACT_TYPE(tlv);
1196        tlv_len = LLDP_EXTRACT_LEN(tlv);
1197        hexdump = FALSE;
1198
1199        tlen -= sizeof(tlv);
1200        tptr += sizeof(tlv);
1201
1202        if (vflag) {
1203            printf("\n\t%s TLV (%u), length %u",
1204                   tok2str(lldp_tlv_values, "Unknown", tlv_type),
1205                   tlv_type, tlv_len);
1206        }
1207
1208        /* infinite loop check */
1209        if (!tlv_type || !tlv_len) {
1210            break;
1211        }
1212
1213        TCHECK2(*tptr, tlv_len);
1214        if (tlen < tlv_len) {
1215            goto trunc;
1216        }
1217
1218        switch (tlv_type) {
1219
1220        case LLDP_CHASSIS_ID_TLV:
1221            if (vflag) {
1222                if (tlv_len < 2) {
1223                    goto trunc;
1224                }
1225                subtype = *tptr;
1226                printf("\n\t  Subtype %s (%u): ",
1227                       tok2str(lldp_chassis_subtype_values, "Unknown", subtype),
1228                       subtype);
1229
1230                switch (subtype) {
1231                case LLDP_CHASSIS_MAC_ADDR_SUBTYPE:
1232                    if (tlv_len < 1+6) {
1233                        goto trunc;
1234                    }
1235                    printf("%s", etheraddr_string(tptr+1));
1236                    break;
1237
1238                case LLDP_CHASSIS_INTF_NAME_SUBTYPE: /* fall through */
1239                case LLDP_CHASSIS_LOCAL_SUBTYPE:
1240                case LLDP_CHASSIS_CHASSIS_COMP_SUBTYPE:
1241                case LLDP_CHASSIS_INTF_ALIAS_SUBTYPE:
1242                case LLDP_CHASSIS_PORT_COMP_SUBTYPE:
1243                    safeputs((const char *)tptr+1, tlv_len-1);
1244                    break;
1245
1246                case LLDP_CHASSIS_NETWORK_ADDR_SUBTYPE:
1247                    network_addr = lldp_network_addr_print(tptr+1, tlv_len-1);
1248                    if (network_addr == NULL) {
1249                        goto trunc;
1250                    }
1251                    printf("%s", network_addr);
1252                    break;
1253
1254                default:
1255                    hexdump = TRUE;
1256                    break;
1257                }
1258            }
1259            break;
1260
1261        case LLDP_PORT_ID_TLV:
1262            if (vflag) {
1263                if (tlv_len < 2) {
1264                    goto trunc;
1265                }
1266                subtype = *tptr;
1267                printf("\n\t  Subtype %s (%u): ",
1268                       tok2str(lldp_port_subtype_values, "Unknown", subtype),
1269                       subtype);
1270
1271                switch (subtype) {
1272                case LLDP_PORT_MAC_ADDR_SUBTYPE:
1273                    if (tlv_len < 1+6) {
1274                        goto trunc;
1275                    }
1276                    printf("%s", etheraddr_string(tptr+1));
1277                    break;
1278
1279                case LLDP_PORT_INTF_NAME_SUBTYPE: /* fall through */
1280                case LLDP_PORT_LOCAL_SUBTYPE:
1281                case LLDP_PORT_AGENT_CIRC_ID_SUBTYPE:
1282                case LLDP_PORT_INTF_ALIAS_SUBTYPE:
1283                case LLDP_PORT_PORT_COMP_SUBTYPE:
1284                    safeputs((const char *)tptr+1, tlv_len-1);
1285                    break;
1286
1287                case LLDP_PORT_NETWORK_ADDR_SUBTYPE:
1288                    network_addr = lldp_network_addr_print(tptr+1, tlv_len-1);
1289                    if (network_addr == NULL) {
1290                        goto trunc;
1291                    }
1292                    printf("%s", network_addr);
1293                    break;
1294
1295                default:
1296                    hexdump = TRUE;
1297                    break;
1298                }
1299            }
1300            break;
1301
1302        case LLDP_TTL_TLV:
1303            if (vflag) {
1304                if (tlv_len < 2) {
1305                    goto trunc;
1306                }
1307                printf(": TTL %us", EXTRACT_16BITS(tptr));
1308            }
1309            break;
1310
1311        case LLDP_PORT_DESCR_TLV:
1312            if (vflag) {
1313                printf(": ");
1314                safeputs((const char *)tptr, tlv_len);
1315            }
1316            break;
1317
1318        case LLDP_SYSTEM_NAME_TLV:
1319            /*
1320             * The system name is also print in non-verbose mode
1321             * similar to the CDP printer.
1322             */
1323            printf(": ");
1324            safeputs((const char *)tptr, tlv_len);
1325            break;
1326
1327        case LLDP_SYSTEM_DESCR_TLV:
1328            if (vflag) {
1329                printf("\n\t  ");
1330                safeputs((const char *)tptr, tlv_len);
1331            }
1332            break;
1333
1334        case LLDP_SYSTEM_CAP_TLV:
1335            if (vflag) {
1336                /*
1337                 * XXX - IEEE Std 802.1AB-2009 says the first octet
1338                 * if a chassis ID subtype, with the system
1339                 * capabilities and enabled capabilities following
1340                 * it.
1341                 */
1342                if (tlv_len < 4) {
1343                    goto trunc;
1344                }
1345                cap = EXTRACT_16BITS(tptr);
1346                ena_cap = EXTRACT_16BITS(tptr+2);
1347                printf("\n\t  System  Capabilities [%s] (0x%04x)",
1348                       bittok2str(lldp_cap_values, "none", cap), cap);
1349                printf("\n\t  Enabled Capabilities [%s] (0x%04x)",
1350                       bittok2str(lldp_cap_values, "none", ena_cap), ena_cap);
1351            }
1352            break;
1353
1354        case LLDP_MGMT_ADDR_TLV:
1355            if (vflag) {
1356                if (!lldp_mgmt_addr_tlv_print(tptr, tlv_len)) {
1357                    goto trunc;
1358                }
1359            }
1360            break;
1361
1362        case LLDP_PRIVATE_TLV:
1363            if (vflag) {
1364                if (tlv_len < 3) {
1365                    goto trunc;
1366                }
1367                oui = EXTRACT_24BITS(tptr);
1368                printf(": OUI %s (0x%06x)", tok2str(oui_values, "Unknown", oui), oui);
1369
1370                switch (oui) {
1371                case OUI_IEEE_8021_PRIVATE:
1372                    hexdump = lldp_private_8021_print(tptr, tlv_len);
1373                    break;
1374                case OUI_IEEE_8023_PRIVATE:
1375                    hexdump = lldp_private_8023_print(tptr, tlv_len);
1376                    break;
1377                case OUI_TIA:
1378                    hexdump = lldp_private_tia_print(tptr, tlv_len);
1379                    break;
1380                case OUI_DCBX:
1381                    hexdump = lldp_private_dcbx_print(tptr, tlv_len);
1382                    break;
1383                default:
1384                    hexdump = TRUE;
1385                    break;
1386                }
1387            }
1388            break;
1389
1390        default:
1391            hexdump = TRUE;
1392            break;
1393        }
1394
1395        /* do we also want to see a hex dump ? */
1396        if (vflag > 1 || (vflag && hexdump)) {
1397            print_unknown_data(tptr,"\n\t  ", tlv_len);
1398        }
1399
1400        tlen -= tlv_len;
1401        tptr += tlv_len;
1402    }
1403    return;
1404 trunc:
1405    printf("\n\t[|LLDP]");
1406}
1407
1408/*
1409 * Local Variables:
1410 * c-style: whitesmith
1411 * c-basic-offset: 4
1412 * End:
1413 */
1414