2 * Routines for MAC Control ethernet header disassembly
4 * Wireshark - Network traffic analyzer
5 * By Gerald Combs <gerald@wireshark.org>
6 * Copyright 1998 Gerald Combs
8 * SPDX-License-Identifier: GPL-2.0-or-later
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.
21 #include <epan/packet.h>
22 #include <epan/expert.h>
23 #include <epan/etypes.h>
25 void proto_register_macctrl(void);
26 void proto_reg_handoff_macctrl(void);
28 static int proto_macctrl = -1;
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;
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;
59 static gint ett_macctrl = -1;
60 static gint ett_macctrl_cbfc_enbv = -1;
61 static gint ett_macctrl_cbfc_pause_times = -1;
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;
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,
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
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
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" },
109 static const value_string reg_flags_vals[] = {
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);
121 dissect_macctrl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
123 proto_item *ti, *opcode_item;
124 proto_tree *macctrl_tree = NULL;
125 proto_tree *pause_times_tree = NULL;
131 col_set_str(pinfo->cinfo, COL_PROTOCOL, "MAC CTRL");
132 col_clear(pinfo->cinfo, COL_INFO);
134 opcode = tvb_get_ntohs(tvb, 0);
136 ti = proto_tree_add_item(tree, proto_macctrl, tvb, 0, 46, ENC_NA);
137 macctrl_tree = proto_item_add_subtree(ti, ett_macctrl);
139 opcode_item = proto_tree_add_uint(macctrl_tree, hf_macctrl_opcode, tvb, offset, 2, opcode);
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);
145 col_add_str(pinfo->cinfo, COL_INFO, val_to_str(opcode, opcode_vals, "Unknown"));
150 if (!addresses_equal(&pinfo->dst, &macctrl_dst_address)) {
151 expert_add_info(pinfo, opcode_item, &ei_macctrl_dst_address);
154 pause_time = tvb_get_ntohs(tvb, offset);
155 col_append_fstr(pinfo->cinfo, COL_INFO, ": pause_time: %u quanta",
157 proto_tree_add_uint(macctrl_tree, hf_macctrl_pause_time, tvb, offset, 2,
167 case MACCTRL_REGISTER_REQ:
169 proto_tree_add_item(macctrl_tree, hf_reg_flags, tvb,
170 offset, 1, ENC_BIG_ENDIAN);
174 proto_tree_add_item(macctrl_tree, hf_reg_req_grants, tvb,
175 offset, 1, ENC_BIG_ENDIAN);
178 case MACCTRL_REGISTER:
181 proto_tree_add_item(macctrl_tree, hf_reg_port, tvb,
182 offset, 2, ENC_BIG_ENDIAN);
186 proto_tree_add_item(macctrl_tree, hf_reg_flags, tvb,
187 offset, 1, ENC_BIG_ENDIAN);
191 proto_tree_add_item(macctrl_tree, hf_reg_time, tvb,
192 offset, 2, ENC_BIG_ENDIAN);
195 /* Echoed Pending Grants */
196 proto_tree_add_item(macctrl_tree, hf_reg_grants, tvb,
197 offset, 1, ENC_BIG_ENDIAN);
200 case MACCTRL_REGISTER_ACK:
203 proto_tree_add_item(macctrl_tree, hf_reg_flags, tvb,
204 offset, 1, ENC_BIG_ENDIAN);
207 /* Echoed Assigned Port */
208 proto_tree_add_item(macctrl_tree, hf_reg_ack_port, tvb,
209 offset, 2, ENC_BIG_ENDIAN);
212 /* Echoed Synch Time */
213 proto_tree_add_item(macctrl_tree, hf_reg_ack_time, tvb,
214 offset, 2, ENC_BIG_ENDIAN);
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);
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);
229 pause_times_tree = proto_tree_add_subtree(macctrl_tree, tvb, offset, 8*2, ett_macctrl_cbfc_pause_times, NULL, "CBFC Class Pause Times");
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);
238 expert_add_info(pinfo, opcode_item, &ei_macctrl_opcode);
241 return tvb_captured_length(tvb);
245 proto_register_macctrl(void)
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}},
252 { &hf_macctrl_timestamp,
253 { "Timestamp", "macc.timestamp", FT_UINT32, BASE_DEC,
254 NULL, 0x0, "MAC Control Timestamp", HFILL }},
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 }},
260 { &hf_macctrl_cbfc_enbv,
261 { "CBFC Class Enable Vector", "macc.cbfc.enbv", FT_UINT16, BASE_HEX,
262 NULL, 0x0, NULL, HFILL }},
264 { &hf_macctrl_cbfc_enbv_c0,
265 { "C0", "macc.cbfc.enbv.c0", FT_BOOLEAN, 16,
266 NULL, 0x01, NULL, HFILL }},
268 { &hf_macctrl_cbfc_enbv_c1,
269 { "C1", "macc.cbfc.enbv.c1", FT_BOOLEAN, 16,
270 NULL, 0x02, NULL, HFILL }},
272 { &hf_macctrl_cbfc_enbv_c2,
273 { "C2", "macc.cbfc.enbv.c2", FT_BOOLEAN, 16,
274 NULL, 0x04, NULL, HFILL }},
276 { &hf_macctrl_cbfc_enbv_c3,
277 { "C3", "macc.cbfc.enbv.c3", FT_BOOLEAN, 16,
278 NULL, 0x08, NULL, HFILL }},
280 { &hf_macctrl_cbfc_enbv_c4,
281 { "C4", "macc.cbfc.enbv.c4", FT_BOOLEAN, 16,
282 NULL, 0x10, NULL, HFILL }},
284 { &hf_macctrl_cbfc_enbv_c5,
285 { "C5", "macc.cbfc.enbv.c5", FT_BOOLEAN, 16,
286 NULL, 0x20, NULL, HFILL }},
288 { &hf_macctrl_cbfc_enbv_c6,
289 { "C6", "macc.cbfc.enbv.c6", FT_BOOLEAN, 16,
290 NULL, 0x40, NULL, HFILL }},
292 { &hf_macctrl_cbfc_enbv_c7,
293 { "C7", "macc.cbfc.enbv.c7", FT_BOOLEAN, 16,
294 NULL, 0x80, NULL, HFILL }},
296 { &hf_macctrl_cbfc_pause_time_c0,
297 { "C0", "macc.cbfc.pause_time.c0", FT_UINT16, BASE_DEC,
298 NULL, 0x00, NULL, HFILL }},
300 { &hf_macctrl_cbfc_pause_time_c1,
301 { "C1", "macc.cbfc.pause_time.c1", FT_UINT16, BASE_DEC,
302 NULL, 0x00, NULL, HFILL }},
304 { &hf_macctrl_cbfc_pause_time_c2,
305 { "C2", "macc.cbfc.pause_time.c2", FT_UINT16, BASE_DEC,
306 NULL, 0x00, NULL, HFILL }},
308 { &hf_macctrl_cbfc_pause_time_c3,
309 { "C3", "macc.cbfc.pause_time.c3", FT_UINT16, BASE_DEC,
310 NULL, 0x00, NULL, HFILL }},
312 { &hf_macctrl_cbfc_pause_time_c4,
313 { "C4", "macc.cbfc.pause_time.c4", FT_UINT16, BASE_DEC,
314 NULL, 0x00, NULL, HFILL }},
316 { &hf_macctrl_cbfc_pause_time_c5,
317 { "C5", "macc.cbfc.pause_time.c5", FT_UINT16, BASE_DEC,
318 NULL, 0x00, NULL, HFILL }},
320 { &hf_macctrl_cbfc_pause_time_c6,
321 { "C6", "macc.cbfc.pause_time.c6", FT_UINT16, BASE_DEC,
322 NULL, 0x00, NULL, HFILL }},
324 { &hf_macctrl_cbfc_pause_time_c7,
325 { "C7", "macc.cbfc.pause_time.c7", FT_UINT16, BASE_DEC,
326 NULL, 0x00, NULL, HFILL }},
329 { "Flags", "macc.reg.flags", FT_UINT8, BASE_HEX,
330 VALS(reg_flags_vals), 0x00, NULL, HFILL }},
332 { &hf_reg_req_grants,
333 { "Pending Grants", "macc.regreq.grants", FT_UINT8, BASE_DEC,
334 NULL, 0x00, NULL, HFILL }},
337 { "Echoed Pending Grants", "macc.reg.grants", FT_UINT8, BASE_DEC,
338 NULL, 0x00, NULL, HFILL }},
341 { "Assigned Port (LLID)", "macc.reg.assignedport", FT_UINT16, BASE_DEC,
342 NULL, 0x00, NULL, HFILL }},
345 { "Echoed Assigned Port (LLID)", "macc.regack.assignedport", FT_UINT16, BASE_DEC,
346 NULL, 0x00, NULL, HFILL }},
349 { "Sync Time", "macc.reg.synctime", FT_UINT16, BASE_DEC,
350 NULL, 0x00, NULL, HFILL }},
353 { "Echoed Sync Time", "macc.regack.synctime", FT_UINT16, BASE_DEC,
354 NULL, 0x00, NULL, HFILL }}
357 static gint *ett[] = {
359 &ett_macctrl_cbfc_enbv,
360 &ett_macctrl_cbfc_pause_times
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 }},
369 expert_module_t* expert_macctrl;
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));
379 proto_reg_handoff_macctrl(void)
381 dissector_handle_t macctrl_handle;
383 macctrl_handle = create_dissector_handle(dissect_macctrl, proto_macctrl);
384 dissector_add_uint("ethertype", ETHERTYPE_MAC_CONTROL, macctrl_handle);
393 * indent-tabs-mode: nil
396 * ex: set shiftwidth=2 tabstop=8 expandtab:
397 * :indentSize=2:tabSize=8:noTabs=true: