2 * Routines for HDMI dissection
3 * Copyright 2014 Martin Kaiser <martin@kaiser.cx>
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 /* this dissector handles I2C messages on the HDMI Display Data Channel (DDC)
14 * EDID (Extended Display Identification Data) messages are dissected here,
15 * HDCP messages are passed on to the HDCP dissector
20 #include <epan/packet.h>
22 void proto_register_hdmi(void);
23 void proto_reg_handoff_hdmi(void);
25 static int proto_hdmi
;
27 static dissector_handle_t hdmi_handle
;
28 static dissector_handle_t hdcp_handle
;
31 static int ett_hdmi_edid
;
33 static int hf_hdmi_addr
;
34 static int hf_hdmi_edid_offset
;
35 static int hf_hdmi_edid_hdr
;
36 static int hf_hdmi_edid_manf_id
;
37 static int hf_hdmi_edid_manf_prod_code
;
38 static int hf_hdmi_edid_manf_serial
;
39 static int hf_hdmi_edid_manf_week
;
40 static int hf_hdmi_edid_mod_year
;
41 static int hf_hdmi_edid_manf_year
;
42 static int hf_hdmi_edid_version
;
45 /* also called Source and Sink in the HDMI spec */
46 #define ADDR_TRX "Transmitter"
47 #define ADDR_RCV "Receiver"
49 /* we use 8bit I2C addresses, including the direction bit */
50 #define ADDR8_HDCP_WRITE 0x74 /* transmitter->receiver */
51 #define ADDR8_HDCP_READ 0x75 /* r->t */
52 #define ADDR8_EDID_WRITE 0xA0 /* t->r */
53 #define ADDR8_EDID_READ 0xA1 /* r->t */
55 #define HDCP_ADDR8(x) (x == ADDR8_HDCP_WRITE || x == ADDR8_HDCP_READ)
57 static const value_string hdmi_addr
[] = {
58 { ADDR8_HDCP_WRITE
, "transmitter writes HDCP data for receiver" },
59 { ADDR8_HDCP_READ
, "transmitter reads HDCP data from receiver" },
61 { ADDR8_EDID_WRITE
, "EDID request" },
62 { ADDR8_EDID_READ
, "EDID read" },
66 #define EDID_HDR_VALUE UINT64_C(0x00ffffffffffff00)
68 /* grab 5 bits, from bit n to n+4, from a big-endian number x
69 map those bits to a capital letter such that A == 1, B == 2, ... */
70 #define CAPITAL_LETTER(x, n) ('A'-1 + (((x) & (0x1F<<n)) >> n))
73 /* dissect EDID data from the receiver
74 return the offset after the dissected data */
76 dissect_hdmi_edid(tvbuff_t
*tvb
, int offset
, packet_info
*pinfo
, proto_tree
*tree
)
79 proto_tree
*edid_tree
;
82 char manf_id_str
[4]; /* 3 letters + 0-termination */
86 edid_tree
= proto_tree_add_subtree(tree
, tvb
,
87 offset
, -1, ett_hdmi_edid
, NULL
,
88 "Extended Display Identification Data (EDID)");
90 edid_hdr
= tvb_get_ntoh64(tvb
, offset
);
91 if (edid_hdr
!= EDID_HDR_VALUE
)
92 return offset
; /* XXX handle fragmented EDID messages */
94 col_append_sep_str(pinfo
->cinfo
, COL_INFO
, NULL
, "EDID");
96 proto_tree_add_item(edid_tree
, hf_hdmi_edid_hdr
,
97 tvb
, offset
, 8, ENC_LITTLE_ENDIAN
);
100 /* read as big endian for easier splitting */
101 manf_id
= tvb_get_ntohs(tvb
, offset
);
102 /* XXX check that MSB is 0 */
103 manf_id_str
[0] = CAPITAL_LETTER(manf_id
, 10);
104 manf_id_str
[1] = CAPITAL_LETTER(manf_id
, 5);
105 manf_id_str
[2] = CAPITAL_LETTER(manf_id
, 0);
107 proto_tree_add_string(edid_tree
, hf_hdmi_edid_manf_id
,
108 tvb
, offset
, 2, manf_id_str
);
111 proto_tree_add_item(edid_tree
, hf_hdmi_edid_manf_prod_code
,
112 tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
115 proto_tree_add_item(edid_tree
, hf_hdmi_edid_manf_serial
,
116 tvb
, offset
, 4, ENC_LITTLE_ENDIAN
);
119 week
= tvb_get_uint8(tvb
, offset
);
120 proto_tree_add_item(edid_tree
, hf_hdmi_edid_manf_week
,
121 tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
124 year_hf
= week
== 255 ? hf_hdmi_edid_mod_year
: hf_hdmi_edid_manf_year
;
125 year
= tvb_get_uint8(tvb
, offset
);
126 yi
= proto_tree_add_item(edid_tree
, year_hf
,
127 tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
128 proto_item_append_text(yi
, " (year %d)", 1990+year
);
131 proto_tree_add_item(edid_tree
, hf_hdmi_edid_version
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
133 /* XXX dissect the parts following the EDID header */
135 return tvb_reported_length(tvb
);
140 dissect_hdmi(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
145 proto_tree
*hdmi_tree
;
147 /* the I2C address in the first byte is always handled by the HDMI
148 dissector, even if the packet contains HDCP data */
149 addr
= tvb_get_uint8(tvb
, 0);
150 if (!try_val_to_str(addr
, hdmi_addr
))
151 return 0; /* no HDMI packet */
153 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "HDMI");
154 col_clear(pinfo
->cinfo
, COL_INFO
);
156 pi
= proto_tree_add_item(tree
, proto_hdmi
, tvb
, 0, -1, ENC_NA
);
157 hdmi_tree
= proto_item_add_subtree(pi
, ett_hdmi
);
160 set_address(&pinfo
->src
, AT_STRINGZ
, (int)strlen(ADDR_RCV
)+1, ADDR_RCV
);
161 set_address(&pinfo
->dst
, AT_STRINGZ
, (int)strlen(ADDR_TRX
)+1, ADDR_TRX
);
162 pinfo
->p2p_dir
= P2P_DIR_RECV
;
165 set_address(&pinfo
->src
, AT_STRINGZ
, (int)strlen(ADDR_TRX
)+1, ADDR_TRX
);
166 set_address(&pinfo
->dst
, AT_STRINGZ
, (int)strlen(ADDR_RCV
)+1, ADDR_RCV
);
167 pinfo
->p2p_dir
= P2P_DIR_SENT
;
170 /* there's no explicit statement in the spec saying that the protocol is
172 there's three cases: one byte values, symmetrical values or values
173 that are explicitly marked as little endian
174 for the sake of simplicity, we use little endian everywhere */
175 proto_tree_add_item(hdmi_tree
, hf_hdmi_addr
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
178 if (HDCP_ADDR8(addr
)) {
181 hdcp_tvb
= tvb_new_subset_remaining(tvb
, offset
);
183 return call_dissector(hdcp_handle
, hdcp_tvb
, pinfo
, hdmi_tree
);
186 if (addr
== ADDR8_EDID_WRITE
) {
187 col_append_sep_str(pinfo
->cinfo
, COL_INFO
, NULL
, "EDID request");
188 proto_tree_add_item(hdmi_tree
, hf_hdmi_edid_offset
,
189 tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
194 return dissect_hdmi_edid(tvb
, offset
, pinfo
, hdmi_tree
);
198 hdmi_fmt_edid_version( char *result
, uint32_t revision
)
200 snprintf( result
, ITEM_LABEL_LENGTH
, "%d.%02d", (uint8_t)(( revision
& 0xFF00 ) >> 8), (uint8_t)(revision
& 0xFF) );
204 proto_register_hdmi(void)
206 static hf_register_info hf
[] = {
208 { "8bit I2C address", "hdmi.addr", FT_UINT8
, BASE_HEX
,
209 VALS(hdmi_addr
), 0, NULL
, HFILL
} },
210 { &hf_hdmi_edid_offset
,
211 { "Offset", "hdmi.edid.offset",
212 FT_UINT8
, BASE_HEX
, NULL
, 0, NULL
, HFILL
} },
214 { "EDID header", "hdmi.edid.hdr",
215 FT_UINT64
, BASE_HEX
, NULL
, 0, NULL
, HFILL
} },
216 { &hf_hdmi_edid_manf_id
,
217 { "Manufacturer ID", "hdmi.edid.manf_id",
218 FT_STRING
, BASE_NONE
, NULL
, 0, NULL
, HFILL
} },
219 { &hf_hdmi_edid_manf_prod_code
,
220 { "Manufacturer product code", "hdmi.edid.manf_prod_code",
221 FT_UINT16
, BASE_HEX
, NULL
, 0, NULL
, HFILL
} },
222 { &hf_hdmi_edid_manf_serial
,
223 { "Serial number", "hdmi.edid.serial_num",
224 FT_UINT32
, BASE_DEC
, NULL
, 0, NULL
, HFILL
} },
225 { &hf_hdmi_edid_manf_week
,
226 { "Week of manufacture", "hdmi.edid.manf_week",
227 FT_UINT8
, BASE_DEC
, NULL
, 0, NULL
, HFILL
} },
228 { &hf_hdmi_edid_mod_year
,
229 { "Model year", "hdmi.edid.model_year",
230 FT_UINT8
, BASE_DEC
, NULL
, 0, NULL
, HFILL
} },
231 { &hf_hdmi_edid_manf_year
,
232 { "Year of manufacture", "hdmi.edid.manf_year",
233 FT_UINT8
, BASE_DEC
, NULL
, 0, NULL
, HFILL
} },
234 { &hf_hdmi_edid_version
,
235 { "EDID Version", "hdmi.edid.version",
236 FT_UINT16
, BASE_CUSTOM
, CF_FUNC(hdmi_fmt_edid_version
), 0, NULL
, HFILL
} }
240 static int *ett
[] = {
245 proto_hdmi
= proto_register_protocol("High-Definition Multimedia Interface", "HDMI", "hdmi");
246 hdmi_handle
= register_dissector("hdmi", dissect_hdmi
, proto_hdmi
);
248 proto_register_field_array(proto_hdmi
, hf
, array_length(hf
));
249 proto_register_subtree_array(ett
, array_length(ett
));
254 proto_reg_handoff_hdmi(void)
256 hdcp_handle
= find_dissector_add_dependency("hdcp", proto_hdmi
);
257 dissector_add_for_decode_as("i2c.message", hdmi_handle
);
261 * Editor modelines - https://www.wireshark.org/tools/modelines.html
266 * indent-tabs-mode: nil
269 * vi: set shiftwidth=4 tabstop=8 expandtab:
270 * :indentSize=4:tabSize=8:noTabs=true: