1190203Srpaulo/*
2190203Srpaulo * Copyright (c) 1998-2007 The TCPDUMP project
3190203Srpaulo *
4190203Srpaulo * Redistribution and use in source and binary forms, with or without
5190203Srpaulo * modification, are permitted provided that: (1) source code
6190203Srpaulo * distributions retain the above copyright notice and this paragraph
7190203Srpaulo * in its entirety, and (2) distributions including binary code include
8190203Srpaulo * the above copyright notice and this paragraph in its entirety in
9190203Srpaulo * the documentation or other materials provided with the distribution.
10190203Srpaulo * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
11190203Srpaulo * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
12190203Srpaulo * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
13190203Srpaulo * FOR A PARTICULAR PURPOSE.
14190203Srpaulo *
15235530Sdelphij * support for the IEEE Link Discovery Protocol as per 802.1AB
16190203Srpaulo *
17190203Srpaulo * Original code by Hannes Gredler (hannes@juniper.net)
18190203Srpaulo * IEEE and TIA extensions by Carles Kishimoto <carles.kishimoto@gmail.com>
19235530Sdelphij * DCBX extensions by Kaladhar Musunuru <kaladharm@sourceforge.net>
20190203Srpaulo */
21190203Srpaulo
22190203Srpaulo#ifndef lint
23190203Srpaulostatic const char rcsid[] _U_ =
24214478Srpaulo"@(#) $Header: /tcpdump/master/tcpdump/print-lldp.c,v 1.10 2008-03-20 09:30:56 hannes Exp $";
25190203Srpaulo#endif
26190203Srpaulo
27190203Srpaulo#ifdef HAVE_CONFIG_H
28190203Srpaulo#include "config.h"
29190203Srpaulo#endif
30190203Srpaulo
31190203Srpaulo#include <tcpdump-stdinc.h>
32190203Srpaulo
33190203Srpaulo#include <stdio.h>
34190203Srpaulo#include <stdlib.h>
35190203Srpaulo#include <string.h>
36190203Srpaulo
37190203Srpaulo#include "interface.h"
38190203Srpaulo#include "extract.h"
39190203Srpaulo#include "addrtoname.h"
40190203Srpaulo#include "af.h"
41190203Srpaulo#include "oui.h"
42190203Srpaulo
43190203Srpaulo#define	LLDP_EXTRACT_TYPE(x) (((x)&0xfe00)>>9)
44190203Srpaulo#define	LLDP_EXTRACT_LEN(x) ((x)&0x01ff)
45190203Srpaulo
46190203Srpaulo/*
47190203Srpaulo * TLV type codes
48190203Srpaulo */
49190203Srpaulo#define LLDP_END_TLV             0
50190203Srpaulo#define LLDP_CHASSIS_ID_TLV      1
51190203Srpaulo#define LLDP_PORT_ID_TLV         2
52190203Srpaulo#define LLDP_TTL_TLV             3
53190203Srpaulo#define LLDP_PORT_DESCR_TLV      4
54190203Srpaulo#define LLDP_SYSTEM_NAME_TLV     5
55190203Srpaulo#define LLDP_SYSTEM_DESCR_TLV    6
56190203Srpaulo#define LLDP_SYSTEM_CAP_TLV      7
57190203Srpaulo#define LLDP_MGMT_ADDR_TLV       8
58190203Srpaulo#define LLDP_PRIVATE_TLV       127
59190203Srpaulo
60190203Srpaulostatic const struct tok lldp_tlv_values[] = {
61190203Srpaulo    { LLDP_END_TLV, "End" },
62190203Srpaulo    { LLDP_CHASSIS_ID_TLV, "Chassis ID" },
63190203Srpaulo    { LLDP_PORT_ID_TLV, "Port ID" },
64190203Srpaulo    { LLDP_TTL_TLV, "Time to Live" },
65190203Srpaulo    { LLDP_PORT_DESCR_TLV, "Port Description" },
66190203Srpaulo    { LLDP_SYSTEM_NAME_TLV, "System Name" },
67190203Srpaulo    { LLDP_SYSTEM_DESCR_TLV, "System Description" },
68190203Srpaulo    { LLDP_SYSTEM_CAP_TLV, "System Capabilities" },
69190203Srpaulo    { LLDP_MGMT_ADDR_TLV, "Management Address" },
70190203Srpaulo    { LLDP_PRIVATE_TLV, "Organization specific" },
71190203Srpaulo    { 0, NULL}
72190203Srpaulo};
73190203Srpaulo
74190203Srpaulo/*
75190203Srpaulo * Chassis ID subtypes
76190203Srpaulo */
77190203Srpaulo#define LLDP_CHASSIS_CHASSIS_COMP_SUBTYPE  1
78190203Srpaulo#define LLDP_CHASSIS_INTF_ALIAS_SUBTYPE    2
79190203Srpaulo#define LLDP_CHASSIS_PORT_COMP_SUBTYPE     3
80190203Srpaulo#define LLDP_CHASSIS_MAC_ADDR_SUBTYPE      4
81190203Srpaulo#define LLDP_CHASSIS_NETWORK_ADDR_SUBTYPE  5
82190203Srpaulo#define LLDP_CHASSIS_INTF_NAME_SUBTYPE     6
83190203Srpaulo#define LLDP_CHASSIS_LOCAL_SUBTYPE         7
84190203Srpaulo
85190203Srpaulostatic const struct tok lldp_chassis_subtype_values[] = {
86190203Srpaulo    { LLDP_CHASSIS_CHASSIS_COMP_SUBTYPE, "Chassis component"},
87190203Srpaulo    { LLDP_CHASSIS_INTF_ALIAS_SUBTYPE, "Interface alias"},
88190203Srpaulo    { LLDP_CHASSIS_PORT_COMP_SUBTYPE, "Port component"},
89190203Srpaulo    { LLDP_CHASSIS_MAC_ADDR_SUBTYPE, "MAC address"},
90190203Srpaulo    { LLDP_CHASSIS_NETWORK_ADDR_SUBTYPE, "Network address"},
91190203Srpaulo    { LLDP_CHASSIS_INTF_NAME_SUBTYPE, "Interface name"},
92190203Srpaulo    { LLDP_CHASSIS_LOCAL_SUBTYPE, "Local"},
93190203Srpaulo    { 0, NULL}
94190203Srpaulo};
95190203Srpaulo
96190203Srpaulo/*
97190203Srpaulo * Port ID subtypes
98190203Srpaulo */
99190203Srpaulo#define LLDP_PORT_INTF_ALIAS_SUBTYPE       1
100190203Srpaulo#define LLDP_PORT_PORT_COMP_SUBTYPE        2
101190203Srpaulo#define LLDP_PORT_MAC_ADDR_SUBTYPE         3
102190203Srpaulo#define LLDP_PORT_NETWORK_ADDR_SUBTYPE     4
103190203Srpaulo#define LLDP_PORT_INTF_NAME_SUBTYPE        5
104190203Srpaulo#define LLDP_PORT_AGENT_CIRC_ID_SUBTYPE    6
105190203Srpaulo#define LLDP_PORT_LOCAL_SUBTYPE            7
106190203Srpaulo
107190203Srpaulostatic const struct tok lldp_port_subtype_values[] = {
108190203Srpaulo    { LLDP_PORT_INTF_ALIAS_SUBTYPE, "Interface alias"},
109190203Srpaulo    { LLDP_PORT_PORT_COMP_SUBTYPE, "Port component"},
110190203Srpaulo    { LLDP_PORT_MAC_ADDR_SUBTYPE, "MAC address"},
111190203Srpaulo    { LLDP_PORT_NETWORK_ADDR_SUBTYPE, "Network Address"},
112190203Srpaulo    { LLDP_PORT_INTF_NAME_SUBTYPE, "Interface Name"},
113190203Srpaulo    { LLDP_PORT_AGENT_CIRC_ID_SUBTYPE, "Agent circuit ID"},
114190203Srpaulo    { LLDP_PORT_LOCAL_SUBTYPE, "Local"},
115190203Srpaulo    { 0, NULL}
116190203Srpaulo};
117190203Srpaulo
118190203Srpaulo/*
119190203Srpaulo * System Capabilities
120190203Srpaulo */
121190203Srpaulo#define LLDP_CAP_OTHER              (1 <<  0)
122190203Srpaulo#define LLDP_CAP_REPEATER           (1 <<  1)
123190203Srpaulo#define LLDP_CAP_BRIDGE             (1 <<  2)
124190203Srpaulo#define LLDP_CAP_WLAN_AP            (1 <<  3)
125190203Srpaulo#define LLDP_CAP_ROUTER             (1 <<  4)
126190203Srpaulo#define LLDP_CAP_PHONE              (1 <<  5)
127190203Srpaulo#define LLDP_CAP_DOCSIS             (1 <<  6)
128190203Srpaulo#define LLDP_CAP_STATION_ONLY       (1 <<  7)
129190203Srpaulo
130190203Srpaulostatic const struct tok lldp_cap_values[] = {
131190203Srpaulo    { LLDP_CAP_OTHER, "Other"},
132190203Srpaulo    { LLDP_CAP_REPEATER, "Repeater"},
133190203Srpaulo    { LLDP_CAP_BRIDGE, "Bridge"},
134190203Srpaulo    { LLDP_CAP_WLAN_AP, "WLAN AP"},
135190203Srpaulo    { LLDP_CAP_ROUTER, "Router"},
136190203Srpaulo    { LLDP_CAP_PHONE, "Telephone"},
137190203Srpaulo    { LLDP_CAP_DOCSIS, "Docsis"},
138190203Srpaulo    { LLDP_CAP_STATION_ONLY, "Station Only"},
139190203Srpaulo    { 0, NULL}
140190203Srpaulo};
141190203Srpaulo
142190203Srpaulo#define LLDP_PRIVATE_8021_SUBTYPE_PORT_VLAN_ID		1
143190203Srpaulo#define LLDP_PRIVATE_8021_SUBTYPE_PROTOCOL_VLAN_ID	2
144190203Srpaulo#define LLDP_PRIVATE_8021_SUBTYPE_VLAN_NAME		3
145190203Srpaulo#define LLDP_PRIVATE_8021_SUBTYPE_PROTOCOL_IDENTITY	4
146190203Srpaulo
147190203Srpaulostatic const struct tok lldp_8021_subtype_values[] = {
148190203Srpaulo    { LLDP_PRIVATE_8021_SUBTYPE_PORT_VLAN_ID, "Port VLAN Id"},
149190203Srpaulo    { LLDP_PRIVATE_8021_SUBTYPE_PROTOCOL_VLAN_ID, "Port and Protocol VLAN ID"},
150190203Srpaulo    { LLDP_PRIVATE_8021_SUBTYPE_VLAN_NAME, "VLAN name"},
151190203Srpaulo    { LLDP_PRIVATE_8021_SUBTYPE_PROTOCOL_IDENTITY, "Protocol Identity"},
152190203Srpaulo    { 0, NULL}
153190203Srpaulo};
154190203Srpaulo
155190203Srpaulo#define LLDP_8021_PORT_PROTOCOL_VLAN_SUPPORT       (1 <<  1)
156190203Srpaulo#define LLDP_8021_PORT_PROTOCOL_VLAN_STATUS        (1 <<  2)
157190203Srpaulo
158190203Srpaulostatic const struct tok lldp_8021_port_protocol_id_values[] = {
159190203Srpaulo    { LLDP_8021_PORT_PROTOCOL_VLAN_SUPPORT, "supported"},
160190203Srpaulo    { LLDP_8021_PORT_PROTOCOL_VLAN_STATUS, "enabled"},
161190203Srpaulo    { 0, NULL}
162190203Srpaulo};
163190203Srpaulo
164190203Srpaulo#define LLDP_PRIVATE_8023_SUBTYPE_MACPHY        1
165190203Srpaulo#define LLDP_PRIVATE_8023_SUBTYPE_MDIPOWER      2
166190203Srpaulo#define LLDP_PRIVATE_8023_SUBTYPE_LINKAGGR      3
167190203Srpaulo#define LLDP_PRIVATE_8023_SUBTYPE_MTU           4
168190203Srpaulo
169190203Srpaulostatic const struct tok lldp_8023_subtype_values[] = {
170190203Srpaulo    { LLDP_PRIVATE_8023_SUBTYPE_MACPHY,	"MAC/PHY configuration/status"},
171190203Srpaulo    { LLDP_PRIVATE_8023_SUBTYPE_MDIPOWER, "Power via MDI"},
172190203Srpaulo    { LLDP_PRIVATE_8023_SUBTYPE_LINKAGGR, "Link aggregation"},
173190203Srpaulo    { LLDP_PRIVATE_8023_SUBTYPE_MTU, "Max frame size"},
174190203Srpaulo    { 0, NULL}
175190203Srpaulo};
176190203Srpaulo
177190203Srpaulo#define LLDP_PRIVATE_TIA_SUBTYPE_CAPABILITIES                   1
178190203Srpaulo#define LLDP_PRIVATE_TIA_SUBTYPE_NETWORK_POLICY                 2
179190203Srpaulo#define LLDP_PRIVATE_TIA_SUBTYPE_LOCAL_ID                       3
180190203Srpaulo#define LLDP_PRIVATE_TIA_SUBTYPE_EXTENDED_POWER_MDI             4
181190203Srpaulo#define LLDP_PRIVATE_TIA_SUBTYPE_INVENTORY_HARDWARE_REV         5
182190203Srpaulo#define LLDP_PRIVATE_TIA_SUBTYPE_INVENTORY_FIRMWARE_REV         6
183190203Srpaulo#define LLDP_PRIVATE_TIA_SUBTYPE_INVENTORY_SOFTWARE_REV         7
184190203Srpaulo#define LLDP_PRIVATE_TIA_SUBTYPE_INVENTORY_SERIAL_NUMBER        8
185190203Srpaulo#define LLDP_PRIVATE_TIA_SUBTYPE_INVENTORY_MANUFACTURER_NAME    9
186190203Srpaulo#define LLDP_PRIVATE_TIA_SUBTYPE_INVENTORY_MODEL_NAME           10
187190203Srpaulo#define LLDP_PRIVATE_TIA_SUBTYPE_INVENTORY_ASSET_ID             11
188190203Srpaulo
189190203Srpaulostatic const struct tok lldp_tia_subtype_values[] = {
190190203Srpaulo    { LLDP_PRIVATE_TIA_SUBTYPE_CAPABILITIES, "LLDP-MED Capabilities" },
191190203Srpaulo    { LLDP_PRIVATE_TIA_SUBTYPE_NETWORK_POLICY, "Network policy" },
192190203Srpaulo    { LLDP_PRIVATE_TIA_SUBTYPE_LOCAL_ID, "Location identification" },
193190203Srpaulo    { LLDP_PRIVATE_TIA_SUBTYPE_EXTENDED_POWER_MDI, "Extended power-via-MDI" },
194190203Srpaulo    { LLDP_PRIVATE_TIA_SUBTYPE_INVENTORY_HARDWARE_REV, "Inventory - hardware revision" },
195190203Srpaulo    { LLDP_PRIVATE_TIA_SUBTYPE_INVENTORY_FIRMWARE_REV, "Inventory - firmware revision" },
196190203Srpaulo    { LLDP_PRIVATE_TIA_SUBTYPE_INVENTORY_SOFTWARE_REV, "Inventory - software revision" },
197190203Srpaulo    { LLDP_PRIVATE_TIA_SUBTYPE_INVENTORY_SERIAL_NUMBER, "Inventory - serial number" },
198190203Srpaulo    { LLDP_PRIVATE_TIA_SUBTYPE_INVENTORY_MANUFACTURER_NAME, "Inventory - manufacturer name" },
199190203Srpaulo    { LLDP_PRIVATE_TIA_SUBTYPE_INVENTORY_MODEL_NAME, "Inventory - model name" },
200190203Srpaulo    { LLDP_PRIVATE_TIA_SUBTYPE_INVENTORY_ASSET_ID, "Inventory - asset ID" },
201190203Srpaulo    { 0, NULL}
202190203Srpaulo};
203190203Srpaulo
204190203Srpaulo#define LLDP_PRIVATE_TIA_LOCATION_ALTITUDE_METERS       1
205190203Srpaulo#define LLDP_PRIVATE_TIA_LOCATION_ALTITUDE_FLOORS       2
206190203Srpaulo
207190203Srpaulostatic const struct tok lldp_tia_location_altitude_type_values[] = {
208190203Srpaulo    { LLDP_PRIVATE_TIA_LOCATION_ALTITUDE_METERS, "meters"},
209190203Srpaulo    { LLDP_PRIVATE_TIA_LOCATION_ALTITUDE_FLOORS, "floors"},
210190203Srpaulo    { 0, NULL}
211190203Srpaulo};
212190203Srpaulo
213190203Srpaulo/* ANSI/TIA-1057 - Annex B */
214190203Srpaulo#define LLDP_PRIVATE_TIA_LOCATION_LCI_CATYPE_A1		1
215190203Srpaulo#define LLDP_PRIVATE_TIA_LOCATION_LCI_CATYPE_A2		2
216190203Srpaulo#define LLDP_PRIVATE_TIA_LOCATION_LCI_CATYPE_A3		3
217190203Srpaulo#define LLDP_PRIVATE_TIA_LOCATION_LCI_CATYPE_A4		4
218190203Srpaulo#define LLDP_PRIVATE_TIA_LOCATION_LCI_CATYPE_A5		5
219190203Srpaulo#define LLDP_PRIVATE_TIA_LOCATION_LCI_CATYPE_A6		6
220190203Srpaulo
221190203Srpaulostatic const struct tok lldp_tia_location_lci_catype_values[] = {
222190203Srpaulo    { LLDP_PRIVATE_TIA_LOCATION_LCI_CATYPE_A1, "national subdivisions (state,canton,region,province,prefecture)"},
223190203Srpaulo    { LLDP_PRIVATE_TIA_LOCATION_LCI_CATYPE_A2, "county, parish, gun, district"},
224190203Srpaulo    { LLDP_PRIVATE_TIA_LOCATION_LCI_CATYPE_A3, "city, township, shi"},
225190203Srpaulo    { LLDP_PRIVATE_TIA_LOCATION_LCI_CATYPE_A4, "city division, borough, city district, ward chou"},
226190203Srpaulo    { LLDP_PRIVATE_TIA_LOCATION_LCI_CATYPE_A5, "neighborhood, block"},
227190203Srpaulo    { LLDP_PRIVATE_TIA_LOCATION_LCI_CATYPE_A6, "street"},
228190203Srpaulo    { 0, NULL}
229190203Srpaulo};
230190203Srpaulo
231190203Srpaulostatic const struct tok lldp_tia_location_lci_what_values[] = {
232190203Srpaulo    { 0, "location of DHCP server"},
233190203Srpaulo    { 1, "location of the network element believed to be closest to the client"},
234190203Srpaulo    { 2, "location of the client"},
235190203Srpaulo    { 0, NULL}
236190203Srpaulo};
237190203Srpaulo
238190203Srpaulo/*
239190203Srpaulo * From RFC 3636 - dot3MauType
240190203Srpaulo */
241190203Srpaulo#define		LLDP_MAU_TYPE_UNKNOWN		0
242190203Srpaulo#define		LLDP_MAU_TYPE_AUI		1
243190203Srpaulo#define		LLDP_MAU_TYPE_10BASE_5		2
244190203Srpaulo#define		LLDP_MAU_TYPE_FOIRL		3
245190203Srpaulo#define		LLDP_MAU_TYPE_10BASE_2		4
246190203Srpaulo#define		LLDP_MAU_TYPE_10BASE_T		5
247190203Srpaulo#define		LLDP_MAU_TYPE_10BASE_FP		6
248190203Srpaulo#define		LLDP_MAU_TYPE_10BASE_FB		7
249190203Srpaulo#define		LLDP_MAU_TYPE_10BASE_FL		8
250190203Srpaulo#define		LLDP_MAU_TYPE_10BROAD36		9
251190203Srpaulo#define		LLDP_MAU_TYPE_10BASE_T_HD	10
252190203Srpaulo#define		LLDP_MAU_TYPE_10BASE_T_FD	11
253190203Srpaulo#define		LLDP_MAU_TYPE_10BASE_FL_HD	12
254190203Srpaulo#define		LLDP_MAU_TYPE_10BASE_FL_FD	13
255190203Srpaulo#define		LLDP_MAU_TYPE_100BASE_T4	14
256190203Srpaulo#define		LLDP_MAU_TYPE_100BASE_TX_HD	15
257190203Srpaulo#define		LLDP_MAU_TYPE_100BASE_TX_FD	16
258190203Srpaulo#define		LLDP_MAU_TYPE_100BASE_FX_HD	17
259190203Srpaulo#define		LLDP_MAU_TYPE_100BASE_FX_FD	18
260190203Srpaulo#define		LLDP_MAU_TYPE_100BASE_T2_HD	19
261190203Srpaulo#define		LLDP_MAU_TYPE_100BASE_T2_FD	20
262190203Srpaulo#define		LLDP_MAU_TYPE_1000BASE_X_HD	21
263190203Srpaulo#define		LLDP_MAU_TYPE_1000BASE_X_FD	22
264190203Srpaulo#define		LLDP_MAU_TYPE_1000BASE_LX_HD	23
265190203Srpaulo#define		LLDP_MAU_TYPE_1000BASE_LX_FD	24
266190203Srpaulo#define		LLDP_MAU_TYPE_1000BASE_SX_HD	25
267190203Srpaulo#define		LLDP_MAU_TYPE_1000BASE_SX_FD	26
268190203Srpaulo#define		LLDP_MAU_TYPE_1000BASE_CX_HD	27
269190203Srpaulo#define		LLDP_MAU_TYPE_1000BASE_CX_FD	28
270190203Srpaulo#define		LLDP_MAU_TYPE_1000BASE_T_HD	29
271190203Srpaulo#define		LLDP_MAU_TYPE_1000BASE_T_FD	30
272190203Srpaulo#define		LLDP_MAU_TYPE_10GBASE_X		31
273190203Srpaulo#define		LLDP_MAU_TYPE_10GBASE_LX4	32
274190203Srpaulo#define		LLDP_MAU_TYPE_10GBASE_R		33
275190203Srpaulo#define		LLDP_MAU_TYPE_10GBASE_ER	34
276190203Srpaulo#define		LLDP_MAU_TYPE_10GBASE_LR	35
277190203Srpaulo#define		LLDP_MAU_TYPE_10GBASE_SR	36
278190203Srpaulo#define		LLDP_MAU_TYPE_10GBASE_W		37
279190203Srpaulo#define		LLDP_MAU_TYPE_10GBASE_EW	38
280190203Srpaulo#define		LLDP_MAU_TYPE_10GBASE_LW	39
281190203Srpaulo#define		LLDP_MAU_TYPE_10GBASE_SW	40
282190203Srpaulo
283190203Srpaulostatic const struct tok lldp_mau_types_values[] = {
284190203Srpaulo    { LLDP_MAU_TYPE_UNKNOWN,            "Unknown"},
285190203Srpaulo    { LLDP_MAU_TYPE_AUI,                "AUI"},
286190203Srpaulo    { LLDP_MAU_TYPE_10BASE_5,           "10BASE_5"},
287190203Srpaulo    { LLDP_MAU_TYPE_FOIRL,              "FOIRL"},
288190203Srpaulo    { LLDP_MAU_TYPE_10BASE_2,           "10BASE2"},
289190203Srpaulo    { LLDP_MAU_TYPE_10BASE_T,           "10BASET duplex mode unknown"},
290190203Srpaulo    { LLDP_MAU_TYPE_10BASE_FP,          "10BASEFP"},
291190203Srpaulo    { LLDP_MAU_TYPE_10BASE_FB,          "10BASEFB"},
292190203Srpaulo    { LLDP_MAU_TYPE_10BASE_FL,          "10BASEFL duplex mode unknown"},
293190203Srpaulo    { LLDP_MAU_TYPE_10BROAD36,          "10BROAD36"},
294190203Srpaulo    { LLDP_MAU_TYPE_10BASE_T_HD,        "10BASET hdx"},
295190203Srpaulo    { LLDP_MAU_TYPE_10BASE_T_FD,        "10BASET fdx"},
296190203Srpaulo    { LLDP_MAU_TYPE_10BASE_FL_HD,       "10BASEFL hdx"},
297190203Srpaulo    { LLDP_MAU_TYPE_10BASE_FL_FD,       "10BASEFL fdx"},
298190203Srpaulo    { LLDP_MAU_TYPE_100BASE_T4,         "100BASET4"},
299190203Srpaulo    { LLDP_MAU_TYPE_100BASE_TX_HD,      "100BASETX hdx"},
300190203Srpaulo    { LLDP_MAU_TYPE_100BASE_TX_FD,      "100BASETX fdx"},
301190203Srpaulo    { LLDP_MAU_TYPE_100BASE_FX_HD,      "100BASEFX hdx"},
302190203Srpaulo    { LLDP_MAU_TYPE_100BASE_FX_FD,      "100BASEFX fdx"},
303190203Srpaulo    { LLDP_MAU_TYPE_100BASE_T2_HD,      "100BASET2 hdx"},
304190203Srpaulo    { LLDP_MAU_TYPE_100BASE_T2_FD,      "100BASET2 fdx"},
305190203Srpaulo    { LLDP_MAU_TYPE_1000BASE_X_HD,      "1000BASEX hdx"},
306190203Srpaulo    { LLDP_MAU_TYPE_1000BASE_X_FD,      "1000BASEX fdx"},
307190203Srpaulo    { LLDP_MAU_TYPE_1000BASE_LX_HD,     "1000BASELX hdx"},
308190203Srpaulo    { LLDP_MAU_TYPE_1000BASE_LX_FD,     "1000BASELX fdx"},
309190203Srpaulo    { LLDP_MAU_TYPE_1000BASE_SX_HD,     "1000BASESX hdx"},
310190203Srpaulo    { LLDP_MAU_TYPE_1000BASE_SX_FD,     "1000BASESX fdx"},
311190203Srpaulo    { LLDP_MAU_TYPE_1000BASE_CX_HD,     "1000BASECX hdx"},
312190203Srpaulo    { LLDP_MAU_TYPE_1000BASE_CX_FD,     "1000BASECX fdx"},
313190203Srpaulo    { LLDP_MAU_TYPE_1000BASE_T_HD,      "1000BASET hdx"},
314190203Srpaulo    { LLDP_MAU_TYPE_1000BASE_T_FD,      "1000BASET fdx"},
315190203Srpaulo    { LLDP_MAU_TYPE_10GBASE_X,          "10GBASEX"},
316190203Srpaulo    { LLDP_MAU_TYPE_10GBASE_LX4,        "10GBASELX4"},
317190203Srpaulo    { LLDP_MAU_TYPE_10GBASE_R,          "10GBASER"},
318190203Srpaulo    { LLDP_MAU_TYPE_10GBASE_ER,         "10GBASEER"},
319190203Srpaulo    { LLDP_MAU_TYPE_10GBASE_LR,         "10GBASELR"},
320190203Srpaulo    { LLDP_MAU_TYPE_10GBASE_SR,         "10GBASESR"},
321190203Srpaulo    { LLDP_MAU_TYPE_10GBASE_W,          "10GBASEW"},
322190203Srpaulo    { LLDP_MAU_TYPE_10GBASE_EW,         "10GBASEEW"},
323190203Srpaulo    { LLDP_MAU_TYPE_10GBASE_LW,         "10GBASELW"},
324190203Srpaulo    { LLDP_MAU_TYPE_10GBASE_SW,         "10GBASESW"},
325190203Srpaulo    { 0, NULL}
326190203Srpaulo};
327190203Srpaulo
328190203Srpaulo#define LLDP_8023_AUTONEGOTIATION_SUPPORT       (1 <<  0)
329190203Srpaulo#define LLDP_8023_AUTONEGOTIATION_STATUS        (1 <<  1)
330190203Srpaulo
331190203Srpaulostatic const struct tok lldp_8023_autonegotiation_values[] = {
332190203Srpaulo    { LLDP_8023_AUTONEGOTIATION_SUPPORT, "supported"},
333190203Srpaulo    { LLDP_8023_AUTONEGOTIATION_STATUS, "enabled"},
334190203Srpaulo    { 0, NULL}
335190203Srpaulo};
336190203Srpaulo
337190203Srpaulo#define LLDP_TIA_CAPABILITY_MED                         (1 <<  0)
338190203Srpaulo#define LLDP_TIA_CAPABILITY_NETWORK_POLICY              (1 <<  1)
339190203Srpaulo#define LLDP_TIA_CAPABILITY_LOCATION_IDENTIFICATION     (1 <<  2)
340190203Srpaulo#define LLDP_TIA_CAPABILITY_EXTENDED_POWER_MDI_PSE      (1 <<  3)
341190203Srpaulo#define LLDP_TIA_CAPABILITY_EXTENDED_POWER_MDI_PD       (1 <<  4)
342190203Srpaulo#define LLDP_TIA_CAPABILITY_INVENTORY                   (1 <<  5)
343190203Srpaulo
344190203Srpaulostatic const struct tok lldp_tia_capabilities_values[] = {
345190203Srpaulo    { LLDP_TIA_CAPABILITY_MED, "LLDP-MED capabilities"},
346190203Srpaulo    { LLDP_TIA_CAPABILITY_NETWORK_POLICY, "network policy"},
347190203Srpaulo    { LLDP_TIA_CAPABILITY_LOCATION_IDENTIFICATION, "location identification"},
348190203Srpaulo    { LLDP_TIA_CAPABILITY_EXTENDED_POWER_MDI_PSE, "extended power via MDI-PSE"},
349190203Srpaulo    { LLDP_TIA_CAPABILITY_EXTENDED_POWER_MDI_PD, "extended power via MDI-PD"},
350190203Srpaulo    { LLDP_TIA_CAPABILITY_INVENTORY, "Inventory"},
351190203Srpaulo    { 0, NULL}
352190203Srpaulo};
353190203Srpaulo
354190203Srpaulo#define LLDP_TIA_DEVICE_TYPE_ENDPOINT_CLASS_1           1
355190203Srpaulo#define LLDP_TIA_DEVICE_TYPE_ENDPOINT_CLASS_2           2
356190203Srpaulo#define LLDP_TIA_DEVICE_TYPE_ENDPOINT_CLASS_3           3
357190203Srpaulo#define LLDP_TIA_DEVICE_TYPE_NETWORK_CONNECTIVITY       4
358190203Srpaulo
359190203Srpaulostatic const struct tok lldp_tia_device_type_values[] = {
360190203Srpaulo    { LLDP_TIA_DEVICE_TYPE_ENDPOINT_CLASS_1, "endpoint class 1"},
361190203Srpaulo    { LLDP_TIA_DEVICE_TYPE_ENDPOINT_CLASS_2, "endpoint class 2"},
362190203Srpaulo    { LLDP_TIA_DEVICE_TYPE_ENDPOINT_CLASS_3, "endpoint class 3"},
363190203Srpaulo    { LLDP_TIA_DEVICE_TYPE_NETWORK_CONNECTIVITY, "network connectivity"},
364190203Srpaulo    { 0, NULL}
365190203Srpaulo};
366190203Srpaulo
367190203Srpaulo#define LLDP_TIA_APPLICATION_TYPE_VOICE                 1
368190203Srpaulo#define LLDP_TIA_APPLICATION_TYPE_VOICE_SIGNALING       2
369190203Srpaulo#define LLDP_TIA_APPLICATION_TYPE_GUEST_VOICE           3
370190203Srpaulo#define LLDP_TIA_APPLICATION_TYPE_GUEST_VOICE_SIGNALING 4
371190203Srpaulo#define LLDP_TIA_APPLICATION_TYPE_SOFTPHONE_VOICE       5
372190203Srpaulo#define LLDP_TIA_APPLICATION_TYPE_VIDEO_CONFERENCING    6
373190203Srpaulo#define LLDP_TIA_APPLICATION_TYPE_STREAMING_VIDEO       7
374190203Srpaulo#define LLDP_TIA_APPLICATION_TYPE_VIDEO_SIGNALING       8
375190203Srpaulo
376190203Srpaulostatic const struct tok lldp_tia_application_type_values[] = {
377190203Srpaulo    { LLDP_TIA_APPLICATION_TYPE_VOICE, "voice"},
378190203Srpaulo    { LLDP_TIA_APPLICATION_TYPE_VOICE_SIGNALING, "voice signaling"},
379190203Srpaulo    { LLDP_TIA_APPLICATION_TYPE_GUEST_VOICE, "guest voice"},
380190203Srpaulo    { LLDP_TIA_APPLICATION_TYPE_GUEST_VOICE_SIGNALING, "guest voice signaling"},
381190203Srpaulo    { LLDP_TIA_APPLICATION_TYPE_SOFTPHONE_VOICE, "softphone voice"},
382190203Srpaulo    { LLDP_TIA_APPLICATION_TYPE_VIDEO_CONFERENCING, "video conferencing"},
383190203Srpaulo    { LLDP_TIA_APPLICATION_TYPE_STREAMING_VIDEO, "streaming video"},
384190203Srpaulo    { LLDP_TIA_APPLICATION_TYPE_VIDEO_SIGNALING, "video signaling"},
385190203Srpaulo    { 0, NULL}
386190203Srpaulo};
387190203Srpaulo
388241235Sdelphij#define LLDP_TIA_NETWORK_POLICY_X_BIT           (1 << 5)
389190203Srpaulo#define LLDP_TIA_NETWORK_POLICY_T_BIT           (1 << 6)
390241235Sdelphij#define LLDP_TIA_NETWORK_POLICY_U_BIT           (1 << 7)
391190203Srpaulo
392190203Srpaulostatic const struct tok lldp_tia_network_policy_bits_values[] = {
393190203Srpaulo    { LLDP_TIA_NETWORK_POLICY_U_BIT, "Unknown"},
394190203Srpaulo    { LLDP_TIA_NETWORK_POLICY_T_BIT, "Tagged"},
395190203Srpaulo    { LLDP_TIA_NETWORK_POLICY_X_BIT, "reserved"},
396190203Srpaulo    { 0, NULL}
397190203Srpaulo};
398190203Srpaulo
399190203Srpaulo#define LLDP_EXTRACT_NETWORK_POLICY_VLAN(x)           (((x)&0x1ffe)>>1)
400190203Srpaulo#define LLDP_EXTRACT_NETWORK_POLICY_L2_PRIORITY(x)    (((x)&0x01ff)>>6)
401190203Srpaulo#define LLDP_EXTRACT_NETWORK_POLICY_DSCP(x)           ((x)&0x003f)
402190203Srpaulo
403190203Srpaulo#define LLDP_TIA_LOCATION_DATA_FORMAT_COORDINATE_BASED  1
404190203Srpaulo#define LLDP_TIA_LOCATION_DATA_FORMAT_CIVIC_ADDRESS     2
405190203Srpaulo#define LLDP_TIA_LOCATION_DATA_FORMAT_ECS_ELIN          3
406190203Srpaulo
407190203Srpaulostatic const struct tok lldp_tia_location_data_format_values[] = {
408190203Srpaulo    { LLDP_TIA_LOCATION_DATA_FORMAT_COORDINATE_BASED, "coordinate-based LCI"},
409190203Srpaulo    { LLDP_TIA_LOCATION_DATA_FORMAT_CIVIC_ADDRESS, "civic address LCI"},
410190203Srpaulo    { LLDP_TIA_LOCATION_DATA_FORMAT_ECS_ELIN, "ECS ELIN"},
411190203Srpaulo    { 0, NULL}
412190203Srpaulo};
413190203Srpaulo
414190203Srpaulo#define LLDP_TIA_LOCATION_DATUM_WGS_84          1
415190203Srpaulo#define LLDP_TIA_LOCATION_DATUM_NAD_83_NAVD_88  2
416190203Srpaulo#define LLDP_TIA_LOCATION_DATUM_NAD_83_MLLW     3
417190203Srpaulo
418190203Srpaulostatic const struct tok lldp_tia_location_datum_type_values[] = {
419190203Srpaulo    { LLDP_TIA_LOCATION_DATUM_WGS_84, "World Geodesic System 1984"},
420190203Srpaulo    { LLDP_TIA_LOCATION_DATUM_NAD_83_NAVD_88, "North American Datum 1983 (NAVD88)"},
421190203Srpaulo    { LLDP_TIA_LOCATION_DATUM_NAD_83_MLLW, "North American Datum 1983 (MLLW)"},
422190203Srpaulo    { 0, NULL}
423190203Srpaulo};
424190203Srpaulo
425190203Srpaulo#define LLDP_TIA_POWER_SOURCE_PSE               1
426190203Srpaulo#define LLDP_TIA_POWER_SOURCE_LOCAL             2
427190203Srpaulo#define LLDP_TIA_POWER_SOURCE_PSE_AND_LOCAL     3
428190203Srpaulo
429190203Srpaulostatic const struct tok lldp_tia_power_source_values[] = {
430190203Srpaulo    { LLDP_TIA_POWER_SOURCE_PSE, "PSE - primary power source"},
431190203Srpaulo    { LLDP_TIA_POWER_SOURCE_LOCAL, "local - backup power source"},
432190203Srpaulo    { LLDP_TIA_POWER_SOURCE_PSE_AND_LOCAL, "PSE+local - reserved"},
433190203Srpaulo    { 0, NULL}
434190203Srpaulo};
435190203Srpaulo
436190203Srpaulo#define LLDP_TIA_POWER_PRIORITY_CRITICAL        1
437190203Srpaulo#define LLDP_TIA_POWER_PRIORITY_HIGH            2
438190203Srpaulo#define LLDP_TIA_POWER_PRIORITY_LOW             3
439190203Srpaulo
440190203Srpaulostatic const struct tok lldp_tia_power_priority_values[] = {
441190203Srpaulo    { LLDP_TIA_POWER_PRIORITY_CRITICAL, "critical"},
442190203Srpaulo    { LLDP_TIA_POWER_PRIORITY_HIGH, "high"},
443190203Srpaulo    { LLDP_TIA_POWER_PRIORITY_LOW, "low"},
444190203Srpaulo    { 0, NULL}
445190203Srpaulo};
446190203Srpaulo
447190203Srpaulo#define LLDP_TIA_POWER_VAL_MAX               1024
448190203Srpaulo
449190203Srpaulostatic const struct tok lldp_tia_inventory_values[] = {
450190203Srpaulo    { LLDP_PRIVATE_TIA_SUBTYPE_INVENTORY_HARDWARE_REV, "Hardware revision" },
451190203Srpaulo    { LLDP_PRIVATE_TIA_SUBTYPE_INVENTORY_FIRMWARE_REV, "Firmware revision" },
452190203Srpaulo    { LLDP_PRIVATE_TIA_SUBTYPE_INVENTORY_SOFTWARE_REV, "Software revision" },
453190203Srpaulo    { LLDP_PRIVATE_TIA_SUBTYPE_INVENTORY_SERIAL_NUMBER, "Serial number" },
454190203Srpaulo    { LLDP_PRIVATE_TIA_SUBTYPE_INVENTORY_MANUFACTURER_NAME, "Manufacturer name" },
455190203Srpaulo    { LLDP_PRIVATE_TIA_SUBTYPE_INVENTORY_MODEL_NAME, "Model name" },
456190203Srpaulo    { LLDP_PRIVATE_TIA_SUBTYPE_INVENTORY_ASSET_ID, "Asset ID" },
457190203Srpaulo    { 0, NULL}
458190203Srpaulo};
459190203Srpaulo
460190203Srpaulo/*
461190203Srpaulo * From RFC 3636 - ifMauAutoNegCapAdvertisedBits
462190203Srpaulo */
463190203Srpaulo#define	 LLDP_MAU_PMD_OTHER			(1 <<  15)
464190203Srpaulo#define	 LLDP_MAU_PMD_10BASE_T			(1 <<  14)
465190203Srpaulo#define	 LLDP_MAU_PMD_10BASE_T_FD		(1 <<  13)
466190203Srpaulo#define	 LLDP_MAU_PMD_100BASE_T4		(1 <<  12)
467190203Srpaulo#define	 LLDP_MAU_PMD_100BASE_TX		(1 <<  11)
468190203Srpaulo#define	 LLDP_MAU_PMD_100BASE_TX_FD		(1 <<  10)
469190203Srpaulo#define	 LLDP_MAU_PMD_100BASE_T2		(1 <<  9)
470190203Srpaulo#define	 LLDP_MAU_PMD_100BASE_T2_FD		(1 <<  8)
471190203Srpaulo#define	 LLDP_MAU_PMD_FDXPAUSE			(1 <<  7)
472190203Srpaulo#define	 LLDP_MAU_PMD_FDXAPAUSE			(1 <<  6)
473190203Srpaulo#define	 LLDP_MAU_PMD_FDXSPAUSE			(1 <<  5)
474190203Srpaulo#define	 LLDP_MAU_PMD_FDXBPAUSE			(1 <<  4)
475190203Srpaulo#define	 LLDP_MAU_PMD_1000BASE_X		(1 <<  3)
476190203Srpaulo#define	 LLDP_MAU_PMD_1000BASE_X_FD		(1 <<  2)
477190203Srpaulo#define	 LLDP_MAU_PMD_1000BASE_T		(1 <<  1)
478190203Srpaulo#define	 LLDP_MAU_PMD_1000BASE_T_FD		(1 <<  0)
479190203Srpaulo
480190203Srpaulostatic const struct tok lldp_pmd_capability_values[] = {
481190203Srpaulo    { LLDP_MAU_PMD_10BASE_T,		"10BASE-T hdx"},
482190203Srpaulo    { LLDP_MAU_PMD_10BASE_T_FD,	        "10BASE-T fdx"},
483190203Srpaulo    { LLDP_MAU_PMD_100BASE_T4,		"100BASE-T4"},
484190203Srpaulo    { LLDP_MAU_PMD_100BASE_TX,		"100BASE-TX hdx"},
485190203Srpaulo    { LLDP_MAU_PMD_100BASE_TX_FD,	"100BASE-TX fdx"},
486190203Srpaulo    { LLDP_MAU_PMD_100BASE_T2,		"100BASE-T2 hdx"},
487190203Srpaulo    { LLDP_MAU_PMD_100BASE_T2_FD,	"100BASE-T2 fdx"},
488190203Srpaulo    { LLDP_MAU_PMD_FDXPAUSE,		"Pause for fdx links"},
489190203Srpaulo    { LLDP_MAU_PMD_FDXAPAUSE,		"Asym PAUSE for fdx"},
490190203Srpaulo    { LLDP_MAU_PMD_FDXSPAUSE,		"Sym PAUSE for fdx"},
491190203Srpaulo    { LLDP_MAU_PMD_FDXBPAUSE,		"Asym and Sym PAUSE for fdx"},
492190203Srpaulo    { LLDP_MAU_PMD_1000BASE_X,		"1000BASE-{X LX SX CX} hdx"},
493190203Srpaulo    { LLDP_MAU_PMD_1000BASE_X_FD,	"1000BASE-{X LX SX CX} fdx"},
494190203Srpaulo    { LLDP_MAU_PMD_1000BASE_T,		"1000BASE-T hdx"},
495190203Srpaulo    { LLDP_MAU_PMD_1000BASE_T_FD,	"1000BASE-T fdx"},
496190203Srpaulo    { 0, NULL}
497190203Srpaulo};
498190203Srpaulo
499190203Srpaulo#define	LLDP_MDI_PORT_CLASS			(1 <<  0)
500190203Srpaulo#define	LLDP_MDI_POWER_SUPPORT			(1 <<  1)
501190203Srpaulo#define LLDP_MDI_POWER_STATE			(1 <<  2)
502190203Srpaulo#define LLDP_MDI_PAIR_CONTROL_ABILITY		(1 <<  3)
503190203Srpaulo
504190203Srpaulostatic const struct tok lldp_mdi_values[] = {
505190203Srpaulo    { LLDP_MDI_PORT_CLASS, 		"PSE"},
506190203Srpaulo    { LLDP_MDI_POWER_SUPPORT, 		"supported"},
507190203Srpaulo    { LLDP_MDI_POWER_STATE, 		"enabled"},
508190203Srpaulo    { LLDP_MDI_PAIR_CONTROL_ABILITY, 	"can be controlled"},
509190203Srpaulo    { 0, NULL}
510190203Srpaulo};
511190203Srpaulo
512190203Srpaulo#define LLDP_MDI_PSE_PORT_POWER_PAIRS_SIGNAL	1
513190203Srpaulo#define LLDP_MDI_PSE_PORT_POWER_PAIRS_SPARE	2
514190203Srpaulo
515190203Srpaulostatic const struct tok lldp_mdi_power_pairs_values[] = {
516190203Srpaulo    { LLDP_MDI_PSE_PORT_POWER_PAIRS_SIGNAL,	"signal"},
517190203Srpaulo    { LLDP_MDI_PSE_PORT_POWER_PAIRS_SPARE,	"spare"},
518190203Srpaulo    { 0, NULL}
519190203Srpaulo};
520190203Srpaulo
521190203Srpaulo#define LLDP_MDI_POWER_CLASS0		1
522190203Srpaulo#define LLDP_MDI_POWER_CLASS1		2
523190203Srpaulo#define LLDP_MDI_POWER_CLASS2		3
524190203Srpaulo#define LLDP_MDI_POWER_CLASS3		4
525190203Srpaulo#define LLDP_MDI_POWER_CLASS4		5
526190203Srpaulo
527190203Srpaulostatic const struct tok lldp_mdi_power_class_values[] = {
528190203Srpaulo    { LLDP_MDI_POWER_CLASS0,     "class0"},
529190203Srpaulo    { LLDP_MDI_POWER_CLASS1,     "class1"},
530190203Srpaulo    { LLDP_MDI_POWER_CLASS2,     "class2"},
531190203Srpaulo    { LLDP_MDI_POWER_CLASS3,     "class3"},
532190203Srpaulo    { LLDP_MDI_POWER_CLASS4,     "class4"},
533190203Srpaulo    { 0, NULL}
534190203Srpaulo};
535190203Srpaulo
536190203Srpaulo#define LLDP_AGGREGATION_CAPABILTIY     (1 <<  0)
537190203Srpaulo#define LLDP_AGGREGATION_STATUS         (1 <<  1)
538190203Srpaulo
539190203Srpaulostatic const struct tok lldp_aggregation_values[] = {
540190203Srpaulo    { LLDP_AGGREGATION_CAPABILTIY, "supported"},
541190203Srpaulo    { LLDP_AGGREGATION_STATUS, "enabled"},
542190203Srpaulo    { 0, NULL}
543190203Srpaulo};
544190203Srpaulo
545190203Srpaulo/*
546235530Sdelphij * DCBX protocol subtypes.
547235530Sdelphij */
548235530Sdelphij#define LLDP_DCBX_SUBTYPE_1                1
549235530Sdelphij#define LLDP_DCBX_SUBTYPE_2                2
550235530Sdelphij
551235530Sdelphijstatic const struct tok lldp_dcbx_subtype_values[] = {
552235530Sdelphij    { LLDP_DCBX_SUBTYPE_1, "DCB Capability Exchange Protocol Rev 1" },
553235530Sdelphij    { LLDP_DCBX_SUBTYPE_2, "DCB Capability Exchange Protocol Rev 1.01" },
554235530Sdelphij    { 0, NULL}
555235530Sdelphij};
556235530Sdelphij
557235530Sdelphij#define LLDP_DCBX_CONTROL_TLV                1
558235530Sdelphij#define LLDP_DCBX_PRIORITY_GROUPS_TLV        2
559235530Sdelphij#define LLDP_DCBX_PRIORITY_FLOW_CONTROL_TLV  3
560235530Sdelphij#define LLDP_DCBX_APPLICATION_TLV            4
561235530Sdelphij
562235530Sdelphij/*
563190203Srpaulo * Interface numbering subtypes.
564190203Srpaulo */
565190203Srpaulo#define LLDP_INTF_NUMB_IFX_SUBTYPE         2
566190203Srpaulo#define LLDP_INTF_NUMB_SYSPORT_SUBTYPE     3
567190203Srpaulo
568190203Srpaulostatic const struct tok lldp_intf_numb_subtype_values[] = {
569190203Srpaulo    { LLDP_INTF_NUMB_IFX_SUBTYPE, "Interface Index" },
570190203Srpaulo    { LLDP_INTF_NUMB_SYSPORT_SUBTYPE, "System Port Number" },
571190203Srpaulo    { 0, NULL}
572190203Srpaulo};
573190203Srpaulo
574190203Srpaulo#define LLDP_INTF_NUM_LEN                  5
575190203Srpaulo
576190203Srpaulo/*
577235530Sdelphij * Print IEEE 802.1 private extensions. (802.1AB annex E)
578190203Srpaulo */
579190203Srpaulostatic int
580235530Sdelphijlldp_private_8021_print(const u_char *tptr, u_int tlv_len)
581190203Srpaulo{
582190203Srpaulo    int subtype, hexdump = FALSE;
583235530Sdelphij    u_int sublen;
584190203Srpaulo
585235530Sdelphij    if (tlv_len < 4) {
586235530Sdelphij        return hexdump;
587235530Sdelphij    }
588190203Srpaulo    subtype = *(tptr+3);
589190203Srpaulo
590190203Srpaulo    printf("\n\t  %s Subtype (%u)",
591190203Srpaulo           tok2str(lldp_8021_subtype_values, "unknown", subtype),
592190203Srpaulo           subtype);
593190203Srpaulo
594190203Srpaulo    switch (subtype) {
595190203Srpaulo    case LLDP_PRIVATE_8021_SUBTYPE_PORT_VLAN_ID:
596235530Sdelphij        if (tlv_len < 6) {
597235530Sdelphij            return hexdump;
598235530Sdelphij        }
599190203Srpaulo        printf("\n\t    port vlan id (PVID): %u",
600190203Srpaulo               EXTRACT_16BITS(tptr+4));
601190203Srpaulo        break;
602190203Srpaulo    case LLDP_PRIVATE_8021_SUBTYPE_PROTOCOL_VLAN_ID:
603235530Sdelphij        if (tlv_len < 7) {
604235530Sdelphij            return hexdump;
605235530Sdelphij        }
606190203Srpaulo        printf("\n\t    port and protocol vlan id (PPVID): %u, flags [%s] (0x%02x)",
607190203Srpaulo               EXTRACT_16BITS(tptr+5),
608190203Srpaulo	       bittok2str(lldp_8021_port_protocol_id_values, "none", *(tptr+4)),
609190203Srpaulo	       *(tptr+4));
610190203Srpaulo        break;
611190203Srpaulo    case LLDP_PRIVATE_8021_SUBTYPE_VLAN_NAME:
612235530Sdelphij        if (tlv_len < 6) {
613235530Sdelphij            return hexdump;
614235530Sdelphij        }
615190203Srpaulo        printf("\n\t    vlan id (VID): %u",
616190203Srpaulo               EXTRACT_16BITS(tptr+4));
617235530Sdelphij        if (tlv_len < 7) {
618235530Sdelphij            return hexdump;
619235530Sdelphij        }
620235530Sdelphij        sublen = *(tptr+6);
621235530Sdelphij        if (tlv_len < 7+sublen) {
622235530Sdelphij            return hexdump;
623235530Sdelphij        }
624190203Srpaulo        printf("\n\t    vlan name: ");
625235530Sdelphij        safeputs((const char *)tptr+7, sublen);
626190203Srpaulo        break;
627190203Srpaulo    case LLDP_PRIVATE_8021_SUBTYPE_PROTOCOL_IDENTITY:
628235530Sdelphij        if (tlv_len < 5) {
629235530Sdelphij            return hexdump;
630235530Sdelphij        }
631235530Sdelphij        sublen = *(tptr+4);
632235530Sdelphij        if (tlv_len < 5+sublen) {
633235530Sdelphij            return hexdump;
634235530Sdelphij        }
635190203Srpaulo        printf("\n\t    protocol identity: ");
636235530Sdelphij        safeputs((const char *)tptr+5, sublen);
637190203Srpaulo        break;
638190203Srpaulo
639190203Srpaulo    default:
640190203Srpaulo        hexdump = TRUE;
641190203Srpaulo        break;
642190203Srpaulo    }
643190203Srpaulo
644190203Srpaulo    return hexdump;
645190203Srpaulo}
646190203Srpaulo
647190203Srpaulo/*
648235530Sdelphij * Print IEEE 802.3 private extensions. (802.3bc)
649190203Srpaulo */
650190203Srpaulostatic int
651235530Sdelphijlldp_private_8023_print(const u_char *tptr, u_int tlv_len)
652190203Srpaulo{
653190203Srpaulo    int subtype, hexdump = FALSE;
654190203Srpaulo
655235530Sdelphij    if (tlv_len < 4) {
656235530Sdelphij        return hexdump;
657235530Sdelphij    }
658190203Srpaulo    subtype = *(tptr+3);
659190203Srpaulo
660190203Srpaulo    printf("\n\t  %s Subtype (%u)",
661190203Srpaulo           tok2str(lldp_8023_subtype_values, "unknown", subtype),
662190203Srpaulo           subtype);
663190203Srpaulo
664190203Srpaulo    switch (subtype) {
665190203Srpaulo    case LLDP_PRIVATE_8023_SUBTYPE_MACPHY:
666235530Sdelphij        if (tlv_len < 9) {
667235530Sdelphij            return hexdump;
668235530Sdelphij        }
669190203Srpaulo        printf("\n\t    autonegotiation [%s] (0x%02x)",
670190203Srpaulo               bittok2str(lldp_8023_autonegotiation_values, "none", *(tptr+4)),
671190203Srpaulo               *(tptr+4));
672190203Srpaulo        printf("\n\t    PMD autoneg capability [%s] (0x%04x)",
673190203Srpaulo               bittok2str(lldp_pmd_capability_values,"unknown", EXTRACT_16BITS(tptr+5)),
674190203Srpaulo               EXTRACT_16BITS(tptr+5));
675190203Srpaulo        printf("\n\t    MAU type %s (0x%04x)",
676190203Srpaulo               tok2str(lldp_mau_types_values, "unknown", EXTRACT_16BITS(tptr+7)),
677190203Srpaulo               EXTRACT_16BITS(tptr+7));
678190203Srpaulo        break;
679190203Srpaulo
680190203Srpaulo    case LLDP_PRIVATE_8023_SUBTYPE_MDIPOWER:
681235530Sdelphij        if (tlv_len < 7) {
682235530Sdelphij            return hexdump;
683235530Sdelphij        }
684190203Srpaulo        printf("\n\t    MDI power support [%s], power pair %s, power class %s",
685190203Srpaulo               bittok2str(lldp_mdi_values, "none", *(tptr+4)),
686190203Srpaulo               tok2str(lldp_mdi_power_pairs_values, "unknown", *(tptr+5)),
687190203Srpaulo               tok2str(lldp_mdi_power_class_values, "unknown", *(tptr+6)));
688190203Srpaulo        break;
689190203Srpaulo
690190203Srpaulo    case LLDP_PRIVATE_8023_SUBTYPE_LINKAGGR:
691235530Sdelphij        if (tlv_len < 9) {
692235530Sdelphij            return hexdump;
693235530Sdelphij        }
694190203Srpaulo        printf("\n\t    aggregation status [%s], aggregation port ID %u",
695190203Srpaulo               bittok2str(lldp_aggregation_values, "none", *(tptr+4)),
696190203Srpaulo               EXTRACT_32BITS(tptr+5));
697190203Srpaulo        break;
698190203Srpaulo
699190203Srpaulo    case LLDP_PRIVATE_8023_SUBTYPE_MTU:
700190203Srpaulo        printf("\n\t    MTU size %u", EXTRACT_16BITS(tptr+4));
701190203Srpaulo        break;
702190203Srpaulo
703190203Srpaulo    default:
704190203Srpaulo        hexdump = TRUE;
705190203Srpaulo        break;
706190203Srpaulo    }
707190203Srpaulo
708190203Srpaulo    return hexdump;
709190203Srpaulo}
710190203Srpaulo
711190203Srpaulo/*
712190203Srpaulo * Extract 34bits of latitude/longitude coordinates.
713190203Srpaulo */
714190203Srpaulostatic u_int64_t
715190203Srpaulolldp_extract_latlon(const u_char *tptr)
716190203Srpaulo{
717190203Srpaulo    u_int64_t latlon;
718190203Srpaulo
719190203Srpaulo    latlon = *tptr & 0x3;
720190203Srpaulo    latlon = (latlon << 32) | EXTRACT_32BITS(tptr+1);
721190203Srpaulo
722190203Srpaulo    return latlon;
723190203Srpaulo}
724190203Srpaulo
725190203Srpaulo/*
726190203Srpaulo * Print private TIA extensions.
727190203Srpaulo */
728190203Srpaulostatic int
729190203Srpaulolldp_private_tia_print(const u_char *tptr, u_int tlv_len)
730190203Srpaulo{
731190203Srpaulo    int subtype, hexdump = FALSE;
732190203Srpaulo    u_int8_t location_format;
733190203Srpaulo    u_int16_t power_val;
734235530Sdelphij    u_int lci_len;
735235530Sdelphij    u_int8_t ca_type, ca_len;
736190203Srpaulo
737235530Sdelphij    if (tlv_len < 4) {
738235530Sdelphij        return hexdump;
739235530Sdelphij    }
740190203Srpaulo    subtype = *(tptr+3);
741190203Srpaulo
742190203Srpaulo    printf("\n\t  %s Subtype (%u)",
743190203Srpaulo           tok2str(lldp_tia_subtype_values, "unknown", subtype),
744190203Srpaulo           subtype);
745190203Srpaulo
746190203Srpaulo    switch (subtype) {
747190203Srpaulo    case LLDP_PRIVATE_TIA_SUBTYPE_CAPABILITIES:
748235530Sdelphij        if (tlv_len < 7) {
749235530Sdelphij            return hexdump;
750235530Sdelphij        }
751190203Srpaulo        printf("\n\t    Media capabilities [%s] (0x%04x)",
752190203Srpaulo               bittok2str(lldp_tia_capabilities_values, "none",
753190203Srpaulo                          EXTRACT_16BITS(tptr+4)), EXTRACT_16BITS(tptr+4));
754190203Srpaulo        printf("\n\t    Device type [%s] (0x%02x)",
755190203Srpaulo               tok2str(lldp_tia_device_type_values, "unknown", *(tptr+6)),
756190203Srpaulo               *(tptr+6));
757190203Srpaulo        break;
758190203Srpaulo
759190203Srpaulo    case LLDP_PRIVATE_TIA_SUBTYPE_NETWORK_POLICY:
760235530Sdelphij        if (tlv_len < 8) {
761235530Sdelphij            return hexdump;
762235530Sdelphij        }
763190203Srpaulo        printf("\n\t    Application type [%s] (0x%02x)",
764190203Srpaulo               tok2str(lldp_tia_application_type_values, "none", *(tptr+4)),
765190203Srpaulo               *(tptr+4));
766190203Srpaulo        printf(", Flags [%s]", bittok2str(
767190203Srpaulo                   lldp_tia_network_policy_bits_values, "none", *(tptr+5)));
768190203Srpaulo        printf("\n\t    Vlan id %u",
769190203Srpaulo               LLDP_EXTRACT_NETWORK_POLICY_VLAN(EXTRACT_16BITS(tptr+5)));
770190203Srpaulo        printf(", L2 priority %u",
771190203Srpaulo               LLDP_EXTRACT_NETWORK_POLICY_L2_PRIORITY(EXTRACT_16BITS(tptr+6)));
772190203Srpaulo        printf(", DSCP value %u",
773190203Srpaulo               LLDP_EXTRACT_NETWORK_POLICY_DSCP(EXTRACT_16BITS(tptr+6)));
774190203Srpaulo        break;
775190203Srpaulo
776190203Srpaulo    case LLDP_PRIVATE_TIA_SUBTYPE_LOCAL_ID:
777235530Sdelphij        if (tlv_len < 5) {
778235530Sdelphij            return hexdump;
779235530Sdelphij        }
780190203Srpaulo        location_format = *(tptr+4);
781190203Srpaulo        printf("\n\t    Location data format %s (0x%02x)",
782190203Srpaulo               tok2str(lldp_tia_location_data_format_values, "unknown", location_format),
783190203Srpaulo               location_format);
784190203Srpaulo
785190203Srpaulo        switch (location_format) {
786190203Srpaulo        case LLDP_TIA_LOCATION_DATA_FORMAT_COORDINATE_BASED:
787235530Sdelphij            if (tlv_len < 21) {
788235530Sdelphij                return hexdump;
789235530Sdelphij            }
790190203Srpaulo            printf("\n\t    Latitude resolution %u, latitude value %" PRIu64,
791190203Srpaulo                   (*(tptr+5)>>2), lldp_extract_latlon(tptr+5));
792190203Srpaulo            printf("\n\t    Longitude resolution %u, longitude value %" PRIu64,
793190203Srpaulo                   (*(tptr+10)>>2), lldp_extract_latlon(tptr+10));
794190203Srpaulo            printf("\n\t    Altitude type %s (%u)",
795190203Srpaulo                   tok2str(lldp_tia_location_altitude_type_values, "unknown",(*(tptr+15)>>4)),
796190203Srpaulo                   (*(tptr+15)>>4));
797190203Srpaulo            printf("\n\t    Altitude resolution %u, altitude value 0x%x",
798190203Srpaulo                   (EXTRACT_16BITS(tptr+15)>>6)&0x3f,
799190203Srpaulo                   ((EXTRACT_32BITS(tptr+16)&0x3fffffff)));
800190203Srpaulo            printf("\n\t    Datum %s (0x%02x)",
801190203Srpaulo                   tok2str(lldp_tia_location_datum_type_values, "unknown", *(tptr+20)),
802190203Srpaulo                   *(tptr+20));
803190203Srpaulo            break;
804190203Srpaulo
805190203Srpaulo        case LLDP_TIA_LOCATION_DATA_FORMAT_CIVIC_ADDRESS:
806235530Sdelphij            if (tlv_len < 6) {
807235530Sdelphij                return hexdump;
808235530Sdelphij            }
809190203Srpaulo            lci_len = *(tptr+5);
810235530Sdelphij            if (lci_len < 3) {
811235530Sdelphij                return hexdump;
812235530Sdelphij            }
813235530Sdelphij            if (tlv_len < 7+lci_len) {
814235530Sdelphij                return hexdump;
815235530Sdelphij            }
816190203Srpaulo            printf("\n\t    LCI length %u, LCI what %s (0x%02x), Country-code ",
817190203Srpaulo                   lci_len,
818190203Srpaulo                   tok2str(lldp_tia_location_lci_what_values, "unknown", *(tptr+6)),
819190203Srpaulo                   *(tptr+6));
820190203Srpaulo
821190203Srpaulo            /* Country code */
822190203Srpaulo            safeputs((const char *)(tptr+7), 2);
823190203Srpaulo
824190203Srpaulo            lci_len = lci_len-3;
825190203Srpaulo            tptr = tptr + 9;
826190203Srpaulo
827190203Srpaulo            /* Decode each civic address element */
828190203Srpaulo            while (lci_len > 0) {
829235530Sdelphij                if (lci_len < 2) {
830235530Sdelphij                    return hexdump;
831235530Sdelphij                }
832190203Srpaulo		ca_type = *(tptr);
833190203Srpaulo                ca_len = *(tptr+1);
834190203Srpaulo
835190203Srpaulo		tptr += 2;
836190203Srpaulo                lci_len -= 2;
837190203Srpaulo
838190203Srpaulo                printf("\n\t      CA type \'%s\' (%u), length %u: ",
839190203Srpaulo                       tok2str(lldp_tia_location_lci_catype_values, "unknown", ca_type),
840190203Srpaulo                       ca_type, ca_len);
841190203Srpaulo
842190203Srpaulo		/* basic sanity check */
843190203Srpaulo		if ( ca_type == 0 || ca_len == 0) {
844190203Srpaulo                    return hexdump;
845190203Srpaulo		}
846235530Sdelphij		if (lci_len < ca_len) {
847235530Sdelphij		    return hexdump;
848235530Sdelphij		}
849190203Srpaulo
850190203Srpaulo                safeputs((const char *)tptr, ca_len);
851190203Srpaulo                tptr += ca_len;
852190203Srpaulo                lci_len -= ca_len;
853190203Srpaulo            }
854190203Srpaulo            break;
855190203Srpaulo
856190203Srpaulo        case LLDP_TIA_LOCATION_DATA_FORMAT_ECS_ELIN:
857190203Srpaulo            printf("\n\t    ECS ELIN id ");
858190203Srpaulo            safeputs((const char *)tptr+5, tlv_len-5);
859190203Srpaulo            break;
860190203Srpaulo
861190203Srpaulo        default:
862190203Srpaulo            printf("\n\t    Location ID ");
863190203Srpaulo            print_unknown_data(tptr+5, "\n\t      ", tlv_len-5);
864190203Srpaulo        }
865190203Srpaulo        break;
866190203Srpaulo
867190203Srpaulo    case LLDP_PRIVATE_TIA_SUBTYPE_EXTENDED_POWER_MDI:
868235530Sdelphij        if (tlv_len < 7) {
869235530Sdelphij            return hexdump;
870235530Sdelphij        }
871190203Srpaulo        printf("\n\t    Power type [%s]",
872190203Srpaulo               (*(tptr+4)&0xC0>>6) ? "PD device" : "PSE device");
873190203Srpaulo        printf(", Power source [%s]",
874190203Srpaulo               tok2str(lldp_tia_power_source_values, "none", (*(tptr+4)&0x30)>>4));
875190203Srpaulo        printf("\n\t    Power priority [%s] (0x%02x)",
876190203Srpaulo               tok2str(lldp_tia_power_priority_values, "none", *(tptr+4)&0x0f),
877190203Srpaulo               *(tptr+4)&0x0f);
878190203Srpaulo        power_val = EXTRACT_16BITS(tptr+5);
879190203Srpaulo        if (power_val < LLDP_TIA_POWER_VAL_MAX) {
880190203Srpaulo            printf(", Power %.1f Watts", ((float)power_val)/10);
881190203Srpaulo        } else {
882190203Srpaulo            printf(", Power %u (Reserved)", power_val);
883190203Srpaulo        }
884190203Srpaulo        break;
885190203Srpaulo
886190203Srpaulo    case LLDP_PRIVATE_TIA_SUBTYPE_INVENTORY_HARDWARE_REV:
887190203Srpaulo    case LLDP_PRIVATE_TIA_SUBTYPE_INVENTORY_FIRMWARE_REV:
888190203Srpaulo    case LLDP_PRIVATE_TIA_SUBTYPE_INVENTORY_SOFTWARE_REV:
889190203Srpaulo    case LLDP_PRIVATE_TIA_SUBTYPE_INVENTORY_SERIAL_NUMBER:
890190203Srpaulo    case LLDP_PRIVATE_TIA_SUBTYPE_INVENTORY_MANUFACTURER_NAME:
891190203Srpaulo    case LLDP_PRIVATE_TIA_SUBTYPE_INVENTORY_MODEL_NAME:
892190203Srpaulo    case LLDP_PRIVATE_TIA_SUBTYPE_INVENTORY_ASSET_ID:
893190203Srpaulo        printf("\n\t  %s ",
894190203Srpaulo               tok2str(lldp_tia_inventory_values, "unknown", subtype));
895190203Srpaulo        safeputs((const char *)tptr+4, tlv_len-4);
896190203Srpaulo        break;
897190203Srpaulo
898190203Srpaulo    default:
899190203Srpaulo        hexdump = TRUE;
900190203Srpaulo        break;
901190203Srpaulo    }
902190203Srpaulo
903190203Srpaulo    return hexdump;
904190203Srpaulo}
905190203Srpaulo
906235530Sdelphij/*
907235530Sdelphij * Print DCBX Protocol fields (V 1.01).
908235530Sdelphij */
909235530Sdelphijstatic int
910235530Sdelphijlldp_private_dcbx_print(const u_char *pptr, u_int len)
911235530Sdelphij{
912235530Sdelphij    int subtype, hexdump = FALSE;
913235530Sdelphij    u_int8_t tval;
914235530Sdelphij    u_int16_t tlv;
915235530Sdelphij    u_int32_t i, pgval, uval;
916235530Sdelphij    u_int tlen, tlv_type, tlv_len;
917235530Sdelphij    const u_char *tptr, *mptr;
918235530Sdelphij
919235530Sdelphij    if (len < 4) {
920235530Sdelphij        return hexdump;
921235530Sdelphij    }
922235530Sdelphij    subtype = *(pptr+3);
923235530Sdelphij
924235530Sdelphij    printf("\n\t  %s Subtype (%u)",
925235530Sdelphij           tok2str(lldp_dcbx_subtype_values, "unknown", subtype),
926235530Sdelphij           subtype);
927235530Sdelphij
928235530Sdelphij    /* by passing old version */
929235530Sdelphij    if (subtype == LLDP_DCBX_SUBTYPE_1)
930235530Sdelphij	return TRUE;
931235530Sdelphij
932235530Sdelphij    tptr = pptr + 4;
933235530Sdelphij    tlen = len - 4;
934235530Sdelphij
935235530Sdelphij    while (tlen >= sizeof(tlv)) {
936235530Sdelphij
937235530Sdelphij        TCHECK2(*tptr, sizeof(tlv));
938235530Sdelphij
939235530Sdelphij        tlv = EXTRACT_16BITS(tptr);
940235530Sdelphij
941235530Sdelphij        tlv_type = LLDP_EXTRACT_TYPE(tlv);
942235530Sdelphij        tlv_len = LLDP_EXTRACT_LEN(tlv);
943235530Sdelphij        hexdump = FALSE;
944235530Sdelphij
945235530Sdelphij        tlen -= sizeof(tlv);
946235530Sdelphij        tptr += sizeof(tlv);
947235530Sdelphij
948235530Sdelphij        /* loop check */
949235530Sdelphij        if (!tlv_type || !tlv_len) {
950235530Sdelphij            break;
951235530Sdelphij        }
952235530Sdelphij
953235530Sdelphij        TCHECK2(*tptr, tlv_len);
954235530Sdelphij        if (tlen < tlv_len) {
955235530Sdelphij            goto trunc;
956235530Sdelphij        }
957235530Sdelphij
958235530Sdelphij	/* decode every tlv */
959235530Sdelphij        switch (tlv_type) {
960235530Sdelphij        case LLDP_DCBX_CONTROL_TLV:
961235530Sdelphij            if (tlv_len < 10) {
962235530Sdelphij                goto trunc;
963235530Sdelphij            }
964235530Sdelphij	    printf("\n\t    Control - Protocol Control (type 0x%x, length %d)",
965235530Sdelphij		LLDP_DCBX_CONTROL_TLV, tlv_len);
966235530Sdelphij	    printf("\n\t      Oper_Version: %d", *tptr);
967235530Sdelphij	    printf("\n\t      Max_Version: %d", *(tptr+1));
968235530Sdelphij	    printf("\n\t      Sequence Number: %d", EXTRACT_32BITS(tptr+2));
969235530Sdelphij	    printf("\n\t      Acknowledgement Number: %d",
970235530Sdelphij					EXTRACT_32BITS(tptr+6));
971235530Sdelphij	    break;
972235530Sdelphij        case LLDP_DCBX_PRIORITY_GROUPS_TLV:
973235530Sdelphij            if (tlv_len < 17) {
974235530Sdelphij                goto trunc;
975235530Sdelphij            }
976235530Sdelphij	    printf("\n\t    Feature - Priority Group (type 0x%x, length %d)",
977235530Sdelphij		LLDP_DCBX_PRIORITY_GROUPS_TLV, tlv_len);
978235530Sdelphij	    printf("\n\t      Oper_Version: %d", *tptr);
979235530Sdelphij	    printf("\n\t      Max_Version: %d", *(tptr+1));
980235530Sdelphij	    printf("\n\t      Info block(0x%02X): ", *(tptr+2));
981235530Sdelphij	    tval = *(tptr+2);
982235530Sdelphij	    printf("Enable bit: %d, Willing bit: %d, Error Bit: %d",
983235530Sdelphij		(tval &  0x80) ? 1 : 0, (tval &  0x40) ? 1 : 0,
984235530Sdelphij		(tval &  0x20) ? 1 : 0);
985235530Sdelphij	    printf("\n\t      SubType: %d", *(tptr+3));
986235530Sdelphij	    printf("\n\t      Priority Allocation");
987235530Sdelphij
988235530Sdelphij	    pgval = EXTRACT_32BITS(tptr+4);
989235530Sdelphij	    for (i = 0; i <= 7; i++) {
990235530Sdelphij		tval = *(tptr+4+(i/2));
991235530Sdelphij		printf("\n\t          PgId_%d: %d",
992235530Sdelphij			i, (pgval >> (28-4*i)) & 0xF);
993235530Sdelphij	    }
994235530Sdelphij	    printf("\n\t      Priority Group Allocation");
995235530Sdelphij	    for (i = 0; i <= 7; i++)
996235530Sdelphij		printf("\n\t          Pg percentage[%d]: %d", i, *(tptr+8+i));
997235530Sdelphij	    printf("\n\t      NumTCsSupported: %d", *(tptr+8+8));
998235530Sdelphij	    break;
999235530Sdelphij        case LLDP_DCBX_PRIORITY_FLOW_CONTROL_TLV:
1000235530Sdelphij            if (tlv_len < 6) {
1001235530Sdelphij                goto trunc;
1002235530Sdelphij            }
1003235530Sdelphij	    printf("\n\t    Feature - Priority Flow Control");
1004235530Sdelphij	    printf(" (type 0x%x, length %d)",
1005235530Sdelphij		LLDP_DCBX_PRIORITY_FLOW_CONTROL_TLV, tlv_len);
1006235530Sdelphij	    printf("\n\t      Oper_Version: %d", *tptr);
1007235530Sdelphij	    printf("\n\t      Max_Version: %d", *(tptr+1));
1008235530Sdelphij	    printf("\n\t      Info block(0x%02X): ", *(tptr+2));
1009235530Sdelphij	    tval = *(tptr+2);
1010235530Sdelphij	    printf("Enable bit: %d, Willing bit: %d, Error Bit: %d",
1011235530Sdelphij		(tval &  0x80) ? 1 : 0, (tval &  0x40) ? 1 : 0,
1012235530Sdelphij		(tval &  0x20) ? 1 : 0);
1013235530Sdelphij	    printf("\n\t      SubType: %d", *(tptr+3));
1014235530Sdelphij	    tval = *(tptr+4);
1015235530Sdelphij	    printf("\n\t      PFC Config (0x%02X)", *(tptr+4));
1016235530Sdelphij	    for (i = 0; i <= 7; i++)
1017235530Sdelphij		printf("\n\t          Priority Bit %d: %s",
1018235530Sdelphij		    i, (tval & (1 << i)) ? "Enabled" : "Disabled");
1019235530Sdelphij	    printf("\n\t      NumTCPFCSupported: %d", *(tptr+5));
1020235530Sdelphij	    break;
1021235530Sdelphij        case LLDP_DCBX_APPLICATION_TLV:
1022235530Sdelphij            if (tlv_len < 4) {
1023235530Sdelphij                goto trunc;
1024235530Sdelphij            }
1025235530Sdelphij	    printf("\n\t    Feature - Application (type 0x%x, length %d)",
1026235530Sdelphij		LLDP_DCBX_APPLICATION_TLV, tlv_len);
1027235530Sdelphij	    printf("\n\t      Oper_Version: %d", *tptr);
1028235530Sdelphij	    printf("\n\t      Max_Version: %d", *(tptr+1));
1029235530Sdelphij	    printf("\n\t      Info block(0x%02X): ", *(tptr+2));
1030235530Sdelphij	    tval = *(tptr+2);
1031235530Sdelphij	    printf("Enable bit: %d, Willing bit: %d, Error Bit: %d",
1032235530Sdelphij		(tval &  0x80) ? 1 : 0, (tval &  0x40) ? 1 : 0,
1033235530Sdelphij		(tval &  0x20) ? 1 : 0);
1034235530Sdelphij	    printf("\n\t      SubType: %d", *(tptr+3));
1035235530Sdelphij	    tval = tlv_len - 4;
1036235530Sdelphij	    mptr = tptr + 4;
1037235530Sdelphij	    while (tval >= 6) {
1038235530Sdelphij		printf("\n\t      Application Value");
1039235530Sdelphij		printf("\n\t          Application Protocol ID: 0x%04x",
1040235530Sdelphij			EXTRACT_16BITS(mptr));
1041235530Sdelphij		uval = EXTRACT_24BITS(mptr+2);
1042235530Sdelphij		printf("\n\t          SF (0x%x) Application Protocol ID is %s",
1043235530Sdelphij			(uval >> 22),
1044235530Sdelphij			(uval >> 22) ? "Socket Number" : "L2 EtherType");
1045235530Sdelphij		printf("\n\t          OUI: 0x%06x", uval & 0x3fffff);
1046235530Sdelphij		printf("\n\t          User Priority Map: 0x%02x", *(mptr+5));
1047235530Sdelphij		tval = tval - 6;
1048235530Sdelphij		mptr = mptr + 6;
1049235530Sdelphij	    }
1050235530Sdelphij	    break;
1051235530Sdelphij	default:
1052235530Sdelphij	    hexdump = TRUE;
1053235530Sdelphij	    break;
1054235530Sdelphij	}
1055235530Sdelphij
1056235530Sdelphij        /* do we also want to see a hex dump ? */
1057235530Sdelphij        if (vflag > 1 || (vflag && hexdump)) {
1058235530Sdelphij	    print_unknown_data(tptr,"\n\t    ", tlv_len);
1059235530Sdelphij        }
1060235530Sdelphij
1061235530Sdelphij        tlen -= tlv_len;
1062235530Sdelphij        tptr += tlv_len;
1063235530Sdelphij    }
1064235530Sdelphij
1065235530Sdelphij trunc:
1066235530Sdelphij    return hexdump;
1067235530Sdelphij}
1068235530Sdelphij
1069190203Srpaulostatic char *
1070235530Sdelphijlldp_network_addr_print(const u_char *tptr, u_int len) {
1071190203Srpaulo
1072190203Srpaulo    u_int8_t af;
1073190203Srpaulo    static char buf[BUFSIZE];
1074190203Srpaulo    const char * (*pfunc)(const u_char *);
1075190203Srpaulo
1076235530Sdelphij    if (len < 1)
1077235530Sdelphij      return NULL;
1078235530Sdelphij    len--;
1079190203Srpaulo    af = *tptr;
1080190203Srpaulo    switch (af) {
1081190203Srpaulo    case AFNUM_INET:
1082235530Sdelphij        if (len < 4)
1083235530Sdelphij          return NULL;
1084190203Srpaulo        pfunc = getname;
1085190203Srpaulo        break;
1086190203Srpaulo#ifdef INET6
1087190203Srpaulo    case AFNUM_INET6:
1088235530Sdelphij        if (len < 16)
1089235530Sdelphij          return NULL;
1090190203Srpaulo        pfunc = getname6;
1091190203Srpaulo        break;
1092190203Srpaulo#endif
1093190203Srpaulo    case AFNUM_802:
1094235530Sdelphij        if (len < 6)
1095235530Sdelphij          return NULL;
1096190203Srpaulo        pfunc = etheraddr_string;
1097190203Srpaulo        break;
1098190203Srpaulo    default:
1099190203Srpaulo        pfunc = NULL;
1100190203Srpaulo        break;
1101190203Srpaulo    }
1102190203Srpaulo
1103190203Srpaulo    if (!pfunc) {
1104190203Srpaulo        snprintf(buf, sizeof(buf), "AFI %s (%u), no AF printer !",
1105190203Srpaulo                 tok2str(af_values, "Unknown", af), af);
1106190203Srpaulo    } else {
1107190203Srpaulo        snprintf(buf, sizeof(buf), "AFI %s (%u): %s",
1108190203Srpaulo                 tok2str(af_values, "Unknown", af), af, (*pfunc)(tptr+1));
1109190203Srpaulo    }
1110190203Srpaulo
1111190203Srpaulo    return buf;
1112190203Srpaulo}
1113190203Srpaulo
1114190203Srpaulostatic int
1115190203Srpaulolldp_mgmt_addr_tlv_print(const u_char *pptr, u_int len) {
1116190203Srpaulo
1117190203Srpaulo    u_int8_t mgmt_addr_len, intf_num_subtype, oid_len;
1118190203Srpaulo    const u_char *tptr;
1119190203Srpaulo    u_int tlen;
1120235530Sdelphij    char *mgmt_addr;
1121190203Srpaulo
1122190203Srpaulo    tlen = len;
1123190203Srpaulo    tptr = pptr;
1124190203Srpaulo
1125235530Sdelphij    if (tlen < 1) {
1126235530Sdelphij        return 0;
1127235530Sdelphij    }
1128190203Srpaulo    mgmt_addr_len = *tptr++;
1129190203Srpaulo    tlen--;
1130190203Srpaulo
1131190203Srpaulo    if (tlen < mgmt_addr_len) {
1132190203Srpaulo        return 0;
1133190203Srpaulo    }
1134190203Srpaulo
1135235530Sdelphij    mgmt_addr = lldp_network_addr_print(tptr, mgmt_addr_len);
1136235530Sdelphij    if (mgmt_addr == NULL) {
1137235530Sdelphij        return 0;
1138235530Sdelphij    }
1139190203Srpaulo    printf("\n\t  Management Address length %u, %s",
1140235530Sdelphij           mgmt_addr_len, mgmt_addr);
1141190203Srpaulo    tptr += mgmt_addr_len;
1142190203Srpaulo    tlen -= mgmt_addr_len;
1143190203Srpaulo
1144190203Srpaulo    if (tlen < LLDP_INTF_NUM_LEN) {
1145190203Srpaulo        return 0;
1146190203Srpaulo    }
1147190203Srpaulo
1148190203Srpaulo    intf_num_subtype = *tptr;
1149190203Srpaulo    printf("\n\t  %s Interface Numbering (%u): %u",
1150190203Srpaulo           tok2str(lldp_intf_numb_subtype_values, "Unknown", intf_num_subtype),
1151190203Srpaulo           intf_num_subtype,
1152190203Srpaulo           EXTRACT_32BITS(tptr+1));
1153190203Srpaulo
1154190203Srpaulo    tptr += LLDP_INTF_NUM_LEN;
1155190203Srpaulo    tlen -= LLDP_INTF_NUM_LEN;
1156190203Srpaulo
1157190203Srpaulo    /*
1158190203Srpaulo     * The OID is optional.
1159190203Srpaulo     */
1160190203Srpaulo    if (tlen) {
1161190203Srpaulo        oid_len = *tptr;
1162190203Srpaulo
1163235530Sdelphij        if (tlen < oid_len) {
1164235530Sdelphij            return 0;
1165235530Sdelphij        }
1166190203Srpaulo        if (oid_len) {
1167190203Srpaulo            printf("\n\t  OID length %u", oid_len);
1168190203Srpaulo            safeputs((const char *)tptr+1, oid_len);
1169190203Srpaulo        }
1170190203Srpaulo    }
1171190203Srpaulo
1172190203Srpaulo    return 1;
1173190203Srpaulo}
1174190203Srpaulo
1175190203Srpaulovoid
1176190203Srpaulolldp_print(register const u_char *pptr, register u_int len) {
1177190203Srpaulo
1178190203Srpaulo    u_int8_t subtype;
1179190203Srpaulo    u_int16_t tlv, cap, ena_cap;
1180190203Srpaulo    u_int oui, tlen, hexdump, tlv_type, tlv_len;
1181190203Srpaulo    const u_char *tptr;
1182235530Sdelphij    char *network_addr;
1183190203Srpaulo
1184190203Srpaulo    tptr = pptr;
1185190203Srpaulo    tlen = len;
1186190203Srpaulo
1187251158Sdelphij    printf("LLDP, length %u", len);
1188190203Srpaulo
1189190203Srpaulo    while (tlen >= sizeof(tlv)) {
1190190203Srpaulo
1191190203Srpaulo        TCHECK2(*tptr, sizeof(tlv));
1192190203Srpaulo
1193190203Srpaulo        tlv = EXTRACT_16BITS(tptr);
1194190203Srpaulo
1195190203Srpaulo        tlv_type = LLDP_EXTRACT_TYPE(tlv);
1196190203Srpaulo        tlv_len = LLDP_EXTRACT_LEN(tlv);
1197190203Srpaulo        hexdump = FALSE;
1198190203Srpaulo
1199190203Srpaulo        tlen -= sizeof(tlv);
1200190203Srpaulo        tptr += sizeof(tlv);
1201190203Srpaulo
1202190203Srpaulo        if (vflag) {
1203190203Srpaulo            printf("\n\t%s TLV (%u), length %u",
1204190203Srpaulo                   tok2str(lldp_tlv_values, "Unknown", tlv_type),
1205190203Srpaulo                   tlv_type, tlv_len);
1206190203Srpaulo        }
1207190203Srpaulo
1208190203Srpaulo        /* infinite loop check */
1209190203Srpaulo        if (!tlv_type || !tlv_len) {
1210190203Srpaulo            break;
1211190203Srpaulo        }
1212190203Srpaulo
1213190203Srpaulo        TCHECK2(*tptr, tlv_len);
1214235530Sdelphij        if (tlen < tlv_len) {
1215235530Sdelphij            goto trunc;
1216235530Sdelphij        }
1217190203Srpaulo
1218190203Srpaulo        switch (tlv_type) {
1219190203Srpaulo
1220190203Srpaulo        case LLDP_CHASSIS_ID_TLV:
1221190203Srpaulo            if (vflag) {
1222235530Sdelphij                if (tlv_len < 2) {
1223235530Sdelphij                    goto trunc;
1224235530Sdelphij                }
1225190203Srpaulo                subtype = *tptr;
1226190203Srpaulo                printf("\n\t  Subtype %s (%u): ",
1227190203Srpaulo                       tok2str(lldp_chassis_subtype_values, "Unknown", subtype),
1228190203Srpaulo                       subtype);
1229190203Srpaulo
1230190203Srpaulo                switch (subtype) {
1231190203Srpaulo                case LLDP_CHASSIS_MAC_ADDR_SUBTYPE:
1232235530Sdelphij                    if (tlv_len < 1+6) {
1233235530Sdelphij                        goto trunc;
1234235530Sdelphij                    }
1235190203Srpaulo                    printf("%s", etheraddr_string(tptr+1));
1236190203Srpaulo                    break;
1237190203Srpaulo
1238190203Srpaulo                case LLDP_CHASSIS_INTF_NAME_SUBTYPE: /* fall through */
1239190203Srpaulo                case LLDP_CHASSIS_LOCAL_SUBTYPE:
1240190203Srpaulo                case LLDP_CHASSIS_CHASSIS_COMP_SUBTYPE:
1241190203Srpaulo                case LLDP_CHASSIS_INTF_ALIAS_SUBTYPE:
1242190203Srpaulo                case LLDP_CHASSIS_PORT_COMP_SUBTYPE:
1243190203Srpaulo                    safeputs((const char *)tptr+1, tlv_len-1);
1244190203Srpaulo                    break;
1245190203Srpaulo
1246190203Srpaulo                case LLDP_CHASSIS_NETWORK_ADDR_SUBTYPE:
1247235530Sdelphij                    network_addr = lldp_network_addr_print(tptr+1, tlv_len-1);
1248235530Sdelphij                    if (network_addr == NULL) {
1249235530Sdelphij                        goto trunc;
1250235530Sdelphij                    }
1251235530Sdelphij                    printf("%s", network_addr);
1252190203Srpaulo                    break;
1253190203Srpaulo
1254190203Srpaulo                default:
1255190203Srpaulo                    hexdump = TRUE;
1256190203Srpaulo                    break;
1257190203Srpaulo                }
1258190203Srpaulo            }
1259190203Srpaulo            break;
1260190203Srpaulo
1261190203Srpaulo        case LLDP_PORT_ID_TLV:
1262190203Srpaulo            if (vflag) {
1263235530Sdelphij                if (tlv_len < 2) {
1264235530Sdelphij                    goto trunc;
1265235530Sdelphij                }
1266190203Srpaulo                subtype = *tptr;
1267190203Srpaulo                printf("\n\t  Subtype %s (%u): ",
1268190203Srpaulo                       tok2str(lldp_port_subtype_values, "Unknown", subtype),
1269190203Srpaulo                       subtype);
1270190203Srpaulo
1271190203Srpaulo                switch (subtype) {
1272190203Srpaulo                case LLDP_PORT_MAC_ADDR_SUBTYPE:
1273235530Sdelphij                    if (tlv_len < 1+6) {
1274235530Sdelphij                        goto trunc;
1275235530Sdelphij                    }
1276190203Srpaulo                    printf("%s", etheraddr_string(tptr+1));
1277190203Srpaulo                    break;
1278190203Srpaulo
1279190203Srpaulo                case LLDP_PORT_INTF_NAME_SUBTYPE: /* fall through */
1280190203Srpaulo                case LLDP_PORT_LOCAL_SUBTYPE:
1281190203Srpaulo                case LLDP_PORT_AGENT_CIRC_ID_SUBTYPE:
1282190203Srpaulo                case LLDP_PORT_INTF_ALIAS_SUBTYPE:
1283190203Srpaulo                case LLDP_PORT_PORT_COMP_SUBTYPE:
1284190203Srpaulo                    safeputs((const char *)tptr+1, tlv_len-1);
1285190203Srpaulo                    break;
1286190203Srpaulo
1287190203Srpaulo                case LLDP_PORT_NETWORK_ADDR_SUBTYPE:
1288235530Sdelphij                    network_addr = lldp_network_addr_print(tptr+1, tlv_len-1);
1289235530Sdelphij                    if (network_addr == NULL) {
1290235530Sdelphij                        goto trunc;
1291235530Sdelphij                    }
1292235530Sdelphij                    printf("%s", network_addr);
1293190203Srpaulo                    break;
1294190203Srpaulo
1295190203Srpaulo                default:
1296190203Srpaulo                    hexdump = TRUE;
1297190203Srpaulo                    break;
1298190203Srpaulo                }
1299190203Srpaulo            }
1300190203Srpaulo            break;
1301190203Srpaulo
1302235530Sdelphij        case LLDP_TTL_TLV:
1303190203Srpaulo            if (vflag) {
1304235530Sdelphij                if (tlv_len < 2) {
1305235530Sdelphij                    goto trunc;
1306190203Srpaulo                }
1307235530Sdelphij                printf(": TTL %us", EXTRACT_16BITS(tptr));
1308190203Srpaulo            }
1309190203Srpaulo            break;
1310190203Srpaulo
1311235530Sdelphij        case LLDP_PORT_DESCR_TLV:
1312235530Sdelphij            if (vflag) {
1313235530Sdelphij                printf(": ");
1314235530Sdelphij                safeputs((const char *)tptr, tlv_len);
1315235530Sdelphij            }
1316235530Sdelphij            break;
1317235530Sdelphij
1318235530Sdelphij        case LLDP_SYSTEM_NAME_TLV:
1319235530Sdelphij            /*
1320235530Sdelphij             * The system name is also print in non-verbose mode
1321235530Sdelphij             * similar to the CDP printer.
1322235530Sdelphij             */
1323251158Sdelphij            printf(": ");
1324251158Sdelphij            safeputs((const char *)tptr, tlv_len);
1325235530Sdelphij            break;
1326235530Sdelphij
1327235530Sdelphij        case LLDP_SYSTEM_DESCR_TLV:
1328235530Sdelphij            if (vflag) {
1329235530Sdelphij                printf("\n\t  ");
1330235530Sdelphij                safeputs((const char *)tptr, tlv_len);
1331235530Sdelphij            }
1332235530Sdelphij            break;
1333235530Sdelphij
1334190203Srpaulo        case LLDP_SYSTEM_CAP_TLV:
1335190203Srpaulo            if (vflag) {
1336235530Sdelphij                /*
1337235530Sdelphij                 * XXX - IEEE Std 802.1AB-2009 says the first octet
1338235530Sdelphij                 * if a chassis ID subtype, with the system
1339235530Sdelphij                 * capabilities and enabled capabilities following
1340235530Sdelphij                 * it.
1341235530Sdelphij                 */
1342235530Sdelphij                if (tlv_len < 4) {
1343235530Sdelphij                    goto trunc;
1344235530Sdelphij                }
1345190203Srpaulo                cap = EXTRACT_16BITS(tptr);
1346190203Srpaulo                ena_cap = EXTRACT_16BITS(tptr+2);
1347190203Srpaulo                printf("\n\t  System  Capabilities [%s] (0x%04x)",
1348190203Srpaulo                       bittok2str(lldp_cap_values, "none", cap), cap);
1349190203Srpaulo                printf("\n\t  Enabled Capabilities [%s] (0x%04x)",
1350190203Srpaulo                       bittok2str(lldp_cap_values, "none", ena_cap), ena_cap);
1351190203Srpaulo            }
1352190203Srpaulo            break;
1353190203Srpaulo
1354190203Srpaulo        case LLDP_MGMT_ADDR_TLV:
1355190203Srpaulo            if (vflag) {
1356235530Sdelphij                if (!lldp_mgmt_addr_tlv_print(tptr, tlv_len)) {
1357190203Srpaulo                    goto trunc;
1358190203Srpaulo                }
1359190203Srpaulo            }
1360190203Srpaulo            break;
1361190203Srpaulo
1362235530Sdelphij        case LLDP_PRIVATE_TLV:
1363235530Sdelphij            if (vflag) {
1364235530Sdelphij                if (tlv_len < 3) {
1365235530Sdelphij                    goto trunc;
1366235530Sdelphij                }
1367235530Sdelphij                oui = EXTRACT_24BITS(tptr);
1368235530Sdelphij                printf(": OUI %s (0x%06x)", tok2str(oui_values, "Unknown", oui), oui);
1369235530Sdelphij
1370235530Sdelphij                switch (oui) {
1371235530Sdelphij                case OUI_IEEE_8021_PRIVATE:
1372235530Sdelphij                    hexdump = lldp_private_8021_print(tptr, tlv_len);
1373235530Sdelphij                    break;
1374235530Sdelphij                case OUI_IEEE_8023_PRIVATE:
1375235530Sdelphij                    hexdump = lldp_private_8023_print(tptr, tlv_len);
1376235530Sdelphij                    break;
1377235530Sdelphij                case OUI_TIA:
1378235530Sdelphij                    hexdump = lldp_private_tia_print(tptr, tlv_len);
1379235530Sdelphij                    break;
1380235530Sdelphij                case OUI_DCBX:
1381235530Sdelphij                    hexdump = lldp_private_dcbx_print(tptr, tlv_len);
1382235530Sdelphij                    break;
1383235530Sdelphij                default:
1384235530Sdelphij                    hexdump = TRUE;
1385235530Sdelphij                    break;
1386235530Sdelphij                }
1387235530Sdelphij            }
1388235530Sdelphij            break;
1389235530Sdelphij
1390190203Srpaulo        default:
1391190203Srpaulo            hexdump = TRUE;
1392190203Srpaulo            break;
1393190203Srpaulo        }
1394190203Srpaulo
1395190203Srpaulo        /* do we also want to see a hex dump ? */
1396190203Srpaulo        if (vflag > 1 || (vflag && hexdump)) {
1397190203Srpaulo            print_unknown_data(tptr,"\n\t  ", tlv_len);
1398190203Srpaulo        }
1399190203Srpaulo
1400190203Srpaulo        tlen -= tlv_len;
1401190203Srpaulo        tptr += tlv_len;
1402190203Srpaulo    }
1403190203Srpaulo    return;
1404190203Srpaulo trunc:
1405190203Srpaulo    printf("\n\t[|LLDP]");
1406190203Srpaulo}
1407190203Srpaulo
1408190203Srpaulo/*
1409190203Srpaulo * Local Variables:
1410190203Srpaulo * c-style: whitesmith
1411190203Srpaulo * c-basic-offset: 4
1412190203Srpaulo * End:
1413190203Srpaulo */
1414