2 * Routines for HDCP dissection
3 * Copyright 2011-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
13 * This dissector supports HDCP (version 1) over I2C. For now, only the
14 * most common protocol messages are recognized.
16 * The specification of the version 1 protocol can be found at
17 * http://www.digital-cp.com/files/static_page_files/5C3DC13B-9F6B-D82E-D77D8ACA08A448BF/HDCP Specification Rev1_4.pdf
22 #include <epan/packet.h>
23 #include <epan/ptvcursor.h>
24 void proto_register_hdcp(void);
26 static int proto_hdcp
;
28 static wmem_tree_t
*transactions
;
32 static int hf_hdcp_reg
;
33 static int hf_hdcp_resp_in
;
34 static int hf_hdcp_resp_to
;
35 static int hf_hdcp_a_ksv
;
36 static int hf_hdcp_b_ksv
;
37 static int hf_hdcp_an
;
38 static int hf_hdcp_hdmi_reserved
;
39 static int hf_hdcp_repeater
;
40 static int hf_hdcp_ksv_fifo
;
41 static int hf_hdcp_fast_trans
;
42 static int hf_hdcp_features
;
43 static int hf_hdcp_fast_reauth
;
44 static int hf_hdcp_hdmi_mode
;
45 static int hf_hdcp_max_casc_exc
;
46 static int hf_hdcp_depth
;
47 static int hf_hdcp_max_devs_exc
;
48 static int hf_hdcp_downstream
;
49 static int hf_hdcp_link_vfy
;
54 #define REG_BCAPS 0x40
55 #define REG_BSTATUS 0x41
57 typedef struct _hdcp_transaction_t
{
63 static const value_string hdcp_reg
[] = {
64 { REG_BKSV
, "B_ksv" },
65 { REG_AKSV
, "A_ksv" },
67 { REG_BCAPS
, "B_caps"},
68 { REG_BSTATUS
, "B_status"},
73 /* the input tvb contains an HDCP message without the leading address byte
74 (the address byte is handled by the HDMI dissector)
75 the caller must set the direction in pinfo */
77 dissect_hdcp(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
82 proto_tree
*hdcp_tree
;
83 hdcp_transaction_t
*hdcp_trans
;
85 uint64_t a_ksv
, b_ksv
;
87 /* XXX check if the packet is really HDCP? */
89 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "HDCP");
90 col_clear(pinfo
->cinfo
, COL_INFO
);
92 pi
= proto_tree_add_protocol_format(tree
, proto_hdcp
,
93 tvb
, 0, tvb_reported_length(tvb
), "HDCP");
94 hdcp_tree
= proto_item_add_subtree(pi
, ett_hdcp
);
96 cursor
= ptvcursor_new(pinfo
->pool
, hdcp_tree
, tvb
, 0);
98 if (pinfo
->p2p_dir
==P2P_DIR_SENT
) {
99 /* transmitter sends data to the receiver */
101 reg
= tvb_get_uint8(tvb
, ptvcursor_current_offset(cursor
));
102 /* all values in HDCP are little endian */
103 ptvcursor_add(cursor
, hf_hdcp_reg
, 1, ENC_LITTLE_ENDIAN
);
105 if (tvb_reported_length_remaining(tvb
,
106 ptvcursor_current_offset(cursor
)) == 0) {
107 /* transmitter requests the content of a register */
108 col_append_sep_fstr(pinfo
->cinfo
, COL_INFO
, NULL
, "request %s",
109 val_to_str(reg
, hdcp_reg
, "unknown (0x%x)"));
111 if (PINFO_FD_VISITED(pinfo
)) {
112 /* we've already dissected the receiver's response */
113 hdcp_trans
= (hdcp_transaction_t
*)wmem_tree_lookup32(
114 transactions
, pinfo
->num
);
115 if (hdcp_trans
&& hdcp_trans
->rqst_frame
==pinfo
->num
&&
116 hdcp_trans
->resp_frame
!=0) {
118 it
= proto_tree_add_uint_format(hdcp_tree
, hf_hdcp_resp_in
,
119 NULL
, 0, 0, hdcp_trans
->resp_frame
,
120 "Request to get the content of register %s, "
121 "response in frame %d",
122 val_to_str_const(hdcp_trans
->rqst_type
,
123 hdcp_reg
, "unknown (0x%x)"),
124 hdcp_trans
->resp_frame
);
125 proto_item_set_generated(it
);
129 /* we've not yet dissected the response */
130 hdcp_trans
= wmem_new(wmem_file_scope(), hdcp_transaction_t
);
131 hdcp_trans
->rqst_frame
= pinfo
->num
;
132 hdcp_trans
->resp_frame
= 0;
133 hdcp_trans
->rqst_type
= reg
;
134 wmem_tree_insert32(transactions
,
135 hdcp_trans
->rqst_frame
, (void *)hdcp_trans
);
139 /* transmitter actually sends protocol data */
140 col_append_sep_fstr(pinfo
->cinfo
, COL_INFO
, NULL
, "send %s",
141 val_to_str(reg
, hdcp_reg
, "unknown (0x%x)"));
144 a_ksv
= tvb_get_letoh40(tvb
,
145 ptvcursor_current_offset(cursor
));
146 proto_tree_add_uint64_format(hdcp_tree
, hf_hdcp_a_ksv
,
147 tvb
, ptvcursor_current_offset(cursor
), 5,
148 a_ksv
, "A_ksv 0x%010" PRIx64
, a_ksv
);
149 ptvcursor_advance(cursor
, 5);
152 ptvcursor_add(cursor
, hf_hdcp_an
, 8, ENC_LITTLE_ENDIAN
);
160 /* transmitter reads from receiver */
162 hdcp_trans
= (hdcp_transaction_t
*)wmem_tree_lookup32_le(
163 transactions
, pinfo
->num
);
165 if (hdcp_trans
->resp_frame
==0) {
166 /* there's a pending request, this packet is the response */
167 hdcp_trans
->resp_frame
= pinfo
->num
;
170 if (hdcp_trans
->resp_frame
== pinfo
->num
) {
171 /* we found the request that corresponds to our response */
172 col_append_sep_fstr(pinfo
->cinfo
, COL_INFO
, NULL
, "send %s",
173 val_to_str_const(hdcp_trans
->rqst_type
,
174 hdcp_reg
, "unknown (0x%x)"));
175 it
= proto_tree_add_uint_format(hdcp_tree
, hf_hdcp_resp_to
,
176 NULL
, 0, 0, hdcp_trans
->rqst_frame
,
177 "Response to frame %d (content of register %s)",
178 hdcp_trans
->rqst_frame
,
179 val_to_str_const(hdcp_trans
->rqst_type
,
180 hdcp_reg
, "unknown (0x%x)"));
181 proto_item_set_generated(it
);
182 switch (hdcp_trans
->rqst_type
) {
184 b_ksv
= tvb_get_letoh40(tvb
,
185 ptvcursor_current_offset(cursor
));
186 proto_tree_add_uint64_format(hdcp_tree
, hf_hdcp_b_ksv
,
187 tvb
, ptvcursor_current_offset(cursor
), 5,
188 b_ksv
, "B_ksv 0x%010" PRIx64
,
190 ptvcursor_advance(cursor
, 5);
193 ptvcursor_add_no_advance(cursor
,
194 hf_hdcp_hdmi_reserved
, 1, ENC_LITTLE_ENDIAN
);
195 ptvcursor_add_no_advance(cursor
,
196 hf_hdcp_repeater
, 1, ENC_LITTLE_ENDIAN
);
197 ptvcursor_add_no_advance(cursor
,
198 hf_hdcp_ksv_fifo
, 1, ENC_LITTLE_ENDIAN
);
199 ptvcursor_add_no_advance(cursor
,
200 hf_hdcp_fast_trans
, 1, ENC_LITTLE_ENDIAN
);
201 ptvcursor_add_no_advance(cursor
,
202 hf_hdcp_features
, 1, ENC_LITTLE_ENDIAN
);
203 ptvcursor_add_no_advance(cursor
,
204 hf_hdcp_fast_reauth
, 1, ENC_LITTLE_ENDIAN
);
207 ptvcursor_add_no_advance(cursor
,
208 hf_hdcp_hdmi_mode
, 2, ENC_LITTLE_ENDIAN
);
209 ptvcursor_add_no_advance(cursor
,
210 hf_hdcp_max_casc_exc
, 2, ENC_LITTLE_ENDIAN
);
211 ptvcursor_add_no_advance(cursor
,
212 hf_hdcp_depth
, 2, ENC_LITTLE_ENDIAN
);
213 ptvcursor_add_no_advance(cursor
,
214 hf_hdcp_max_devs_exc
, 2, ENC_LITTLE_ENDIAN
);
215 ptvcursor_add_no_advance(cursor
,
216 hf_hdcp_downstream
, 2, ENC_LITTLE_ENDIAN
);
222 if (!hdcp_trans
|| hdcp_trans
->resp_frame
!=pinfo
->num
) {
223 /* the packet isn't a response to a request from the
224 * transmitter; it must be a link verification */
225 if (tvb_reported_length_remaining(
226 tvb
, ptvcursor_current_offset(cursor
)) == 2) {
227 col_append_sep_str(pinfo
->cinfo
, COL_INFO
, NULL
,
228 "send link verification Ri'");
229 ptvcursor_add_no_advance(cursor
,
230 hf_hdcp_link_vfy
, 2, ENC_LITTLE_ENDIAN
);
235 ptvcursor_free(cursor
);
236 return tvb_reported_length(tvb
);
241 proto_register_hdcp(void)
243 static hf_register_info hf
[] = {
245 { "Register offset", "hdcp.reg", FT_UINT8
, BASE_HEX
,
246 VALS(hdcp_reg
), 0, NULL
, HFILL
} },
248 { "Response In", "hdcp.resp_in", FT_FRAMENUM
, BASE_NONE
, FRAMENUM_TYPE(FT_FRAMENUM_RESPONSE
), 0x0,
249 "The response to this request is in this frame", HFILL
}},
251 { "Response To", "hdcp.resp_to", FT_FRAMENUM
, BASE_NONE
, FRAMENUM_TYPE(FT_FRAMENUM_REQUEST
), 0x0,
252 "This is the response to the request in this frame", HFILL
}},
254 { "Transmitter's key selection vector", "hdcp.a_ksv", FT_UINT40
,
255 BASE_HEX
, NULL
, 0, NULL
, HFILL
} },
257 { "Receiver's key selection vector", "hdcp.b_ksv", FT_UINT64
,
258 BASE_HEX
, NULL
, 0, NULL
, HFILL
} },
260 { "Random number for the session", "hdcp.an", FT_UINT64
,
261 BASE_HEX
, NULL
, 0, NULL
, HFILL
} },
262 { &hf_hdcp_hdmi_reserved
,
263 { "HDMI reserved", "hdcp.hdmi_reserved", FT_UINT8
, BASE_DEC
,
264 NULL
, 0x80, NULL
, HFILL
} },
266 { "Repeater", "hdcp.repeater", FT_UINT8
, BASE_DEC
,
267 NULL
, 0x40, NULL
, HFILL
} },
269 { "KSV fifo ready", "hdcp.ksv_fifo", FT_UINT8
, BASE_DEC
,
270 NULL
, 0x20, NULL
, HFILL
} },
271 { &hf_hdcp_fast_trans
,
272 { "Support for 400KHz transfers", "hdcp.fast_trans",
273 FT_UINT8
, BASE_DEC
, NULL
, 0x10, NULL
, HFILL
} },
275 { "Support for additional features", "hdcp.features",
276 FT_UINT8
, BASE_DEC
, NULL
, 0x02, NULL
, HFILL
} },
277 { &hf_hdcp_fast_reauth
,
278 { "Support for fast re-authentication", "hdcp.fast_reauth",
279 FT_UINT8
, BASE_DEC
, NULL
, 0x01, NULL
, HFILL
} },
280 { &hf_hdcp_hdmi_mode
,
281 { "HDMI mode", "hdcp.hdmi_mode",
282 FT_UINT16
, BASE_DEC
, NULL
, 0x1000, NULL
, HFILL
} },
283 { &hf_hdcp_max_casc_exc
,
284 { "Maximum cascading depth exceeded", "hdcp.max_casc_exc",
285 FT_UINT16
, BASE_DEC
, NULL
, 0x0800, NULL
, HFILL
} },
287 { "Repeater cascade depth", "hdcp.depth",
288 FT_UINT16
, BASE_DEC
, NULL
, 0x0700, NULL
, HFILL
} },
289 { &hf_hdcp_max_devs_exc
,
290 { "Maximum number of devices exceeded", "hdcp.max_devs_exc",
291 FT_UINT16
, BASE_DEC
, NULL
, 0x0080, NULL
, HFILL
} },
292 { &hf_hdcp_downstream
,
293 { "Number of downstream receivers", "hdcp.downstream",
294 FT_UINT16
, BASE_DEC
, NULL
, 0x007F, NULL
, HFILL
} },
296 { "Link verification response Ri'", "hdcp.link_vfy",
297 FT_UINT16
, BASE_HEX
, NULL
, 0, NULL
, HFILL
} }
300 static int *ett
[] = {
305 proto_hdcp
= proto_register_protocol("High bandwidth Digital Content Protection", "HDCP", "hdcp");
307 proto_register_field_array(proto_hdcp
, hf
, array_length(hf
));
308 proto_register_subtree_array(ett
, array_length(ett
));
310 register_dissector("hdcp", dissect_hdcp
, proto_hdcp
);
312 transactions
= wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
316 * Editor modelines - https://www.wireshark.org/tools/modelines.html
321 * indent-tabs-mode: nil
324 * vi: set shiftwidth=4 tabstop=8 expandtab:
325 * :indentSize=4:tabSize=8:noTabs=true: