Fix for bug 5422:
[obnox/wireshark/wip.git] / epan / dissectors / packet-lldp.c
1 /* packet-lldp.c
2  * Routines for LLDP dissection
3  * By Juan Gonzalez <juan.gonzalez@pikatech.com>
4  * Copyright 2005 MITEL
5  *
6  * July 2005
7  * Modified by: Brian Bogora <brian_bogora@mitel.com>
8  *
9  * $Id$
10  *
11  * Wireshark - Network traffic analyzer
12  * By Gerald Combs <gerald@wireshark.org>
13  * Copyright 1998 Gerald Combs
14  *
15  * This program is free software; you can redistribute it and/or
16  * modify it under the terms of the GNU General Public License
17  * as published by the Free Software Foundation; either version 2
18  * of the License, or (at your option) any later version.
19  *
20  * This program is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23  * GNU General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public License
26  * along with this program; if not, write to the Free Software
27  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
28  */
29
30 #ifdef HAVE_CONFIG_H
31 # include "config.h"
32 #endif
33
34 #include <gmodule.h>
35 #include <glib.h>
36
37 #include <epan/packet.h>
38 #include <epan/emem.h>
39 #include <epan/etypes.h>
40 #include <epan/oui.h>
41 #include <epan/afn.h>
42
43 /* TLV Types */
44 #define END_OF_LLDPDU_TLV_TYPE          0x00    /* Mandatory */
45 #define CHASSIS_ID_TLV_TYPE             0x01    /* Mandatory */
46 #define PORT_ID_TLV_TYPE                0x02    /* Mandatory */
47 #define TIME_TO_LIVE_TLV_TYPE           0x03    /* Mandatory */
48 #define PORT_DESCRIPTION_TLV_TYPE       0x04
49 #define SYSTEM_NAME_TLV_TYPE            0x05
50 #define SYSTEM_DESCRIPTION_TLV_TYPE     0x06
51 #define SYSTEM_CAPABILITIES_TLV_TYPE    0x07
52 #define MANAGEMENT_ADDR_TLV_TYPE        0x08
53 #define ORGANIZATION_SPECIFIC_TLV_TYPE  0x7F
54
55 /* Masks */
56 #define TLV_TYPE_MASK           0xFE00
57 #define TLV_TYPE(value)         (((value) & TLV_TYPE_MASK) >> 9)
58 #define TLV_INFO_LEN_MASK       0x01FF
59 #define TLV_INFO_LEN(value)     ((value) & TLV_INFO_LEN_MASK)
60
61 /* Initialize the protocol and registered fields */
62 static int proto_lldp = -1;
63 static int hf_lldp_tlv_type = -1;
64 static int hf_lldp_tlv_len = -1;
65 static int hf_chassis_id_subtype = -1;
66 static int hf_chassis_id = -1;
67 static int hf_chassis_id_mac = -1;
68 static int hf_chassis_id_ip4 = -1;
69 static int hf_chassis_id_ip6 = -1;
70 static int hf_port_id_subtype = -1;
71 static int hf_port_id_mac = -1;
72 static int hf_lldp_network_address_family = -1;
73 static int hf_port_id_ip4 = -1;
74 static int hf_port_id_ip6 = -1;
75 static int hf_time_to_live = -1;
76 static int hf_mgn_addr_ipv4 = -1;
77 static int hf_mgn_addr_ipv6 = -1;
78 static int hf_mgn_addr_hex = -1;
79 static int hf_mgn_obj_id = -1;
80 static int hf_org_spc_oui = -1;
81 static int hf_ieee_802_1_subtype = -1;
82 static int hf_ieee_802_3_subtype = -1;
83 static int hf_media_tlv_subtype = -1;
84 static int hf_profinet_tlv_subtype = -1;
85 static int hf_profinet_class2_port_status = -1;
86 static int hf_profinet_class3_port_status = -1;
87 static int hf_profinet_port_rx_delay_local = -1;
88 static int hf_profinet_port_rx_delay_remote = -1;
89 static int hf_profinet_port_tx_delay_local = -1;
90 static int hf_profinet_port_tx_delay_remote = -1;
91 static int hf_profinet_cable_delay_local = -1;
92 static int hf_profinet_mrp_domain_uuid = -1;
93 static int hf_profinet_mrrt_port_status = -1;
94 static int hf_profinet_cm_mac = -1;
95 static int hf_profinet_master_source_address = -1;
96 static int hf_profinet_subdomain_uuid = -1;
97 static int hf_profinet_ir_data_uuid = -1;
98 static int hf_profinet_length_of_period_valid = -1;
99 static int hf_profinet_length_of_period_length = -1;
100 static int hf_profinet_red_period_begin_valid = -1;
101 static int hf_profinet_red_period_begin_offset = -1;
102 static int hf_profinet_orange_period_begin_valid = -1;
103 static int hf_profinet_orange_period_begin_offset = -1;
104 static int hf_profinet_green_period_begin_valid = -1;
105 static int hf_profinet_green_period_begin_offset = -1;
106 static int hf_unknown_subtype = -1;
107
108 /* Initialize the subtree pointers */
109 static gint ett_lldp = -1;
110 static gint ett_chassis_id = -1;
111 static gint ett_port_id = -1;
112 static gint ett_time_to_live = -1;
113 static gint ett_end_of_lldpdu = -1;
114 static gint ett_port_description = -1;
115 static gint ett_system_name = -1;
116 static gint ett_system_cap = -1;
117 static gint ett_system_cap_summary = -1;
118 static gint ett_system_cap_enabled = -1;
119 static gint ett_management_address = -1;
120 static gint ett_unknown_tlv = -1;
121 static gint ett_org_spc_tlv = -1;
122 static gint ett_port_vlan_flags = -1;
123 static gint ett_802_3_flags = -1;
124 static gint ett_802_3_autoneg_advertised = -1;
125 static gint ett_802_3_power = -1;
126 static gint ett_802_3_aggregation = -1;
127 static gint ett_media_capabilities = -1;
128 static gint ett_profinet_period = -1;
129
130 static const value_string tlv_types[] = {
131         { END_OF_LLDPDU_TLV_TYPE,                       "End of LLDPDU"},
132         { CHASSIS_ID_TLV_TYPE,                          "Chassis Id"},
133         { PORT_ID_TLV_TYPE,                                     "Port Id"},
134         { TIME_TO_LIVE_TLV_TYPE,                        "Time to Live"},
135         { PORT_DESCRIPTION_TLV_TYPE,            "Port Description"},
136         { SYSTEM_NAME_TLV_TYPE,                         "System Name"},
137         { SYSTEM_DESCRIPTION_TLV_TYPE,          "System Description"},
138         { SYSTEM_CAPABILITIES_TLV_TYPE,         "System Capabilities"},
139         { MANAGEMENT_ADDR_TLV_TYPE,                     "Management Address"},
140         { ORGANIZATION_SPECIFIC_TLV_TYPE,       "Organization Specific"},
141         { 0, NULL}
142 };
143
144 static const value_string chassis_id_subtypes[] = {
145         { 0,    "Reserved"},
146         { 1,    "Chassis component"},
147         { 2,    "Interface alias"},
148         { 3,    "Port component"},
149         { 4,    "MAC address"},
150         { 5,    "Network address"},
151         { 6,    "Interface name"},
152         { 7,    "Locally assigned"},
153         { 0, NULL}
154 };
155
156 static const value_string port_id_subtypes[] = {
157         { 0,    "Reserved"},
158         { 1,    "Interface alias"},
159         { 2,    "Port component"},
160         { 3,    "MAC address"},
161         { 4,    "Network address"},
162         { 5,    "Interface name"},
163         { 6,    "Agent circuit Id"},
164         { 7,    "Locally assigned"},
165         { 0, NULL}
166 };
167
168 static const value_string interface_subtype_values[] = {
169         { 1,    "Unknown"},
170         { 2,    "ifIndex"},
171         { 3,    "System port number"},
172         { 0, NULL}
173 };
174
175 static const value_string tlv_oui_subtype_vals[] = {
176         { OUI_IEEE_802_1,       "IEEE 802.1" },
177         { OUI_IEEE_802_3,       "IEEE 802.3" },
178         { OUI_MEDIA_ENDPOINT,   "TIA" },
179         { OUI_PROFINET,         "PROFINET" },
180         { 0, NULL }
181 };
182
183 /* IEEE 802.1 Subtypes */
184 static const value_string ieee_802_1_subtypes[] = {
185         { 0x01, "Port VLAN ID" },
186         { 0x02, "Port and Protocol VLAN ID" },
187         { 0x03, "VLAN Name" },
188         { 0x04, "Protocol Identity" },
189         { 0, NULL }
190 };
191
192 /* IEEE 802.3 Subtypes */
193 static const value_string ieee_802_3_subtypes[] = {
194         { 0x01, "MAC/PHY Configuration/Status" },
195         { 0x02, "Power Via MDI" },
196         { 0x03, "Link Aggregation" },
197         { 0x04, "Maximum Frame Size" },
198         { 0, NULL }
199 };
200
201 /* Media Subtypes */
202 static const value_string media_subtypes[] = {
203         { 1,    "Media Capabilities" },
204         { 2,    "Network Policy" },
205         { 3,    "Location Identification" },
206         { 4,    "Extended Power-via-MDI" },
207         { 5,    "Inventory - Hardware Revision" },
208         { 6,    "Inventory - Firmware Revision" },
209         { 7,    "Inventory - Software Revision" },
210         { 8,    "Inventory - Serial Number" },
211         { 9,    "Inventory - Manufacturer Name" },
212         { 10,   "Inventory - Model Name" },
213         { 11,   "Inventory - Asset ID" },
214         { 0, NULL }
215 };
216
217 /* Media Class Values */
218 static const value_string media_class_values[] = {
219         { 0,    "Type Not Defined" },
220         { 1,    "Endpoint Class I" },
221         { 2,    "Endpoint Class II" },
222         { 3,    "Endpoint Class III" },
223         { 4,    "Network Connectivity" },
224         { 0, NULL }
225 };
226
227 /* Media Application Types */
228 static const value_string media_application_type[] = {
229         { 0,    "Reserved" },
230         { 1,    "Voice" },
231         { 2,    "Voice Signaling" },
232         { 3,    "Guest Voice" },
233         { 4,    "Guest Voice Signaling" },
234         { 5,    "Softphone Voice" },
235         { 6,    "Video Conferencing" },
236         { 7,    "Streaming Video" },
237         { 8,    "Video Signaling" },
238         { 0, NULL }
239 };
240
241 /* PROFINET subtypes */
242 static const value_string profinet_subtypes[] = {
243         { 1, "Measured Delay Values" },
244         { 2, "Port Status" },
245         { 3, "Alias" },
246         { 4, "MRP Port Status" },
247         { 5, "Chassis MAC" },
248         { 6, "PTCP Status" },
249         { 0, NULL }
250 };
251
252 /* 802.3 Power Type */
253 static const value_string power_type_802_3[] = {
254         { 0,    "Type 2" },
255         { 1,    "Type 2" },
256         { 2,    "Type 1" },
257         { 3,    "Type 1" },
258         { 0, NULL }
259 };
260
261 /* Power Type */
262 static const value_string media_power_type[] = {
263         { 0,    "PSE Device" },
264         { 1,    "PD Device" },
265         { 2,    "PSE Device" },
266         { 3,    "PD Device" },
267         { 0, NULL }
268 };
269
270 /* Power Priority */
271 static const value_string media_power_priority[] = {
272         { 0,    "Unknown" },
273         { 1,    "Critical" },
274         { 2,    "High" },
275         { 3,    "Low" },
276         { 0, NULL }
277 };
278
279 /* Power Sources */
280 static const value_string media_power_pd_device[] = {
281         { 0,    "Unknown" },
282         { 1,    "PSE" },
283         { 2,    "Local" },
284         { 3,    "PSE and Local" },
285         { 0, NULL }
286 };
287 static const value_string media_power_pse_device[] = {
288         { 0,    "Unknown" },
289         { 1,    "Primary Power Source" },
290         { 2,    "Backup Power Source" },
291         { 0, NULL }
292 };
293
294 /* Location data format */
295 static const value_string location_data_format[] = {
296         { 0,    "Invalid " },
297         { 1,    "Coordinate-based LCI" },
298         { 2,    "Civic Address LCI" },
299         { 3,    "ECS ELIN" },
300         { 0, NULL }
301 };
302
303 /* Civic Address LCI - What field */
304 static const value_string civic_address_what_values[] = {
305         { 0,    "Location of the DHCP server" },
306         { 1,    "Location of the network element believed to be closest to the client" },
307         { 2,    "Location of the client"},
308         { 0, NULL}
309 };
310
311 /* Civic Address Type field */
312 static const value_string civic_address_type_values[] = {
313         { 0,    "Language" },
314         { 1,    "National subdivisions (province, state, etc)" },
315         { 2,    "County, parish, district" },
316         { 3,    "City, township" },
317         { 4,    "City division, borough, ward" },
318         { 5,    "Neighborhood, block" },
319         { 6,    "Street" },
320         { 16,   "Leading street direction" },
321         { 17,   "Trailing street suffix" },
322         { 18,   "Street suffix" },
323         { 19,   "House number" },
324         { 20,   "House number suffix" },
325         { 21,   "Landmark or vanity address" },
326         { 22,   "Additional location information" },
327         { 23,   "Name" },
328         { 24,   "Postal/ZIP code" },
329         { 25,   "Building" },
330         { 26,   "Unit" },
331         { 27,   "Floor" },
332         { 28,   "Room number" },
333         { 29,   "Place type" },
334         { 128,  "Script" },
335         { 0, NULL }
336 };
337
338 /*
339  * Define the text strings for the LLDP 802.3 MAC/PHY Configuration/Status
340  * Operational MAU Type field.
341  *
342  * These values are taken from the DESCRIPTION field of the dot3MauType
343  * objects defined in RFC 3636 (or subsequent revisions).
344  */
345
346 static const value_string operational_mau_type_values[] = {
347         { 1,    "AUI - no internal MAU, view from AUI" },
348         { 2,    "10Base5 - thick coax MAU" },
349         { 3,    "Foirl - FOIRL MAU" },
350         { 4,    "10Base2 - thin coax MAU" },
351         { 5,    "10BaseT - UTP MAU" },
352         { 6,    "10BaseFP - passive fiber MAU" },
353         { 7,    "10BaseFB - sync fiber MAU" },
354         { 8,    "10BaseFL - async fiber MAU" },
355         { 9,    "10Broad36 - broadband DTE MAU" },
356         { 10,   "10BaseTHD - UTP MAU, half duplex mode" },
357         { 11,   "10BaseTFD - UTP MAU, full duplex mode" },
358         { 12,   "10BaseFLHD - async fiber MAU, half duplex mode" },
359         { 13,   "10BaseFLDF - async fiber MAU, full duplex mode" },
360         { 14,   "10BaseT4 - 4 pair category 3 UTP" },
361         { 15,   "100BaseTXHD - 2 pair category 5 UTP, half duplex mode" },
362         { 16,   "100BaseTXFD - 2 pair category 5 UTP, full duplex mode" },
363         { 17,   "100BaseFXHD - X fiber over PMT, half duplex mode" },
364         { 18,   "100BaseFXFD - X fiber over PMT, full duplex mode" },
365         { 19,   "100BaseT2HD - 2 pair category 3 UTP, half duplex mode" },
366         { 20,   "100BaseT2DF - 2 pair category 3 UTP, full duplex mode" },
367         { 21,   "1000BaseXHD - PCS/PMA, unknown PMD, half duplex mode" },
368         { 22,   "1000BaseXFD - PCS/PMA, unknown PMD, full duplex mode" },
369         { 23,   "1000BaseLXHD - Fiber over long-wavelength laser, half duplex mode" },
370         { 24,   "1000BaseLXFD - Fiber over long-wavelength laser, full duplex mode" },
371         { 25,   "1000BaseSXHD - Fiber over short-wavelength laser, half duplex mode" },
372         { 26,   "1000BaseSXFD - Fiber over short-wavelength laser, full duplex mode" },
373         { 27,   "1000BaseCXHD - Copper over 150-Ohm balanced cable, half duplex mode" },
374         { 28,   "1000BaseCXFD - Copper over 150-Ohm balanced cable, full duplex mode" },
375         { 29,   "1000BaseTHD - Four-pair Category 5 UTP, half duplex mode" },
376         { 30,   "1000BaseTFD - Four-pair Category 5 UTP, full duplex mode" },
377         { 31,   "10GigBaseX - X PCS/PMA, unknown PMD." },
378         { 32,   "10GigBaseLX4 - X fiber over WWDM optics" },
379         { 33,   "10GigBaseR - R PCS/PMA, unknown PMD." },
380         { 34,   "10GigBaseER - R fiber over 1550 nm optics" },
381         { 35,   "10GigBaseLR - R fiber over 1310 nm optics" },
382         { 36,   "10GigBaseSR - R fiber over 850 nm optics" },
383         { 37,   "10GigBaseW - W PCS/PMA, unknown PMD." },
384         { 38,   "10GigBaseEW - W fiber over 1550 nm optics" },
385         { 39,   "10GigBaseLW - W fiber over 1310 nm optics" },
386         { 40,   "10GigBaseSW - W fiber over 850 nm optics" },
387         { 0, NULL }
388 };
389
390 /* System Capabilities */
391 #define SYSTEM_CAPABILITY_OTHER         0x0001
392 #define SYSTEM_CAPABILITY_REPEATER      0x0002
393 #define SYSTEM_CAPABILITY_BRIDGE        0x0004
394 #define SYSTEM_CAPABILITY_WLAN          0x0008
395 #define SYSTEM_CAPABILITY_ROUTER        0x0010
396 #define SYSTEM_CAPABILITY_TELEPHONE     0x0020
397 #define SYSTEM_CAPABILITY_DOCSIS        0x0040
398 #define SYSTEM_CAPABILITY_STATION       0x0080
399
400 /* Media Capabilities */
401 #define MEDIA_CAPABILITY_LLDP                           0x0001
402 #define MEDIA_CAPABILITY_NETWORK_POLICY         0x0002
403 #define MEDIA_CAPABILITY_LOCATION_ID            0x0004
404 #define MEDIA_CAPABILITY_MDI_PSE                        0x0008
405 #define MEDIA_CAPABILITY_MDI_PD                         0x0010
406 #define MEDIA_CAPABILITY_INVENTORY                      0x0020
407
408 /*
409  * Define constants for the LLDP 802.3 MAC/PHY Configuration/Status
410  * PMD Auto-Negotiation Advertised Capability field.
411  * These values are taken from the ifMauAutoNegCapAdvertisedBits
412  * object defined in RFC 3636.
413  */
414
415 #define AUTONEG_OTHER                   0x8000 /* bOther(0),        -- other or unknown */
416 #define AUTONEG_10BASE_T                0x4000 /* b10baseT(1),      -- 10BASE-T  half duplex mode */
417 #define AUTONEG_10BASET_FD              0x2000 /* b10baseTFD(2),    -- 10BASE-T  full duplex mode */
418 #define AUTONEG_100BASE_T4              0x1000 /* b100baseT4(3),    -- 100BASE-T4 */
419 #define AUTONEG_100BASE_TX              0x0800 /* b100baseTX(4),    -- 100BASE-TX half duplex mode */
420 #define AUTONEG_100BASE_TXFD    0x0400 /* b100baseTXFD(5),  -- 100BASE-TX full duplex mode */
421 #define AUTONEG_100BASE_T2              0x0200 /* b100baseT2(6),    -- 100BASE-T2 half duplex mode */
422 #define AUTONEG_100BASE_T2FD    0x0100 /* b100baseT2FD(7),  -- 100BASE-T2 full duplex mode */
423 #define AUTONEG_FDX_PAUSE               0x0080 /* bFdxPause(8),     -- PAUSE for full-duplex links */
424 #define AUTONEG_FDX_APAUSE              0x0040 /* bFdxAPause(9),    -- Asymmetric PAUSE for full-duplex links */
425 #define AUTONEG_FDX_SPAUSE              0x0020 /* bFdxSPause(10),   -- Symmetric PAUSE for full-duplex links */
426 #define AUTONEG_FDX_BPAUSE              0x0010 /* bFdxBPause(11),   -- Asymmetric and Symmetric PAUSE for full-duplex links */
427 #define AUTONEG_1000BASE_X              0x0008 /* b1000baseX(12),   -- 1000BASE-X, -LX, -SX, -CX half duplex mode */
428 #define AUTONEG_1000BASE_XFD    0x0004 /* b1000baseXFD(13), -- 1000BASE-X, -LX, -SX, -CX full duplex mode */
429 #define AUTONEG_1000BASE_T              0x0002 /* b1000baseT(14),   -- 1000BASE-T half duplex mode */
430 #define AUTONEG_1000BASE_TFD    0x0001 /* b1000baseTFD(15)  -- 1000BASE-T full duplex mode */
431
432 /* Some vendors interpreted the standard to invert the bitorder:
433  * according to a IEEE ruling, this is now officially wrong.
434  * See https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=1455
435  * for all the gory details
436  */
437
438 #define INV_AUTONEG_OTHER               0x0001 /* bOther(0),        -- other or unknown */
439 #define INV_AUTONEG_10BASE_T            0x0002 /* b10baseT(1),      -- 10BASE-T  half duplex mode */
440 #define INV_AUTONEG_10BASET_FD          0x0004 /* b10baseTFD(2),    -- 10BASE-T  full duplex mode */
441 #define INV_AUTONEG_100BASE_T4          0x0008 /* b100baseT4(3),    -- 100BASE-T4 */
442 #define INV_AUTONEG_100BASE_TX          0x0010 /* b100baseTX(4),    -- 100BASE-TX half duplex mode */
443 #define INV_AUTONEG_100BASE_TXFD        0x0020 /* b100baseTXFD(5),  -- 100BASE-TX full duplex mode */
444 #define INV_AUTONEG_100BASE_T2          0x0040 /* b100baseT2(6),    -- 100BASE-T2 half duplex mode */
445 #define INV_AUTONEG_100BASE_T2FD        0x0080 /* b100baseT2FD(7),  -- 100BASE-T2 full duplex mode */
446 #define INV_AUTONEG_FDX_PAUSE           0x0100 /* bFdxPause(8),     -- PAUSE for full-duplex links */
447 #define INV_AUTONEG_FDX_APAUSE          0x0200 /* bFdxAPause(9),    -- Asymmetric PAUSE for full-duplex links */
448 #define INV_AUTONEG_FDX_SPAUSE          0x0400 /* bFdxSPause(10),   -- Symmetric PAUSE for full-duplex links */
449 #define INV_AUTONEG_FDX_BPAUSE          0x0800 /* bFdxBPause(11),   -- Asymmetric and Symmetric PAUSE for full-duplex links */
450 #define INV_AUTONEG_1000BASE_X          0x1000 /* b1000baseX(12),   -- 1000BASE-X, -LX, -SX, -CX half duplex mode */
451 #define INV_AUTONEG_1000BASE_XFD        0x2000 /* b1000baseXFD(13), -- 1000BASE-X, -LX, -SX, -CX full duplex mode */
452 #define INV_AUTONEG_1000BASE_T          0x4000 /* b1000baseT(14),   -- 1000BASE-T half duplex mode */
453 #define INV_AUTONEG_1000BASE_TFD        0x8000 /* b1000baseTFD(15)  -- 1000BASE-T full duplex mode */
454
455 #define MAX_MAC_LEN     6
456
457
458 static const value_string profinet_port2_status_vals[] = {
459         { 0,    "OFF" },
460         { 1,    "SYNCDATA_LOADED" },
461         { 2,    "RTCLASS2_UP" },
462         { 3,    "Reserved" },
463         /* all other bits reserved */
464         { 0,    NULL }
465 };
466
467 static const value_string profinet_port3_status_vals[] = {
468         { 0,    "OFF" },
469         { 1,    "IRDATA_LOADED" },
470         { 2,    "RTCLASS3_UP" },
471         { 3,    "RTCLASS3_DOWN" },
472         { 4,    "RTCLASS3_RUN" },
473         /* all other bits reserved */
474         { 0,    NULL }
475 };
476
477 static const value_string profinet_mrrt_port_status_vals[] = {
478         { 0,    "OFF" },
479         { 1,    "MRRT_CONFIGURED" },
480         { 2,    "MRRT_UP" },
481         /* all other bits reserved */
482         { 0,    NULL }
483 };
484
485 /* Calculate Latitude and Longitude string */
486 /*
487         Parameters:
488                 option = 0 -> Latitude
489                 option = 1 -> Longitude
490 */
491 static gchar *
492 get_latitude_or_longitude(int option, guint64 value)
493 {
494         guint64 tempValue = value;
495         gboolean negativeNum = FALSE;
496         guint32 integerPortion = 0;
497         const char *direction;
498
499         /* The latitude and longitude are 34 bit fixed point value consisting
500            of 9 bits of integer and 25 bits of fraction.
501            When option is equal to 0, positive numbers are represent a location
502            north of the equator and negative (2s complement) numbers are south of the equator.
503            When option is equal to 1, positive values are east of the prime
504            meridian and negative (2s complement) numbers are west of the prime meridian.
505         */
506
507         if (value & G_GINT64_CONSTANT(0x0000000200000000))
508         {
509                 /* Have a negative number (2s complement) */
510                 negativeNum = TRUE;
511
512                 tempValue = ~value;
513                 tempValue += 1;
514         }
515
516         /* Get the integer portion */
517         integerPortion = (guint32)((tempValue & G_GINT64_CONSTANT(0x00000003FE000000)) >> 25);
518
519         /* Calculate decimal portion (using 25 bits for fraction) */
520         tempValue = (tempValue & G_GINT64_CONSTANT(0x0000000001FFFFFF))/33554432;
521
522         if (option == 0)
523         {
524                 /* Latitude - north/south directions */
525                 if (negativeNum)
526                         direction = "South";
527                 else
528                         direction = "North";
529         }
530         else
531         {
532                 /* Longitude - east/west directions */
533                 if (negativeNum)
534                         direction = "West";
535                 else
536                         direction = "East";
537         }
538
539         return ep_strdup_printf("%u.%04" G_GINT64_MODIFIER "u degrees %s",
540             integerPortion, tempValue, direction);
541 }
542
543 /* Dissect Chassis Id TLV (Mandatory) */
544 static gint32
545 dissect_lldp_chassis_id(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 offset)
546 {
547         guint8 tempType;
548         guint16 tempShort;
549         guint32 tempLen = 0;
550         const char *strPtr=NULL;
551         guint8 incorrectLen = 0;        /* incorrect length if 1 */
552
553         const guint8 *mac_addr = NULL;
554         guint32 ip_addr = 0;
555         struct e_in6_addr ip6_addr;
556         guint8 addr_family = 0;
557
558         proto_tree      *chassis_tree = NULL;
559         proto_item      *tf = NULL;
560
561         /* Get tlv type */
562         tempShort = tvb_get_ntohs(tvb, offset);
563         tempType = TLV_TYPE(tempShort);
564         if (tempType != CHASSIS_ID_TLV_TYPE)
565         {
566                 if (tree)
567                 {
568                         tf = proto_tree_add_text(tree, tvb, offset, 2, "Invalid Chassis ID (0x%02X)", tempType);
569                         chassis_tree = proto_item_add_subtree(tf, ett_chassis_id);
570                         proto_tree_add_text(chassis_tree, tvb, offset, 2, "%s Invalid Chassis ID (%u)",
571                                                 decode_boolean_bitfield(tempType, TLV_TYPE_MASK, 16, "", ""), tempType);
572                 }
573
574                 return -1;
575         }
576
577         /* Get tlv length */
578         tempLen = TLV_INFO_LEN(tempShort);
579         if (tempLen < 2)
580         {
581                 if (tree)
582                 {
583                         tf = proto_tree_add_text(tree, tvb, offset, 2, "Invalid Chassis ID Length (%u)", tempLen);
584                         chassis_tree = proto_item_add_subtree(tf, ett_chassis_id);
585                         proto_tree_add_item(chassis_tree, hf_lldp_tlv_type, tvb, offset, 2, FALSE);
586                         proto_tree_add_text(chassis_tree, tvb, offset, 2, "%s Invalid Length: %u",
587                                                 decode_boolean_bitfield(tempLen, TLV_INFO_LEN_MASK, 16, "", ""), tempLen);
588                 }
589
590                 return -1;
591         }
592
593         /* Get tlv subtype */
594         tempType = tvb_get_guint8(tvb, (offset+2));
595
596         switch (tempType)
597         {
598         case 4: /* MAC address */
599         {
600                 if (tempLen != 7)
601                 {
602                         incorrectLen = 1;       /* Invalid length */
603                         break;
604                 }
605
606                 mac_addr=tvb_get_ptr(tvb, (offset+3), 6);
607                 strPtr = ether_to_str(mac_addr);
608
609                 break;
610         }
611         case 5: /* Network address */
612         {
613                 /* Get network address family */
614                 addr_family = tvb_get_guint8(tvb,offset+3);
615                 /* Check for IPv4 or IPv6 */
616                 switch(addr_family){
617                 case AFNUM_INET:
618                         if (tempLen == 6){
619                                 ip_addr = tvb_get_ipv4(tvb, (offset+4));
620                                 strPtr = ip_to_str((guint8 *)&ip_addr);
621                         }else{
622                                 incorrectLen = 1;       /* Invalid length */
623                         }
624                         break;
625                 case AFNUM_INET6:
626                         if  (tempLen == 18){
627                                 tvb_get_ipv6(tvb, (offset+4), &ip6_addr);
628                                 strPtr = ip6_to_str(&ip6_addr);
629                         }else{
630                                 incorrectLen = 1;       /* Invalid length */
631                         }
632                         break;
633                 default:
634                         strPtr = tvb_bytes_to_str(tvb, (offset+4), (tempLen-2));
635                         break;
636                 }
637                 break;
638         }
639         case 2: /* Interface alias */
640         case 6: /* Interface name */
641         case 7: /* Locally assigned */
642         {
643                 if (tempLen > 256)
644                 {
645                         incorrectLen = 1;       /* Invalid length */
646                         break;
647                 }
648
649                 strPtr = tvb_format_stringzpad(tvb, (offset+3), (tempLen-1));
650
651                 break;
652         }
653         case 1: /* Chassis component */
654         case 3: /* Port component */
655         {
656                 if (tempLen > 256)
657                 {
658                         incorrectLen = 1;       /* Invalid length */
659                         break;
660                 }
661
662                 strPtr = tvb_bytes_to_str(tvb, (offset+3), (tempLen-1));
663                 break;
664         }
665         default:        /* Reserved types */
666         {
667                 if (tempLen > 256)
668                 {
669                         incorrectLen = 1;       /* Invalid length */
670                         break;
671                 }
672
673                 strPtr = "Reserved";
674
675                 break;
676         }
677         }
678
679         if (incorrectLen == 1)
680         {
681                 if (tree)
682                 {
683                         tf = proto_tree_add_text(tree, tvb, offset, 2, "Invalid Chassis ID Length (%u)", tempLen);
684                         chassis_tree = proto_item_add_subtree(tf, ett_chassis_id);
685                         proto_tree_add_item(chassis_tree, hf_lldp_tlv_type, tvb, offset, 2, FALSE);
686                         proto_tree_add_text(chassis_tree, tvb, offset, 2, "%s Invalid Length: %u",
687                                                 decode_boolean_bitfield(tempLen, TLV_INFO_LEN_MASK, 16, "", ""), tempLen);
688                         /* Get chassis id subtype */
689                         proto_tree_add_item(chassis_tree, hf_chassis_id_subtype, tvb, (offset+2), 1, FALSE);
690
691                 }
692
693                 return -1;
694         }
695
696         if (check_col(pinfo->cinfo, COL_INFO))
697                 col_add_fstr(pinfo->cinfo, COL_INFO, "Chassis Id = %s ", strPtr);
698
699         if (tree)
700         {
701                 /* Set chassis tree */
702                 tf = proto_tree_add_text(tree, tvb, offset, (tempLen + 2), "Chassis Subtype = %s",
703                                                                 val_to_str(tempType, chassis_id_subtypes, "Reserved" ));
704                 chassis_tree = proto_item_add_subtree(tf, ett_chassis_id);
705
706                 proto_tree_add_item(chassis_tree, hf_lldp_tlv_type, tvb, offset, 2, FALSE);
707                 proto_tree_add_item(chassis_tree, hf_lldp_tlv_len, tvb, offset, 2, FALSE);
708
709                 /* Get chassis id subtype */
710                 proto_tree_add_item(chassis_tree, hf_chassis_id_subtype, tvb, (offset+2), 1, FALSE);
711
712                 /* Get chassis id */
713                 switch (tempType)
714                 {
715                 case 4: /* MAC address */
716                         proto_tree_add_ether(chassis_tree, hf_chassis_id_mac, tvb, (offset+3), 6, mac_addr);
717                         proto_item_append_text(tf, ", Id: %s", strPtr);
718                         break;
719                 case 5: /* Network address */
720                         proto_tree_add_item(chassis_tree, hf_lldp_network_address_family, tvb, offset+3, 1, FALSE);
721                         switch(addr_family){
722                         case AFNUM_INET:
723                                 proto_tree_add_ipv4(chassis_tree, hf_chassis_id_ip4, tvb, (offset+4), 4, ip_addr);
724                                 break;
725                         case AFNUM_INET6:
726                                 proto_tree_add_ipv6(chassis_tree, hf_chassis_id_ip6, tvb, (offset+4), 16, ip6_addr.bytes);
727                                 break;
728                         default:
729                                 proto_tree_add_text(chassis_tree, tvb, (offset+4), (tempLen-2), "Chassis Id: %s", strPtr);
730                                 break;
731                         }
732                         break;
733                 case 2: /* Interface alias */
734                 case 6: /* Interface name */
735                 case 7: /* Locally assigned */
736                         proto_tree_add_text(chassis_tree, tvb, (offset+3), (tempLen-1), "Chassis Id: %s", strPtr);
737                         proto_item_append_text(tf, ", Id: %s", strPtr);
738                         break;
739                 case 1: /* Chassis component */
740                 case 3: /* Port component */
741                         proto_tree_add_item(chassis_tree, hf_chassis_id, tvb, (offset+3), (tempLen-1), FALSE);
742                         break;
743                 }
744         }
745
746         return (tempLen + 2);
747 }
748
749 /* Dissect Port Id TLV (Mandatory) */
750 static gint32
751 dissect_lldp_port_id(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 offset)
752 {
753         guint8 tempType;
754         guint16 tempShort;
755         guint32 tempLen = 0;
756         const char *strPtr;
757         const guint8 *mac_addr = NULL;
758         guint32 ip_addr = 0;
759         struct e_in6_addr ip6_addr;
760         guint8 addr_family = 0;
761
762         proto_tree      *port_tree = NULL;
763         proto_item      *tf = NULL;
764
765         /* Get tlv type */
766         tempShort = tvb_get_ntohs(tvb, offset);
767         tempType = TLV_TYPE(tempShort);
768         if (tempType != PORT_ID_TLV_TYPE)
769                 return -1;
770
771         /* Get tlv length and subtype */
772         tempLen = TLV_INFO_LEN(tempShort);
773         tempType = tvb_get_guint8(tvb, (offset+2));
774
775         /* Get port id */
776         switch (tempType)
777         {
778         case 3: /* MAC address */
779         {
780                 if (tempLen != 7)
781                         return -1;      /* Invalid port id */
782
783                 mac_addr=tvb_get_ptr(tvb, (offset+3), 6);
784                 strPtr = ether_to_str(mac_addr);
785
786                 break;
787         }
788         case 4: /* Network address */
789         {
790                 /* Get network address family */
791                 addr_family = tvb_get_guint8(tvb,offset+3);
792                 /* Check for IPv4 or IPv6 */
793                 switch(addr_family){
794                 case AFNUM_INET:
795                         if (tempLen == 6){
796                                 ip_addr = tvb_get_ipv4(tvb, (offset+4));
797                                 strPtr = ip_to_str((guint8 *)&ip_addr);
798                         }else{
799                                 return -1;
800                         }
801                         break;
802                 case AFNUM_INET6:
803                         if  (tempLen == 18){
804                                 tvb_get_ipv6(tvb, (offset+4), &ip6_addr);
805                                 strPtr = ip6_to_str(&ip6_addr);
806                         }else{
807                                 return -1;      /* Invalid chassis id */
808                         }
809                         break;
810                 default:
811                         strPtr = tvb_bytes_to_str(tvb, (offset+4), (tempLen-2));
812                         break;
813                 }
814                 break;
815         }
816         default:
817         {
818                 strPtr = tvb_format_stringzpad(tvb, (offset+3), (tempLen-1));
819
820                 break;
821         }
822         }
823
824         if (check_col(pinfo->cinfo, COL_INFO))
825                 col_append_fstr(pinfo->cinfo, COL_INFO, "Port Id = %s ", strPtr);
826
827         if (tree)
828         {
829                 /* Set port tree */
830                 tf = proto_tree_add_text(tree, tvb, offset, (tempLen + 2), "Port Subtype = %s",
831                                                                 val_to_str(tempType, port_id_subtypes, "Unknown" ));
832                 port_tree = proto_item_add_subtree(tf, ett_port_id);
833
834                 proto_tree_add_item(port_tree, hf_lldp_tlv_type, tvb, offset, 2, FALSE);
835                 proto_tree_add_item(port_tree, hf_lldp_tlv_len, tvb, offset, 2, FALSE);
836
837                 /* Get port id subtype */
838                 proto_tree_add_item(port_tree, hf_port_id_subtype, tvb, (offset+2), 1, FALSE);
839
840                 /* Get port id */
841                 /*proto_tree_add_text(port_tree, tvb, (offset+3), (tempLen-1), "Port Id: %s", strPtr);*/
842                 switch (tempType)
843                 {
844                 case 3: /* MAC address */
845                         proto_tree_add_ether(port_tree, hf_port_id_mac, tvb, (offset+3), 6, mac_addr);
846                         break;
847                 case 4: /* Network address */
848                         /* Network address
849                          * networkAddress is an octet string that identifies a particular network address family
850                          * and an associated network address that are encoded in network octet order.
851                          */
852                         /* Network address family */
853                         proto_tree_add_item(port_tree, hf_lldp_network_address_family, tvb, offset+3, 1, FALSE);
854                         switch(addr_family){
855                         case AFNUM_INET:
856                                 proto_tree_add_ipv4(port_tree, hf_port_id_ip4, tvb, (offset+4), 4, ip_addr);
857                                 break;
858                         case AFNUM_INET6:
859                                 proto_tree_add_ipv6(port_tree, hf_port_id_ip6, tvb, (offset+4), 16, ip6_addr.bytes);
860                                 break;
861                         default:
862                                 proto_tree_add_text(port_tree, tvb, (offset+4), (tempLen-2), "Port Id: %s", strPtr);
863                                 break;
864                         }
865                         break;
866                 default:
867                         proto_tree_add_text(port_tree, tvb, (offset+3), (tempLen-1), "Port Id: %s", strPtr);
868                         proto_item_append_text(tf, ", Id: %s", strPtr);
869                         break;
870                 }
871
872         }
873
874         return (tempLen + 2);
875 }
876
877 /* Dissect Time To Live TLV (Mandatory) */
878 static gint32
879 dissect_lldp_time_to_live(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 offset)
880 {
881         guint8 tempType;
882         guint16 tempShort;
883         guint32 tempLen = 0;
884
885         proto_tree      *time_to_live_tree = NULL;
886         proto_item      *tf = NULL;
887
888         /* Get tlv type */
889         tempShort = tvb_get_ntohs(tvb, offset);
890         tempType = TLV_TYPE(tempShort);
891         if (tempType != TIME_TO_LIVE_TLV_TYPE)
892                 return -1;
893
894         /* Get tlv length and seconds field */
895         tempLen = TLV_INFO_LEN(tempShort);
896         tempShort = tvb_get_ntohs(tvb, (offset+2));
897
898         if (check_col(pinfo->cinfo, COL_INFO))
899                 col_append_fstr(pinfo->cinfo, COL_INFO, "TTL = %u ", tempShort);
900
901         if (tree)
902         {
903                 /* Set port tree */
904                 tf = proto_tree_add_text(tree, tvb, offset, (tempLen + 2), "Time To Live = %u sec", tempShort);
905                 time_to_live_tree = proto_item_add_subtree(tf, ett_time_to_live);
906
907                 proto_tree_add_item(time_to_live_tree, hf_lldp_tlv_type, tvb, offset, 2, FALSE);
908                 proto_tree_add_item(time_to_live_tree, hf_lldp_tlv_len, tvb, offset, 2, FALSE);
909
910                 /* Display time to live information */
911                 proto_tree_add_item(time_to_live_tree, hf_time_to_live, tvb, (offset+2), 2, FALSE);
912         }
913
914         return (tempLen + 2);
915 }
916
917 /* Dissect End of LLDPDU TLV (Mandatory) */
918 static gint32
919 dissect_lldp_end_of_lldpdu(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, guint32 offset)
920 {
921         guint16 tempLen;
922         guint16 tempShort;
923
924         proto_tree      *end_of_lldpdu_tree = NULL;
925         proto_item      *tf = NULL;
926
927         /* Get tlv type and length */
928         tempShort = tvb_get_ntohs(tvb, offset);
929
930         /* Get tlv length */
931         tempLen = TLV_INFO_LEN(tempShort);
932
933         if (tree)
934         {
935                 /* Set port tree */
936                 tf = proto_tree_add_text(tree, tvb, offset, (tempLen + 2), "End of LLDPDU");
937                 end_of_lldpdu_tree = proto_item_add_subtree(tf, ett_end_of_lldpdu);
938
939                 proto_tree_add_item(end_of_lldpdu_tree, hf_lldp_tlv_type, tvb, offset, 2, FALSE);
940                 proto_tree_add_item(end_of_lldpdu_tree, hf_lldp_tlv_len, tvb, offset, 2, FALSE);
941         }
942
943         return -1;      /* Force the lldp dissector to terminate */
944 }
945
946 /* Dissect Port Description TLV */
947 static gint32
948 dissect_lldp_port_desc(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, guint32 offset)
949 {
950         guint16 tempShort;
951         guint32 tempLen = 0;
952         const char *strPtr;
953
954         proto_tree      *port_desc_tree = NULL;
955         proto_item      *tf = NULL;
956
957         /* Get tlv type and length */
958         tempShort = tvb_get_ntohs(tvb, offset);
959
960         /* Get tlv length */
961         tempLen = TLV_INFO_LEN(tempShort);
962
963         if (tree)
964         {
965                 strPtr = tvb_format_stringzpad(tvb, (offset+2), tempLen);
966
967                 /* Set port tree */
968                 tf = proto_tree_add_text(tree, tvb, offset, (tempLen + 2), "Port Description = %s", strPtr);
969                 port_desc_tree = proto_item_add_subtree(tf, ett_port_description);
970
971                 proto_tree_add_item(port_desc_tree, hf_lldp_tlv_type, tvb, offset, 2, FALSE);
972                 proto_tree_add_item(port_desc_tree, hf_lldp_tlv_len, tvb, offset, 2, FALSE);
973
974                 /* Display port description information */
975                 proto_tree_add_text(port_desc_tree, tvb, (offset+2), tempLen, "Port Description: %s",
976                     strPtr);
977         }
978
979         return (tempLen + 2);
980 }
981
982 /* Dissect System Name and description TLV */
983 static gint32
984 dissect_lldp_system_name(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, guint32 offset)
985 {
986         guint16 tempShort;
987         guint32 tempLen = 0;
988         guint8 tempType;
989         const char *strPtr;
990
991         proto_tree      *system_name_tree = NULL;
992         proto_item      *tf = NULL;
993
994         /* Get tlv type and length */
995         tempShort = tvb_get_ntohs(tvb, offset);
996         tempType = TLV_TYPE(tempShort);
997
998         /* Get tlv length */
999         tempLen = TLV_INFO_LEN(tempShort);
1000
1001         if (tree)
1002         {
1003                 strPtr = tvb_format_stringzpad(tvb, (offset+2), tempLen);
1004
1005                 /* Set system name tree */
1006                 if (tempType == SYSTEM_NAME_TLV_TYPE) {
1007                         tf = proto_tree_add_text(tree, tvb, offset, (tempLen + 2), "System Name = %s", strPtr);
1008                         if (check_col(pinfo->cinfo, COL_INFO))
1009                                 col_append_fstr(pinfo->cinfo, COL_INFO, "System Name = %s ", strPtr);
1010                 } else
1011                         tf = proto_tree_add_text(tree, tvb, offset, (tempLen + 2), "System Description = %s", strPtr);
1012                 system_name_tree = proto_item_add_subtree(tf, ett_system_name);
1013
1014                 proto_tree_add_item(system_name_tree, hf_lldp_tlv_type, tvb, offset, 2, FALSE);
1015                 proto_tree_add_item(system_name_tree, hf_lldp_tlv_len, tvb, offset, 2, FALSE);
1016
1017                 /* Display system name information */
1018                 proto_tree_add_text(system_name_tree, tvb, (offset+2), tempLen, "%s = %s",
1019                                         ((tempType == SYSTEM_NAME_TLV_TYPE) ? "System Name" : "System Description"),
1020                                         strPtr);
1021         }
1022
1023         return (tempLen + 2);
1024 }
1025
1026 /* Dissect System Capabilities TLV */
1027 static gint32
1028 dissect_lldp_system_capabilities(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, guint32 offset)
1029 {
1030         guint16 tempShort;
1031         guint32 tempLen = 0;
1032         guint16 tempCapability;
1033
1034         proto_tree      *system_capabilities_tree = NULL;
1035         proto_tree      *capabilities_summary_tree = NULL;
1036         proto_tree  *capabilities_enabled_tree = NULL;
1037         proto_item      *tf = NULL;
1038
1039         /* Get tlv type and length */
1040         tempShort = tvb_get_ntohs(tvb, offset);
1041
1042         /* Get tlv length */
1043         tempLen = TLV_INFO_LEN(tempShort);
1044
1045         /* Get system capabilities */
1046         tempCapability = tvb_get_ntohs(tvb, (offset+2));
1047
1048         if (tree)
1049         {
1050                 /* Set system capabilities tree */
1051                 tf = proto_tree_add_text(tree, tvb, offset, (tempLen + 2), "Capabilities");
1052                 system_capabilities_tree = proto_item_add_subtree(tf, ett_system_cap);
1053
1054                 proto_tree_add_item(system_capabilities_tree, hf_lldp_tlv_type, tvb, offset, 2, FALSE);
1055                 proto_tree_add_item(system_capabilities_tree, hf_lldp_tlv_len, tvb, offset, 2, FALSE);
1056
1057                 /* Display system capability information */
1058                 tf = proto_tree_add_text(system_capabilities_tree, tvb, (offset+2), 2, "Capabilities: 0x%04x", tempCapability);
1059                 capabilities_summary_tree = proto_item_add_subtree(tf, ett_system_cap_summary);
1060                 /* Add capabilities to summary tree */
1061                 if (tempCapability & SYSTEM_CAPABILITY_OTHER)
1062                         proto_tree_add_text(capabilities_summary_tree, tvb, (offset+2), 2, "%s",
1063                                                 decode_boolean_bitfield(tempCapability, SYSTEM_CAPABILITY_OTHER,
1064                                                 16, "Other", ""));
1065                 if (tempCapability & SYSTEM_CAPABILITY_REPEATER)
1066                         proto_tree_add_text(capabilities_summary_tree, tvb, (offset+2), 2, "%s",
1067                                                 decode_boolean_bitfield(tempCapability, SYSTEM_CAPABILITY_REPEATER,
1068                                                 16, "Repeater", ""));
1069                 if (tempCapability & SYSTEM_CAPABILITY_BRIDGE)
1070                         proto_tree_add_text(capabilities_summary_tree, tvb, (offset+2), 2, "%s",
1071                                                 decode_boolean_bitfield(tempCapability, SYSTEM_CAPABILITY_BRIDGE,
1072                                                 16, "Bridge", ""));
1073                 if (tempCapability & SYSTEM_CAPABILITY_WLAN)
1074                         proto_tree_add_text(capabilities_summary_tree, tvb, (offset+2), 2, "%s",
1075                                                 decode_boolean_bitfield(tempCapability, SYSTEM_CAPABILITY_WLAN,
1076                                                 16, "WLAN access point", ""));
1077                 if (tempCapability & SYSTEM_CAPABILITY_ROUTER)
1078                         proto_tree_add_text(capabilities_summary_tree, tvb, (offset+2), 2, "%s",
1079                                                 decode_boolean_bitfield(tempCapability, SYSTEM_CAPABILITY_ROUTER,
1080                                                 16, "Router", ""));
1081                 if (tempCapability & SYSTEM_CAPABILITY_TELEPHONE)
1082                         proto_tree_add_text(capabilities_summary_tree, tvb, (offset+2), 2, "%s",
1083                                                 decode_boolean_bitfield(tempCapability, SYSTEM_CAPABILITY_TELEPHONE,
1084                                                 16, "Telephone", ""));
1085                 if (tempCapability & SYSTEM_CAPABILITY_DOCSIS)
1086                         proto_tree_add_text(capabilities_summary_tree, tvb, (offset+2), 2, "%s",
1087                                                 decode_boolean_bitfield(tempCapability, SYSTEM_CAPABILITY_DOCSIS,
1088                                                 16, "DOCSIS cable device", ""));
1089                 if (tempCapability & SYSTEM_CAPABILITY_STATION)
1090                         proto_tree_add_text(capabilities_summary_tree, tvb, (offset+2), 2, "%s",
1091                                                 decode_boolean_bitfield(tempCapability, SYSTEM_CAPABILITY_STATION,
1092                                                 16, "Station only", ""));
1093
1094                 /* Get enabled summary */
1095                 tempShort = tvb_get_ntohs(tvb, (offset+4));
1096
1097                 /* Display system capability information */
1098                 tf = proto_tree_add_text(system_capabilities_tree, tvb, (offset+4), 2, "Enabled Capabilities: 0x%04x", tempShort);
1099                 capabilities_enabled_tree = proto_item_add_subtree(tf, ett_system_cap_enabled);
1100                 /* Add capabilities to summary tree */
1101                 if (tempShort & SYSTEM_CAPABILITY_OTHER)
1102                         proto_tree_add_text(capabilities_enabled_tree, tvb, (offset+4), 2, "%s",
1103                                                 decode_boolean_bitfield(tempShort, SYSTEM_CAPABILITY_OTHER,
1104                                                 16, "Other", ""));
1105                 if (tempShort & SYSTEM_CAPABILITY_REPEATER)
1106                         proto_tree_add_text(capabilities_enabled_tree, tvb, (offset+4), 2, "%s",
1107                                                 decode_boolean_bitfield(tempShort, SYSTEM_CAPABILITY_REPEATER,
1108                                                 16, "Repeater", ""));
1109                 if (tempShort & SYSTEM_CAPABILITY_BRIDGE)
1110                         proto_tree_add_text(capabilities_enabled_tree, tvb, (offset+4), 2, "%s",
1111                                                 decode_boolean_bitfield(tempShort, SYSTEM_CAPABILITY_BRIDGE,
1112                                                 16, "Bridge", ""));
1113                 if (tempShort & SYSTEM_CAPABILITY_WLAN)
1114                         proto_tree_add_text(capabilities_enabled_tree, tvb, (offset+4), 2, "%s",
1115                                                 decode_boolean_bitfield(tempShort, SYSTEM_CAPABILITY_WLAN,
1116                                                 16, "WLAN access point", ""));
1117                 if (tempShort & SYSTEM_CAPABILITY_ROUTER)
1118                         proto_tree_add_text(capabilities_enabled_tree, tvb, (offset+4), 2, "%s",
1119                                                 decode_boolean_bitfield(tempShort, SYSTEM_CAPABILITY_ROUTER,
1120                                                 16, "Router", ""));
1121                 if (tempShort & SYSTEM_CAPABILITY_TELEPHONE)
1122                         proto_tree_add_text(capabilities_enabled_tree, tvb, (offset+4), 2, "%s",
1123                                                 decode_boolean_bitfield(tempShort, SYSTEM_CAPABILITY_TELEPHONE,
1124                                                 16, "Telephone", ""));
1125                 if (tempShort & SYSTEM_CAPABILITY_DOCSIS)
1126                         proto_tree_add_text(capabilities_enabled_tree, tvb, (offset+4), 2, "%s",
1127                                                 decode_boolean_bitfield(tempShort, SYSTEM_CAPABILITY_DOCSIS,
1128                                                 16, "DOCSIS cable device", ""));
1129                 if (tempShort & SYSTEM_CAPABILITY_STATION)
1130                         proto_tree_add_text(capabilities_enabled_tree, tvb, (offset+4), 2, "%s",
1131                                                 decode_boolean_bitfield(tempShort, SYSTEM_CAPABILITY_STATION,
1132                                                 16, "Station only", ""));
1133         }
1134
1135         return (tempLen + 2);
1136 }
1137
1138 /* Dissect Management Address TLV */
1139 static gint32
1140 dissect_lldp_management_address(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, guint32 offset)
1141 {
1142         guint16 tempShort;
1143         guint32 tempLen = 0;
1144         guint8  tempByte;
1145         guint8  stringLen = 0;
1146         guint32 tempOffset = offset;
1147         guint32 tempLong;
1148
1149         proto_tree      *system_mgm_addr = NULL;
1150         proto_item      *tf = NULL;
1151
1152         /* Get tlv type and length */
1153         tempShort = tvb_get_ntohs(tvb, tempOffset);
1154
1155         /* Get tlv length */
1156         tempLen = TLV_INFO_LEN(tempShort);
1157
1158         if (tree)
1159         {
1160                 /* Set system capabilities tree */
1161                 tf = proto_tree_add_text(tree, tvb, tempOffset, (tempLen + 2), "Management Address");
1162                 system_mgm_addr = proto_item_add_subtree(tf, ett_management_address);
1163
1164                 proto_tree_add_item(system_mgm_addr, hf_lldp_tlv_type, tvb, tempOffset, 2, FALSE);
1165                 proto_tree_add_item(system_mgm_addr, hf_lldp_tlv_len, tvb, tempOffset, 2, FALSE);
1166
1167                 tempOffset += 2;
1168
1169                 /* Get management address string length */
1170                 stringLen = tvb_get_guint8(tvb, tempOffset);
1171                 proto_tree_add_text(system_mgm_addr, tvb, tempOffset, 1, "Address String Length: %u", stringLen);
1172
1173                 tempOffset++;
1174
1175                 /* Get management address subtype */
1176                 tempByte = tvb_get_guint8(tvb, tempOffset);
1177                 proto_tree_add_text(system_mgm_addr, tvb, tempOffset, 1, "Address Subtype: %s (%u)",
1178                                                         val_to_str(tempByte, afn_vals, "Undefined"),
1179                                                         tempByte);
1180
1181                 tempOffset++;
1182
1183                 /* Get address */
1184                 switch (tempByte)
1185                 {
1186                 /* XXX - Should we throw an exception if stringLen doesn't match our address length? */
1187                 case 1:         /* IPv4 */
1188                         proto_tree_add_item(system_mgm_addr, hf_mgn_addr_ipv4, tvb, tempOffset, 4, FALSE);
1189                         break;
1190                 case 2:         /* IPv6 */
1191                         proto_tree_add_item(system_mgm_addr, hf_mgn_addr_ipv6, tvb, tempOffset, 16, FALSE);
1192                         break;
1193                 default:
1194                         proto_tree_add_item(system_mgm_addr, hf_mgn_addr_hex, tvb, tempOffset, (stringLen-1), FALSE);
1195                         break;
1196                 }
1197
1198                 tempOffset += (stringLen-1);
1199
1200                 /* Get interface numbering subtype */
1201                 tempByte = tvb_get_guint8(tvb, tempOffset);
1202                 proto_tree_add_text(system_mgm_addr, tvb, tempOffset, 1, "Interface Subtype: %s (%u)",
1203                                                         val_to_str(tempByte, interface_subtype_values, "Undefined"),
1204                                                         tempByte);
1205
1206                 tempOffset++;
1207
1208                 /* Get interface number */
1209                 tempLong = tvb_get_ntohl(tvb, tempOffset);
1210                 proto_tree_add_text(system_mgm_addr, tvb, tempOffset, 4, "Interface Number: %u", tempLong);
1211
1212                 tempOffset += 4;
1213
1214                 /* Get OID string length */
1215                 stringLen = tvb_get_guint8(tvb, tempOffset);
1216                 proto_tree_add_text(system_mgm_addr, tvb, tempOffset, 1, "OID String Length: %u", stringLen);
1217
1218                 if (stringLen > 0)
1219                 {
1220                         tempOffset++;
1221
1222                         /* Get OID identifier */
1223                         proto_tree_add_item(system_mgm_addr, hf_mgn_obj_id, tvb, tempOffset, stringLen, FALSE);
1224                 }
1225         }
1226
1227         return (tempLen + 2);
1228 }
1229
1230 /* Dissect IEEE 802.1 TLVs */
1231 static void
1232 dissect_ieee_802_1_tlv(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, guint32 offset)
1233 {
1234         guint8 subType;
1235         guint8 tempByte;
1236         guint16 tempShort;
1237         guint32 tempOffset = offset;
1238
1239         proto_tree      *vlan_flags = NULL;
1240         proto_item      *tf = NULL;
1241
1242         /* Get subtype */
1243         subType = tvb_get_guint8(tvb, tempOffset);
1244
1245         if (tree)
1246                 proto_tree_add_item(tree, hf_ieee_802_1_subtype, tvb, tempOffset, 1, FALSE);
1247
1248         tempOffset++;
1249
1250         switch (subType)
1251         {
1252         case 0x01:      /* Port VLAN ID */
1253         {
1254                 /* Get port vland id */
1255                 tempShort = tvb_get_ntohs(tvb, tempOffset);
1256                 if (tree)
1257                         proto_tree_add_text(tree, tvb, tempOffset, 2, "Port VLAN Identifier: %u (0x%04X)", tempShort, tempShort);
1258
1259                 break;
1260         }
1261         case 0x02:      /* Port and Protocol VLAN ID */
1262         {
1263                 /* Get flags */
1264                 tempByte = tvb_get_guint8(tvb, tempOffset);
1265                 if (tree)
1266                 {
1267                         tf = proto_tree_add_text(tree, tvb, tempOffset, 1, "Flags: 0x%02x", tempByte);
1268                         vlan_flags = proto_item_add_subtree(tf, ett_port_vlan_flags);
1269
1270                         /* Get supported flag */
1271                         proto_tree_add_text(vlan_flags, tvb, tempOffset, 1, "%s",
1272                                                 decode_boolean_bitfield(tempByte, 1 << 1, 8, "Port and Protocol VLAN: Supported",
1273                                                                                                 "Port and Protocol VLAN: Not Supported"));
1274
1275                         /* Get enabled flag */
1276                         proto_tree_add_text(vlan_flags, tvb, tempOffset, 1, "%s",
1277                                                 decode_boolean_bitfield(tempByte, 1 << 2, 8, "Port and Protocol VLAN: Enabled",
1278                                                                                                 "Port and Protocol VLAN: Not Enabled"));
1279                 }
1280
1281                 tempOffset++;
1282
1283                 /* Get port and protocol vlan id */
1284                 tempShort = tvb_get_ntohs(tvb, tempOffset);
1285                 if (tree)
1286                         proto_tree_add_text(tree, tvb, tempOffset, 2, "Port and Protocol VLAN Identifier: %u (0x%04X)", tempShort, tempShort);
1287
1288                 break;
1289         }
1290         case 0x03:      /* VLAN Name */
1291         {
1292                 /* Get vlan id */
1293                 tempShort = tvb_get_ntohs(tvb, tempOffset);
1294                 if (tree)
1295                         proto_tree_add_text(tree, tvb, tempOffset, 2, "VLAN Identifier: %u (0x%04X)", tempShort, tempShort);
1296
1297                 tempOffset += 2;
1298
1299                 /* Get vlan name length */
1300                 tempByte = tvb_get_guint8(tvb, tempOffset);
1301                 if (tree)
1302                         proto_tree_add_text(tree, tvb, tempOffset, 1, "VLAN Name Length: %u", tempByte);
1303
1304                 tempOffset++;
1305
1306                 if (tempByte > 0)
1307                 {
1308                         if (tree)
1309                                 proto_tree_add_text(tree, tvb, tempOffset, tempByte, "VLAN Name: %s",
1310                                     tvb_format_stringzpad(tvb, tempOffset, tempByte));
1311                 }
1312
1313                 break;
1314         }
1315         case 0x04:      /* Protocol ID */
1316         {
1317                 /* Get protocal id length */
1318                 tempByte = tvb_get_guint8(tvb, tempOffset);
1319                 if (tree)
1320                         proto_tree_add_text(tree, tvb, tempOffset, 1, "Protocol Identity Length: %u", tempByte);
1321
1322                 tempOffset++;
1323
1324                 if (tempByte > 0)
1325                 {
1326                         if (tree)
1327                                 proto_tree_add_text(tree, tvb, tempOffset, tempByte, "Protocol Identity: %s",
1328                                         tvb_bytes_to_str(tvb, tempOffset, tempByte));
1329                 }
1330
1331                 break;
1332         }
1333         }
1334
1335         return;
1336 }
1337
1338 /* Dissect IEEE 802.3 TLVs */
1339 static void
1340 dissect_ieee_802_3_tlv(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, guint32 offset)
1341 {
1342         guint8 subType;
1343         guint8 tempByte;
1344         guint16 tempShort;
1345         guint32 tempLong;
1346         guint32 tempOffset = offset;
1347
1348         proto_tree      *mac_phy_flags = NULL;
1349         proto_tree      *autoneg_advertised_subtree = NULL;
1350
1351         proto_item      *tf = NULL;
1352
1353         /* Get subtype */
1354         subType = tvb_get_guint8(tvb, tempOffset);
1355
1356         if (tree)
1357                 proto_tree_add_item(tree, hf_ieee_802_3_subtype, tvb, tempOffset, 1, FALSE);
1358
1359         tempOffset++;
1360
1361         switch (subType)
1362         {
1363         case 0x01:      /* MAC/PHY Configuration/Status */
1364         {
1365                 /* Get auto-negotiation info */
1366                 tempByte = tvb_get_guint8(tvb, tempOffset);
1367                 if (tree)
1368                 {
1369                         tf = proto_tree_add_text(tree, tvb, tempOffset, 1, "Auto-Negotiation Support/Status: 0x%02x", tempByte);
1370                         mac_phy_flags = proto_item_add_subtree(tf, ett_802_3_flags);
1371
1372                         /* Get supported flag */
1373                         proto_tree_add_text(mac_phy_flags, tvb, tempOffset, 1, "%s",
1374                                                 decode_boolean_bitfield(tempByte, 0x01, 8, "Auto-Negotiation: Supported",
1375                                                                                                 "Auto-Negotiation: Not Supported"));
1376
1377                         /* Get enabled flag */
1378                         proto_tree_add_text(mac_phy_flags, tvb, tempOffset, 1, "%s",
1379                                                 decode_boolean_bitfield(tempByte, 0x02, 8, "Auto-Negotiation: Enabled",
1380                                                                                                 "Auto-Negotiation: Not Enabled"));
1381                 }
1382
1383                 tempOffset++;
1384
1385                 /* Get pmd auto-negotiation advertised capability */
1386                 tempShort = tvb_get_ntohs(tvb, tempOffset);
1387                 if (tree)
1388                 {
1389                         tf = proto_tree_add_text(tree, tvb, tempOffset, 2, "PMD Auto-Negotiation Advertised Capability: 0x%04X", tempShort);
1390                         autoneg_advertised_subtree = proto_item_add_subtree(tf, ett_802_3_autoneg_advertised);
1391
1392                         if (tempShort & AUTONEG_1000BASE_TFD)
1393                                 proto_tree_add_text(autoneg_advertised_subtree, tvb, (offset+2), 2, "%s",
1394                                                         decode_boolean_bitfield(tempShort, AUTONEG_1000BASE_TFD,
1395                                                         16, "1000BASE-T (full duplex mode)", ""));
1396
1397                         if (tempShort & AUTONEG_1000BASE_T)
1398                                 proto_tree_add_text(autoneg_advertised_subtree, tvb, (offset+2), 2, "%s",
1399                                                         decode_boolean_bitfield(tempShort, AUTONEG_1000BASE_T,
1400                                                         16, "1000BASE-T (half duplex mode)", ""));
1401
1402                         if (tempShort & AUTONEG_1000BASE_XFD)
1403                                 proto_tree_add_text(autoneg_advertised_subtree, tvb, (offset+2), 2, "%s",
1404                                                         decode_boolean_bitfield(tempShort, AUTONEG_1000BASE_XFD,
1405                                                         16, "1000BASE-X (-LX, -SX, -CX full duplex mode)", ""));
1406
1407                         if (tempShort & AUTONEG_1000BASE_X)
1408                                 proto_tree_add_text(autoneg_advertised_subtree, tvb, (offset+2), 2, "%s",
1409                                                         decode_boolean_bitfield(tempShort, AUTONEG_1000BASE_X,
1410                                                         16, "1000BASE-X (-LX, -SX, -CX half duplex mode)", ""));
1411
1412                         if (tempShort & AUTONEG_FDX_BPAUSE)
1413                                 proto_tree_add_text(autoneg_advertised_subtree, tvb, (offset+2), 2, "%s",
1414                                                         decode_boolean_bitfield(tempShort, AUTONEG_FDX_BPAUSE,
1415                                                         16, "Asymmetric and Symmetric PAUSE (for full-duplex links)", ""));
1416
1417                         if (tempShort & AUTONEG_FDX_SPAUSE)
1418                                 proto_tree_add_text(autoneg_advertised_subtree, tvb, (offset+2), 2, "%s",
1419                                                         decode_boolean_bitfield(tempShort, AUTONEG_FDX_SPAUSE,
1420                                                         16, "Symmetric PAUSE (for full-duplex links)", ""));
1421
1422                         if (tempShort & AUTONEG_FDX_APAUSE)
1423                                 proto_tree_add_text(autoneg_advertised_subtree, tvb, (offset+2), 2, "%s",
1424                                                         decode_boolean_bitfield(tempShort, AUTONEG_FDX_APAUSE,
1425                                                         16, "Asymmetric PAUSE (for full-duplex links)", ""));
1426
1427                         if (tempShort & AUTONEG_FDX_PAUSE)
1428                                 proto_tree_add_text(autoneg_advertised_subtree, tvb, (offset+2), 2, "%s",
1429                                                         decode_boolean_bitfield(tempShort, AUTONEG_FDX_PAUSE,
1430                                                         16, "PAUSE (for full-duplex links)", ""));
1431
1432                         if (tempShort & AUTONEG_100BASE_T2FD)
1433                                 proto_tree_add_text(autoneg_advertised_subtree, tvb, (offset+2), 2, "%s",
1434                                                         decode_boolean_bitfield(tempShort, AUTONEG_100BASE_T2FD,
1435                                                         16, "100BASE-T2 (full duplex mode)", ""));
1436
1437                         if (tempShort & AUTONEG_100BASE_T2)
1438                                 proto_tree_add_text(autoneg_advertised_subtree, tvb, (offset+2), 2, "%s",
1439                                                         decode_boolean_bitfield(tempShort, AUTONEG_100BASE_T2,
1440                                                         16, "100BASE-T2 (half duplex mode)", ""));
1441
1442                         if (tempShort & AUTONEG_100BASE_TXFD)
1443                                 proto_tree_add_text(autoneg_advertised_subtree, tvb, (offset+2), 2, "%s",
1444                                                         decode_boolean_bitfield(tempShort, AUTONEG_100BASE_TXFD,
1445                                                         16, "100BASE-TX (full duplex mode)", ""));
1446
1447                         if (tempShort & AUTONEG_100BASE_TX)
1448                                 proto_tree_add_text(autoneg_advertised_subtree, tvb, (offset+2), 2, "%s",
1449                                                         decode_boolean_bitfield(tempShort, AUTONEG_100BASE_TX,
1450                                                         16, "100BASE-TX (half duplex mode)", ""));
1451
1452                         if (tempShort & AUTONEG_100BASE_T4)
1453                                 proto_tree_add_text(autoneg_advertised_subtree, tvb, (offset+2), 2, "%s",
1454                                                         decode_boolean_bitfield(tempShort, AUTONEG_100BASE_T4,
1455                                                         16, "100BASE-T4", ""));
1456
1457                         if (tempShort & AUTONEG_10BASET_FD)
1458                                 proto_tree_add_text(autoneg_advertised_subtree, tvb, (offset+2), 2, "%s",
1459                                                         decode_boolean_bitfield(tempShort, AUTONEG_10BASET_FD,
1460                                                         16, "10BASE-T (full duplex mode)", ""));
1461
1462                         if (tempShort & AUTONEG_10BASE_T)
1463                                 proto_tree_add_text(autoneg_advertised_subtree, tvb, (offset+2), 2, "%s",
1464                                                         decode_boolean_bitfield(tempShort, AUTONEG_10BASE_T,
1465                                                         16, "10BASE-T (half duplex mode)", ""));
1466
1467                         if (tempShort & AUTONEG_OTHER)
1468                                 proto_tree_add_text(autoneg_advertised_subtree, tvb, (offset+2), 2, "%s",
1469                                                         decode_boolean_bitfield(tempShort, AUTONEG_OTHER,
1470                                                         16, "other or unknown", ""));
1471
1472                         tf = proto_tree_add_text(tree, tvb, tempOffset, 2, "Same in inverse (wrong) bitorder");
1473                         autoneg_advertised_subtree = proto_item_add_subtree(tf, ett_802_3_autoneg_advertised);
1474
1475                         if (tempShort & INV_AUTONEG_1000BASE_TFD)
1476                                 proto_tree_add_text(autoneg_advertised_subtree, tvb, (offset+2), 2, "%s",
1477                                                         decode_boolean_bitfield(tempShort, INV_AUTONEG_1000BASE_TFD,
1478                                                         16, "1000BASE-T (full duplex mode)", ""));
1479
1480                         if (tempShort & INV_AUTONEG_1000BASE_T)
1481                                 proto_tree_add_text(autoneg_advertised_subtree, tvb, (offset+2), 2, "%s",
1482                                                         decode_boolean_bitfield(tempShort, INV_AUTONEG_1000BASE_T,
1483                                                         16, "1000BASE-T (half duplex mode)", ""));
1484
1485                         if (tempShort & INV_AUTONEG_1000BASE_XFD)
1486                                 proto_tree_add_text(autoneg_advertised_subtree, tvb, (offset+2), 2, "%s",
1487                                                         decode_boolean_bitfield(tempShort, INV_AUTONEG_1000BASE_XFD,
1488                                                         16, "1000BASE-X (-LX, -SX, -CX full duplex mode)", ""));
1489
1490                         if (tempShort & INV_AUTONEG_1000BASE_X)
1491                                 proto_tree_add_text(autoneg_advertised_subtree, tvb, (offset+2), 2, "%s",
1492                                                         decode_boolean_bitfield(tempShort, INV_AUTONEG_1000BASE_X,
1493                                                         16, "1000BASE-X (-LX, -SX, -CX half duplex mode)", ""));
1494
1495                         if (tempShort & INV_AUTONEG_FDX_BPAUSE)
1496                                 proto_tree_add_text(autoneg_advertised_subtree, tvb, (offset+2), 2, "%s",
1497                                                         decode_boolean_bitfield(tempShort, INV_AUTONEG_FDX_BPAUSE,
1498                                                         16, "Asymmetric and Symmetric PAUSE (for full-duplex links)", ""));
1499
1500                         if (tempShort & INV_AUTONEG_FDX_SPAUSE)
1501                                 proto_tree_add_text(autoneg_advertised_subtree, tvb, (offset+2), 2, "%s",
1502                                                         decode_boolean_bitfield(tempShort, INV_AUTONEG_FDX_SPAUSE,
1503                                                         16, "Symmetric PAUSE (for full-duplex links)", ""));
1504
1505                         if (tempShort & INV_AUTONEG_FDX_APAUSE)
1506                                 proto_tree_add_text(autoneg_advertised_subtree, tvb, (offset+2), 2, "%s",
1507                                                         decode_boolean_bitfield(tempShort, INV_AUTONEG_FDX_APAUSE,
1508                                                         16, "Asymmetric PAUSE (for full-duplex links)", ""));
1509
1510                         if (tempShort & INV_AUTONEG_FDX_PAUSE)
1511                                 proto_tree_add_text(autoneg_advertised_subtree, tvb, (offset+2), 2, "%s",
1512                                                         decode_boolean_bitfield(tempShort, INV_AUTONEG_FDX_PAUSE,
1513                                                         16, "PAUSE (for full-duplex links)", ""));
1514
1515                         if (tempShort & INV_AUTONEG_100BASE_T2FD)
1516                                 proto_tree_add_text(autoneg_advertised_subtree, tvb, (offset+2), 2, "%s",
1517                                                         decode_boolean_bitfield(tempShort, INV_AUTONEG_100BASE_T2FD,
1518                                                         16, "100BASE-T2 (full duplex mode)", ""));
1519
1520                         if (tempShort & INV_AUTONEG_100BASE_T2)
1521                                 proto_tree_add_text(autoneg_advertised_subtree, tvb, (offset+2), 2, "%s",
1522                                                         decode_boolean_bitfield(tempShort, INV_AUTONEG_100BASE_T2,
1523                                                         16, "100BASE-T2 (half duplex mode)", ""));
1524
1525                         if (tempShort & INV_AUTONEG_100BASE_TXFD)
1526                                 proto_tree_add_text(autoneg_advertised_subtree, tvb, (offset+2), 2, "%s",
1527                                                         decode_boolean_bitfield(tempShort, INV_AUTONEG_100BASE_TXFD,
1528                                                         16, "100BASE-TX (full duplex mode)", ""));
1529
1530                         if (tempShort & INV_AUTONEG_100BASE_TX)
1531                                 proto_tree_add_text(autoneg_advertised_subtree, tvb, (offset+2), 2, "%s",
1532                                                         decode_boolean_bitfield(tempShort, INV_AUTONEG_100BASE_TX,
1533                                                         16, "100BASE-TX (half duplex mode)", ""));
1534
1535                         if (tempShort & INV_AUTONEG_100BASE_T4)
1536                                 proto_tree_add_text(autoneg_advertised_subtree, tvb, (offset+2), 2, "%s",
1537                                                         decode_boolean_bitfield(tempShort, INV_AUTONEG_100BASE_T4,
1538                                                         16, "100BASE-T4", ""));
1539
1540                         if (tempShort & INV_AUTONEG_10BASET_FD)
1541                                 proto_tree_add_text(autoneg_advertised_subtree, tvb, (offset+2), 2, "%s",
1542                                                         decode_boolean_bitfield(tempShort, INV_AUTONEG_10BASET_FD,
1543                                                         16, "10BASE-T (full duplex mode)", ""));
1544
1545                         if (tempShort & INV_AUTONEG_10BASE_T)
1546                                 proto_tree_add_text(autoneg_advertised_subtree, tvb, (offset+2), 2, "%s",
1547                                                         decode_boolean_bitfield(tempShort, INV_AUTONEG_10BASE_T,
1548                                                         16, "10BASE-T (half duplex mode)", ""));
1549
1550                         if (tempShort & INV_AUTONEG_OTHER)
1551                                 proto_tree_add_text(autoneg_advertised_subtree, tvb, (offset+2), 2, "%s",
1552                                                         decode_boolean_bitfield(tempShort, INV_AUTONEG_OTHER,
1553                                                         16, "other or unknown", ""));
1554
1555                 }
1556
1557                 tempOffset += 2;
1558
1559                 /* Get operational MAU type */
1560                 tempShort = tvb_get_ntohs(tvb, tempOffset);
1561                 if (tree)
1562                         proto_tree_add_text(tree, tvb, tempOffset, 2, "Operational MAU Type: %s (0x%04X)",
1563                                                         val_to_str(tempShort,operational_mau_type_values,"Unknown"),
1564                                                         tempShort);
1565
1566                 tempOffset += 2;
1567
1568                 break;
1569         }
1570         case 0x02:      /* MDI Power Support */
1571         {
1572                 const char *strPtr;
1573
1574                 /* Get MDI power support info */
1575                 tempByte = tvb_get_guint8(tvb, tempOffset);
1576                 if (tree)
1577                 {
1578                         tf = proto_tree_add_text(tree, tvb, tempOffset, 1, "MDI Power Support: 0x%02x", tempByte);
1579                         mac_phy_flags = proto_item_add_subtree(tf, ett_802_3_power);
1580
1581                         /* Get port class */
1582                         proto_tree_add_text(mac_phy_flags, tvb, tempOffset, 1, "%s",
1583                                                 decode_boolean_bitfield(tempByte, 0x01, 8, "Port Class: PSE",
1584                                                                                                 "Port Class: PD"));
1585
1586                         /* Get PSE MDI power support */
1587                         proto_tree_add_text(mac_phy_flags, tvb, tempOffset, 1, "%s",
1588                                                 decode_boolean_bitfield(tempByte, 0x02, 8, "PSE MDI Power: Supported",
1589                                                                                                 "PSE MDI Power: Not Supported"));
1590
1591                         /* Get PSE MDI power state */
1592                         proto_tree_add_text(mac_phy_flags, tvb, tempOffset, 1, "%s",
1593                                                 decode_boolean_bitfield(tempByte, 0x04, 8, "PSE MDI Power Enabled: Yes",
1594                                                                                                 "PSE MDI Power Enabled: No"));
1595
1596                         /* Get PSE pairs control ability */
1597                         proto_tree_add_text(mac_phy_flags, tvb, tempOffset, 1, "%s",
1598                                                 decode_boolean_bitfield(tempByte, 0x08, 8, "PSE Pairs Control Ability: Yes",
1599                                                                                                 "PSE Pairs Control Ability: No"));
1600                 }
1601
1602                 tempOffset++;
1603
1604                 /* Get PSE power pair */
1605                 tempByte = tvb_get_guint8(tvb, tempOffset);
1606                 if (tree)
1607                         proto_tree_add_text(tree, tvb, tempOffset, 1, "PSE Power Pair: %u", tempByte);
1608
1609                 tempOffset++;
1610
1611                 /* Get power class */
1612                 tempByte = tvb_get_guint8(tvb, tempOffset);
1613                 if (tree)
1614                         proto_tree_add_text(tree, tvb, tempOffset, 1, "Power Class: %u", tempByte);
1615
1616                 tempOffset++;
1617
1618                 /* Get first byte */
1619                 tempByte = tvb_get_guint8(tvb, tempOffset);
1620
1621                 /* Determine power type */
1622                 subType = ((tempByte & 0xC0) >> 6);
1623                 if (tree)
1624                         proto_tree_add_text(tree, tvb, tempOffset, 1, "%s %s %s",
1625                                 decode_boolean_bitfield(tempByte, 0xC0, 8, "Power Type:", "Power Type:"),
1626                                 val_to_str(subType, power_type_802_3, "Unkown"),
1627                                 val_to_str(subType, media_power_type, "Unknown"));
1628
1629                 /* Determine power source */
1630                 switch (subType)
1631                 {
1632                 case 0:
1633                 case 2:
1634                 {
1635                         subType = ((tempByte & 0x30) >> 4);
1636                         strPtr = val_to_str(subType, media_power_pse_device, "Reserved");
1637
1638                         break;
1639                 }
1640                 case 1:
1641                 case 3:
1642                 {
1643                         subType = ((tempByte & 0x30) >> 4);
1644                         strPtr = val_to_str(subType, media_power_pd_device, "Reserved");
1645
1646                         break;
1647                 }
1648                 default:
1649                 {
1650                         strPtr = "Unknown";
1651                         break;
1652                 }
1653                 }
1654                 if (tree)
1655                         proto_tree_add_text(tree, tvb, tempOffset, 1, "%s %s",
1656                                 decode_boolean_bitfield(tempByte, 0x30, 8, "Power Source:", "Power Source:"),
1657                                 strPtr);
1658
1659                 /* Determine power priority */
1660                 subType = (tempByte & 0x0F);
1661                 if (tree)
1662                         proto_tree_add_text(tree, tvb, tempOffset, 1, "%s %s",
1663                                 decode_boolean_bitfield(tempByte, 0x0F, 8, "Power Priority:", "Power Priority:"),
1664                                 val_to_str(subType, media_power_priority, "Reserved"));
1665
1666                 tempOffset++;
1667
1668                 /* Power Value: 1 to 255 expected  */
1669                 tempShort = tvb_get_ntohs(tvb, tempOffset);
1670                 if (tree)
1671                         proto_tree_add_text(tree, tvb, tempOffset, 2, "PD Requested Power Value: %u.%u Watt", tempShort/10, tempShort%10);
1672
1673                 tempOffset+=2;
1674
1675                 /* Power Value: 1 to 255 expected */
1676                 tempShort = tvb_get_ntohs(tvb, tempOffset);
1677                 if (tree)
1678                         proto_tree_add_text(tree, tvb, tempOffset, 2, "PSE Allocated Power Value: %u.%u Watt", tempShort/10, tempShort%10);
1679
1680                 tempOffset+=2;
1681
1682                 break;
1683         }
1684         case 0x03:      /* Link Aggregation */
1685         {
1686                 /* Get aggregation status */
1687                 tempByte = tvb_get_guint8(tvb, tempOffset);
1688                 if (tree)
1689                 {
1690                         tf = proto_tree_add_text(tree, tvb, tempOffset, 1, "Aggregation Status: 0x%02x", tempByte);
1691                         mac_phy_flags = proto_item_add_subtree(tf, ett_802_3_aggregation);
1692
1693                         /* Get aggregation capability */
1694                         proto_tree_add_text(mac_phy_flags, tvb, tempOffset, 1, "%s",
1695                                                 decode_boolean_bitfield(tempByte, 0x01, 8, "Aggregation Capability: Yes",
1696                                                                                                 "Aggregation Capability: No"));
1697
1698                         /* Get aggregation status */
1699                         proto_tree_add_text(mac_phy_flags, tvb, tempOffset, 1, "%s",
1700                                                 decode_boolean_bitfield(tempByte, 0x02, 8, "Aggregation Status: Enabled",
1701                                                                                                 "Aggregation Status: Not Enabled"));
1702                 }
1703
1704                 tempOffset++;
1705
1706                 /* Get aggregated port id */
1707                 tempLong = tvb_get_ntohl(tvb, tempOffset);
1708                 if (tree)
1709                         proto_tree_add_text(tree, tvb, tempOffset, 4, "Aggregated Port Id: %u", tempLong);
1710
1711                 tempOffset += 4;
1712
1713                 break;
1714         }
1715         case 0x04:      /* Maximum Frame Size */
1716         {
1717                 /* Get maximum frame size */
1718                 tempShort = tvb_get_ntohs(tvb, tempOffset);
1719                 if (tree)
1720                         proto_tree_add_text(tree, tvb, tempOffset, 2, "Maximum Frame Size: %u", tempShort);
1721
1722                 tempOffset += 2;
1723
1724                 break;
1725         }
1726         }
1727
1728         return;
1729 }
1730
1731 /* Dissect Media TLVs */
1732 static void
1733 dissect_media_tlv(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, guint32 offset, guint16 tlvLen)
1734 {
1735         guint32 tempOffset = offset;
1736         guint8 subType;
1737         guint16 tempShort;
1738         guint16 tempVLAN;
1739         guint8 tempByte;
1740         guint32 tempLong;
1741         const char *strPtr;
1742         guint32 LCI_Length;
1743         guint64 temp64bit = 0;
1744
1745         proto_tree      *media_flags = NULL;
1746         proto_item      *tf = NULL;
1747
1748         /* Get subtype */
1749         subType = tvb_get_guint8(tvb, tempOffset);
1750         if (tree)
1751                 proto_tree_add_item(tree, hf_media_tlv_subtype, tvb, tempOffset, 1, FALSE);
1752         tempOffset++;
1753         tlvLen--;
1754
1755         switch (subType)
1756         {
1757         case 1:         /* LLDP-MED Capabilities */
1758         {
1759                 /* Get capabilities */
1760                 if (tlvLen < 2)
1761                 {
1762                         proto_tree_add_text(tree, tvb, tempOffset, 0, "TLV too short");
1763                         return;
1764                 }
1765                 tempShort = tvb_get_ntohs(tvb, tempOffset);
1766                 if (tree)
1767                 {
1768                         tf = proto_tree_add_text(tree, tvb, tempOffset, 2, "Capabilities: 0x%04x", tempShort);
1769                         media_flags = proto_item_add_subtree(tf, ett_media_capabilities);
1770                         if (tempShort & MEDIA_CAPABILITY_LLDP)
1771                                 proto_tree_add_text(media_flags, tvb, tempOffset, 2, "%s",
1772                                                 decode_boolean_bitfield(tempShort, MEDIA_CAPABILITY_LLDP, 16,
1773                                                                                                 "LLDP-MED Capabilities", ""));
1774                         if (tempShort & MEDIA_CAPABILITY_NETWORK_POLICY)
1775                                 proto_tree_add_text(media_flags, tvb, tempOffset, 2, "%s",
1776                                                 decode_boolean_bitfield(tempShort, MEDIA_CAPABILITY_NETWORK_POLICY, 16,
1777                                                                                                 "Network Policy", ""));
1778                         if (tempShort & MEDIA_CAPABILITY_LOCATION_ID)
1779                                 proto_tree_add_text(media_flags, tvb, tempOffset, 2, "%s",
1780                                                 decode_boolean_bitfield(tempShort, MEDIA_CAPABILITY_LOCATION_ID, 16,
1781                                                                                                 "Location Identification", ""));
1782                         if (tempShort & MEDIA_CAPABILITY_MDI_PSE)
1783                                 proto_tree_add_text(media_flags, tvb, tempOffset, 2, "%s",
1784                                                 decode_boolean_bitfield(tempShort, MEDIA_CAPABILITY_MDI_PSE, 16,
1785                                                                                                 "Extended Power via MDI-PSE", ""));
1786                         if (tempShort & MEDIA_CAPABILITY_MDI_PD)
1787                                 proto_tree_add_text(media_flags, tvb, tempOffset, 2, "%s",
1788                                                 decode_boolean_bitfield(tempShort, MEDIA_CAPABILITY_MDI_PD, 16,
1789                                                                                                 "Extended Power via MDI-PD", ""));
1790                         if (tempShort & MEDIA_CAPABILITY_INVENTORY)
1791                                 proto_tree_add_text(media_flags, tvb, tempOffset, 2, "%s",
1792                                                 decode_boolean_bitfield(tempShort, MEDIA_CAPABILITY_INVENTORY, 16,
1793                                                                                                 "Inventory", ""));
1794                 }
1795                 tempOffset += 2;
1796                 tlvLen -= 2;
1797
1798                 /* Get Class type */
1799                 if (tlvLen < 1)
1800                 {
1801                         proto_tree_add_text(tree, tvb, tempOffset, 0, "TLV too short");
1802                         return;
1803                 }
1804                 tempByte = tvb_get_guint8(tvb, tempOffset);
1805                 if (tree)
1806                         proto_tree_add_text(tree, tvb, tempOffset, 1, "Class Type: %s", val_to_str(tempByte, media_class_values, "Unknown"));
1807                 tempOffset++;
1808                 tlvLen--;
1809
1810                 break;
1811         }
1812         case 2:         /* Network Policy */
1813         {
1814                 /* Get application type */
1815                 if (tlvLen < 1)
1816                 {
1817                         proto_tree_add_text(tree, tvb, tempOffset, 0, "TLV too short");
1818                         return;
1819                 }
1820                 tempByte = tvb_get_guint8(tvb, tempOffset);
1821                 if (tree)
1822                         proto_tree_add_text(tree, tvb, tempOffset, 1, "Application Type: %s (%u)",
1823                                                         val_to_str(tempByte, media_application_type, "Unknown"), tempByte);
1824                 tempOffset++;
1825                 tlvLen--;
1826
1827                 /* Get flags */
1828                 if (tlvLen < 2)
1829                 {
1830                         proto_tree_add_text(tree, tvb, tempOffset, 0, "TLV too short");
1831                         return;
1832                 }
1833                 tempShort = tvb_get_ntohs(tvb, tempOffset);
1834
1835                 /* Unknown policy flag */
1836                 if (tree)
1837                         proto_tree_add_text(tree, tvb, tempOffset, 2, "%s",
1838                                                 decode_boolean_bitfield(tempShort, 0x8000, 16,"Policy: Unknown", "Policy: Defined"));
1839
1840                 /* Tagged flag */
1841                 if (tree)
1842                         proto_tree_add_text(tree, tvb, tempOffset, 2, "%s",
1843                                                 decode_boolean_bitfield(tempShort, 0x4000, 16,"Tagged: Yes", "Tagged: No"));
1844
1845                 /* Get vlan id */
1846                 tempVLAN = (tempShort & 0x1FFE) >> 1;
1847                 if (tree)
1848                         proto_tree_add_text(tree, tvb, tempOffset, 2, "%s %u",
1849                                                 decode_boolean_bitfield(tempShort, 0x1FFE, 16, "VLAN Id:", "VLAN Id:"), tempVLAN);
1850                 tempOffset++;
1851                 tlvLen--;
1852
1853                 /* Get L2 priority */
1854                 if (tlvLen < 1)
1855                 {
1856                         proto_tree_add_text(tree, tvb, tempOffset, 0, "TLV too short");
1857                         return;
1858                 }
1859                 tempShort = tvb_get_ntohs(tvb, tempOffset);
1860                 if (tree)
1861                         proto_tree_add_text(tree, tvb, tempOffset, 2, "%s %u",
1862                                                 decode_boolean_bitfield(tempShort, 0x01C0, 16, "L2 Priority:", "L2 Priority:"),
1863                                                                                                 ((tempShort & 0x01C0) >> 6));
1864                 tempOffset++;
1865                 tlvLen--;
1866
1867                 /* Get DSCP value */
1868                 tempByte = tvb_get_guint8(tvb, tempOffset);
1869                 if (tree)
1870                         proto_tree_add_text(tree, tvb, tempOffset, 1, "%s %u",
1871                                                 decode_boolean_bitfield(tempByte, 0x3F, 8, "DSCP Value:", "DSCP Value:"),
1872                                                                                                 (tempByte & 0x3F));
1873
1874                 break;
1875         }
1876         case 3: /* Location Identification */
1877         {
1878                 /* Get location data format */
1879                 if (tlvLen < 1)
1880                 {
1881                         proto_tree_add_text(tree, tvb, tempOffset, 0, "TLV too short");
1882                         return;
1883                 }
1884                 tempByte = tvb_get_guint8(tvb, tempOffset);
1885                 if (tree)
1886                         proto_tree_add_text(tree, tvb, tempOffset, 1, "Location Data Format: %s (%u)",
1887                                                         val_to_str(tempByte, location_data_format, "Unknown"), tempByte);
1888                 tempOffset++;
1889                 tlvLen--;
1890
1891                 switch (tempByte)
1892                 {
1893                 case 1: /* Coordinate-based LCI */
1894                 {
1895                         /*
1896                          * See RFC 3825.
1897                          * XXX - should this be handled by the BOOTP
1898                          * dissector, and exported to us?
1899                          */
1900                         if (tlvLen < 16)
1901                         {
1902                                 proto_tree_add_text(tree, tvb, tempOffset, 0, "TLV too short");
1903                                 return;
1904                         }
1905
1906                         /* Get latitude resolution */
1907                         tempByte = tvb_get_guint8(tvb, tempOffset);
1908                         if (tree)
1909                                 proto_tree_add_text(tree, tvb, tempOffset, 1, "%s %u",
1910                                                 decode_boolean_bitfield(tempByte, 0xFC, 8, "Latitude Resolution:", "Latitude Resolution:"),
1911                                                                                                 ((tempByte & 0xFC) >> 2));
1912
1913                         /* Get latitude */
1914                         temp64bit = tvb_get_ntoh64(tvb, tempOffset);
1915                         temp64bit = (temp64bit & G_GINT64_CONSTANT(0x03FFFFFFFF000000)) >> 24;
1916                         if (tree)
1917                                 proto_tree_add_text(tree, tvb, tempOffset, 5, "Latitude: %s (0x%16" G_GINT64_MODIFIER "X)",
1918                                     get_latitude_or_longitude(0, temp64bit),
1919                                     temp64bit);
1920
1921                         tempOffset += 5;
1922
1923                         /* Get longitude resolution */
1924                         tempByte = tvb_get_guint8(tvb, tempOffset);
1925                         if (tree)
1926                                 proto_tree_add_text(tree, tvb, tempOffset, 1, "%s %u",
1927                                         decode_boolean_bitfield(tempByte, 0xFC, 8, "Longitude Resolution:", "Longitude Resolution:"),
1928                                                                                         ((tempByte & 0xFC) >> 2));
1929
1930                         /* Get longitude */
1931                         temp64bit = tvb_get_ntoh64(tvb, tempOffset);
1932                         temp64bit = (temp64bit & G_GINT64_CONSTANT(0x03FFFFFFFF000000)) >> 24;
1933                         ;
1934                         if (tree)
1935                                 proto_tree_add_text(tree, tvb, tempOffset, 5, "Longitude: %s (0x%16" G_GINT64_MODIFIER "X)",
1936                                     get_latitude_or_longitude(1,temp64bit),
1937                                     temp64bit);
1938
1939                         tempOffset += 5;
1940
1941                         /* Altitude Type */
1942                         tempByte = tvb_get_guint8(tvb, tempOffset);
1943                         if (tree)
1944                         {
1945                                 tf = proto_tree_add_text(tree, tvb, tempOffset, 1, "%s",
1946                                                 decode_boolean_bitfield(tempByte, 0xF0, 8, "Altitude Type: ", "Altitude Type: "));
1947
1948                                 switch ((tempByte >> 4))
1949                                 {
1950                                 case 1:
1951                                         proto_item_append_text(tf, "Meters (1)");
1952                                         break;
1953                                 case 2:
1954                                         proto_item_append_text(tf, "Floors (2)");
1955                                         break;
1956                                 default:
1957                                         proto_item_append_text(tf, " Unknown (%u)", (tempByte >> 4));
1958                                         break;
1959                                 }
1960                         }
1961
1962                         /* Get Altitude Resolution */
1963                         tempShort = tvb_get_ntohs(tvb, tempOffset);
1964                         if (tree)
1965                                 proto_tree_add_text(tree, tvb, tempOffset, 2, "%s %u",
1966                                                 decode_boolean_bitfield(tempShort, 0x0FC0, 16, "Altitude Resolution: ", "Altitude Type: "),
1967                                                 ((tempShort & 0x0FC0) >> 6));
1968
1969                         tempOffset++;
1970
1971                         /* Get Altitude */
1972                         tempLong = (tvb_get_ntohl(tvb, tempOffset) & 0x03FFFFFFF);
1973                         if (tree)
1974                                 proto_tree_add_text(tree, tvb, tempOffset, 4, "Altitude: 0x%08X", tempLong);
1975
1976                         tempOffset += 4;
1977
1978                         /* Get datum */
1979                         tempByte = tvb_get_guint8(tvb, tempOffset);
1980                         if (tree)
1981                                 proto_tree_add_text(tree, tvb, tempOffset, 1, "Datum: %u", tempByte);
1982
1983                         break;
1984                 }
1985                 case 2: /* Civic Address LCI */
1986                 {
1987                         /*
1988                          * See draft-ietf-geopriv-dhcp-civil-07.
1989                          * XXX - should this be handled by the BOOTP
1990                          * dissector, and exported to us?
1991                          */
1992                         if (tlvLen < 1)
1993                         {
1994                                 proto_tree_add_text(tree, tvb, tempOffset, 0, "TLV too short");
1995                                 return;
1996                         }
1997
1998                         /* Get LCI length */
1999                         tempByte = tvb_get_guint8(tvb, tempOffset);
2000                         tlvLen--;
2001                         if (tempByte > tlvLen)
2002                         {
2003                                 if (tree)
2004                                         proto_tree_add_text(tree, tvb, tempOffset, 1, "LCI Length: %u (greater than TLV length)", tempByte);
2005
2006                                 return;
2007                         }
2008
2009                         if (tree)
2010                                 proto_tree_add_text(tree, tvb, tempOffset, 1, "LCI Length: %u", tempByte);
2011
2012                         LCI_Length = (guint32)tempByte;
2013
2014                         tempOffset++;
2015
2016                         /* Get what value */
2017                         if (LCI_Length < 1)
2018                         {
2019                                 proto_tree_add_text(tree, tvb, tempOffset, 0, "LCI Length too short");
2020                                 return;
2021                         }
2022                         tempByte = tvb_get_guint8(tvb, tempOffset);
2023                         if (tree)
2024                                 proto_tree_add_text(tree, tvb, tempOffset, 1, "What: %s (%u)",
2025                                                                         val_to_str(tempByte,civic_address_what_values,"Unknown"),
2026                                                                         tempByte);
2027                         tempOffset++;
2028                         LCI_Length--;
2029
2030                         /* Get country code */
2031                         if (LCI_Length < 2)
2032                         {
2033                                 proto_tree_add_text(tree, tvb, tempOffset, 0, "LCI Length too short");
2034                                 return;
2035                         }
2036                         if (tree)
2037                                 proto_tree_add_text(tree, tvb, tempOffset, 2, "Country: %s",
2038                                     tvb_format_text(tvb, tempOffset, 2));
2039
2040                         tempOffset += 2;
2041                         LCI_Length -= 2;
2042
2043                         while (LCI_Length > 0)
2044                         {
2045                                 /* Get CA Type */
2046                                 if (LCI_Length < 1)
2047                                 {
2048                                         proto_tree_add_text(tree, tvb, tempOffset, 0, "LCI Length too short");
2049                                         return;
2050                                 }
2051                                 tempByte = tvb_get_guint8(tvb, tempOffset);
2052                                 if (tree)
2053                                         proto_tree_add_text(tree, tvb, tempOffset, 1, "CA Type: %s (%u)",
2054                                                                         val_to_str(tempByte,civic_address_type_values,"Unknown"),
2055                                                                         tempByte);
2056
2057                                 tempOffset++;
2058                                 LCI_Length--;
2059
2060                                 /* Get CA Length */
2061                                 if (LCI_Length < 1)
2062                                 {
2063                                         proto_tree_add_text(tree, tvb, tempOffset, 0, "LCI Length too short");
2064                                         return;
2065                                 }
2066                                 tempByte = tvb_get_guint8(tvb, tempOffset);
2067                                 if (tree)
2068                                         proto_tree_add_text(tree, tvb, tempOffset, 1, "CA Length: %u", tempByte);
2069
2070                                 tempOffset++;
2071                                 LCI_Length--;
2072
2073                                 /* Make sure the CA value is within the specified length */
2074                                 if (tempByte > LCI_Length)
2075                                         return;
2076
2077                                 if (tempByte > 0)
2078                                 {
2079                                         /* Get CA Value */
2080                                         if (tree)
2081                                                 proto_tree_add_text(tree, tvb, tempOffset, tempByte, "CA Value: %s",
2082                                                     tvb_format_stringzpad(tvb, tempOffset, tempByte));
2083
2084                                         tempOffset += tempByte;
2085                                         LCI_Length -= tempByte;
2086                                 }
2087                         }
2088
2089                         break;
2090                 }
2091                 case 3: /* ECS ELIN */
2092                 {
2093                         if (tlvLen > 0)
2094                         {
2095                                 if (tree)
2096                                         proto_tree_add_text(tree, tvb, tempOffset, tlvLen, "ELIN: %s",
2097                                             tvb_format_stringzpad(tvb, tempOffset, tlvLen));
2098
2099                         }
2100
2101                         break;
2102                 }
2103                 }
2104
2105                 break;
2106         }
2107         case 4: /* Extended Power-via-MDI */
2108         {
2109                 /* Get first byte */
2110                 tempByte = tvb_get_guint8(tvb, tempOffset);
2111
2112                 /* Determine power type */
2113                 subType = ((tempByte & 0xC0) >> 6);
2114                 if (tree)
2115                         proto_tree_add_text(tree, tvb, tempOffset, 1, "%s %s",
2116                                                 decode_boolean_bitfield(tempByte, 0xC0, 8, "Power Type:", "Power Type:"),
2117                                                                                                 val_to_str(subType, media_power_type, "Unknown"));
2118
2119                 /* Determine power source */
2120                 switch (subType)
2121                 {
2122                 case 0:
2123                 {
2124                         subType = ((tempByte & 0x30) >> 4);
2125                         strPtr = val_to_str(subType, media_power_pse_device, "Reserved");
2126
2127                         break;
2128                 }
2129                 case 1:
2130                 {
2131                         subType = ((tempByte & 0x30) >> 4);
2132                         strPtr = val_to_str(subType, media_power_pd_device, "Reserved");
2133
2134                         break;
2135                 }
2136                 default:
2137                 {
2138                         strPtr = "Unknown";
2139                         break;
2140                 }
2141                 }
2142                 if (tree)
2143                         proto_tree_add_text(tree, tvb, tempOffset, 1, "%s %s",
2144                                                 decode_boolean_bitfield(tempByte, 0x30, 8, "Power Source:", "Power Source:"),
2145                                                                                                 strPtr);
2146
2147                 /* Determine power priority */
2148                 subType = (tempByte & 0x0F);
2149                 if (tree)
2150                         proto_tree_add_text(tree, tvb, tempOffset, 1, "%s %s",
2151                                                 decode_boolean_bitfield(tempByte, 0x0F, 8, "Power Priority:", "Power Priority:"),
2152                                                                                                 val_to_str(subType, media_power_priority, "Reserved"));
2153
2154                 tempOffset++;
2155
2156                 /* Power Value: 0 to 102.3 Watts (0.1 W increments) */
2157                 tempShort = tvb_get_ntohs(tvb, tempOffset) * 100;
2158                 if (tree)
2159                         proto_tree_add_text(tree, tvb, tempOffset, 2, "Power Value: %u mW", tempShort);
2160
2161                 break;
2162         }
2163         case 5: /* Hardware Revision */
2164         {
2165                 /* Figure out the length of the hardware revision field */
2166                 if (tlvLen > 0)
2167                 {
2168                         if (tree)
2169                                 proto_tree_add_text(tree, tvb, tempOffset, tlvLen, "Hardware Revision: %s",
2170                                     tvb_format_stringzpad(tvb, tempOffset, tlvLen));
2171                 }
2172
2173                 break;
2174         }
2175         case 6: /* Firmware Revision */
2176         {
2177                 /* Figure out the length of the firmware revision field */
2178                 if (tlvLen > 0)
2179                 {
2180                         if (tree)
2181                                 proto_tree_add_text(tree, tvb, tempOffset, tlvLen, "Firmware Revision: %s",
2182                                     tvb_format_stringzpad(tvb, tempOffset, tlvLen));
2183                 }
2184
2185                 break;
2186         }
2187         case 7: /* Software Revision */
2188         {
2189                 /* Figure out the length of the software revision field */
2190                 if (tlvLen > 0)
2191                 {
2192                         if (tree)
2193                                 proto_tree_add_text(tree, tvb, tempOffset, tlvLen, "Software Revision: %s",
2194                                     tvb_format_stringzpad(tvb, tempOffset, tlvLen));
2195                 }
2196
2197                 break;
2198         }
2199         case 8: /* Serial Number */
2200         {
2201                 /* Figure out the length of the serial number field */
2202                 if (tlvLen > 0)
2203                 {
2204                         if (tree)
2205                                 proto_tree_add_text(tree, tvb, tempOffset, tlvLen, "Serial Number: %s",
2206                                     tvb_format_stringzpad(tvb, tempOffset, tlvLen));
2207                 }
2208
2209                 break;
2210         }
2211         case 9: /* Manufacturer Name */
2212         {
2213                 /* Figure out the length of the manufacturer name field */
2214                 if (tlvLen > 0)
2215                 {
2216                         if (tree)
2217                                 proto_tree_add_text(tree, tvb, tempOffset, tlvLen, "Manufacturer Name: %s",
2218                                     tvb_format_stringzpad(tvb, tempOffset, tlvLen));
2219                 }
2220
2221                 break;
2222         }
2223         case 10:        /* Model Name */
2224         {
2225                 /* Figure out the length of the model name field */
2226                 if (tlvLen > 0)
2227                 {
2228                         if (tree)
2229                                 proto_tree_add_text(tree, tvb, tempOffset, tlvLen, "Model Name: %s",
2230                                     tvb_format_stringzpad(tvb, tempOffset, tlvLen));
2231                 }
2232
2233                 break;
2234         }
2235         case 11:        /* Asset ID */
2236         {
2237                 /* Figure out the length of the asset id field */
2238                 if (tlvLen > 0)
2239                 {
2240                         if (tree)
2241                                 proto_tree_add_text(tree, tvb, tempOffset, tlvLen, "Asset ID: %s",
2242                                     tvb_format_stringzpad(tvb, tempOffset, tlvLen));
2243                 }
2244
2245                 break;
2246         }
2247         }
2248
2249         return;
2250 }
2251
2252
2253 static guint32
2254 dissect_profinet_period(tvbuff_t *tvb, proto_tree *tree, guint32 offset, const gchar *name, int hf_valid, int hf_value)
2255 {
2256     guint32 period;
2257     proto_tree  *period_tree;
2258     proto_item  *period_item;
2259
2260
2261     period = tvb_get_ntohl(tvb, offset);
2262
2263     period_item = proto_tree_add_text(tree, tvb, offset, 4, "%s: %s, %uns",
2264         name, (period & 0x80000000) ? "Valid" : "Invalid", period & 0x7FFFFFFF);
2265     period_tree = proto_item_add_subtree(period_item, ett_profinet_period);
2266
2267     proto_tree_add_uint(period_tree, hf_valid, tvb, offset, 4, period);
2268     proto_tree_add_uint(period_tree, hf_value, tvb, offset, 4, period);
2269     offset+=4;
2270
2271     return offset;
2272 }
2273
2274
2275 /* Dissect PROFINET TLVs */
2276 static void
2277 dissect_profinet_tlv(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, guint32 offset, guint16 tlvLen2)
2278 {
2279         guint8 subType;
2280         proto_item      *tf = NULL;
2281         guint16 class2_PortStatus;
2282         guint16 class3_PortStatus;
2283         guint32 port_rx_delay_local;
2284         guint32 port_rx_delay_remote;
2285         guint32 port_tx_delay_local;
2286         guint32 port_tx_delay_remote;
2287         guint32 cable_delay_local;
2288         const guint8 *mac_addr = NULL;
2289         e_guid_t * uuid;
2290         guint16 mrrt_PortStatus;
2291
2292
2293         /* Get subtype */
2294         subType = tvb_get_guint8(tvb, offset);
2295         if (tree)
2296                 proto_tree_add_uint(tree, hf_profinet_tlv_subtype, tvb, offset, 1, subType);
2297         offset++;
2298
2299         switch (subType)
2300         {
2301         case 1:         /* LLDP_PNIO_DELAY */
2302         {
2303                 port_rx_delay_local = tvb_get_ntohl(tvb, offset);
2304                 tf = proto_tree_add_uint(tree, hf_profinet_port_rx_delay_local, tvb, offset, 4, port_rx_delay_local);
2305                 if(port_rx_delay_local) {
2306                         proto_item_append_text(tf, "ns");
2307                 } else {
2308                         proto_item_append_text(tf, " (unknown)");
2309                 }
2310                 offset+=4;
2311                 port_rx_delay_remote = tvb_get_ntohl(tvb, offset);
2312                 tf = proto_tree_add_uint(tree, hf_profinet_port_rx_delay_remote, tvb, offset, 4, port_rx_delay_remote);
2313                 if(port_rx_delay_remote) {
2314                         proto_item_append_text(tf, "ns");
2315                 } else {
2316                         proto_item_append_text(tf, " (unknown)");
2317                 }
2318                 offset+=4;
2319                 port_tx_delay_local = tvb_get_ntohl(tvb, offset);
2320                 tf = proto_tree_add_uint(tree, hf_profinet_port_tx_delay_local, tvb, offset, 4, port_tx_delay_local);
2321                 if(port_tx_delay_local) {
2322                         proto_item_append_text(tf, "ns");
2323                 } else {
2324                         proto_item_append_text(tf, " (unknown)");
2325                 }
2326                 offset+=4;
2327                 port_tx_delay_remote = tvb_get_ntohl(tvb, offset);
2328                 tf = proto_tree_add_uint(tree, hf_profinet_port_tx_delay_remote, tvb, offset, 4, port_tx_delay_remote);
2329                 if(port_tx_delay_remote) {
2330                         proto_item_append_text(tf, "ns");
2331                 } else {
2332                         proto_item_append_text(tf, " (unknown)");
2333                 }
2334                 offset+=4;
2335                 cable_delay_local = tvb_get_ntohl(tvb, offset);
2336                 tf = proto_tree_add_uint(tree, hf_profinet_cable_delay_local, tvb, offset, 4, cable_delay_local);
2337                 if(cable_delay_local) {
2338                         proto_item_append_text(tf, "ns");
2339                 } else {
2340                         proto_item_append_text(tf, " (unknown)");
2341                 }
2342                 offset+=4;
2343                 break;
2344         }
2345         case 2:         /* LLDP_PNIO_PORTSTATUS */
2346         {
2347                 class2_PortStatus = tvb_get_ntohs(tvb, offset);
2348                 proto_tree_add_uint(tree, hf_profinet_class2_port_status, tvb, offset, 2, class2_PortStatus);
2349                 offset+=2;
2350                 class3_PortStatus = tvb_get_ntohs(tvb, offset);
2351                 proto_tree_add_uint(tree, hf_profinet_class3_port_status, tvb, offset, 2, class3_PortStatus);
2352                 offset+=2;
2353                 break;
2354         }
2355         /*case 3:*/     /* XXX - LLDP_PNIO_ALIAS */
2356         case 4:         /* LLDP_PNIO_MRPPORTSTATUS */
2357         {
2358             /* DomainUUID */
2359             tvb_get_ntohguid (tvb, offset, (e_guid_t *) &uuid);
2360             proto_tree_add_guid(tree, hf_profinet_mrp_domain_uuid, tvb, offset, 16, (e_guid_t *) &uuid);
2361             offset += 16;
2362
2363             /* MRRT PortStatus */
2364             mrrt_PortStatus = tvb_get_ntohs(tvb, offset);
2365             proto_tree_add_uint(tree, hf_profinet_mrrt_port_status, tvb, offset, 2, mrrt_PortStatus);
2366             offset+=2;
2367             break;
2368         }
2369     case 5:     /* LLDP_PNIO_CHASSIS_MAC */
2370     {
2371         mac_addr=tvb_get_ptr(tvb, offset, 6);
2372         proto_tree_add_ether(tree, hf_profinet_cm_mac, tvb, offset, 6, mac_addr);
2373         offset += 6;
2374         break;
2375     }
2376     case 6:     /* LLDP_PNIO_PTCPSTATUS */
2377     {
2378             /* MasterSourceAddress */
2379             mac_addr=tvb_get_ptr(tvb, offset, 6);
2380             proto_tree_add_ether(tree, hf_profinet_master_source_address, tvb, offset, 6, mac_addr);
2381             offset += 6;
2382             /* SubdomainUUID */
2383             tvb_get_ntohguid (tvb, offset, (e_guid_t *) &uuid);
2384             proto_tree_add_guid(tree, hf_profinet_subdomain_uuid, tvb, offset, 16, (e_guid_t *) &uuid);
2385             offset += 16;
2386         /* IRDataUUID */
2387             tvb_get_ntohguid (tvb, offset, (e_guid_t *) &uuid);
2388             proto_tree_add_guid(tree, hf_profinet_ir_data_uuid, tvb, offset, 16, (e_guid_t *) &uuid);
2389             offset += 16;
2390         /* LengthOfPeriod */
2391         offset = dissect_profinet_period(tvb, tree, offset, "LengthOfPeriod",
2392             hf_profinet_length_of_period_valid, hf_profinet_length_of_period_length);
2393         /* RedPeriodBegin */
2394         offset = dissect_profinet_period(tvb, tree, offset, "RedPeriodBegin",
2395             hf_profinet_red_period_begin_valid, hf_profinet_red_period_begin_offset);
2396         /* OrangePeriodBegin */
2397         offset = dissect_profinet_period(tvb, tree, offset, "OrangePeriodBegin",
2398             hf_profinet_orange_period_begin_valid, hf_profinet_orange_period_begin_offset);
2399         /* GreenPeriodBegin */
2400         offset = dissect_profinet_period(tvb, tree, offset, "GreenPeriodBegin",
2401             hf_profinet_green_period_begin_valid, hf_profinet_green_period_begin_offset);
2402         break;
2403     }
2404         default:
2405                 proto_tree_add_item(tree, hf_unknown_subtype, tvb, offset, tlvLen2-1, FALSE);
2406         }
2407 }
2408
2409
2410 /* Dissect Organizational Specific TLV */
2411 static gint32
2412 dissect_organizational_specific_tlv(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 offset)
2413 {
2414         guint16 tempLen;
2415         guint16 tempShort;
2416         guint32 oui;
2417         guint8 subType;
2418         const char *ouiStr;
2419         const char *subTypeStr;
2420
2421         proto_tree      *org_tlv_tree = NULL;
2422         proto_item      *tf = NULL;
2423
2424         /* Get tlv type and length */
2425         tempShort = tvb_get_ntohs(tvb, offset);
2426
2427         /* Get tlv length */
2428         tempLen = TLV_INFO_LEN(tempShort);
2429
2430         /* Get OUI value */
2431         oui = tvb_get_ntoh24(tvb, (offset+2));
2432         subType = tvb_get_guint8(tvb, (offset+5));
2433
2434         ouiStr = val_to_str(oui, tlv_oui_subtype_vals, "Unknown");
2435         switch(oui)
2436         {
2437         case OUI_IEEE_802_1:
2438                 subTypeStr = val_to_str(subType, ieee_802_1_subtypes, "Unknown subtype 0x%x");
2439                 break;
2440         case OUI_IEEE_802_3:
2441                 subTypeStr = val_to_str(subType, ieee_802_3_subtypes, "Unknown subtype 0x%x");
2442                 break;
2443         case OUI_MEDIA_ENDPOINT:
2444                 subTypeStr = val_to_str(subType, media_subtypes, "Unknown subtype 0x%x");
2445                 break;
2446         case OUI_PROFINET:
2447                 subTypeStr = val_to_str(subType, profinet_subtypes, "Reserved (0x%x)");
2448                 break;
2449         default:
2450                 subTypeStr = "Unknown";
2451                 break;
2452         }
2453
2454         if (tree)
2455         {
2456                 tf = proto_tree_add_text(tree, tvb, offset, (tempLen + 2), "%s - %s",
2457                     ouiStr, subTypeStr);
2458                 org_tlv_tree = proto_item_add_subtree(tf, ett_org_spc_tlv);
2459
2460                 proto_tree_add_item(org_tlv_tree, hf_lldp_tlv_type, tvb, offset, 2, FALSE);
2461         }
2462         if (tempLen < 4)
2463         {
2464                 if (tree)
2465                         proto_tree_add_uint_format(org_tlv_tree, hf_lldp_tlv_len, tvb, offset, 2,
2466                             tempShort, "TLV Length: %u (too short, must be >= 4)", tempLen);
2467
2468                 return (tempLen + 2);
2469         }
2470         if (tree)
2471         {
2472                 proto_tree_add_item(org_tlv_tree, hf_lldp_tlv_len, tvb, offset, 2, FALSE);
2473
2474                 /* Display organizational unique id */
2475                 proto_tree_add_uint(org_tlv_tree, hf_org_spc_oui, tvb, (offset+2), 3, oui);
2476         }
2477
2478         switch (oui)
2479         {
2480         case OUI_IEEE_802_1:
2481                 dissect_ieee_802_1_tlv(tvb, pinfo, org_tlv_tree, (offset+5));
2482                 break;
2483         case OUI_IEEE_802_3:
2484                 dissect_ieee_802_3_tlv(tvb, pinfo, org_tlv_tree, (offset+5));
2485                 break;
2486         case OUI_MEDIA_ENDPOINT:
2487                 dissect_media_tlv(tvb, pinfo, org_tlv_tree, (offset+5), (guint16) (tempLen-3));
2488                 break;
2489         case OUI_PROFINET:
2490                 dissect_profinet_tlv(tvb, pinfo, org_tlv_tree, (offset+5), (guint16) (tempLen-3));
2491                 break;
2492         default:
2493                 proto_tree_add_item(org_tlv_tree, hf_unknown_subtype, tvb, (offset+5), (guint16) (tempLen-3), FALSE);
2494         }
2495
2496         return (tempLen + 2);
2497 }
2498
2499 /* Dissect Unknown TLV */
2500 static gint32
2501 dissect_lldp_unknown_tlv(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, guint32 offset)
2502 {
2503         guint16 tempLen;
2504         guint16 tempShort;
2505
2506         proto_tree      *unknown_tlv_tree = NULL;
2507         proto_item      *tf = NULL;
2508
2509         /* Get tlv type and length */
2510         tempShort = tvb_get_ntohs(tvb, offset);
2511
2512         /* Get tlv length */
2513         tempLen = TLV_INFO_LEN(tempShort);
2514
2515         if (tree)
2516         {
2517                 tf = proto_tree_add_text(tree, tvb, offset, (tempLen + 2), "Unknown TLV");
2518                 unknown_tlv_tree = proto_item_add_subtree(tf, ett_unknown_tlv);
2519
2520                 proto_tree_add_item(unknown_tlv_tree, hf_lldp_tlv_type, tvb, offset, 2, FALSE);
2521                 proto_tree_add_item(unknown_tlv_tree, hf_lldp_tlv_len, tvb, offset, 2, FALSE);
2522         }
2523
2524         return (tempLen + 2);
2525 }
2526
2527
2528 /* Dissect LLDP packets */
2529 static void
2530 dissect_lldp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2531 {
2532         proto_item *ti;
2533         proto_tree *lldp_tree = NULL;
2534
2535         guint32 offset = 0;
2536         gint32 rtnValue = 0;
2537         guint16 tempShort;
2538         guint8 tempType;
2539         gboolean reachedEnd = FALSE;
2540
2541         col_set_str(pinfo->cinfo, COL_PROTOCOL, "LLDP");
2542
2543         /* Clear the information column on summary display */
2544         col_clear(pinfo->cinfo, COL_INFO);
2545
2546         if (tree)
2547         {
2548                 ti = proto_tree_add_item(tree, proto_lldp, tvb, offset, -1, FALSE);
2549                 lldp_tree = proto_item_add_subtree(ti, ett_lldp);
2550         }
2551
2552         /* Get chassis id tlv */
2553         rtnValue = dissect_lldp_chassis_id(tvb, pinfo, lldp_tree, offset);
2554         if (rtnValue < 0)
2555         {
2556                 col_set_str(pinfo->cinfo, COL_INFO, "Invalid Chassis ID TLV");
2557
2558                 return;
2559         }
2560
2561         offset += rtnValue;
2562
2563         /* Get port id tlv */
2564         rtnValue = dissect_lldp_port_id(tvb, pinfo, lldp_tree, offset);
2565         if (rtnValue < 0)
2566         {
2567                 col_set_str(pinfo->cinfo, COL_INFO, "Invalid Port ID TLV");
2568
2569                 return;
2570         }
2571
2572         offset += rtnValue;
2573
2574         /* Get time to live tlv */
2575         rtnValue = dissect_lldp_time_to_live(tvb, pinfo, lldp_tree, offset);
2576         if (rtnValue < 0)
2577         {
2578                 col_set_str(pinfo->cinfo, COL_INFO, "Invalid Time-to-Live TLV");
2579
2580                 return;
2581         }
2582
2583         offset += rtnValue;
2584
2585         /* Dissect optional tlv's until end-of-lldpdu is reached */
2586         while (!reachedEnd)
2587         {
2588                 tempShort = tvb_get_ntohs(tvb, offset);
2589                 tempType = TLV_TYPE(tempShort);
2590
2591                 switch (tempType)
2592                 {
2593                 case CHASSIS_ID_TLV_TYPE:
2594                         rtnValue = dissect_lldp_chassis_id(tvb, pinfo, lldp_tree, offset);
2595                         rtnValue = -1;  /* Duplicate chassis id tlv */
2596                         col_set_str(pinfo->cinfo, COL_INFO, "Duplicate Chassis ID TLV");
2597                         break;
2598                 case PORT_ID_TLV_TYPE:
2599                         rtnValue = dissect_lldp_port_id(tvb, pinfo, lldp_tree, offset);
2600                         rtnValue = -1;  /* Duplicate port id tlv */
2601                         col_set_str(pinfo->cinfo, COL_INFO, "Duplicate Port ID TLV");
2602                         break;
2603                 case TIME_TO_LIVE_TLV_TYPE:
2604                         rtnValue = dissect_lldp_time_to_live(tvb, pinfo, lldp_tree, offset);
2605                         rtnValue = -1;  /* Duplicate time-to-live tlv */
2606                         col_set_str(pinfo->cinfo, COL_INFO, "Duplicate Time-To-Live TLV");
2607                         break;
2608                 case END_OF_LLDPDU_TLV_TYPE:
2609                         rtnValue = dissect_lldp_end_of_lldpdu(tvb, pinfo, lldp_tree, offset);
2610                         break;
2611                 case PORT_DESCRIPTION_TLV_TYPE:
2612                         rtnValue = dissect_lldp_port_desc(tvb, pinfo, lldp_tree, offset);
2613                         break;
2614                 case SYSTEM_NAME_TLV_TYPE:
2615                 case SYSTEM_DESCRIPTION_TLV_TYPE:
2616                         rtnValue = dissect_lldp_system_name(tvb, pinfo, lldp_tree, offset);
2617                         break;
2618                 case SYSTEM_CAPABILITIES_TLV_TYPE:
2619                         rtnValue = dissect_lldp_system_capabilities(tvb, pinfo, lldp_tree, offset);
2620                         break;
2621                 case MANAGEMENT_ADDR_TLV_TYPE:
2622                         rtnValue = dissect_lldp_management_address(tvb, pinfo, lldp_tree, offset);
2623                         break;
2624                 case ORGANIZATION_SPECIFIC_TLV_TYPE:
2625                         rtnValue = dissect_organizational_specific_tlv(tvb, pinfo, lldp_tree, offset);
2626                         break;
2627                 default:
2628                         rtnValue = dissect_lldp_unknown_tlv(tvb, pinfo, lldp_tree, offset);
2629                         break;
2630                 }
2631
2632                 if (rtnValue < 0)
2633                         reachedEnd = TRUE;
2634                 else
2635                         offset += rtnValue;
2636         }
2637
2638 }
2639
2640 /* Register the protocol with Wireshark */
2641 void
2642 proto_register_lldp(void)
2643 {
2644         /* Setup list of header fields */
2645         static hf_register_info hf[] = {
2646                 { &hf_lldp_tlv_type,
2647                         { "TLV Type", "lldp.tlv.type", FT_UINT16, BASE_DEC,
2648                         VALS(tlv_types), TLV_TYPE_MASK, NULL, HFILL }
2649                 },
2650                 { &hf_lldp_tlv_len,
2651                         { "TLV Length", "lldp.tlv.len", FT_UINT16, BASE_DEC,
2652                         NULL, TLV_INFO_LEN_MASK, NULL, HFILL }
2653                 },
2654                 { &hf_chassis_id_subtype,
2655                         { "Chassis Id Subtype", "lldp.chassis.subtype", FT_UINT8, BASE_DEC,
2656                         VALS(chassis_id_subtypes), 0, NULL, HFILL }
2657                 },
2658                 { &hf_chassis_id,
2659                         { "Chassis Id", "lldp.chassis.id", FT_BYTES, BASE_NONE,
2660                         NULL, 0, NULL, HFILL }
2661                 },
2662                 { &hf_chassis_id_mac,
2663                         { "Chassis Id", "lldp.chassis.id.mac", FT_ETHER, BASE_NONE,
2664                         NULL, 0, NULL, HFILL }
2665                 },
2666                 { &hf_chassis_id_ip4,
2667                         { "Chassis Id", "lldp.chassis.id.ip4", FT_IPv4, BASE_NONE,
2668                         NULL, 0, NULL, HFILL }
2669                 },
2670                 { &hf_chassis_id_ip6,
2671                         { "Chassis Id", "lldp.chassis.id.ip6", FT_IPv6, BASE_NONE,
2672                         NULL, 0, NULL, HFILL }
2673                 },
2674                 { &hf_port_id_subtype,
2675                         { "Port Id Subtype", "lldp.port.subtype", FT_UINT8, BASE_DEC,
2676                         VALS(port_id_subtypes), 0, NULL, HFILL }
2677                 },
2678                 { &hf_port_id_mac,
2679                         { "Port Id", "lldp.port.id.mac", FT_ETHER, BASE_NONE,
2680                         NULL, 0, NULL, HFILL }
2681                 },
2682                 { &hf_lldp_network_address_family,
2683                         { "Network Address family", "lldp.network_address.subtype", FT_UINT8, BASE_DEC,
2684                         VALS(afn_vals), 0, NULL, HFILL }
2685                 },
2686                 { &hf_port_id_ip4,
2687                         { "Port Id", "lldp.port.id.ip4", FT_IPv4, BASE_NONE,
2688                         NULL, 0, NULL, HFILL }
2689                 },
2690                 { &hf_port_id_ip6,
2691                         { "Port Id", "lldp.port.id.ip6", FT_IPv6, BASE_NONE,
2692                         NULL, 0, NULL, HFILL }
2693                 },
2694                 { &hf_time_to_live,
2695                         { "Seconds", "lldp.time_to_live", FT_UINT16, BASE_DEC,
2696                         NULL, 0, NULL, HFILL }
2697                 },
2698                 { &hf_mgn_addr_ipv4,
2699                         { "Management Address", "lldp.mgn.addr.ip4", FT_IPv4, BASE_NONE,
2700                         NULL, 0, NULL, HFILL }
2701                 },
2702                 { &hf_mgn_addr_ipv6,
2703                         { "Management Address", "lldp.mgn.addr.ip6", FT_IPv6, BASE_NONE,
2704                         NULL, 0, NULL, HFILL }
2705                 },
2706                 { &hf_mgn_addr_hex,
2707                         { "Management Address", "lldp.mgn.addr.hex", FT_BYTES, BASE_NONE,
2708                         NULL, 0, NULL, HFILL }
2709                 },
2710                 { &hf_mgn_obj_id,
2711                         { "Object Identifier", "lldp.mgn.obj.id", FT_BYTES, BASE_NONE,
2712                         NULL, 0, NULL, HFILL }
2713                 },
2714                 { &hf_org_spc_oui,
2715                         { "Organization Unique Code",   "lldp.orgtlv.oui", FT_UINT24, BASE_HEX,
2716                         VALS(tlv_oui_subtype_vals), 0x0, NULL, HFILL }
2717                 },
2718                 { &hf_ieee_802_1_subtype,
2719                         { "IEEE 802.1 Subtype", "lldp.ieee.802_1.subtype", FT_UINT8, BASE_HEX,
2720                         VALS(ieee_802_1_subtypes), 0x0, NULL, HFILL }
2721                 },
2722                 { &hf_ieee_802_3_subtype,
2723                         { "IEEE 802.3 Subtype", "lldp.ieee.802_3.subtype", FT_UINT8, BASE_HEX,
2724                         VALS(ieee_802_3_subtypes), 0x0, NULL, HFILL }
2725                 },
2726                 { &hf_media_tlv_subtype,
2727                         { "Media Subtype",      "lldp.media.subtype", FT_UINT8, BASE_HEX,
2728                         VALS(media_subtypes), 0x0, NULL, HFILL }
2729                 },
2730                 { &hf_profinet_tlv_subtype,
2731                         { "Subtype",    "lldp.profinet.subtype", FT_UINT8, BASE_HEX,
2732                         VALS(profinet_subtypes), 0x0, "PROFINET Subtype", HFILL }
2733                 },
2734                 { &hf_profinet_port_rx_delay_local,
2735                         { "Port RX Delay Local",        "lldp.profinet.port_rx_delay_local", FT_UINT32, BASE_DEC,
2736                         NULL, 0x0, NULL, HFILL }
2737                 },
2738                 { &hf_profinet_port_rx_delay_remote,
2739                         { "Port RX Delay Remote",       "lldp.profinet.port_rx_delay_remote", FT_UINT32, BASE_DEC,
2740                         NULL, 0x0, NULL, HFILL }
2741                 },
2742                 { &hf_profinet_port_tx_delay_local,
2743                         { "Port TX Delay Local",        "lldp.profinet.port_tx_delay_local", FT_UINT32, BASE_DEC,
2744                         NULL, 0x0, NULL, HFILL }
2745                 },
2746                 { &hf_profinet_port_tx_delay_remote,
2747                         { "Port TX Delay Remote",       "lldp.profinet.port_tx_delay_remote", FT_UINT32, BASE_DEC,
2748                         NULL, 0x0, NULL, HFILL }
2749                 },
2750                 { &hf_profinet_cable_delay_local,
2751                         { "Port Cable Delay Local",     "lldp.profinet.cable_delay_local", FT_UINT32, BASE_DEC,
2752                         NULL, 0x0, NULL, HFILL }
2753                 },
2754                 { &hf_profinet_class2_port_status,
2755                         { "RTClass2 Port Status",       "lldp.profinet.rtc2_port_status", FT_UINT16, BASE_HEX,
2756                         VALS(profinet_port2_status_vals), 0x0, NULL, HFILL }
2757                 },
2758                 { &hf_profinet_class3_port_status,
2759                         { "RTClass3 Port Status",       "lldp.profinet.rtc3_port_status", FT_UINT16, BASE_HEX,
2760                         VALS(profinet_port3_status_vals), 0x0, NULL, HFILL }
2761                 },
2762                 { &hf_profinet_mrp_domain_uuid,
2763                         { "MRP DomainUUID",     "lldp.profinet.mrp_domain_uuid", FT_GUID, BASE_NONE,
2764                         NULL, 0x0, NULL, HFILL }
2765                 },
2766                 { &hf_profinet_mrrt_port_status,
2767                         { "MRRT PortStatus",    "lldp.profinet.mrrt_port_status", FT_UINT16, BASE_HEX,
2768                         VALS(profinet_mrrt_port_status_vals), 0x0, NULL, HFILL }
2769                 },
2770                 { &hf_profinet_cm_mac,
2771                         { "CMMacAdd",   "lldp.profinet.cm_mac_add", FT_ETHER, BASE_NONE,
2772                         NULL, 0x0, "CMResponderMacAdd or CMInitiatorMacAdd", HFILL }
2773                 },
2774                 { &hf_profinet_master_source_address,
2775                         { "MasterSourceAddress",        "lldp.profinet.master_source_address", FT_ETHER, BASE_NONE,
2776                         NULL, 0x0, NULL, HFILL }
2777                 },
2778                 { &hf_profinet_subdomain_uuid,
2779                         { "SubdomainUUID",      "lldp.profinet.subdomain_uuid", FT_GUID, BASE_NONE,
2780                         NULL, 0x0, NULL, HFILL }
2781                 },
2782                 { &hf_profinet_ir_data_uuid,
2783                         { "IRDataUUID", "lldp.profinet.ir_data_uuid", FT_GUID, BASE_NONE,
2784                         NULL, 0x0, NULL, HFILL }
2785                 },
2786                 { &hf_profinet_length_of_period_valid,
2787                         { "LengthOfPeriod.Valid",       "lldp.profinet.length_of_period_valid", FT_UINT32, BASE_DEC,
2788                         NULL, 0x80000000, "Length field is valid/invalid", HFILL }
2789                 },
2790                 { &hf_profinet_length_of_period_length,
2791                         { "LengthOfPeriod.Length",      "lldp.profinet.length_of_period_length", FT_UINT32, BASE_DEC,
2792                         NULL, 0x7FFFFFFF, "Duration of a cycle in nanoseconds", HFILL }
2793                 },
2794                 { &hf_profinet_red_period_begin_valid,
2795                         { "RedPeriodBegin.Valid",       "lldp.profinet.red_period_begin_valid", FT_UINT32, BASE_DEC,
2796                         NULL, 0x80000000, "Offset field is valid/invalid", HFILL }
2797                 },
2798                 { &hf_profinet_red_period_begin_offset,
2799                         { "RedPeriodBegin.Offset",      "lldp.profinet.red_period_begin_offset", FT_UINT32, BASE_DEC,
2800                         NULL, 0x7FFFFFFF, "RT_CLASS_3 period, offset to cycle begin in nanoseconds", HFILL }
2801                 },
2802                 { &hf_profinet_orange_period_begin_valid,
2803                         { "OrangePeriodBegin.Valid",    "lldp.profinet.orange_period_begin_valid", FT_UINT32, BASE_DEC,
2804                         NULL, 0x80000000, "Offset field is valid/invalid", HFILL }
2805                 },
2806                 { &hf_profinet_orange_period_begin_offset,
2807                         { "OrangePeriodBegin.Offset","lldp.profinet.orange_period_begin_offset", FT_UINT32, BASE_DEC,
2808                         NULL, 0x7FFFFFFF, "RT_CLASS_2 period, offset to cycle begin in nanoseconds", HFILL }
2809                 },
2810                 { &hf_profinet_green_period_begin_valid,
2811                         { "GreenPeriodBegin.Valid",     "lldp.profinet.green_period_begin_valid", FT_UINT32, BASE_DEC,
2812                         NULL, 0x80000000, "Offset field is valid/invalid", HFILL }
2813                 },
2814                 { &hf_profinet_green_period_begin_offset,
2815                         { "GreenPeriodBegin.Offset",    "lldp.profinet.green_period_begin_offset", FT_UINT32, BASE_DEC,
2816                         NULL, 0x7FFFFFFF, "Unrestricted period, offset to cycle begin in nanoseconds", HFILL }
2817                 },
2818                 { &hf_unknown_subtype,
2819                         { "Unknown Subtype Content","lldp.unknown_subtype", FT_BYTES, BASE_NONE,
2820                         NULL, 0x0, NULL, HFILL }
2821                 },
2822         };
2823
2824         /* Setup protocol subtree array */
2825         static gint *ett[] = {
2826                 &ett_lldp,
2827                 &ett_chassis_id,
2828                 &ett_port_id,
2829                 &ett_time_to_live,
2830                 &ett_end_of_lldpdu,
2831                 &ett_port_description,
2832                 &ett_system_name,
2833                 &ett_system_cap,
2834                 &ett_system_cap_summary,
2835                 &ett_system_cap_enabled,
2836                 &ett_management_address,
2837                 &ett_unknown_tlv,
2838                 &ett_org_spc_tlv,
2839                 &ett_port_vlan_flags,
2840                 &ett_802_3_flags,
2841                 &ett_802_3_autoneg_advertised,
2842                 &ett_802_3_power,
2843                 &ett_802_3_aggregation,
2844                 &ett_media_capabilities,
2845                 &ett_profinet_period
2846         };
2847
2848         /* Register the protocol name and description */
2849         proto_lldp = proto_register_protocol("Link Layer Discovery Protocol", "LLDP", "lldp");
2850
2851         /* Required function calls to register the header fields and subtrees used */
2852         proto_register_field_array(proto_lldp, hf, array_length(hf));
2853         proto_register_subtree_array(ett, array_length(ett));
2854 }
2855
2856 void
2857 proto_reg_handoff_lldp(void)
2858 {
2859         dissector_handle_t lldp_handle;
2860
2861         lldp_handle = create_dissector_handle(dissect_lldp,proto_lldp);
2862         dissector_add("ethertype", ETHERTYPE_LLDP, lldp_handle);
2863 }