/src/wireshark/epan/dissectors/packet-btavctp.c
Line | Count | Source |
1 | | /* packet-btavctp.c |
2 | | * Routines for Bluetooth AVCTP 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 <epan/decode_as.h> |
19 | | #include <epan/proto_data.h> |
20 | | |
21 | | #include "packet-bluetooth.h" |
22 | | #include "packet-btl2cap.h" |
23 | | #include "packet-btsdp.h" |
24 | | #include "packet-btavctp.h" |
25 | | |
26 | 5 | #define PACKET_TYPE_SINGLE 0x00 |
27 | 4 | #define PACKET_TYPE_START 0x01 |
28 | 0 | #define PACKET_TYPE_CONTINUE 0x02 |
29 | 0 | #define PACKET_TYPE_END 0x03 |
30 | | |
31 | | int proto_btavctp; |
32 | | |
33 | | static int hf_btavctp_transaction; |
34 | | static int hf_btavctp_packet_type; |
35 | | static int hf_btavctp_cr; |
36 | | static int hf_btavctp_ipid; |
37 | | static int hf_btavctp_rfa; |
38 | | static int hf_btavctp_pid; |
39 | | static int hf_btavctp_number_of_packets; |
40 | | |
41 | | static int ett_btavctp; |
42 | | |
43 | | static expert_field ei_btavctp_unexpected_frame; |
44 | | static expert_field ei_btavctp_invalid_profile; |
45 | | |
46 | | static dissector_handle_t btavctp_handle; |
47 | | |
48 | | typedef struct _fragment_t { |
49 | | unsigned length; |
50 | | uint8_t *data; |
51 | | } fragment_t; |
52 | | |
53 | | typedef struct _fragments_t { |
54 | | uint32_t interface_id; |
55 | | uint32_t adapter_id; |
56 | | uint32_t chandle; |
57 | | uint32_t psm; |
58 | | uint32_t count; |
59 | | uint32_t number_of_packets; |
60 | | uint32_t pid; |
61 | | wmem_tree_t *fragment; |
62 | | } fragments_t; |
63 | | |
64 | | static wmem_tree_t *reassembling; |
65 | | static fragments_t *fragments; |
66 | | |
67 | | static const value_string packet_type_vals[] = { |
68 | | { PACKET_TYPE_SINGLE, "Single" }, |
69 | | { PACKET_TYPE_START, "Start" }, |
70 | | { PACKET_TYPE_CONTINUE, "Continue" }, |
71 | | { PACKET_TYPE_END, "End" }, |
72 | | { 0, NULL } |
73 | | }; |
74 | | |
75 | | static const value_string cr_vals[] = { |
76 | | { 0x00, "Command" }, |
77 | | { 0x01, "Response" }, |
78 | | { 0, NULL } |
79 | | }; |
80 | | |
81 | | static const value_string ipid_vals[] = { |
82 | | { 0x00, "Profile OK" }, |
83 | | { 0x01, "Invalid profile" }, |
84 | | { 0, NULL } |
85 | | }; |
86 | | |
87 | | void proto_register_btavctp(void); |
88 | | void proto_reg_handoff_btavctp(void); |
89 | | |
90 | | static int |
91 | | dissect_btavctp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) |
92 | 1 | { |
93 | 1 | proto_item *ti; |
94 | 1 | proto_tree *btavctp_tree; |
95 | 1 | proto_item *pitem; |
96 | 1 | proto_item *ipid_item = NULL; |
97 | 1 | btavctp_data_t *avctp_data; |
98 | 1 | tvbuff_t *next_tvb; |
99 | 1 | int offset = 0; |
100 | 1 | unsigned packet_type; |
101 | 1 | unsigned cr; |
102 | 1 | unsigned pid = 0; |
103 | 1 | unsigned transaction; |
104 | 1 | unsigned number_of_packets = 0; |
105 | 1 | unsigned length; |
106 | 1 | unsigned i_frame; |
107 | 1 | bool ipid = false; |
108 | 1 | uint32_t interface_id; |
109 | 1 | uint32_t adapter_id; |
110 | 1 | uint32_t chandle; |
111 | 1 | uint32_t psm; |
112 | 1 | int previous_proto; |
113 | | |
114 | 1 | previous_proto = (GPOINTER_TO_INT(wmem_list_frame_data(wmem_list_frame_prev(wmem_list_tail(pinfo->layers))))); |
115 | 1 | if (previous_proto == proto_btl2cap) { |
116 | 1 | btl2cap_data_t *l2cap_data; |
117 | | |
118 | 1 | l2cap_data = (btl2cap_data_t *) data; |
119 | | |
120 | 1 | interface_id = l2cap_data->interface_id; |
121 | 1 | adapter_id = l2cap_data->adapter_id; |
122 | 1 | chandle = l2cap_data->chandle; |
123 | 1 | psm = l2cap_data->psm; |
124 | 1 | } else { |
125 | 0 | interface_id = HCI_INTERFACE_DEFAULT; |
126 | 0 | adapter_id = HCI_ADAPTER_DEFAULT; |
127 | 0 | chandle = 0; |
128 | 0 | psm = 0; |
129 | 0 | } |
130 | | |
131 | 1 | ti = proto_tree_add_item(tree, proto_btavctp, tvb, offset, tvb_captured_length_remaining(tvb, offset), ENC_NA); |
132 | 1 | btavctp_tree = proto_item_add_subtree(ti, ett_btavctp); |
133 | | |
134 | 1 | col_set_str(pinfo->cinfo, COL_PROTOCOL, "AVCTP"); |
135 | 1 | col_clear(pinfo->cinfo, COL_INFO); |
136 | | |
137 | 1 | switch (pinfo->p2p_dir) { |
138 | 0 | case P2P_DIR_SENT: |
139 | 0 | col_set_str(pinfo->cinfo, COL_INFO, "Sent "); |
140 | 0 | break; |
141 | 0 | case P2P_DIR_RECV: |
142 | 0 | col_set_str(pinfo->cinfo, COL_INFO, "Rcvd "); |
143 | 0 | break; |
144 | 1 | default: |
145 | 1 | col_set_str(pinfo->cinfo, COL_INFO, "UnknownDirection "); |
146 | 1 | break; |
147 | 1 | } |
148 | | |
149 | 1 | proto_tree_add_item(btavctp_tree, hf_btavctp_transaction, tvb, offset, 1, ENC_BIG_ENDIAN); |
150 | 1 | pitem = proto_tree_add_item(btavctp_tree, hf_btavctp_packet_type, tvb, offset, 1, ENC_BIG_ENDIAN); |
151 | 1 | proto_tree_add_item(btavctp_tree, hf_btavctp_cr, tvb, offset, 1, ENC_BIG_ENDIAN); |
152 | 1 | transaction = tvb_get_uint8(tvb, offset) >> 4; |
153 | 1 | packet_type = (tvb_get_uint8(tvb, offset) & 0x0C) >> 2; |
154 | 1 | cr = (tvb_get_uint8(tvb, offset) & 0x02) >> 1 ; |
155 | | |
156 | 1 | if (packet_type == PACKET_TYPE_SINGLE || packet_type == PACKET_TYPE_START) { |
157 | 1 | ipid_item = proto_tree_add_item(btavctp_tree, hf_btavctp_ipid, tvb, offset, 1, ENC_BIG_ENDIAN); |
158 | 1 | ipid = tvb_get_uint8(tvb, offset) & 0x01; |
159 | 1 | } else { |
160 | 0 | proto_tree_add_item(btavctp_tree, hf_btavctp_rfa, tvb, offset, 1, ENC_BIG_ENDIAN); |
161 | 0 | } |
162 | 1 | offset++; |
163 | | |
164 | 1 | if (packet_type == PACKET_TYPE_START) { |
165 | 1 | proto_tree_add_item(btavctp_tree, hf_btavctp_number_of_packets, tvb, offset, 1, ENC_BIG_ENDIAN); |
166 | 1 | number_of_packets = tvb_get_uint8(tvb, offset); |
167 | 1 | offset++; |
168 | 1 | } |
169 | | |
170 | 1 | if (packet_type == PACKET_TYPE_SINGLE || packet_type == PACKET_TYPE_START) { |
171 | 1 | proto_tree_add_item(btavctp_tree, hf_btavctp_pid, tvb, offset, 2, ENC_BIG_ENDIAN); |
172 | 1 | pid = tvb_get_ntohs(tvb, offset); |
173 | | |
174 | 1 | if (p_get_proto_data(pinfo->pool, pinfo, proto_bluetooth, PROTO_DATA_BLUETOOTH_SERVICE_UUID ) == NULL) { |
175 | 1 | char *value_data; |
176 | 1 | bluetooth_uuid_t uuid; |
177 | | |
178 | 1 | uuid.size = 2; |
179 | 1 | uuid.bt_uuid = pid; |
180 | 1 | uuid.data[0] = pid >> 8; |
181 | 1 | uuid.data[1] = pid & 0xFF; |
182 | | |
183 | 1 | value_data = wmem_strdup(wmem_file_scope(), print_numeric_bluetooth_uuid(pinfo->pool, &uuid)); |
184 | | |
185 | 1 | p_add_proto_data(pinfo->pool, pinfo, proto_bluetooth, PROTO_DATA_BLUETOOTH_SERVICE_UUID, value_data); |
186 | 1 | } |
187 | 1 | offset +=2; |
188 | 1 | } |
189 | | |
190 | 1 | col_append_fstr(pinfo->cinfo, COL_INFO, "%s - Transaction: %u, PacketType: %s", |
191 | 1 | val_to_str_const(cr, cr_vals, "unknown CR"), transaction, |
192 | 1 | val_to_str_const(packet_type, packet_type_vals, "unknown packet type")); |
193 | | |
194 | 1 | if (ipid) { |
195 | 0 | expert_add_info(pinfo, ipid_item, &ei_btavctp_invalid_profile); |
196 | 0 | col_append_sep_str(pinfo->cinfo, COL_INFO, NULL, "Invalid profile"); |
197 | 0 | if (tvb_captured_length_remaining(tvb, offset) == 0) |
198 | 0 | return offset; |
199 | 0 | } |
200 | | |
201 | 1 | avctp_data = wmem_new(pinfo->pool, btavctp_data_t); |
202 | 1 | avctp_data->cr = cr; |
203 | 1 | avctp_data->interface_id = interface_id; |
204 | 1 | avctp_data->adapter_id = adapter_id; |
205 | 1 | avctp_data->chandle = chandle; |
206 | 1 | avctp_data->psm = psm; |
207 | | |
208 | 1 | length = tvb_reported_length_remaining(tvb, offset); |
209 | | |
210 | | /* reassembling */ |
211 | 1 | next_tvb = tvb_new_subset_length(tvb, offset, length); |
212 | 1 | if (packet_type == PACKET_TYPE_SINGLE) { |
213 | 0 | bluetooth_uuid_t uuid; |
214 | |
|
215 | 0 | uuid.size = 2; |
216 | 0 | uuid.bt_uuid = pid; |
217 | 0 | uuid.data[0] = pid >> 8; |
218 | 0 | uuid.data[1] = pid & 0xFF; |
219 | |
|
220 | 0 | if (!dissector_try_string_with_data(bluetooth_uuid_table, print_numeric_bluetooth_uuid(pinfo->pool, &uuid), next_tvb, pinfo, tree, true, avctp_data)) { |
221 | 0 | call_data_dissector(next_tvb, pinfo, tree); |
222 | 0 | } |
223 | |
|
224 | 1 | } else { |
225 | 1 | fragment_t *fragment; |
226 | 1 | wmem_tree_key_t key[6]; |
227 | 1 | uint32_t frame_number; |
228 | | |
229 | 1 | frame_number = pinfo->num; |
230 | | |
231 | 1 | key[0].length = 1; |
232 | 1 | key[0].key = &interface_id; |
233 | 1 | key[1].length = 1; |
234 | 1 | key[1].key = &adapter_id; |
235 | 1 | key[2].length = 1; |
236 | 1 | key[2].key = &chandle; |
237 | 1 | key[3].length = 1; |
238 | 1 | key[3].key = &psm; |
239 | 1 | key[4].length = 1; |
240 | 1 | key[4].key = &frame_number; |
241 | 1 | key[5].length = 0; |
242 | 1 | key[5].key = NULL; |
243 | | |
244 | 1 | if (packet_type == PACKET_TYPE_START) { |
245 | 1 | if (!pinfo->fd->visited) { |
246 | 1 | fragment = wmem_new(wmem_file_scope(), fragment_t); |
247 | 1 | fragment->length = length; |
248 | 1 | fragment->data = (uint8_t *) wmem_alloc(wmem_file_scope(), fragment->length); |
249 | 1 | tvb_memcpy(tvb, fragment->data, offset, fragment->length); |
250 | | |
251 | 1 | fragments = wmem_new(wmem_file_scope(), fragments_t); |
252 | 1 | fragments->number_of_packets = number_of_packets; |
253 | 1 | fragments->pid = pid; |
254 | | |
255 | 1 | fragments->count = 1; |
256 | 1 | fragments->fragment = wmem_tree_new(wmem_file_scope()); |
257 | 1 | wmem_tree_insert32(fragments->fragment, fragments->count, fragment); |
258 | | |
259 | 1 | fragments->interface_id = interface_id; |
260 | 1 | fragments->adapter_id = adapter_id; |
261 | 1 | fragments->chandle = chandle; |
262 | 1 | fragments->psm = psm; |
263 | | |
264 | 1 | wmem_tree_insert32_array(reassembling, key, fragments); |
265 | | |
266 | 1 | } else { |
267 | 0 | fragments = (fragments_t *)wmem_tree_lookup32_array_le(reassembling, key); |
268 | 0 | if (!(fragments && fragments->interface_id == interface_id && |
269 | 0 | fragments->adapter_id == adapter_id && |
270 | 0 | fragments->chandle == chandle && |
271 | 0 | fragments->psm == psm)) |
272 | 0 | fragments = NULL; |
273 | 0 | } |
274 | | |
275 | 1 | call_data_dissector(next_tvb, pinfo, tree); |
276 | | |
277 | 1 | } else if (packet_type == PACKET_TYPE_CONTINUE) { |
278 | 0 | fragments = (fragments_t *)wmem_tree_lookup32_array_le(reassembling, key); |
279 | 0 | if (!(fragments && fragments->interface_id == interface_id && |
280 | 0 | fragments->adapter_id == adapter_id && |
281 | 0 | fragments->chandle == chandle && |
282 | 0 | fragments->psm == psm)) |
283 | 0 | fragments = NULL; |
284 | |
|
285 | 0 | if (!pinfo->fd->visited && fragments != NULL) { |
286 | 0 | fragment = wmem_new(wmem_file_scope(), fragment_t); |
287 | 0 | fragment->length = length; |
288 | 0 | fragment->data = (uint8_t *) wmem_alloc(wmem_file_scope(), fragment->length); |
289 | 0 | tvb_memcpy(tvb, fragment->data, offset, fragment->length); |
290 | |
|
291 | 0 | fragments->count++; |
292 | 0 | wmem_tree_insert32(fragments->fragment, fragments->count, fragment); |
293 | |
|
294 | 0 | fragments->interface_id = interface_id; |
295 | 0 | fragments->adapter_id = adapter_id; |
296 | 0 | fragments->chandle = chandle; |
297 | 0 | fragments->psm = psm; |
298 | |
|
299 | 0 | frame_number = pinfo->num; |
300 | |
|
301 | 0 | key[0].length = 1; |
302 | 0 | key[0].key = &interface_id; |
303 | 0 | key[1].length = 1; |
304 | 0 | key[1].key = &adapter_id; |
305 | 0 | key[2].length = 1; |
306 | 0 | key[2].key = &chandle; |
307 | 0 | key[3].length = 1; |
308 | 0 | key[3].key = &psm; |
309 | 0 | key[4].length = 1; |
310 | 0 | key[4].key = &frame_number; |
311 | 0 | key[5].length = 0; |
312 | 0 | key[5].key = NULL; |
313 | |
|
314 | 0 | wmem_tree_insert32_array(reassembling, key, fragments); |
315 | 0 | } |
316 | |
|
317 | 0 | call_data_dissector(next_tvb, pinfo, tree); |
318 | |
|
319 | 0 | } else if (packet_type == PACKET_TYPE_END) { |
320 | |
|
321 | 0 | fragments = (fragments_t *)wmem_tree_lookup32_array_le(reassembling, key); |
322 | 0 | if (!(fragments && fragments->interface_id == interface_id && |
323 | 0 | fragments->adapter_id == adapter_id && |
324 | 0 | fragments->chandle == chandle && |
325 | 0 | fragments->psm == psm)) |
326 | 0 | fragments = NULL; |
327 | |
|
328 | 0 | if (!pinfo->fd->visited && fragments != NULL) { |
329 | 0 | fragment = wmem_new(wmem_file_scope(), fragment_t); |
330 | 0 | fragment->length = length; |
331 | 0 | fragment->data = (uint8_t *) wmem_alloc(wmem_file_scope(), fragment->length); |
332 | 0 | tvb_memcpy(tvb, fragment->data, offset, fragment->length); |
333 | |
|
334 | 0 | fragments->count++; |
335 | 0 | wmem_tree_insert32(fragments->fragment, fragments->count, fragment); |
336 | |
|
337 | 0 | fragments->interface_id = interface_id; |
338 | 0 | fragments->adapter_id = adapter_id; |
339 | 0 | fragments->chandle = chandle; |
340 | 0 | fragments->psm = psm; |
341 | |
|
342 | 0 | frame_number = pinfo->num; |
343 | |
|
344 | 0 | key[0].length = 1; |
345 | 0 | key[0].key = &interface_id; |
346 | 0 | key[1].length = 1; |
347 | 0 | key[1].key = &adapter_id; |
348 | 0 | key[2].length = 1; |
349 | 0 | key[2].key = &chandle; |
350 | 0 | key[3].length = 1; |
351 | 0 | key[3].key = &psm; |
352 | 0 | key[4].length = 1; |
353 | 0 | key[4].key = &frame_number; |
354 | 0 | key[5].length = 0; |
355 | 0 | key[5].key = NULL; |
356 | |
|
357 | 0 | wmem_tree_insert32_array(reassembling, key, fragments); |
358 | 0 | } |
359 | |
|
360 | 0 | length = 0; |
361 | 0 | if (!fragments || fragments->count != fragments->number_of_packets) { |
362 | 0 | expert_add_info(pinfo, pitem, &ei_btavctp_unexpected_frame); |
363 | 0 | call_data_dissector(next_tvb, pinfo, tree); |
364 | 0 | } else { |
365 | 0 | uint8_t *reassembled = NULL; |
366 | 0 | bluetooth_uuid_t uuid; |
367 | |
|
368 | 0 | for (i_frame = 1; i_frame <= fragments->count; ++i_frame) { |
369 | 0 | fragment = (fragment_t *)wmem_tree_lookup32_le(fragments->fragment, i_frame); |
370 | 0 | if (fragment) { |
371 | 0 | reassembled = (uint8_t*)wmem_realloc(pinfo->pool, reassembled, length + fragment->length); |
372 | 0 | memcpy(reassembled + length, fragment->data, fragment->length); |
373 | 0 | length += fragment->length; |
374 | 0 | } |
375 | 0 | } |
376 | |
|
377 | 0 | next_tvb = tvb_new_child_real_data(tvb, reassembled, length, length); |
378 | 0 | add_new_data_source(pinfo, next_tvb, "Reassembled AVCTP"); |
379 | |
|
380 | 0 | uuid.size = 2; |
381 | 0 | uuid.bt_uuid = fragments->pid; |
382 | 0 | uuid.data[0] = fragments->pid >> 8; |
383 | 0 | uuid.data[1] = fragments->pid & 0xFF; |
384 | |
|
385 | 0 | if (!dissector_try_string_with_data(bluetooth_uuid_table, print_numeric_bluetooth_uuid(pinfo->pool, &uuid), next_tvb, pinfo, tree, true, avctp_data)) { |
386 | 0 | call_data_dissector(next_tvb, pinfo, tree); |
387 | 0 | } |
388 | 0 | } |
389 | |
|
390 | 0 | fragments = NULL; |
391 | 0 | } else { |
392 | 0 | call_data_dissector(next_tvb, pinfo, tree); |
393 | 0 | } |
394 | 1 | } |
395 | | |
396 | 1 | return offset; |
397 | 1 | } |
398 | | |
399 | | void |
400 | | proto_register_btavctp(void) |
401 | 14 | { |
402 | 14 | module_t *module; |
403 | 14 | expert_module_t* expert_btavctp; |
404 | | |
405 | 14 | static hf_register_info hf[] = { |
406 | 14 | { &hf_btavctp_transaction, |
407 | 14 | { "Transaction", "btavctp.transaction", |
408 | 14 | FT_UINT8, BASE_HEX, NULL, 0xF0, |
409 | 14 | NULL, HFILL } |
410 | 14 | }, |
411 | 14 | { &hf_btavctp_packet_type, |
412 | 14 | { "Packet Type", "btavctp.packet_type", |
413 | 14 | FT_UINT8, BASE_HEX, VALS(packet_type_vals), 0x0C, |
414 | 14 | NULL, HFILL } |
415 | 14 | }, |
416 | 14 | { &hf_btavctp_cr, |
417 | 14 | { "C/R", "btavctp.cr", |
418 | 14 | FT_UINT8, BASE_HEX, VALS(cr_vals), 0x02, |
419 | 14 | NULL, HFILL } |
420 | 14 | }, |
421 | 14 | { &hf_btavctp_ipid, |
422 | 14 | { "IPID", "btavctp.ipid", |
423 | 14 | FT_UINT8, BASE_HEX, VALS(ipid_vals), 0x01, |
424 | 14 | NULL, HFILL } |
425 | 14 | }, |
426 | 14 | { &hf_btavctp_rfa, |
427 | 14 | { "RFA", "btavctp.rfa", |
428 | 14 | FT_UINT8, BASE_HEX, NULL, 0x01, |
429 | 14 | NULL, HFILL } |
430 | 14 | }, |
431 | 14 | { &hf_btavctp_pid, |
432 | 14 | { "Profile Identifier", "btavctp.pid", |
433 | 14 | FT_UINT16, BASE_HEX|BASE_EXT_STRING, &bluetooth_uuid_vals_ext, 0x00, |
434 | 14 | NULL, HFILL } |
435 | 14 | }, |
436 | 14 | { &hf_btavctp_number_of_packets, |
437 | 14 | { "Number of packets", "btavctp.nop", |
438 | 14 | FT_UINT8, BASE_DEC, NULL, 0x00, |
439 | 14 | NULL, HFILL } |
440 | 14 | } |
441 | 14 | }; |
442 | | |
443 | 14 | static int *ett[] = { |
444 | 14 | &ett_btavctp |
445 | 14 | }; |
446 | | |
447 | 14 | static ei_register_info ei[] = { |
448 | 14 | { &ei_btavctp_unexpected_frame, { "btavctp.unexpected_frame", PI_PROTOCOL, PI_WARN, "Unexpected frame", EXPFILL }}, |
449 | 14 | { &ei_btavctp_invalid_profile, { "btavctp.invalid_profile", PI_PROTOCOL, PI_NOTE, "Invalid Profile", EXPFILL }}, |
450 | 14 | }; |
451 | | |
452 | | /* Decode As handling */ |
453 | 14 | reassembling = wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope()); |
454 | | |
455 | 14 | proto_btavctp = proto_register_protocol("Bluetooth AVCTP Protocol", "BT AVCTP", "btavctp"); |
456 | 14 | btavctp_handle = register_dissector("btavctp", dissect_btavctp, proto_btavctp); |
457 | | |
458 | 14 | proto_register_field_array(proto_btavctp, hf, array_length(hf)); |
459 | 14 | proto_register_subtree_array(ett, array_length(ett)); |
460 | 14 | expert_btavctp = expert_register_protocol(proto_btavctp); |
461 | 14 | expert_register_field_array(expert_btavctp, ei, array_length(ei)); |
462 | | |
463 | 14 | module = prefs_register_protocol_subtree("Bluetooth", proto_btavctp, NULL); |
464 | 14 | prefs_register_static_text_preference(module, "avctp.version", |
465 | 14 | "Bluetooth Protocol AVCTP version: 1.4", |
466 | 14 | "Version of protocol supported by this dissector."); |
467 | 14 | } |
468 | | |
469 | | |
470 | | void |
471 | | proto_reg_handoff_btavctp(void) |
472 | 14 | { |
473 | 14 | dissector_add_string("bluetooth.uuid", "17", btavctp_handle); |
474 | | |
475 | 14 | dissector_add_uint("btl2cap.psm", BTL2CAP_PSM_AVCTP_CTRL, btavctp_handle); |
476 | 14 | dissector_add_uint("btl2cap.psm", BTL2CAP_PSM_AVCTP_BRWS, btavctp_handle); |
477 | | |
478 | 14 | dissector_add_for_decode_as("btl2cap.cid", btavctp_handle); |
479 | 14 | } |
480 | | |
481 | | /* |
482 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
483 | | * |
484 | | * Local variables: |
485 | | * c-basic-offset: 4 |
486 | | * tab-width: 8 |
487 | | * indent-tabs-mode: nil |
488 | | * End: |
489 | | * |
490 | | * vi: set shiftwidth=4 tabstop=8 expandtab: |
491 | | * :indentSize=4:tabSize=8:noTabs=true: |
492 | | */ |