- Decode some more annex C fields
[obnox/wireshark/wip.git] / epan / dissectors / packet-ieee802a.c
1 /* packet-ieee802a.c
2  * Routines for IEEE 802a
3  *
4  * $Id$
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@ethereal.com>
8  * Copyright 1998 Gerald Combs
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
23  */
24
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
28
29 #include <glib.h>
30 #include <epan/packet.h>
31 #include <epan/oui.h>
32 #include <epan/etypes.h>
33
34 #include "packet-ieee802a.h"
35
36 static int proto_ieee802a = -1;
37 static int hf_ieee802a_oui = -1;
38 static int hf_ieee802a_pid = -1;
39
40 static gint ett_ieee802a = -1;
41
42 static dissector_handle_t data_handle;
43
44 /*
45  * Hash table for translating OUIs to a dissector table/field info pair;
46  * the dissector table maps PID values to dissectors, and the field
47  * corresponds to the PID for that OUI.
48  */
49 typedef struct {
50         dissector_table_t table;
51         hf_register_info *field_info;
52 } oui_info_t;
53
54 static GHashTable *oui_info_table = NULL;
55
56 /*
57  * Add an entry for a new OUI.
58  */
59 void
60 ieee802a_add_oui(guint32 oui, const char *table_name, char *table_ui_name,
61     hf_register_info *hf_item)
62 {
63         oui_info_t *new_info;
64
65         new_info = g_malloc(sizeof (oui_info_t));
66         new_info->table = register_dissector_table(table_name,
67             table_ui_name, FT_UINT16, BASE_HEX);
68         new_info->field_info = hf_item;
69
70         /*
71          * Create the hash table for OUI information, if it doesn't
72          * already exist.
73          */
74         if (oui_info_table == NULL) {
75                 oui_info_table = g_hash_table_new(g_direct_hash,
76                     g_direct_equal);
77         }
78         g_hash_table_insert(oui_info_table, GUINT_TO_POINTER(oui), new_info);
79 }
80
81 static void
82 dissect_ieee802a(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
83 {
84         proto_tree      *ieee802a_tree = NULL;
85         proto_item      *ti;
86         int             offset = 0;
87         tvbuff_t        *next_tvb;
88         guint32         oui;
89         guint16         etype;
90         oui_info_t      *oui_info;
91         dissector_table_t subdissector_table;
92         int             hf;
93
94         if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
95                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "IEEE802a");
96         }
97         if (check_col(pinfo->cinfo, COL_INFO)) {
98                 col_clear(pinfo->cinfo, COL_INFO);
99         }
100
101         if (tree) {
102                 ti = proto_tree_add_item(tree, proto_ieee802a, tvb, 0, -1, FALSE);
103                 ieee802a_tree = proto_item_add_subtree(ti, ett_ieee802a);
104         } else
105                 ieee802a_tree = NULL;
106
107         oui =   tvb_get_ntoh24(tvb, offset);
108         etype = tvb_get_ntohs(tvb, offset+3);
109
110         if (check_col(pinfo->cinfo, COL_INFO)) {
111                 col_add_fstr(pinfo->cinfo, COL_INFO,
112                     "OUI 0x%06X (%s), PID 0x%04X",
113                     oui, val_to_str(oui, oui_vals, "Unknown"), etype);
114         }
115         if (tree) {
116                 proto_tree_add_uint(ieee802a_tree, hf_ieee802a_oui,
117                     tvb, offset, 3, oui);
118         }
119
120         /*
121          * Do we have information for this OUI?
122          */
123         if (oui_info_table != NULL &&
124             (oui_info = g_hash_table_lookup(oui_info_table,
125               GUINT_TO_POINTER(oui))) != NULL) {
126                 /*
127                  * Yes - use it.
128                  */
129                 hf = *oui_info->field_info->p_id;
130                 subdissector_table = oui_info->table;
131         } else {
132                 /*
133                  * No, use hf_ieee802a_pid for the PID and just dissect
134                  * the payload as data.
135                  */
136                 hf = hf_ieee802a_pid;
137                 subdissector_table = NULL;
138         }
139         if (tree)
140                 proto_tree_add_uint(ieee802a_tree, hf, tvb, offset+3, 2, etype);
141         next_tvb = tvb_new_subset(tvb, offset+5, -1, -1);
142         if (subdissector_table != NULL) {
143                 /* do lookup with the subdissector table */
144                 if (dissector_try_port(subdissector_table, etype, next_tvb,
145                     pinfo, tree))
146                         return;
147         }
148         call_dissector(data_handle, next_tvb, pinfo, tree);
149 }
150
151 void
152 proto_register_ieee802a(void)
153 {
154         static hf_register_info hf[] = {
155                 { &hf_ieee802a_oui,
156                 { "Organization Code",  "ieee802a.oui", FT_UINT24, BASE_HEX,
157                         VALS(oui_vals), 0x0, "", HFILL }},
158
159                 { &hf_ieee802a_pid,
160                 { "Protocol ID", "ieee802a.pid", FT_UINT16, BASE_HEX,
161                         NULL, 0x0, "", HFILL }}
162         };
163         static gint *ett[] = {
164                 &ett_ieee802a,
165         };
166
167         proto_ieee802a = proto_register_protocol("IEEE802a OUI Extended Ethertype", "IEEE802a", "ieee802a");
168         proto_register_field_array(proto_ieee802a, hf, array_length(hf));
169         proto_register_subtree_array(ett, array_length(ett));
170 }
171
172 static void
173 register_hf(gpointer key _U_, gpointer value, gpointer user_data _U_)
174 {
175         oui_info_t *info = value;
176
177         proto_register_field_array(proto_ieee802a, info->field_info, 1);
178 }
179
180 void
181 proto_reg_handoff_ieee802a(void)
182 {
183         dissector_handle_t ieee802a_handle;
184
185         data_handle = find_dissector("data");
186
187         ieee802a_handle = create_dissector_handle(dissect_ieee802a,
188             proto_ieee802a);
189         dissector_add("ethertype", ETHERTYPE_IEEE802_OUI_EXTENDED,
190             ieee802a_handle);
191
192         /*
193          * Register all the fields for PIDs for various OUIs.
194          */
195         if (oui_info_table != NULL)
196                 g_hash_table_foreach(oui_info_table, register_hf, NULL);
197 }