HACK: 2nd try to match RowsetProperties
[wireshark-wip.git] / epan / dissectors / packet-hdcp.c
blob9fcfc196a98b5a03a22e75e2c94be78ab3eee25f
1 /* packet-hdcp.c
2 * Routines for HDCP dissection
3 * Copyright 2011-2012, Martin Kaiser <martin@kaiser.cx>
5 * $Id$
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
34 #include "config.h"
36 #include <glib.h>
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"
80 #define REG_BKSV 0x0
81 #define REG_AKSV 0x10
82 #define REG_AN 0x18
83 #define REG_BCAPS 0x40
84 #define REG_BSTATUS 0x41
86 typedef struct _hdcp_transaction_t {
87 guint32 rqst_frame;
88 guint32 resp_frame;
89 guint8 rqst_type;
90 } 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" },
95 { 0, NULL }
98 static const value_string hdcp_reg[] = {
99 { REG_BKSV, "B_ksv" },
100 { REG_AKSV, "A_ksv" },
101 { REG_AN, "An" },
102 { REG_BCAPS, "B_caps"},
103 { REG_BSTATUS, "B_status"},
104 { 0, NULL }
107 gboolean
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
112 in the preferences
113 therefore, we always return TRUE and hand the data to the (new
114 style) dissector who will check if the packet is HDCPv1 */
116 return TRUE;
119 static int
120 dissect_hdcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
122 guint8 addr, reg;
123 proto_item *pi;
124 ptvcursor_t *cursor;
125 proto_tree *hdcp_tree = NULL;
126 hdcp_transaction_t *hdcp_trans;
127 proto_item *it;
128 guint64 a_ksv, b_ksv;
130 addr = tvb_get_guint8(tvb, 0);
131 if (!HDCP_ADDR8(addr))
132 return 0;
134 col_set_str(pinfo->cinfo, COL_PROTOCOL, "HDCP");
135 col_clear(pinfo->cinfo, COL_INFO);
137 if (tree) {
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);
178 else {
179 /* we've not yet dissected the response */
180 if (transactions) {
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);
190 else {
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)"));
194 switch (reg) {
195 case REG_AKSV:
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);
202 break;
203 case REG_AN:
204 ptvcursor_add(cursor, hf_hdcp_an, 8, ENC_LITTLE_ENDIAN);
205 break;
206 default:
207 break;
211 else {
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);
216 if (transactions) {
217 hdcp_trans = (hdcp_transaction_t *)wmem_tree_lookup32_le(
218 transactions, PINFO_FD_NUM(pinfo));
219 if (hdcp_trans) {
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) {
238 case REG_BKSV:
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",
244 b_ksv);
245 ptvcursor_advance(cursor, 5);
246 break;
247 case REG_BCAPS:
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);
260 break;
261 case REG_BSTATUS:
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);
272 break;
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);
296 void
297 proto_register_hdcp(void)
299 static hf_register_info hf[] = {
300 { &hf_hdcp_addr,
301 { "8bit I2C address", "hdcp.addr", FT_UINT8, BASE_HEX,
302 VALS(hdcp_addr), 0, NULL, HFILL } },
303 { &hf_hdcp_reg,
304 { "Register offset", "hdcp.reg", FT_UINT8, BASE_HEX,
305 VALS(hdcp_reg), 0, NULL, HFILL } },
306 { &hf_hdcp_resp_in,
307 { "Response In", "hdcp.resp_in", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
308 "The response to this request is in this frame", HFILL }},
309 { &hf_hdcp_resp_to,
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 */
313 { &hf_hdcp_a_ksv,
314 { "Transmitter's key selection vector", "hdcp.a_ksv", FT_UINT64,
315 BASE_HEX, NULL, 0, NULL, HFILL } },
316 { &hf_hdcp_b_ksv,
317 { "Receiver's key selection vector", "hdcp.b_ksv", FT_UINT64,
318 BASE_HEX, NULL, 0, NULL, HFILL } },
319 { &hf_hdcp_an,
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 } },
325 { &hf_hdcp_repeater,
326 { "Repeater", "hdcp.repeater", FT_UINT8, BASE_DEC,
327 NULL, 0x40, NULL, HFILL } },
328 { &hf_hdcp_ksv_fifo,
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 } },
334 { &hf_hdcp_features,
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 } },
346 { &hf_hdcp_depth,
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 } },
355 { &hf_hdcp_link_vfy,
356 { "Link verification response Ri'", "hdcp.link_vfy",
357 FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL } }
360 static gint *ett[] = {
361 &ett_hdcp
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
379 * Local variables:
380 * c-basic-offset: 4
381 * tab-width: 8
382 * indent-tabs-mode: nil
383 * End:
385 * vi: set shiftwidth=4 tabstop=8 expandtab:
386 * :indentSize=4:tabSize=8:noTabs=true: