1 /* packet-hdcp.c
2  * Routines for HDCP dissection
3  * Copyright 2011-2014, Martin Kaiser <martin@kaiser.cx>
4  *
5  * Wireshark - Network traffic analyzer
6  * By Gerald Combs <gerald@wireshark.org>
7  * Copyright 1998 Gerald Combs
8  *
9  * SPDX-License-Identifier: GPL-2.0-or-later
10  */
11 
12 /*
13  * This dissector supports HDCP (version 1) over I2C. For now, only the
14  * most common protocol messages are recognized.
15  *
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
18  */
19 
20 #include "config.h"
21 
22 #include <epan/packet.h>
23 #include <epan/ptvcursor.h>
24 void proto_register_hdcp(void);
25 
26 static int proto_hdcp  = -1;
27 
28 static wmem_tree_t *transactions;
29 
30 static gint ett_hdcp = -1;
31 
32 static int hf_hdcp_reg = -1;
33 static int hf_hdcp_resp_in = -1;
34 static int hf_hdcp_resp_to = -1;
35 static int hf_hdcp_a_ksv = -1;
36 static int hf_hdcp_b_ksv = -1;
37 static int hf_hdcp_an = -1;
38 static int hf_hdcp_hdmi_reserved = -1;
39 static int hf_hdcp_repeater = -1;
40 static int hf_hdcp_ksv_fifo = -1;
41 static int hf_hdcp_fast_trans = -1;
42 static int hf_hdcp_features = -1;
43 static int hf_hdcp_fast_reauth = -1;
44 static int hf_hdcp_hdmi_mode = -1;
45 static int hf_hdcp_max_casc_exc = -1;
46 static int hf_hdcp_depth = -1;
47 static int hf_hdcp_max_devs_exc = -1;
48 static int hf_hdcp_downstream = -1;
49 static int hf_hdcp_link_vfy = -1;
50 
51 #define REG_BKSV    0x0
52 #define REG_AKSV    0x10
53 #define REG_AN      0x18
54 #define REG_BCAPS   0x40
55 #define REG_BSTATUS 0x41
56 
57 typedef struct _hdcp_transaction_t {
58     guint32 rqst_frame;
59     guint32 resp_frame;
60     guint8 rqst_type;
61 } hdcp_transaction_t;
62 
63 static const value_string hdcp_reg[] = {
64     { REG_BKSV, "B_ksv" },
65     { REG_AKSV, "A_ksv" },
66     { REG_AN, "An" },
67     { REG_BCAPS, "B_caps"},
68     { REG_BSTATUS, "B_status"},
69     { 0, NULL }
70 };
71 
72 
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 */
76 static int
dissect_hdcp(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data _U_)77 dissect_hdcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
78 {
79     guint8 reg;
80     proto_item *pi;
81     ptvcursor_t *cursor;
82     proto_tree *hdcp_tree;
83     hdcp_transaction_t *hdcp_trans;
84     proto_item *it;
85     guint64 a_ksv, b_ksv;
86 
87     /* XXX check if the packet is really HDCP? */
88 
89     col_set_str(pinfo->cinfo, COL_PROTOCOL, "HDCP");
90     col_clear(pinfo->cinfo, COL_INFO);
91 
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);
95 
96     cursor = ptvcursor_new(pinfo->pool, hdcp_tree, tvb, 0);
97 
98     if (pinfo->p2p_dir==P2P_DIR_SENT) {
99         /* transmitter sends data to the receiver */
100 
101         reg = tvb_get_guint8(tvb, ptvcursor_current_offset(cursor));
102         /* all values in HDCP are little endian */
103         ptvcursor_add(cursor, hf_hdcp_reg, 1, ENC_LITTLE_ENDIAN);
104 
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)"));
110 
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) {
117 
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);
126                 }
127             }
128             else {
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);
136             }
137         }
138         else {
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)"));
142             switch (reg) {
143                 case REG_AKSV:
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" G_GINT64_MODIFIER "x", a_ksv);
149                     ptvcursor_advance(cursor, 5);
150                     break;
151                 case REG_AN:
152                     ptvcursor_add(cursor, hf_hdcp_an, 8, ENC_LITTLE_ENDIAN);
153                     break;
154                 default:
155                     break;
156             }
157         }
158     }
159     else {
160         /* transmitter reads from receiver */
161 
162         hdcp_trans = (hdcp_transaction_t *)wmem_tree_lookup32_le(
163                 transactions, pinfo->num);
164         if (hdcp_trans) {
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;
168             }
169 
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) {
183                     case REG_BKSV:
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" G_GINT64_MODIFIER "x",
189                                 b_ksv);
190                         ptvcursor_advance(cursor, 5);
191                         break;
192                     case REG_BCAPS:
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);
205                         break;
206                     case REG_BSTATUS:
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);
217                         break;
218                 }
219             }
220         }
221 
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);
231             }
232         }
233     }
234 
235     ptvcursor_free(cursor);
236     return tvb_reported_length(tvb);
237 }
238 
239 
240 void
proto_register_hdcp(void)241 proto_register_hdcp(void)
242 {
243     static hf_register_info hf[] = {
244         { &hf_hdcp_reg,
245             { "Register offset", "hdcp.reg", FT_UINT8, BASE_HEX,
246                 VALS(hdcp_reg), 0, NULL, HFILL } },
247         { &hf_hdcp_resp_in,
248             { "Response In", "hdcp.resp_in", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
249                 "The response to this request is in this frame", HFILL }},
250         { &hf_hdcp_resp_to,
251             { "Response To", "hdcp.resp_to", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
252                 "This is the response to the request in this frame", HFILL }},
253         { &hf_hdcp_a_ksv,
254             { "Transmitter's key selection vector", "hdcp.a_ksv", FT_UINT40,
255                 BASE_HEX, NULL, 0, NULL, HFILL } },
256         { &hf_hdcp_b_ksv,
257             { "Receiver's key selection vector", "hdcp.b_ksv", FT_UINT64,
258                 BASE_HEX, NULL, 0, NULL, HFILL } },
259         { &hf_hdcp_an,
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 } },
265         { &hf_hdcp_repeater,
266             { "Repeater", "hdcp.repeater", FT_UINT8, BASE_DEC,
267                 NULL, 0x40, NULL, HFILL } },
268         { &hf_hdcp_ksv_fifo,
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 } },
274         { &hf_hdcp_features,
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 } },
286         { &hf_hdcp_depth,
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 } },
295         { &hf_hdcp_link_vfy,
296             { "Link verification response Ri'", "hdcp.link_vfy",
297                 FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL } }
298     };
299 
300     static gint *ett[] = {
301         &ett_hdcp
302     };
303 
304 
305     proto_hdcp = proto_register_protocol(
306             "High bandwidth Digital Content Protection", "HDCP", "hdcp");
307 
308     proto_register_field_array(proto_hdcp, hf, array_length(hf));
309     proto_register_subtree_array(ett, array_length(ett));
310 
311     register_dissector("hdcp", dissect_hdcp, proto_hdcp);
312 
313     transactions = wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
314 }
315 
316 /*
317  * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
318  *
319  * Local variables:
320  * c-basic-offset: 4
321  * tab-width: 8
322  * indent-tabs-mode: nil
323  * End:
324  *
325  * vi: set shiftwidth=4 tabstop=8 expandtab:
326  * :indentSize=4:tabSize=8:noTabs=true:
327  */
328