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
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.
35 #include <epan/packet.h>
36 #include <epan/prefs.h>
37 #include <epan/expert.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
;
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",
145 UAT_FLD_PROTO(rfcomm_channels
, payload_proto
, "Payload protocol",
146 "Dissector name used to decode RFCOMM channel"),
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"},
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)"},
177 static const value_string vs_frame_type
[] = {
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)"},
191 static const value_string vs_frame_type_short
[] = {
198 #if 0 /* specified by 07.10, but not used by RFCOMM */
205 static const value_string vs_ctl
[] = {
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)"},
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)"},
236 static const value_string vs_ea
[] = {
237 {1, "Last field octet"},
238 {0, "More field octets following"},
242 static const value_string vs_cr
[] = {
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
) {
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
;
270 get_le_multi_byte_value(tvbuff_t
*tvb
, int offset
, proto_tree
*tree
, guint32
*val_ptr
, int hf_index
)
274 int start_offset
= offset
;
277 byte
= tvb_get_guint8(tvb
, offset
);
279 val
|= ((byte
>> 1) & 0xff) << (bc
++ * 7);
280 } while ((byte
& 0x1) == 0);
285 proto_tree_add_uint(tree
, hf_index
, tvb
, start_offset
, offset
- start_offset
, val
);
293 dissect_ctrl_pn(proto_tree
*t
, tvbuff_t
*tvb
, int offset
, guint8
*mcc_channel
)
297 proto_tree
*dlci_tree
;
298 proto_item
*dlci_item
;
303 proto_tree_add_item(t
, hf_mcc_pn_zeros_padding
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
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
);
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
);
327 proto_tree_add_item(t
, hf_priority
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
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);
336 proto_tree_add_item(t
, hf_max_frame_size
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
340 proto_tree_add_item(t
, hf_max_retrans
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
343 /* error recovery mode */
344 proto_tree_add_item(t
, hf_error_recovery_mode
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
351 dissect_ctrl_msc(proto_tree
*t
, tvbuff_t
*tvb
, int offset
, int length
, guint8
*mcc_channel
)
356 proto_tree
*dlci_tree
;
357 proto_item
*dlci_item
;
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
);
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
);
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
);
397 proto_item_set_len(it
, offset
- start_offset
);
403 dissect_btrfcomm_address(tvbuff_t
*tvb
, int offset
, proto_tree
*tree
, guint8
*ea_flagp
, guint8
*cr_flagp
, guint8
*dlcip
)
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;
418 cr_flag
= (flags
& 0x02) ? 1 : 0;
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
);
446 dissect_btrfcomm_control(tvbuff_t
*tvb
, int offset
, proto_tree
*tree
, guint8
*pf_flagp
, guint8
*frame_typep
)
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;
459 frame_type
= flags
& 0xef;
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
);
478 dissect_btrfcomm_payload_length(tvbuff_t
*tvb
, int offset
, proto_tree
*tree
, guint16
*frame_lenp
)
481 int start_offset
= offset
;
483 frame_len
= tvb_get_guint8(tvb
, offset
);
486 if (frame_len
& 0x01) {
487 frame_len
>>= 1; /* 0 - 127 */
489 frame_len
>>= 1; /* 128 - ... */
490 frame_len
|= (tvb_get_guint8(tvb
, offset
)) << 7;
494 proto_tree_add_uint(tree
, hf_len
, tvb
, start_offset
, offset
- start_offset
, frame_len
);
497 *frame_lenp
= frame_len
;
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
;
508 proto_tree
*mcc_tree
;
509 guint8 flags
, mcc_cr_flag
, mcc_ea_flag
;
512 flags
= tvb_get_guint8(tvb
, offset
);
514 mcc_cr_flag
= (flags
& 0x2) ? 1 : 0;
516 *mcc_cr_flagp
= mcc_cr_flag
;
519 mcc_ea_flag
= flags
& 0x1;
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 */
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
);
544 dissect_btrfcomm(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
547 proto_tree
*rfcomm_tree
;
550 guint8 dlci
, cr_flag
, ea_flag
;
551 guint8 frame_type
, pf_flag
;
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
) {
563 col_set_str(pinfo
->cinfo
, COL_INFO
, "Sent ");
566 col_set_str(pinfo
->cinfo
, COL_INFO
, "Rcvd ");
569 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "Unknown direction %d ",
574 l2cap_data
= (btl2cap_data_t
*) data
;
575 DISSECTOR_ASSERT(l2cap_data
);
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
);
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
;
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
;
607 k_service_type
= BTSDP_RFCOMM_PROTOCOL_UUID
;
608 k_service_channel
= dlci
>> 1;
609 k_frame_number
= pinfo
->fd
->num
;
612 key
[0].key
= &k_interface_id
;
614 key
[1].key
= &k_adapter_id
;
616 key
[2].key
= &k_sdp_psm
;
618 key
[3].key
= &k_direction
;
620 key
[4].key
= &k_bd_addr_oui
;
622 key
[5].key
= &k_bd_addr_id
;
624 key
[6].key
= &k_service_type
;
626 key
[7].key
= &k_service_channel
;
628 key
[8].key
= &k_frame_number
;
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)) {
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"));
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
);
668 fcs_offset
= offset
+ frame_len
;
670 /* multiplexer control command */
671 if (!dlci
&& frame_len
) {
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
;
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
);
686 offset
= dissect_btrfcomm_MccType(tvb
, offset
, ctrl_tree
, &mcc_cr_flag
, &mcc_ea_flag
, &mcc_type
);
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
);
697 case 0x20: /* DLC Parameter Negotiation */
698 dissect_ctrl_pn(ctrl_tree
, tvb
, offset
, &mcc_channel
);
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
);
715 case 0x38: /* Modem Status Command */
716 dissect_ctrl_msc(ctrl_tree
, tvb
, offset
, length
, &mcc_channel
);
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 ");
729 col_append_fstr(pinfo
->cinfo
, COL_INFO
, "%s ", val_to_str_const(mcc_type
, vs_ctl
, "Unknown"));
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
;
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
);
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
);
778 proto_register_btrfcomm(void)
781 expert_module_t
*expert_btrfcomm
;
783 static hf_register_info hf
[] = {
785 { "DLCI", "btrfcomm.dlci",
786 FT_UINT8
, BASE_HEX
, NULL
, 0xFC,
787 "RFCOMM Data Link Connection Identifier", HFILL
}
790 { "Channel", "btrfcomm.channel",
791 FT_UINT8
, BASE_DEC
, NULL
, 0xF8,
792 "RFCOMM Channel", HFILL
}
795 {"Direction", "btrfcomm.direction",
796 FT_UINT8
, BASE_HEX
, NULL
, 0x04,
800 { "Priority", "btrfcomm.priority",
801 FT_UINT8
, BASE_DEC
, NULL
, 0x3f,
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
}
810 { "Maximum number of retransmissions", "btrfcomm.max_retrans",
811 FT_UINT8
, BASE_DEC
, NULL
, 0,
814 { &hf_error_recovery_mode
,
815 { "Error Recovery Mode", "btrfcomm.error_recovery_mode",
816 FT_UINT8
, BASE_DEC
, NULL
, 0x07,
820 { "EA Flag", "btrfcomm.ea",
821 FT_UINT8
, BASE_HEX
, VALS(vs_ea
), 0x01,
822 "EA flag (should be always 1)", HFILL
}
825 { "C/R Flag", "btrfcomm.cr",
826 FT_UINT8
, BASE_HEX
, VALS(vs_cr
), 0x02,
827 "Command/Response flag", HFILL
}
830 { "Multiplexer Control Command", "btrfcomm.mcc",
831 FT_NONE
, BASE_NONE
, NULL
, 0x00,
834 { &hf_mcc_pn_parameters
,
835 { "Parameters", "btrfcomm.mcc.pn_parameters",
836 FT_NONE
, BASE_NONE
, NULL
, 0x00,
840 { "Types", "btrfcomm.mcc.types",
841 FT_NONE
, BASE_NONE
, NULL
, 0x00,
845 { "EA Flag", "btrfcomm.mcc.ea",
846 FT_UINT8
, BASE_HEX
, VALS(vs_ea
), 0x01,
847 "RFCOMM MCC EA flag", HFILL
}
850 { "C/R Flag", "btrfcomm.mcc.cr",
851 FT_UINT8
, BASE_HEX
, VALS(vs_cr
), 0x02,
852 "Command/Response flag", HFILL
}
855 { "Ones padding", "btrfcomm.mcc.padding",
856 FT_UINT8
, BASE_HEX
, NULL
, 0x02,
860 { "MCC DLCI", "btrfcomm.mcc.dlci",
861 FT_UINT8
, BASE_HEX
, NULL
, 0xFC,
862 "RFCOMM MCC Data Link Connection Identifier", HFILL
}
865 { "MCC Channel", "btrfcomm.mcc.channel",
866 FT_UINT8
, BASE_DEC
, NULL
, 0xF8,
867 "RFCOMM MCC Channel", HFILL
}
870 { "MCC Direction", "btrfcomm.mcc.direction",
871 FT_UINT8
, BASE_HEX
, NULL
, 0x04,
872 "RFCOMM MCC Direction", HFILL
}
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
}
895 { "MCC Command Type", "btrfcomm.mcc.cmd",
896 FT_UINT8
, BASE_HEX
, VALS(vs_ctl
), 0xFC,
897 "Command Type", HFILL
}
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,
910 { "P/F flag", "btrfcomm.pf",
911 FT_UINT8
, BASE_HEX
, NULL
, 0x10,
912 "Poll/Final bit", HFILL
}
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",
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
}
926 { "Payload length", "btrfcomm.len",
927 FT_UINT16
, BASE_DEC
, NULL
, 0,
928 "Frame length", HFILL
}
931 { "MCC Length", "btrfcomm.mcc.len",
932 FT_UINT16
, BASE_DEC
, NULL
, 0,
933 "Length of MCC data", HFILL
}
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,
946 { "Flow Control (FC)", "btrfcomm.msc.fc",
947 FT_UINT8
, BASE_HEX
, NULL
, 0x02,
948 "Flow Control", HFILL
}
951 { "Ready To Communicate (RTC)", "btrfcomm.msc.rtc",
952 FT_UINT8
, BASE_HEX
, NULL
, 0x04,
953 "Ready To Communicate", HFILL
}
956 { "Ready To Receive (RTR)", "btrfcomm.msc.rtr",
957 FT_UINT8
, BASE_HEX
, NULL
, 0x08,
958 "Ready To Receive", HFILL
}
961 { "Incoming Call Indicator (IC)", "btrfcomm.msc.ic",
962 FT_UINT8
, BASE_HEX
, NULL
, 0x40,
963 "Incoming Call Indicator", HFILL
}
966 { "Data Valid (DV)", "btrfcomm.msc.dv",
967 FT_UINT8
, BASE_HEX
, NULL
, 0x80,
971 { "Length of break in units of 200ms", "btrfcomm.msc.bl",
972 FT_UINT8
, BASE_DEC
, NULL
, 0xF0,
975 { &hf_msc_break_bits
,
976 { "Break Bits", "btrfcomm.msc.break_bits",
977 FT_UINT8
, BASE_DEC
, NULL
, 0xE0,
981 { "Address", "btrfcomm.address",
982 FT_NONE
, BASE_NONE
, NULL
, 0x00,
986 { "Control", "btrfcomm.control",
987 FT_NONE
, BASE_NONE
, NULL
, 0x00,
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
[] = {
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
),
1041 (void**) &rfcomm_channels
,
1042 &num_rfcomm_channels
,
1043 UAT_AFFECTS_DISSECTION
,
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
);
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
;
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 */
1088 dissect_btdun(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
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
);
1103 for(i
= 0; i
< length
&& is_at_cmd
; i
++) {
1104 is_at_cmd
= tvb_get_guint8(tvb
, i
) < 0x7d;
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
);
1116 /* ... or raw PPP */
1118 call_dissector(ppp_handle
, tvb
, pinfo
, tree
);
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
);
1133 proto_register_btdun(void)
1135 static hf_register_info hf
[] = {
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
[] = {
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
));
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 */
1171 dissect_btspp(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
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);
1185 for(i
= 0; i
< length
&& ascii_only
; i
++) {
1186 ascii_only
= tvb_get_guint8(tvb
, i
) < 0x80;
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
);
1202 proto_register_btspp(void)
1204 static hf_register_info hf
[] = {
1206 { "Data", "btspp.data",
1207 FT_BYTES
, BASE_NONE
, NULL
, 0,
1212 /* Setup protocol subtree array */
1213 static gint
*ett
[] = {
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
));
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 */
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
);
1260 proto_register_btgnss(void)
1262 static hf_register_info hf
[] = {
1264 { "Data", "btgnss.data",
1265 FT_STRING
, BASE_NONE
, NULL
, 0,
1270 static gint
*ett
[] = {
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
));
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
1299 * indent-tabs-mode: nil
1302 * vi: set shiftwidth=4 tabstop=8 expandtab:
1303 * :indentSize=4:tabSize=8:noTabs=true: