/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, ¶meters[i_parameter], ¶meter_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 | | */ |