Coverage Report

Created: 2026-05-14 06:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/epan/dissectors/packet-hdcp.c
Line
Count
Source
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;
27
28
static wmem_tree_t *transactions;
29
30
static int ett_hdcp;
31
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;
50
51
0
#define REG_BKSV    0x0
52
0
#define REG_AKSV    0x10
53
0
#define REG_AN      0x18
54
0
#define REG_BCAPS   0x40
55
0
#define REG_BSTATUS 0x41
56
57
typedef struct _hdcp_transaction_t {
58
    uint32_t rqst_frame;
59
    uint32_t resp_frame;
60
    uint8_t 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
77
dissect_hdcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
78
0
{
79
0
    uint8_t reg;
80
0
    proto_item *pi;
81
0
    ptvcursor_t *cursor;
82
0
    proto_tree *hdcp_tree;
83
0
    hdcp_transaction_t *hdcp_trans;
84
0
    proto_item *it;
85
0
    uint64_t a_ksv, b_ksv;
86
87
    /* XXX check if the packet is really HDCP? */
88
89
0
    col_set_str(pinfo->cinfo, COL_PROTOCOL, "HDCP");
90
0
    col_clear(pinfo->cinfo, COL_INFO);
91
92
0
    pi = proto_tree_add_protocol_format(tree, proto_hdcp,
93
0
            tvb, 0, tvb_reported_length(tvb), "HDCP");
94
0
    hdcp_tree = proto_item_add_subtree(pi, ett_hdcp);
95
96
0
    cursor = ptvcursor_new(pinfo->pool, hdcp_tree, tvb, 0);
97
98
0
    if (pinfo->p2p_dir==P2P_DIR_SENT) {
99
        /* transmitter sends data to the receiver */
100
101
0
        reg = tvb_get_uint8(tvb, ptvcursor_current_offset(cursor));
102
        /* all values in HDCP are little endian */
103
0
        ptvcursor_add(cursor, hf_hdcp_reg, 1, ENC_LITTLE_ENDIAN);
104
105
0
        if (tvb_reported_length_remaining(tvb,
106
0
                    ptvcursor_current_offset(cursor)) == 0) {
107
            /* transmitter requests the content of a register */
108
0
            col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL, "request %s",
109
0
                    val_to_str(pinfo->pool, reg, hdcp_reg, "unknown (0x%x)"));
110
111
0
            if (PINFO_FD_VISITED(pinfo)) {
112
                /* we've already dissected the receiver's response */
113
0
                hdcp_trans = (hdcp_transaction_t *)wmem_tree_lookup32(
114
0
                        transactions, pinfo->num);
115
0
                if (hdcp_trans && hdcp_trans->rqst_frame==pinfo->num &&
116
0
                        hdcp_trans->resp_frame!=0) {
117
118
0
                   it = proto_tree_add_uint_format(hdcp_tree, hf_hdcp_resp_in,
119
0
                           NULL, 0, 0, hdcp_trans->resp_frame,
120
0
                           "Request to get the content of register %s, "
121
0
                           "response in frame %d",
122
0
                           val_to_str_const(hdcp_trans->rqst_type,
123
0
                               hdcp_reg, "unknown (0x%x)"),
124
0
                           hdcp_trans->resp_frame);
125
0
                    proto_item_set_generated(it);
126
0
                }
127
0
            }
128
0
            else {
129
                /* we've not yet dissected the response */
130
0
                hdcp_trans = wmem_new(wmem_file_scope(), hdcp_transaction_t);
131
0
                hdcp_trans->rqst_frame = pinfo->num;
132
0
                hdcp_trans->resp_frame = 0;
133
0
                hdcp_trans->rqst_type = reg;
134
0
                wmem_tree_insert32(transactions,
135
0
                        hdcp_trans->rqst_frame, (void *)hdcp_trans);
136
0
            }
137
0
        }
138
0
        else {
139
            /* transmitter actually sends protocol data */
140
0
            col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL, "send %s",
141
0
                    val_to_str(pinfo->pool, reg, hdcp_reg, "unknown (0x%x)"));
142
0
            switch (reg) {
143
0
                case REG_AKSV:
144
0
                    a_ksv = tvb_get_letoh40(tvb,
145
0
                                ptvcursor_current_offset(cursor));
146
0
                    proto_tree_add_uint64_format(hdcp_tree, hf_hdcp_a_ksv,
147
0
                            tvb, ptvcursor_current_offset(cursor), 5,
148
0
                            a_ksv, "A_ksv 0x%010" PRIx64, a_ksv);
149
0
                    ptvcursor_advance(cursor, 5);
150
0
                    break;
151
0
                case REG_AN:
152
0
                    ptvcursor_add(cursor, hf_hdcp_an, 8, ENC_LITTLE_ENDIAN);
153
0
                    break;
154
0
                default:
155
0
                    break;
156
0
            }
157
0
        }
158
0
    }
159
0
    else {
160
        /* transmitter reads from receiver */
161
162
0
        hdcp_trans = (hdcp_transaction_t *)wmem_tree_lookup32_le(
163
0
                transactions, pinfo->num);
164
0
        if (hdcp_trans) {
165
0
            if (hdcp_trans->resp_frame==0) {
166
                /* there's a pending request, this packet is the response */
167
0
                hdcp_trans->resp_frame = pinfo->num;
168
0
            }
169
170
0
            if (hdcp_trans->resp_frame== pinfo->num) {
171
                /* we found the request that corresponds to our response */
172
0
                col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL, "send %s",
173
0
                        val_to_str_const(hdcp_trans->rqst_type,
174
0
                            hdcp_reg, "unknown (0x%x)"));
175
0
                it = proto_tree_add_uint_format(hdcp_tree, hf_hdcp_resp_to,
176
0
                        NULL, 0, 0, hdcp_trans->rqst_frame,
177
0
                        "Response to frame %d (content of register %s)",
178
0
                        hdcp_trans->rqst_frame,
179
0
                        val_to_str_const(hdcp_trans->rqst_type,
180
0
                            hdcp_reg, "unknown (0x%x)"));
181
0
                proto_item_set_generated(it);
182
0
                switch (hdcp_trans->rqst_type) {
183
0
                    case REG_BKSV:
184
0
                        b_ksv = tvb_get_letoh40(tvb,
185
0
                                ptvcursor_current_offset(cursor));
186
0
                        proto_tree_add_uint64_format(hdcp_tree, hf_hdcp_b_ksv,
187
0
                                tvb, ptvcursor_current_offset(cursor), 5,
188
0
                                b_ksv, "B_ksv 0x%010" PRIx64,
189
0
                                b_ksv);
190
0
                        ptvcursor_advance(cursor, 5);
191
0
                        break;
192
0
                    case REG_BCAPS:
193
0
                        ptvcursor_add_no_advance(cursor,
194
0
                                hf_hdcp_hdmi_reserved, 1, ENC_LITTLE_ENDIAN);
195
0
                        ptvcursor_add_no_advance(cursor,
196
0
                                hf_hdcp_repeater, 1, ENC_LITTLE_ENDIAN);
197
0
                        ptvcursor_add_no_advance(cursor,
198
0
                                hf_hdcp_ksv_fifo, 1, ENC_LITTLE_ENDIAN);
199
0
                        ptvcursor_add_no_advance(cursor,
200
0
                                hf_hdcp_fast_trans, 1, ENC_LITTLE_ENDIAN);
201
0
                        ptvcursor_add_no_advance(cursor,
202
0
                                hf_hdcp_features, 1, ENC_LITTLE_ENDIAN);
203
0
                        ptvcursor_add_no_advance(cursor,
204
0
                                hf_hdcp_fast_reauth, 1, ENC_LITTLE_ENDIAN);
205
0
                        break;
206
0
                    case REG_BSTATUS:
207
0
                        ptvcursor_add_no_advance(cursor,
208
0
                                hf_hdcp_hdmi_mode, 2, ENC_LITTLE_ENDIAN);
209
0
                        ptvcursor_add_no_advance(cursor,
210
0
                                hf_hdcp_max_casc_exc, 2, ENC_LITTLE_ENDIAN);
211
0
                        ptvcursor_add_no_advance(cursor,
212
0
                                hf_hdcp_depth, 2, ENC_LITTLE_ENDIAN);
213
0
                        ptvcursor_add_no_advance(cursor,
214
0
                                hf_hdcp_max_devs_exc, 2, ENC_LITTLE_ENDIAN);
215
0
                        ptvcursor_add_no_advance(cursor,
216
0
                                hf_hdcp_downstream, 2, ENC_LITTLE_ENDIAN);
217
0
                        break;
218
0
                }
219
0
            }
220
0
        }
221
222
0
        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
0
            if (tvb_reported_length_remaining(
226
0
                        tvb, ptvcursor_current_offset(cursor)) == 2) {
227
0
                col_append_sep_str(pinfo->cinfo, COL_INFO, NULL,
228
0
                        "send link verification Ri'");
229
0
                ptvcursor_add_no_advance(cursor,
230
0
                        hf_hdcp_link_vfy, 2, ENC_LITTLE_ENDIAN);
231
0
            }
232
0
        }
233
0
    }
234
235
0
    ptvcursor_free(cursor);
236
0
    return tvb_reported_length(tvb);
237
0
}
238
239
240
void
241
proto_register_hdcp(void)
242
15
{
243
15
    static hf_register_info hf[] = {
244
15
        { &hf_hdcp_reg,
245
15
            { "Register offset", "hdcp.reg", FT_UINT8, BASE_HEX,
246
15
                VALS(hdcp_reg), 0, NULL, HFILL } },
247
15
        { &hf_hdcp_resp_in,
248
15
            { "Response In", "hdcp.resp_in", FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_RESPONSE), 0x0,
249
15
                "The response to this request is in this frame", HFILL }},
250
15
        { &hf_hdcp_resp_to,
251
15
            { "Response To", "hdcp.resp_to", FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_REQUEST), 0x0,
252
15
                "This is the response to the request in this frame", HFILL }},
253
15
        { &hf_hdcp_a_ksv,
254
15
            { "Transmitter's key selection vector", "hdcp.a_ksv", FT_UINT40,
255
15
                BASE_HEX, NULL, 0, NULL, HFILL } },
256
15
        { &hf_hdcp_b_ksv,
257
15
            { "Receiver's key selection vector", "hdcp.b_ksv", FT_UINT64,
258
15
                BASE_HEX, NULL, 0, NULL, HFILL } },
259
15
        { &hf_hdcp_an,
260
15
            { "Random number for the session", "hdcp.an", FT_UINT64,
261
15
                BASE_HEX, NULL, 0, NULL, HFILL } },
262
15
        { &hf_hdcp_hdmi_reserved,
263
15
            { "HDMI reserved", "hdcp.hdmi_reserved", FT_UINT8, BASE_DEC,
264
15
                NULL, 0x80, NULL, HFILL } },
265
15
        { &hf_hdcp_repeater,
266
15
            { "Repeater", "hdcp.repeater", FT_UINT8, BASE_DEC,
267
15
                NULL, 0x40, NULL, HFILL } },
268
15
        { &hf_hdcp_ksv_fifo,
269
15
            { "KSV fifo ready", "hdcp.ksv_fifo", FT_UINT8, BASE_DEC,
270
15
                NULL, 0x20, NULL, HFILL } },
271
15
        { &hf_hdcp_fast_trans,
272
15
            { "Support for 400KHz transfers", "hdcp.fast_trans",
273
15
                FT_UINT8, BASE_DEC, NULL, 0x10, NULL, HFILL } },
274
15
        { &hf_hdcp_features,
275
15
            { "Support for additional features", "hdcp.features",
276
15
                FT_UINT8, BASE_DEC, NULL, 0x02, NULL, HFILL } },
277
15
        { &hf_hdcp_fast_reauth,
278
15
            { "Support for fast re-authentication", "hdcp.fast_reauth",
279
15
                FT_UINT8, BASE_DEC, NULL, 0x01, NULL, HFILL } },
280
15
        { &hf_hdcp_hdmi_mode,
281
15
            { "HDMI mode", "hdcp.hdmi_mode",
282
15
                FT_UINT16, BASE_DEC, NULL, 0x1000, NULL, HFILL } },
283
15
        { &hf_hdcp_max_casc_exc,
284
15
            { "Maximum cascading depth exceeded", "hdcp.max_casc_exc",
285
15
                FT_UINT16, BASE_DEC, NULL, 0x0800, NULL, HFILL } },
286
15
        { &hf_hdcp_depth,
287
15
            { "Repeater cascade depth", "hdcp.depth",
288
15
                FT_UINT16, BASE_DEC, NULL, 0x0700, NULL, HFILL } },
289
15
        { &hf_hdcp_max_devs_exc,
290
15
            { "Maximum number of devices exceeded", "hdcp.max_devs_exc",
291
15
                FT_UINT16, BASE_DEC, NULL, 0x0080, NULL, HFILL } },
292
15
        { &hf_hdcp_downstream,
293
15
            { "Number of downstream receivers", "hdcp.downstream",
294
15
                FT_UINT16, BASE_DEC, NULL, 0x007F, NULL, HFILL } },
295
15
        { &hf_hdcp_link_vfy,
296
15
            { "Link verification response Ri'", "hdcp.link_vfy",
297
15
                FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL } }
298
15
    };
299
300
15
    static int *ett[] = {
301
15
        &ett_hdcp
302
15
    };
303
304
305
15
    proto_hdcp = proto_register_protocol("High bandwidth Digital Content Protection", "HDCP", "hdcp");
306
307
15
    proto_register_field_array(proto_hdcp, hf, array_length(hf));
308
15
    proto_register_subtree_array(ett, array_length(ett));
309
310
15
    register_dissector("hdcp", dissect_hdcp, proto_hdcp);
311
312
15
    transactions = wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
313
15
}
314
315
/*
316
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
317
 *
318
 * Local variables:
319
 * c-basic-offset: 4
320
 * tab-width: 8
321
 * indent-tabs-mode: nil
322
 * End:
323
 *
324
 * vi: set shiftwidth=4 tabstop=8 expandtab:
325
 * :indentSize=4:tabSize=8:noTabs=true:
326
 */