Update minimum version requirement for GTK to 2.12.
[obnox/wireshark/wip.git] / plugins / docsis / packet-tlv-cmctrl.c
1 /* packet-tlv-cmctrl.c
2  * Routines to Dissect TLV's for CM-Control Messages
3  * Copyright 2010, Guido Reismueller <g.reismueller[AT]avm.de>
4  *
5  * $Id$
6  *
7  * Wireshark - Network traffic analyzer
8  * By Gerald Combs <gerald@wireshark.org>
9  * Copyright 1998 Gerald Combs
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #include <epan/packet.h>
31
32 #define CM_CTRL_MUTE 1
33 #define CM_CTRL_MUTE_TIMEOUT 2
34 #define CM_CTRL_REINIT 3
35 #define CM_CTRL_DISABLE_FWD 4
36 #define CM_CTRL_DS_EVENT 5
37 #define CM_CTRL_US_EVENT 6
38 #define CM_CTRL_EVENT 7
39
40 #define DS_EVENT_CH_ID 1
41 #define DS_EVENT_MASK 2
42
43 #define US_EVENT_CH_ID 1
44 #define US_EVENT_MASK 2
45
46 static int proto_cmctrl_tlv = -1;
47 static int hf_cmctrl_tlv_mute = -1;
48 static int hf_cmctrl_tlv_mute_timeout = -1;
49 static int hf_cmctrl_tlv_reinit = -1;
50 static int hf_cmctrl_tlv_disable_fwd = -1;
51 static int hf_cmctrl_tlv_ds_event = -1;
52 static int hf_cmctrl_tlv_us_event = -1;
53 static int hf_cmctrl_tlv_event = -1;
54
55 static int hf_ds_event_ch_id = -1;
56 static int hf_ds_event_mask = -1;
57
58 static int hf_us_event_ch_id = -1;
59 static int hf_us_event_mask = -1;
60
61 static gint ett_cmctrl_tlv = -1;
62 static gint ett_cmctrl_tlv_ds_event = -1;
63 static gint ett_cmctrl_tlv_us_event = -1;
64
65
66 static void
67 dissect_ds_event(tvbuff_t * tvb, proto_tree *tree, int start, guint16 len)
68 {
69   guint8 type, length;
70   proto_item *it;
71   proto_tree *event_tree;
72   int pos = start;
73   it =
74     proto_tree_add_text (tree, tvb, start, len,
75                          "Override Downstream Status Event Event Mask (Length = %u)", len);
76   event_tree = proto_item_add_subtree (it, ett_cmctrl_tlv_ds_event);
77
78   while (pos < (start + len))
79     {
80       type = tvb_get_guint8 (tvb, pos++);
81       length = tvb_get_guint8 (tvb, pos++);
82       switch (type)
83         {
84         case DS_EVENT_CH_ID:
85       if (length == 1)
86         {
87           proto_tree_add_item (event_tree, hf_ds_event_ch_id,
88                                tvb, pos, length, ENC_BIG_ENDIAN);
89         }
90       else
91         {
92           THROW (ReportedBoundsError);
93         }
94           break;
95         case DS_EVENT_MASK:
96       if (length == 2)
97         {
98           proto_tree_add_item (event_tree, hf_ds_event_mask,
99                                tvb, pos, length, ENC_NA);
100         }
101       else
102         {
103           THROW (ReportedBoundsError);
104         }
105           break;
106         }                       /* switch */
107       pos = pos + length;
108     }                           /* while */
109 }
110
111 static void
112 dissect_us_event(tvbuff_t * tvb, proto_tree *tree, int start, guint16 len)
113 {
114   guint8 type, length;
115   proto_item *it;
116   proto_tree *event_tree;
117   int pos = start;
118   it =
119     proto_tree_add_text (tree, tvb, start, len,
120                          "Override Upstream Status Enable Event Mask (Length = %u)", len);
121   event_tree = proto_item_add_subtree (it, ett_cmctrl_tlv_us_event);
122
123   while (pos < (start + len))
124     {
125       type = tvb_get_guint8 (tvb, pos++);
126       length = tvb_get_guint8 (tvb, pos++);
127       switch (type)
128         {
129         case US_EVENT_CH_ID:
130       if (length == 1)
131         {
132           proto_tree_add_item (event_tree, hf_us_event_ch_id,
133                                tvb, pos, length, ENC_BIG_ENDIAN);
134         }
135       else
136         {
137           THROW (ReportedBoundsError);
138         }
139           break;
140         case US_EVENT_MASK:
141       if (length == 2)
142         {
143           proto_tree_add_item (event_tree, hf_us_event_mask,
144                                tvb, pos, length, ENC_NA);
145         }
146       else
147         {
148           THROW (ReportedBoundsError);
149         }
150           break;
151         }                       /* switch */
152       pos = pos + length;
153     }                           /* while */
154 }
155
156 static void
157 dissect_cmctrl_tlv (tvbuff_t * tvb, packet_info * pinfo _U_, proto_tree * tree)
158 {
159
160   proto_item *it;
161   proto_tree *tlv_tree;
162   int pos = 0;
163   gint total_len;
164   guint8 type, length;
165
166   total_len = tvb_reported_length_remaining (tvb, 0);
167
168   it =
169     proto_tree_add_protocol_format (tree, proto_cmctrl_tlv, tvb, 0,
170                                     total_len, "TLV Data");
171   tlv_tree = proto_item_add_subtree (it, ett_cmctrl_tlv);
172
173   while (pos < total_len)
174     {
175       type = tvb_get_guint8 (tvb, pos++);
176       length = tvb_get_guint8 (tvb, pos++);
177       switch (type)
178         {
179         case CM_CTRL_MUTE:
180           if (length == 1)
181             {
182               proto_tree_add_item (tlv_tree, hf_cmctrl_tlv_mute,
183                                    tvb, pos, length, ENC_BIG_ENDIAN);
184             }
185           else
186             {
187               THROW (ReportedBoundsError);
188             }
189           break;
190         case CM_CTRL_MUTE_TIMEOUT:
191           if (length == 4 || length == 1) /* response TLV always with len 1 */
192             {
193               proto_tree_add_item (tlv_tree, hf_cmctrl_tlv_mute_timeout,
194                                    tvb, pos, length, ENC_BIG_ENDIAN);
195             }
196           else
197             {
198               THROW (ReportedBoundsError);
199             }
200           break;
201         case CM_CTRL_REINIT:
202           if (length == 1)
203             {
204               proto_tree_add_item (tlv_tree, hf_cmctrl_tlv_reinit,
205                                    tvb, pos, length, ENC_BIG_ENDIAN);
206             }
207           else
208             {
209               THROW (ReportedBoundsError);
210             }
211           break;
212         case CM_CTRL_DISABLE_FWD:
213           if (length == 1)
214             {
215               proto_tree_add_item (tlv_tree, hf_cmctrl_tlv_disable_fwd,
216                                    tvb, pos, length, ENC_BIG_ENDIAN);
217             }
218           else
219             {
220               THROW (ReportedBoundsError);
221             }
222           break;
223         case CM_CTRL_DS_EVENT:
224           if (length == 1)
225             proto_tree_add_item (tlv_tree, hf_cmctrl_tlv_ds_event,
226                                  tvb, pos, length, ENC_NA);
227           else
228             dissect_ds_event(tvb, tlv_tree, pos, length);
229           break;
230         case CM_CTRL_US_EVENT:
231           if (length == 1)
232             proto_tree_add_item (tlv_tree, hf_cmctrl_tlv_ds_event,
233                                  tvb, pos, length, ENC_NA);
234           else
235             dissect_us_event(tvb, tlv_tree, pos, length);
236           break;
237         case CM_CTRL_EVENT:
238           if (length == 2 || length == 1) /* response TLV always with len 1 */
239             {
240               proto_tree_add_item (tlv_tree, hf_cmctrl_tlv_event,
241                                    tvb, pos, length, ENC_NA);
242             }
243           else
244             {
245               THROW (ReportedBoundsError);
246             }
247           break;
248
249         } /* switch */
250       pos = pos + length;
251     } /* while */
252 }
253
254 /* Register the protocol with Wireshark */
255
256 /* this format is require because a script is used to build the C function
257    that calls all the protocol registration.
258 */
259
260
261 void
262 proto_register_cmctrl_tlv (void)
263 {
264
265 /* Setup list of header fields  See Section 1.6.1 for details*/
266   static hf_register_info hf[] = {
267     {&hf_cmctrl_tlv_mute,
268      {"1 Upstream Channel RF Mute", "cmctrl_tlv.mute",
269       FT_UINT8, BASE_DEC, NULL, 0x0,
270       "Upstream Channel RF Mute", HFILL}
271      },
272     {&hf_cmctrl_tlv_mute_timeout,
273      {"2 RF Mute Timeout Interval", "cmctrl_tlv.mute_timeout",
274       FT_UINT32, BASE_DEC, NULL, 0x0,
275       "RF Mute Timeout Interval", HFILL}
276      },
277     {&hf_cmctrl_tlv_reinit,
278      {"3 CM Reinitialize", "cmctrl_tlv.reinit",
279       FT_UINT8, BASE_DEC, NULL, 0x0,
280       "CM Reinitialize", HFILL}
281      },
282     {&hf_cmctrl_tlv_disable_fwd,
283      {"4 Disable Forwarding", "cmctrl_tlv.disable_fwd",
284       FT_UINT8, BASE_DEC, NULL, 0x0,
285       "Disable Forwarding", HFILL}
286      },
287     {&hf_cmctrl_tlv_ds_event,
288      {"5 Override Downstream Events", "cmctrl_tlv.ds_event",
289       FT_BYTES, BASE_NONE, NULL, 0x0,
290       "Override Downstream Events", HFILL}
291      },
292     {&hf_ds_event_ch_id,
293      {".1 Downstream Channel ID", "cmctrl_tlv.ds_event.chid",
294       FT_UINT8, BASE_DEC, NULL, 0x0,
295       "Downstream Channel ID", HFILL}
296      },
297     {&hf_ds_event_mask,
298      {".2 Downstream Status Event Enable Bitmask", "cmctrl_tlv.ds_event.mask",
299       FT_BYTES, BASE_NONE, NULL, 0x0,
300       "Downstream Status Event Enable Bitmask", HFILL}
301      },
302     {&hf_cmctrl_tlv_us_event,
303      {"6 Override Upstream Events", "cmctrl_tlv.us_event",
304       FT_BYTES, BASE_NONE, NULL, 0x0,
305       "Override Downstream Events", HFILL}
306      },
307     {&hf_us_event_ch_id,
308      {".1 Upstream Channel ID", "cmctrl_tlv.us_event.chid",
309       FT_UINT8, BASE_DEC, NULL, 0x0,
310       "Upstream Channel ID", HFILL}
311      },
312     {&hf_us_event_mask,
313      {".2 Upstream Status Event Enable Bitmask", "cmctrl_tlv.us_event.mask",
314       FT_BYTES, BASE_NONE, NULL, 0x0,
315       "Upstream Status Event Enable Bitmask", HFILL}
316      },
317     {&hf_cmctrl_tlv_event,
318      {"7 Override Non-Channel-Specific Events", "cmctrl_tlv.event",
319       FT_BYTES, BASE_NONE, NULL, 0x0,
320       "Override Non-Channel-Specific Events", HFILL}
321      },
322   };
323
324 /* Setup protocol subtree array */
325   static gint *ett[] = {
326     &ett_cmctrl_tlv,
327     &ett_cmctrl_tlv_ds_event,
328     &ett_cmctrl_tlv_us_event,
329   };
330
331 /* Register the protocol name and description */
332   proto_cmctrl_tlv = proto_register_protocol ("DOCSIS CM-CTRL TLV's",
333                                               "DOCSIS CM-CTRL TLVs", "cmctrl_tlv");
334
335 /* Required function calls to register the header fields and subtrees used */
336   proto_register_field_array (proto_cmctrl_tlv, hf, array_length (hf));
337   proto_register_subtree_array (ett, array_length (ett));
338
339   register_dissector ("cmctrl_tlv", dissect_cmctrl_tlv, proto_cmctrl_tlv);
340 }
341
342 /* If this dissector uses sub-dissector registration add a registration routine.
343    This format is required because a script is used to find these routines and
344    create the code that calls these routines.
345 */
346 void
347 proto_reg_handoff_cmctrl_tlv (void)
348 {
349 #if 0
350   dissector_handle_t cmctrl_tlv_handle;
351
352   cmctrl_tlv_handle = find_dissector ("cmctrl_tlv");
353
354   dissector_add_uint ("docsis", 0xFE, cmctrl_tlv_handle);
355 #endif
356 }