Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-dpaux.c
blobbc805b699dd92826eaf5feb7cba1e1106f8e62e9
1 /* packet-dpaux.c
2 * Routines for DisplayPort AUX-Channel dissection
3 * Copyright 2018, Dirk Eibach, Guntermann & Drunck GmbH <dirk.eibach@gdsys.cc>
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * SPDX-License-Identifier: GPL-2.0-or-later
12 #include <config.h>
13 #include <conversation.h>
15 #include <epan/packet.h>
16 #include <epan/proto_data.h>
18 #include "packet-dpaux.h"
20 void proto_register_dpaux(void);
22 static int proto_dpaux;
24 static int hf_dpaux_transaction_type;
25 static int hf_dpaux_native_req_cmd;
26 static int hf_dpaux_i2c_req_cmd;
27 static int hf_dpaux_reply_cmd;
28 static int hf_dpaux_mot;
29 static int hf_dpaux_addr;
30 static int hf_dpaux_len;
31 static int hf_dpaux_data;
33 static int hf_dpaux_reg_addr;
35 static int hf_00000;
36 static int hf_00000_MINOR;
37 static int hf_00000_MAJOR;
38 static int * const reg00000_fields[] = {
39 &hf_00000_MAJOR,
40 &hf_00000_MINOR,
41 NULL
44 static int hf_00001;
45 static int hf_00001_MAX_LINK_RATE;
46 static int * const reg00001_fields[] = {
47 &hf_00001_MAX_LINK_RATE,
48 NULL
51 static int hf_00002;
52 static int hf_00002_MAX_LANE_COUNT;
53 static int hf_00002_POST_LT_ADJ_REQ_SUPPORTED;
54 static int hf_00002_TPS3_SUPPORTED;
55 static int hf_00002_ENHANCED_FRAME_CAP;
56 static int * const reg00002_fields[] = {
57 &hf_00002_MAX_LANE_COUNT,
58 &hf_00002_POST_LT_ADJ_REQ_SUPPORTED,
59 &hf_00002_TPS3_SUPPORTED,
60 &hf_00002_ENHANCED_FRAME_CAP,
61 NULL
64 static int hf_00003;
65 static int hf_00003_MAX_DOWNSPREAD;
66 static int hf_00003_NO_AUX_TRANSACTION_LINK_TRAINING;
67 static int hf_00003_TPS4_SUPPORTED;
68 static int * const reg00003_fields[] = {
69 &hf_00003_MAX_DOWNSPREAD,
70 &hf_00003_NO_AUX_TRANSACTION_LINK_TRAINING,
71 &hf_00003_TPS4_SUPPORTED,
72 NULL
75 static int hf_00004;
76 static int hf_00004_NORP;
77 static int hf_00004_5V_DP_PWR_CAP;
78 static int hf_00004_12V_DP_PWR_CAP;
79 static int hf_00004_18V_DP_PWR_CAP;
80 static int * const reg00004_fields[] = {
81 &hf_00004_NORP,
82 &hf_00004_5V_DP_PWR_CAP,
83 &hf_00004_12V_DP_PWR_CAP,
84 &hf_00004_18V_DP_PWR_CAP,
85 NULL
88 /* Initialize the subtree pointers */
89 static int ett_dpaux;
90 static int ett_register;
92 struct dpaux_transaction {
93 bool is_native;
94 uint32_t addr;
97 enum {
98 DPAUX_TRANSACTION_NATIVE,
99 DPAUX_TRANSACTION_I2C_OVER_AUX,
100 DPAUX_TRANSACTION_N_A,
103 enum {
104 DPAUX_REPLY_CODE_ACK = 0x0,
105 DPAUX_REPLY_CODE_I2C_ACK = 0x0,
106 DPAUX_REPLY_CODE_NACK = 0x1,
107 DPAUX_REPLY_CODE_DEFER = 0x2,
108 DPAUX_REPLY_CODE_I2C_NACK = 0x4,
109 DPAUX_REPLY_CODE_I2C_DEFER = 0x8,
112 enum {
113 DPAUX_REGISTER_TYPE_BITFIELD,
116 struct bitfield_data {
117 int *hf;
118 int * const *fields;
121 struct dpaux_register {
122 uint32_t addr;
123 uint8_t type;
124 union {
125 struct bitfield_data bitfield;
126 } data;
129 static struct dpaux_register registers[] = {
130 { 0x0, DPAUX_REGISTER_TYPE_BITFIELD, .data.bitfield = { &hf_00000, reg00000_fields } },
131 { 0x1, DPAUX_REGISTER_TYPE_BITFIELD, .data.bitfield = { &hf_00001, reg00001_fields } },
132 { 0x2, DPAUX_REGISTER_TYPE_BITFIELD, .data.bitfield = { &hf_00002, reg00002_fields } },
133 { 0x3, DPAUX_REGISTER_TYPE_BITFIELD, .data.bitfield = { &hf_00003, reg00003_fields } },
134 { 0x4, DPAUX_REGISTER_TYPE_BITFIELD, .data.bitfield = { &hf_00004, reg00004_fields } },
137 static int
138 dissect_dpaux_register(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
139 unsigned int offset, unsigned int register_addr)
141 unsigned int k;
142 struct dpaux_register *reg = NULL;
144 for (k = 0; k < G_N_ELEMENTS(registers); ++k) {
145 if (registers[k].addr == register_addr) {
146 reg = &registers[k];
147 break;
151 if (!reg)
152 return -1;
154 switch (reg->type) {
155 case DPAUX_REGISTER_TYPE_BITFIELD:
156 proto_tree_add_bitmask_with_flags(tree, tvb, offset,
157 *reg->data.bitfield.hf, 0,
158 reg->data.bitfield.fields,
159 ENC_BIG_ENDIAN, BMT_NO_FLAGS);
160 break;
163 return 1;
166 static int
167 dissect_dpaux_from_source(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
169 uint8_t type = tvb_get_bits8(tvb, 0, 1);
170 uint8_t mot = tvb_get_bits8(tvb, 1, 1);
171 uint8_t cmd = tvb_get_bits8(tvb, 2, 2);
172 uint32_t addr = tvb_get_bits32(tvb, 4, 20, ENC_BIG_ENDIAN);
173 uint8_t len = tvb_get_uint8(tvb, 3) + 1;
174 bool is_read = cmd & 0x1;
176 conversation_t *conversation = NULL;
177 struct dpaux_transaction *transaction = NULL;
179 conversation = conversation_new(pinfo->num, &pinfo->src, &pinfo->dst,
180 CONVERSATION_NONE, pinfo->srcport, pinfo->destport, 0);
182 transaction = wmem_new(wmem_file_scope(), struct dpaux_transaction);
183 transaction->is_native = type;
184 transaction->addr = addr;
186 conversation_add_proto_data(conversation, proto_dpaux, (void *)transaction);
188 proto_tree_add_uint(tree, hf_dpaux_transaction_type, tvb, 0, 0,
189 type ? DPAUX_TRANSACTION_NATIVE : DPAUX_TRANSACTION_I2C_OVER_AUX);
191 col_set_str(pinfo->cinfo, COL_PROTOCOL,
192 transaction->is_native ? "Native" : "I2C-over-AUX");
193 col_set_str(pinfo->cinfo, COL_INFO, is_read ? "RD" : "WR");
194 col_append_fstr(pinfo->cinfo, COL_INFO, " %u byte%s %s 0x%05x",
195 len, len > 1 ? "s" : "", is_read ? "FROM" : "TO", addr);
197 if (transaction->is_native) {
198 proto_tree_add_uint(tree, hf_dpaux_native_req_cmd, tvb, 0, 1, cmd);
199 } else {
200 proto_tree_add_uint(tree, hf_dpaux_i2c_req_cmd, tvb, 0, 1, cmd);
201 proto_tree_add_boolean(tree, hf_dpaux_mot, tvb, 0, 1, mot);
203 proto_tree_add_uint(tree, hf_dpaux_addr, tvb, 0, 3, addr);
204 proto_tree_add_uint(tree, hf_dpaux_len, tvb, 3, 1, len);
207 if (!is_read)
208 proto_tree_add_item(tree, hf_dpaux_data, tvb, 4, len, ENC_NA);
210 return 0;
213 static int
214 dissect_dpaux_from_sink(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
216 uint8_t cmd = tvb_get_bits8(tvb, 2, 2);
217 uint8_t len = (tvb_reported_length(tvb) > 1) ? tvb_reported_length(tvb) -1 : 0;
218 conversation_t *conversation = NULL;
219 struct dpaux_transaction *transaction = NULL;
220 proto_item *ti;
222 conversation = find_conversation(pinfo->num, &pinfo->src, &pinfo->dst,
223 CONVERSATION_NONE, pinfo->srcport, pinfo->destport, 0);
224 if (conversation)
225 transaction = (struct dpaux_transaction*)conversation_get_proto_data(
226 conversation, proto_dpaux);
228 if (transaction) {
229 proto_tree_add_uint(tree, hf_dpaux_transaction_type, tvb, 0, 0,
230 transaction->is_native ? DPAUX_TRANSACTION_NATIVE :
231 DPAUX_TRANSACTION_I2C_OVER_AUX);
232 col_set_str(pinfo->cinfo, COL_PROTOCOL,
233 transaction->is_native ? "Native" : "I2C-over-AUX");
234 } else {
235 proto_tree_add_uint(tree, hf_dpaux_transaction_type, tvb, 0, 0, DPAUX_TRANSACTION_N_A);
236 col_set_str(pinfo->cinfo, COL_PROTOCOL, "N/A");
239 switch (cmd) {
240 case DPAUX_REPLY_CODE_ACK:
241 col_set_str(pinfo->cinfo, COL_INFO, "ACK");
242 break;
243 case DPAUX_REPLY_CODE_NACK:
244 case DPAUX_REPLY_CODE_I2C_NACK:
245 col_set_str(pinfo->cinfo, COL_INFO, "NACK");
246 break;
247 case DPAUX_REPLY_CODE_DEFER:
248 case DPAUX_REPLY_CODE_I2C_DEFER:
249 col_set_str(pinfo->cinfo, COL_INFO, "DEFER");
250 break;
253 proto_tree_add_uint(tree, hf_dpaux_reply_cmd, tvb, 0, 1, cmd);
255 if (len) {
256 if (transaction) {
257 col_append_fstr(pinfo->cinfo, COL_INFO, " with %u byte%s FROM 0x%05x",
258 len, len > 1 ? "s" : "", transaction->addr);
259 proto_tree_add_uint(tree, hf_dpaux_addr, tvb, 0, 3, transaction->addr);
260 } else {
261 col_append_fstr(pinfo->cinfo, COL_INFO, " with %u byte%s", len,
262 len > 1 ? "s" : "");
264 proto_tree_add_uint(tree, hf_dpaux_len, tvb, 3, 1, len);
265 proto_tree_add_item(tree, hf_dpaux_data, tvb, 1, len, ENC_NA);
267 if (transaction && transaction->is_native) {
268 unsigned int k;
270 for (k = 0; k < len;) {
271 proto_tree *register_tree;
272 int res;
274 ti = proto_tree_add_uint_format(tree, hf_dpaux_reg_addr,
275 tvb, k + 1, 1,
276 transaction->addr + k,
277 "DPCD 0x%05x: 0x%02x",
278 transaction->addr + k,
279 tvb_get_uint8(tvb, k + 1));
280 register_tree = proto_item_add_subtree(ti, ett_register);
282 res = dissect_dpaux_register(tvb, pinfo, register_tree, k + 1,
283 transaction->addr + k);
285 k += (res > 0) ? res : 1;
290 return 0;
293 static int
294 dissect_dpaux(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
296 proto_item *ti;
297 proto_tree *dpaux_tree;
298 bool from_source = false;
299 struct dpaux_info *dpaux_info = (struct dpaux_info*)data;
301 if (dpaux_info != NULL)
302 from_source = dpaux_info->from_source;
304 col_set_str(pinfo->cinfo, COL_PROTOCOL, "dpaux");
305 col_set_str(pinfo->cinfo, COL_INFO, "DisplayPort AUX channel");
306 col_set_str(pinfo->cinfo, COL_RES_DL_DST, "N/A");
308 if (from_source)
309 col_set_str(pinfo->cinfo, COL_RES_DL_SRC, "DP-Source");
310 else
311 col_set_str(pinfo->cinfo, COL_RES_DL_SRC, "DP-Sink");
313 /* create display subtree for the protocol */
314 ti = proto_tree_add_item(tree, proto_dpaux, tvb, 0, -1, ENC_NA);
315 dpaux_tree = proto_item_add_subtree(ti, ett_dpaux);
317 if (from_source)
318 dissect_dpaux_from_source(tvb, pinfo, dpaux_tree);
319 else
320 dissect_dpaux_from_sink(tvb, pinfo, dpaux_tree);
322 return tvb_captured_length(tvb);
325 /* Register the protocol with Wireshark.
327 * This format is required because a script is used to build the C function that
328 * calls all the protocol registration.
330 void
331 proto_register_dpaux(void)
333 static const value_string convert_transaction_type[] = {
334 { DPAUX_TRANSACTION_NATIVE, "Native" },
335 { DPAUX_TRANSACTION_I2C_OVER_AUX, "I2C-over-AUX" },
336 { DPAUX_TRANSACTION_N_A, "N/A," },
337 { 0, NULL }
340 static const value_string convert_native_req_cmd[] = {
341 { 0, "Write" },
342 { 1, "Read" },
343 { 0, NULL }
346 static const value_string convert_i2c_req_cmd[] = {
347 { 0, "Write" },
348 { 1, "Read" },
349 { 2, "Write_Status_Update_Request" },
350 { 0, NULL }
353 static const value_string convert_reply_cmd[] = {
354 { 0, "AUX ACK" },
355 { 1, "AUX NACK" },
356 { 2, "AUX DEFER" },
357 { 1 << 2, "I2C NACK" },
358 { 2 << 2, "I2C DEFER" },
359 { 0, NULL }
362 static const value_string convert_link_rate[] = {
363 { 0x06, "1.62Gbps/lane" },
364 { 0x0a, "2.7Gbps/lane" },
365 { 0x14, "5.4Gbps/lane" },
366 { 0x1e, "8.1Gbps/lane" },
367 { 0, NULL }
370 static const value_string convert_downspread[] = {
371 { 0x00, "none" },
372 { 0x01, "up to 0.5%" },
373 { 0, NULL }
376 static const value_string convert_norp[] = {
377 { 0x00, "One receiver port" },
378 { 0x01, "Two or more receiver ports" },
379 { 0, NULL }
382 /* Setup protocol subtree array */
383 static int *ett[] = {
384 &ett_dpaux,
385 &ett_register,
388 static hf_register_info hf[] = {
389 { &hf_dpaux_transaction_type, { "Transaction type", "dpaux.transaction_type", FT_UINT8, BASE_DEC, VALS(convert_transaction_type), 0, NULL, HFILL } },
390 { &hf_dpaux_native_req_cmd, { "Native Request Command", "dpaux.native_req_cmd", FT_UINT8, BASE_DEC, VALS(convert_native_req_cmd), 0, NULL, HFILL } },
391 { &hf_dpaux_i2c_req_cmd, { "I2C over AUX Request Command", "dpaux.native_i2c_req_cmd", FT_UINT8, BASE_DEC, VALS(convert_i2c_req_cmd), 0, NULL, HFILL } },
392 { &hf_dpaux_reply_cmd, { "Reply Command", "dpaux.reply_cmd", FT_UINT8, BASE_DEC, VALS(convert_reply_cmd), 0, NULL, HFILL } },
393 { &hf_dpaux_mot, { "MOT (Middle-of-Transaction)", "dpaux.mot", FT_BOOLEAN, BASE_NONE, NULL, 0, NULL, HFILL } },
394 { &hf_dpaux_addr, { "Address", "dpaux.addr", FT_UINT24, BASE_HEX, NULL, 0, NULL, HFILL } },
395 { &hf_dpaux_len, { "Data Length", "dpaux.len", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL } },
396 { &hf_dpaux_data, { "Data", "dpaux.data", FT_BYTES, SEP_SPACE, NULL, 0, NULL, HFILL } },
397 { &hf_dpaux_reg_addr, { "DPCD", "dpaux.reg", FT_UINT24, BASE_HEX, NULL, 0, NULL, HFILL } },
399 { &hf_00000, { "DPCD_REV", "dpaux." "00000", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL } },
400 { &hf_00000_MINOR, { "MINOR", "dpaux." "00000" "_" "MINOR", FT_UINT8, BASE_HEX, NULL, 0x0f, NULL, HFILL } },
401 { &hf_00000_MAJOR, { "MAJOR", "dpaux." "00000" "_" "MAJOR", FT_UINT8, BASE_HEX, NULL, 0xf0, NULL, HFILL } },
403 { &hf_00001, { "MAX_LINK_RATE", "dpaux." "00001", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL } },
404 { &hf_00001_MAX_LINK_RATE, { "MAX_LINK_RATE", "dpaux." "00001" "_" "MAX_LINK_RATE", FT_UINT8, BASE_HEX, VALS(convert_link_rate), 0xff, NULL, HFILL } },
406 { &hf_00002, { "MAX_LANE_COUNT", "dpaux." "00002", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL } },
407 { &hf_00002_MAX_LANE_COUNT, { "MAX_LANE_COUNT", "dpaux." "00002" "_" "MAX_LANE_COUNT", FT_UINT8, BASE_DEC, NULL, 0x0f, NULL, HFILL } },
408 { &hf_00002_POST_LT_ADJ_REQ_SUPPORTED, { "POST_LT_ADJ_REQ_SUPPORTED", "dpaux." "00002" "_" "POST_LT_ADJ_REQ_SUPPORTED", FT_BOOLEAN, 8, NULL, 1<<5, NULL, HFILL } },
409 { &hf_00002_TPS3_SUPPORTED, { "TPS3_SUPPORTED", "dpaux." "00002" "_" "TPS3_SUPPORTED", FT_BOOLEAN, 8, NULL, 1<<6, NULL, HFILL } },
410 { &hf_00002_ENHANCED_FRAME_CAP, { "ENHANCED_FRAME_CAP", "dpaux." "00002" "_" "ENHANCED_FRAME_CAP", FT_BOOLEAN, 8, NULL, 1<<7, NULL, HFILL } },
412 { &hf_00003, { "MAX_DOWNSPREAD", "dpaux." "00003", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL } },
413 { &hf_00003_MAX_DOWNSPREAD, { "MAX_DOWNSPREAD", "dpaux." "00003" "_" "MAX_DOWNSPREAD", FT_UINT8, BASE_DEC, VALS(convert_downspread), 0x01, NULL, HFILL } },
414 { &hf_00003_NO_AUX_TRANSACTION_LINK_TRAINING, { "NO_AUX_TRANSACTION_LINK_TRAINING", "dpaux." "00003" "_" "NO_AUX_TRANSACTION_LINK_TRAINING", FT_BOOLEAN, 8, NULL, 1<<6, NULL, HFILL } },
415 { &hf_00003_TPS4_SUPPORTED, { "TPS4_SUPPORTED", "dpaux." "00003" "_" "TPS4_SUPPORTED", FT_BOOLEAN, 8, NULL, 1<<7, NULL, HFILL } },
417 { &hf_00004, { "NORP & DP_PWR_VOLTAGE_CAP", "dpaux." "00004", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL } },
418 { &hf_00004_NORP, { "NORP", "dpaux." "00004" "_" "NORP", FT_UINT8, BASE_DEC, convert_norp, 0x01, NULL, HFILL } },
419 { &hf_00004_5V_DP_PWR_CAP, { "5V_DP_PWR_CAP", "dpaux." "00004" "_" "5V_DP_PWR_CAP", FT_BOOLEAN, 8, NULL, 1<<5, NULL, HFILL } },
420 { &hf_00004_12V_DP_PWR_CAP, { "12V_DP_PWR_CAP", "dpaux." "00004" "_" "12V_DP_PWR_CAP", FT_BOOLEAN, 8, NULL, 1<<6, NULL, HFILL } },
421 { &hf_00004_18V_DP_PWR_CAP, { "18V_DP_PWR_CAP", "dpaux." "00004" "_" "18V_DP_PWR_CAP", FT_BOOLEAN, 8, NULL, 1<<7, NULL, HFILL } },
424 /* Register the protocol name and description */
425 proto_dpaux = proto_register_protocol("DisplayPort AUX-Channel", "DPAUX", "dpaux");
426 register_dissector("dpaux", dissect_dpaux, proto_dpaux);
428 proto_register_field_array(proto_dpaux, hf, array_length(hf));
429 proto_register_subtree_array(ett, array_length(ett));
434 * Editor modelines - https://www.wireshark.org/tools/modelines.html
436 * Local variables:
437 * c-basic-offset: 4
438 * tab-width: 8
439 * indent-tabs-mode: nil
440 * End:
442 * vi: set shiftwidth=4 tabstop=8 expandtab:
443 * :indentSize=4:tabSize=8:noTabs=true: