Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-hdmi.c
blob862d9cf2e6e7f400a95bc8b872dd53177b65477b
1 /* packet-hdmi.c
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
18 #include "config.h"
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;
30 static int ett_hdmi;
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" },
63 { 0, NULL }
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 */
75 static int
76 dissect_hdmi_edid(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
78 proto_item *yi;
79 proto_tree *edid_tree;
80 uint64_t edid_hdr;
81 uint16_t manf_id;
82 char manf_id_str[4]; /* 3 letters + 0-termination */
83 uint8_t week, year;
84 int year_hf;
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);
98 offset += 8;
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);
106 manf_id_str[3] = 0;
107 proto_tree_add_string(edid_tree, hf_hdmi_edid_manf_id,
108 tvb, offset, 2, manf_id_str);
109 offset += 2;
111 proto_tree_add_item(edid_tree, hf_hdmi_edid_manf_prod_code,
112 tvb, offset, 2, ENC_LITTLE_ENDIAN);
113 offset += 2;
115 proto_tree_add_item(edid_tree, hf_hdmi_edid_manf_serial,
116 tvb, offset, 4, ENC_LITTLE_ENDIAN);
117 offset += 4;
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);
122 offset += 1;
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);
129 offset += 1;
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);
139 static int
140 dissect_hdmi(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
142 uint8_t addr;
143 int offset=0;
144 proto_item *pi;
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);
159 if (addr&0x01) {
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;
164 else {
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
171 big or little endian
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);
176 offset += 1;
178 if (HDCP_ADDR8(addr)) {
179 tvbuff_t *hdcp_tvb;
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);
190 offset += 1;
191 return offset;
194 return dissect_hdmi_edid(tvb, offset, pinfo, hdmi_tree);
197 static void
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) );
203 void
204 proto_register_hdmi(void)
206 static hf_register_info hf[] = {
207 { &hf_hdmi_addr,
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 } },
213 { &hf_hdmi_edid_hdr,
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[] = {
241 &ett_hdmi,
242 &ett_hdmi_edid
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));
253 void
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
263 * Local variables:
264 * c-basic-offset: 4
265 * tab-width: 8
266 * indent-tabs-mode: nil
267 * End:
269 * vi: set shiftwidth=4 tabstop=8 expandtab:
270 * :indentSize=4:tabSize=8:noTabs=true: