6b52d9c88d32257191d5f16048b65f2ad3f2480a
[jlayton/wireshark.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  * Ethereal - Network traffic analyzer
10  * By Gerald Combs <gerald@ethereal.com>
11  * Copyright 1998 Gerald Combs
12  * 
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  * 
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  * 
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26  */
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35
36 #include <gmodule.h>
37 #include <glib.h>
38
39 #include <epan/packet.h>
40 #include <epan/prefs.h>
41 #include <epan/emem.h>
42 #include <epan/etypes.h>
43 #include <epan/oui.h>
44
45 /* TLV Types */
46 #define END_OF_LLDPDU_TLV_TYPE          0x00    /* Mandatory */
47 #define CHASSIS_ID_TLV_TYPE             0x01    /* Mandatory */
48 #define PORT_ID_TLV_TYPE                0x02    /* Mandatory */
49 #define TIME_TO_LIVE_TLV_TYPE           0x03    /* Mandatory */
50 #define PORT_DESCRIPTION_TLV_TYPE       0x04
51 #define SYSTEM_NAME_TLV_TYPE            0x05
52 #define SYSTEM_DESCRIPTION_TLV_TYPE     0x06
53 #define SYSTEM_CAPABILITIES_TLV_TYPE    0x07
54 #define MANAGEMENT_ADDR_TLV_TYPE        0x08
55 #define ORGANIZATION_SPECIFIC_TLV_TYPE  0x7F
56
57 /* Masks */
58 #define TLV_TYPE_MASK           0xFE00
59 #define TLV_TYPE(value)         (((value) & TLV_TYPE_MASK) >> 9)
60 #define TLV_INFO_LEN_MASK       0x01FF
61 #define TLV_INFO_LEN(value)     ((value) & TLV_INFO_LEN_MASK)
62
63 /* Initialize the protocol and registered fields */
64 static int proto_lldp = -1;
65 static int hf_lldp_tlv_type = -1;
66 static int hf_lldp_tlv_len = -1;
67 static int hf_chassis_id_subtype = -1;
68 static int hf_chassis_id = -1;
69 static int hf_chassis_id_mac = -1;
70 static int hf_chassis_id_ip4 = -1;
71 static int hf_chassis_id_ip6 = -1;
72 static int hf_port_id_subtype = -1;
73 static int hf_port_id_mac = -1;
74 static int hf_port_id_ip4 = -1;
75 static int hf_port_id_ip6 = -1;
76 static int hf_time_to_live = -1;
77 static int hf_mgn_addr_ipv4 = -1;
78 static int hf_mgn_addr_ipv6 = -1;
79 static int hf_mgn_addr_hex = -1;
80 static int hf_mgn_obj_id = -1;
81 static int hf_org_spc_oui = -1;
82 static int hf_ieee_802_1_subtype = -1;
83 static int hf_ieee_802_3_subtype = -1;
84 static int hf_media_tlv_subtype = -1;
85
86 /* Initialize the subtree pointers */
87 static gint ett_lldp = -1;
88 static gint ett_chassis_id = -1;
89 static gint ett_port_id = -1;
90 static gint ett_time_to_live = -1;
91 static gint ett_end_of_lldpdu = -1;
92 static gint ett_port_description = -1;
93 static gint ett_system_name = -1;
94 static gint ett_system_cap = -1;
95 static gint ett_system_cap_summary = -1;
96 static gint ett_system_cap_enabled = -1;
97 static gint ett_management_address = -1;
98 static gint ett_unknown_tlv = -1;
99 static gint ett_org_spc_tlv = -1;
100 static gint ett_port_vlan_flags = -1;
101 static gint ett_802_3_flags = -1;
102 static gint ett_802_3_power = -1;
103 static gint ett_802_3_aggregation = -1;
104 static gint ett_media_capabilities = -1;
105
106 const value_string tlv_types[] = {
107         { END_OF_LLDPDU_TLV_TYPE,               "End of LLDPDU"},
108         { CHASSIS_ID_TLV_TYPE,                  "Chassis Id"},
109         { PORT_ID_TLV_TYPE,                     "Port Id"},
110         { TIME_TO_LIVE_TLV_TYPE,                "Time to Live"},
111         { PORT_DESCRIPTION_TLV_TYPE,            "Port Description"},
112         { SYSTEM_NAME_TLV_TYPE,                 "System Name"},
113         { SYSTEM_DESCRIPTION_TLV_TYPE,          "System Description"},
114         { SYSTEM_CAPABILITIES_TLV_TYPE,         "System Capabilities"},
115         { MANAGEMENT_ADDR_TLV_TYPE,             "Management Address"},
116         { ORGANIZATION_SPECIFIC_TLV_TYPE,       "Organization Specific"},
117         { 0, NULL} 
118 };
119
120 const value_string chassis_id_subtypes[] = {
121         { 0,    "Reserved"},
122         { 1,    "Chassis component"},
123         { 2,    "Interface alias"},
124         { 3,    "Port component"},
125         { 4,    "MAC address"},
126         { 5,    "Network address"},
127         { 6,    "Interface name"},
128         { 7,    "Locally assigned"},
129         { 0, NULL} 
130 };
131
132 const value_string port_id_subtypes[] = {
133         { 0,    "Reserved"},
134         { 1,    "Interface alias"},
135         { 2,    "Port component"},
136         { 3,    "MAC address"},
137         { 4,    "Network address"},
138         { 5,    "Interface name"},
139         { 6,    "Agent circuit Id"},
140         { 7,    "Locally assigned"},
141         { 0, NULL} 
142 };
143
144 const value_string management_addr_values[] = {
145         { 0,    "Reserved"},
146         { 1,    "IPv4"},
147         { 2,    "IPv6"},
148         { 3,    "NSAP"},
149         { 4,    "HDLC (8-bit multidrop)"},
150         { 5,    "BBN 1822"},
151         { 6,    "802 (includes all 802 media plus Ethernet)"},
152         { 7,    "E.163"},
153         { 8,    "E.164 (SMDS, Frame Relay, ATM)"},
154         { 9,    "F.69 (Telex)"},
155         { 10,   "X.121 (X.25, Frame Relay)"},
156         { 11,   "IPX"},
157         { 12,   "Appletalk"},
158         { 13,   "Decnet IV"},
159         { 14,   "Banyan Vines"},
160         { 15,   "E.164 with NSAP format subaddress"},
161         { 16,   "DNS (Domain Name System)"},
162         { 17,   "Distinguished Name"},
163         { 18,   "AS Number"},
164         { 19,   "XTP over IP version 4"},
165         { 20,   "XTP over IP version 6"},
166         { 21,   "XTP native mode XTP"},
167         { 22,   "Fibre Channel World-Wide Port Name"},
168         { 23,   "Fibre Channel World-Wide Node Name"},
169         { 24,   "GWID"},
170         { 0, NULL}
171 };
172
173 const value_string interface_subtype_values[] = {
174         { 1,    "Unknown"},
175         { 2,    "ifIndex"},
176         { 3,    "System port number"},
177         { 0, NULL} 
178 };
179
180 const value_string tlv_oui_subtype_vals[] = {
181         { OUI_IEEE_802_1,       "IEEE 802.1" },
182         { OUI_IEEE_802_3,       "IEEE 802.3" },
183         { OUI_MEDIA_ENDPOINT,   "TIA" },
184         { 0, NULL }
185 };
186
187 /* IEEE 802.1 Subtypes */
188 const value_string ieee_802_1_subtypes[] = {
189         { 0x01, "Port VLAN ID" },
190         { 0x02, "Port and Protocol VLAN ID" },
191         { 0x03, "VLAN Name" },
192         { 0x04, "Protocol Identity" },
193         { 0, NULL }
194 };
195
196 /* IEEE 802.3 Subtypes */
197 const value_string ieee_802_3_subtypes[] = {
198         { 0x01, "MAC/PHY Configuration/Status" },
199         { 0x02, "Power Via MDI" },
200         { 0x03, "Link Aggregation" },
201         { 0x04, "Maximum Frame Size" },
202         { 0, NULL }
203 };
204
205 /* Media Subtypes */
206 const value_string media_subtypes[] = {
207         { 1,    "Media Capabilities" },
208         { 2,    "Network Policy" },
209         { 3,    "Location Identification" },
210         { 4,    "Extended Power-via-MDI" },
211         { 5,    "Inventory - Hardware Revision" },
212         { 6,    "Inventory - Firmware Revision" },
213         { 7,    "Inventory - Software Revision" },
214         { 8,    "Inventory - Serial Number" },
215         { 9,    "Inventory - Manufacturer Name" },
216         { 10,   "Inventory - Model Name" },
217         { 11,   "Inventory - Asset ID" },
218         { 0, NULL }
219 };
220
221 /* Media Class Values */
222 const value_string media_class_values[] = {
223         { 0,    "Type Not Defined" },
224         { 1,    "Endpoint Class I" },
225         { 2,    "Endpoint Class II" },
226         { 3,    "Endpoint Class III" },
227         { 4,    "Network Connectivity" },
228         { 0, NULL }
229 };
230
231 /* Media Application Types */
232 const value_string media_application_type[] = {
233         { 0,    "Reserved" },
234         { 1,    "Voice" },
235         { 2,    "Voice Signaling" },
236         { 3,    "Guest Voice" },
237         { 4,    "Guest Voice Signaling" },
238         { 5,    "Softphone Voice" },
239         { 6,    "Video Conferencing" },
240         { 7,    "Streaming Video" },
241         { 8,    "Video Signaling" },
242         { 0, NULL }
243 };
244
245 /* Power Type */
246 const value_string media_power_type[] = {
247         { 0,    "PSE Device" },
248         { 1,    "PD Device" },
249         { 0, NULL }
250 };
251
252 /* Power Priority */
253 const value_string media_power_priority[] = {
254         { 0,    "Unknown" },
255         { 1,    "Critical" },
256         { 2,    "High" },
257         { 3,    "Low" },
258         { 0, NULL }
259 };
260
261 /* Power Sources */
262 const value_string media_power_pd_device[] = {
263         { 0,    "Unknown" },
264         { 1,    "PSE" },
265         { 2,    "Local" },
266         { 3,    "PSE and Local" },
267         { 0, NULL }
268 };
269 const value_string media_power_pse_device[] = {
270         { 0,    "Unknown" },
271         { 1,    "Primary Power Source" },
272         { 2,    "Backup Power Source" },
273         { 0, NULL }
274 };
275
276 /* Location data format */
277 const value_string location_data_format[] = {
278         { 0,    "Invalid " },
279         { 1,    "Coordinate-based LCI" },
280         { 2,    "Civic Address LCI" },
281         { 3,    "ECS ELIN" },
282         { 0, NULL }
283 };
284
285 /* Civic Address LCI - What field */
286 const value_string civic_address_what_values[] = {
287         { 0,    "Location of the DHCP server" },
288         { 1,    "Location of the network element believed to be closest to the client" },
289         { 2,    "Location of the client"},
290         { 0, NULL}
291 };
292
293 /* Civic Address Type field */
294 const value_string civic_address_type_values[] = {
295         { 0,    "Language" },
296         { 1,    "National subdivisions (province, state, etc)" },
297         { 2,    "County, parish, district" },
298         { 3,    "City, township" },
299         { 4,    "City division, borough, ward" },
300         { 5,    "Neighborhood, block" },
301         { 6,    "Street" },
302         { 16,   "Leading street direction" },
303         { 17,   "Trailing street suffix" },
304         { 18,   "Street suffix" },
305         { 19,   "House number" },
306         { 20,   "House number suffix" },
307         { 21,   "Landmark or vanity address" },
308         { 22,   "Additional location information" },
309         { 23,   "Name" },
310         { 24,   "Postal/ZIP code" },
311         { 25,   "Building" },
312         { 26,   "Unit" },
313         { 27,   "Floor" },
314         { 28,   "Room number" },
315         { 29,   "Place type" },
316         { 128,  "Script" },
317         { 0, NULL }
318 };
319
320 /* System Capabilities */
321 #define SYSTEM_CAPABILITY_OTHER         0x0001
322 #define SYSTEM_CAPABILITY_REPEATER      0x0002
323 #define SYSTEM_CAPABILITY_BRIDGE        0x0004
324 #define SYSTEM_CAPABILITY_WLAN          0x0008
325 #define SYSTEM_CAPABILITY_ROUTER        0x0010
326 #define SYSTEM_CAPABILITY_TELEPHONE     0x0020
327 #define SYSTEM_CAPABILITY_DOCSIS        0x0040
328 #define SYSTEM_CAPABILITY_STATION       0x0080
329
330 /* Media Capabilities */
331 #define MEDIA_CAPABILITY_LLDP                           0x0001
332 #define MEDIA_CAPABILITY_NETWORK_POLICY         0x0002
333 #define MEDIA_CAPABILITY_LOCATION_ID            0x0004
334 #define MEDIA_CAPABILITY_MDI_PSE                        0x0008
335 #define MEDIA_CAPABILITY_MDI_PD                         0x0010
336 #define MEDIA_CAPABILITY_INVENTORY                      0x0020
337
338 #define MAX_MAC_LEN     6
339
340 /* Calculate Latitude and Longitude string */
341 /*
342         Parameters:
343                 option = 0 -> Latitude
344                 option = 1 -> Longitude
345 */
346 static gchar *
347 get_latitude_or_longitude(int option, guint64 value)
348 {
349         guint64 tempValue = value;
350         gboolean negativeNum = FALSE;
351         guint32 integerPortion = 0;
352         const char *direction;
353         
354         /* The latitude and longitude are 34 bit fixed point value consisting
355            of 9 bits of integer and 25 bits of fraction.  
356            When option is equal to 0, positive numbers are represent a location
357            north of the equator and negative (2s complement) numbers are south of the equator.
358            When option is equal to 1, positive values are east of the prime 
359            meridian and negative (2s complement) numbers are west of the prime meridian.
360         */
361         
362         if (value & G_GINT64_CONSTANT(0x0000000200000000))
363         {
364                 /* Have a negative number (2s complement) */
365                 negativeNum = TRUE;
366                 
367                 tempValue = ~value;
368                 tempValue += 1;
369         }
370         
371         /* Get the integer portion */
372         integerPortion = (guint32)((tempValue & G_GINT64_CONSTANT(0x00000003FE000000)) >> 25);
373         
374         /* Calculate decimal portion (using 25 bits for fraction) */
375         tempValue = (tempValue & G_GINT64_CONSTANT(0x0000000001FFFFFF))/33554432;
376         
377         if (option == 0)
378         {
379                 /* Latitude - north/south directions */
380                 if (negativeNum)
381                         direction = "South";
382                 else
383                         direction = "North";
384         }
385         else
386         {
387                 /* Longitude - east/west directions */
388                 if (negativeNum)
389                         direction = "West";
390                 else
391                         direction = "East";
392         }
393         
394         return ep_strdup_printf("%u.%04" PRIu64 " degrees %s",
395             integerPortion, tempValue, direction);
396 }
397
398 /* Dissect Chassis Id TLV (Mandatory) */
399 static gint32
400 dissect_lldp_chassis_id(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 offset)
401 {
402         guint8 tempType;
403         guint16 tempShort;
404         guint32 tempLen = 0;
405         const char *strPtr;
406         guint8 incorrectLen = 0;        /* incorrect length if 1 */
407         
408         const guint8 *mac_addr = NULL;
409         guint32 ip_addr;
410         struct e_in6_addr ip6_addr;
411         
412         proto_tree      *chassis_tree = NULL;
413         proto_item      *tf = NULL;
414         
415         /* Get tlv type */
416         tempShort = tvb_get_ntohs(tvb, offset);
417         tempType = TLV_TYPE(tempShort);
418         if (tempType != CHASSIS_ID_TLV_TYPE)
419         {
420                 if (tree)
421                 {
422                         tf = proto_tree_add_text(tree, tvb, offset, 2, "Invalid Chassis ID (0x%02X)", tempType);
423                         chassis_tree = proto_item_add_subtree(tf, ett_chassis_id);
424                         proto_tree_add_text(chassis_tree, tvb, offset, 2, "%s Invalid Chassis ID (%u)",
425                                                 decode_boolean_bitfield(tempType, TLV_TYPE_MASK, 16, "", ""), tempType);
426                 }
427                 
428                 return -1;
429         }
430                 
431         /* Get tlv length */
432         tempLen = TLV_INFO_LEN(tempShort);
433         if (tempLen < 2)
434         {
435                 if (tree)
436                 {
437                         tf = proto_tree_add_text(tree, tvb, offset, 2, "Invalid Chassis ID Length (%u)", tempLen);
438                         chassis_tree = proto_item_add_subtree(tf, ett_chassis_id);
439                         proto_tree_add_item(chassis_tree, hf_lldp_tlv_type, tvb, offset, 2, FALSE);
440                         proto_tree_add_text(chassis_tree, tvb, offset, 2, "%s Invalid Length: %u",
441                                                 decode_boolean_bitfield(tempLen, TLV_INFO_LEN_MASK, 16, "", ""), tempLen);
442                 }
443                 
444                 return -1;
445         }
446         
447         /* Get tlv subtype */
448         tempType = tvb_get_guint8(tvb, (offset+2));
449         
450         switch (tempType)
451         {
452         case 4: /* MAC address */
453         {
454                 if (tempLen != 7)
455                 {
456                         incorrectLen = 1;       /* Invalid length */
457                         break;
458                 }
459                         
460                 mac_addr=tvb_get_ptr(tvb, (offset+3), 6);
461                 strPtr = ether_to_str(mac_addr);
462         
463                 break;
464         }
465         case 5: /* Network address */
466         {
467                 /* Check for IPv4 or IPv6 */
468                 if (tempLen == 5)
469                 {
470                         ip_addr = tvb_get_ipv4(tvb, (offset+3));
471                         strPtr = ip_to_str((guint8 *)&ip_addr);
472                 }
473                 else if  (tempLen == 17)
474                 {
475                         tvb_get_ipv6(tvb, (offset+3), &ip6_addr);
476                         strPtr = ip6_to_str(&ip6_addr);
477                 }
478                 else
479                 {
480                         incorrectLen = 1;       /* Invalid length */
481                         break;
482                 }
483                         
484                 break;
485         }
486         case 2: /* Interface alias */
487         case 6: /* Interface name */
488         case 7: /* Locally assigned */
489         {
490                 if (tempLen > 256)
491                 {
492                         incorrectLen = 1;       /* Invalid length */
493                         break;
494                 }
495                 
496                 strPtr = tvb_format_stringzpad(tvb, (offset+3), (tempLen-1));
497
498                 break;
499         }
500         case 1: /* Chassis component */
501         case 3: /* Port component */
502         {
503                 if (tempLen > 256)
504                 {
505                         incorrectLen = 1;       /* Invalid length */
506                         break;
507                 }
508                 
509                 strPtr = tvb_bytes_to_str(tvb, (offset+3), (tempLen-1));
510                 break;
511         }
512         default:        /* Reserved types */
513         {
514                 if (tempLen > 256)
515                 {
516                         incorrectLen = 1;       /* Invalid length */
517                         break;
518                 }
519                 
520                 strPtr = "Reserved";
521                 
522                 break;
523         }
524         }
525         
526         if (incorrectLen == 1)
527         {
528                 if (tree)
529                 {
530                         tf = proto_tree_add_text(tree, tvb, offset, 2, "Invalid Chassis ID Length (%u)", tempLen);
531                         chassis_tree = proto_item_add_subtree(tf, ett_chassis_id);
532                         proto_tree_add_item(chassis_tree, hf_lldp_tlv_type, tvb, offset, 2, FALSE);
533                         proto_tree_add_text(chassis_tree, tvb, offset, 2, "%s Invalid Length: %u",
534                                                 decode_boolean_bitfield(tempLen, TLV_INFO_LEN_MASK, 16, "", ""), tempLen);                      
535                         /* Get chassis id subtype */
536                         proto_tree_add_item(chassis_tree, hf_chassis_id_subtype, tvb, (offset+2), 1, FALSE);
537                 
538                 }
539                 
540                 return -1;
541         }
542         
543         if (check_col(pinfo->cinfo, COL_INFO))
544                 col_add_fstr(pinfo->cinfo, COL_INFO, "Chassis Id = %s ", strPtr);
545                         
546         if (tree)
547         {
548                 /* Set chassis tree */
549                 tf = proto_tree_add_text(tree, tvb, offset, (tempLen + 2), "Chassis Subtype = %s", 
550                                                                 val_to_str(tempType, chassis_id_subtypes, "Reserved" ));
551                 chassis_tree = proto_item_add_subtree(tf, ett_chassis_id);
552                 
553                 proto_tree_add_item(chassis_tree, hf_lldp_tlv_type, tvb, offset, 2, FALSE);
554                 proto_tree_add_item(chassis_tree, hf_lldp_tlv_len, tvb, offset, 2, FALSE);
555                 
556                 /* Get chassis id subtype */
557                 proto_tree_add_item(chassis_tree, hf_chassis_id_subtype, tvb, (offset+2), 1, FALSE);
558                 
559                 /* Get chassis id */
560                 switch (tempType)
561                 {
562                 case 4: /* MAC address */
563                         proto_tree_add_ether(chassis_tree, hf_chassis_id_mac, tvb, (offset+3), 6, mac_addr);
564                         break;
565                 case 5: /* Network address */
566                         if (tempLen == 5)
567                                 proto_tree_add_ipv4(chassis_tree, hf_chassis_id_ip4, tvb, (offset+3), 4, ip_addr);
568                         else
569                                 proto_tree_add_ipv6(chassis_tree, hf_chassis_id_ip6, tvb, (offset+3), 16, ip6_addr.bytes);
570                         break;
571                 case 2: /* Interface alias */
572                 case 6: /* Interface name */
573                 case 7: /* Locally assigned */
574                         proto_tree_add_text(chassis_tree, tvb, (offset+3), (tempLen-1), "Chassis Id: %s", strPtr);
575                         break;
576                 case 1: /* Chassis component */
577                 case 3: /* Port component */
578                         proto_tree_add_item(chassis_tree, hf_chassis_id, tvb, (offset+3), (tempLen-1), FALSE);
579                         break;
580                 }
581         }
582         
583         return (tempLen + 2);
584 }
585
586 /* Dissect Port Id TLV (Mandatory) */
587 static gint32
588 dissect_lldp_port_id(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 offset)
589 {
590         guint8 tempType;
591         guint16 tempShort;
592         guint32 tempLen = 0;
593         const char *strPtr;
594         const guint8 *mac_addr = NULL;
595         guint32 ip_addr;
596         struct e_in6_addr ip6_addr;
597         
598         proto_tree      *port_tree = NULL;
599         proto_item      *tf = NULL;
600         
601         /* Get tlv type */
602         tempShort = tvb_get_ntohs(tvb, offset);
603         tempType = TLV_TYPE(tempShort);
604         if (tempType != PORT_ID_TLV_TYPE)
605                 return -1;
606                 
607         /* Get tlv length and subtype */
608         tempLen = TLV_INFO_LEN(tempShort);
609         tempType = tvb_get_guint8(tvb, (offset+2));
610         
611         /* Get port id */
612         switch (tempType)
613         {
614         case 3: /* MAC address */
615         {
616                 if (tempLen != 7)
617                         return -1;      /* Invalid port id */
618                         
619                 mac_addr=tvb_get_ptr(tvb, (offset+3), 6);
620                 strPtr = ether_to_str(mac_addr);
621         
622                 break;
623         }
624         case 4: /* Network address */
625         {
626                 /* Check for IPv4 or IPv6 */
627                 if (tempLen == 5)
628                 {
629                         ip_addr = tvb_get_ipv4(tvb, (offset+3));
630                         strPtr = ip_to_str((guint8 *)&ip_addr);
631                 }
632                 else if  (tempLen == 17)
633                 {
634                         tvb_get_ipv6(tvb, (offset+3), &ip6_addr);
635                         strPtr = ip6_to_str(&ip6_addr);
636                 }
637                 else
638                         return -1;      /* Invalid chassis id */
639                         
640                 break;
641         }
642         default:
643         {
644                 strPtr = tvb_format_stringzpad(tvb, (offset+3), (tempLen-1));
645         
646                 break;
647         }
648         }
649         
650         if (check_col(pinfo->cinfo, COL_INFO))
651                 col_append_fstr(pinfo->cinfo, COL_INFO, "Port Id = %s ", strPtr);
652                         
653         if (tree)
654         {
655                 /* Set port tree */
656                 tf = proto_tree_add_text(tree, tvb, offset, (tempLen + 2), "Port Subtype = %s", 
657                                                                 val_to_str(tempType, port_id_subtypes, "Unknown" ));
658                 port_tree = proto_item_add_subtree(tf, ett_port_id);
659                 
660                 proto_tree_add_item(port_tree, hf_lldp_tlv_type, tvb, offset, 2, FALSE);
661                 proto_tree_add_item(port_tree, hf_lldp_tlv_len, tvb, offset, 2, FALSE);
662                 
663                 /* Get port id subtype */
664                 proto_tree_add_item(port_tree, hf_port_id_subtype, tvb, (offset+2), 1, FALSE);
665                 
666                 /* Get port id */
667                 /*proto_tree_add_text(port_tree, tvb, (offset+3), (tempLen-1), "Port Id: %s", strPtr);*/
668                 switch (tempType)
669                 {
670                 case 3: /* MAC address */
671                         proto_tree_add_ether(port_tree, hf_port_id_mac, tvb, (offset+3), 6, mac_addr);
672                         break;
673                 case 4: /* Network address */
674                         if (tempLen == 5)
675                                 proto_tree_add_ipv4(port_tree, hf_port_id_ip4, tvb, (offset+3), 4, ip_addr);
676                         else
677                                 proto_tree_add_ipv6(port_tree, hf_port_id_ip6, tvb, (offset+3), 16, ip6_addr.bytes);
678                         break;
679                 default:
680                         proto_tree_add_text(port_tree, tvb, (offset+3), (tempLen-1), "Port Id: %s", strPtr);
681                         break;
682                 }
683                 
684         }
685         
686         return (tempLen + 2);
687 }
688
689 /* Dissect Time To Live TLV (Mandatory) */
690 static gint32
691 dissect_lldp_time_to_live(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 offset)
692 {
693         guint8 tempType;
694         guint16 tempShort;
695         guint32 tempLen = 0;
696         
697         proto_tree      *time_to_live_tree = NULL;
698         proto_item      *tf = NULL;
699         
700         /* Get tlv type */
701         tempShort = tvb_get_ntohs(tvb, offset);
702         tempType = TLV_TYPE(tempShort);
703         if (tempType != TIME_TO_LIVE_TLV_TYPE)
704                 return -1;
705                 
706         /* Get tlv length and seconds field */
707         tempLen = TLV_INFO_LEN(tempShort);
708         tempShort = tvb_get_ntohs(tvb, (offset+2));
709         
710         if (check_col(pinfo->cinfo, COL_INFO))
711                 col_append_fstr(pinfo->cinfo, COL_INFO, "TTL = %u ", tempShort);
712                         
713         if (tree)
714         {
715                 /* Set port tree */
716                 tf = proto_tree_add_text(tree, tvb, offset, (tempLen + 2), "Time To Live = %u sec", tempShort);
717                 time_to_live_tree = proto_item_add_subtree(tf, ett_time_to_live);
718                 
719                 proto_tree_add_item(time_to_live_tree, hf_lldp_tlv_type, tvb, offset, 2, FALSE);
720                 proto_tree_add_item(time_to_live_tree, hf_lldp_tlv_len, tvb, offset, 2, FALSE);
721                 
722                 /* Display time to live information */
723                 proto_tree_add_item(time_to_live_tree, hf_time_to_live, tvb, (offset+2), 2, FALSE);
724         }
725         
726         return (tempLen + 2);
727 }
728
729 /* Dissect End of LLDPDU TLV (Mandatory) */
730 static gint32
731 dissect_lldp_end_of_lldpdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 offset)
732 {
733         guint16 tempLen;
734         guint16 tempShort;
735         
736         proto_tree      *end_of_lldpdu_tree = NULL;
737         proto_item      *tf = NULL;
738         
739         /* Get tlv type and length */
740         tempShort = tvb_get_ntohs(tvb, offset);
741                 
742         /* Get tlv length */
743         tempLen = TLV_INFO_LEN(tempShort);
744                         
745         if (tree)
746         {
747                 /* Set port tree */
748                 tf = proto_tree_add_text(tree, tvb, offset, (tempLen + 2), "End of LLDPDU");
749                 end_of_lldpdu_tree = proto_item_add_subtree(tf, ett_end_of_lldpdu);
750                 
751                 proto_tree_add_item(end_of_lldpdu_tree, hf_lldp_tlv_type, tvb, offset, 2, FALSE);
752                 proto_tree_add_item(end_of_lldpdu_tree, hf_lldp_tlv_len, tvb, offset, 2, FALSE);
753         }
754         
755         return -1;      /* Force the lldp dissector to terminate */
756 }
757
758 /* Dissect Port Description TLV */
759 static gint32
760 dissect_lldp_port_desc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 offset)
761 {
762         guint16 tempShort;
763         guint32 tempLen = 0;
764         const char *strPtr;
765         
766         proto_tree      *port_desc_tree = NULL;
767         proto_item      *tf = NULL;
768         
769         /* Get tlv type and length */
770         tempShort = tvb_get_ntohs(tvb, offset);
771                 
772         /* Get tlv length */
773         tempLen = TLV_INFO_LEN(tempShort);
774                         
775         if (tree)
776         {
777                 strPtr = tvb_format_stringzpad(tvb, (offset+2), tempLen);
778
779                 /* Set port tree */
780                 tf = proto_tree_add_text(tree, tvb, offset, (tempLen + 2), "Port Description = %s", strPtr);
781                 port_desc_tree = proto_item_add_subtree(tf, ett_port_description);
782                 
783                 proto_tree_add_item(port_desc_tree, hf_lldp_tlv_type, tvb, offset, 2, FALSE);
784                 proto_tree_add_item(port_desc_tree, hf_lldp_tlv_len, tvb, offset, 2, FALSE);
785                 
786                 /* Display port description information */
787                 proto_tree_add_text(port_desc_tree, tvb, (offset+2), tempLen, "Port Description: %s",
788                     strPtr);
789         }
790         
791         return (tempLen + 2);
792 }
793
794 /* Dissect System Name and description TLV */
795 static gint32
796 dissect_lldp_system_name(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 offset)
797 {
798         guint16 tempShort;
799         guint32 tempLen = 0;
800         guint8 tempType;
801         const char *strPtr;
802         
803         proto_tree      *system_name_tree = NULL;
804         proto_item      *tf = NULL;
805         
806         /* Get tlv type and length */
807         tempShort = tvb_get_ntohs(tvb, offset);
808         tempType = TLV_TYPE(tempShort);
809                 
810         /* Get tlv length */
811         tempLen = TLV_INFO_LEN(tempShort);
812                         
813         if (tree)
814         {
815                 strPtr = tvb_format_stringzpad(tvb, (offset+2), tempLen);
816
817                 /* Set system name tree */
818                 if (tempType == SYSTEM_NAME_TLV_TYPE) 
819                         tf = proto_tree_add_text(tree, tvb, offset, (tempLen + 2), "System Name = %s", strPtr);
820                 else
821                         tf = proto_tree_add_text(tree, tvb, offset, (tempLen + 2), "System Description = %s", strPtr);
822                 system_name_tree = proto_item_add_subtree(tf, ett_system_name);
823                 
824                 proto_tree_add_item(system_name_tree, hf_lldp_tlv_type, tvb, offset, 2, FALSE);
825                 proto_tree_add_item(system_name_tree, hf_lldp_tlv_len, tvb, offset, 2, FALSE);
826                 
827                 /* Display system name information */
828                 proto_tree_add_text(system_name_tree, tvb, (offset+2), tempLen, "%s = %s", 
829                                         ((tempType == SYSTEM_NAME_TLV_TYPE) ? "System Name" : "System Description"),
830                                         strPtr);
831         }
832         
833         return (tempLen + 2);
834 }
835
836 /* Dissect System Capabilities TLV */
837 static gint32
838 dissect_lldp_system_capabilities(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 offset)
839 {
840         guint16 tempShort;
841         guint32 tempLen = 0;
842         guint16 tempCapability;
843         
844         proto_tree      *system_capabilities_tree = NULL;
845         proto_tree      *capabilities_summary_tree = NULL;
846         proto_tree  *capabilities_enabled_tree = NULL;
847         proto_item      *tf = NULL;
848         
849         /* Get tlv type and length */
850         tempShort = tvb_get_ntohs(tvb, offset);
851                 
852         /* Get tlv length */
853         tempLen = TLV_INFO_LEN(tempShort);
854         
855         /* Get system capabilities */
856         tempCapability = tvb_get_ntohs(tvb, (offset+2));
857                         
858         if (tree)
859         {
860                 /* Set system capabilities tree */
861                 tf = proto_tree_add_text(tree, tvb, offset, (tempLen + 2), "Capabilities");
862                 system_capabilities_tree = proto_item_add_subtree(tf, ett_system_cap);
863                 
864                 proto_tree_add_item(system_capabilities_tree, hf_lldp_tlv_type, tvb, offset, 2, FALSE);
865                 proto_tree_add_item(system_capabilities_tree, hf_lldp_tlv_len, tvb, offset, 2, FALSE);
866                 
867                 /* Display system capability information */
868                 tf = proto_tree_add_text(system_capabilities_tree, tvb, (offset+2), 2, "Capabilities: 0x%04x", tempCapability);
869                 capabilities_summary_tree = proto_item_add_subtree(tf, ett_system_cap_summary);
870                 /* Add capabilities to summary tree */
871                 if (tempCapability & SYSTEM_CAPABILITY_OTHER)
872                         proto_tree_add_text(capabilities_summary_tree, tvb, (offset+2), 2, "%s",
873                                                 decode_boolean_bitfield(tempCapability, SYSTEM_CAPABILITY_OTHER,
874                                                 16, "Other", ""));
875                 if (tempCapability & SYSTEM_CAPABILITY_REPEATER)
876                         proto_tree_add_text(capabilities_summary_tree, tvb, (offset+2), 2, "%s",
877                                                 decode_boolean_bitfield(tempCapability, SYSTEM_CAPABILITY_REPEATER,
878                                                 16, "Repeater", ""));
879                 if (tempCapability & SYSTEM_CAPABILITY_BRIDGE)
880                         proto_tree_add_text(capabilities_summary_tree, tvb, (offset+2), 2, "%s",
881                                                 decode_boolean_bitfield(tempCapability, SYSTEM_CAPABILITY_BRIDGE,
882                                                 16, "Bridge", ""));
883                 if (tempCapability & SYSTEM_CAPABILITY_WLAN)
884                         proto_tree_add_text(capabilities_summary_tree, tvb, (offset+2), 2, "%s",
885                                                 decode_boolean_bitfield(tempCapability, SYSTEM_CAPABILITY_WLAN,
886                                                 16, "WLAN access point", ""));
887                 if (tempCapability & SYSTEM_CAPABILITY_ROUTER)
888                         proto_tree_add_text(capabilities_summary_tree, tvb, (offset+2), 2, "%s",
889                                                 decode_boolean_bitfield(tempCapability, SYSTEM_CAPABILITY_ROUTER,
890                                                 16, "Router", ""));
891                 if (tempCapability & SYSTEM_CAPABILITY_TELEPHONE)
892                         proto_tree_add_text(capabilities_summary_tree, tvb, (offset+2), 2, "%s",
893                                                 decode_boolean_bitfield(tempCapability, SYSTEM_CAPABILITY_TELEPHONE,
894                                                 16, "Telephone", ""));
895                 if (tempCapability & SYSTEM_CAPABILITY_DOCSIS)
896                         proto_tree_add_text(capabilities_summary_tree, tvb, (offset+2), 2, "%s",
897                                                 decode_boolean_bitfield(tempCapability, SYSTEM_CAPABILITY_DOCSIS,
898                                                 16, "DOCSIS cable device", ""));
899                 if (tempCapability & SYSTEM_CAPABILITY_STATION)
900                         proto_tree_add_text(capabilities_summary_tree, tvb, (offset+2), 2, "%s",
901                                                 decode_boolean_bitfield(tempCapability, SYSTEM_CAPABILITY_STATION,
902                                                 16, "Station only", ""));
903                                                 
904                 /* Get enabled summary */
905                 tempShort = tvb_get_ntohs(tvb, (offset+4));
906   
907                 /* Display system capability information */
908                 tf = proto_tree_add_text(system_capabilities_tree, tvb, (offset+4), 2, "Enabled Capabilities: 0x%04x", tempShort);
909                 capabilities_enabled_tree = proto_item_add_subtree(tf, ett_system_cap_enabled);
910                 /* Add capabilities to summary tree */
911                 if (tempShort & SYSTEM_CAPABILITY_OTHER)
912                         proto_tree_add_text(capabilities_enabled_tree, tvb, (offset+4), 2, "%s",
913                                                 decode_boolean_bitfield(tempShort, SYSTEM_CAPABILITY_OTHER,
914                                                 16, "Other", ""));
915                 if (tempShort & SYSTEM_CAPABILITY_REPEATER)
916                         proto_tree_add_text(capabilities_enabled_tree, tvb, (offset+4), 2, "%s",
917                                                 decode_boolean_bitfield(tempShort, SYSTEM_CAPABILITY_REPEATER,
918                                                 16, "Repeater", ""));
919                 if (tempShort & SYSTEM_CAPABILITY_BRIDGE)
920                         proto_tree_add_text(capabilities_enabled_tree, tvb, (offset+4), 2, "%s",
921                                                 decode_boolean_bitfield(tempShort, SYSTEM_CAPABILITY_BRIDGE,
922                                                 16, "Bridge", ""));
923                 if (tempShort & SYSTEM_CAPABILITY_WLAN)
924                         proto_tree_add_text(capabilities_enabled_tree, tvb, (offset+4), 2, "%s",
925                                                 decode_boolean_bitfield(tempShort, SYSTEM_CAPABILITY_WLAN,
926                                                 16, "WLAN access point", ""));
927                 if (tempShort & SYSTEM_CAPABILITY_ROUTER)
928                         proto_tree_add_text(capabilities_enabled_tree, tvb, (offset+4), 2, "%s",
929                                                 decode_boolean_bitfield(tempShort, SYSTEM_CAPABILITY_ROUTER,
930                                                 16, "Router", ""));
931                 if (tempShort & SYSTEM_CAPABILITY_TELEPHONE)
932                         proto_tree_add_text(capabilities_enabled_tree, tvb, (offset+4), 2, "%s",
933                                                 decode_boolean_bitfield(tempShort, SYSTEM_CAPABILITY_TELEPHONE,
934                                                 16, "Telephone", ""));
935                 if (tempShort & SYSTEM_CAPABILITY_DOCSIS)
936                         proto_tree_add_text(capabilities_enabled_tree, tvb, (offset+4), 2, "%s",
937                                                 decode_boolean_bitfield(tempShort, SYSTEM_CAPABILITY_DOCSIS,
938                                                 16, "DOCSIS cable device", ""));
939                 if (tempShort & SYSTEM_CAPABILITY_STATION)
940                         proto_tree_add_text(capabilities_enabled_tree, tvb, (offset+4), 2, "%s",
941                                                 decode_boolean_bitfield(tempShort, SYSTEM_CAPABILITY_STATION,
942                                                 16, "Station only", ""));
943         }
944         
945         return (tempLen + 2);
946 }
947
948 /* Dissect Management Address TLV */
949 static gint32
950 dissect_lldp_management_address(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 offset)
951 {
952         guint16 tempShort;
953         guint32 tempLen = 0;
954         guint8  tempByte;
955         guint8  stringLen = 0;
956         guint32 tempOffset = offset;
957         guint32 tempLong;
958         
959         proto_tree      *system_mgm_addr = NULL;
960         proto_item      *tf = NULL;
961         
962         /* Get tlv type and length */
963         tempShort = tvb_get_ntohs(tvb, tempOffset);
964                 
965         /* Get tlv length */
966         tempLen = TLV_INFO_LEN(tempShort);
967                         
968         if (tree)
969         {
970                 /* Set system capabilities tree */
971                 tf = proto_tree_add_text(tree, tvb, tempOffset, (tempLen + 2), "Management Address");
972                 system_mgm_addr = proto_item_add_subtree(tf, ett_management_address);
973                 
974                 proto_tree_add_item(system_mgm_addr, hf_lldp_tlv_type, tvb, tempOffset, 2, FALSE);
975                 proto_tree_add_item(system_mgm_addr, hf_lldp_tlv_len, tvb, tempOffset, 2, FALSE);
976                 
977                 tempOffset += 2;
978                 
979                 /* Get management address string length */
980                 stringLen = tvb_get_guint8(tvb, tempOffset);
981                 proto_tree_add_text(system_mgm_addr, tvb, tempOffset, 1, "Address String Length: %u", stringLen);
982                 
983                 tempOffset++;
984                 
985                 /* Get management address subtype */
986                 tempByte = tvb_get_guint8(tvb, tempOffset);
987                 proto_tree_add_text(system_mgm_addr, tvb, tempOffset, 1, "Address Subtype: %s (%u)",
988                                                         val_to_str(tempByte, management_addr_values, "Undefined"),
989                                                         tempByte);
990                                                         
991                 tempOffset++;
992                 
993                 /* Get address */
994                 switch (tempByte)
995                 {
996                 case 1:         /* IPv4 */
997                         proto_tree_add_item(system_mgm_addr, hf_mgn_addr_ipv4, tvb, tempOffset, 4, FALSE);
998                         break;
999                 case 2:         /* IPv6 */
1000                         proto_tree_add_item(system_mgm_addr, hf_mgn_addr_ipv6, tvb, tempOffset, (stringLen-1), FALSE);
1001                         break;
1002                 default:        
1003                         proto_tree_add_item(system_mgm_addr, hf_mgn_addr_hex, tvb, tempOffset, (stringLen-1), FALSE);
1004                         break;
1005                 }
1006                 
1007                 tempOffset += (stringLen-1);
1008                 
1009                 /* Get interface numbering subtype */
1010                 tempByte = tvb_get_guint8(tvb, tempOffset);
1011                 proto_tree_add_text(system_mgm_addr, tvb, tempOffset, 1, "Interface Subtype: %s (%u)",
1012                                                         val_to_str(tempByte, interface_subtype_values, "Undefined"),
1013                                                         tempByte);
1014                 
1015                 tempOffset++;
1016                                                         
1017                 /* Get interface number */
1018                 tempLong = tvb_get_ntohl(tvb, tempOffset);
1019                 proto_tree_add_text(system_mgm_addr, tvb, tempOffset, 4, "Interface Number: %u", tempLong);
1020                 
1021                 tempOffset += 4;
1022                 
1023                 /* Get OID string length */
1024                 stringLen = tvb_get_guint8(tvb, tempOffset);
1025                 proto_tree_add_text(system_mgm_addr, tvb, tempOffset, 1, "OID String Length: %u", stringLen);
1026                 
1027                 if (stringLen > 0)
1028                 {
1029                         tempOffset++;
1030                         
1031                         /* Get OID identifier */
1032                         proto_tree_add_item(system_mgm_addr, hf_mgn_obj_id, tvb, tempOffset, stringLen, FALSE);
1033                 }
1034         }
1035         
1036         return (tempLen + 2);
1037 }
1038
1039 /* Dissect IEEE 802.1 TLVs */
1040 static void
1041 dissect_ieee_802_1_tlv(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 offset)
1042 {
1043         guint8 subType;
1044         guint8 tempByte;
1045         guint16 tempShort;
1046         guint32 tempOffset = offset;
1047         
1048         proto_tree      *vlan_flags = NULL;
1049         proto_item      *tf = NULL;
1050         
1051         /* Get subtype */
1052         subType = tvb_get_guint8(tvb, tempOffset);
1053         
1054         if (tree)
1055                 proto_tree_add_item(tree, hf_ieee_802_1_subtype, tvb, tempOffset, 1, FALSE);
1056                 
1057         tempOffset++;
1058         
1059         switch (subType)
1060         {
1061         case 0x01:      /* Port VLAN ID */
1062         {
1063                 /* Get port vland id */
1064                 tempShort = tvb_get_ntohs(tvb, tempOffset);
1065                 if (tree)
1066                         proto_tree_add_text(tree, tvb, tempOffset, 2, "Port VLAN Identifier: 0x%04X", tempShort);
1067                         
1068                 break;
1069         }
1070         case 0x02:      /* Port and Protocol VLAN ID */
1071         {
1072                 /* Get flags */
1073                 tempByte = tvb_get_guint8(tvb, tempOffset);
1074                 if (tree)
1075                 {
1076                         tf = proto_tree_add_text(tree, tvb, tempOffset, 1, "Flags: 0x%02x", tempByte);
1077                         vlan_flags = proto_item_add_subtree(tf, ett_port_vlan_flags);
1078                 
1079                         /* Get supported flag */
1080                         proto_tree_add_text(vlan_flags, tvb, tempOffset, 1, "%s",
1081                                                 decode_boolean_bitfield(tempByte, 0x01, 8, "Port and Protocol VLAN: Supported", 
1082                                                                                                 "Port and Protocol VLAN: Not Supported"));
1083                                                                         
1084                         /* Get enabled flag */
1085                         proto_tree_add_text(vlan_flags, tvb, tempOffset, 1, "%s",
1086                                                 decode_boolean_bitfield(tempByte, 0x02, 8, "Port and Protocol VLAN: Enabled", 
1087                                                                                                 "Port and Protocol VLAN: Not Enabled"));
1088                 }
1089                 
1090                 tempOffset++;
1091                 
1092                 /* Get port and protocol vlan id */
1093                 tempShort = tvb_get_ntohs(tvb, tempOffset);
1094                 if (tree)
1095                         proto_tree_add_text(tree, tvb, tempOffset, 2, "Port and Protocol VLAN Identifier: 0x%04X", tempShort);
1096                 
1097                 break;
1098         }
1099         case 0x03:      /* VLAN Name */
1100         {
1101                 /* Get vlan id */
1102                 tempShort = tvb_get_ntohs(tvb, tempOffset);
1103                 if (tree)
1104                         proto_tree_add_text(tree, tvb, tempOffset, 2, "VLAN Identifier: 0x%04X", tempShort);
1105                         
1106                 tempOffset += 2;
1107                 
1108                 /* Get vlan name length */
1109                 tempByte = tvb_get_guint8(tvb, tempOffset);
1110                 if (tree)
1111                         proto_tree_add_text(tree, tvb, tempOffset, 1, "VLAN Name Length: %u", tempByte);
1112                 
1113                 tempOffset++;
1114                 
1115                 if (tempByte > 0)
1116                 {
1117                         if (tree)
1118                                 proto_tree_add_text(tree, tvb, tempOffset, tempByte, "VLAN Name: %s",
1119                                     tvb_format_stringzpad(tvb, tempOffset, tempByte));
1120                 }
1121                 
1122                 break;
1123         }
1124         case 0x04:      /* Protocol ID */
1125         {
1126                 /* Get protocal id length */
1127                 tempByte = tvb_get_guint8(tvb, tempOffset);
1128                 if (tree)
1129                         proto_tree_add_text(tree, tvb, tempOffset, 1, "Protocol Identity Length: %u", tempByte);
1130                 
1131                 tempOffset++;
1132                 
1133                 if (tempByte > 0)
1134                 {
1135                         if (tree)
1136                                 proto_tree_add_text(tree, tvb, tempOffset, tempByte, "Protocol Identity: %s",
1137                                         tvb_bytes_to_str(tvb, tempOffset, tempByte));
1138                 }
1139                 
1140                 break;
1141         }
1142         }
1143         
1144         return;
1145 }
1146
1147 /* Dissect IEEE 802.3 TLVs */
1148 static void
1149 dissect_ieee_802_3_tlv(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 offset)
1150 {
1151         guint8 subType;
1152         guint8 tempByte;
1153         guint16 tempShort;
1154         guint32 tempLong;
1155         guint32 tempOffset = offset;
1156         
1157         proto_tree      *mac_phy_flags = NULL;
1158         proto_item      *tf = NULL;
1159         
1160         /* Get subtype */
1161         subType = tvb_get_guint8(tvb, tempOffset);
1162         
1163         if (tree)
1164                 proto_tree_add_item(tree, hf_ieee_802_3_subtype, tvb, tempOffset, 1, FALSE);
1165                 
1166         tempOffset++;
1167         
1168         switch (subType)
1169         {
1170         case 0x01:      /* MAC/PHY Configuration/Status */
1171         {
1172                 /* Get auto-negotiation info */
1173                 tempByte = tvb_get_guint8(tvb, tempOffset);
1174                 if (tree)
1175                 {
1176                         tf = proto_tree_add_text(tree, tvb, tempOffset, 1, "Auto-Negotiation Support/Status: 0x%02x", tempByte);
1177                         mac_phy_flags = proto_item_add_subtree(tf, ett_802_3_flags);
1178                 
1179                         /* Get supported flag */
1180                         proto_tree_add_text(mac_phy_flags, tvb, tempOffset, 1, "%s",
1181                                                 decode_boolean_bitfield(tempByte, 0x01, 8, "Auto-Negotiation: Supported", 
1182                                                                                                 "Auto-Negotiation: Not Supported"));
1183                                                                         
1184                         /* Get enabled flag */
1185                         proto_tree_add_text(mac_phy_flags, tvb, tempOffset, 1, "%s",
1186                                                 decode_boolean_bitfield(tempByte, 0x02, 8, "Auto-Negotiation: Enabled", 
1187                                                                                                 "Auto-Negotiation: Not Enabled"));
1188                 }
1189                 
1190                 tempOffset++;
1191                 
1192                 /* Get pmd auto-negotiation advertised capability */
1193                 tempShort = tvb_get_ntohs(tvb, tempOffset);
1194                 if (tree)
1195                         proto_tree_add_text(tree, tvb, tempOffset, 2, "PMD Auto-Negotiation Advertised Capability: 0x%04X", tempShort);
1196                         
1197                 tempOffset += 2;
1198                 
1199                 /* Get operational MAU type */
1200                 tempShort = tvb_get_ntohs(tvb, tempOffset);
1201                 if (tree)
1202                         proto_tree_add_text(tree, tvb, tempOffset, 2, "Operational MAU Type: 0x%04X", tempShort);
1203                         
1204                 tempOffset += 2;
1205                 
1206                 break;
1207         }
1208         case 0x02:      /* MDI Power Support */
1209         {
1210                 /* Get MDI power support info */
1211                 tempByte = tvb_get_guint8(tvb, tempOffset);
1212                 if (tree)
1213                 {
1214                         tf = proto_tree_add_text(tree, tvb, tempOffset, 1, "MDI Power Support: 0x%02x", tempByte);
1215                         mac_phy_flags = proto_item_add_subtree(tf, ett_802_3_power);
1216                 
1217                         /* Get port class */
1218                         proto_tree_add_text(mac_phy_flags, tvb, tempOffset, 1, "%s",
1219                                                 decode_boolean_bitfield(tempByte, 0x01, 8, "Port Class: PSE", 
1220                                                                                                 "Port Class: PD"));
1221                                                                         
1222                         /* Get PSE MDI power support */
1223                         proto_tree_add_text(mac_phy_flags, tvb, tempOffset, 1, "%s",
1224                                                 decode_boolean_bitfield(tempByte, 0x02, 8, "PSE MDI Power: Supported", 
1225                                                                                                 "PSE MDI Power: Not Supported"));
1226                                                                                         
1227                         /* Get PSE MDI power state */
1228                         proto_tree_add_text(mac_phy_flags, tvb, tempOffset, 1, "%s",
1229                                                 decode_boolean_bitfield(tempByte, 0x04, 8, "PSE MDI Power Enabled: Yes", 
1230                                                                                                 "PSE MDI Power Enabled: No"));
1231                                                                                                 
1232                         /* Get PSE pairs control ability */
1233                         proto_tree_add_text(mac_phy_flags, tvb, tempOffset, 1, "%s",
1234                                                 decode_boolean_bitfield(tempByte, 0x08, 8, "PSE Pairs Control Ability: Yes", 
1235                                                                                                 "PSE Pairs Control Ability: No"));
1236                 }
1237                 
1238                 tempOffset++;
1239                 
1240                 /* Get PSE power pair */
1241                 tempByte = tvb_get_guint8(tvb, tempOffset);
1242                 if (tree)
1243                         proto_tree_add_text(tree, tvb, tempOffset, 1, "PSE Power Pair: %u", tempByte);
1244                         
1245                 tempOffset++;
1246                 
1247                 /* Get power class */
1248                 tempByte = tvb_get_guint8(tvb, tempOffset);
1249                 if (tree)
1250                         proto_tree_add_text(tree, tvb, tempOffset, 1, "Power Class: %u", tempByte);
1251                         
1252                 tempOffset++;
1253                 
1254                 break;
1255         }
1256         case 0x03:      /* Link Aggregation */
1257         {
1258                 /* Get aggregation status */
1259                 tempByte = tvb_get_guint8(tvb, tempOffset);
1260                 if (tree)
1261                 {
1262                         tf = proto_tree_add_text(tree, tvb, tempOffset, 1, "Aggregation Status: 0x%02x", tempByte);
1263                         mac_phy_flags = proto_item_add_subtree(tf, ett_802_3_aggregation);
1264                 
1265                         /* Get aggregation capability */
1266                         proto_tree_add_text(mac_phy_flags, tvb, tempOffset, 1, "%s",
1267                                                 decode_boolean_bitfield(tempByte, 0x01, 8, "Aggregation Capability: Yes", 
1268                                                                                                 "Aggregation Capability: No"));
1269                                                                         
1270                         /* Get aggregation status */
1271                         proto_tree_add_text(mac_phy_flags, tvb, tempOffset, 1, "%s",
1272                                                 decode_boolean_bitfield(tempByte, 0x02, 8, "Aggregation Status: Enabled", 
1273                                                                                                 "Aggregation Status: Not Enabled"));
1274                 }
1275                 
1276                 tempOffset++;
1277                 
1278                 /* Get aggregated port id */
1279                 tempLong = tvb_get_ntohl(tvb, tempOffset);
1280                 if (tree)
1281                         proto_tree_add_text(tree, tvb, tempOffset, 4, "Aggregated Port Id: %u", tempLong);
1282                         
1283                 tempOffset += 4;
1284                 
1285                 break;
1286         }
1287         case 0x04:      /* Maximum Frame Size */
1288         {
1289                 /* Get maximum frame size */
1290                 tempShort = tvb_get_ntohs(tvb, tempOffset);
1291                 if (tree)
1292                         proto_tree_add_text(tree, tvb, tempOffset, 2, "Maximum Frame Size: %u", tempShort);
1293                         
1294                 tempOffset += 2;
1295                 
1296                 break; 
1297         }
1298         }
1299                 
1300         return;
1301 }
1302
1303 /* Dissect Media TLVs */
1304 static void
1305 dissect_media_tlv(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 offset, guint16 tlvLen)
1306 {
1307         guint32 tempOffset = offset;
1308         guint8 subType;
1309         guint16 tempShort;
1310         guint16 tempVLAN;
1311         guint8 tempByte;
1312         guint32 tempLong;
1313         const char *strPtr;
1314         guint32 LCI_Length;
1315         guint64 temp64bit = 0;
1316         
1317         proto_tree      *media_flags = NULL;
1318         proto_item      *tf = NULL;
1319         
1320         /* Get subtype */
1321         subType = tvb_get_guint8(tvb, tempOffset);
1322         if (tree)
1323                 proto_tree_add_item(tree, hf_media_tlv_subtype, tvb, tempOffset, 1, FALSE);
1324         tempOffset++;
1325         tlvLen--;
1326         
1327         switch (subType)
1328         {
1329         case 1:         /* LLDP-MED Capabilities */
1330         {
1331                 /* Get capabilities */
1332                 if (tlvLen < 2)
1333                 {
1334                         proto_tree_add_text(tree, tvb, tempOffset, 0, "TLV too short");
1335                         return;
1336                 }
1337                 tempShort = tvb_get_ntohs(tvb, tempOffset);
1338                 if (tree)
1339                 {
1340                         tf = proto_tree_add_text(tree, tvb, tempOffset, 2, "Capabilities: 0x%04x", tempShort);
1341                         media_flags = proto_item_add_subtree(tf, ett_media_capabilities);
1342                         if (tempShort & MEDIA_CAPABILITY_LLDP)
1343                                 proto_tree_add_text(media_flags, tvb, tempOffset, 2, "%s",
1344                                                 decode_boolean_bitfield(tempShort, MEDIA_CAPABILITY_LLDP, 16, 
1345                                                                                                 "LLDP-MED Capabilities", ""));
1346                         if (tempShort & MEDIA_CAPABILITY_NETWORK_POLICY)
1347                                 proto_tree_add_text(media_flags, tvb, tempOffset, 2, "%s",
1348                                                 decode_boolean_bitfield(tempShort, MEDIA_CAPABILITY_NETWORK_POLICY, 16, 
1349                                                                                                 "Network Policy", ""));
1350                         if (tempShort & MEDIA_CAPABILITY_LOCATION_ID)
1351                                 proto_tree_add_text(media_flags, tvb, tempOffset, 2, "%s",
1352                                                 decode_boolean_bitfield(tempShort, MEDIA_CAPABILITY_LOCATION_ID, 16, 
1353                                                                                                 "Location Identification", ""));
1354                         if (tempShort & MEDIA_CAPABILITY_MDI_PSE)
1355                                 proto_tree_add_text(media_flags, tvb, tempOffset, 2, "%s",
1356                                                 decode_boolean_bitfield(tempShort, MEDIA_CAPABILITY_MDI_PSE, 16, 
1357                                                                                                 "Extended Power via MDI-PSE", ""));
1358                         if (tempShort & MEDIA_CAPABILITY_MDI_PD)
1359                                 proto_tree_add_text(media_flags, tvb, tempOffset, 2, "%s",
1360                                                 decode_boolean_bitfield(tempShort, MEDIA_CAPABILITY_MDI_PD, 16, 
1361                                                                                                 "Extended Power via MDI-PD", ""));
1362                         if (tempShort & MEDIA_CAPABILITY_INVENTORY)
1363                                 proto_tree_add_text(media_flags, tvb, tempOffset, 2, "%s",
1364                                                 decode_boolean_bitfield(tempShort, MEDIA_CAPABILITY_INVENTORY, 16, 
1365                                                                                                 "Inventory", ""));
1366                 }
1367                 tempOffset += 2;
1368                 tlvLen -= 2;
1369                 
1370                 /* Get Class type */
1371                 if (tlvLen < 1)
1372                 {
1373                         proto_tree_add_text(tree, tvb, tempOffset, 0, "TLV too short");
1374                         return;
1375                 }
1376                 tempByte = tvb_get_guint8(tvb, tempOffset);
1377                 if (tree)
1378                         proto_tree_add_text(tree, tvb, tempOffset, 1, "Class Type: %s", val_to_str(tempByte, media_class_values, "Unknown"));
1379                 tempOffset++;
1380                 tlvLen--;
1381         
1382                 break;
1383         }
1384         case 2:         /* Network Policy */
1385         {
1386                 /* Get application type */
1387                 if (tlvLen < 1)
1388                 {
1389                         proto_tree_add_text(tree, tvb, tempOffset, 0, "TLV too short");
1390                         return;
1391                 }
1392                 tempByte = tvb_get_guint8(tvb, tempOffset);
1393                 if (tree)
1394                         proto_tree_add_text(tree, tvb, tempOffset, 1, "Applicaton Type: %s (%u)", 
1395                                                         val_to_str(tempByte, media_application_type, "Unknown"), tempByte);
1396                 tempOffset++;
1397                 tlvLen--;
1398                 
1399                 /* Get flags */
1400                 if (tlvLen < 1)
1401                 {
1402                         proto_tree_add_text(tree, tvb, tempOffset, 0, "TLV too short");
1403                         return;
1404                 }
1405                 tempByte = tvb_get_guint8(tvb, tempOffset);
1406                 
1407                 /* Unknown policy flag */
1408                 if (tree)
1409                         proto_tree_add_text(tree, tvb, tempOffset, 1, "%s",
1410                                                 decode_boolean_bitfield(tempByte, 0x80, 8,"Policy: Unknown", "Policy: Defined"));
1411                 
1412                 /* Tagged flag */
1413                 if (tree)
1414                         proto_tree_add_text(tree, tvb, tempOffset, 1, "%s",
1415                                                 decode_boolean_bitfield(tempByte, 0x40, 8,"Tagged: Yes", "Tagged: No"));
1416                 tempOffset++;
1417                 tlvLen--;
1418                                                 
1419                 /* Get vlan id */
1420                 if (tlvLen < 1)
1421                 {
1422                         proto_tree_add_text(tree, tvb, tempOffset, 0, "TLV too short");
1423                         return;
1424                 }
1425                 tempShort = tvb_get_ntohs(tvb, tempOffset);
1426                 tempVLAN = (tempShort & 0x1FFE) >> 1;
1427                 if (tree)
1428                         proto_tree_add_text(tree, tvb, tempOffset, 2, "%s %u",
1429                                                 decode_boolean_bitfield(tempShort, 0x1FFE, 16, "VLAN Id:", "VLAN Id:"), tempVLAN);
1430                 tempOffset++;
1431                 tlvLen--;
1432                 
1433                 /* Get L2 priority */
1434                 if (tlvLen < 1)
1435                 {
1436                         proto_tree_add_text(tree, tvb, tempOffset, 0, "TLV too short");
1437                         return;
1438                 }
1439                 tempShort = tvb_get_ntohs(tvb, tempOffset);
1440                 if (tree)
1441                         proto_tree_add_text(tree, tvb, tempOffset, 2, "%s %u",
1442                                                 decode_boolean_bitfield(tempShort, 0x01C0, 16, "L2 Priority:", "L2 Priority:"), 
1443                                                                                                 ((tempShort & 0x01C0) >> 6));
1444                 tempOffset++;
1445                 tlvLen--;
1446                                                                                                         
1447                 /* Get DSCP value */
1448                 tempByte = tvb_get_guint8(tvb, tempOffset);
1449                 if (tree)
1450                         proto_tree_add_text(tree, tvb, tempOffset, 1, "%s %u",
1451                                                 decode_boolean_bitfield(tempByte, 0x3F, 8, "DSCP Value:", "DSCP Value:"), 
1452                                                                                                 (tempByte & 0x3F));
1453                 
1454                 break;
1455         }
1456         case 3: /* Location Identification */
1457         {
1458                 /* Get location data format */
1459                 if (tlvLen < 1)
1460                 {
1461                         proto_tree_add_text(tree, tvb, tempOffset, 0, "TLV too short");
1462                         return;
1463                 }
1464                 tempByte = tvb_get_guint8(tvb, tempOffset);
1465                 if (tree)
1466                         proto_tree_add_text(tree, tvb, tempOffset, 1, "Location Data Format: %s (%u)", 
1467                                                         val_to_str(tempByte, location_data_format, "Unknown"), tempByte);
1468                 tempOffset++;
1469                 tlvLen--;
1470                 
1471                 switch (tempByte)
1472                 {
1473                 case 1: /* Coordinate-based LCI */
1474                 {
1475                         /*
1476                          * See RFC 3825.
1477                          * XXX - should this be handled by the BOOTP
1478                          * dissector, and exported to us?
1479                          */
1480                         if (tlvLen < 16)
1481                         {
1482                                 proto_tree_add_text(tree, tvb, tempOffset, 0, "TLV too short");
1483                                 return;
1484                         }
1485                         
1486                         /* Get latitude resolution */
1487                         tempByte = tvb_get_guint8(tvb, tempOffset);
1488                         if (tree)
1489                                 proto_tree_add_text(tree, tvb, tempOffset, 1, "%s %u",
1490                                                 decode_boolean_bitfield(tempByte, 0xFC, 8, "Latitude Resolution:", "Latitude Resolution:"), 
1491                                                                                                 ((tempByte & 0xFC) >> 2));
1492                                                                                                 
1493                         /* Get latitude */
1494                         temp64bit = tvb_get_ntoh64(tvb, tempOffset);
1495                         temp64bit = (temp64bit & G_GINT64_CONSTANT(0x03FFFFFFFF000000)) >> 24;
1496                         if (tree)
1497                                 proto_tree_add_text(tree, tvb, tempOffset, 5, "Latitude: %s (0x%16" PRIX64 ")", 
1498                                     get_latitude_or_longitude(0, temp64bit),
1499                                     temp64bit);
1500                                 
1501                         tempOffset += 5;
1502                         
1503                         /* Get longitude resolution */
1504                         tempByte = tvb_get_guint8(tvb, tempOffset);
1505                         if (tree)
1506                                 proto_tree_add_text(tree, tvb, tempOffset, 1, "%s %u",
1507                                         decode_boolean_bitfield(tempByte, 0xFC, 8, "Longitude Resolution:", "Longitude Resolution:"), 
1508                                                                                         ((tempByte & 0xFC) >> 2));
1509
1510                         /* Get longitude */
1511                         temp64bit = tvb_get_ntoh64(tvb, tempOffset);
1512                         temp64bit = (temp64bit & G_GINT64_CONSTANT(0x03FFFFFFFF000000)) >> 24;
1513                         ;
1514                         if (tree)
1515                                 proto_tree_add_text(tree, tvb, tempOffset, 5, "Longitude: %s (0x%16" PRIX64 ")", 
1516                                     get_latitude_or_longitude(1,temp64bit),
1517                                     temp64bit);
1518                                 
1519                         tempOffset += 5;
1520                         
1521                         /* Altitude Type */
1522                         tempByte = tvb_get_guint8(tvb, tempOffset);
1523                         if (tree)
1524                         {
1525                                 tf = proto_tree_add_text(tree, tvb, tempOffset, 1, "%s",
1526                                                 decode_boolean_bitfield(tempByte, 0xF0, 8, "Altitude Type: ", "Altitude Type: "));
1527                                 
1528                                 switch ((tempByte >> 4))
1529                                 {
1530                                 case 1:
1531                                         proto_item_append_text(tf, "Meters (1)");
1532                                         break;
1533                                 case 2:
1534                                         proto_item_append_text(tf, "Floors (2)");
1535                                         break;
1536                                 default:
1537                                         proto_item_append_text(tf, " Unknown (%u)", (tempByte >> 4));
1538                                         break;
1539                                 }
1540                         }
1541                         
1542                         /* Get Altitude Resolution */
1543                         tempShort = tvb_get_ntohs(tvb, tempOffset);
1544                         if (tree)
1545                                 proto_tree_add_text(tree, tvb, tempOffset, 2, "%s %u",
1546                                                 decode_boolean_bitfield(tempShort, 0x0FC0, 16, "Altitude Resolution: ", "Altitude Type: "),
1547                                                 ((tempShort & 0x0FC0) >> 6));
1548                                                 
1549                         tempOffset++;
1550                         
1551                         /* Get Altitude */
1552                         tempLong = (tvb_get_ntohl(tvb, tempOffset) & 0x03FFFFFFF);
1553                         if (tree)
1554                                 proto_tree_add_text(tree, tvb, tempOffset, 4, "Altitude: 0x%08X", tempLong);
1555                                 
1556                         tempOffset += 4;
1557                         
1558                         /* Get datum */
1559                         tempByte = tvb_get_guint8(tvb, tempOffset);
1560                         if (tree)
1561                                 proto_tree_add_text(tree, tvb, tempOffset, 1, "Datum: %u", tempByte);   
1562                         
1563                         break;
1564                 }
1565                 case 2: /* Civic Address LCI */
1566                 {
1567                         /*
1568                          * See draft-ietf-geopriv-dhcp-civil-07.
1569                          * XXX - should this be handled by the BOOTP
1570                          * dissector, and exported to us?
1571                          */
1572                         if (tlvLen < 1)
1573                         {
1574                                 proto_tree_add_text(tree, tvb, tempOffset, 0, "TLV too short");
1575                                 return;
1576                         }
1577                         
1578                         /* Get LCI length */
1579                         tempByte = tvb_get_guint8(tvb, tempOffset);
1580                         tlvLen--;
1581                         if (tempByte > tlvLen)
1582                         {
1583                                 if (tree)
1584                                         proto_tree_add_text(tree, tvb, tempOffset, 1, "LCI Length: %u (greater than TLV length)", tempByte); 
1585                                         
1586                                 return;
1587                         }
1588                         
1589                         if (tree)
1590                                 proto_tree_add_text(tree, tvb, tempOffset, 1, "LCI Length: %u", tempByte); 
1591                                 
1592                         LCI_Length = (guint32)tempByte;
1593                                 
1594                         tempOffset++;
1595                         
1596                         /* Get what value */
1597                         if (LCI_Length < 1)
1598                         {
1599                                 proto_tree_add_text(tree, tvb, tempOffset, 0, "LCI Length too short");
1600                                 return;
1601                         }
1602                         tempByte = tvb_get_guint8(tvb, tempOffset);
1603                         if (tree)
1604                                 proto_tree_add_text(tree, tvb, tempOffset, 1, "What: %s (%u)",
1605                                                                         val_to_str(tempByte,civic_address_what_values,"Unknown"),
1606                                                                         tempByte);
1607                         tempOffset++;
1608                         LCI_Length--;
1609                         
1610                         /* Get country code */
1611                         if (LCI_Length < 2)
1612                         {
1613                                 proto_tree_add_text(tree, tvb, tempOffset, 0, "LCI Length too short");
1614                                 return;
1615                         }
1616                         if (tree)
1617                                 proto_tree_add_text(tree, tvb, tempOffset, 2, "Country: %s",
1618                                     tvb_format_text(tvb, tempOffset, 2));
1619                                 
1620                         tempOffset += 2;
1621                         LCI_Length -= 2;
1622                         
1623                         while (LCI_Length > 0)
1624                         {
1625                                 /* Get CA Type */
1626                                 if (LCI_Length < 1)
1627                                 {
1628                                         proto_tree_add_text(tree, tvb, tempOffset, 0, "LCI Length too short");
1629                                         return;
1630                                 }
1631                                 tempByte = tvb_get_guint8(tvb, tempOffset);
1632                                 if (tree)
1633                                         proto_tree_add_text(tree, tvb, tempOffset, 1, "CA Type: %s (%u)",
1634                                                                         val_to_str(tempByte,civic_address_type_values,"Unknown"),
1635                                                                         tempByte);
1636                                                                         
1637                                 tempOffset++;
1638                                 LCI_Length--;
1639                                 
1640                                 /* Get CA Length */
1641                                 if (LCI_Length < 1)
1642                                 {
1643                                         proto_tree_add_text(tree, tvb, tempOffset, 0, "LCI Length too short");
1644                                         return;
1645                                 }
1646                                 tempByte = tvb_get_guint8(tvb, tempOffset);
1647                                 if (tree)
1648                                         proto_tree_add_text(tree, tvb, tempOffset, 1, "CA Length: %u", tempByte);
1649                                 
1650                                 tempOffset++;
1651                                 LCI_Length--;
1652                                 
1653                                 /* Make sure the CA value is within the specified length */
1654                                 if (tempByte > LCI_Length)
1655                                         return;
1656                                 
1657                                 if (tempByte > 0)
1658                                 {
1659                                         /* Get CA Value */
1660                                         if (tree)
1661                                                 proto_tree_add_text(tree, tvb, tempOffset, tempByte, "CA Value: %s",
1662                                                     tvb_format_stringzpad(tvb, tempOffset, tempByte));
1663                                 
1664                                         tempOffset += tempByte;
1665                                         LCI_Length -= tempByte;
1666                                 }
1667                         }
1668                 
1669                         break;
1670                 }
1671                 case 3: /* ECS ELIN */
1672                 {
1673                         if (tlvLen > 0)
1674                         {
1675                                 if (tree)
1676                                         proto_tree_add_text(tree, tvb, tempOffset, tlvLen, "ELIN: %s",
1677                                             tvb_format_stringzpad(tvb, tempOffset, tlvLen));
1678                                         
1679                         }
1680                 
1681                         break;
1682                 }
1683                 }
1684                 
1685                 break;
1686         }
1687         case 4: /* Extended Power-via-MDI */
1688         {
1689                 /* Get first byte */
1690                 tempByte = tvb_get_guint8(tvb, tempOffset);
1691                 
1692                 /* Determine power type */
1693                 subType = ((tempByte & 0xC0) >> 6);
1694                 if (tree)
1695                         proto_tree_add_text(tree, tvb, tempOffset, 1, "%s %s",
1696                                                 decode_boolean_bitfield(tempByte, 0xC0, 8, "Power Type:", "Power Type:"), 
1697                                                                                                 val_to_str(subType, media_power_type, "Unknown"));
1698                                 
1699                 /* Determine power source */                                                            
1700                 switch (subType)
1701                 {
1702                 case 0:
1703                 {
1704                         subType = ((tempByte & 0x30) >> 4);
1705                         strPtr = val_to_str(subType, media_power_pse_device, "Reserved");
1706                         
1707                         break;
1708                 }
1709                 case 1:
1710                 {
1711                         subType = ((tempByte & 0x30) >> 4);
1712                         strPtr = val_to_str(subType, media_power_pd_device, "Reserved");
1713                         
1714                         break;
1715                 }
1716                 default:
1717                 {
1718                         strPtr = "Unknown";
1719                         break;
1720                 }
1721                 }
1722                 if (tree)
1723                         proto_tree_add_text(tree, tvb, tempOffset, 1, "%s %s",
1724                                                 decode_boolean_bitfield(tempByte, 0x30, 8, "Power Source:", "Power Source:"), 
1725                                                                                                 strPtr);
1726                                                 
1727                 /* Determine power priority */
1728                 subType = (tempByte & 0x0F);
1729                 if (tree)
1730                         proto_tree_add_text(tree, tvb, tempOffset, 1, "%s %s",
1731                                                 decode_boolean_bitfield(tempByte, 0x0F, 8, "Power Priority:", "Power Priority:"), 
1732                                                                                                 val_to_str(subType, media_power_priority, "Reserved"));
1733                                                         
1734                 tempOffset++;
1735                                                         
1736                 /* Get power value */
1737                 tempShort = tvb_get_ntohs(tvb, tempOffset);
1738                 if (tree)
1739                         proto_tree_add_text(tree, tvb, tempOffset, 2, "Power Value: %u", tempShort);
1740                                                                 
1741                 break;
1742         }
1743         case 5: /* Hardware Revision */
1744         {
1745                 /* Figure out the length of the hardware revision field */
1746                 if (tlvLen > 0)
1747                 {
1748                         if (tree)
1749                                 proto_tree_add_text(tree, tvb, tempOffset, tlvLen, "Hardware Revision: %s",
1750                                     tvb_format_stringzpad(tvb, tempOffset, tlvLen));
1751                 }
1752                 
1753                 break;
1754         }
1755         case 6: /* Firmware Revision */
1756         {
1757                 /* Figure out the length of the firmware revision field */
1758                 if (tlvLen > 0)
1759                 {
1760                         if (tree)
1761                                 proto_tree_add_text(tree, tvb, tempOffset, tlvLen, "Firmware Revision: %s",
1762                                     tvb_format_stringzpad(tvb, tempOffset, tlvLen));
1763                 }
1764                 
1765                 break;
1766         }
1767         case 7: /* Software Revision */
1768         {
1769                 /* Figure out the length of the software revision field */
1770                 if (tlvLen > 0)
1771                 {
1772                         if (tree)
1773                                 proto_tree_add_text(tree, tvb, tempOffset, tlvLen, "Software Revision: %s",
1774                                     tvb_format_stringzpad(tvb, tempOffset, tlvLen));
1775                 }
1776                 
1777                 break;
1778         }
1779         case 8: /* Serial Number */
1780         {
1781                 /* Figure out the length of the serial number field */
1782                 if (tlvLen > 0)
1783                 {
1784                         if (tree)
1785                                 proto_tree_add_text(tree, tvb, tempOffset, tlvLen, "Serial Number: %s",
1786                                     tvb_format_stringzpad(tvb, tempOffset, tlvLen));
1787                 }
1788                 
1789                 break;
1790         }
1791         case 9: /* Manufacturer Name */
1792         {
1793                 /* Figure out the length of the manufacturer name field */
1794                 if (tlvLen > 0)
1795                 {
1796                         if (tree)
1797                                 proto_tree_add_text(tree, tvb, tempOffset, tlvLen, "Manufacturer Name: %s",
1798                                     tvb_format_stringzpad(tvb, tempOffset, tlvLen));
1799                 }
1800                 
1801                 break;
1802         }
1803         case 10:        /* Model Name */
1804         {
1805                 /* Figure out the length of the model name field */
1806                 if (tlvLen > 0)
1807                 {
1808                         if (tree)
1809                                 proto_tree_add_text(tree, tvb, tempOffset, tlvLen, "Model Name: %s",
1810                                     tvb_format_stringzpad(tvb, tempOffset, tlvLen));
1811                 }
1812                 
1813                 break;
1814         }
1815         case 11:        /* Asset ID */
1816         {
1817                 /* Figure out the length of the asset id field */
1818                 if (tlvLen > 0)
1819                 {
1820                         if (tree)
1821                                 proto_tree_add_text(tree, tvb, tempOffset, tlvLen, "Asset ID: %s",
1822                                     tvb_format_stringzpad(tvb, tempOffset, tlvLen));
1823                 }
1824                 
1825                 break;
1826         }
1827         }
1828         
1829         return;
1830 }
1831
1832 /* Dissect Organizational Specific TLV */
1833 static gint32
1834 dissect_organizational_specific_tlv(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 offset)
1835 {
1836         guint16 tempLen;
1837         guint16 tempShort;
1838         guint32 oui;
1839         guint8 subType;
1840         const char *ouiStr;
1841         const char *subTypeStr;
1842         
1843         proto_tree      *org_tlv_tree = NULL;
1844         proto_item      *tf = NULL;
1845         
1846         /* Get tlv type and length */
1847         tempShort = tvb_get_ntohs(tvb, offset);
1848                 
1849         /* Get tlv length */
1850         tempLen = TLV_INFO_LEN(tempShort);
1851         
1852         /* Get OUI value */
1853         oui = tvb_get_ntoh24(tvb, (offset+2));
1854         subType = tvb_get_guint8(tvb, (offset+5));
1855         
1856         ouiStr = val_to_str(oui, tlv_oui_subtype_vals, "Unknown");
1857         switch(oui)
1858         {
1859         case OUI_IEEE_802_1:
1860                 subTypeStr = val_to_str(subType, ieee_802_1_subtypes, "Unknown");
1861                 break;
1862         case OUI_IEEE_802_3:
1863                 subTypeStr = val_to_str(subType, ieee_802_3_subtypes, "Unknown");
1864                 break;
1865         case OUI_MEDIA_ENDPOINT:
1866                 subTypeStr = val_to_str(subType, media_subtypes, "Unknown");
1867                 break;
1868         default:
1869                 subTypeStr = "Unknown";
1870                 break;
1871         }
1872         
1873         if (tree)
1874         {
1875                 tf = proto_tree_add_text(tree, tvb, offset, (tempLen + 2), "%s - %s",
1876                     ouiStr, subTypeStr);
1877                 org_tlv_tree = proto_item_add_subtree(tf, ett_org_spc_tlv);
1878                 
1879                 proto_tree_add_item(org_tlv_tree, hf_lldp_tlv_type, tvb, offset, 2, FALSE);
1880         }
1881         if (tempLen < 4)
1882         {
1883                 if (tree)
1884                         proto_tree_add_uint_format(org_tlv_tree, hf_lldp_tlv_len, tvb, offset, 2,
1885                             tempShort, "TLV Length: %u (too short, must be >= 4)", tempLen);
1886                         
1887                 return (tempLen + 2);
1888         }
1889         if (tree)
1890         {
1891                 proto_tree_add_item(org_tlv_tree, hf_lldp_tlv_len, tvb, offset, 2, FALSE);
1892                 
1893                 /* Display organizational unique id */
1894                 proto_tree_add_uint(org_tlv_tree, hf_org_spc_oui, tvb, (offset+2), 3, oui);
1895         }
1896         
1897         switch (oui)
1898         {
1899         case OUI_IEEE_802_1:
1900                 dissect_ieee_802_1_tlv(tvb, pinfo, org_tlv_tree, (offset+5));
1901                 break;
1902         case OUI_IEEE_802_3:
1903                 dissect_ieee_802_3_tlv(tvb, pinfo, org_tlv_tree, (offset+5));
1904                 break;
1905         case OUI_MEDIA_ENDPOINT:
1906                 dissect_media_tlv(tvb, pinfo, org_tlv_tree, (offset+5), (tempLen-3));
1907                 break;
1908         }
1909         
1910         return (tempLen + 2);
1911 }
1912
1913 /* Dissect Unknown TLV */
1914 static gint32
1915 dissect_lldp_unknown_tlv(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 offset)
1916 {
1917         guint16 tempLen;
1918         guint16 tempShort;
1919         
1920         proto_tree      *unknown_tlv_tree = NULL;
1921         proto_item      *tf = NULL;
1922         
1923         /* Get tlv type and length */
1924         tempShort = tvb_get_ntohs(tvb, offset);
1925                 
1926         /* Get tlv length */
1927         tempLen = TLV_INFO_LEN(tempShort);
1928         
1929         if (tree)
1930         {
1931                 tf = proto_tree_add_text(tree, tvb, offset, (tempLen + 2), "Unknown TLV");
1932                 unknown_tlv_tree = proto_item_add_subtree(tf, ett_unknown_tlv);
1933                 
1934                 proto_tree_add_item(unknown_tlv_tree, hf_lldp_tlv_type, tvb, offset, 2, FALSE);
1935                 proto_tree_add_item(unknown_tlv_tree, hf_lldp_tlv_len, tvb, offset, 2, FALSE);
1936         }
1937         
1938         return (tempLen + 2);
1939 }
1940
1941
1942 /* Dissect LLDP packets */
1943 static void
1944 dissect_lldp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1945 {
1946         proto_item *ti;
1947         proto_tree *lldp_tree = NULL;
1948         
1949         guint32 offset = 0;
1950         gint32 rtnValue = 0;
1951         guint16 tempShort;
1952         guint8 tempType;
1953         gboolean reachedEnd = FALSE;
1954
1955         if (check_col(pinfo->cinfo, COL_PROTOCOL)) 
1956                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "LLDP");
1957                 
1958         /* Clear the information column on summary display */
1959         if (check_col(pinfo->cinfo, COL_INFO)) {
1960                         col_clear(pinfo->cinfo, COL_INFO);
1961         }
1962
1963         if (tree) 
1964         {
1965                 ti = proto_tree_add_item(tree, proto_lldp, tvb, offset, -1, FALSE);
1966                 lldp_tree = proto_item_add_subtree(ti, ett_lldp);
1967         }
1968         
1969         /* Get chassis id tlv */
1970         rtnValue = dissect_lldp_chassis_id(tvb, pinfo, lldp_tree, offset);
1971         if (rtnValue < 0)
1972         {
1973                 if (check_col(pinfo->cinfo, COL_INFO)) 
1974                         col_set_str(pinfo->cinfo, COL_INFO, "Invalid Chassis ID TLV");
1975                         
1976                 return;
1977         }
1978         
1979         offset += rtnValue;
1980         
1981         /* Get port id tlv */
1982         rtnValue = dissect_lldp_port_id(tvb, pinfo, lldp_tree, offset);
1983         if (rtnValue < 0)
1984         {
1985                 if (check_col(pinfo->cinfo, COL_INFO)) 
1986                         col_set_str(pinfo->cinfo, COL_INFO, "Invalid Port ID TLV");
1987                         
1988                 return;
1989         }
1990         
1991         offset += rtnValue;
1992         
1993         /* Get time to live tlv */
1994         rtnValue = dissect_lldp_time_to_live(tvb, pinfo, lldp_tree, offset);
1995         if (rtnValue < 0)
1996         {
1997                 if (check_col(pinfo->cinfo, COL_INFO)) 
1998                         col_set_str(pinfo->cinfo, COL_INFO, "Invalid Time-to-Live TLV");
1999                         
2000                 return;
2001         }
2002         
2003         offset += rtnValue;
2004         
2005         /* Dissect optional tlv's until end-of-lldpdu is reached */
2006         while (!reachedEnd)
2007         {
2008                 tempShort = tvb_get_ntohs(tvb, offset);
2009                 tempType = TLV_TYPE(tempShort);
2010                 
2011                 switch (tempType)
2012                 {
2013                 case CHASSIS_ID_TLV_TYPE:
2014                         rtnValue = dissect_lldp_chassis_id(tvb, pinfo, lldp_tree, offset);
2015                         rtnValue = -1;  /* Duplicate chassis id tlv */
2016                         if (check_col(pinfo->cinfo, COL_INFO)) 
2017                                 col_set_str(pinfo->cinfo, COL_INFO, "Duplicate Chassis ID TLV");
2018                         break;
2019                 case PORT_ID_TLV_TYPE:
2020                         rtnValue = dissect_lldp_port_id(tvb, pinfo, lldp_tree, offset);
2021                         rtnValue = -1;  /* Duplicate port id tlv */
2022                         if (check_col(pinfo->cinfo, COL_INFO)) 
2023                                 col_set_str(pinfo->cinfo, COL_INFO, "Duplicate Port ID TLV");
2024                         break;
2025                 case TIME_TO_LIVE_TLV_TYPE:
2026                         rtnValue = dissect_lldp_time_to_live(tvb, pinfo, lldp_tree, offset);
2027                         rtnValue = -1;  /* Duplicate time-to-live tlv */
2028                         if (check_col(pinfo->cinfo, COL_INFO)) 
2029                                 col_set_str(pinfo->cinfo, COL_INFO, "Duplicate Time-To-Live TLV");
2030                         break;
2031                 case END_OF_LLDPDU_TLV_TYPE:
2032                         rtnValue = dissect_lldp_end_of_lldpdu(tvb, pinfo, lldp_tree, offset);
2033                         break;
2034                 case PORT_DESCRIPTION_TLV_TYPE:
2035                         rtnValue = dissect_lldp_port_desc(tvb, pinfo, lldp_tree, offset);
2036                         break;
2037                 case SYSTEM_NAME_TLV_TYPE:
2038                 case SYSTEM_DESCRIPTION_TLV_TYPE:
2039                         rtnValue = dissect_lldp_system_name(tvb, pinfo, lldp_tree, offset);
2040                         break;
2041                 case SYSTEM_CAPABILITIES_TLV_TYPE:
2042                         rtnValue = dissect_lldp_system_capabilities(tvb, pinfo, lldp_tree, offset);
2043                         break;
2044                 case MANAGEMENT_ADDR_TLV_TYPE:
2045                         rtnValue = dissect_lldp_management_address(tvb, pinfo, lldp_tree, offset);
2046                         break;
2047                 case ORGANIZATION_SPECIFIC_TLV_TYPE:
2048                         rtnValue = dissect_organizational_specific_tlv(tvb, pinfo, lldp_tree, offset);
2049                         break;
2050                 default:
2051                         rtnValue = dissect_lldp_unknown_tlv(tvb, pinfo, lldp_tree, offset);
2052                         break;
2053                 }
2054                 
2055                 if (rtnValue < 0)
2056                         reachedEnd = TRUE;
2057                 else
2058                         offset += rtnValue;
2059         }
2060         
2061 }
2062
2063 /* Register the protocol with Ethereal */
2064 void
2065 proto_register_lldp(void)
2066 {
2067         /* Setup list of header fields */
2068         static hf_register_info hf[] = {
2069                 { &hf_lldp_tlv_type,
2070                         { "TLV Type", "lldp.tlv.type", FT_UINT16, BASE_DEC, 
2071                         VALS(tlv_types), TLV_TYPE_MASK, "", HFILL }
2072                 },
2073                 { &hf_lldp_tlv_len,
2074                         { "TLV Length", "lldp.tlv.len", FT_UINT16, BASE_DEC, 
2075                         NULL, TLV_INFO_LEN_MASK, "", HFILL }
2076                 },
2077                 { &hf_chassis_id_subtype,
2078                         { "Chassis Id Subtype", "lldp.chassis.subtype", FT_UINT8, BASE_DEC, 
2079                         VALS(chassis_id_subtypes), 0, "", HFILL }
2080                 },
2081                 { &hf_chassis_id,
2082                         { "Chassis Id", "lldp.chassis.id", FT_BYTES, BASE_HEX, 
2083                         NULL, 0, "", HFILL }
2084                 },
2085                 { &hf_chassis_id_mac,
2086                         { "Chassis Id", "lldp.chassis.id.mac", FT_ETHER, BASE_NONE, 
2087                         NULL, 0, "", HFILL }
2088                 },
2089                 { &hf_chassis_id_ip4,
2090                         { "Chassis Id", "lldp.chassis.id.ip4", FT_IPv4, BASE_NONE, 
2091                         NULL, 0, "", HFILL }
2092                 },
2093                 { &hf_chassis_id_ip6,
2094                         { "Chassis Id", "lldp.chassis.id.ip6", FT_IPv6, BASE_NONE, 
2095                         NULL, 0, "", HFILL }
2096                 },
2097                 { &hf_port_id_subtype,
2098                         { "Port Id Subtype", "lldp.port.subtype", FT_UINT8, BASE_DEC, 
2099                         VALS(port_id_subtypes), 0, "", HFILL }
2100                 },
2101                 { &hf_port_id_mac,
2102                         { "Port Id", "lldp.port.id.mac", FT_ETHER, BASE_NONE, 
2103                         NULL, 0, "", HFILL }
2104                 },
2105                 { &hf_port_id_ip4,
2106                         { "Port Id", "lldp.port.id.ip4", FT_IPv4, BASE_NONE, 
2107                         NULL, 0, "", HFILL }
2108                 },
2109                 { &hf_port_id_ip6,
2110                         { "Port Id", "lldp.port.id.ip6", FT_IPv6, BASE_NONE, 
2111                         NULL, 0, "", HFILL }
2112                 },
2113                 { &hf_time_to_live,
2114                         { "Seconds", "lldp.time_to_live", FT_UINT16, BASE_DEC, 
2115                         NULL, 0, "", HFILL }
2116                 },
2117                 { &hf_mgn_addr_ipv4,
2118                         { "Management Address", "lldp.mgn.addr.ip4", FT_IPv4, BASE_NONE, 
2119                         NULL, 0, "", HFILL }
2120                 },
2121                 { &hf_mgn_addr_ipv6,
2122                         { "Management Address", "lldp.mgn.addr.ip6", FT_IPv6, BASE_NONE, 
2123                         NULL, 0, "", HFILL }
2124                 },
2125                 { &hf_mgn_addr_hex,
2126                         { "Management Address", "lldp.mgn.addr.hex", FT_BYTES, BASE_HEX, 
2127                         NULL, 0, "", HFILL }
2128                 },
2129                 { &hf_mgn_obj_id,
2130                         { "Object Identifier", "lldp.mgn.obj.id", FT_BYTES, BASE_HEX, 
2131                         NULL, 0, "", HFILL }
2132                 },
2133                 { & hf_org_spc_oui,
2134                         { "Organization Unique Code",   "lldp.orgtlv.oui", FT_UINT24, BASE_HEX,
2135                         VALS(tlv_oui_subtype_vals), 0x0, "", HFILL }
2136                 },
2137                 { &hf_ieee_802_1_subtype,
2138                         { "IEEE 802.1 Subtype", "lldp.ieee.802_1.subtype", FT_UINT8, BASE_HEX,
2139                         VALS(ieee_802_1_subtypes), 0x0, "", HFILL }
2140                 },
2141                 { &hf_ieee_802_3_subtype,
2142                         { "IEEE 802.3 Subtype", "lldp.ieee.802_3.subtype", FT_UINT8, BASE_HEX,
2143                         VALS(ieee_802_3_subtypes), 0x0, "", HFILL }
2144                 },
2145                 { &hf_media_tlv_subtype,
2146                         { "Media Subtype",      "lldp.media.subtype", FT_UINT8, BASE_HEX,
2147                         VALS(media_subtypes), 0x0, "", HFILL }
2148                 },
2149         };
2150         
2151         /* Setup protocol subtree array */
2152         static gint *ett[] = {
2153                 &ett_lldp,
2154                 &ett_chassis_id,
2155                 &ett_port_id,
2156                 &ett_time_to_live,
2157                 &ett_end_of_lldpdu,
2158                 &ett_port_description,
2159                 &ett_system_name,
2160                 &ett_system_cap,
2161                 &ett_system_cap_summary,
2162                 &ett_system_cap_enabled,
2163                 &ett_management_address,
2164                 &ett_unknown_tlv,
2165                 &ett_org_spc_tlv,
2166                 &ett_port_vlan_flags,
2167                 &ett_802_3_flags,
2168                 &ett_802_3_power,
2169                 &ett_802_3_aggregation,
2170                 &ett_media_capabilities,
2171         };
2172
2173         /* Register the protocol name and description */
2174         proto_lldp = proto_register_protocol("Link Layer Discovery Protocol", "LLDP", "lldp");
2175
2176         /* Required function calls to register the header fields and subtrees used */
2177         proto_register_field_array(proto_lldp, hf, array_length(hf));
2178         proto_register_subtree_array(ett, array_length(ett));
2179 }
2180
2181 void
2182 proto_reg_handoff_lldp(void)
2183 {
2184         dissector_handle_t lldp_handle;
2185
2186         lldp_handle = create_dissector_handle(dissect_lldp,proto_lldp);
2187         dissector_add("ethertype", ETHERTYPE_LLDP, lldp_handle);
2188 }