HACK: pinfo->private_data points to smb_info again
[wireshark-wip.git] / epan / dissectors / packet-bthci_acl.c
blobc48ea26ee25a515e4285e783441fc4fa7a9b0e83
1 /* TODO mix direction bit into the chandle tree lookup so we can handle when fragments sent in both directions simultaneously on the same chandle */
3 /* packet-bthci_acl.c
4 * Routines for the Bluetooth ACL dissection
5 * Copyright 2002, Christoph Scholz <scholz@cs.uni-bonn.de>
6 * From: http://affix.sourceforge.net/archive/ethereal_affix-3.patch
8 * Refactored for wireshark checkin
9 * Ronnie Sahlberg 2006
11 * $Id$
13 * Wireshark - Network traffic analyzer
14 * By Gerald Combs <gerald@wireshark.org>
15 * Copyright 1998 Gerald Combs
17 * This program is free software; you can redistribute it and/or
18 * modify it under the terms of the GNU General Public License
19 * as published by the Free Software Foundation; either version 2
20 * of the License, or (at your option) any later version.
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
29 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
32 #include "config.h"
34 #include <epan/packet.h>
35 #include <epan/prefs.h>
36 #include <epan/wmem/wmem.h>
38 #include "packet-bluetooth-hci.h"
39 #include "packet-bthci_acl.h"
41 /* Initialize the protocol and registered fields */
42 static int proto_bthci_acl = -1;
43 static int hf_bthci_acl_chandle = -1;
44 static int hf_bthci_acl_pb_flag = -1;
45 static int hf_bthci_acl_bc_flag = -1;
46 static int hf_bthci_acl_length = -1;
47 /* static int hf_bthci_acl_data = -1; */
48 static int hf_bthci_acl_continuation_to = -1;
49 static int hf_bthci_acl_reassembled_in = -1;
51 /* Initialize the subtree pointers */
52 static gint ett_bthci_acl = -1;
54 static dissector_handle_t btl2cap_handle = NULL;
56 static gboolean acl_reassembly = TRUE;
58 typedef struct _multi_fragment_pdu_t {
59 guint32 first_frame;
60 guint32 last_frame;
61 guint16 tot_len;
62 char *reassembled;
63 int cur_off; /* counter used by reassembly */
64 } multi_fragment_pdu_t;
66 typedef struct _chandle_data_t {
67 wmem_tree_t *start_fragments; /* indexed by pinfo->fd->num */
68 guint32 interface_id;
69 guint32 adapter_id;
70 guint32 chandle;
71 } chandle_data_t;
73 static wmem_tree_t *chandle_tree = NULL;
75 static const value_string pb_flag_vals[] = {
76 { 0, "First Non-automatically Flushable Packet" },
77 { 1, "Continuing Fragment" },
78 { 2, "First Automatically Flushable Packet" },
79 { 0, NULL }
82 static const value_string bc_flag_vals[] = {
83 { 0, "Point-To-Point" },
84 { 1, "Active Broadcast" },
85 { 2, "Piconet Broadcast" },
86 { 0, NULL }
89 void proto_register_bthci_acl(void);
90 void proto_reg_handoff_bthci_acl(void);
92 /* Code to actually dissect the packets */
93 static gint
94 dissect_bthci_acl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
96 proto_item *ti;
97 proto_tree *bthci_acl_tree;
98 guint16 flags;
99 guint16 length;
100 gboolean fragmented;
101 gint offset = 0;
102 guint16 pb_flag, l2cap_length = 0;
103 tvbuff_t *next_tvb;
104 bthci_acl_data_t *acl_data;
105 chandle_data_t *chandle_data;
106 hci_data_t *hci_data;
107 wmem_tree_key_t key[5];
108 guint32 k_connection_handle;
109 guint32 k_frame_number;
110 guint32 k_interface_id;
111 guint32 k_adapter_id;
112 remote_bdaddr_t *remote_bdaddr;
113 const gchar *localhost_name;
114 guint8 localhost_bdaddr[6];
115 const gchar *localhost_ether_addr;
116 gchar *localhost_addr_name;
117 gint localhost_length;
118 localhost_bdaddr_entry_t *localhost_bdaddr_entry;
119 localhost_name_entry_t *localhost_name_entry;
121 ti = proto_tree_add_item(tree, proto_bthci_acl, tvb, offset, -1, ENC_NA);
122 bthci_acl_tree = proto_item_add_subtree(ti, ett_bthci_acl);
124 switch (pinfo->p2p_dir) {
125 case P2P_DIR_SENT:
126 col_set_str(pinfo->cinfo, COL_INFO, "Sent ");
127 break;
128 case P2P_DIR_RECV:
129 col_set_str(pinfo->cinfo, COL_INFO, "Rcvd ");
130 break;
131 default:
132 col_add_fstr(pinfo->cinfo, COL_INFO, "Unknown direction %d ",
133 pinfo->p2p_dir);
134 break;
137 col_set_str(pinfo->cinfo, COL_PROTOCOL, "HCI_ACL");
139 hci_data = (hci_data_t *) data;
140 DISSECTOR_ASSERT(hci_data);
142 flags = tvb_get_letohs(tvb, offset);
143 pb_flag = (flags & 0x3000) >> 12;
144 proto_tree_add_item(bthci_acl_tree, hf_bthci_acl_chandle, tvb, offset, 2, ENC_LITTLE_ENDIAN);
145 proto_tree_add_item(bthci_acl_tree, hf_bthci_acl_pb_flag, tvb, offset, 2, ENC_LITTLE_ENDIAN);
146 proto_tree_add_item(bthci_acl_tree, hf_bthci_acl_bc_flag, tvb, offset, 2, ENC_LITTLE_ENDIAN);
147 offset += 2;
149 acl_data = wmem_new(wmem_packet_scope(), bthci_acl_data_t);
151 acl_data->interface_id = hci_data->interface_id;
152 acl_data->adapter_id = hci_data->adapter_id;
153 acl_data->chandle = flags & 0x0fff;
154 acl_data->remote_bd_addr_oui = 0;
155 acl_data->remote_bd_addr_id = 0;
157 k_interface_id = hci_data->interface_id;
158 k_adapter_id = hci_data->adapter_id;
159 k_connection_handle = flags & 0x0fff;
160 k_frame_number = pinfo->fd->num;
162 key[0].length = 1;
163 key[0].key = &k_interface_id;
164 key[1].length = 1;
165 key[1].key = &k_adapter_id;
166 key[2].length = 1;
167 key[2].key = &k_connection_handle;
168 key[3].length = 1;
169 key[3].key = &k_frame_number;
170 key[4].length = 0;
171 key[4].key = NULL;
173 /* remote bdaddr and name */
174 remote_bdaddr = (remote_bdaddr_t *)wmem_tree_lookup32_array_le(hci_data->chandle_to_bdaddr_table, key);
175 if (remote_bdaddr && remote_bdaddr->interface_id == hci_data->interface_id &&
176 remote_bdaddr->adapter_id == hci_data->adapter_id &&
177 remote_bdaddr->chandle == (flags & 0x0fff)) {
178 guint32 k_bd_addr_oui;
179 guint32 k_bd_addr_id;
180 guint32 bd_addr_oui;
181 guint32 bd_addr_id;
182 device_name_t *device_name;
183 const gchar *remote_name;
184 const gchar *remote_ether_addr;
185 gchar *remote_addr_name;
186 gint remote_length;
188 bd_addr_oui = remote_bdaddr->bd_addr[0] << 16 | remote_bdaddr->bd_addr[1] << 8 | remote_bdaddr->bd_addr[2];
189 bd_addr_id = remote_bdaddr->bd_addr[3] << 16 | remote_bdaddr->bd_addr[4] << 8 | remote_bdaddr->bd_addr[5];
191 acl_data->remote_bd_addr_oui = bd_addr_oui;
192 acl_data->remote_bd_addr_id = bd_addr_id;
194 k_bd_addr_oui = bd_addr_oui;
195 k_bd_addr_id = bd_addr_id;
196 k_frame_number = pinfo->fd->num;
198 key[0].length = 1;
199 key[0].key = &k_bd_addr_id;
200 key[1].length = 1;
201 key[1].key = &k_bd_addr_oui;
202 key[2].length = 1;
203 key[2].key = &k_frame_number;
204 key[3].length = 0;
205 key[3].key = NULL;
207 device_name = (device_name_t *)wmem_tree_lookup32_array_le(hci_data->bdaddr_to_name_table, key);
208 if (device_name && device_name->bd_addr_oui == bd_addr_oui && device_name->bd_addr_id == bd_addr_id)
209 remote_name = device_name->name;
210 else
211 remote_name = "";
213 remote_ether_addr = get_ether_name(remote_bdaddr->bd_addr);
214 remote_length = (gint)(strlen(remote_ether_addr) + 3 + strlen(remote_name) + 1);
215 remote_addr_name = (gchar *)wmem_alloc(pinfo->pool, remote_length);
217 g_snprintf(remote_addr_name, remote_length, "%s (%s)", remote_ether_addr, remote_name);
219 if (pinfo->p2p_dir == P2P_DIR_RECV) {
220 SET_ADDRESS(&pinfo->net_src, AT_STRINGZ, (int)strlen(remote_name) + 1, remote_name);
221 SET_ADDRESS(&pinfo->dl_src, AT_ETHER, 6, remote_bdaddr->bd_addr);
222 SET_ADDRESS(&pinfo->src, AT_STRINGZ, (int)strlen(remote_addr_name) + 1, remote_addr_name);
223 } else if (pinfo->p2p_dir == P2P_DIR_SENT) {
224 SET_ADDRESS(&pinfo->net_dst, AT_STRINGZ, (int)strlen(remote_name) + 1, remote_name);
225 SET_ADDRESS(&pinfo->dl_dst, AT_ETHER, 6, remote_bdaddr->bd_addr);
226 SET_ADDRESS(&pinfo->dst, AT_STRINGZ, (int)strlen(remote_addr_name) + 1, remote_addr_name);
228 } else {
229 if (pinfo->p2p_dir == P2P_DIR_RECV) {
230 SET_ADDRESS(&pinfo->net_src, AT_STRINGZ, 1, "");
231 SET_ADDRESS(&pinfo->dl_src, AT_STRINGZ, 1, "");
232 SET_ADDRESS(&pinfo->src, AT_STRINGZ, 10, "remote ()");
233 } else if (pinfo->p2p_dir == P2P_DIR_SENT) {
234 SET_ADDRESS(&pinfo->net_dst, AT_STRINGZ, 1, "");
235 SET_ADDRESS(&pinfo->dl_dst, AT_STRINGZ, 1, "");
236 SET_ADDRESS(&pinfo->dst, AT_STRINGZ, 10, "remote ()");
240 k_interface_id = hci_data->interface_id;
241 k_adapter_id = hci_data->adapter_id;
242 k_frame_number = pinfo->fd->num;
244 /* localhost bdaddr and name */
245 key[0].length = 1;
246 key[0].key = &k_interface_id;
247 key[1].length = 1;
248 key[1].key = &k_adapter_id;
249 key[2].length = 1;
250 key[2].key = &k_frame_number;
251 key[3].length = 0;
252 key[3].key = NULL;
255 localhost_bdaddr_entry = (localhost_bdaddr_entry_t *)wmem_tree_lookup32_array_le(hci_data->localhost_bdaddr, key);
256 if (localhost_bdaddr_entry && localhost_bdaddr_entry->interface_id == hci_data->interface_id &&
257 localhost_bdaddr_entry->adapter_id == hci_data->adapter_id) {
259 localhost_ether_addr = get_ether_name(localhost_bdaddr_entry->bd_addr);
260 memcpy(localhost_bdaddr, localhost_bdaddr_entry->bd_addr, 6);
261 } else {
262 localhost_ether_addr = "localhost";
263 /* XXX - is this the right value to use? */
264 memset(localhost_bdaddr, 0, 6);
267 localhost_name_entry = (localhost_name_entry_t *)wmem_tree_lookup32_array_le(hci_data->localhost_name, key);
268 if (localhost_name_entry && localhost_name_entry->interface_id == hci_data->interface_id &&
269 localhost_name_entry->adapter_id == hci_data->adapter_id)
270 localhost_name = localhost_name_entry->name;
271 else
272 localhost_name = "";
274 localhost_length = (gint)(strlen(localhost_ether_addr) + 3 + strlen(localhost_name) + 1);
275 localhost_addr_name = (gchar *)wmem_alloc(pinfo->pool, localhost_length);
277 g_snprintf(localhost_addr_name, localhost_length, "%s (%s)", localhost_ether_addr, localhost_name);
279 if (pinfo->p2p_dir == P2P_DIR_RECV) {
280 SET_ADDRESS(&pinfo->net_dst, AT_STRINGZ, (int)strlen(localhost_name) + 1, localhost_name);
281 SET_ADDRESS(&pinfo->dl_dst, AT_ETHER, 6, localhost_bdaddr);
282 SET_ADDRESS(&pinfo->dst, AT_STRINGZ, (int)strlen(localhost_addr_name) + 1, localhost_addr_name);
283 } else if (pinfo->p2p_dir == P2P_DIR_SENT) {
284 SET_ADDRESS(&pinfo->net_src, AT_STRINGZ, (int)strlen(localhost_name) + 1, localhost_name);
285 SET_ADDRESS(&pinfo->dl_src, AT_ETHER, 6, localhost_bdaddr);
286 SET_ADDRESS(&pinfo->src, AT_STRINGZ, (int)strlen(localhost_addr_name) + 1, localhost_addr_name);
289 /* find the chandle_data structure associated with this chandle */
290 k_interface_id = hci_data->interface_id;
291 k_adapter_id = hci_data->adapter_id;
292 k_connection_handle = flags & 0x0fff;
293 k_frame_number = pinfo->fd->num;
295 key[0].length = 1;
296 key[0].key = &k_interface_id;
297 key[1].length = 1;
298 key[1].key = &k_adapter_id;
299 key[2].length = 1;
300 key[2].key = &k_connection_handle;
301 key[3].length = 1;
302 key[3].key = &k_frame_number;
303 key[4].length = 0;
304 key[4].key = NULL;
306 chandle_data = (chandle_data_t *)wmem_tree_lookup32_array_le(chandle_tree, key);
307 if (!(chandle_data && chandle_data->interface_id == hci_data->interface_id &&
308 chandle_data->adapter_id == hci_data->adapter_id &&
309 chandle_data->chandle == (flags & 0x0fff))) {
310 k_interface_id = hci_data->interface_id;
311 k_adapter_id = hci_data->adapter_id;
312 k_connection_handle = flags & 0x0fff;
313 k_frame_number = pinfo->fd->num;
315 key[0].length = 1;
316 key[0].key = &k_interface_id;
317 key[1].length = 1;
318 key[1].key = &k_adapter_id;
319 key[2].length = 1;
320 key[2].key = &k_connection_handle;
321 key[3].length = 1;
322 key[3].key = &k_frame_number;
323 key[4].length = 0;
324 key[4].key = NULL;
326 chandle_data = (chandle_data_t *)wmem_alloc(wmem_file_scope(), sizeof(chandle_data_t));
327 chandle_data->start_fragments = wmem_tree_new(wmem_file_scope());
328 chandle_data->interface_id = hci_data->interface_id;
329 chandle_data->adapter_id = hci_data->adapter_id;
330 chandle_data->chandle = flags & 0x0fff;
332 wmem_tree_insert32_array(chandle_tree, key, chandle_data);
335 length = tvb_get_letohs(tvb, offset);
336 proto_tree_add_item(bthci_acl_tree, hf_bthci_acl_length, tvb, offset, 2, ENC_LITTLE_ENDIAN);
337 offset += 2;
339 /* determine if packet is fragmented */
340 switch(pb_flag) {
341 case 0x01: /* Continuation fragment */
342 fragmented = TRUE;
343 break;
344 case 0x00: /* First fragment/packet, non-auto flushable */
345 case 0x02: /* First fragment/packet, auto flushable */
346 l2cap_length = tvb_get_letohs(tvb, offset);
347 fragmented = (l2cap_length + 4 != length);
348 break;
349 default:
350 /* unknown pb_flag */
351 fragmented = FALSE;
355 if (!fragmented || (!acl_reassembly && !(pb_flag & 0x01))) {
356 /* call L2CAP dissector for PDUs that are not fragmented
357 * also for the first fragment if reassembly is disabled
359 next_tvb = tvb_new_subset(tvb, offset, tvb_length_remaining(tvb, offset), length);
360 if (btl2cap_handle) {
361 call_dissector_with_data(btl2cap_handle, next_tvb, pinfo, tree, acl_data);
364 return offset;
367 if (fragmented && acl_reassembly) {
368 multi_fragment_pdu_t *mfp = NULL;
369 gint len;
371 if (!(pb_flag & 0x01)) { /* first fragment */
372 if (!pinfo->fd->flags.visited) {
373 mfp = (multi_fragment_pdu_t *) wmem_new(wmem_file_scope(), multi_fragment_pdu_t);
374 mfp->first_frame = pinfo->fd->num;
375 mfp->last_frame = 0;
376 mfp->tot_len = l2cap_length + 4;
377 mfp->reassembled = (char *) wmem_alloc(wmem_file_scope(), mfp->tot_len);
378 len = tvb_length_remaining(tvb, offset);
379 if (len <= mfp->tot_len) {
380 tvb_memcpy(tvb, (guint8 *) mfp->reassembled, offset, len);
381 mfp->cur_off = len;
382 wmem_tree_insert32(chandle_data->start_fragments, pinfo->fd->num, mfp);
384 } else {
385 mfp = (multi_fragment_pdu_t *)wmem_tree_lookup32(chandle_data->start_fragments, pinfo->fd->num);
387 if (mfp != NULL && mfp->last_frame) {
388 proto_item *item;
390 item = proto_tree_add_uint(bthci_acl_tree, hf_bthci_acl_reassembled_in, tvb, 0, 0, mfp->last_frame);
391 PROTO_ITEM_SET_GENERATED(item);
392 col_append_fstr(pinfo->cinfo, COL_INFO, " [Reassembled in #%u]", mfp->last_frame);
395 if (pb_flag == 0x01) { /* continuation fragment */
396 mfp = (multi_fragment_pdu_t *)wmem_tree_lookup32_le(chandle_data->start_fragments, pinfo->fd->num);
397 if (!pinfo->fd->flags.visited) {
398 len = tvb_length_remaining(tvb, offset);
399 if (mfp != NULL && !mfp->last_frame && (mfp->tot_len >= mfp->cur_off + len)) {
400 tvb_memcpy(tvb, (guint8 *) mfp->reassembled + mfp->cur_off, offset, len);
401 mfp->cur_off += len;
402 if (mfp->cur_off == mfp->tot_len) {
403 mfp->last_frame = pinfo->fd->num;
407 if (mfp) {
408 proto_item *item;
410 item = proto_tree_add_uint(bthci_acl_tree, hf_bthci_acl_continuation_to, tvb, 0, 0, mfp->first_frame);
411 PROTO_ITEM_SET_GENERATED(item);
412 col_append_fstr(pinfo->cinfo, COL_INFO, " [Continuation to #%u]", mfp->first_frame);
414 if (mfp != NULL && mfp->last_frame == pinfo->fd->num) {
415 next_tvb = tvb_new_child_real_data(tvb, (guint8 *) mfp->reassembled, mfp->tot_len, mfp->tot_len);
416 add_new_data_source(pinfo, next_tvb, "Reassembled BTHCI ACL");
418 /* call L2CAP dissector */
419 if (btl2cap_handle) {
420 call_dissector_with_data(btl2cap_handle, next_tvb, pinfo, tree, acl_data);
426 return offset;
430 void
431 proto_register_bthci_acl(void)
434 /* Setup list of header fields See Section 1.6.1 for details*/
435 static hf_register_info hf[] = {
436 { &hf_bthci_acl_chandle,
437 { "Connection Handle", "bthci_acl.chandle",
438 FT_UINT16, BASE_HEX, NULL, 0x0FFF,
439 NULL, HFILL }
441 { &hf_bthci_acl_pb_flag,
442 { "PB Flag", "bthci_acl.pb_flag",
443 FT_UINT16, BASE_DEC, VALS(pb_flag_vals), 0x3000,
444 "Packet Boundary Flag", HFILL }
446 { &hf_bthci_acl_bc_flag,
447 { "BC Flag", "bthci_acl.bc_flag",
448 FT_UINT16, BASE_DEC, VALS(bc_flag_vals), 0xC000,
449 "Broadcast Flag", HFILL }
451 { &hf_bthci_acl_length,
452 { "Data Total Length", "bthci_acl.length",
453 FT_UINT16, BASE_DEC, NULL, 0x0,
454 NULL, HFILL }
456 #if 0
457 { &hf_bthci_acl_data,
458 { "Data", "bthci_acl.data",
459 FT_NONE, BASE_NONE, NULL, 0x0,
460 NULL, HFILL }
462 #endif
463 { &hf_bthci_acl_continuation_to,
464 { "This is a continuation to the PDU in frame", "bthci_acl.continuation_to",
465 FT_FRAMENUM, BASE_NONE, NULL, 0x0,
466 "This is a continuation to the PDU in frame #", HFILL }
468 { &hf_bthci_acl_reassembled_in,
469 { "This PDU is reassembled in frame", "bthci_acl.reassembled_in",
470 FT_FRAMENUM, BASE_NONE, NULL, 0x0,
471 "This PDU is reassembled in frame #", HFILL }
475 /* Setup protocol subtree array */
476 static gint *ett[] = {
477 &ett_bthci_acl,
479 module_t *bthci_acl_module;
481 /* Register the protocol name and description */
482 proto_bthci_acl = proto_register_protocol("Bluetooth HCI ACL Packet", "HCI_ACL", "bthci_acl");
483 new_register_dissector("bthci_acl", dissect_bthci_acl, proto_bthci_acl);
485 /* Required function calls to register the header fields and subtrees used */
486 proto_register_field_array(proto_bthci_acl, hf, array_length(hf));
487 proto_register_subtree_array(ett, array_length(ett));
489 /* Register configuration preferences */
490 bthci_acl_module = prefs_register_protocol(proto_bthci_acl, NULL);
491 prefs_register_bool_preference(bthci_acl_module, "hci_acl_reassembly",
492 "Reassemble ACL Fragments",
493 "Whether the ACL dissector should reassemble fragmented PDUs",
494 &acl_reassembly);
496 chandle_tree = wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
500 void
501 proto_reg_handoff_bthci_acl(void)
503 dissector_handle_t bthci_acl_handle;
505 bthci_acl_handle = find_dissector("bthci_acl");
506 dissector_add_uint("hci_h4.type", HCI_H4_TYPE_ACL, bthci_acl_handle);
507 dissector_add_uint("hci_h1.type", BTHCI_CHANNEL_ACL, bthci_acl_handle);
509 btl2cap_handle = find_dissector("btl2cap");
513 * Editor modelines - http://www.wireshark.org/tools/modelines.html
515 * Local variables:
516 * c-basic-offset: 4
517 * tab-width: 8
518 * indent-tabs-mode: nil
519 * End:
521 * vi: set shiftwidth=4 tabstop=8 expandtab:
522 * :indentSize=4:tabSize=8:noTabs=true: