aboutsummaryrefslogtreecommitdiffstats
path: root/epan
diff options
context:
space:
mode:
authorDirk Eibach <dirk.eibach@gdsys.cc>2018-05-03 16:07:44 +0200
committerGuy Harris <guy@alum.mit.edu>2018-05-10 20:27:36 +0000
commitbfd51199e707c1d5c28732be34b44a9ee8a91cd8 (patch)
tree9cf90368c05a3ce58b92b4b8391dbd98f9c2eda9 /epan
parent68ec514b5f63e09a1628df321c0e5240edd54edc (diff)
DisplayPort AUX channel protocol dissector
Dissector for the VESA DisplayPort AUX channel protocol. Bug: 14651 Change-Id: I5c0c7668bda969086d9d6e5069aad87e929f6340 Reviewed-on: https://code.wireshark.org/review/27311 Reviewed-by: Dario Lombardo <lomato@gmail.com> Petri-Dish: Dario Lombardo <lomato@gmail.com> Tested-by: Petri Dish Buildbot Reviewed-by: Guy Harris <guy@alum.mit.edu>
Diffstat (limited to 'epan')
-rw-r--r--epan/dissectors/CMakeLists.txt2
-rw-r--r--epan/dissectors/packet-dpaux.c459
-rw-r--r--epan/dissectors/packet-dpaux.h20
-rw-r--r--epan/dissectors/packet-dpauxmon.c207
4 files changed, 688 insertions, 0 deletions
diff --git a/epan/dissectors/CMakeLists.txt b/epan/dissectors/CMakeLists.txt
index 5a4fa25fce..6448a216d1 100644
--- a/epan/dissectors/CMakeLists.txt
+++ b/epan/dissectors/CMakeLists.txt
@@ -896,6 +896,8 @@ set(DISSECTOR_SRC
${CMAKE_CURRENT_SOURCE_DIR}/packet-docsis-tlv.c
${CMAKE_CURRENT_SOURCE_DIR}/packet-docsis-vendor.c
${CMAKE_CURRENT_SOURCE_DIR}/packet-dof.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/packet-dpaux.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/packet-dpauxmon.c
${CMAKE_CURRENT_SOURCE_DIR}/packet-dplay.c
${CMAKE_CURRENT_SOURCE_DIR}/packet-dpnet.c
${CMAKE_CURRENT_SOURCE_DIR}/packet-dpnss-link.c
diff --git a/epan/dissectors/packet-dpaux.c b/epan/dissectors/packet-dpaux.c
new file mode 100644
index 0000000000..232727e279
--- /dev/null
+++ b/epan/dissectors/packet-dpaux.c
@@ -0,0 +1,459 @@
+/* packet-dpaux.c
+ * Routines for DisplayPort AUX-Channel dissection
+ * Copyright 2018, Dirk Eibach, Guntermann & Drunck GmbH <dirk.eibach@gdsys.cc>
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+* SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include <config.h>
+#include <conversation.h>
+
+#include <epan/packet.h>
+#include <epan/proto_data.h>
+
+#include "packet-dpaux.h"
+
+/* Prototypes */
+/* (Required to prevent [-Wmissing-prototypes] warnings */
+void proto_reg_handoff_dpaux(void);
+void proto_register_dpaux(void);
+
+/* Initialize the protocol and registered fields */
+int proto_dpaux = -1;
+
+static int hf_dpaux_transaction_type = -1;
+static int hf_dpaux_native_req_cmd = -1;
+static int hf_dpaux_i2c_req_cmd = -1;
+static int hf_dpaux_reply_cmd = -1;
+static int hf_dpaux_mot = -1;
+static int hf_dpaux_addr = -1;
+static int hf_dpaux_len = -1;
+static int hf_dpaux_data = -1;
+
+static int hf_dpaux_reg_addr = -1;
+
+static int hf_00000 = -1;
+static int hf_00000_MINOR = -1;
+static int hf_00000_MAJOR = -1;
+static const int *reg00000_fields[] = {
+ &hf_00000_MINOR,
+ &hf_00000_MAJOR,
+ NULL
+};
+
+static int hf_00001 = -1;
+static int hf_00001_MAX_LINK_RATE = -1;
+static const int *reg00001_fields[] = {
+ &hf_00001_MAX_LINK_RATE,
+ NULL
+};
+
+static int hf_00002 = -1;
+static int hf_00002_MAX_LANE_COUNT = -1;
+static int hf_00002_POST_LT_ADJ_REQ_SUPPORTED = -1;
+static int hf_00002_TPS3_SUPPORTED = -1;
+static int hf_00002_ENHANCED_FRAME_CAP = -1;
+static const int *reg00002_fields[] = {
+ &hf_00002_MAX_LANE_COUNT,
+ &hf_00002_POST_LT_ADJ_REQ_SUPPORTED,
+ &hf_00002_TPS3_SUPPORTED,
+ &hf_00002_ENHANCED_FRAME_CAP,
+ NULL
+};
+
+static int hf_00003 = -1;
+static int hf_00003_MAX_DOWNSPREAD = -1;
+static int hf_00003_NO_AUX_TRANSACTION_LINK_TRAINING = -1;
+static int hf_00003_TPS4_SUPPORTED = -1;
+static const int *reg00003_fields[] = {
+ &hf_00003_MAX_DOWNSPREAD,
+ &hf_00003_NO_AUX_TRANSACTION_LINK_TRAINING,
+ &hf_00003_TPS4_SUPPORTED,
+ NULL
+};
+
+static int hf_00004 = -1;
+static int hf_00004_NORP = -1;
+static int hf_00004_5V_DP_PWR_CAP = -1;
+static int hf_00004_12V_DP_PWR_CAP = -1;
+static int hf_00004_18V_DP_PWR_CAP = -1;
+static const int *reg00004_fields[] = {
+ &hf_00004_NORP,
+ &hf_00004_5V_DP_PWR_CAP,
+ &hf_00004_12V_DP_PWR_CAP,
+ &hf_00004_18V_DP_PWR_CAP,
+ NULL
+};
+
+/* Initialize the subtree pointers */
+static gint ett_dpaux = -1;
+static gint ett_register = -1;
+
+struct dpaux_transaction {
+ gboolean is_native;
+ guint32 addr;
+};
+
+enum {
+ DPAUX_TRANSACTION_NATIVE,
+ DPAUX_TRANSACTION_I2C_OVER_AUX,
+ DPAUX_TRANSACTION_N_A,
+};
+
+enum {
+ DPAUX_REPLY_CODE_ACK = 0x0,
+ DPAUX_REPLY_CODE_I2C_ACK = 0x0,
+ DPAUX_REPLY_CODE_NACK = 0x1,
+ DPAUX_REPLY_CODE_DEFER = 0x2,
+ DPAUX_REPLY_CODE_I2C_NACK = 0x4,
+ DPAUX_REPLY_CODE_I2C_DEFER = 0x8,
+};
+
+enum {
+ DPAUX_REGISTER_TYPE_BITFIELD,
+};
+
+struct bitfield_data {
+ int *hf;
+ const int **fields;
+};
+
+struct dpaux_register {
+ guint32 addr;
+ guint8 type;
+ union {
+ struct bitfield_data bitfield;
+ } data;
+};
+
+struct dpaux_register registers[] = {
+ { 0x0, DPAUX_REGISTER_TYPE_BITFIELD, .data.bitfield = { &hf_00000, reg00000_fields } },
+ { 0x1, DPAUX_REGISTER_TYPE_BITFIELD, .data.bitfield = { &hf_00001, reg00001_fields } },
+ { 0x2, DPAUX_REGISTER_TYPE_BITFIELD, .data.bitfield = { &hf_00002, reg00002_fields } },
+ { 0x3, DPAUX_REGISTER_TYPE_BITFIELD, .data.bitfield = { &hf_00003, reg00003_fields } },
+ { 0x4, DPAUX_REGISTER_TYPE_BITFIELD, .data.bitfield = { &hf_00004, reg00004_fields } },
+};
+
+static int
+dissect_dpaux_register(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ unsigned int offset, unsigned int register_addr)
+{
+ unsigned int k;
+ struct dpaux_register *reg = NULL;
+
+ if (!pinfo) { }
+
+ for (k = 0; k < G_N_ELEMENTS(registers); ++k) {
+ if (registers[k].addr == register_addr) {
+ reg = &registers[k];
+ break;
+ }
+ }
+
+ if (!reg)
+ return -1;
+
+ switch (reg->type) {
+ case DPAUX_REGISTER_TYPE_BITFIELD:
+ proto_tree_add_bitmask_with_flags(tree, tvb, offset,
+ *reg->data.bitfield.hf, 0,
+ reg->data.bitfield.fields,
+ ENC_BIG_ENDIAN, BMT_NO_FLAGS);
+ break;
+ }
+
+ return 1;
+}
+
+static int
+dissect_dpaux_from_source(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ guint8 type = tvb_get_bits8(tvb, 0, 1);
+ guint8 mot = tvb_get_bits8(tvb, 1, 1);
+ guint8 cmd = tvb_get_bits8(tvb, 2, 2);
+ guint32 addr = tvb_get_bits32(tvb, 4, 20, ENC_BIG_ENDIAN);
+ guint8 len = tvb_get_guint8(tvb, 3) + 1;
+ gboolean is_read = cmd & 0x1;
+
+ conversation_t *conversation = NULL;
+ struct dpaux_transaction *transaction = NULL;
+
+ conversation = conversation_new(pinfo->num, &pinfo->src, &pinfo->dst,
+ ENDPOINT_NONE, pinfo->srcport, pinfo->destport, 0);
+
+ transaction = (struct dpaux_transaction*)wmem_alloc(wmem_file_scope(),
+ sizeof(struct dpaux_transaction));
+ transaction->is_native = type;
+ transaction->addr = addr;
+
+ conversation_add_proto_data(conversation, proto_dpaux, (void *)transaction);
+
+ proto_tree_add_uint(tree, hf_dpaux_transaction_type, tvb, 0, 0,
+ type ? DPAUX_TRANSACTION_NATIVE : DPAUX_TRANSACTION_I2C_OVER_AUX);
+
+ col_set_str(pinfo->cinfo, COL_PROTOCOL,
+ transaction->is_native ? "Native" : "I2C-over-AUX");
+ col_set_str(pinfo->cinfo, COL_INFO, is_read ? "RD" : "WR");
+ col_append_fstr(pinfo->cinfo, COL_INFO, " %u byte%s %s 0x%05x",
+ len, len > 1 ? "s" : "", is_read ? "FROM" : "TO", addr);
+
+ if (transaction->is_native) {
+ proto_tree_add_uint(tree, hf_dpaux_native_req_cmd, tvb, 0, 1, cmd);
+ } else {
+ proto_tree_add_uint(tree, hf_dpaux_i2c_req_cmd, tvb, 0, 1, cmd);
+ proto_tree_add_boolean(tree, hf_dpaux_mot, tvb, 0, 1, mot);
+ }
+ proto_tree_add_uint(tree, hf_dpaux_addr, tvb, 0, 3, addr);
+ proto_tree_add_uint(tree, hf_dpaux_len, tvb, 3, 1, len);
+
+
+ if (!is_read)
+ proto_tree_add_bytes(tree, hf_dpaux_data, tvb, 4, len,
+ (guint8*)tvb_memdup(wmem_file_scope(), tvb, 4, len));
+
+ return 0;
+}
+
+static int
+dissect_dpaux_from_sink(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ guint8 cmd = tvb_get_bits8(tvb, 2, 2);
+ guint8 len = (tvb_reported_length(tvb) > 1) ? tvb_reported_length(tvb) -1 : 0;
+ conversation_t *conversation = NULL;
+ struct dpaux_transaction *transaction = NULL;
+ proto_item *ti;
+
+ conversation = find_conversation(pinfo->num, &pinfo->src, &pinfo->dst,
+ ENDPOINT_NONE, pinfo->srcport, pinfo->destport, 0);
+ if (conversation)
+ transaction = (struct dpaux_transaction*)conversation_get_proto_data(
+ conversation, proto_dpaux);
+
+ if (transaction) {
+ proto_tree_add_uint(tree, hf_dpaux_transaction_type, tvb, 0, 0,
+ transaction->is_native ? DPAUX_TRANSACTION_NATIVE :
+ DPAUX_TRANSACTION_I2C_OVER_AUX);
+ col_set_str(pinfo->cinfo, COL_PROTOCOL,
+ transaction->is_native ? "Native" : "I2C-over-AUX");
+ } else {
+ proto_tree_add_uint(tree, hf_dpaux_transaction_type, tvb, 0, 0, DPAUX_TRANSACTION_N_A);
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "N/A");
+ }
+
+ switch (cmd) {
+ case DPAUX_REPLY_CODE_ACK:
+ col_set_str(pinfo->cinfo, COL_INFO, "ACK");
+ break;
+ case DPAUX_REPLY_CODE_NACK:
+ case DPAUX_REPLY_CODE_I2C_NACK:
+ col_set_str(pinfo->cinfo, COL_INFO, "NACK");
+ break;
+ case DPAUX_REPLY_CODE_DEFER:
+ case DPAUX_REPLY_CODE_I2C_DEFER:
+ col_set_str(pinfo->cinfo, COL_INFO, "DEFER");
+ break;
+ };
+
+ proto_tree_add_uint(tree, hf_dpaux_reply_cmd, tvb, 0, 1, cmd);
+
+ if (len) {
+ if (transaction) {
+ col_append_fstr(pinfo->cinfo, COL_INFO, " with %u byte%s FROM 0x%05x",
+ len, len > 1 ? "s" : "", transaction->addr);
+ proto_tree_add_uint(tree, hf_dpaux_addr, tvb, 0, 3, transaction->addr);
+ } else {
+ col_append_fstr(pinfo->cinfo, COL_INFO, " with %u byte%s", len,
+ len > 1 ? "s" : "");
+ }
+ proto_tree_add_uint(tree, hf_dpaux_len, tvb, 3, 1, len);
+ proto_tree_add_bytes(tree, hf_dpaux_data, tvb, 1, len,
+ (guint8*)tvb_memdup(wmem_file_scope(), tvb, 1, len));
+
+ if (transaction && transaction->is_native) {
+ unsigned int k;
+
+ for (k = 0; k < len;) {
+ proto_tree *register_tree;
+ int res;
+
+ ti = proto_tree_add_uint_format(tree, hf_dpaux_reg_addr,
+ tvb, k + 1, 1,
+ transaction->addr + k,
+ "DPCD 0x%05x: 0x%02x",
+ transaction->addr + k,
+ tvb_get_guint8(tvb, k + 1));
+ register_tree = proto_item_add_subtree(ti, ett_register);
+
+ res = dissect_dpaux_register(tvb, pinfo, register_tree, k + 1,
+ transaction->addr + k);
+
+ k += (res > 0) ? res : 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int
+dissect_dpaux(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ void *data _U_)
+{
+ /* Set up structures needed to add the protocol subtree and manage it */
+ proto_item *ti;
+ proto_tree *dpaux_tree;
+
+ struct dpaux_info *dpaux_info = (struct dpaux_info*)p_get_proto_data(
+ wmem_file_scope(), pinfo, proto_dpaux, 0);
+
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "dpaux");
+ col_set_str(pinfo->cinfo, COL_INFO, "DisplayPort AUX channel");
+ col_set_str(pinfo->cinfo, COL_RES_DL_DST, "N/A");
+
+ if (dpaux_info->from_source)
+ col_set_str(pinfo->cinfo, COL_RES_DL_SRC, "DP-Source");
+ else
+ col_set_str(pinfo->cinfo, COL_RES_DL_SRC, "DP-Sink");
+
+ /* create display subtree for the protocol */
+ ti = proto_tree_add_item(tree, proto_dpaux, tvb, 0, -1, ENC_NA);
+
+ dpaux_tree = proto_item_add_subtree(ti, ett_dpaux);
+
+ if (dpaux_info->from_source)
+ dissect_dpaux_from_source(tvb, pinfo, dpaux_tree);
+ else
+ dissect_dpaux_from_sink(tvb, pinfo, dpaux_tree);
+
+ return tvb_captured_length(tvb);
+}
+
+/* Register the protocol with Wireshark.
+ *
+ * This format is require because a script is used to build the C function that
+ * calls all the protocol registration.
+ */
+void
+proto_register_dpaux(void)
+{
+ static const value_string convert_transaction_type[] = {
+ { DPAUX_TRANSACTION_NATIVE, "Native" },
+ { DPAUX_TRANSACTION_I2C_OVER_AUX, "I2C-over-AUX" },
+ { DPAUX_TRANSACTION_N_A, "N/A," },
+ { 0, NULL }
+ };
+
+ static const value_string convert_native_req_cmd[] = {
+ { 0, "Write" },
+ { 1, "Read" },
+ { 0, NULL }
+ };
+
+ static const value_string convert_i2c_req_cmd[] = {
+ { 0, "Write" },
+ { 1, "Read" },
+ { 2, "Write_Status_Update_Request" },
+ { 0, NULL }
+ };
+
+ static const value_string convert_reply_cmd[] = {
+ { 0, "AUX ACK" },
+ { 1, "AUX NACK" },
+ { 2, "AUX DEFER" },
+ { 1 << 2, "I2C NACK" },
+ { 2 << 2, "I2C DEFER" },
+ { 0, NULL }
+ };
+
+ static const value_string convert_link_rate[] = {
+ { 0x06, "1.62Gbps/lane" },
+ { 0x0a, "2.7Gbps/lane" },
+ { 0x14, "5.4Gbps/lane" },
+ { 0x1e, "8.1Gbps/lane" },
+ { 0, NULL }
+ };
+
+ static const value_string convert_downspread[] = {
+ { 0x00, "none" },
+ { 0x01, "up to 0.5%" },
+ { 0, NULL }
+ };
+
+ static const value_string convert_norp[] = {
+ { 0x00, "One receiver port" },
+ { 0x01, "Two or more receiver ports" },
+ { 0, NULL }
+ };
+
+ /* Setup protocol subtree array */
+ static gint *ett[] = {
+ &ett_dpaux,
+ &ett_register,
+ };
+
+ static hf_register_info hf[] = {
+ { &hf_dpaux_transaction_type, { "Transaction type", "dpaux.transaction_type", FT_UINT8, BASE_DEC, VALS(convert_transaction_type), 0, NULL, HFILL } },
+ { &hf_dpaux_native_req_cmd, { "Native Request Command", "dpaux.native_req_cmd", FT_UINT8, BASE_DEC, VALS(convert_native_req_cmd), 0, NULL, HFILL } },
+ { &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 } },
+ { &hf_dpaux_reply_cmd, { "Reply Command", "dpaux.reply_cmd", FT_UINT8, BASE_DEC, VALS(convert_reply_cmd), 0, NULL, HFILL } },
+ { &hf_dpaux_mot, { "MOT (Middle-of-Transaction)", "dpaux.mot", FT_BOOLEAN, BASE_NONE, NULL, 0, NULL, HFILL } },
+ { &hf_dpaux_addr, { "Address", "dpaux.addr", FT_UINT24, BASE_HEX, NULL, 0, NULL, HFILL } },
+ { &hf_dpaux_len, { "Data Length", "dpaux.len", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL } },
+ { &hf_dpaux_data, { "Data", "dpaux.data", FT_BYTES, SEP_SPACE, NULL, 0, NULL, HFILL } },
+ { &hf_dpaux_reg_addr, { "DPCD", "dpaux.reg", FT_UINT24, BASE_HEX, NULL, 0, NULL, HFILL } },
+
+ { &hf_00000, { "DPCD_REV", "dpaux." "00000", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL } },
+ { &hf_00000_MINOR, { "MINOR", "dpaux." "00000" "_" "MINOR", FT_UINT8, BASE_HEX, NULL, 0x0f, NULL, HFILL } },
+ { &hf_00000_MAJOR, { "MAJOR", "dpaux." "00000" "_" "MAJOR", FT_UINT8, BASE_HEX, NULL, 0x0f, NULL, HFILL } },
+
+ { &hf_00001, { "MAX_LINK_RATE", "dpaux." "00001", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL } },
+ { &hf_00001_MAX_LINK_RATE, { "MAX_LINK_RATE", "dpaux." "00001" "_" "MAX_LINK_RATE", FT_UINT8, BASE_HEX, VALS(convert_link_rate), 0xff, NULL, HFILL } },
+
+ { &hf_00002, { "MAX_LANE_COUNT", "dpaux." "00002", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL } },
+ { &hf_00002_MAX_LANE_COUNT, { "MAX_LANE_COUNT", "dpaux." "00002" "_" "MAX_LANE_COUNT", FT_UINT8, BASE_DEC, NULL, 0x0f, NULL, HFILL } },
+ { &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 } },
+ { &hf_00002_TPS3_SUPPORTED, { "TPS3_SUPPORTED", "dpaux." "00002" "_" "TPS3_SUPPORTED", FT_BOOLEAN, 8, NULL, 1<<6, NULL, HFILL } },
+ { &hf_00002_ENHANCED_FRAME_CAP, { "ENHANCED_FRAME_CAP", "dpaux." "00002" "_" "ENHANCED_FRAME_CAP", FT_BOOLEAN, 8, NULL, 1<<7, NULL, HFILL } },
+
+ { &hf_00003, { "MAX_DOWNSPREAD", "dpaux." "00003", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL } },
+ { &hf_00003_MAX_DOWNSPREAD, { "MAX_DOWNSPREAD", "dpaux." "00003" "_" "MAX_DOWNSPREAD", FT_UINT8, BASE_DEC, VALS(convert_downspread), 0x01, NULL, HFILL } },
+ { &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 } },
+ { &hf_00003_TPS4_SUPPORTED, { "TPS4_SUPPORTED", "dpaux." "00003" "_" "TPS4_SUPPORTED", FT_BOOLEAN, 8, NULL, 1<<7, NULL, HFILL } },
+
+ { &hf_00004, { "NORP & DP_PWR_VOLTAGE_CAP", "dpaux." "00004", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL } },
+ { &hf_00004_NORP, { "NORP", "dpaux." "00004" "_" "NORP", FT_UINT8, BASE_DEC, convert_norp, 0x01, NULL, HFILL } },
+ { &hf_00004_5V_DP_PWR_CAP, { "5V_DP_PWR_CAP", "dpaux." "00004" "_" "5V_DP_PWR_CAP", FT_BOOLEAN, 8, NULL, 1<<5, NULL, HFILL } },
+ { &hf_00004_12V_DP_PWR_CAP, { "12V_DP_PWR_CAP", "dpaux." "00004" "_" "12V_DP_PWR_CAP", FT_BOOLEAN, 8, NULL, 1<<6, NULL, HFILL } },
+ { &hf_00004_18V_DP_PWR_CAP, { "18V_DP_PWR_CAP", "dpaux." "00004" "_" "18V_DP_PWR_CAP", FT_BOOLEAN, 8, NULL, 1<<7, NULL, HFILL } },
+ };
+
+ /* Register the protocol name and description */
+ proto_dpaux = proto_register_protocol("DisplayPort AUX-Channel",
+ "DPAUX", "dpaux");
+ register_dissector("dpaux", dissect_dpaux, proto_dpaux);
+
+ proto_register_field_array(proto_dpaux, hf, array_length(hf));
+ proto_register_subtree_array(ett, array_length(ett));
+}
+
+void
+proto_reg_handoff_dpaux(void)
+{
+}
+
+/*
+ * Editor modelines - https://www.wireshark.org/tools/modelines.html
+ *
+ * Local variables:
+ * c-basic-offset: 4
+ * tab-width: 8
+ * indent-tabs-mode: nil
+ * End:
+ *
+ * vi: set shiftwidth=4 tabstop=8 expandtab:
+ * :indentSize=4:tabSize=8:noTabs=true:
+ */
diff --git a/epan/dissectors/packet-dpaux.h b/epan/dissectors/packet-dpaux.h
new file mode 100644
index 0000000000..e0ab61be03
--- /dev/null
+++ b/epan/dissectors/packet-dpaux.h
@@ -0,0 +1,20 @@
+/* packet-dpaux.h
+ * Definitions for packet disassembly structures and routines
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef PACKET_DPAUX_H
+#define PACKET_DPAUX_H
+
+extern int proto_dpaux;
+
+struct dpaux_info {
+ gboolean from_source;
+};
+
+#endif
diff --git a/epan/dissectors/packet-dpauxmon.c b/epan/dissectors/packet-dpauxmon.c
new file mode 100644
index 0000000000..13bba1daa0
--- /dev/null
+++ b/epan/dissectors/packet-dpauxmon.c
@@ -0,0 +1,207 @@
+/* packet-dpauxmon.c
+ * Routines for DisplayPort AUX-Channel monitor dissection
+ * Copyright 2018, Dirk Eibach, Guntermann & Drunck GmbH <dirk.eibach@gdsys.cc>
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include <config.h>
+#include <conversation.h>
+
+#include "packet-dpaux.h"
+
+#include <epan/packet.h>
+#include <epan/proto_data.h>
+
+enum {
+ DPAUXMON_DATA = 0x00,
+ DPAUXMON_DATA_END = 0x01,
+ DPAUXMON_EVENT = 0x02,
+ DPAUXMON_START = 0x03,
+ DPAUXMON_STOP = 0x04,
+ DPAUXMON_TS_OVERFLOW = 0x84,
+};
+
+void proto_reg_handoff_dpauxmon(void);
+void proto_register_dpauxmon(void);
+
+static dissector_handle_t dpaux_handle;
+
+/* Initialize the protocol and registered fields */
+static int proto_dpauxmon = -1;
+
+static int hf_packet_type = -1;
+static int hf_origin = -1;
+static int hf_inputs = -1;
+static int hf_hpd = -1;
+static int hf_in0 = -1;
+static int hf_in1 = -1;
+static int hf_in2 = -1;
+
+static const int *input_fields[] = {
+ &hf_hpd,
+ &hf_in0,
+ &hf_in1,
+ &hf_in2,
+ NULL
+};
+
+/* Initialize the subtree pointers */
+static gint ett_dpauxmon = -1;
+
+static int
+dissect_dpauxmon(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ void *data _U_)
+{
+ proto_item *ti;
+ proto_tree *dpauxmon_tree;
+ guint8 packet_type = tvb_get_guint8(tvb, 0);
+
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "dpauxmon");
+ col_set_str(pinfo->cinfo, COL_INFO, "DisplayPort AUX channel");
+ col_set_str(pinfo->cinfo, COL_RES_DL_DST, "N/A");
+ col_set_str(pinfo->cinfo, COL_RES_DL_SRC, "Internal");
+
+ /* create display subtree for the protocol */
+ ti = proto_tree_add_item(tree, proto_dpauxmon, tvb, 0, -1, ENC_NA);
+
+ dpauxmon_tree = proto_item_add_subtree(ti, ett_dpauxmon);
+
+ proto_tree_add_uint(dpauxmon_tree, hf_packet_type, tvb, 0, 1, packet_type);
+
+ switch (packet_type) {
+ case DPAUXMON_DATA: {
+ struct dpaux_info *dpaux_info = (struct dpaux_info*)
+ wmem_alloc(wmem_file_scope(), sizeof(struct dpaux_info));
+
+ dpaux_info->from_source = tvb_get_guint8(tvb, 1);
+ p_add_proto_data(wmem_file_scope(), pinfo, proto_dpaux, 0, dpaux_info);
+ proto_tree_add_uint(dpauxmon_tree, hf_origin, tvb, 1, 1,
+ dpaux_info->from_source);
+
+ call_dissector(dpaux_handle, tvb_new_subset_remaining(tvb, 2),
+ pinfo, dpauxmon_tree);
+ break;
+ }
+ case DPAUXMON_EVENT:
+ case DPAUXMON_START:
+ col_set_str(pinfo->cinfo, COL_INFO,
+ (packet_type == DPAUXMON_START) ? "Start" : "Input changed");
+ proto_tree_add_bitmask(dpauxmon_tree, tvb, 1, hf_inputs, 0, input_fields,
+ ENC_BIG_ENDIAN);
+ break;
+ case DPAUXMON_STOP:
+ col_set_str(pinfo->cinfo, COL_INFO, "Stop");
+ break;
+ case DPAUXMON_TS_OVERFLOW:
+ col_set_str(pinfo->cinfo, COL_INFO, "Timestamp overflow");
+ break;
+ };
+
+ return tvb_captured_length(tvb);
+}
+
+void
+proto_register_dpauxmon(void)
+{
+ static const value_string convert_packet_type[] = {
+ { DPAUXMON_DATA, "Data" },
+ { DPAUXMON_EVENT, "Event" },
+ { DPAUXMON_START, "Start" },
+ { DPAUXMON_STOP, "Stop" },
+ { DPAUXMON_TS_OVERFLOW, "Timestamp Overflow" },
+ { 0, NULL }
+ };
+
+ static const value_string convert_origin[] = {
+ { 0, "Sink" },
+ { 1, "Source" },
+ { 0, NULL }
+ };
+
+ /* Setup protocol subtree array */
+ static gint *ett[] = {
+ &ett_dpauxmon
+ };
+
+ /* Setup list of header fields See Section 1.5 of README.dissector for
+ * details. */
+ static hf_register_info hf[] = {
+ { &hf_packet_type,
+ { "Packet Type", "dpauxmon.packet_type",
+ FT_UINT8, BASE_DEC, VALS(convert_packet_type), 0,
+ NULL, HFILL }
+ },
+ { &hf_origin,
+ { "Origin", "dpauxmon.origin",
+ FT_UINT8, BASE_DEC, VALS(convert_origin), 0,
+ NULL, HFILL }
+ },
+ { &hf_inputs,
+ { "Inputs", "dpauxmon.inputs",
+ FT_UINT8, BASE_HEX, NULL, 0,
+ NULL, HFILL }
+ },
+ { &hf_hpd,
+ { "Hotplug Detect", "dpauxmon.hpd",
+ FT_BOOLEAN, 4, NULL, 0x01,
+ NULL, HFILL }
+ },
+ { &hf_in0,
+ { "IN0", "dpauxmon.in0",
+ FT_BOOLEAN, 4, NULL, 0x02,
+ NULL, HFILL }
+ },
+ { &hf_in1,
+ { "IN1", "dpauxmon.in1",
+ FT_BOOLEAN, 4, NULL, 0x04,
+ NULL, HFILL }
+ },
+ { &hf_in2,
+ { "IN2", "dpauxmon.in2",
+ FT_BOOLEAN, 4, NULL, 0x08,
+ NULL, HFILL }
+ },
+ };
+
+ /* Register the protocol name and description */
+ proto_dpauxmon = proto_register_protocol("DPAUXMON DisplayPort AUX channel monitor",
+ "DPAUXMON", "dpauxmon");
+ proto_register_field_array(proto_dpauxmon, hf, array_length(hf));
+ proto_register_subtree_array(ett, array_length(ett));
+}
+
+void
+proto_reg_handoff_dpauxmon(void)
+{
+ static gboolean initialized = FALSE;
+ static dissector_handle_t dpauxmon_handle;
+
+ dpaux_handle = find_dissector_add_dependency("dpaux", proto_dpauxmon);
+
+ if (!initialized) {
+ dpauxmon_handle = create_dissector_handle(dissect_dpauxmon, proto_dpauxmon);
+ initialized = TRUE;
+ } else {
+ dissector_delete_uint("wtap_encap", WTAP_ENCAP_DPAUXMON, dpauxmon_handle);
+ }
+
+ dissector_add_uint("wtap_encap", WTAP_ENCAP_DPAUXMON, dpauxmon_handle);
+}
+
+/*
+ * Editor modelines - https://www.wireshark.org/tools/modelines.html
+ *
+ * Local variables:
+ * c-basic-offset: 4
+ * tab-width: 8
+ * indent-tabs-mode: nil
+ * End:
+ *
+ * vi: set shiftwidth=4 tabstop=8 expandtab:
+ * :indentSize=4:tabSize=8:noTabs=true:
+ */