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 dissector_handle_t macctrl_handle
;
30 static int proto_macctrl
;
32 static int hf_macctrl_opcode
;
33 static int hf_macctrl_timestamp
;
34 static int hf_macctrl_pause_time
;
35 static int hf_macctrl_cbfc_enbv
;
36 static int hf_macctrl_cbfc_enbv_c0
;
37 static int hf_macctrl_cbfc_enbv_c1
;
38 static int hf_macctrl_cbfc_enbv_c2
;
39 static int hf_macctrl_cbfc_enbv_c3
;
40 static int hf_macctrl_cbfc_enbv_c4
;
41 static int hf_macctrl_cbfc_enbv_c5
;
42 static int hf_macctrl_cbfc_enbv_c6
;
43 static int hf_macctrl_cbfc_enbv_c7
;
44 static int hf_macctrl_cbfc_pause_time_c0
;
45 static int hf_macctrl_cbfc_pause_time_c1
;
46 static int hf_macctrl_cbfc_pause_time_c2
;
47 static int hf_macctrl_cbfc_pause_time_c3
;
48 static int hf_macctrl_cbfc_pause_time_c4
;
49 static int hf_macctrl_cbfc_pause_time_c5
;
50 static int hf_macctrl_cbfc_pause_time_c6
;
51 static int hf_macctrl_cbfc_pause_time_c7
;
53 static int hf_reg_flags
;
54 static int hf_reg_req_grants
;
55 static int hf_reg_grants
;
56 static int hf_reg_port
;
57 static int hf_reg_ack_port
;
58 static int hf_reg_time
;
59 static int hf_reg_ack_time
;
61 static int ett_macctrl
;
62 static int ett_macctrl_cbfc_enbv
;
63 static int ett_macctrl_cbfc_pause_times
;
65 static expert_field ei_macctrl_opcode
;
66 static expert_field ei_macctrl_cbfc_enbv
;
67 static expert_field ei_macctrl_dst_address
;
69 static int * const macctrl_cbfc_enbv_list
[] = {
70 &hf_macctrl_cbfc_enbv_c0
,
71 &hf_macctrl_cbfc_enbv_c1
,
72 &hf_macctrl_cbfc_enbv_c2
,
73 &hf_macctrl_cbfc_enbv_c3
,
74 &hf_macctrl_cbfc_enbv_c4
,
75 &hf_macctrl_cbfc_enbv_c5
,
76 &hf_macctrl_cbfc_enbv_c6
,
77 &hf_macctrl_cbfc_enbv_c7
,
81 static int * const macctrl_cbfc_pause_times_list
[] = {
82 &hf_macctrl_cbfc_pause_time_c0
,
83 &hf_macctrl_cbfc_pause_time_c1
,
84 &hf_macctrl_cbfc_pause_time_c2
,
85 &hf_macctrl_cbfc_pause_time_c3
,
86 &hf_macctrl_cbfc_pause_time_c4
,
87 &hf_macctrl_cbfc_pause_time_c5
,
88 &hf_macctrl_cbfc_pause_time_c6
,
89 &hf_macctrl_cbfc_pause_time_c7
92 #define MACCTRL_PAUSE 0x0001
93 #define MACCTRL_GATE 0x0002
94 #define MACCTRL_REPORT 0x0003
95 #define MACCTRL_REGISTER_REQ 0x0004
96 #define MACCTRL_REGISTER 0x0005
97 #define MACCTRL_REGISTER_ACK 0x0006
98 #define MACCTRL_CLASS_BASED_FLOW_CNTRL_PAUSE 0x0101
100 static const value_string opcode_vals
[] = {
101 { MACCTRL_PAUSE
, "Pause" },
102 { MACCTRL_GATE
, "Gate" },
103 { MACCTRL_REPORT
, "Report" },
104 { MACCTRL_REGISTER_REQ
, "Register Req" },
105 { MACCTRL_REGISTER
, "Register" },
106 { MACCTRL_REGISTER_ACK
, "Register Ack" },
107 { MACCTRL_CLASS_BASED_FLOW_CNTRL_PAUSE
, "Class Based Flow Control [CBFC] Pause" },
111 static const value_string reg_flags_vals
[] = {
119 static const uint8_t dst_addr
[] = {0x01, 0x80, 0xC2, 0x00, 0x00, 0x01};
120 static const address macctrl_dst_address
= ADDRESS_INIT(AT_ETHER
, 6, dst_addr
);
123 dissect_macctrl(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
125 proto_item
*ti
, *opcode_item
;
126 proto_tree
*macctrl_tree
= NULL
;
127 proto_tree
*pause_times_tree
= NULL
;
133 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "MAC CTRL");
134 col_clear(pinfo
->cinfo
, COL_INFO
);
136 opcode
= tvb_get_ntohs(tvb
, 0);
138 ti
= proto_tree_add_item(tree
, proto_macctrl
, tvb
, 0, 46, ENC_NA
);
139 macctrl_tree
= proto_item_add_subtree(ti
, ett_macctrl
);
141 opcode_item
= proto_tree_add_uint(macctrl_tree
, hf_macctrl_opcode
, tvb
, offset
, 2, opcode
);
143 if ((opcode
>= MACCTRL_GATE
) && (opcode
<= MACCTRL_REGISTER_ACK
)) {
144 proto_tree_add_item(macctrl_tree
, hf_macctrl_timestamp
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
147 col_set_str(pinfo
->cinfo
, COL_INFO
, val_to_str_const(opcode
, opcode_vals
, "Unknown"));
152 if (!addresses_equal(&pinfo
->dst
, &macctrl_dst_address
)) {
153 expert_add_info(pinfo
, opcode_item
, &ei_macctrl_dst_address
);
156 pause_time
= tvb_get_ntohs(tvb
, offset
);
157 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ": pause_time: %u quanta",
159 proto_tree_add_uint(macctrl_tree
, hf_macctrl_pause_time
, tvb
, offset
, 2,
169 case MACCTRL_REGISTER_REQ
:
171 proto_tree_add_item(macctrl_tree
, hf_reg_flags
, tvb
,
172 offset
, 1, ENC_BIG_ENDIAN
);
176 proto_tree_add_item(macctrl_tree
, hf_reg_req_grants
, tvb
,
177 offset
, 1, ENC_BIG_ENDIAN
);
180 case MACCTRL_REGISTER
:
183 proto_tree_add_item(macctrl_tree
, hf_reg_port
, tvb
,
184 offset
, 2, ENC_BIG_ENDIAN
);
188 proto_tree_add_item(macctrl_tree
, hf_reg_flags
, tvb
,
189 offset
, 1, ENC_BIG_ENDIAN
);
193 proto_tree_add_item(macctrl_tree
, hf_reg_time
, tvb
,
194 offset
, 2, ENC_BIG_ENDIAN
);
197 /* Echoed Pending Grants */
198 proto_tree_add_item(macctrl_tree
, hf_reg_grants
, tvb
,
199 offset
, 1, ENC_BIG_ENDIAN
);
202 case MACCTRL_REGISTER_ACK
:
205 proto_tree_add_item(macctrl_tree
, hf_reg_flags
, tvb
,
206 offset
, 1, ENC_BIG_ENDIAN
);
209 /* Echoed Assigned Port */
210 proto_tree_add_item(macctrl_tree
, hf_reg_ack_port
, tvb
,
211 offset
, 2, ENC_BIG_ENDIAN
);
214 /* Echoed Synch Time */
215 proto_tree_add_item(macctrl_tree
, hf_reg_ack_time
, tvb
,
216 offset
, 2, ENC_BIG_ENDIAN
);
219 case MACCTRL_CLASS_BASED_FLOW_CNTRL_PAUSE
:
220 if (!addresses_equal(&pinfo
->dst
, &macctrl_dst_address
)) {
221 expert_add_info(pinfo
, opcode_item
, &ei_macctrl_dst_address
);
224 ti
= proto_tree_add_bitmask(macctrl_tree
, tvb
, offset
, hf_macctrl_cbfc_enbv
,
225 ett_macctrl_cbfc_enbv
, macctrl_cbfc_enbv_list
, ENC_BIG_ENDIAN
);
226 if (tvb_get_uint8(tvb
, offset
) != 0) {
227 expert_add_info(pinfo
, ti
, &ei_macctrl_cbfc_enbv
);
231 pause_times_tree
= proto_tree_add_subtree(macctrl_tree
, tvb
, offset
, 8*2, ett_macctrl_cbfc_pause_times
, NULL
, "CBFC Class Pause Times");
233 for (i
=0; i
<8; i
++) {
234 proto_tree_add_item(pause_times_tree
, *macctrl_cbfc_pause_times_list
[i
], tvb
, offset
, 2, ENC_BIG_ENDIAN
);
240 expert_add_info(pinfo
, opcode_item
, &ei_macctrl_opcode
);
243 return tvb_captured_length(tvb
);
247 proto_register_macctrl(void)
249 static hf_register_info hf
[] = {
250 { &hf_macctrl_opcode
,
251 { "Opcode", "macc.opcode", FT_UINT16
, BASE_HEX
,
252 VALS(opcode_vals
), 0x0, "MAC Control Opcode", HFILL
}},
254 { &hf_macctrl_timestamp
,
255 { "Timestamp", "macc.timestamp", FT_UINT32
, BASE_DEC
,
256 NULL
, 0x0, "MAC Control Timestamp", HFILL
}},
258 { &hf_macctrl_pause_time
,
259 { "pause_time", "macc.pause_time", FT_UINT16
, BASE_DEC
,
260 NULL
, 0x0, "MAC control PAUSE frame pause_time", HFILL
}},
262 { &hf_macctrl_cbfc_enbv
,
263 { "CBFC Class Enable Vector", "macc.cbfc.enbv", FT_UINT16
, BASE_HEX
,
264 NULL
, 0x0, NULL
, HFILL
}},
266 { &hf_macctrl_cbfc_enbv_c0
,
267 { "C0", "macc.cbfc.enbv.c0", FT_BOOLEAN
, 16,
268 NULL
, 0x0001, NULL
, HFILL
}},
270 { &hf_macctrl_cbfc_enbv_c1
,
271 { "C1", "macc.cbfc.enbv.c1", FT_BOOLEAN
, 16,
272 NULL
, 0x0002, NULL
, HFILL
}},
274 { &hf_macctrl_cbfc_enbv_c2
,
275 { "C2", "macc.cbfc.enbv.c2", FT_BOOLEAN
, 16,
276 NULL
, 0x0004, NULL
, HFILL
}},
278 { &hf_macctrl_cbfc_enbv_c3
,
279 { "C3", "macc.cbfc.enbv.c3", FT_BOOLEAN
, 16,
280 NULL
, 0x0008, NULL
, HFILL
}},
282 { &hf_macctrl_cbfc_enbv_c4
,
283 { "C4", "macc.cbfc.enbv.c4", FT_BOOLEAN
, 16,
284 NULL
, 0x0010, NULL
, HFILL
}},
286 { &hf_macctrl_cbfc_enbv_c5
,
287 { "C5", "macc.cbfc.enbv.c5", FT_BOOLEAN
, 16,
288 NULL
, 0x0020, NULL
, HFILL
}},
290 { &hf_macctrl_cbfc_enbv_c6
,
291 { "C6", "macc.cbfc.enbv.c6", FT_BOOLEAN
, 16,
292 NULL
, 0x0040, NULL
, HFILL
}},
294 { &hf_macctrl_cbfc_enbv_c7
,
295 { "C7", "macc.cbfc.enbv.c7", FT_BOOLEAN
, 16,
296 NULL
, 0x0080, NULL
, HFILL
}},
298 { &hf_macctrl_cbfc_pause_time_c0
,
299 { "C0", "macc.cbfc.pause_time.c0", FT_UINT16
, BASE_DEC
,
300 NULL
, 0x0, NULL
, HFILL
}},
302 { &hf_macctrl_cbfc_pause_time_c1
,
303 { "C1", "macc.cbfc.pause_time.c1", FT_UINT16
, BASE_DEC
,
304 NULL
, 0x0, NULL
, HFILL
}},
306 { &hf_macctrl_cbfc_pause_time_c2
,
307 { "C2", "macc.cbfc.pause_time.c2", FT_UINT16
, BASE_DEC
,
308 NULL
, 0x0, NULL
, HFILL
}},
310 { &hf_macctrl_cbfc_pause_time_c3
,
311 { "C3", "macc.cbfc.pause_time.c3", FT_UINT16
, BASE_DEC
,
312 NULL
, 0x0, NULL
, HFILL
}},
314 { &hf_macctrl_cbfc_pause_time_c4
,
315 { "C4", "macc.cbfc.pause_time.c4", FT_UINT16
, BASE_DEC
,
316 NULL
, 0x0, NULL
, HFILL
}},
318 { &hf_macctrl_cbfc_pause_time_c5
,
319 { "C5", "macc.cbfc.pause_time.c5", FT_UINT16
, BASE_DEC
,
320 NULL
, 0x0, NULL
, HFILL
}},
322 { &hf_macctrl_cbfc_pause_time_c6
,
323 { "C6", "macc.cbfc.pause_time.c6", FT_UINT16
, BASE_DEC
,
324 NULL
, 0x0, NULL
, HFILL
}},
326 { &hf_macctrl_cbfc_pause_time_c7
,
327 { "C7", "macc.cbfc.pause_time.c7", FT_UINT16
, BASE_DEC
,
328 NULL
, 0x0, NULL
, HFILL
}},
331 { "Flags", "macc.reg.flags", FT_UINT8
, BASE_HEX
,
332 VALS(reg_flags_vals
), 0x0, NULL
, HFILL
}},
334 { &hf_reg_req_grants
,
335 { "Pending Grants", "macc.regreq.grants", FT_UINT8
, BASE_DEC
,
336 NULL
, 0x0, NULL
, HFILL
}},
339 { "Echoed Pending Grants", "macc.reg.grants", FT_UINT8
, BASE_DEC
,
340 NULL
, 0x0, NULL
, HFILL
}},
343 { "Assigned Port (LLID)", "macc.reg.assignedport", FT_UINT16
, BASE_DEC
,
344 NULL
, 0x0, NULL
, HFILL
}},
347 { "Echoed Assigned Port (LLID)", "macc.regack.assignedport", FT_UINT16
, BASE_DEC
,
348 NULL
, 0x0, NULL
, HFILL
}},
351 { "Sync Time", "macc.reg.synctime", FT_UINT16
, BASE_DEC
,
352 NULL
, 0x0, NULL
, HFILL
}},
355 { "Echoed Sync Time", "macc.regack.synctime", FT_UINT16
, BASE_DEC
,
356 NULL
, 0x0, NULL
, HFILL
}}
359 static int *ett
[] = {
361 &ett_macctrl_cbfc_enbv
,
362 &ett_macctrl_cbfc_pause_times
365 static ei_register_info ei
[] = {
366 { &ei_macctrl_opcode
, { "macc.opcode.unknown", PI_PROTOCOL
, PI_WARN
, "Unknown opcode", EXPFILL
}},
367 { &ei_macctrl_cbfc_enbv
, { "macc.cbfc.enbv.not_zero", PI_PROTOCOL
, PI_WARN
, "8 MSbs of ENBV must be 0", EXPFILL
}},
368 { &ei_macctrl_dst_address
, { "macc.dst_address_invalid", PI_PROTOCOL
, PI_WARN
, "Destination address must be 01-80-C2-00-00-01", EXPFILL
}},
371 expert_module_t
* expert_macctrl
;
373 proto_macctrl
= proto_register_protocol("MAC Control", "MACC", "macc");
374 proto_register_field_array(proto_macctrl
, hf
, array_length(hf
));
375 proto_register_subtree_array(ett
, array_length(ett
));
376 expert_macctrl
= expert_register_protocol(proto_macctrl
);
377 expert_register_field_array(expert_macctrl
, ei
, array_length(ei
));
379 macctrl_handle
= register_dissector("macc", dissect_macctrl
, proto_macctrl
);
383 proto_reg_handoff_macctrl(void)
385 dissector_add_uint("ethertype", ETHERTYPE_MAC_CONTROL
, macctrl_handle
);
394 * indent-tabs-mode: nil
397 * ex: set shiftwidth=2 tabstop=8 expandtab:
398 * :indentSize=2:tabSize=8:noTabs=true: