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