GSM A DTAP: add UMTS EVS to supported codecs list IE
[metze/wireshark/wip.git] / epan / dissectors / packet-maccontrol.c
1 /* packet-maccontrol.c
2  * Routines for MAC Control ethernet header disassembly
3  *
4  * Wireshark - Network traffic analyzer
5  * By Gerald Combs <gerald@wireshark.org>
6  * Copyright 1998 Gerald Combs
7  *
8  * SPDX-License-Identifier: GPL-2.0-or-later
9  */
10
11 /*
12  * 04/26/2010: WMeier: "Class-Based Flow Control [CBFC] Pause Frame"  dissection added
13  *             See: http://www.ieee802.org/1/files/public/docs2007/new-cm-barrass-pause-proposal.pdf
14  * 2014-04:    David Miller <d.miller[at]cablelabs.com> and
15  *             Philip Rosenberg-Watt <p.rosenberg-watt[at]cablelabs.com>
16  *             + Added MPCP Gate, Report, and Register messages.
17  */
18
19 #include "config.h"
20
21 #include <epan/packet.h>
22 #include <epan/expert.h>
23 #include <epan/etypes.h>
24
25 void proto_register_macctrl(void);
26 void proto_reg_handoff_macctrl(void);
27
28 static int proto_macctrl = -1;
29
30 static int hf_macctrl_opcode       = -1;
31 static int hf_macctrl_timestamp    = -1;
32 static int hf_macctrl_pause_time   = -1;
33 static int hf_macctrl_cbfc_enbv    = -1;
34 static int hf_macctrl_cbfc_enbv_c0 = -1;
35 static int hf_macctrl_cbfc_enbv_c1 = -1;
36 static int hf_macctrl_cbfc_enbv_c2 = -1;
37 static int hf_macctrl_cbfc_enbv_c3 = -1;
38 static int hf_macctrl_cbfc_enbv_c4 = -1;
39 static int hf_macctrl_cbfc_enbv_c5 = -1;
40 static int hf_macctrl_cbfc_enbv_c6 = -1;
41 static int hf_macctrl_cbfc_enbv_c7 = -1;
42 static int hf_macctrl_cbfc_pause_time_c0 = -1;
43 static int hf_macctrl_cbfc_pause_time_c1 = -1;
44 static int hf_macctrl_cbfc_pause_time_c2 = -1;
45 static int hf_macctrl_cbfc_pause_time_c3 = -1;
46 static int hf_macctrl_cbfc_pause_time_c4 = -1;
47 static int hf_macctrl_cbfc_pause_time_c5 = -1;
48 static int hf_macctrl_cbfc_pause_time_c6 = -1;
49 static int hf_macctrl_cbfc_pause_time_c7 = -1;
50
51 static int hf_reg_flags      = -1;
52 static int hf_reg_req_grants = -1;
53 static int hf_reg_grants     = -1;
54 static int hf_reg_port       = -1;
55 static int hf_reg_ack_port   = -1;
56 static int hf_reg_time       = -1;
57 static int hf_reg_ack_time   = -1;
58
59 static gint ett_macctrl            = -1;
60 static gint ett_macctrl_cbfc_enbv  = -1;
61 static gint ett_macctrl_cbfc_pause_times = -1;
62
63 static expert_field ei_macctrl_opcode = EI_INIT;
64 static expert_field ei_macctrl_cbfc_enbv = EI_INIT;
65 static expert_field ei_macctrl_dst_address = EI_INIT;
66
67 static const int *macctrl_cbfc_enbv_list[] = {
68   &hf_macctrl_cbfc_enbv_c0,
69   &hf_macctrl_cbfc_enbv_c1,
70   &hf_macctrl_cbfc_enbv_c2,
71   &hf_macctrl_cbfc_enbv_c3,
72   &hf_macctrl_cbfc_enbv_c4,
73   &hf_macctrl_cbfc_enbv_c5,
74   &hf_macctrl_cbfc_enbv_c6,
75   &hf_macctrl_cbfc_enbv_c7,
76   NULL
77 };
78
79 static const int *macctrl_cbfc_pause_times_list[] = {
80   &hf_macctrl_cbfc_pause_time_c0,
81   &hf_macctrl_cbfc_pause_time_c1,
82   &hf_macctrl_cbfc_pause_time_c2,
83   &hf_macctrl_cbfc_pause_time_c3,
84   &hf_macctrl_cbfc_pause_time_c4,
85   &hf_macctrl_cbfc_pause_time_c5,
86   &hf_macctrl_cbfc_pause_time_c6,
87   &hf_macctrl_cbfc_pause_time_c7
88 };
89
90 #define MACCTRL_PAUSE                        0x0001
91 #define MACCTRL_GATE                         0x0002
92 #define MACCTRL_REPORT                       0x0003
93 #define MACCTRL_REGISTER_REQ                 0x0004
94 #define MACCTRL_REGISTER                     0x0005
95 #define MACCTRL_REGISTER_ACK                 0x0006
96 #define MACCTRL_CLASS_BASED_FLOW_CNTRL_PAUSE 0x0101
97
98 static const value_string opcode_vals[] = {
99   { MACCTRL_PAUSE,                        "Pause" },
100   { MACCTRL_GATE,                         "Gate" },
101   { MACCTRL_REPORT,                       "Report" },
102   { MACCTRL_REGISTER_REQ,                 "Register Req" },
103   { MACCTRL_REGISTER,                     "Register" },
104   { MACCTRL_REGISTER_ACK,                 "Register Ack" },
105   { MACCTRL_CLASS_BASED_FLOW_CNTRL_PAUSE, "Class Based Flow Control [CBFC] Pause" },
106   { 0, NULL }
107 };
108
109 static const value_string reg_flags_vals[] = {
110   { 1, "Register" },
111   { 2, "Deregister" },
112   { 3, "Ack" },
113   { 4, "Nack" },
114   { 0, NULL }
115 };
116
117 static const guint8 dst_addr[] = {0x01, 0x80, 0xC2, 0x00, 0x00, 0x01};
118 static const address macctrl_dst_address = ADDRESS_INIT(AT_ETHER, 6, dst_addr);
119
120 static int
121 dissect_macctrl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
122 {
123   proto_item *ti, *opcode_item;
124   proto_tree *macctrl_tree = NULL;
125   proto_tree *pause_times_tree = NULL;
126   guint16     opcode;
127   guint16     pause_time;
128   int i;
129   gint offset = 0;
130
131   col_set_str(pinfo->cinfo, COL_PROTOCOL, "MAC CTRL");
132   col_clear(pinfo->cinfo, COL_INFO);
133
134   opcode = tvb_get_ntohs(tvb, 0);
135
136   ti = proto_tree_add_item(tree, proto_macctrl, tvb, 0, 46, ENC_NA);
137   macctrl_tree = proto_item_add_subtree(ti, ett_macctrl);
138
139   opcode_item = proto_tree_add_uint(macctrl_tree, hf_macctrl_opcode, tvb, offset, 2, opcode);
140   offset += 2;
141   if ((opcode >= MACCTRL_GATE) && (opcode <= MACCTRL_REGISTER_ACK)) {
142     proto_tree_add_item(macctrl_tree, hf_macctrl_timestamp, tvb, offset, 4, ENC_BIG_ENDIAN);
143     offset += 4;
144   }
145   col_add_str(pinfo->cinfo, COL_INFO, val_to_str(opcode, opcode_vals, "Unknown"));
146
147   switch (opcode) {
148
149     case MACCTRL_PAUSE:
150       if (!addresses_equal(&pinfo->dst, &macctrl_dst_address)) {
151         expert_add_info(pinfo, opcode_item, &ei_macctrl_dst_address);
152       }
153
154       pause_time = tvb_get_ntohs(tvb, offset);
155       col_append_fstr(pinfo->cinfo, COL_INFO, ": pause_time: %u quanta",
156                       pause_time);
157       proto_tree_add_uint(macctrl_tree, hf_macctrl_pause_time, tvb, offset, 2,
158                           pause_time);
159       break;
160
161     case MACCTRL_GATE:
162       break;
163
164     case MACCTRL_REPORT:
165       break;
166
167     case MACCTRL_REGISTER_REQ:
168       /* Flags */
169       proto_tree_add_item(macctrl_tree, hf_reg_flags, tvb,
170                           offset, 1, ENC_BIG_ENDIAN);
171       offset++;
172
173       /* Pending Grants */
174       proto_tree_add_item(macctrl_tree, hf_reg_req_grants, tvb,
175                           offset, 1, ENC_BIG_ENDIAN);
176       break;
177
178     case MACCTRL_REGISTER:
179
180       /* Assigned Port */
181       proto_tree_add_item(macctrl_tree, hf_reg_port, tvb,
182                           offset, 2, ENC_BIG_ENDIAN);
183       offset += 2;
184
185       /* Flags */
186       proto_tree_add_item(macctrl_tree, hf_reg_flags, tvb,
187                           offset, 1, ENC_BIG_ENDIAN);
188       offset++;
189
190       /* Synch Time */
191       proto_tree_add_item(macctrl_tree, hf_reg_time, tvb,
192                           offset, 2, ENC_BIG_ENDIAN);
193       offset += 2;
194
195       /* Echoed Pending Grants */
196       proto_tree_add_item(macctrl_tree, hf_reg_grants, tvb,
197                           offset, 1, ENC_BIG_ENDIAN);
198       break;
199
200     case MACCTRL_REGISTER_ACK:
201
202       /* Flags */
203       proto_tree_add_item(macctrl_tree, hf_reg_flags, tvb,
204                           offset, 1, ENC_BIG_ENDIAN);
205       offset++;
206
207       /* Echoed Assigned Port */
208       proto_tree_add_item(macctrl_tree, hf_reg_ack_port, tvb,
209                           offset, 2, ENC_BIG_ENDIAN);
210       offset += 2;
211
212       /* Echoed Synch Time */
213       proto_tree_add_item(macctrl_tree, hf_reg_ack_time, tvb,
214                           offset, 2, ENC_BIG_ENDIAN);
215       break;
216
217     case MACCTRL_CLASS_BASED_FLOW_CNTRL_PAUSE:
218       if (!addresses_equal(&pinfo->dst, &macctrl_dst_address)) {
219         expert_add_info(pinfo, opcode_item, &ei_macctrl_dst_address);
220       }
221
222       ti = proto_tree_add_bitmask(macctrl_tree, tvb, offset, hf_macctrl_cbfc_enbv,
223                              ett_macctrl_cbfc_enbv, macctrl_cbfc_enbv_list, ENC_BIG_ENDIAN);
224       if (tvb_get_guint8(tvb, offset) != 0) {
225         expert_add_info(pinfo, ti, &ei_macctrl_cbfc_enbv);
226       }
227       offset += 2;
228
229       pause_times_tree = proto_tree_add_subtree(macctrl_tree, tvb, offset, 8*2, ett_macctrl_cbfc_pause_times, NULL, "CBFC Class Pause Times");
230
231       for (i=0; i<8; i++) {
232         proto_tree_add_item(pause_times_tree, *macctrl_cbfc_pause_times_list[i], tvb, offset, 2, ENC_BIG_ENDIAN);
233         offset += 2;
234       }
235       break;
236
237     default:
238       expert_add_info(pinfo, opcode_item, &ei_macctrl_opcode);
239      break;
240   }
241   return tvb_captured_length(tvb);
242 }
243
244 void
245 proto_register_macctrl(void)
246 {
247   static hf_register_info hf[] = {
248     { &hf_macctrl_opcode,
249       { "Opcode", "macc.opcode", FT_UINT16, BASE_HEX,
250         VALS(opcode_vals), 0x0, "MAC Control Opcode", HFILL}},
251
252     { &hf_macctrl_timestamp,
253       { "Timestamp", "macc.timestamp", FT_UINT32, BASE_DEC,
254         NULL, 0x0, "MAC Control Timestamp", HFILL }},
255
256     { &hf_macctrl_pause_time,
257       { "pause_time", "macc.pause_time", FT_UINT16, BASE_DEC,
258         NULL, 0x0, "MAC control PAUSE frame pause_time", HFILL }},
259
260     { &hf_macctrl_cbfc_enbv,
261       { "CBFC Class Enable Vector", "macc.cbfc.enbv", FT_UINT16, BASE_HEX,
262         NULL, 0x0, NULL, HFILL }},
263
264     { &hf_macctrl_cbfc_enbv_c0,
265       { "C0", "macc.cbfc.enbv.c0", FT_BOOLEAN, 16,
266         NULL, 0x01, NULL, HFILL }},
267
268     { &hf_macctrl_cbfc_enbv_c1,
269       { "C1", "macc.cbfc.enbv.c1", FT_BOOLEAN, 16,
270         NULL, 0x02, NULL, HFILL }},
271
272     { &hf_macctrl_cbfc_enbv_c2,
273       { "C2", "macc.cbfc.enbv.c2", FT_BOOLEAN, 16,
274         NULL, 0x04, NULL, HFILL }},
275
276     { &hf_macctrl_cbfc_enbv_c3,
277       { "C3", "macc.cbfc.enbv.c3", FT_BOOLEAN, 16,
278         NULL, 0x08, NULL, HFILL }},
279
280     { &hf_macctrl_cbfc_enbv_c4,
281       { "C4", "macc.cbfc.enbv.c4", FT_BOOLEAN, 16,
282         NULL, 0x10, NULL, HFILL }},
283
284     { &hf_macctrl_cbfc_enbv_c5,
285       { "C5", "macc.cbfc.enbv.c5", FT_BOOLEAN, 16,
286         NULL, 0x20, NULL, HFILL }},
287
288     { &hf_macctrl_cbfc_enbv_c6,
289       { "C6", "macc.cbfc.enbv.c6", FT_BOOLEAN, 16,
290         NULL, 0x40, NULL, HFILL }},
291
292     { &hf_macctrl_cbfc_enbv_c7,
293       { "C7", "macc.cbfc.enbv.c7", FT_BOOLEAN, 16,
294         NULL, 0x80, NULL, HFILL }},
295
296     { &hf_macctrl_cbfc_pause_time_c0,
297       { "C0", "macc.cbfc.pause_time.c0", FT_UINT16, BASE_DEC,
298         NULL, 0x00, NULL, HFILL }},
299
300     { &hf_macctrl_cbfc_pause_time_c1,
301       { "C1", "macc.cbfc.pause_time.c1", FT_UINT16, BASE_DEC,
302         NULL, 0x00, NULL, HFILL }},
303
304     { &hf_macctrl_cbfc_pause_time_c2,
305       { "C2", "macc.cbfc.pause_time.c2", FT_UINT16, BASE_DEC,
306         NULL, 0x00, NULL, HFILL }},
307
308     { &hf_macctrl_cbfc_pause_time_c3,
309       { "C3", "macc.cbfc.pause_time.c3", FT_UINT16, BASE_DEC,
310         NULL, 0x00, NULL, HFILL }},
311
312     { &hf_macctrl_cbfc_pause_time_c4,
313       { "C4", "macc.cbfc.pause_time.c4", FT_UINT16, BASE_DEC,
314         NULL, 0x00, NULL, HFILL }},
315
316     { &hf_macctrl_cbfc_pause_time_c5,
317       { "C5", "macc.cbfc.pause_time.c5", FT_UINT16, BASE_DEC,
318         NULL, 0x00, NULL, HFILL }},
319
320     { &hf_macctrl_cbfc_pause_time_c6,
321       { "C6", "macc.cbfc.pause_time.c6", FT_UINT16, BASE_DEC,
322         NULL, 0x00, NULL, HFILL }},
323
324     { &hf_macctrl_cbfc_pause_time_c7,
325       { "C7", "macc.cbfc.pause_time.c7", FT_UINT16, BASE_DEC,
326         NULL, 0x00, NULL, HFILL }},
327
328     { &hf_reg_flags,
329       { "Flags", "macc.reg.flags", FT_UINT8, BASE_HEX,
330         VALS(reg_flags_vals), 0x00, NULL, HFILL }},
331
332     { &hf_reg_req_grants,
333       { "Pending Grants", "macc.regreq.grants", FT_UINT8, BASE_DEC,
334         NULL, 0x00, NULL, HFILL }},
335
336     { &hf_reg_grants,
337       { "Echoed Pending Grants", "macc.reg.grants", FT_UINT8, BASE_DEC,
338         NULL, 0x00, NULL, HFILL }},
339
340     { &hf_reg_port,
341       { "Assigned Port (LLID)", "macc.reg.assignedport", FT_UINT16, BASE_DEC,
342         NULL, 0x00, NULL, HFILL }},
343
344     { &hf_reg_ack_port,
345       { "Echoed Assigned Port (LLID)", "macc.regack.assignedport", FT_UINT16, BASE_DEC,
346         NULL, 0x00, NULL, HFILL }},
347
348     { &hf_reg_time,
349       { "Sync Time", "macc.reg.synctime", FT_UINT16, BASE_DEC,
350         NULL, 0x00, NULL, HFILL }},
351
352     { &hf_reg_ack_time,
353       { "Echoed Sync Time", "macc.regack.synctime", FT_UINT16, BASE_DEC,
354         NULL, 0x00, NULL, HFILL }}
355   };
356
357   static gint *ett[] = {
358         &ett_macctrl,
359         &ett_macctrl_cbfc_enbv,
360         &ett_macctrl_cbfc_pause_times
361   };
362
363   static ei_register_info ei[] = {
364       { &ei_macctrl_opcode, { "macc.opcode.unknown", PI_PROTOCOL, PI_WARN, "Unknown opcode", EXPFILL }},
365       { &ei_macctrl_cbfc_enbv, { "macc.cbfc.enbv.not_zero", PI_PROTOCOL, PI_WARN, "8 MSbs of ENBV must be 0", EXPFILL }},
366       { &ei_macctrl_dst_address, { "macc.dst_address_invalid", PI_PROTOCOL, PI_WARN, "Destination address must be 01-80-C2-00-00-01", EXPFILL }},
367   };
368
369   expert_module_t* expert_macctrl;
370
371   proto_macctrl = proto_register_protocol("MAC Control", "MACC", "macc");
372   proto_register_field_array(proto_macctrl, hf, array_length(hf));
373   proto_register_subtree_array(ett, array_length(ett));
374   expert_macctrl = expert_register_protocol(proto_macctrl);
375   expert_register_field_array(expert_macctrl, ei, array_length(ei));
376 }
377
378 void
379 proto_reg_handoff_macctrl(void)
380 {
381   dissector_handle_t macctrl_handle;
382
383   macctrl_handle = create_dissector_handle(dissect_macctrl, proto_macctrl);
384   dissector_add_uint("ethertype", ETHERTYPE_MAC_CONTROL, macctrl_handle);
385 }
386
387 /*
388  * Editor modelines
389  *
390  * Local Variables:
391  * c-basic-offset: 2
392  * tab-width: 8
393  * indent-tabs-mode: nil
394  * End:
395  *
396  * ex: set shiftwidth=2 tabstop=8 expandtab:
397  * :indentSize=2:tabSize=8:noTabs=true:
398  */