Move 3 ASN1 dissectors to 'clean' group; move 1 PIDL dissector to 'dirty' group.
[metze/wireshark/wip.git] / epan / dissectors / packet-ecp-oui.c
1 /* packet-ecp-oui.c
2  * ECP/VDP dissector for wireshark (according to IEEE 802.1Qbg draft 0)
3  * By Jens Osterkamp <jens at linux.vnet.ibm.com>
4  *    Mijo Safradin <mijo at linux.vnet.ibm.com>
5  * Copyright 2011,2012  IBM Corp.
6  *
7  * $Id$
8  *
9  * Wireshark - Network traffic analyzer
10  * By Gerald Combs <gerald@wireshark.org>
11  * Copyright 1998 Gerald Combs
12  *
13  * This program is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation; either version 2 of the License, or
16  * (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 along
24  * with this program; if not, write to the Free Software Foundation, Inc.,
25  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26  */
27
28 #include "config.h"
29
30 #include <glib.h>
31 #include <epan/packet.h>
32 #include <epan/oui.h>
33 #include <epan/addr_resolv.h>
34
35 #include "packet-ieee802a.h"
36 #include "packet-lldp.h"
37
38 #define ECP_SUBTYPE     0
39
40 #define VDP_TLV_TYPE    0x02
41
42 /* IEEE 802.1Qbg VDP filter info formats */
43 #define VDP_FIF_VID                             0x01
44 #define VDP_FIF_MACVID                  0x02
45 #define VDP_FIF_GROUPVID                0x03
46 #define VDP_FIF_GROUPVMACVID    0x04
47
48 static gint proto_ecp = -1;
49 static gint hf_ecp_pid = -1;
50 static gint hf_ecp_subtype = -1;
51 static gint hf_ecp_mode = -1;
52 static gint hf_ecp_sequence = -1;
53 static gint hf_ecp_vdp_oui = -1;
54 static gint hf_ecp_vdp_mode = -1;
55 static gint hf_ecp_vdp_response = -1;
56 static gint hf_ecp_vdp_mgrid = -1;
57 static gint hf_ecp_vdp_vsitypeid = -1;
58 static gint hf_ecp_vdp_vsitypeidversion = -1;
59 static gint hf_ecp_vdp_instanceid = -1;
60 static gint hf_ecp_vdp_format = -1;
61 static gint hf_ecp_vdp_mac = -1;
62 static gint hf_ecp_vdp_vlan = -1;
63 static gint ett_802_1qbg_capabilities_flags = -1;
64
65 static gint ett_ecp = -1;
66
67 static const value_string ecp_pid_vals[] = {
68         { 0x0000,       "ECP draft 0" },
69         { 0,            NULL }
70 };
71
72 /* IEEE 802.1Qbg  ECP subtypes */
73 static const value_string ecp_subtypes[] = {
74         { 0x00, "ECP default subtype" },
75         { 0, NULL }
76 };
77
78 /* IEEE 802.1Qbg ECP modes */
79 static const value_string ecp_modes[] = {
80         { 0x00, "REQUEST" },
81         { 0x01, "ACK" },
82         { 0, NULL }
83 };
84
85 /* IEEE 802.1Qbg VDP modes */
86 static const value_string ecp_vdp_modes[] = {
87         { 0x00, "Pre-Associate" },
88         { 0x01, "Pre-Associate with resource reservation" },
89         { 0x02, "Associate" },
90         { 0x03, "De-Associate" },
91         { 0, NULL }
92 };
93
94 /* IEEE 802.1Qbg VDP responses */
95 static const value_string ecp_vdp_responses[] = {
96         { 0x00, "success" },
97         { 0x01, "invalid format" },
98         { 0x02, "insufficient resources" },
99         { 0x03, "unused VTID" },
100         { 0x04, "VTID violation" },
101         { 0x05, "VTID version violation" },
102         { 0x06, "out of sync" },
103         { 0, NULL }
104 };
105
106 /* IEEE 802.1Qbg VDP filter info formats */
107 static const value_string ecp_vdp_formats[] = {
108         { VDP_FIF_VID, "VID values" },
109         { VDP_FIF_MACVID, "MAC/VID pairs" },
110         { VDP_FIF_GROUPVID, "GROUPID/VID pairs" },
111         { VDP_FIF_GROUPVMACVID, "GROUPID/MAC/VID triples" },
112         { 0, NULL }
113 };
114
115 /* Dissect Unknown TLV */
116 static gint32
117 dissect_ecp_unknown_tlv(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, guint32 offset)
118 {
119         guint16 tempLen;
120         guint16 tempShort;
121
122         proto_tree      *ecp_unknown_tlv_tree = NULL;
123         proto_item      *ti = NULL;
124
125         /* Get tlv type and length */
126         tempShort = tvb_get_ntohs(tvb, offset);
127
128         /* Get tlv length */
129         tempLen = TLV_INFO_LEN(tempShort);
130
131         if (tree)
132         {
133             ti = proto_tree_add_text(tree, tvb, offset, (tempLen + 2), "Unknown TLV");
134                 ecp_unknown_tlv_tree = proto_item_add_subtree(ti, ett_ecp);
135         }
136
137         proto_tree_add_item(ecp_unknown_tlv_tree, hf_ecp_subtype, tvb, offset, 2, ENC_BIG_ENDIAN);
138
139         return -1;
140 }
141
142 /* Dissect mac/vid pairs in VDP TLVs */
143 static gint32
144 dissect_vdp_fi_macvid(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, guint32 offset)
145 {
146         gint i;
147         guint16 entries;
148         guint32 tempOffset = offset;
149         const guint8 *mac_addr = NULL;
150
151         proto_tree *ecp_vdp_tlv_fi_subtree = NULL;
152         proto_item *ti = NULL;
153
154         entries = tvb_get_ntohs(tvb, offset);
155
156         if (tree)
157         {
158                 ti = proto_tree_add_text(tree, tvb, tempOffset, 2, "%i MAC/VID pair%s",
159                     entries, plurality((entries > 1), "s", ""));
160                 ecp_vdp_tlv_fi_subtree = proto_item_add_subtree(ti, ett_ecp);
161         }
162
163         tempOffset += 2;
164
165         for (i=0; i < entries; i++) {
166                 mac_addr = tvb_get_ptr(tvb, tempOffset, 6);
167
168                 if (tree) {
169                         proto_tree_add_ether(ecp_vdp_tlv_fi_subtree, hf_ecp_vdp_mac, tvb, tempOffset, 6, mac_addr);
170                 }
171
172                 tempOffset += 6;
173
174                 proto_tree_add_item(ecp_vdp_tlv_fi_subtree, hf_ecp_vdp_vlan, tvb, tempOffset, 2, ENC_BIG_ENDIAN);
175
176                 tempOffset += 2;
177         }
178
179         return tempOffset-offset;
180 }
181
182 /* Dissect VDP TLVs */
183 static gint32
184 dissect_vdp_tlv(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, guint32 offset)
185 {
186         guint16 tempLen;
187         guint16 len;
188         guint16 tempShort;
189         guint32 tempOffset = offset;
190         guint32 oui;
191         const char *ouiStr;
192         guint8 subType, format;
193         const char *subTypeStr;
194
195         proto_tree      *ecp_vdp_tlv_subtree = NULL;
196         proto_item      *ti = NULL;
197
198         tempLen = 0;
199         tempShort = tvb_get_ntohs(tvb, offset);
200         len = TLV_INFO_LEN(tempShort);
201
202         tempOffset += 2;
203
204         oui = tvb_get_ntoh24(tvb, (tempOffset));
205         /* maintain previous OUI names.  If not included, look in manuf database for OUI */
206         ouiStr = val_to_str_const(oui, tlv_oui_subtype_vals, "Unknown");
207         if (strcmp(ouiStr, "Unknown")==0) {
208                 ouiStr = uint_get_manuf_name_if_known(oui);
209                 if(ouiStr==NULL) ouiStr="Unknown";
210         }
211
212         tempOffset += 3;
213
214         subType = tvb_get_guint8(tvb, tempOffset);
215
216         switch(oui) {
217         case OUI_IEEE_802_1QBG:
218                 subTypeStr = val_to_str(subType, ieee_802_1qbg_subtypes, "Unknown subtype 0x%x");
219                 break;
220         default:
221                 subTypeStr = "Unknown";
222                 break;
223         }
224
225         if (tree) {
226                 ti = proto_tree_add_text(tree, tvb, offset, (len + 2), "%s - %s",
227                     ouiStr, subTypeStr);
228                 ecp_vdp_tlv_subtree = proto_item_add_subtree(ti, ett_ecp);
229         }
230
231         tempOffset++;
232
233         proto_tree_add_item(ecp_vdp_tlv_subtree, hf_ecp_vdp_mode, tvb, tempOffset, 1, ENC_BIG_ENDIAN);
234         tempOffset++;
235
236         proto_tree_add_item(ecp_vdp_tlv_subtree, hf_ecp_vdp_response, tvb, tempOffset, 1, ENC_BIG_ENDIAN);
237         tempOffset++;
238
239         proto_tree_add_item(ecp_vdp_tlv_subtree, hf_ecp_vdp_mgrid, tvb, tempOffset, 1, ENC_BIG_ENDIAN);
240         tempOffset++;
241
242         proto_tree_add_item(ecp_vdp_tlv_subtree, hf_ecp_vdp_vsitypeid, tvb, tempOffset, 3, ENC_BIG_ENDIAN);
243         tempOffset += 3;
244
245         proto_tree_add_item(ecp_vdp_tlv_subtree, hf_ecp_vdp_vsitypeidversion, tvb, tempOffset, 1, ENC_BIG_ENDIAN);
246         tempOffset += 1;
247
248         proto_tree_add_item(ecp_vdp_tlv_subtree, hf_ecp_vdp_instanceid, tvb, tempOffset, 16, ENC_NA);
249         tempOffset += 16;
250
251         format = tvb_get_guint8(tvb, tempOffset);
252         proto_tree_add_item(ecp_vdp_tlv_subtree, hf_ecp_vdp_format, tvb, tempOffset, 1, ENC_BIG_ENDIAN);
253         tempOffset++;
254
255         switch (format) {
256         case VDP_FIF_VID:
257                 /* place holder for future enablement */
258                 /* For compatibility of different implementations proceed to next entry */
259         case VDP_FIF_MACVID:
260                 tempLen = dissect_vdp_fi_macvid(tvb, pinfo, ecp_vdp_tlv_subtree, tempOffset);
261                 break;
262         case VDP_FIF_GROUPVID:
263                 /* place holder for future enablement */
264                 break;
265         case VDP_FIF_GROUPVMACVID:
266                 /* place holder for future enablement */
267                 break;
268         default:
269                 break;
270         }
271
272         tempOffset += tempLen;
273
274         return tempOffset-offset;
275 }
276
277 static void
278 dissect_ecp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
279 {
280         proto_tree *ecp_tree = NULL;
281         proto_item *ti = NULL;
282         gint32 tempLen = 0;
283         guint32 offset = 0;
284         guint16 tempShort;
285         guint8 tempType;
286         gboolean end = FALSE;
287
288         col_set_str(pinfo->cinfo, COL_PROTOCOL, "ECP");
289
290         if (tree) {
291             ti = proto_tree_add_item(tree, proto_ecp, tvb, 0, -1, ENC_NA);
292                 ecp_tree = proto_item_add_subtree(ti, ett_ecp);
293         }
294
295         proto_tree_add_item(ecp_tree, hf_ecp_subtype, tvb, offset, 1, ENC_BIG_ENDIAN);
296         proto_tree_add_item(ecp_tree, hf_ecp_mode, tvb, offset+1, 1, ENC_BIG_ENDIAN);
297         proto_tree_add_item(ecp_tree, hf_ecp_sequence, tvb, offset+2, 2, ENC_BIG_ENDIAN);
298
299         offset += 4;
300
301         while (!end) {
302                 if (!tvb_bytes_exist(tvb, offset, 1))
303                         break;
304
305                 tempShort = tvb_get_ntohs(tvb, offset);
306                 tempType = TLV_TYPE(tempShort);
307
308                 switch (tempType) {
309                 case ORGANIZATION_SPECIFIC_TLV_TYPE:
310                         tempLen = dissect_vdp_tlv(tvb, pinfo, ecp_tree, offset);
311                         break;
312                 case END_OF_LLDPDU_TLV_TYPE:
313                         tempLen = dissect_lldp_end_of_lldpdu(tvb, pinfo, ecp_tree, offset);
314                         break;
315                 default:
316                         tempLen = dissect_ecp_unknown_tlv(tvb, pinfo, ecp_tree, offset);
317                         break;
318                 }
319
320                 offset += tempLen;
321
322                 if (tempLen < 0)
323                         end = TRUE;
324         }
325
326 }
327
328 void proto_register_ecp_oui(void)
329 {
330         static hf_register_info hf_reg = {
331                 &hf_ecp_pid,
332                 { "PID", "ieee802a.ecp_pid", FT_UINT16, BASE_HEX,
333                         VALS(ecp_pid_vals), 0x0, NULL, HFILL },
334         };
335
336         static hf_register_info hf[] = {
337                 { &hf_ecp_subtype,
338                         { "subtype", "ecp.subtype", FT_UINT8, BASE_HEX,
339                                 VALS(ecp_subtypes), 0x0, NULL, HFILL },
340                 },
341                 { &hf_ecp_mode,
342                         { "mode", "ecp.mode", FT_UINT8, BASE_HEX,
343                                 VALS(ecp_modes), 0x0, NULL, HFILL },
344                 },
345                 { &hf_ecp_sequence,
346                         { "sequence number", "ecp.seq", FT_UINT16, BASE_HEX,
347                                 NULL, 0x0, NULL, HFILL },
348                 },
349                 { &hf_ecp_vdp_oui,
350                         { "Organization Unique Code",   "ecp.vdp.oui", FT_UINT24, BASE_HEX,
351                         VALS(tlv_oui_subtype_vals), 0x0, NULL, HFILL }
352                 },
353                 { &hf_ecp_vdp_mode,
354                         { "mode", "ecp.vdp.mode", FT_UINT8, BASE_HEX,
355                                 VALS(ecp_vdp_modes), 0x0, NULL, HFILL },
356                 },
357                 { &hf_ecp_vdp_response,
358                         { "response", "ecp.vdp.response", FT_UINT8, BASE_HEX,
359                                 VALS(ecp_vdp_responses), 0x0, NULL, HFILL },
360                 },
361                 { &hf_ecp_vdp_mgrid,
362                         { "Manager ID", "ecp.vdp.mgrid", FT_UINT8, BASE_HEX,
363                                 NULL, 0x0, NULL, HFILL },
364                 },
365                 { &hf_ecp_vdp_vsitypeid,
366                         { "VSI type ID", "ecp.vdp.vsitypeid", FT_UINT24, BASE_HEX,
367                                 NULL, 0x0, NULL, HFILL },
368                 },
369                 { &hf_ecp_vdp_vsitypeidversion,
370                         { "VSI type ID version", "ecp.vdp.vsitypeidversion", FT_UINT8, BASE_HEX,
371                                 NULL, 0x0, NULL, HFILL },
372                 },
373                 { &hf_ecp_vdp_instanceid,
374                         { "VSI Instance ID version", "ecp.vdp.instanceid", FT_BYTES, BASE_NONE,
375                                 NULL, 0x0, NULL, HFILL },
376                 },
377                 { &hf_ecp_vdp_format,
378                         { "VSI filter info format", "ecp.vdp.format", FT_UINT8, BASE_HEX,
379                                 VALS(ecp_vdp_formats), 0x0, NULL, HFILL },
380                 },
381                 { &hf_ecp_vdp_mac,
382                         { "VSI Mac Address", "ecp.vdp.mac", FT_ETHER, BASE_NONE,
383                                 NULL, 0x0, NULL, HFILL }
384                 },
385                 { &hf_ecp_vdp_vlan,
386                         { "VSI VLAN ID", "ecp.vdp.vlan", FT_UINT16, BASE_DEC,
387                                 NULL, 0x0, NULL, HFILL }
388                 },
389         };
390
391         static gint *ett[] = {
392                 &ett_ecp,
393                 &ett_802_1qbg_capabilities_flags,
394         };
395
396         ieee802a_add_oui(OUI_IEEE_802_1QBG, "ieee802a.ecp_pid", "ECP", &hf_reg);
397
398         proto_ecp = proto_register_protocol("ECP Protocol", "ECP", "ecp");
399         proto_register_field_array(proto_ecp, hf, array_length(hf));
400         proto_register_subtree_array(ett, array_length(ett));
401
402         register_dissector("ecp", dissect_ecp, proto_ecp);
403 }
404
405 void proto_reg_handoff_ecp(void)
406 {
407         static dissector_handle_t ecp_handle;
408
409         ecp_handle = find_dissector("ecp");
410         dissector_add_uint("ieee802a.ecp_pid", 0x0000, ecp_handle);
411
412 }