HACK: 2nd try to match RowsetProperties
[wireshark-wip.git] / epan / dissectors / packet-btrfcomm.c
blob1ab4dfb5170e3017f96b28329541fb6cafd17f34
1 /* packet-btrfcomm.c
2 * Routines for Bluetooth RFCOMM protocol dissection
3 * and RFCOMM based profile dissection:
4 * - Dial-Up Networking (DUN) Profile
5 * - Serial Port Profile (SPP)
7 * Copyright 2002, Wolfgang Hansmann <hansmann@cs.uni-bonn.de>
9 * Refactored for wireshark checkin
10 * Ronnie Sahlberg 2006
12 * $Id$
14 * Wireshark - Network traffic analyzer
15 * By Gerald Combs <gerald@wireshark.org>
16 * Copyright 1998 Gerald Combs
18 * This program is free software; you can redistribute it and/or
19 * modify it under the terms of the GNU General Public License
20 * as published by the Free Software Foundation; either version 2
21 * of the License, or (at your option) any later version.
23 * This program is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
28 * You should have received a copy of the GNU General Public License
29 * along with this program; if not, write to the Free Software
30 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
33 #include "config.h"
35 #include <epan/packet.h>
36 #include <epan/prefs.h>
37 #include <epan/expert.h>
38 #include <epan/tap.h>
39 #include <epan/uat.h>
40 #include <epan/wmem/wmem.h>
42 #include "packet-btsdp.h"
43 #include "packet-btl2cap.h"
44 #include "packet-btrfcomm.h"
46 static int hf_pf = -1;
47 static int hf_ea = -1;
48 static int hf_len = -1;
49 static int hf_frame_type = -1;
50 static int hf_cr = -1;
51 static int hf_dlci = -1;
52 static int hf_channel = -1;
53 static int hf_direction = -1;
54 static int hf_priority = -1;
55 static int hf_error_recovery_mode = -1;
56 static int hf_max_frame_size = -1;
57 static int hf_max_retrans = -1;
58 static int hf_fc_credits = -1;
60 static int hf_mcc_pn_parameters = -1;
61 static int hf_pn_i14 = -1;
62 static int hf_pn_c14 = -1;
64 static int hf_mcc = -1;
65 static int hf_mcc_types = -1;
66 static int hf_mcc_len = -1;
67 static int hf_mcc_ea = -1;
68 static int hf_mcc_cr = -1;
69 static int hf_mcc_cmd = -1;
71 static int hf_msc_parameters = -1;
72 static int hf_msc_fc = -1;
73 static int hf_msc_rtc = -1;
74 static int hf_msc_rtr = -1;
75 static int hf_msc_ic = -1;
76 static int hf_msc_dv = -1;
77 static int hf_msc_l = -1;
78 static int hf_msc_break_bits = -1;
80 static int hf_fcs = -1;
82 static int hf_dun_at_cmd = -1;
83 static int hf_spp_data = -1;
84 static int hf_gnss_data = -1;
86 static int hf_mcc_dlci = -1;
87 static int hf_mcc_channel = -1;
88 static int hf_mcc_direction = -1;
89 static int hf_mcc_const_1 = -1;
91 static int hf_mcc_pn_dlci = -1;
92 static int hf_mcc_pn_channel = -1;
93 static int hf_mcc_pn_direction = -1;
94 static int hf_mcc_pn_zeros_padding = -1;
96 static int hf_acknowledgement_timer_t1 = -1;
97 static int hf_address = -1;
98 static int hf_control = -1;
100 /* Initialize the protocol and registered fields */
101 int proto_btrfcomm = -1;
102 static int proto_btdun = -1;
103 static int proto_btspp = -1;
104 static int proto_btgnss = -1;
106 /* Initialize the subtree pointers */
107 static gint ett_btrfcomm = -1;
108 static gint ett_btrfcomm_ctrl = -1;
109 static gint ett_addr = -1;
110 static gint ett_control = -1;
111 static gint ett_mcc = -1;
112 static gint ett_ctrl_pn_ci = -1;
113 static gint ett_ctrl_pn_v24 = -1;
114 static gint ett_dlci = -1;
115 static gint ett_mcc_dlci = -1;
117 static gint ett_btdun = -1;
118 static gint ett_btspp = -1;
119 static gint ett_btgnss = -1;
121 static expert_field ei_btrfcomm_mcc_length_bad = EI_INIT;
123 static wmem_tree_t *sdp_service_infos = NULL;
125 static dissector_table_t rfcomm_service_dissector_table;
126 static dissector_table_t rfcomm_channel_dissector_table;
128 typedef struct {
129 guint channel;
130 gchar* payload_proto_name;
131 dissector_handle_t payload_proto;
132 } uat_rfcomm_channels_t;
134 static gboolean rfcomm_channels_enabled = FALSE;
135 static uat_t *uat_rfcomm_channels = NULL;
136 static uat_rfcomm_channels_t *rfcomm_channels = NULL;
137 static guint num_rfcomm_channels = 0;
139 UAT_DEC_CB_DEF(rfcomm_channels, channel, uat_rfcomm_channels_t)
140 UAT_PROTO_DEF(rfcomm_channels, payload_proto, payload_proto, payload_proto_name, uat_rfcomm_channels_t)
142 static uat_field_t uat_rfcomm_channels_fields[] = {
143 UAT_FLD_DEC(rfcomm_channels, channel, "RFCOMM Channel",
144 "Range: 0-32"),
145 UAT_FLD_PROTO(rfcomm_channels, payload_proto, "Payload protocol",
146 "Dissector name used to decode RFCOMM channel"),
147 UAT_END_FIELDS
150 static dissector_handle_t data_handle;
151 static dissector_handle_t ppp_handle;
153 static const value_string vs_ctl_pn_i[] = {
154 {0x0, "use UIH Frames"},
155 #if 0 /* specified by 07.10, but not used by RFCOMM */
156 {0x1, "use UI Frames"},
157 {0x2, "use I Frames"},
158 #endif
159 {0, NULL}
162 static const value_string vs_ctl_pn_cl[] = {
164 {0x0, "no credit based flow control scheme"},
165 {0xe, "support of credit based flow control scheme (resp)"},
166 {0xf, "support of credit based flow control scheme (req)"},
167 #if 0 /* specified by 07.10. Redefined by RFCOMM */
168 {0x0, "type 1 (unstructured octet stream)"},
169 {0x1, "type 2 (unstructured octet stream with flow control)"},
170 {0x2, "type 3 (uninterruptible framed data)"},
171 {0x3, "type 4 (interruptible framed data)"},
172 #endif
173 {0, NULL}
177 static const value_string vs_frame_type[] = {
178 /* masked 0xef */
179 {0x2f, "Set Asynchronous Balanced Mode (SABM)"},
180 {0x63, "Unnumbered Acknowledgement (UA)"},
181 {0x0f, "Disconnected Mode (DM)"},
182 {0x43, "Disconnect (DISC)"},
183 {0xef, "Unnumbered Information with Header check (UIH)"},
184 #if 0 /* specified by 07.10, but not used by RFCOMM */
185 {0x03, "Unnumbered Information (UI)"},
186 #endif
187 {0, NULL}
191 static const value_string vs_frame_type_short[] = {
192 /* masked 0xef */
193 {0x2f, "SABM"},
194 {0x63, "UA"},
195 {0x0f, "DM"},
196 {0x43, "DISC"},
197 {0xef, "UIH"},
198 #if 0 /* specified by 07.10, but not used by RFCOMM */
199 {0x03, "UI"},
200 #endif
201 {0, NULL}
205 static const value_string vs_ctl[] = {
206 /* masked 0xfc */
207 {0x20, "DLC Parameter Negotiation (PN)"},
208 {0x08, "Test Command (Test)"},
209 {0x28, "Flow Control On Command (FCon)"},
210 {0x18, "Flow Control Off Command (FCoff)"},
211 {0x38, "Modem Status Command (MSC)"},
212 {0x04, "Non Supported Command Response (NSC)"},
213 {0x24, "Remote Port Negotiation Command (RPN)"},
214 {0x14, "Remote Line Status Command (RLS)"},
215 #if 0 /* Specified by 07.10, but not used by RFCOMM */
216 {0x10, "Power Saving Control (PSC)"},
217 {0x30, "Multiplexer close down (CLD)"},
218 {0x34, "Service Negotiation Command (SNC)"},
219 #endif
220 #if 0 /* old */
221 {0x80, "DLC parameter negotiation (PN)"},
222 {0x20, "Test Command (Test)"},
223 {0xa0, "Flow Control On Command (FCon)"},
224 {0x60, "Flow Control Off Command (FCoff)"},
225 {0xe0, "Modem Status Command (MSC)"},
226 {0x10, "Non Supported Command Response (NSC)"},
227 {0x90, "Remote Port Negotiation Command (RPN)"},
228 {0x50, "Remote Line Status Command (RLS)"},
229 {0x40, "Power Saving Control (PSC)"},
230 {0xc0, "Multiplexer close down (CLD)"},
231 {0xd0, "Service Negotiation Command (SNC)"},
232 #endif
233 {0x0, NULL}
236 static const value_string vs_ea[] = {
237 {1, "Last field octet"},
238 {0, "More field octets following"},
239 {0, NULL}
242 static const value_string vs_cr[] = {
243 {1, "Command"},
244 {0, "Response"},
245 {0, NULL}
248 void proto_register_btrfcomm(void);
249 void proto_reg_handoff_btrfcomm(void);
250 void proto_register_btdun(void);
251 void proto_reg_handoff_btdun(void);
252 void proto_register_btspp(void);
253 void proto_reg_handoff_btspp(void);
254 void proto_register_btgnss(void);
255 void proto_reg_handoff_btgnss(void);
257 static dissector_handle_t
258 find_proto_by_channel(guint channel) {
259 guint i_channel;
261 for (i_channel = 0; i_channel < num_rfcomm_channels; ++i_channel) {
262 if (rfcomm_channels[i_channel].channel == channel) {
263 return rfcomm_channels[i_channel].payload_proto;
266 return NULL;
269 static int
270 get_le_multi_byte_value(tvbuff_t *tvb, int offset, proto_tree *tree, guint32 *val_ptr, int hf_index)
272 guint8 byte, bc = 0;
273 guint32 val = 0;
274 int start_offset = offset;
276 do {
277 byte = tvb_get_guint8(tvb, offset);
278 offset += 1;
279 val |= ((byte >> 1) & 0xff) << (bc++ * 7);
280 } while ((byte & 0x1) == 0);
282 *val_ptr = val;
284 if (hf_index > 0) {
285 proto_tree_add_uint(tree, hf_index, tvb, start_offset, offset - start_offset, val);
288 return offset;
292 static int
293 dissect_ctrl_pn(proto_tree *t, tvbuff_t *tvb, int offset, guint8 *mcc_channel)
295 proto_tree *st;
296 proto_item *ti;
297 proto_tree *dlci_tree;
298 proto_item *dlci_item;
299 proto_item *item;
300 int mcc_dlci;
301 guint8 flags;
303 proto_tree_add_item(t, hf_mcc_pn_zeros_padding, tvb, offset, 1, ENC_LITTLE_ENDIAN);
305 /* mcc dlci */
306 mcc_dlci = tvb_get_guint8(tvb, offset) & 0x3f;
307 *mcc_channel = mcc_dlci >> 1;
309 dlci_item = proto_tree_add_item(t, hf_mcc_pn_dlci, tvb, offset, 1, ENC_LITTLE_ENDIAN);
310 proto_item_append_text(dlci_item, " (Direction: %d, Channel: %u)", mcc_dlci & 0x01, *mcc_channel);
312 dlci_tree = proto_item_add_subtree(dlci_item, ett_mcc_dlci);
313 proto_tree_add_item(dlci_tree, hf_mcc_pn_channel, tvb, offset, 1, ENC_LITTLE_ENDIAN);
314 proto_tree_add_item(dlci_tree, hf_mcc_pn_direction, tvb, offset, 1, ENC_LITTLE_ENDIAN);
315 offset += 1;
317 flags = tvb_get_guint8(tvb, offset);
319 ti = proto_tree_add_none_format(t, hf_mcc_pn_parameters, tvb, offset, 1, "I1-I4: 0x%x, C1-C4: 0x%x", flags & 0xf, (flags >> 4) & 0xf);
320 st = proto_item_add_subtree(ti, ett_ctrl_pn_ci);
322 proto_tree_add_item(st, hf_pn_c14, tvb, offset, 1, ENC_LITTLE_ENDIAN);
323 proto_tree_add_item(st, hf_pn_i14, tvb, offset, 1, ENC_LITTLE_ENDIAN);
324 offset += 1;
326 /* priority */
327 proto_tree_add_item(t, hf_priority, tvb, offset, 1, ENC_LITTLE_ENDIAN);
328 offset += 1;
330 /* Ack timer */
331 item = proto_tree_add_item(t, hf_acknowledgement_timer_t1, tvb, offset, 1, ENC_LITTLE_ENDIAN);
332 proto_item_append_text(item, "(%d ms)", (guint32)tvb_get_guint8(tvb, offset) * 100);
333 offset += 1;
335 /* max frame size */
336 proto_tree_add_item(t, hf_max_frame_size, tvb, offset, 2, ENC_LITTLE_ENDIAN);
337 offset += 2;
339 /* max retrans */
340 proto_tree_add_item(t, hf_max_retrans, tvb, offset, 1, ENC_LITTLE_ENDIAN);
341 offset += 1;
343 /* error recovery mode */
344 proto_tree_add_item(t, hf_error_recovery_mode, tvb, offset, 1, ENC_LITTLE_ENDIAN);
345 offset += 1;
347 return offset;
350 static int
351 dissect_ctrl_msc(proto_tree *t, tvbuff_t *tvb, int offset, int length, guint8 *mcc_channel)
354 proto_tree *st;
355 proto_item *it;
356 proto_tree *dlci_tree;
357 proto_item *dlci_item;
358 guint8 mcc_dlci;
359 guint8 status;
360 int start_offset;
362 mcc_dlci = tvb_get_guint8(tvb, offset) >> 2;
363 *mcc_channel = mcc_dlci >> 1;
365 dlci_item = proto_tree_add_item(t, hf_mcc_dlci, tvb, offset, 1, ENC_LITTLE_ENDIAN);
366 proto_item_append_text(dlci_item, " (Direction: %d, Channel: %u)", mcc_dlci & 0x01, *mcc_channel);
368 dlci_tree = proto_item_add_subtree(dlci_item, ett_mcc_dlci);
369 proto_tree_add_item(dlci_tree, hf_mcc_channel, tvb, offset, 1, ENC_LITTLE_ENDIAN);
370 proto_tree_add_item(dlci_tree, hf_mcc_direction, tvb, offset, 1, ENC_LITTLE_ENDIAN);
372 proto_tree_add_item(t, hf_mcc_const_1, tvb, offset, 1, ENC_LITTLE_ENDIAN);
373 proto_tree_add_item(t, hf_mcc_ea, tvb, offset, 1, ENC_LITTLE_ENDIAN);
375 offset += 1;
377 start_offset = offset;
378 status = tvb_get_guint8(tvb, offset);
379 it = proto_tree_add_none_format(t, hf_msc_parameters, tvb, offset, 1, "V.24 Signals: FC = %d, RTC = %d, RTR = %d, IC = %d, DV = %d", (status >> 1) & 1,
380 (status >> 2) & 1, (status >> 3) & 1,
381 (status >> 6) & 1, (status >> 7) & 1);
382 st = proto_item_add_subtree(it, ett_ctrl_pn_v24);
384 proto_tree_add_item(st, hf_msc_fc, tvb, offset, 1, ENC_LITTLE_ENDIAN);
385 proto_tree_add_item(st, hf_msc_rtc, tvb, offset, 1, ENC_LITTLE_ENDIAN);
386 proto_tree_add_item(st, hf_msc_rtr, tvb, offset, 1, ENC_LITTLE_ENDIAN);
387 proto_tree_add_item(st, hf_msc_ic, tvb, offset, 1, ENC_LITTLE_ENDIAN);
388 proto_tree_add_item(st, hf_msc_dv, tvb, offset, 1, ENC_LITTLE_ENDIAN);
389 offset += 1;
391 if (length == 3) {
392 proto_tree_add_item(t, hf_msc_break_bits, tvb, offset, 1, ENC_LITTLE_ENDIAN);
393 proto_tree_add_item(t, hf_msc_l, tvb, offset, 1, ENC_LITTLE_ENDIAN);
394 offset += 1;
397 proto_item_set_len(it, offset - start_offset);
399 return offset;
402 static int
403 dissect_btrfcomm_address(tvbuff_t *tvb, int offset, proto_tree *tree, guint8 *ea_flagp, guint8 *cr_flagp, guint8 *dlcip)
405 proto_item *ti;
406 proto_tree *addr_tree;
407 proto_tree *dlci_tree = NULL;
408 proto_item *dlci_item = NULL;
409 guint8 dlci, cr_flag, ea_flag, flags;
411 flags = tvb_get_guint8(tvb, offset);
413 ea_flag = flags & 0x01;
414 if (ea_flagp) {
415 *ea_flagp = ea_flag;
418 cr_flag = (flags & 0x02) ? 1 : 0;
419 if (cr_flagp) {
420 *cr_flagp = cr_flag;
423 dlci = flags >> 2;
424 if (dlcip) {
425 *dlcip = dlci;
428 ti = proto_tree_add_none_format(tree, hf_address, tvb, offset, 1, "Address: E/A flag: %d, C/R flag: %d, Direction: %d, Channel: %u", ea_flag, cr_flag, dlci & 0x01, dlci >> 1);
429 addr_tree = proto_item_add_subtree(ti, ett_addr);
431 dlci_item = proto_tree_add_item(addr_tree, hf_dlci, tvb, offset, 1, ENC_LITTLE_ENDIAN);
432 proto_item_append_text(dlci_item, " (Direction: %d, Channel: %u)", dlci & 0x01, dlci >> 1);
434 dlci_tree = proto_item_add_subtree(dlci_item, ett_dlci);
435 proto_tree_add_item(dlci_tree, hf_channel, tvb, offset, 1, ENC_LITTLE_ENDIAN);
436 proto_tree_add_item(dlci_tree, hf_direction, tvb, offset, 1, ENC_LITTLE_ENDIAN);
438 proto_tree_add_item(addr_tree, hf_cr, tvb, offset, 1, ENC_LITTLE_ENDIAN);
439 proto_tree_add_item(addr_tree, hf_ea, tvb, offset, 1, ENC_LITTLE_ENDIAN);
440 offset += 1;
442 return offset;
445 static int
446 dissect_btrfcomm_control(tvbuff_t *tvb, int offset, proto_tree *tree, guint8 *pf_flagp, guint8 *frame_typep)
448 proto_item *ti;
449 proto_tree *hctl_tree;
450 guint8 frame_type, pf_flag, flags;
452 flags = tvb_get_guint8(tvb, offset);
454 pf_flag = (flags & 0x10) ? 1 : 0;
455 if (pf_flagp) {
456 *pf_flagp = pf_flag;
459 frame_type = flags & 0xef;
460 if (frame_typep) {
461 *frame_typep = frame_type;
464 ti = proto_tree_add_none_format(tree, hf_control, tvb, offset, 1, "Control: Frame type: %s (0x%x), P/F flag: %d",
465 val_to_str_const(frame_type, vs_frame_type, "Unknown"), frame_type, pf_flag);
466 hctl_tree = proto_item_add_subtree(ti, ett_control);
468 proto_tree_add_item(hctl_tree, hf_pf, tvb, offset, 1, ENC_LITTLE_ENDIAN);
469 proto_tree_add_item(hctl_tree, hf_frame_type, tvb, offset, 1, ENC_LITTLE_ENDIAN);
471 offset += 1;
472 return offset;
477 static int
478 dissect_btrfcomm_payload_length(tvbuff_t *tvb, int offset, proto_tree *tree, guint16 *frame_lenp)
480 guint16 frame_len;
481 int start_offset = offset;
483 frame_len = tvb_get_guint8(tvb, offset);
484 offset += 1;
486 if (frame_len & 0x01) {
487 frame_len >>= 1; /* 0 - 127 */
488 } else {
489 frame_len >>= 1; /* 128 - ... */
490 frame_len |= (tvb_get_guint8(tvb, offset)) << 7;
491 offset += 1;
494 proto_tree_add_uint(tree, hf_len, tvb, start_offset, offset - start_offset, frame_len);
496 if (frame_lenp) {
497 *frame_lenp = frame_len;
500 return offset;
503 static int
504 dissect_btrfcomm_MccType(tvbuff_t *tvb, int offset, proto_tree *tree, guint8 *mcc_cr_flagp, guint8 *mcc_ea_flagp, guint32 *mcc_typep)
506 int start_offset = offset;
507 proto_item *ti;
508 proto_tree *mcc_tree;
509 guint8 flags, mcc_cr_flag, mcc_ea_flag;
510 guint32 mcc_type;
512 flags = tvb_get_guint8(tvb, offset);
514 mcc_cr_flag = (flags & 0x2) ? 1 : 0;
515 if (mcc_cr_flagp) {
516 *mcc_cr_flagp = mcc_cr_flag;
519 mcc_ea_flag = flags & 0x1;
520 if (mcc_ea_flagp) {
521 *mcc_ea_flagp = mcc_ea_flag;
524 offset = get_le_multi_byte_value(tvb, offset, tree, &mcc_type, -1);
525 mcc_type = (mcc_type >> 1) & 0x3f; /* shift c/r flag off */
526 if (mcc_typep) {
527 *mcc_typep = mcc_type;
530 ti = proto_tree_add_none_format(tree, hf_mcc_types, tvb, start_offset, offset - start_offset,
531 "Type: %s (0x%x), C/R flag = %d, E/A flag = %d",
532 val_to_str_const(mcc_type, vs_ctl, "Unknown"),
533 mcc_type, mcc_cr_flag, mcc_ea_flag);
534 mcc_tree = proto_item_add_subtree(ti, ett_mcc);
536 proto_tree_add_item(mcc_tree, hf_mcc_cmd, tvb, start_offset, offset - start_offset, ENC_LITTLE_ENDIAN);
537 proto_tree_add_item(mcc_tree, hf_mcc_cr, tvb, start_offset, 1, ENC_LITTLE_ENDIAN);
538 proto_tree_add_item(mcc_tree, hf_mcc_ea, tvb, start_offset, 1, ENC_LITTLE_ENDIAN);
540 return offset;
543 static gint
544 dissect_btrfcomm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
546 proto_item *ti;
547 proto_tree *rfcomm_tree;
548 gint offset = 0;
549 gint fcs_offset;
550 guint8 dlci, cr_flag, ea_flag;
551 guint8 frame_type, pf_flag;
552 guint16 frame_len;
553 btl2cap_data_t *l2cap_data;
554 service_info_t *service_info = NULL;
556 ti = proto_tree_add_item(tree, proto_btrfcomm, tvb, offset, -1, ENC_NA);
557 rfcomm_tree = proto_item_add_subtree(ti, ett_btrfcomm);
559 col_set_str(pinfo->cinfo, COL_PROTOCOL, "RFCOMM");
561 switch (pinfo->p2p_dir) {
562 case P2P_DIR_SENT:
563 col_set_str(pinfo->cinfo, COL_INFO, "Sent ");
564 break;
565 case P2P_DIR_RECV:
566 col_set_str(pinfo->cinfo, COL_INFO, "Rcvd ");
567 break;
568 default:
569 col_add_fstr(pinfo->cinfo, COL_INFO, "Unknown direction %d ",
570 pinfo->p2p_dir);
571 break;
574 l2cap_data = (btl2cap_data_t *) data;
575 DISSECTOR_ASSERT(l2cap_data);
577 /* flags and dlci */
578 offset = dissect_btrfcomm_address(tvb, offset, rfcomm_tree, &ea_flag, &cr_flag, &dlci);
579 /* pf and frame type */
580 offset = dissect_btrfcomm_control(tvb, offset, rfcomm_tree, &pf_flag, &frame_type);
581 /* payload length */
582 offset = dissect_btrfcomm_payload_length(tvb, offset, rfcomm_tree, &frame_len);
584 if (dlci && (frame_len || (frame_type == 0xef) || (frame_type == 0x2f))) {
585 wmem_tree_key_t key[10];
586 guint32 k_interface_id;
587 guint32 k_adapter_id;
588 guint32 k_sdp_psm;
589 guint32 k_direction;
590 guint32 k_bd_addr_oui;
591 guint32 k_bd_addr_id;
592 guint32 k_service_type;
593 guint32 k_service_channel;
594 guint32 k_frame_number;
596 k_interface_id = l2cap_data->interface_id;
597 k_adapter_id = l2cap_data->adapter_id;
598 k_sdp_psm = SDP_PSM_DEFAULT;
599 k_direction = (dlci & 0x01) ? P2P_DIR_SENT : P2P_DIR_RECV;
600 if (k_direction == P2P_DIR_RECV) {
601 k_bd_addr_oui = l2cap_data->remote_bd_addr_oui;
602 k_bd_addr_id = l2cap_data->remote_bd_addr_id;
603 } else {
604 k_bd_addr_oui = 0;
605 k_bd_addr_id = 0;
607 k_service_type = BTSDP_RFCOMM_PROTOCOL_UUID;
608 k_service_channel = dlci >> 1;
609 k_frame_number = pinfo->fd->num;
611 key[0].length = 1;
612 key[0].key = &k_interface_id;
613 key[1].length = 1;
614 key[1].key = &k_adapter_id;
615 key[2].length = 1;
616 key[2].key = &k_sdp_psm;
617 key[3].length = 1;
618 key[3].key = &k_direction;
619 key[4].length = 1;
620 key[4].key = &k_bd_addr_oui;
621 key[5].length = 1;
622 key[5].key = &k_bd_addr_id;
623 key[6].length = 1;
624 key[6].key = &k_service_type;
625 key[7].length = 1;
626 key[7].key = &k_service_channel;
627 key[8].length = 1;
628 key[8].key = &k_frame_number;
629 key[9].length = 0;
630 key[9].key = NULL;
632 if (sdp_service_infos) {
633 service_info = (service_info_t *) wmem_tree_lookup32_array_le(sdp_service_infos, key);
635 if (service_info && service_info->interface_id == l2cap_data->interface_id &&
636 service_info->adapter_id == l2cap_data->adapter_id &&
637 service_info->sdp_psm == SDP_PSM_DEFAULT &&
638 ((service_info->direction == P2P_DIR_RECV &&
639 service_info->bd_addr_oui == l2cap_data->remote_bd_addr_oui &&
640 service_info->bd_addr_id == l2cap_data->remote_bd_addr_id) ||
641 (service_info->direction != P2P_DIR_RECV &&
642 service_info->bd_addr_oui == 0 &&
643 service_info->bd_addr_id == 0)) &&
644 service_info->type == BTSDP_RFCOMM_PROTOCOL_UUID &&
645 service_info->channel == (dlci >> 1)) {
647 } else {
648 service_info = wmem_new0(wmem_packet_scope(), service_info_t);
652 col_append_fstr(pinfo->cinfo, COL_INFO, "%s Channel=%u ",
653 val_to_str_const(frame_type, vs_frame_type_short, "Unknown"), dlci >> 1);
654 if (dlci && (frame_type == 0x2f))
655 col_append_fstr(pinfo->cinfo, COL_INFO, "(%s) ",
656 val_to_str_ext_const(service_info->uuid.bt_uuid, &vs_service_classes_ext, "Unknown"));
658 /* UID frame */
659 if ((frame_type == 0xef) && dlci && pf_flag) {
660 col_append_str(pinfo->cinfo, COL_INFO, "UID ");
662 /* add credit based flow control byte */
663 proto_tree_add_item(rfcomm_tree, hf_fc_credits, tvb, offset, 1, ENC_LITTLE_ENDIAN);
664 offset += 1;
668 fcs_offset = offset + frame_len;
670 /* multiplexer control command */
671 if (!dlci && frame_len) {
672 proto_item *mcc_ti;
673 proto_tree *ctrl_tree;
674 proto_tree *dlci_tree;
675 proto_item *dlci_item;
676 guint32 mcc_type, length;
677 guint8 mcc_cr_flag, mcc_ea_flag;
678 guint8 mcc_channel;
679 guint8 mcc_dlci;
680 int start_offset = offset;
682 mcc_ti = proto_tree_add_item(rfcomm_tree, hf_mcc, tvb, offset, 1, ENC_NA);
683 ctrl_tree = proto_item_add_subtree(mcc_ti, ett_btrfcomm_ctrl);
685 /* mcc type */
686 offset = dissect_btrfcomm_MccType(tvb, offset, ctrl_tree, &mcc_cr_flag, &mcc_ea_flag, &mcc_type);
688 /* len */
689 offset = get_le_multi_byte_value(tvb, offset, ctrl_tree, &length, hf_mcc_len);
691 if (length > (guint32) tvb_length_remaining(tvb, offset)) {
692 expert_add_info_format(pinfo, ctrl_tree, &ei_btrfcomm_mcc_length_bad, "Huge MCC length: %u", length);
693 return offset;
696 switch(mcc_type) {
697 case 0x20: /* DLC Parameter Negotiation */
698 dissect_ctrl_pn(ctrl_tree, tvb, offset, &mcc_channel);
699 break;
700 case 0x24: /* Remote Port Negotiation */
701 mcc_dlci = tvb_get_guint8(tvb, offset) >> 2;
702 mcc_channel = mcc_dlci >> 1;
704 dlci_item = proto_tree_add_item(ctrl_tree, hf_mcc_dlci, tvb, offset, 1, ENC_LITTLE_ENDIAN);
705 proto_item_append_text(dlci_item, " (Direction: %d, Channel: %u)", mcc_dlci & 0x01, mcc_channel);
707 dlci_tree = proto_item_add_subtree(dlci_item, ett_mcc_dlci);
708 proto_tree_add_item(dlci_tree, hf_mcc_channel, tvb, offset, 1, ENC_LITTLE_ENDIAN);
709 proto_tree_add_item(dlci_tree, hf_mcc_direction, tvb, offset, 1, ENC_LITTLE_ENDIAN);
711 proto_tree_add_item(ctrl_tree, hf_mcc_const_1, tvb, offset, 1, ENC_LITTLE_ENDIAN);
712 proto_tree_add_item(ctrl_tree, hf_mcc_ea, tvb, offset, 1, ENC_LITTLE_ENDIAN);
714 break;
715 case 0x38: /* Modem Status Command */
716 dissect_ctrl_msc(ctrl_tree, tvb, offset, length, &mcc_channel);
717 break;
718 default:
719 mcc_channel = -1;
722 if (mcc_channel > 0) {
723 col_append_fstr(pinfo->cinfo, COL_INFO, "-> %d ", mcc_channel);
726 col_append_str(pinfo->cinfo, COL_INFO, "MPX_CTRL ");
728 if(mcc_type){
729 col_append_fstr(pinfo->cinfo, COL_INFO, "%s ", val_to_str_const(mcc_type, vs_ctl, "Unknown"));
732 offset += length;
734 proto_item_set_len(mcc_ti, offset - start_offset);
737 /* try to find a higher layer dissector that has registered to handle data
738 * for this kind of service, if none is found dissect it as raw "data"
740 if (dlci && frame_len) {
741 dissector_handle_t decode_by_dissector;
742 tvbuff_t *next_tvb;
743 btrfcomm_data_t *rfcomm_data;
745 next_tvb = tvb_new_subset(tvb, offset, frame_len, frame_len);
747 rfcomm_data = (btrfcomm_data_t *) wmem_new(wmem_packet_scope(), btrfcomm_data_t);
748 rfcomm_data->interface_id = l2cap_data->interface_id;
749 rfcomm_data->adapter_id = l2cap_data->adapter_id;
750 rfcomm_data->chandle = l2cap_data->chandle;
751 rfcomm_data->cid = l2cap_data->cid;
752 rfcomm_data->dlci = dlci;
753 rfcomm_data->remote_bd_addr_oui = l2cap_data->remote_bd_addr_oui;
754 rfcomm_data->remote_bd_addr_id = l2cap_data->remote_bd_addr_id;
756 if (!dissector_try_uint_new(rfcomm_channel_dissector_table, (guint32) dlci >> 1,
757 next_tvb, pinfo, tree, TRUE, rfcomm_data)) {
758 if (!dissector_try_uint_new(rfcomm_service_dissector_table, service_info->uuid.bt_uuid,
759 next_tvb, pinfo, tree, TRUE, rfcomm_data)) {
760 decode_by_dissector = find_proto_by_channel(dlci >> 1);
761 if (rfcomm_channels_enabled && decode_by_dissector) {
762 call_dissector_with_data(decode_by_dissector, next_tvb, pinfo, tree, rfcomm_data);
763 } else {
764 /* unknown service, let the data dissector handle it */
765 call_dissector(data_handle, next_tvb, pinfo, tree);
771 proto_tree_add_item(rfcomm_tree, hf_fcs, tvb, fcs_offset, 1, ENC_LITTLE_ENDIAN);
772 offset += 1;
774 return offset;
777 void
778 proto_register_btrfcomm(void)
780 module_t *module;
781 expert_module_t *expert_btrfcomm;
783 static hf_register_info hf[] = {
784 { &hf_dlci,
785 { "DLCI", "btrfcomm.dlci",
786 FT_UINT8, BASE_HEX, NULL, 0xFC,
787 "RFCOMM Data Link Connection Identifier", HFILL}
789 { &hf_channel,
790 { "Channel", "btrfcomm.channel",
791 FT_UINT8, BASE_DEC, NULL, 0xF8,
792 "RFCOMM Channel", HFILL}
794 { &hf_direction,
795 {"Direction", "btrfcomm.direction",
796 FT_UINT8, BASE_HEX, NULL, 0x04,
797 NULL, HFILL}
799 { &hf_priority,
800 { "Priority", "btrfcomm.priority",
801 FT_UINT8, BASE_DEC, NULL, 0x3f,
802 NULL, HFILL}
804 { &hf_max_frame_size,
805 { "Max Frame Size", "btrfcomm.max_frame_size",
806 FT_UINT16, BASE_DEC, NULL, 0,
807 "Maximum Frame Size", HFILL}
809 { &hf_max_retrans,
810 { "Maximum number of retransmissions", "btrfcomm.max_retrans",
811 FT_UINT8, BASE_DEC, NULL, 0,
812 NULL, HFILL}
814 { &hf_error_recovery_mode,
815 { "Error Recovery Mode", "btrfcomm.error_recovery_mode",
816 FT_UINT8, BASE_DEC, NULL, 0x07,
817 NULL, HFILL}
819 { &hf_ea,
820 { "EA Flag", "btrfcomm.ea",
821 FT_UINT8, BASE_HEX, VALS(vs_ea), 0x01,
822 "EA flag (should be always 1)", HFILL}
824 { &hf_cr,
825 { "C/R Flag", "btrfcomm.cr",
826 FT_UINT8, BASE_HEX, VALS(vs_cr), 0x02,
827 "Command/Response flag", HFILL}
829 { &hf_mcc,
830 { "Multiplexer Control Command", "btrfcomm.mcc",
831 FT_NONE, BASE_NONE, NULL, 0x00,
832 NULL, HFILL}
834 { &hf_mcc_pn_parameters,
835 { "Parameters", "btrfcomm.mcc.pn_parameters",
836 FT_NONE, BASE_NONE, NULL, 0x00,
837 NULL, HFILL}
839 { &hf_mcc_types,
840 { "Types", "btrfcomm.mcc.types",
841 FT_NONE, BASE_NONE, NULL, 0x00,
842 NULL, HFILL}
844 { &hf_mcc_ea,
845 { "EA Flag", "btrfcomm.mcc.ea",
846 FT_UINT8, BASE_HEX, VALS(vs_ea), 0x01,
847 "RFCOMM MCC EA flag", HFILL}
849 { &hf_mcc_cr,
850 { "C/R Flag", "btrfcomm.mcc.cr",
851 FT_UINT8, BASE_HEX, VALS(vs_cr), 0x02,
852 "Command/Response flag", HFILL}
854 { &hf_mcc_const_1,
855 { "Ones padding", "btrfcomm.mcc.padding",
856 FT_UINT8, BASE_HEX, NULL, 0x02,
857 NULL, HFILL}
859 { &hf_mcc_dlci,
860 { "MCC DLCI", "btrfcomm.mcc.dlci",
861 FT_UINT8, BASE_HEX, NULL, 0xFC,
862 "RFCOMM MCC Data Link Connection Identifier", HFILL}
864 { &hf_mcc_channel,
865 { "MCC Channel", "btrfcomm.mcc.channel",
866 FT_UINT8, BASE_DEC, NULL, 0xF8,
867 "RFCOMM MCC Channel", HFILL}
869 { &hf_mcc_direction,
870 { "MCC Direction", "btrfcomm.mcc.direction",
871 FT_UINT8, BASE_HEX, NULL, 0x04,
872 "RFCOMM MCC Direction", HFILL}
874 { &hf_mcc_pn_dlci,
875 { "MCC DLCI", "btrfcomm.mcc.dlci",
876 FT_UINT8, BASE_HEX, NULL, 0x3F,
877 "RFCOMM MCC Data Link Connection Identifier", HFILL}
879 { &hf_mcc_pn_channel,
880 { "MCC Channel", "btrfcomm.mcc.channel",
881 FT_UINT8, BASE_DEC, NULL, 0x3E,
882 "RFCOMM MCC Channel", HFILL}
884 { &hf_mcc_pn_direction,
885 { "MCC Direction", "btrfcomm.mcc.direction",
886 FT_UINT8, BASE_HEX, NULL, 0x01,
887 "RFCOMM MCC Direction", HFILL}
889 { &hf_mcc_pn_zeros_padding,
890 { "Zeros padding", "btrfcomm.mcc.padding",
891 FT_UINT8, BASE_HEX, NULL, 0xC0,
892 "RFCOMM MSC Zeros padding", HFILL}
894 { &hf_mcc_cmd,
895 { "MCC Command Type", "btrfcomm.mcc.cmd",
896 FT_UINT8, BASE_HEX, VALS(vs_ctl), 0xFC,
897 "Command Type", HFILL}
899 { &hf_frame_type,
900 { "Frame type", "btrfcomm.frame_type",
901 FT_UINT8, BASE_HEX, VALS(vs_frame_type), 0xEF,
902 "Command/Response flag", HFILL}
904 { &hf_acknowledgement_timer_t1,
905 { "Acknowledgement Timer T1", "btrfcomm.acknowledgement_timer_t1",
906 FT_UINT8, BASE_DEC, NULL, 0x00,
907 NULL, HFILL}
909 { &hf_pf,
910 { "P/F flag", "btrfcomm.pf",
911 FT_UINT8, BASE_HEX, NULL, 0x10,
912 "Poll/Final bit", HFILL}
914 { &hf_pn_i14,
915 { "Type of frame", "btrfcomm.pn.i",
916 FT_UINT8, BASE_HEX, VALS(vs_ctl_pn_i), 0x0F,
917 "Type of information frames used for that particular DLCI",
918 HFILL}
920 { &hf_pn_c14,
921 { "Convergence layer", "btrfcomm.pn.cl",
922 FT_UINT8, BASE_HEX, VALS(vs_ctl_pn_cl), 0xF0,
923 "Convergence layer used for that particular DLCI", HFILL}
925 { &hf_len,
926 { "Payload length", "btrfcomm.len",
927 FT_UINT16, BASE_DEC, NULL, 0,
928 "Frame length", HFILL}
930 { &hf_mcc_len,
931 { "MCC Length", "btrfcomm.mcc.len",
932 FT_UINT16, BASE_DEC, NULL, 0,
933 "Length of MCC data", HFILL}
935 { &hf_fcs,
936 { "Frame Check Sequence", "btrfcomm.fcs",
937 FT_UINT8, BASE_HEX, NULL, 0,
938 "Checksum over frame", HFILL}
940 { &hf_msc_parameters,
941 { "Parameters", "btrfcomm.mcc.msc_parameters",
942 FT_NONE, BASE_NONE, NULL, 0x00,
943 NULL, HFILL}
945 { &hf_msc_fc,
946 { "Flow Control (FC)", "btrfcomm.msc.fc",
947 FT_UINT8, BASE_HEX, NULL, 0x02,
948 "Flow Control", HFILL}
950 { &hf_msc_rtc,
951 { "Ready To Communicate (RTC)", "btrfcomm.msc.rtc",
952 FT_UINT8, BASE_HEX, NULL, 0x04,
953 "Ready To Communicate", HFILL}
955 { &hf_msc_rtr,
956 { "Ready To Receive (RTR)", "btrfcomm.msc.rtr",
957 FT_UINT8, BASE_HEX, NULL, 0x08,
958 "Ready To Receive", HFILL}
960 { &hf_msc_ic,
961 { "Incoming Call Indicator (IC)", "btrfcomm.msc.ic",
962 FT_UINT8, BASE_HEX, NULL, 0x40,
963 "Incoming Call Indicator", HFILL}
965 { &hf_msc_dv,
966 { "Data Valid (DV)", "btrfcomm.msc.dv",
967 FT_UINT8, BASE_HEX, NULL, 0x80,
968 "Data Valid", HFILL}
970 { &hf_msc_l,
971 { "Length of break in units of 200ms", "btrfcomm.msc.bl",
972 FT_UINT8, BASE_DEC, NULL, 0xF0,
973 NULL, HFILL}
975 { &hf_msc_break_bits,
976 { "Break Bits", "btrfcomm.msc.break_bits",
977 FT_UINT8, BASE_DEC, NULL, 0xE0,
978 NULL, HFILL}
980 { &hf_address,
981 { "Address", "btrfcomm.address",
982 FT_NONE, BASE_NONE, NULL, 0x00,
983 NULL, HFILL}
985 { &hf_control,
986 { "Control", "btrfcomm.control",
987 FT_NONE, BASE_NONE, NULL, 0x00,
988 NULL, HFILL}
990 { &hf_fc_credits,
991 { "Credits", "btrfcomm.credits",
992 FT_UINT8, BASE_DEC, NULL, 0,
993 "Flow control: number of UIH frames allowed to send", HFILL}
998 /* Setup protocol subtree array */
999 static gint *ett[] = {
1000 &ett_btrfcomm,
1001 &ett_btrfcomm_ctrl,
1002 &ett_addr,
1003 &ett_control,
1004 &ett_mcc,
1005 &ett_ctrl_pn_ci,
1006 &ett_ctrl_pn_v24,
1007 &ett_dlci,
1008 &ett_mcc_dlci
1011 static ei_register_info ei[] = {
1012 { &ei_btrfcomm_mcc_length_bad, { "btrfcomm.mcc_length_bad", PI_MALFORMED, PI_ERROR, "Huge MCC length", EXPFILL }},
1015 /* Register the protocol name and description */
1016 proto_btrfcomm = proto_register_protocol("Bluetooth RFCOMM Protocol", "BT RFCOMM", "btrfcomm");
1017 new_register_dissector("btrfcomm", dissect_btrfcomm, proto_btrfcomm);
1019 /* Required function calls to register the header fields and subtrees used */
1020 proto_register_field_array(proto_btrfcomm, hf, array_length(hf));
1021 proto_register_subtree_array(ett, array_length(ett));
1022 expert_btrfcomm = expert_register_protocol(proto_btrfcomm);
1023 expert_register_field_array(expert_btrfcomm, ei, array_length(ei));
1025 rfcomm_service_dissector_table = register_dissector_table("btrfcomm.service", "BT RFCOMM Service", FT_UINT16, BASE_HEX);
1026 rfcomm_channel_dissector_table = register_dissector_table("btrfcomm.channel", "BT RFCOMM Channel", FT_UINT16, BASE_DEC);
1028 module = prefs_register_protocol(proto_btrfcomm, NULL);
1029 prefs_register_static_text_preference(module, "rfcomm.version",
1030 "Bluetooth Protocol RFCOMM version: 1.1", "Version of protocol supported by this dissector.");
1032 prefs_register_bool_preference(module, "rfcomm.decode_by.enabled",
1033 "Enable Force Decode by Channel",
1034 "Turn on/off decode by next rules",
1035 &rfcomm_channels_enabled);
1037 uat_rfcomm_channels = uat_new("Force Decode by Channel",
1038 sizeof(uat_rfcomm_channels_t),
1039 "rfcomm_channels",
1040 TRUE,
1041 (void**) &rfcomm_channels,
1042 &num_rfcomm_channels,
1043 UAT_AFFECTS_DISSECTION,
1044 NULL,
1045 NULL,
1046 NULL,
1047 NULL,
1048 NULL,
1049 uat_rfcomm_channels_fields);
1051 prefs_register_uat_preference(module, "rfcomm.channels",
1052 "Force Decode by channel",
1053 "Decode by channel",
1054 uat_rfcomm_channels);
1057 static int
1058 btrfcomm_sdp_tap_packet(void *arg _U_, packet_info *pinfo _U_, epan_dissect_t *edt _U_, const void *arg2)
1060 const sdp_package_t *sdp_package = (const sdp_package_t *) arg2;
1062 if (sdp_service_infos == NULL) {
1063 sdp_service_infos = sdp_package->service_infos;
1066 return 0;
1069 void
1070 proto_reg_handoff_btrfcomm(void)
1072 dissector_handle_t btrfcomm_handle;
1074 btrfcomm_handle = find_dissector("btrfcomm");
1075 dissector_add_uint("btl2cap.psm", BTL2CAP_PSM_RFCOMM, btrfcomm_handle);
1076 dissector_add_handle("btl2cap.cid", btrfcomm_handle);
1078 data_handle = find_dissector("data");
1080 /* tap into the btsdp dissector to look for rfcomm channel infomation that
1081 helps us determine the type of rfcomm payload, i.e. which service is
1082 using the channels so we know which sub-dissector to call */
1083 register_tap_listener("btsdp", NULL, NULL, TL_IS_DISSECTOR_HELPER, NULL, btrfcomm_sdp_tap_packet, NULL);
1086 /* Bluetooth Dial-Up Networking (DUN) profile dissection */
1087 static gint
1088 dissect_btdun(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
1090 proto_item *ti;
1091 proto_tree *st;
1092 gboolean is_at_cmd;
1093 guint i, length;
1095 length = tvb_length(tvb);
1097 col_set_str(pinfo->cinfo, COL_PROTOCOL, "DUN");
1099 ti = proto_tree_add_item(tree, proto_btdun, tvb, 0, -1, ENC_NA);
1100 st = proto_item_add_subtree(ti, ett_btdun);
1102 is_at_cmd = TRUE;
1103 for(i = 0; i < length && is_at_cmd; i++) {
1104 is_at_cmd = tvb_get_guint8(tvb, i) < 0x7d;
1107 if (is_at_cmd) {
1108 /* presumably an AT command */
1109 col_add_fstr(pinfo->cinfo, COL_INFO, "%s \"%s\"",
1110 (pinfo->p2p_dir == P2P_DIR_SENT) ? "Sent" : "Rcvd",
1111 tvb_format_text(tvb, 0, length));
1113 proto_tree_add_item(st, hf_dun_at_cmd, tvb, 0, -1, ENC_ASCII|ENC_NA);
1115 else {
1116 /* ... or raw PPP */
1117 if (ppp_handle)
1118 call_dissector(ppp_handle, tvb, pinfo, tree);
1119 else {
1120 /* TODO: remove the above 'if' and this 'else-body' when "ppp_raw_hdlc" is available, requires that it is
1121 made non-anonymous in ppp dissector to use */
1122 col_set_str(pinfo->cinfo, COL_PROTOCOL, "PPP");
1123 col_add_fstr(pinfo->cinfo, COL_INFO, "%s <PPP frame>", (pinfo->p2p_dir == P2P_DIR_SENT) ? "Sent" : "Rcvd");
1125 call_dissector(data_handle, tvb, pinfo, tree);
1129 return length;
1132 void
1133 proto_register_btdun(void)
1135 static hf_register_info hf[] = {
1136 { &hf_dun_at_cmd,
1137 { "AT Cmd", "btdun.atcmd",
1138 FT_STRING, BASE_NONE, NULL, 0,
1139 "AT Command", HFILL}
1143 /* Setup protocol subtree array */
1144 static gint *ett[] = {
1145 &ett_btdun
1148 proto_btdun = proto_register_protocol("Bluetooth DUN Packet", "BT DUN", "btdun");
1149 new_register_dissector("btdun", dissect_btdun, proto_btdun);
1151 /* Required function calls to register the header fields and subtrees used */
1152 proto_register_field_array(proto_btdun, hf, array_length(hf));
1153 proto_register_subtree_array(ett, array_length(ett));
1156 void
1157 proto_reg_handoff_btdun(void)
1159 dissector_handle_t btdun_handle;
1161 btdun_handle = find_dissector("btdun");
1163 dissector_add_uint("btrfcomm.service", BTSDP_DUN_SERVICE_UUID, btdun_handle);
1164 dissector_add_handle("btrfcomm.channel", btdun_handle);
1166 ppp_handle = find_dissector("ppp_raw_hdlc");
1169 /* Bluetooth Serial Port profile (SPP) dissection */
1170 static gint
1171 dissect_btspp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
1173 proto_item *ti;
1174 proto_tree *st;
1175 gboolean ascii_only;
1176 guint i, length = tvb_length(tvb);
1178 col_set_str(pinfo->cinfo, COL_PROTOCOL, "SPP");
1180 ti = proto_tree_add_item(tree, proto_btspp, tvb, 0, -1, ENC_NA);
1181 st = proto_item_add_subtree(ti, ett_btspp);
1183 length = MIN(length, 60);
1184 ascii_only = TRUE;
1185 for(i = 0; i < length && ascii_only; i++) {
1186 ascii_only = tvb_get_guint8(tvb, i) < 0x80;
1189 if (ascii_only) {
1190 col_add_fstr(pinfo->cinfo, COL_INFO, "%s \"%s%s\"",
1191 (pinfo->p2p_dir == P2P_DIR_SENT) ? "Sent" : "Rcvd",
1192 tvb_format_text(tvb, 0, length),
1193 (tvb_length(tvb) > length) ? "..." : "");
1196 proto_tree_add_item(st, hf_spp_data, tvb, 0, -1, ENC_NA);
1198 return tvb_length(tvb);
1201 void
1202 proto_register_btspp(void)
1204 static hf_register_info hf[] = {
1205 { &hf_spp_data,
1206 { "Data", "btspp.data",
1207 FT_BYTES, BASE_NONE, NULL, 0,
1208 NULL, HFILL }
1212 /* Setup protocol subtree array */
1213 static gint *ett[] = {
1214 &ett_btspp
1217 proto_btspp = proto_register_protocol("Bluetooth SPP Packet", "BT SPP", "btspp");
1218 new_register_dissector("btspp", dissect_btspp, proto_btspp);
1220 /* Required function calls to register the header fields and subtrees used */
1221 proto_register_field_array(proto_btspp, hf, array_length(hf));
1222 proto_register_subtree_array(ett, array_length(ett));
1225 void
1226 proto_reg_handoff_btspp(void)
1228 dissector_handle_t btspp_handle;
1230 btspp_handle = find_dissector("btspp");
1232 dissector_add_uint("btrfcomm.service", BTSDP_SPP_SERVICE_UUID, btspp_handle);
1233 dissector_add_handle("btrfcomm.channel", btspp_handle);
1237 /* Bluetooth Global Navigation Satellite System profile (GNSS) dissection */
1238 static gint
1239 dissect_btgnss(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
1241 proto_item *main_item;
1242 proto_tree *main_tree;
1244 col_set_str(pinfo->cinfo, COL_PROTOCOL, "GNSS");
1246 main_item = proto_tree_add_item(tree, proto_btgnss, tvb, 0, -1, ENC_NA);
1247 main_tree = proto_item_add_subtree(main_item, ett_btgnss);
1249 col_add_fstr(pinfo->cinfo, COL_INFO, "%s %s",
1250 (pinfo->p2p_dir == P2P_DIR_SENT) ? "Sent" : "Rcvd",
1251 tvb_format_text(tvb, 0, tvb_length(tvb)));
1253 /* GNSS using NMEA-0183 protocol, but it is not available */
1254 proto_tree_add_item(main_tree, hf_gnss_data, tvb, 0, -1, ENC_NA | ENC_ASCII);
1256 return tvb_length(tvb);
1259 void
1260 proto_register_btgnss(void)
1262 static hf_register_info hf[] = {
1263 { &hf_gnss_data,
1264 { "Data", "btgnss.data",
1265 FT_STRING, BASE_NONE, NULL, 0,
1266 NULL, HFILL }
1270 static gint *ett[] = {
1271 &ett_btgnss
1274 proto_btgnss = proto_register_protocol("Bluetooth GNSS Profile", "BT GNSS", "btgnss");
1275 new_register_dissector("btgnss", dissect_btgnss, proto_btgnss);
1277 proto_register_field_array(proto_btgnss, hf, array_length(hf));
1278 proto_register_subtree_array(ett, array_length(ett));
1281 void
1282 proto_reg_handoff_btgnss(void)
1284 dissector_handle_t btgnss_handle;
1286 btgnss_handle = find_dissector("btgnss");
1288 dissector_add_uint("btrfcomm.service", BTSDP_GNSS_UUID, btgnss_handle);
1289 dissector_add_uint("btrfcomm.service", BTSDP_GNSS_SERVER_UUID, btgnss_handle);
1290 dissector_add_handle("btrfcomm.channel", btgnss_handle);
1294 * Editor modelines - http://www.wireshark.org/tools/modelines.html
1296 * Local variables:
1297 * c-basic-offset: 4
1298 * tab-width: 8
1299 * indent-tabs-mode: nil
1300 * End:
1302 * vi: set shiftwidth=4 tabstop=8 expandtab:
1303 * :indentSize=4:tabSize=8:noTabs=true: