Coverage Report

Created: 2025-08-04 07:15

/src/wireshark/epan/dissectors/packet-btsap.c
Line
Count
Source (jump to first uncovered line)
1
/* packet-btsap.c
2
 * Routines for Bluetooth SAP dissection
3
 *
4
 * Copyright 2012, Michal Labedzki for Tieto Corporation
5
 *
6
 * Wireshark - Network traffic analyzer
7
 * By Gerald Combs <gerald@wireshark.org>
8
 * Copyright 1998 Gerald Combs
9
 *
10
 * SPDX-License-Identifier: GPL-2.0-or-later
11
 */
12
13
#include "config.h"
14
15
#include <epan/packet.h>
16
#include <epan/prefs.h>
17
#include <epan/expert.h>
18
#include "packet-btsdp.h"
19
20
enum {
21
    TOP_DISSECT_OFF       = 0,
22
    TOP_DISSECT_INTERNAL  = 1,
23
    TOP_DISSECT_TOP       = 2
24
};
25
26
enum {
27
    PARAMETER_MAX_MSG_SIZE                 = 0x00,
28
    PARAMETER_CONNECTION_STATUS            = 0x01,
29
    PARAMETER_RESULT_CODE                  = 0x02,
30
    PARAMETER_DISCONNECTION_TYPE           = 0x03,
31
    PARAMETER_COMMAND_APDU                 = 0x04,
32
    PARAMETER_RESPONSE_APDU                = 0x05,
33
    PARAMETER_ATR                          = 0x06,
34
    PARAMETER_CARD_READER_STATUS           = 0x07,
35
    PARAMETER_STATUS_CHANGE                = 0x08,
36
    PARAMETER_TRANSPORT_PROTOCOL           = 0x09,
37
    PARAMETER_COMMAND_APDU_7816            = 0x10
38
};
39
40
static int proto_btsap;
41
static int hf_btsap_header_msg_id;
42
static int hf_btsap_header_number_of_parameters;
43
static int hf_btsap_header_reserved;
44
static int hf_btsap_parameter;
45
static int hf_btsap_parameter_id;
46
static int hf_btsap_parameter_reserved;
47
static int hf_btsap_parameter_length;
48
static int hf_btsap_parameter_padding;
49
static int hf_btsap_parameter_max_msg_size;
50
static int hf_btsap_parameter_connection_status;
51
static int hf_btsap_parameter_result_code;
52
static int hf_btsap_parameter_disconnection_type;
53
static int hf_btsap_parameter_status_change;
54
static int hf_btsap_parameter_transport_protocol;
55
static int hf_btsap_parameter_card_reader_status_card_reader_identity;
56
static int hf_btsap_parameter_card_reader_status_card_reader_removable;
57
static int hf_btsap_parameter_card_reader_status_card_reader_present;
58
static int hf_btsap_parameter_card_reader_status_card_reader_present_lower;
59
static int hf_btsap_parameter_card_reader_status_card_present;
60
static int hf_btsap_parameter_card_reader_status_card_powered;
61
62
static int hf_btsap_data;
63
64
static int ett_btsap;
65
static int ett_btsap_parameter;
66
67
static expert_field ei_btsap_parameter_error;
68
static expert_field ei_unexpected_data;
69
70
static int top_dissect = TOP_DISSECT_INTERNAL;
71
72
static dissector_handle_t btsap_handle;
73
static dissector_handle_t gsm_sim_cmd_handle;
74
static dissector_handle_t gsm_sim_resp_handle;
75
static dissector_handle_t iso7816_atr_handle;
76
77
static const value_string msg_id_vals[] = {
78
    { 0x00,   "CONNECT_REQ" },
79
    { 0x01,   "CONNECT_RESP" },
80
    { 0x02,   "DISCONNECT_REQ" },
81
    { 0x03,   "DISCONNECT_RESP" },
82
    { 0x04,   "DISCONNECT_IND" },
83
    { 0x05,   "TRANSFER_APDU_REQ" },
84
    { 0x06,   "TRANSFER_APDU_RESP" },
85
    { 0x07,   "TRANSFER_ATR_REQ" },
86
    { 0x08,   "TRANSFER_ATR_RESP" },
87
    { 0x09,   "POWER_SIM_OFF_REQ" },
88
    { 0x0A,   "POWER_SIM_OFF_RESP" },
89
    { 0x0B,   "POWER_SIM_ON_REQ" },
90
    { 0x0C,   "POWER_SIM_ON_RESP" },
91
    { 0x0D,   "RESET_SIM_REQ" },
92
    { 0x0E,   "RESET_SIM_RESP" },
93
    { 0x0F,   "TRANSFER_CARD_READER_STATUS_REQ" },
94
    { 0x10,   "TRANSFER_CARD_READER_STATUS_RESP" },
95
    { 0x11,   "STATUS_IND" },
96
    { 0x12,   "ERROR_RESP" },
97
    { 0x13,   "SET_TRANSPORT_PROTOCOL_REQ" },
98
    { 0x14,   "SET_TRANSPORT_PROTOCOL_RESP" },
99
    { 0, NULL }
100
};
101
102
static const value_string parameter_id_vals[] = {
103
    { 0x00,   "MaxMsgSize" },
104
    { 0x01,   "ConnectionStatus" },
105
    { 0x02,   "ResultCode" },
106
    { 0x03,   "DisconnectionType" },
107
    { 0x04,   "CommandAPDU" },
108
    { 0x05,   "ResponseAPDU" },
109
    { 0x06,   "ATR" },
110
    { 0x07,   "CardReaderStatus" },
111
    { 0x08,   "StatusChange" },
112
    { 0x09,   "TransportProtocol" },
113
    { 0x10,   "CommandAPDU7816" },
114
    { 0, NULL }
115
};
116
117
static const value_string connection_status_vals[] = {
118
    { 0x00,   "OK, Server can fulfill requirements" },
119
    { 0x01,   "Error, Server unable to establish connection" },
120
    { 0x02,   "Error, Server does not support maximum message size" },
121
    { 0x03,   "Error, maximum message size by Client is too small" },
122
    { 0x04,   "OK, ongoing call" },
123
    { 0, NULL }
124
};
125
126
static const value_string result_code_vals[] = {
127
    { 0x00,   "OK, request processed correctly" },
128
    { 0x01,   "Error, no reason defined" },
129
    { 0x02,   "Error, card not accessible" },
130
    { 0x03,   "Error, card (already) powered off" },
131
    { 0x04,   "Error, card removed" },
132
    { 0x05,   "Error, card already powered on" },
133
    { 0x06,   "Error, data no available" },
134
    { 0x07,   "Error, not supported" },
135
    { 0, NULL }
136
};
137
138
static const value_string disconnection_type_vals[] = {
139
    { 0x00,   "Graceful" },
140
    { 0x01,   "Immediate" },
141
    { 0, NULL }
142
};
143
144
static const value_string status_change_vals[] = {
145
    { 0x00,   "Unknown Error" },
146
    { 0x01,   "Card Reset" },
147
    { 0x02,   "Card Not Accessible" },
148
    { 0x03,   "Card Removed" },
149
    { 0x04,   "Card Inserted" },
150
    { 0x05,   "Card Recovered" },
151
    { 0, NULL }
152
};
153
154
static const enum_val_t pref_top_dissect[] = {
155
    { "off",      "off",                                  TOP_DISSECT_OFF },
156
    { "internal", "Put higher dissectors under this one", TOP_DISSECT_INTERNAL },
157
    { "top",      "On top",                               TOP_DISSECT_TOP },
158
    { NULL, NULL, 0 }
159
};
160
161
void proto_register_btsap(void);
162
void proto_reg_handoff_btsap(void);
163
164
static int
165
dissect_parameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *top_tree,
166
        proto_tree *tree, int offset, uint8_t *parameter, int *parameter_offset)
167
630
{
168
630
    proto_item  *parameter_item;
169
630
    proto_item  *pitem;
170
630
    proto_tree  *ptree;
171
630
    tvbuff_t    *next_tvb;
172
630
    unsigned     parameter_id;
173
630
    unsigned     parameter_length;
174
630
    unsigned     parameter_padding_length;
175
630
    unsigned     padding_length;
176
630
    unsigned     length;
177
630
    uint16_t     max_msg_size;
178
630
    uint8_t      connection_status;
179
630
    uint8_t      result_code;
180
630
    uint8_t      disconnection_type;
181
630
    uint8_t      status_change;
182
630
    uint8_t      transport_protocol;
183
184
630
    parameter_id = tvb_get_uint8(tvb, offset);
185
630
    parameter_length = tvb_get_ntohs(tvb, offset + 2);
186
630
    parameter_padding_length = parameter_length % 4;
187
630
    if (parameter_padding_length > 0)
188
233
        parameter_padding_length = 4 - parameter_padding_length;
189
190
630
    parameter_item = proto_tree_add_none_format(tree, hf_btsap_parameter, tvb, offset,
191
630
            2 + 2 + parameter_length + parameter_padding_length, "Parameter: %s: ",
192
630
            val_to_str_const(parameter_id, parameter_id_vals, "Unknown ParameterID"));
193
630
    ptree = proto_item_add_subtree(parameter_item, ett_btsap_parameter);
194
195
630
    proto_tree_add_item(ptree, hf_btsap_parameter_id, tvb, offset, 1, ENC_BIG_ENDIAN);
196
197
630
    col_append_fstr(pinfo->cinfo, COL_INFO, " - %s", val_to_str_const(parameter_id, parameter_id_vals, "Unknown ParameterID"));
198
630
    offset += 1;
199
200
630
    proto_tree_add_item(ptree, hf_btsap_parameter_reserved, tvb, offset, 1, ENC_BIG_ENDIAN);
201
630
    offset += 1;
202
203
630
    pitem = proto_tree_add_item(ptree, hf_btsap_parameter_length, tvb, offset, 2, ENC_BIG_ENDIAN);
204
205
630
    proto_item_append_text(pitem, " (in 4 bytes sections, padding length: %u)", parameter_padding_length);
206
630
    offset += 2;
207
208
630
    switch(parameter_id) {
209
68
        case 0x00: /* MaxMsgSize */
210
68
            proto_tree_add_item(ptree, hf_btsap_parameter_max_msg_size, tvb, offset, 2, ENC_BIG_ENDIAN);
211
68
            max_msg_size = tvb_get_ntohs(tvb, offset);
212
68
            proto_item_append_text(parameter_item, "%u", max_msg_size);
213
68
            col_append_fstr(pinfo->cinfo, COL_INFO, ": %u", max_msg_size);
214
68
            length = 2;
215
68
            padding_length = 2;
216
68
            break;
217
1
        case 0x01: /* ConnectionStatus */
218
1
            proto_tree_add_item(ptree, hf_btsap_parameter_connection_status, tvb, offset, 1, ENC_BIG_ENDIAN);
219
1
            connection_status = tvb_get_uint8(tvb, offset);
220
1
            proto_item_append_text(parameter_item, "%s", val_to_str_const(connection_status, connection_status_vals, "Unknown"));
221
1
            col_append_fstr(pinfo->cinfo, COL_INFO, ": %s", val_to_str_const(connection_status, connection_status_vals, "Unknown"));
222
1
            length = 1;
223
1
            padding_length = 3;
224
1
            break;
225
1
        case 0x02: /* ResultCode */
226
1
            proto_tree_add_item(ptree, hf_btsap_parameter_result_code, tvb, offset, 1, ENC_BIG_ENDIAN);
227
1
            result_code = tvb_get_uint8(tvb, offset);
228
1
            proto_item_append_text(parameter_item, "%s", val_to_str_const(result_code, result_code_vals, "Unknown"));
229
1
            col_append_fstr(pinfo->cinfo, COL_INFO, ": %s", val_to_str_const(result_code, result_code_vals, "Unknown"));
230
1
            length = 1;
231
1
            padding_length = 3;
232
1
            break;
233
6
        case 0x03: /* DisconnectionType */
234
6
            proto_tree_add_item(ptree, hf_btsap_parameter_disconnection_type, tvb, offset, 1, ENC_BIG_ENDIAN);
235
6
            disconnection_type = tvb_get_uint8(tvb, offset);
236
6
            proto_item_append_text(parameter_item, "%s", val_to_str_const(disconnection_type, disconnection_type_vals, "Unknown"));
237
6
            col_append_fstr(pinfo->cinfo, COL_INFO, ": %s", val_to_str_const(disconnection_type, disconnection_type_vals, "Unknown"));
238
6
            length = 1;
239
6
            padding_length = 3;
240
6
            break;
241
3
        case 0x04: /* CommandAPDU */
242
            /* GSM 11.11 */
243
3
            if (gsm_sim_cmd_handle && top_dissect != TOP_DISSECT_OFF) {
244
3
                next_tvb = tvb_new_subset_length(tvb, offset, parameter_length);
245
3
                col_append_str(pinfo->cinfo, COL_INFO, ": ");
246
247
3
                if (top_dissect == TOP_DISSECT_INTERNAL) {
248
3
                    call_dissector(gsm_sim_cmd_handle, next_tvb, pinfo, ptree);
249
3
                } else {
250
0
                    col_clear(pinfo->cinfo, COL_INFO);
251
0
                    call_dissector(gsm_sim_cmd_handle, next_tvb, pinfo, top_tree);
252
0
                }
253
3
            } else {
254
0
                proto_tree_add_item(ptree, hf_btsap_data, tvb, offset, parameter_length, ENC_NA);
255
0
            }
256
257
3
            length = parameter_length;
258
3
            padding_length = parameter_padding_length;
259
3
            break;
260
2
        case 0x05: /* ResponseAPDU */
261
            /* GSM 11.11 or ISO/IEC 7816-4; depend of TRANSFER_APDU_REQ */
262
2
            if (gsm_sim_resp_handle && top_dissect != TOP_DISSECT_OFF) {
263
2
                next_tvb = tvb_new_subset_length(tvb, offset, parameter_length);
264
2
                col_append_str(pinfo->cinfo, COL_INFO, ": ");
265
266
2
                if (top_dissect == TOP_DISSECT_INTERNAL) {
267
2
                    call_dissector(gsm_sim_resp_handle, next_tvb, pinfo, ptree);
268
2
                } else {
269
0
                    col_clear(pinfo->cinfo, COL_INFO);
270
0
                    call_dissector(gsm_sim_resp_handle, next_tvb, pinfo, top_tree);
271
0
                }
272
2
            } else {
273
0
                proto_tree_add_item(ptree, hf_btsap_data, tvb, offset, parameter_length, ENC_NA);
274
0
            }
275
276
2
            length = parameter_length;
277
2
            padding_length = parameter_padding_length;
278
2
            break;
279
3
        case 0x06: /* ATR */
280
            /* ISO/IEC 7816-3 */
281
3
            if (iso7816_atr_handle && top_dissect != TOP_DISSECT_OFF) {
282
3
                next_tvb = tvb_new_subset_length(tvb, offset, parameter_length);
283
3
                col_append_str(pinfo->cinfo, COL_INFO, ": ");
284
285
3
                if (top_dissect == TOP_DISSECT_INTERNAL) {
286
3
                    call_dissector(iso7816_atr_handle, next_tvb, pinfo, ptree);
287
3
                } else {
288
0
                    col_clear(pinfo->cinfo, COL_INFO);
289
0
                    call_dissector(iso7816_atr_handle, next_tvb, pinfo, top_tree);
290
0
                }
291
3
            } else {
292
0
                proto_tree_add_item(ptree, hf_btsap_data, tvb, offset, parameter_length, ENC_NA);
293
0
            }
294
295
3
            length = parameter_length;
296
3
            padding_length = parameter_padding_length;
297
3
            break;
298
3
        case 0x07: /* CardReaderStatus */
299
            /* 3GPP TS 11.14 */
300
3
            proto_tree_add_item(ptree, hf_btsap_parameter_card_reader_status_card_powered, tvb, offset, 1, ENC_BIG_ENDIAN);
301
3
            proto_tree_add_item(ptree, hf_btsap_parameter_card_reader_status_card_present, tvb, offset, 1, ENC_BIG_ENDIAN);
302
3
            proto_tree_add_item(ptree, hf_btsap_parameter_card_reader_status_card_reader_present_lower, tvb, offset, 1, ENC_BIG_ENDIAN);
303
3
            proto_tree_add_item(ptree, hf_btsap_parameter_card_reader_status_card_reader_present, tvb, offset, 1, ENC_BIG_ENDIAN);
304
3
            proto_tree_add_item(ptree, hf_btsap_parameter_card_reader_status_card_reader_removable, tvb, offset, 1, ENC_BIG_ENDIAN);
305
3
            proto_tree_add_item(ptree, hf_btsap_parameter_card_reader_status_card_reader_identity, tvb, offset, 1, ENC_BIG_ENDIAN);
306
3
            length = 1;
307
3
            padding_length = 3;
308
3
            break;
309
1
        case 0x08: /* StatusChange */
310
1
            proto_tree_add_item(ptree, hf_btsap_parameter_status_change, tvb, offset, 1, ENC_BIG_ENDIAN);
311
1
            status_change = tvb_get_uint8(tvb, offset);
312
1
            proto_item_append_text(parameter_item, "%s", val_to_str_const(status_change, status_change_vals, "Unknown"));
313
1
            col_append_fstr(pinfo->cinfo, COL_INFO, ": %s", val_to_str_const(status_change, status_change_vals, "Unknown"));
314
1
            length = 1;
315
1
            padding_length = 3;
316
1
            break;
317
3
        case 0x09: /* TransportProtocol */
318
3
            proto_tree_add_item(ptree, hf_btsap_parameter_transport_protocol, tvb, offset, 1, ENC_BIG_ENDIAN);
319
3
            transport_protocol = tvb_get_uint8(tvb, offset);
320
3
            proto_item_append_text(parameter_item, "%u", transport_protocol);
321
3
            col_append_fstr(pinfo->cinfo, COL_INFO, ": %u", transport_protocol);
322
3
            length = 1;
323
3
            padding_length = 3;
324
3
            break;
325
253
        case 0x10: /* CommandAPDU7816 */
326
            /* ISO/IEC 7816-4 */
327
253
            if (gsm_sim_cmd_handle && top_dissect != TOP_DISSECT_OFF) {
328
253
                next_tvb = tvb_new_subset_length(tvb, offset, parameter_length);
329
253
                col_append_str(pinfo->cinfo, COL_INFO, ": ");
330
331
253
                if (top_dissect == TOP_DISSECT_INTERNAL) {
332
253
                    call_dissector(gsm_sim_cmd_handle, next_tvb, pinfo, ptree);
333
253
                } else {
334
0
                    col_clear(pinfo->cinfo, COL_INFO);
335
0
                    call_dissector(gsm_sim_cmd_handle, next_tvb, pinfo, top_tree);
336
0
                }
337
253
            } else {
338
0
                proto_tree_add_item(ptree, hf_btsap_data, tvb, offset, parameter_length, ENC_NA);
339
0
            }
340
341
253
            length = parameter_length;
342
253
            padding_length = parameter_padding_length;
343
253
            break;
344
271
        default:
345
271
            proto_tree_add_item(ptree, hf_btsap_data, tvb, offset, parameter_length, ENC_NA);
346
271
            length = parameter_length;
347
271
            padding_length = parameter_padding_length;
348
630
    }
349
350
373
    *parameter = parameter_id;
351
373
    *parameter_offset = offset;
352
353
373
    if (length != parameter_length || padding_length != parameter_padding_length) {
354
        /* Malformed frame */
355
83
        expert_add_info_format(pinfo, pitem, &ei_btsap_parameter_error,
356
83
            "Parameter Length does not meet content length");
357
83
    }
358
359
373
    offset += parameter_length;
360
361
373
    if (parameter_padding_length > 0) {
362
41
        pitem = proto_tree_add_item(ptree, hf_btsap_parameter_padding, tvb, offset, parameter_padding_length, ENC_NA);
363
41
        proto_item_append_text(pitem, " (length %d)", parameter_padding_length);
364
41
        offset += parameter_padding_length;
365
41
    }
366
367
373
    return offset;
368
630
}
369
370
static int
371
dissect_btsap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
372
323
{
373
323
    proto_item  *ti;
374
323
    proto_tree  *btsap_tree;
375
323
    unsigned     offset = 0;
376
323
    unsigned     msg_id;
377
323
    unsigned     number_of_parameters;
378
323
    uint8_t     *parameters;
379
323
    int         *parameter_offsets;
380
323
    unsigned     parameters_check = 0;
381
323
    unsigned     required_parameters = 0;
382
323
    unsigned     i_parameter;
383
323
    unsigned     i_next_parameter;
384
385
323
    ti = proto_tree_add_item(tree, proto_btsap, tvb, offset, -1, ENC_NA);
386
323
    btsap_tree = proto_item_add_subtree(ti, ett_btsap);
387
388
323
    col_set_str(pinfo->cinfo, COL_PROTOCOL, "SAP");
389
390
323
    switch (pinfo->p2p_dir) {
391
23
        case P2P_DIR_SENT:
392
23
            col_set_str(pinfo->cinfo, COL_INFO, "Sent ");
393
23
            break;
394
0
        case P2P_DIR_RECV:
395
0
            col_set_str(pinfo->cinfo, COL_INFO, "Rcvd ");
396
0
            break;
397
300
        default:
398
300
            col_set_str(pinfo->cinfo, COL_INFO, "UnknownDirection ");
399
300
            break;
400
323
    }
401
402
323
    proto_tree_add_item(btsap_tree, hf_btsap_header_msg_id, tvb, offset, 1, ENC_BIG_ENDIAN);
403
323
    msg_id = tvb_get_uint8(tvb, offset);
404
323
    col_append_str(pinfo->cinfo, COL_INFO, val_to_str_const(msg_id, msg_id_vals, "Unknown MsgID"));
405
323
    offset += 1;
406
407
323
    proto_tree_add_item(btsap_tree, hf_btsap_header_number_of_parameters, tvb, offset, 1, ENC_BIG_ENDIAN);
408
323
    number_of_parameters = tvb_get_uint8(tvb, offset);
409
323
    offset += 1;
410
411
323
    proto_tree_add_item(btsap_tree, hf_btsap_header_reserved, tvb, offset, 2, ENC_BIG_ENDIAN);
412
323
    offset += 2;
413
414
323
    parameters = (uint8_t *) wmem_alloc(pinfo->pool, number_of_parameters * sizeof(uint8_t));
415
323
    parameter_offsets = (int *) wmem_alloc0(pinfo->pool, number_of_parameters * sizeof(unsigned));
416
417
953
    for (i_parameter = 0; i_parameter < number_of_parameters; ++i_parameter) {
418
630
        offset = dissect_parameter(tvb, pinfo, tree, btsap_tree, offset, &parameters[i_parameter], &parameter_offsets[i_parameter]);
419
630
    }
420
421
    /* detect invalid data  */
422
323
    switch(msg_id) {
423
0
        case 0x02: /* DISCONNECT_REQ */
424
0
        case 0x03: /* DISCONNECT_RESP */
425
0
        case 0x07: /* TRANSFER_ATR_REQ */
426
0
        case 0x09: /* POWER_SIM_OFF_REQ */
427
0
        case 0x0B: /* POWER_SIM_ON_REQ */
428
0
        case 0x0D: /* RESET_SIM_REQ */
429
0
        case 0x0F: /* TRANSFER_CARD_READER_STATUS_REQ */
430
0
        case 0x12: /* ERROR_RESP */
431
0
            required_parameters = 0;
432
0
            break;
433
0
        case 0x0A: /* POWER_SIM_OFF_RESP */
434
0
        case 0x0C: /* POWER_SIM_ON_RESP */
435
0
        case 0x0E: /* RESET_SIM_RESP */
436
1
        case 0x14: /* SET_TRANSPORT_PROTOCOL_RESP */
437
            /* Parameters: 1 - ResultCode */
438
1
            required_parameters = 1;
439
1
            for (i_parameter = 0; i_parameter < number_of_parameters; ++i_parameter) {
440
0
                if (parameters[i_parameter] == PARAMETER_RESULT_CODE) ++parameters_check;
441
0
            }
442
1
            break;
443
11
        case 0x00: /* CONNECT_REQ */
444
            /* 1 - MaxMsgSize */
445
11
            required_parameters = 1;
446
11
            for (i_parameter = 0; i_parameter < number_of_parameters; ++i_parameter) {
447
0
                if (parameters[i_parameter] == PARAMETER_MAX_MSG_SIZE) ++parameters_check;
448
0
            }
449
11
            break;
450
0
        case 0x01: /* CONNECT_RESP */
451
            /* Parameters: 1..2 - ConnectionStatus, MaxMsgSize (if error cannot fulfill) */
452
0
            required_parameters = 1;
453
0
            for (i_parameter = 0; i_parameter < number_of_parameters; ++i_parameter) {
454
0
                if (parameters[i_parameter] == PARAMETER_CONNECTION_STATUS) {
455
0
                    if (tvb_get_uint8(tvb, parameter_offsets[i_parameter]) != 0x00) {
456
0
                        for (i_next_parameter = 0; i_next_parameter < number_of_parameters; ++i_next_parameter) {
457
0
                            if (parameters[i_next_parameter] == PARAMETER_MAX_MSG_SIZE) {
458
0
                                ++parameters_check;
459
0
                                required_parameters = 2;
460
0
                            }
461
0
                        }
462
0
                    }
463
0
                    ++parameters_check;
464
0
                }
465
0
            }
466
0
            break;
467
3
        case 0x04: /* DISCONNECT_IND */
468
            /* Parameters: 1 - DisconnectionType */
469
3
            required_parameters = 1;
470
3
            for (i_parameter = 0; i_parameter < number_of_parameters; ++i_parameter) {
471
0
                if (parameters[i_parameter] == PARAMETER_DISCONNECTION_TYPE) ++parameters_check;
472
0
            }
473
3
            break;
474
0
        case 0x05: /* TRANSFER_APDU_REQ */
475
            /* Parameters: 1 - CommandAPU or CommandAPU7816 */
476
0
            required_parameters = 1;
477
0
            for (i_parameter = 0; i_parameter < number_of_parameters; ++i_parameter) {
478
0
                if (parameters[i_parameter] == PARAMETER_COMMAND_APDU ||
479
0
                        parameters[i_parameter] == PARAMETER_COMMAND_APDU_7816)
480
0
                    ++parameters_check;
481
0
            }
482
0
            break;
483
0
        case 0x06: /* TRANSFER_APDU_RESP */
484
            /* Parameters: 1..2 - ResultCode, ResponseAPDU (if status ok) */
485
0
            required_parameters = 1;
486
0
            for (i_parameter = 0; i_parameter < number_of_parameters; ++i_parameter) {
487
0
                if (parameters[i_parameter] == PARAMETER_RESULT_CODE) {
488
0
                    if (tvb_get_uint8(tvb, parameter_offsets[i_parameter]) == 0x00) {
489
0
                        for (i_next_parameter = 0; i_next_parameter < number_of_parameters; ++i_next_parameter) {
490
0
                            if (parameters[i_next_parameter] == PARAMETER_RESPONSE_APDU) {
491
0
                                ++parameters_check;
492
0
                                required_parameters = 2;
493
0
                            }
494
0
                        }
495
0
                    }
496
0
                    ++parameters_check;
497
0
                }
498
0
            }
499
0
            break;
500
13
        case 0x08: /* TRANSFER_ATR_RESP */
501
            /* Parameters: 1..2 - ResultCode, ATR (if status ok) */
502
13
            required_parameters = 1;
503
13
            for (i_parameter = 0; i_parameter < number_of_parameters; ++i_parameter) {
504
0
                if (parameters[i_parameter] == PARAMETER_RESULT_CODE) {
505
0
                    if (tvb_get_uint8(tvb, parameter_offsets[i_parameter]) == 0x00) {
506
0
                        for (i_next_parameter = 0; i_next_parameter < number_of_parameters; ++i_next_parameter) {
507
0
                            if (parameters[i_next_parameter] == PARAMETER_ATR) {
508
0
                                ++parameters_check;
509
0
                                required_parameters = 2;
510
0
                            }
511
0
                        }
512
0
                    }
513
0
                    ++parameters_check;
514
0
                }
515
0
            }
516
13
            break;
517
3
        case 0x10: /* TRANSFER_CARD_READER_STATUS_RESP */
518
            /* Parameters: 1..2 - ResultCode, CardReaderStatus (if status ok)  */
519
3
            required_parameters = 1;
520
20
            for (i_parameter = 0; i_parameter < number_of_parameters; ++i_parameter) {
521
17
                if (parameters[i_parameter] == PARAMETER_RESULT_CODE) {
522
0
                    if (tvb_get_uint8(tvb, parameter_offsets[i_parameter]) == 0x00) {
523
0
                        for (i_next_parameter = 0; i_next_parameter < number_of_parameters; ++i_next_parameter) {
524
0
                            if (parameters[i_next_parameter] == PARAMETER_CARD_READER_STATUS) {
525
0
                                ++parameters_check;
526
0
                                required_parameters = 2;
527
0
                            }
528
0
                        }
529
0
                    }
530
0
                    ++parameters_check;
531
0
                }
532
17
            }
533
3
            break;
534
3
        case 0x11: /* STATUS_IND */
535
            /* Parameters: 1 - StatusChange */
536
3
            required_parameters = 1;
537
3
            for (i_parameter = 0; i_parameter < number_of_parameters; ++i_parameter) {
538
0
                if (parameters[i_parameter] == PARAMETER_STATUS_CHANGE) ++parameters_check;
539
0
            }
540
3
            break;
541
3
        case 0x13: /* SET_TRANSPORT_PROTOCOL_REQ */
542
            /* Parameters: 1 - TransportProtocol */
543
3
            required_parameters = 1;
544
3
            for (i_parameter = 0; i_parameter < number_of_parameters; ++i_parameter) {
545
0
                if (parameters[i_parameter] == PARAMETER_TRANSPORT_PROTOCOL) ++parameters_check;
546
0
            }
547
3
            break;
548
323
    }
549
550
38
    if (parameters_check < required_parameters) {
551
37
        proto_tree_add_expert_format(tree, pinfo, &ei_btsap_parameter_error,
552
37
                                     tvb, offset, 0, "There are no required parameters");
553
37
    } else if (parameters_check > required_parameters) {
554
0
        proto_tree_add_expert_format(tree, pinfo, &ei_btsap_parameter_error,
555
0
                                     tvb, offset, 0, "Invalid parameters");
556
0
    }
557
38
    if (number_of_parameters < required_parameters) {
558
35
        proto_tree_add_expert_format(tree, pinfo, &ei_btsap_parameter_error,
559
35
                                     tvb, offset, 0, "Too few parameters");
560
35
    } else if (number_of_parameters > required_parameters) {
561
1
        proto_tree_add_expert_format(tree, pinfo, &ei_btsap_parameter_error,
562
1
                                     tvb, offset, 0, "Too many parameters");
563
1
    }
564
565
38
    if (tvb_reported_length(tvb) > offset)
566
37
        proto_tree_add_expert(tree, pinfo, &ei_unexpected_data, tvb, offset, tvb_reported_length_remaining(tvb, offset));
567
568
38
    return offset;
569
323
}
570
571
572
void
573
proto_register_btsap(void)
574
14
{
575
14
    module_t *module;
576
14
    expert_module_t *expert_btsap;
577
578
14
    static hf_register_info hf[] = {
579
14
        { &hf_btsap_header_msg_id,
580
14
            { "MsgID",                           "btsap.msg_id",
581
14
            FT_UINT8, BASE_HEX, VALS(msg_id_vals), 0x00,
582
14
            NULL, HFILL }
583
14
        },
584
14
        { &hf_btsap_header_number_of_parameters,
585
14
            { "Number of Parameters",            "btsap.number_of_parameters",
586
14
            FT_UINT8, BASE_HEX, NULL, 0x00,
587
14
            NULL, HFILL }
588
14
        },
589
14
        { &hf_btsap_header_reserved,
590
14
            { "reserved",                        "btsap.reserved",
591
14
            FT_UINT16, BASE_HEX, NULL, 0x00,
592
14
            NULL, HFILL }
593
14
        },
594
14
        { &hf_btsap_parameter,
595
14
            { "Parameter",                    "btsap.parameter",
596
14
            FT_NONE, BASE_NONE, NULL, 0x00,
597
14
            NULL, HFILL }
598
14
        },
599
14
        { &hf_btsap_parameter_id,
600
14
            { "Parameter ID",                    "btsap.parameter_id",
601
14
            FT_UINT8, BASE_HEX, VALS(parameter_id_vals), 0x00,
602
14
            NULL, HFILL }
603
14
        },
604
14
        { &hf_btsap_parameter_reserved,
605
14
            { "reserved",                        "btsap.parameter.reserved",
606
14
            FT_UINT8, BASE_HEX, NULL, 0x00,
607
14
            NULL, HFILL }
608
14
        },
609
14
        { &hf_btsap_parameter_length,
610
14
            { "Parameter Length",                "btsap.parameter.length",
611
14
            FT_UINT16, BASE_DEC, NULL, 0x00,
612
14
            NULL, HFILL }
613
14
        },
614
14
        { &hf_btsap_parameter_padding,
615
14
            { "Parameter Padding",               "btsap.parameter.padding",
616
14
            FT_NONE, BASE_NONE, NULL, 0x00,
617
14
            NULL, HFILL }
618
14
        },
619
14
        { &hf_btsap_parameter_max_msg_size,
620
14
            { "Max Msg Size",                    "btsap.parameter.max_msg_size",
621
14
            FT_UINT16, BASE_DEC, NULL, 0x00,
622
14
            NULL, HFILL }
623
14
        },
624
14
        { &hf_btsap_parameter_connection_status,
625
14
            { "Connection Status",               "btsap.parameter.connection_status",
626
14
            FT_UINT8, BASE_HEX, VALS(connection_status_vals), 0x00,
627
14
            NULL, HFILL }
628
14
        },
629
14
        { &hf_btsap_parameter_result_code,
630
14
            { "Result Code",                     "btsap.parameter.result_code",
631
14
            FT_UINT8, BASE_HEX, VALS(result_code_vals), 0x00,
632
14
            NULL, HFILL }
633
14
        },
634
14
        { &hf_btsap_parameter_disconnection_type,
635
14
            { "Disconnection Type",              "btsap.parameter.disconnection_type",
636
14
            FT_UINT8, BASE_HEX, VALS(disconnection_type_vals), 0x00,
637
14
            NULL, HFILL }
638
14
        },
639
14
        { &hf_btsap_parameter_card_reader_status_card_reader_identity,
640
14
            { "Identify of Card Reader",         "btsap.parameter.card_reader_status.card_reader_identity",
641
14
            FT_UINT8, BASE_HEX, NULL, 0x03,
642
14
            NULL, HFILL }
643
14
        },
644
14
        { &hf_btsap_parameter_card_reader_status_card_reader_removable,
645
14
            { "Card Reader is Removable",        "btsap.parameter.card_reader_status.card_reader_removable",
646
14
            FT_BOOLEAN, 8, NULL, 0x08,
647
14
            NULL, HFILL }
648
14
        },
649
14
        { &hf_btsap_parameter_card_reader_status_card_reader_present,
650
14
            { "Card Reader is Present",          "btsap.parameter.card_reader_status.card_reader_present",
651
14
            FT_BOOLEAN, 8, NULL, 0x10,
652
14
            NULL, HFILL }
653
14
        },
654
14
        { &hf_btsap_parameter_card_reader_status_card_reader_present_lower,
655
14
            { "Card Reader Present is ID-1 Size","btsap.parameter.card_reader_status.card_reader_present_lower",
656
14
            FT_BOOLEAN, 8, NULL, 0x20,
657
14
            NULL, HFILL }
658
14
        },
659
14
        { &hf_btsap_parameter_card_reader_status_card_present,
660
14
            { "Card is Present in Reader",       "btsap.parameter.card_reader_status.card_present",
661
14
            FT_BOOLEAN, 8, NULL, 0x40,
662
14
            NULL, HFILL }
663
14
        },
664
14
        { &hf_btsap_parameter_card_reader_status_card_powered,
665
14
            { "Card in Reader is Powered",       "btsap.parameter.card_reader_status.card_powered",
666
14
            FT_BOOLEAN, 8, NULL, 0x80,
667
14
            NULL, HFILL }
668
14
        },
669
14
        { &hf_btsap_parameter_status_change,
670
14
            { "Status Change",                   "btsap.parameter.status_change",
671
14
            FT_UINT8, BASE_HEX, VALS(status_change_vals), 0x00,
672
14
            NULL, HFILL }
673
14
        },
674
14
        { &hf_btsap_parameter_transport_protocol,
675
14
            { "Transport Protocol",              "btsap.parameter.transport_protocol",
676
14
            FT_UINT8, BASE_HEX, NULL, 0x00,
677
14
            NULL, HFILL }
678
14
        },
679
680
14
        { &hf_btsap_data,
681
14
            { "Data",                            "btsap.data",
682
14
            FT_NONE, BASE_NONE, NULL, 0x0,
683
14
            NULL, HFILL }
684
14
        },
685
686
14
    };
687
688
14
    static int *ett[] = {
689
14
        &ett_btsap,
690
14
        &ett_btsap_parameter
691
14
    };
692
693
14
    static ei_register_info ei[] = {
694
14
        { &ei_btsap_parameter_error, { "btsap.parameter_error", PI_PROTOCOL, PI_WARN, "Parameter error", EXPFILL }},
695
14
        { &ei_unexpected_data,       { "btsap.unexpected_data", PI_PROTOCOL, PI_WARN, "Unexpected_data", EXPFILL }},
696
14
    };
697
698
14
    proto_btsap = proto_register_protocol("Bluetooth SAP Profile", "BT SAP", "btsap");
699
14
    btsap_handle = register_dissector("btsap", dissect_btsap, proto_btsap);
700
701
14
    proto_register_field_array(proto_btsap, hf, array_length(hf));
702
14
    proto_register_subtree_array(ett, array_length(ett));
703
14
    expert_btsap = expert_register_protocol(proto_btsap);
704
14
    expert_register_field_array(expert_btsap, ei, array_length(ei));
705
706
14
    module = prefs_register_protocol_subtree("Bluetooth", proto_btsap, NULL);
707
14
    prefs_register_static_text_preference(module, "sap.version",
708
14
            "Bluetooth Profile SAP version: 1.1",
709
14
            "Version of protocol supported by this dissector.");
710
711
14
    prefs_register_enum_preference(module, "sap.top_dissect",
712
14
            "Dissecting the top protocols", "Dissecting the top protocols",
713
14
            &top_dissect, pref_top_dissect, false);
714
14
}
715
716
717
void
718
proto_reg_handoff_btsap(void)
719
14
{
720
14
    gsm_sim_cmd_handle = find_dissector_add_dependency("gsm_sim.command", proto_btsap);
721
14
    gsm_sim_resp_handle = find_dissector_add_dependency("gsm_sim.response", proto_btsap);
722
14
    iso7816_atr_handle = find_dissector_add_dependency("iso7816.atr", proto_btsap);
723
724
14
    dissector_add_string("bluetooth.uuid",  "112d", btsap_handle);
725
726
14
    dissector_add_for_decode_as("btrfcomm.dlci", btsap_handle);
727
14
}
728
729
/*
730
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
731
 *
732
 * Local variables:
733
 * c-basic-offset: 4
734
 * tab-width: 8
735
 * indent-tabs-mode: nil
736
 * End:
737
 *
738
 * vi: set shiftwidth=4 tabstop=8 expandtab:
739
 * :indentSize=4:tabSize=8:noTabs=true:
740
 */