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                                                     = -1;
41 static int hf_btsap_header_msg_id                                          = -1;
42 static int hf_btsap_header_number_of_parameters                            = -1;
43 static int hf_btsap_header_reserved                                        = -1;
44 static int hf_btsap_parameter                                              = -1;
45 static int hf_btsap_parameter_id                                           = -1;
46 static int hf_btsap_parameter_reserved                                     = -1;
47 static int hf_btsap_parameter_length                                       = -1;
48 static int hf_btsap_parameter_padding                                      = -1;
49 static int hf_btsap_parameter_max_msg_size                                 = -1;
50 static int hf_btsap_parameter_connection_status                            = -1;
51 static int hf_btsap_parameter_result_code                                  = -1;
52 static int hf_btsap_parameter_disconnection_type                           = -1;
53 static int hf_btsap_parameter_status_change                                = -1;
54 static int hf_btsap_parameter_transport_protocol                           = -1;
55 static int hf_btsap_parameter_card_reader_status_card_reader_identity      = -1;
56 static int hf_btsap_parameter_card_reader_status_card_reader_removable     = -1;
57 static int hf_btsap_parameter_card_reader_status_card_reader_present       = -1;
58 static int hf_btsap_parameter_card_reader_status_card_reader_present_lower = -1;
59 static int hf_btsap_parameter_card_reader_status_card_present              = -1;
60 static int hf_btsap_parameter_card_reader_status_card_powered              = -1;
61 
62 static int hf_btsap_data                                                   = -1;
63 
64 static gint ett_btsap                                                      = -1;
65 static gint ett_btsap_parameter                                            = -1;
66 
67 static expert_field ei_btsap_parameter_error = EI_INIT;
68 static expert_field ei_unexpected_data = EI_INIT;
69 
70 static gint 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 gint
dissect_parameter(tvbuff_t * tvb,packet_info * pinfo,proto_tree * top_tree,proto_tree * tree,gint offset,guint8 * parameter,gint * parameter_offset)165 dissect_parameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *top_tree,
166         proto_tree *tree, gint offset, guint8 *parameter, gint *parameter_offset)
167 {
168     proto_item  *parameter_item;
169     proto_item  *pitem;
170     proto_tree  *ptree;
171     tvbuff_t    *next_tvb;
172     guint        parameter_id;
173     guint        parameter_length;
174     guint        parameter_padding_length;
175     guint        padding_length;
176     guint        length;
177     guint16      max_msg_size;
178     guint8       connection_status;
179     guint8       result_code;
180     guint8       disconnection_type;
181     guint8       status_change;
182     guint8       transport_protocol;
183 
184     parameter_id = tvb_get_guint8(tvb, offset);
185     parameter_length = tvb_get_ntohs(tvb, offset + 2);
186     parameter_padding_length = parameter_length % 4;
187     if (parameter_padding_length > 0)
188         parameter_padding_length = 4 - parameter_padding_length;
189 
190     parameter_item = proto_tree_add_none_format(tree, hf_btsap_parameter, tvb, offset,
191             2 + 2 + parameter_length + parameter_padding_length, "Parameter: %s: ",
192             val_to_str_const(parameter_id, parameter_id_vals, "Unknown ParameterID"));
193     ptree = proto_item_add_subtree(parameter_item, ett_btsap_parameter);
194 
195     proto_tree_add_item(ptree, hf_btsap_parameter_id, tvb, offset, 1, ENC_BIG_ENDIAN);
196 
197     col_append_fstr(pinfo->cinfo, COL_INFO, " - %s", val_to_str_const(parameter_id, parameter_id_vals, "Unknown ParameterID"));
198     offset += 1;
199 
200     proto_tree_add_item(ptree, hf_btsap_parameter_reserved, tvb, offset, 1, ENC_BIG_ENDIAN);
201     offset += 1;
202 
203     pitem = proto_tree_add_item(ptree, hf_btsap_parameter_length, tvb, offset, 2, ENC_BIG_ENDIAN);
204 
205     proto_item_append_text(pitem, " (in 4 bytes sections, padding length: %u)", parameter_padding_length);
206     offset += 2;
207 
208     switch(parameter_id) {
209         case 0x00: /* MaxMsgSize */
210             proto_tree_add_item(ptree, hf_btsap_parameter_max_msg_size, tvb, offset, 2, ENC_BIG_ENDIAN);
211             max_msg_size = tvb_get_ntohs(tvb, offset);
212             proto_item_append_text(parameter_item, "%u", max_msg_size);
213             col_append_fstr(pinfo->cinfo, COL_INFO, ": %u", max_msg_size);
214             length = 2;
215             padding_length = 2;
216             break;
217         case 0x01: /* ConnectionStatus */
218             proto_tree_add_item(ptree, hf_btsap_parameter_connection_status, tvb, offset, 1, ENC_BIG_ENDIAN);
219             connection_status = tvb_get_guint8(tvb, offset);
220             proto_item_append_text(parameter_item, "%s", val_to_str_const(connection_status, connection_status_vals, "Unknown"));
221             col_append_fstr(pinfo->cinfo, COL_INFO, ": %s", val_to_str_const(connection_status, connection_status_vals, "Unknown"));
222             length = 1;
223             padding_length = 3;
224             break;
225         case 0x02: /* ResultCode */
226             proto_tree_add_item(ptree, hf_btsap_parameter_result_code, tvb, offset, 1, ENC_BIG_ENDIAN);
227             result_code = tvb_get_guint8(tvb, offset);
228             proto_item_append_text(parameter_item, "%s", val_to_str_const(result_code, result_code_vals, "Unknown"));
229             col_append_fstr(pinfo->cinfo, COL_INFO, ": %s", val_to_str_const(result_code, result_code_vals, "Unknown"));
230             length = 1;
231             padding_length = 3;
232             break;
233         case 0x03: /* DisconnectionType */
234             proto_tree_add_item(ptree, hf_btsap_parameter_disconnection_type, tvb, offset, 1, ENC_BIG_ENDIAN);
235             disconnection_type = tvb_get_guint8(tvb, offset);
236             proto_item_append_text(parameter_item, "%s", val_to_str_const(disconnection_type, disconnection_type_vals, "Unknown"));
237             col_append_fstr(pinfo->cinfo, COL_INFO, ": %s", val_to_str_const(disconnection_type, disconnection_type_vals, "Unknown"));
238             length = 1;
239             padding_length = 3;
240             break;
241         case 0x04: /* CommandAPDU */
242             /* GSM 11.11 */
243             if (gsm_sim_cmd_handle && top_dissect != TOP_DISSECT_OFF) {
244                 next_tvb = tvb_new_subset_length(tvb, offset, parameter_length);
245                 col_append_str(pinfo->cinfo, COL_INFO, ": ");
246 
247                 if (top_dissect == TOP_DISSECT_INTERNAL) {
248                     call_dissector(gsm_sim_cmd_handle, next_tvb, pinfo, ptree);
249                 } else {
250                     col_clear(pinfo->cinfo, COL_INFO);
251                     call_dissector(gsm_sim_cmd_handle, next_tvb, pinfo, top_tree);
252                 }
253             } else {
254                 proto_tree_add_item(ptree, hf_btsap_data, tvb, offset, parameter_length, ENC_NA);
255             }
256 
257             length = parameter_length;
258             padding_length = parameter_padding_length;
259             break;
260         case 0x05: /* ResponseAPDU */
261             /* GSM 11.11 or ISO/IEC 7816-4; depend of TRANSFER_APDU_REQ */
262             if (gsm_sim_resp_handle && top_dissect != TOP_DISSECT_OFF) {
263                 next_tvb = tvb_new_subset_length(tvb, offset, parameter_length);
264                 col_append_str(pinfo->cinfo, COL_INFO, ": ");
265 
266                 if (top_dissect == TOP_DISSECT_INTERNAL) {
267                     call_dissector(gsm_sim_resp_handle, next_tvb, pinfo, ptree);
268                 } else {
269                     col_clear(pinfo->cinfo, COL_INFO);
270                     call_dissector(gsm_sim_resp_handle, next_tvb, pinfo, top_tree);
271                 }
272             } else {
273                 proto_tree_add_item(ptree, hf_btsap_data, tvb, offset, parameter_length, ENC_NA);
274             }
275 
276             length = parameter_length;
277             padding_length = parameter_padding_length;
278             break;
279         case 0x06: /* ATR */
280             /* ISO/IEC 7816-3 */
281             if (iso7816_atr_handle && top_dissect != TOP_DISSECT_OFF) {
282                 next_tvb = tvb_new_subset_length(tvb, offset, parameter_length);
283                 col_append_str(pinfo->cinfo, COL_INFO, ": ");
284 
285                 if (top_dissect == TOP_DISSECT_INTERNAL) {
286                     call_dissector(iso7816_atr_handle, next_tvb, pinfo, ptree);
287                 } else {
288                     col_clear(pinfo->cinfo, COL_INFO);
289                     call_dissector(iso7816_atr_handle, next_tvb, pinfo, top_tree);
290                 }
291             } else {
292                 proto_tree_add_item(ptree, hf_btsap_data, tvb, offset, parameter_length, ENC_NA);
293             }
294 
295             length = parameter_length;
296             padding_length = parameter_padding_length;
297             break;
298         case 0x07: /* CardReaderStatus */
299             /* 3GPP TS 11.14 */
300             proto_tree_add_item(ptree, hf_btsap_parameter_card_reader_status_card_powered, tvb, offset, 1, ENC_BIG_ENDIAN);
301             proto_tree_add_item(ptree, hf_btsap_parameter_card_reader_status_card_present, tvb, offset, 1, ENC_BIG_ENDIAN);
302             proto_tree_add_item(ptree, hf_btsap_parameter_card_reader_status_card_reader_present_lower, tvb, offset, 1, ENC_BIG_ENDIAN);
303             proto_tree_add_item(ptree, hf_btsap_parameter_card_reader_status_card_reader_present, tvb, offset, 1, ENC_BIG_ENDIAN);
304             proto_tree_add_item(ptree, hf_btsap_parameter_card_reader_status_card_reader_removable, tvb, offset, 1, ENC_BIG_ENDIAN);
305             proto_tree_add_item(ptree, hf_btsap_parameter_card_reader_status_card_reader_identity, tvb, offset, 1, ENC_BIG_ENDIAN);
306             length = 1;
307             padding_length = 3;
308             break;
309         case 0x08: /* StatusChange */
310             proto_tree_add_item(ptree, hf_btsap_parameter_status_change, tvb, offset, 1, ENC_BIG_ENDIAN);
311             status_change = tvb_get_guint8(tvb, offset);
312             proto_item_append_text(parameter_item, "%s", val_to_str_const(status_change, status_change_vals, "Unknown"));
313             col_append_fstr(pinfo->cinfo, COL_INFO, ": %s", val_to_str_const(status_change, status_change_vals, "Unknown"));
314             length = 1;
315             padding_length = 3;
316             break;
317         case 0x09: /* TransportProtocol */
318             proto_tree_add_item(ptree, hf_btsap_parameter_transport_protocol, tvb, offset, 1, ENC_BIG_ENDIAN);
319             transport_protocol = tvb_get_guint8(tvb, offset);
320             proto_item_append_text(parameter_item, "%u", transport_protocol);
321             col_append_fstr(pinfo->cinfo, COL_INFO, ": %u", transport_protocol);
322             length = 1;
323             padding_length = 3;
324             break;
325         case 0x10: /* CommandAPDU7816 */
326             /* ISO/IEC 7816-4 */
327             if (gsm_sim_cmd_handle && top_dissect != TOP_DISSECT_OFF) {
328                 next_tvb = tvb_new_subset_length(tvb, offset, parameter_length);
329                 col_append_str(pinfo->cinfo, COL_INFO, ": ");
330 
331                 if (top_dissect == TOP_DISSECT_INTERNAL) {
332                     call_dissector(gsm_sim_cmd_handle, next_tvb, pinfo, ptree);
333                 } else {
334                     col_clear(pinfo->cinfo, COL_INFO);
335                     call_dissector(gsm_sim_cmd_handle, next_tvb, pinfo, top_tree);
336                 }
337             } else {
338                 proto_tree_add_item(ptree, hf_btsap_data, tvb, offset, parameter_length, ENC_NA);
339             }
340 
341             length = parameter_length;
342             padding_length = parameter_padding_length;
343             break;
344         default:
345             proto_tree_add_item(ptree, hf_btsap_data, tvb, offset, parameter_length, ENC_NA);
346             length = parameter_length;
347             padding_length = parameter_padding_length;
348     }
349 
350     *parameter = parameter_id;
351     *parameter_offset = offset;
352 
353     if (length != parameter_length || padding_length != parameter_padding_length) {
354         /* Malformed frame */
355         expert_add_info_format(pinfo, pitem, &ei_btsap_parameter_error,
356             "Parameter Length does not meet content length");
357     }
358 
359     offset += parameter_length;
360 
361     if (parameter_padding_length > 0) {
362         pitem = proto_tree_add_item(ptree, hf_btsap_parameter_padding, tvb, offset, parameter_padding_length, ENC_NA);
363         proto_item_append_text(pitem, " (length %d)", parameter_padding_length);
364         offset += parameter_padding_length;
365     }
366 
367     return offset;
368 }
369 
370 static gint
dissect_btsap(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data _U_)371 dissect_btsap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
372 {
373     proto_item  *ti;
374     proto_tree  *btsap_tree;
375     guint        offset = 0;
376     guint        msg_id;
377     guint        number_of_parameters;
378     guint8      *parameters;
379     gint        *parameter_offsets;
380     guint        parameters_check = 0;
381     guint        required_parameters = 0;
382     guint        i_parameter;
383     guint        i_next_parameter;
384 
385     ti = proto_tree_add_item(tree, proto_btsap, tvb, offset, -1, ENC_NA);
386     btsap_tree = proto_item_add_subtree(ti, ett_btsap);
387 
388     col_set_str(pinfo->cinfo, COL_PROTOCOL, "SAP");
389 
390     switch (pinfo->p2p_dir) {
391         case P2P_DIR_SENT:
392             col_set_str(pinfo->cinfo, COL_INFO, "Sent ");
393             break;
394         case P2P_DIR_RECV:
395             col_set_str(pinfo->cinfo, COL_INFO, "Rcvd ");
396             break;
397         default:
398             col_set_str(pinfo->cinfo, COL_INFO, "UnknownDirection ");
399             break;
400     }
401 
402     proto_tree_add_item(btsap_tree, hf_btsap_header_msg_id, tvb, offset, 1, ENC_BIG_ENDIAN);
403     msg_id = tvb_get_guint8(tvb, offset);
404     col_append_str(pinfo->cinfo, COL_INFO, val_to_str_const(msg_id, msg_id_vals, "Unknown MsgID"));
405     offset += 1;
406 
407     proto_tree_add_item(btsap_tree, hf_btsap_header_number_of_parameters, tvb, offset, 1, ENC_BIG_ENDIAN);
408     number_of_parameters = tvb_get_guint8(tvb, offset);
409     offset += 1;
410 
411     proto_tree_add_item(btsap_tree, hf_btsap_header_reserved, tvb, offset, 2, ENC_BIG_ENDIAN);
412     offset += 2;
413 
414     parameters = (guint8 *) wmem_alloc(pinfo->pool, number_of_parameters * sizeof(guint8));
415     parameter_offsets = (gint *) wmem_alloc0(pinfo->pool, number_of_parameters * sizeof(guint));
416 
417     for (i_parameter = 0; i_parameter < number_of_parameters; ++i_parameter) {
418         offset = dissect_parameter(tvb, pinfo, tree, btsap_tree, offset, &parameters[i_parameter], &parameter_offsets[i_parameter]);
419     }
420 
421     /* detect invalid data  */
422     switch(msg_id) {
423         case 0x02: /* DISCONNECT_REQ */
424         case 0x03: /* DISCONNECT_RESP */
425         case 0x07: /* TRANSFER_ATR_REQ */
426         case 0x09: /* POWER_SIM_OFF_REQ */
427         case 0x0B: /* POWER_SIM_ON_REQ */
428         case 0x0D: /* RESET_SIM_REQ */
429         case 0x0F: /* TRANSFER_CARD_READER_STATUS_REQ */
430         case 0x12: /* ERROR_RESP */
431             required_parameters = 0;
432             break;
433         case 0x0A: /* POWER_SIM_OFF_RESP */
434         case 0x0C: /* POWER_SIM_ON_RESP */
435         case 0x0E: /* RESET_SIM_RESP */
436         case 0x14: /* SET_TRANSPORT_PROTOCOL_RESP */
437             /* Parameters: 1 - ResultCode */
438             required_parameters = 1;
439             for (i_parameter = 0; i_parameter < number_of_parameters; ++i_parameter) {
440                 if (parameters[i_parameter] == PARAMETER_RESULT_CODE) ++parameters_check;
441             }
442             break;
443         case 0x00: /* CONNECT_REQ */
444             /* 1 - MaxMsgSize */
445             required_parameters = 1;
446             for (i_parameter = 0; i_parameter < number_of_parameters; ++i_parameter) {
447                 if (parameters[i_parameter] == PARAMETER_MAX_MSG_SIZE) ++parameters_check;
448             }
449             break;
450         case 0x01: /* CONNECT_RESP */
451             /* Parameters: 1..2 - ConnectionStatus, MaxMsgSize (if error cannot fulfill) */
452             required_parameters = 1;
453             for (i_parameter = 0; i_parameter < number_of_parameters; ++i_parameter) {
454                 if (parameters[i_parameter] == PARAMETER_CONNECTION_STATUS) {
455                     if (tvb_get_guint8(tvb, parameter_offsets[i_parameter]) != 0x00) {
456                         for (i_next_parameter = 0; i_next_parameter < number_of_parameters; ++i_next_parameter) {
457                             if (parameters[i_next_parameter] == PARAMETER_MAX_MSG_SIZE) {
458                                 ++parameters_check;
459                                 required_parameters = 2;
460                             }
461                         }
462                     }
463                     ++parameters_check;
464                 }
465             }
466             break;
467         case 0x04: /* DISCONNECT_IND */
468             /* Parameters: 1 - DisconnectionType */
469             required_parameters = 1;
470             for (i_parameter = 0; i_parameter < number_of_parameters; ++i_parameter) {
471                 if (parameters[i_parameter] == PARAMETER_DISCONNECTION_TYPE) ++parameters_check;
472             }
473             break;
474         case 0x05: /* TRANSFER_APDU_REQ */
475             /* Parameters: 1 - CommandAPU or CommandAPU7816 */
476             required_parameters = 1;
477             for (i_parameter = 0; i_parameter < number_of_parameters; ++i_parameter) {
478                 if (parameters[i_parameter] == PARAMETER_COMMAND_APDU ||
479                         parameters[i_parameter] == PARAMETER_COMMAND_APDU_7816)
480                     ++parameters_check;
481             }
482             break;
483         case 0x06: /* TRANSFER_APDU_RESP */
484             /* Parameters: 1..2 - ResultCode, ResponseAPDU (if status ok) */
485             required_parameters = 1;
486             for (i_parameter = 0; i_parameter < number_of_parameters; ++i_parameter) {
487                 if (parameters[i_parameter] == PARAMETER_RESULT_CODE) {
488                     if (tvb_get_guint8(tvb, parameter_offsets[i_parameter]) == 0x00) {
489                         for (i_next_parameter = 0; i_next_parameter < number_of_parameters; ++i_next_parameter) {
490                             if (parameters[i_next_parameter] == PARAMETER_RESPONSE_APDU) {
491                                 ++parameters_check;
492                                 required_parameters = 2;
493                             }
494                         }
495                     }
496                     ++parameters_check;
497                 }
498             }
499             break;
500         case 0x08: /* TRANSFER_ATR_RESP */
501             /* Parameters: 1..2 - ResultCode, ATR (if status ok) */
502             required_parameters = 1;
503             for (i_parameter = 0; i_parameter < number_of_parameters; ++i_parameter) {
504                 if (parameters[i_parameter] == PARAMETER_RESULT_CODE) {
505                     if (tvb_get_guint8(tvb, parameter_offsets[i_parameter]) == 0x00) {
506                         for (i_next_parameter = 0; i_next_parameter < number_of_parameters; ++i_next_parameter) {
507                             if (parameters[i_next_parameter] == PARAMETER_ATR) {
508                                 ++parameters_check;
509                                 required_parameters = 2;
510                             }
511                         }
512                     }
513                     ++parameters_check;
514                 }
515             }
516             break;
517         case 0x10: /* TRANSFER_CARD_READER_STATUS_RESP */
518             /* Parameters: 1..2 - ResultCode, CardReaderStatus (if status ok)  */
519             required_parameters = 1;
520             for (i_parameter = 0; i_parameter < number_of_parameters; ++i_parameter) {
521                 if (parameters[i_parameter] == PARAMETER_RESULT_CODE) {
522                     if (tvb_get_guint8(tvb, parameter_offsets[i_parameter]) == 0x00) {
523                         for (i_next_parameter = 0; i_next_parameter < number_of_parameters; ++i_next_parameter) {
524                             if (parameters[i_next_parameter] == PARAMETER_CARD_READER_STATUS) {
525                                 ++parameters_check;
526                                 required_parameters = 2;
527                             }
528                         }
529                     }
530                     ++parameters_check;
531                 }
532             }
533             break;
534         case 0x11: /* STATUS_IND */
535             /* Parameters: 1 - StatusChange */
536             required_parameters = 1;
537             for (i_parameter = 0; i_parameter < number_of_parameters; ++i_parameter) {
538                 if (parameters[i_parameter] == PARAMETER_STATUS_CHANGE) ++parameters_check;
539             }
540             break;
541         case 0x13: /* SET_TRANSPORT_PROTOCOL_REQ */
542             /* Parameters: 1 - TransportProtocol */
543             required_parameters = 1;
544             for (i_parameter = 0; i_parameter < number_of_parameters; ++i_parameter) {
545                 if (parameters[i_parameter] == PARAMETER_TRANSPORT_PROTOCOL) ++parameters_check;
546             }
547             break;
548     }
549 
550     if (parameters_check < required_parameters) {
551         proto_tree_add_expert_format(tree, pinfo, &ei_btsap_parameter_error,
552                                      tvb, offset, 0, "There are no required parameters");
553     } else if (parameters_check > required_parameters) {
554         proto_tree_add_expert_format(tree, pinfo, &ei_btsap_parameter_error,
555                                      tvb, offset, 0, "Invalid parameters");
556     }
557     if (number_of_parameters < required_parameters) {
558         proto_tree_add_expert_format(tree, pinfo, &ei_btsap_parameter_error,
559                                      tvb, offset, 0, "Too few parameters");
560     } else if (number_of_parameters > required_parameters) {
561         proto_tree_add_expert_format(tree, pinfo, &ei_btsap_parameter_error,
562                                      tvb, offset, 0, "Too many parameters");
563     }
564 
565     if (tvb_reported_length(tvb) > offset)
566         proto_tree_add_expert(tree, pinfo, &ei_unexpected_data, tvb, offset, tvb_reported_length_remaining(tvb, offset));
567 
568     return offset;
569 }
570 
571 
572 void
proto_register_btsap(void)573 proto_register_btsap(void)
574 {
575     module_t *module;
576     expert_module_t *expert_btsap;
577 
578     static hf_register_info hf[] = {
579         { &hf_btsap_header_msg_id,
580             { "MsgID",                           "btsap.msg_id",
581             FT_UINT8, BASE_HEX, VALS(msg_id_vals), 0x00,
582             NULL, HFILL }
583         },
584         { &hf_btsap_header_number_of_parameters,
585             { "Number of Parameters",            "btsap.number_of_parameters",
586             FT_UINT8, BASE_HEX, NULL, 0x00,
587             NULL, HFILL }
588         },
589         { &hf_btsap_header_reserved,
590             { "reserved",                        "btsap.reserved",
591             FT_UINT16, BASE_HEX, NULL, 0x00,
592             NULL, HFILL }
593         },
594         { &hf_btsap_parameter,
595             { "Parameter",                    "btsap.parameter",
596             FT_NONE, BASE_NONE, NULL, 0x00,
597             NULL, HFILL }
598         },
599         { &hf_btsap_parameter_id,
600             { "Parameter ID",                    "btsap.parameter_id",
601             FT_UINT8, BASE_HEX, VALS(parameter_id_vals), 0x00,
602             NULL, HFILL }
603         },
604         { &hf_btsap_parameter_reserved,
605             { "reserved",                        "btsap.parameter.reserved",
606             FT_UINT8, BASE_HEX, NULL, 0x00,
607             NULL, HFILL }
608         },
609         { &hf_btsap_parameter_length,
610             { "Parameter Length",                "btsap.parameter.length",
611             FT_UINT16, BASE_DEC, NULL, 0x00,
612             NULL, HFILL }
613         },
614         { &hf_btsap_parameter_padding,
615             { "Parameter Padding",               "btsap.parameter.padding",
616             FT_NONE, BASE_NONE, NULL, 0x00,
617             NULL, HFILL }
618         },
619         { &hf_btsap_parameter_max_msg_size,
620             { "Max Msg Size",                    "btsap.parameter.max_msg_size",
621             FT_UINT16, BASE_DEC, NULL, 0x00,
622             NULL, HFILL }
623         },
624         { &hf_btsap_parameter_connection_status,
625             { "Connection Status",               "btsap.parameter.connection_status",
626             FT_UINT8, BASE_HEX, VALS(connection_status_vals), 0x00,
627             NULL, HFILL }
628         },
629         { &hf_btsap_parameter_result_code,
630             { "Result Code",                     "btsap.parameter.result_code",
631             FT_UINT8, BASE_HEX, VALS(result_code_vals), 0x00,
632             NULL, HFILL }
633         },
634         { &hf_btsap_parameter_disconnection_type,
635             { "Disconnection Type",              "btsap.parameter.disconnection_type",
636             FT_UINT8, BASE_HEX, VALS(disconnection_type_vals), 0x00,
637             NULL, HFILL }
638         },
639         { &hf_btsap_parameter_card_reader_status_card_reader_identity,
640             { "Identify of Card Reader",         "btsap.parameter.card_reader_status.card_reader_identity",
641             FT_UINT8, BASE_HEX, NULL, 0x03,
642             NULL, HFILL }
643         },
644         { &hf_btsap_parameter_card_reader_status_card_reader_removable,
645             { "Card Reader is Removable",        "btsap.parameter.card_reader_status.card_reader_removable",
646             FT_BOOLEAN, 8, NULL, 0x08,
647             NULL, HFILL }
648         },
649         { &hf_btsap_parameter_card_reader_status_card_reader_present,
650             { "Card Reader is Present",          "btsap.parameter.card_reader_status.card_reader_present",
651             FT_BOOLEAN, 8, NULL, 0x10,
652             NULL, HFILL }
653         },
654         { &hf_btsap_parameter_card_reader_status_card_reader_present_lower,
655             { "Card Reader Present is ID-1 Size","btsap.parameter.card_reader_status.card_reader_present_lower",
656             FT_BOOLEAN, 8, NULL, 0x20,
657             NULL, HFILL }
658         },
659         { &hf_btsap_parameter_card_reader_status_card_present,
660             { "Card is Present in Reader",       "btsap.parameter.card_reader_status.card_present",
661             FT_BOOLEAN, 8, NULL, 0x40,
662             NULL, HFILL }
663         },
664         { &hf_btsap_parameter_card_reader_status_card_powered,
665             { "Card in Reader is Powered",       "btsap.parameter.card_reader_status.card_powered",
666             FT_BOOLEAN, 8, NULL, 0x80,
667             NULL, HFILL }
668         },
669         { &hf_btsap_parameter_status_change,
670             { "Status Change",                   "btsap.parameter.status_change",
671             FT_UINT8, BASE_HEX, VALS(status_change_vals), 0x00,
672             NULL, HFILL }
673         },
674         { &hf_btsap_parameter_transport_protocol,
675             { "Transport Protocol",              "btsap.parameter.transport_protocol",
676             FT_UINT8, BASE_HEX, NULL, 0x00,
677             NULL, HFILL }
678         },
679 
680         { &hf_btsap_data,
681             { "Data",                            "btsap.data",
682             FT_NONE, BASE_NONE, NULL, 0x0,
683             NULL, HFILL }
684         },
685 
686     };
687 
688     static gint *ett[] = {
689         &ett_btsap,
690         &ett_btsap_parameter
691     };
692 
693     static ei_register_info ei[] = {
694         { &ei_btsap_parameter_error, { "btsap.parameter_error", PI_PROTOCOL, PI_WARN, "Parameter error", EXPFILL }},
695         { &ei_unexpected_data,       { "btsap.unexpected_data", PI_PROTOCOL, PI_WARN, "Unexpected_data", EXPFILL }},
696     };
697 
698     proto_btsap = proto_register_protocol("Bluetooth SAP Profile", "BT SAP", "btsap");
699     btsap_handle = register_dissector("btsap", dissect_btsap, proto_btsap);
700 
701     proto_register_field_array(proto_btsap, hf, array_length(hf));
702     proto_register_subtree_array(ett, array_length(ett));
703     expert_btsap = expert_register_protocol(proto_btsap);
704     expert_register_field_array(expert_btsap, ei, array_length(ei));
705 
706     module = prefs_register_protocol_subtree("Bluetooth", proto_btsap, NULL);
707     prefs_register_static_text_preference(module, "sap.version",
708             "Bluetooth Profile SAP version: 1.1",
709             "Version of protocol supported by this dissector.");
710 
711     prefs_register_enum_preference(module, "sap.top_dissect",
712             "Dissecting the top protocols", "Dissecting the top protocols",
713             &top_dissect, pref_top_dissect, FALSE);
714 }
715 
716 
717 void
proto_reg_handoff_btsap(void)718 proto_reg_handoff_btsap(void)
719 {
720     gsm_sim_cmd_handle = find_dissector_add_dependency("gsm_sim.command", proto_btsap);
721     gsm_sim_resp_handle = find_dissector_add_dependency("gsm_sim.response", proto_btsap);
722     iso7816_atr_handle = find_dissector_add_dependency("iso7816.atr", proto_btsap);
723 
724     dissector_add_string("bluetooth.uuid",  "112d", btsap_handle);
725 
726     dissector_add_for_decode_as("btrfcomm.dlci", btsap_handle);
727 }
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  */
741