2 * Routines for HDCP dissection
3 * Copyright 2011-2012, Martin Kaiser <martin@kaiser.cx>
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1998 Gerald Combs
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License along
22 * with this program; if not, write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 * This dissector supports HDCP (version 1) over I2C. For now, only the
28 * most common protocol messages are recognized.
30 * The specification of the version 1 protocol can be found at
31 * http://www.digital-cp.com/files/static_page_files/5C3DC13B-9F6B-D82E-D77D8ACA08A448BF/HDCP Specification Rev1_4.pdf
37 #include <epan/packet.h>
38 #include <epan/ptvcursor.h>
39 #include <epan/expert.h>
40 #include <epan/wmem/wmem.h>
41 #include "packet-hdcp.h"
44 static int proto_hdcp
= -1;
46 static wmem_tree_t
*transactions
= NULL
;
48 static gint ett_hdcp
= -1;
50 static int hf_hdcp_addr
= -1;
51 static int hf_hdcp_reg
= -1;
52 static int hf_hdcp_resp_in
= -1;
53 static int hf_hdcp_resp_to
= -1;
54 static int hf_hdcp_a_ksv
= -1;
55 static int hf_hdcp_b_ksv
= -1;
56 static int hf_hdcp_an
= -1;
57 static int hf_hdcp_hdmi_reserved
= -1;
58 static int hf_hdcp_repeater
= -1;
59 static int hf_hdcp_ksv_fifo
= -1;
60 static int hf_hdcp_fast_trans
= -1;
61 static int hf_hdcp_features
= -1;
62 static int hf_hdcp_fast_reauth
= -1;
63 static int hf_hdcp_hdmi_mode
= -1;
64 static int hf_hdcp_max_casc_exc
= -1;
65 static int hf_hdcp_depth
= -1;
66 static int hf_hdcp_max_devs_exc
= -1;
67 static int hf_hdcp_downstream
= -1;
68 static int hf_hdcp_link_vfy
= -1;
70 /* the addresses used by this dissector are 8bit, including the direction bit
71 (to be in line with the HDCP specification) */
72 #define ADDR8_HDCP_WRITE 0x74 /* transmitter->receiver */
73 #define ADDR8_HDCP_READ 0x75 /* receiver->transmitter */
75 #define HDCP_ADDR8(x) (x==ADDR8_HDCP_WRITE || x==ADDR8_HDCP_READ)
77 #define ADDR8_RCV "Receiver"
78 #define ADDR8_TRX "Transmitter"
83 #define REG_BCAPS 0x40
84 #define REG_BSTATUS 0x41
86 typedef struct _hdcp_transaction_t
{
92 static const value_string hdcp_addr
[] = {
93 { ADDR8_HDCP_WRITE
, "transmitter writes data for receiver" },
94 { ADDR8_HDCP_READ
, "transmitter reads data from receiver" },
98 static const value_string hdcp_reg
[] = {
99 { REG_BKSV
, "B_ksv" },
100 { REG_AKSV
, "A_ksv" },
102 { REG_BCAPS
, "B_caps"},
103 { REG_BSTATUS
, "B_status"},
108 sub_check_hdcp(packet_info
*pinfo _U_
)
110 /* by looking at the i2c_phdr only, we can't decide if this packet is HDCPv1
111 this function is called when the user explicitly selected HDCPv1
113 therefore, we always return TRUE and hand the data to the (new
114 style) dissector who will check if the packet is HDCPv1 */
120 dissect_hdcp(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
125 proto_tree
*hdcp_tree
= NULL
;
126 hdcp_transaction_t
*hdcp_trans
;
128 guint64 a_ksv
, b_ksv
;
130 addr
= tvb_get_guint8(tvb
, 0);
131 if (!HDCP_ADDR8(addr
))
134 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "HDCP");
135 col_clear(pinfo
->cinfo
, COL_INFO
);
138 pi
= proto_tree_add_protocol_format(tree
, proto_hdcp
,
139 tvb
, 0, tvb_reported_length(tvb
), "HDCP");
140 hdcp_tree
= proto_item_add_subtree(pi
, ett_hdcp
);
143 cursor
= ptvcursor_new(hdcp_tree
, tvb
, 0);
144 /* all values in HDCP are little endian */
145 ptvcursor_add(cursor
, hf_hdcp_addr
, 1, ENC_LITTLE_ENDIAN
);
147 if (addr
==ADDR8_HDCP_WRITE
) {
148 /* transmitter sends data to the receiver */
149 SET_ADDRESS(&pinfo
->src
, AT_STRINGZ
, (int)strlen(ADDR8_TRX
)+1, ADDR8_TRX
);
150 SET_ADDRESS(&pinfo
->dst
, AT_STRINGZ
, (int)strlen(ADDR8_RCV
)+1, ADDR8_RCV
);
152 reg
= tvb_get_guint8(tvb
, ptvcursor_current_offset(cursor
));
153 ptvcursor_add(cursor
, hf_hdcp_reg
, 1, ENC_LITTLE_ENDIAN
);
155 if (tvb_reported_length_remaining(tvb
,
156 ptvcursor_current_offset(cursor
)) == 0) {
157 /* transmitter requests the content of a register */
158 col_append_sep_fstr(pinfo
->cinfo
, COL_INFO
, NULL
, "request %s",
159 val_to_str(reg
, hdcp_reg
, "unknown (0x%x)"));
161 if (PINFO_FD_VISITED(pinfo
)) {
162 /* we've already dissected the receiver's response */
163 hdcp_trans
= (hdcp_transaction_t
*)wmem_tree_lookup32(
164 transactions
, PINFO_FD_NUM(pinfo
));
165 if (hdcp_trans
&& hdcp_trans
->rqst_frame
==PINFO_FD_NUM(pinfo
) &&
166 hdcp_trans
->resp_frame
!=0) {
168 it
= proto_tree_add_uint_format(hdcp_tree
, hf_hdcp_resp_in
,
169 NULL
, 0, 0, hdcp_trans
->resp_frame
,
170 "Request to get the content of register %s, "
171 "response in frame %d",
172 val_to_str_const(hdcp_trans
->rqst_type
,
173 hdcp_reg
, "unknown (0x%x)"),
174 hdcp_trans
->resp_frame
);
175 PROTO_ITEM_SET_GENERATED(it
);
179 /* we've not yet dissected the response */
181 hdcp_trans
= wmem_new(wmem_file_scope(), hdcp_transaction_t
);
182 hdcp_trans
->rqst_frame
= PINFO_FD_NUM(pinfo
);
183 hdcp_trans
->resp_frame
= 0;
184 hdcp_trans
->rqst_type
= reg
;
185 wmem_tree_insert32(transactions
,
186 hdcp_trans
->rqst_frame
, (void *)hdcp_trans
);
191 /* transmitter actually sends protocol data */
192 col_append_sep_fstr(pinfo
->cinfo
, COL_INFO
, NULL
, "send %s",
193 val_to_str(reg
, hdcp_reg
, "unknown (0x%x)"));
196 a_ksv
= tvb_get_letoh40(tvb
,
197 ptvcursor_current_offset(cursor
));
198 proto_tree_add_uint64_format(hdcp_tree
, hf_hdcp_a_ksv
,
199 tvb
, ptvcursor_current_offset(cursor
), 5,
200 a_ksv
, "A_ksv 0x%010" G_GINT64_MODIFIER
"x", a_ksv
);
201 ptvcursor_advance(cursor
, 5);
204 ptvcursor_add(cursor
, hf_hdcp_an
, 8, ENC_LITTLE_ENDIAN
);
212 /* transmitter reads from receiver */
213 SET_ADDRESS(&pinfo
->src
, AT_STRINGZ
, (int)strlen(ADDR8_RCV
)+1, ADDR8_RCV
);
214 SET_ADDRESS(&pinfo
->dst
, AT_STRINGZ
, (int)strlen(ADDR8_TRX
)+1, ADDR8_TRX
);
217 hdcp_trans
= (hdcp_transaction_t
*)wmem_tree_lookup32_le(
218 transactions
, PINFO_FD_NUM(pinfo
));
220 if (hdcp_trans
->resp_frame
==0) {
221 /* there's a pending request, this packet is the response */
222 hdcp_trans
->resp_frame
= PINFO_FD_NUM(pinfo
);
225 if (hdcp_trans
->resp_frame
== PINFO_FD_NUM(pinfo
)) {
226 /* we found the request that corresponds to our response */
227 col_append_sep_fstr(pinfo
->cinfo
, COL_INFO
, NULL
, "send %s",
228 val_to_str_const(hdcp_trans
->rqst_type
,
229 hdcp_reg
, "unknown (0x%x)"));
230 it
= proto_tree_add_uint_format(hdcp_tree
, hf_hdcp_resp_to
,
231 NULL
, 0, 0, hdcp_trans
->rqst_frame
,
232 "Response to frame %d (content of register %s)",
233 hdcp_trans
->rqst_frame
,
234 val_to_str_const(hdcp_trans
->rqst_type
,
235 hdcp_reg
, "unknown (0x%x)"));
236 PROTO_ITEM_SET_GENERATED(it
);
237 switch (hdcp_trans
->rqst_type
) {
239 b_ksv
= tvb_get_letoh40(tvb
,
240 ptvcursor_current_offset(cursor
));
241 proto_tree_add_uint64_format(hdcp_tree
, hf_hdcp_b_ksv
,
242 tvb
, ptvcursor_current_offset(cursor
), 5,
243 b_ksv
, "B_ksv 0x%010" G_GINT64_MODIFIER
"x",
245 ptvcursor_advance(cursor
, 5);
248 ptvcursor_add_no_advance(cursor
,
249 hf_hdcp_hdmi_reserved
, 1, ENC_LITTLE_ENDIAN
);
250 ptvcursor_add_no_advance(cursor
,
251 hf_hdcp_repeater
, 1, ENC_LITTLE_ENDIAN
);
252 ptvcursor_add_no_advance(cursor
,
253 hf_hdcp_ksv_fifo
, 1, ENC_LITTLE_ENDIAN
);
254 ptvcursor_add_no_advance(cursor
,
255 hf_hdcp_fast_trans
, 1, ENC_LITTLE_ENDIAN
);
256 ptvcursor_add_no_advance(cursor
,
257 hf_hdcp_features
, 1, ENC_LITTLE_ENDIAN
);
258 ptvcursor_add_no_advance(cursor
,
259 hf_hdcp_fast_reauth
, 1, ENC_LITTLE_ENDIAN
);
262 ptvcursor_add_no_advance(cursor
,
263 hf_hdcp_hdmi_mode
, 2, ENC_LITTLE_ENDIAN
);
264 ptvcursor_add_no_advance(cursor
,
265 hf_hdcp_max_casc_exc
, 2, ENC_LITTLE_ENDIAN
);
266 ptvcursor_add_no_advance(cursor
,
267 hf_hdcp_depth
, 2, ENC_LITTLE_ENDIAN
);
268 ptvcursor_add_no_advance(cursor
,
269 hf_hdcp_max_devs_exc
, 2, ENC_LITTLE_ENDIAN
);
270 ptvcursor_add_no_advance(cursor
,
271 hf_hdcp_downstream
, 2, ENC_LITTLE_ENDIAN
);
277 if (!hdcp_trans
|| hdcp_trans
->resp_frame
!=PINFO_FD_NUM(pinfo
)) {
278 /* the packet isn't a response to a request from the
279 * transmitter; it must be a link verification */
280 if (tvb_reported_length_remaining(
281 tvb
, ptvcursor_current_offset(cursor
)) == 2) {
282 col_append_sep_fstr(pinfo
->cinfo
, COL_INFO
, NULL
,
283 "send link verification Ri'");
284 ptvcursor_add_no_advance(cursor
,
285 hf_hdcp_link_vfy
, 2, ENC_LITTLE_ENDIAN
);
291 ptvcursor_free(cursor
);
292 return tvb_reported_length(tvb
);
297 proto_register_hdcp(void)
299 static hf_register_info hf
[] = {
301 { "8bit I2C address", "hdcp.addr", FT_UINT8
, BASE_HEX
,
302 VALS(hdcp_addr
), 0, NULL
, HFILL
} },
304 { "Register offset", "hdcp.reg", FT_UINT8
, BASE_HEX
,
305 VALS(hdcp_reg
), 0, NULL
, HFILL
} },
307 { "Response In", "hdcp.resp_in", FT_FRAMENUM
, BASE_NONE
, NULL
, 0x0,
308 "The response to this request is in this frame", HFILL
}},
310 { "Response To", "hdcp.resp_to", FT_FRAMENUM
, BASE_NONE
, NULL
, 0x0,
311 "This is the response to the request in this frame", HFILL
}},
312 /* actually, the KSVs are only 40bits, but there's no FT_UINT40 type */
314 { "Transmitter's key selection vector", "hdcp.a_ksv", FT_UINT64
,
315 BASE_HEX
, NULL
, 0, NULL
, HFILL
} },
317 { "Receiver's key selection vector", "hdcp.b_ksv", FT_UINT64
,
318 BASE_HEX
, NULL
, 0, NULL
, HFILL
} },
320 { "Random number for the session", "hdcp.an", FT_UINT64
,
321 BASE_HEX
, NULL
, 0, NULL
, HFILL
} },
322 { &hf_hdcp_hdmi_reserved
,
323 { "HDMI reserved", "hdcp.hdmi_reserved", FT_UINT8
, BASE_DEC
,
324 NULL
, 0x80, NULL
, HFILL
} },
326 { "Repeater", "hdcp.repeater", FT_UINT8
, BASE_DEC
,
327 NULL
, 0x40, NULL
, HFILL
} },
329 { "KSV fifo ready", "hdcp.ksv_fifo", FT_UINT8
, BASE_DEC
,
330 NULL
, 0x20, NULL
, HFILL
} },
331 { &hf_hdcp_fast_trans
,
332 { "Support for 400KHz transfers", "hdcp.fast_trans",
333 FT_UINT8
, BASE_DEC
, NULL
, 0x10, NULL
, HFILL
} },
335 { "Support for additional features", "hdcp.features",
336 FT_UINT8
, BASE_DEC
, NULL
, 0x02, NULL
, HFILL
} },
337 { &hf_hdcp_fast_reauth
,
338 { "Support for fast re-authentication", "hdcp.fast_reauth",
339 FT_UINT8
, BASE_DEC
, NULL
, 0x01, NULL
, HFILL
} },
340 { &hf_hdcp_hdmi_mode
,
341 { "HDMI mode", "hdcp.hdmi_mode",
342 FT_UINT16
, BASE_DEC
, NULL
, 0x1000, NULL
, HFILL
} },
343 { &hf_hdcp_max_casc_exc
,
344 { "Maximum cascading depth exceeded", "hdcp.max_casc_exc",
345 FT_UINT16
, BASE_DEC
, NULL
, 0x0800, NULL
, HFILL
} },
347 { "Repeater cascade depth", "hdcp.depth",
348 FT_UINT16
, BASE_DEC
, NULL
, 0x0700, NULL
, HFILL
} },
349 { &hf_hdcp_max_devs_exc
,
350 { "Maximum number of devices exceeded", "hdcp.max_devs_exc",
351 FT_UINT16
, BASE_DEC
, NULL
, 0x0080, NULL
, HFILL
} },
352 { &hf_hdcp_downstream
,
353 { "Number of downstream receivers", "hdcp.downstream",
354 FT_UINT16
, BASE_DEC
, NULL
, 0x007F, NULL
, HFILL
} },
356 { "Link verification response Ri'", "hdcp.link_vfy",
357 FT_UINT16
, BASE_HEX
, NULL
, 0, NULL
, HFILL
} }
360 static gint
*ett
[] = {
365 proto_hdcp
= proto_register_protocol(
366 "High bandwidth Digital Content Protection", "HDCP", "hdcp");
368 proto_register_field_array(proto_hdcp
, hf
, array_length(hf
));
369 proto_register_subtree_array(ett
, array_length(ett
));
371 new_register_dissector("hdcp", dissect_hdcp
, proto_hdcp
);
373 transactions
= wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
377 * Editor modelines - http://www.wireshark.org/tools/modelines.html
382 * indent-tabs-mode: nil
385 * vi: set shiftwidth=4 tabstop=8 expandtab:
386 * :indentSize=4:tabSize=8:noTabs=true: