2 * Routines for the Bluetooth L2CAP dissection
3 * Copyright 2002, Christoph Scholz <scholz@cs.uni-bonn.de>
4 * From: http://affix.sourceforge.net/archive/ethereal_affix-3.patch
6 * Refactored for wireshark checkin
11 * Wireshark - Network traffic analyzer
12 * By Gerald Combs <gerald@wireshark.org>
13 * Copyright 1998 Gerald Combs
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
36 #include <epan/packet.h>
38 #include <epan/emem.h>
39 #include <epan/expert.h>
41 #include "packet-btsdp.h"
42 #include "packet-bthci_acl.h"
43 #include "packet-btl2cap.h"
45 /* Initialize the protocol and registered fields */
46 static int proto_btl2cap = -1;
47 static int hf_btl2cap_length = -1;
48 static int hf_btl2cap_cid = -1;
49 static int hf_btl2cap_payload = -1;
50 static int hf_btl2cap_command = -1;
51 static int hf_btl2cap_cmd_code = -1;
52 static int hf_btl2cap_cmd_ident = -1;
53 static int hf_btl2cap_cmd_length = -1;
54 static int hf_btl2cap_cmd_data = -1;
55 static int hf_btl2cap_psm = -1;
56 static int hf_btl2cap_psm_dynamic = -1;
57 static int hf_btl2cap_scid = -1;
58 static int hf_btl2cap_dcid = -1;
59 static int hf_btl2cap_icid = -1;
60 static int hf_btl2cap_controller = -1;
61 static int hf_btl2cap_dcontroller = -1;
62 static int hf_btl2cap_result = -1;
63 static int hf_btl2cap_move_result = -1;
64 static int hf_btl2cap_move_confirmation_result = -1;
65 static int hf_btl2cap_status = -1;
66 static int hf_btl2cap_rej_reason = -1;
67 static int hf_btl2cap_sig_mtu = -1;
68 static int hf_btl2cap_info_mtu = -1;
69 static int hf_btl2cap_info_flowcontrol = -1;
70 static int hf_btl2cap_info_retransmission = -1;
71 static int hf_btl2cap_info_bidirqos = -1;
72 static int hf_btl2cap_info_enh_retransmission = -1;
73 static int hf_btl2cap_info_streaming = -1;
74 static int hf_btl2cap_info_fcs = -1;
75 static int hf_btl2cap_info_flow_spec = -1;
76 static int hf_btl2cap_info_fixedchan = -1;
77 static int hf_btl2cap_info_fixedchans = -1;
78 static int hf_btl2cap_info_fixedchans_null = -1;
79 static int hf_btl2cap_info_fixedchans_signal = -1;
80 static int hf_btl2cap_info_fixedchans_connless = -1;
81 static int hf_btl2cap_info_fixedchans_amp_man = -1;
82 static int hf_btl2cap_info_fixedchans_amp_test = -1;
83 static int hf_btl2cap_info_window = -1;
84 static int hf_btl2cap_info_unicast = -1;
85 static int hf_btl2cap_info_type = -1;
86 static int hf_btl2cap_info_result = -1;
87 static int hf_btl2cap_continuation_flag = -1;
88 static int hf_btl2cap_configuration_result = -1;
89 static int hf_btl2cap_info_extfeatures = -1;
90 static int hf_btl2cap_option = -1;
91 static int hf_btl2cap_option_type = -1;
92 static int hf_btl2cap_option_length = -1;
93 static int hf_btl2cap_option_mtu = -1;
94 static int hf_btl2cap_option_flushTO = -1;
95 static int hf_btl2cap_option_flush_to_us = -1;
96 static int hf_btl2cap_option_flags = -1;
97 static int hf_btl2cap_option_service_type = -1;
98 static int hf_btl2cap_option_tokenrate = -1;
99 static int hf_btl2cap_option_tokenbucketsize = -1;
100 static int hf_btl2cap_option_peakbandwidth = -1;
101 static int hf_btl2cap_option_latency = -1;
102 static int hf_btl2cap_option_delayvariation = -1;
103 static int hf_btl2cap_option_retransmissionmode = -1;
104 static int hf_btl2cap_option_txwindow = -1;
105 static int hf_btl2cap_option_maxtransmit = -1;
106 static int hf_btl2cap_option_retransmittimeout = -1;
107 static int hf_btl2cap_option_monitortimeout = -1;
108 static int hf_btl2cap_option_mps = -1;
109 static int hf_btl2cap_option_fcs = -1;
110 static int hf_btl2cap_option_window = -1;
111 static int hf_btl2cap_option_identifier = -1;
112 static int hf_btl2cap_option_sdu_size = -1;
113 static int hf_btl2cap_option_sdu_arrival_time = -1;
114 static int hf_btl2cap_option_access_latency = -1;
115 static int hf_btl2cap_control = -1;
116 static int hf_btl2cap_control_sar = -1;
117 static int hf_btl2cap_control_reqseq = -1;
118 static int hf_btl2cap_control_txseq = -1;
119 static int hf_btl2cap_control_retransmissiondisable = -1;
120 static int hf_btl2cap_control_supervisory = -1;
121 static int hf_btl2cap_control_type = -1;
122 static int hf_btl2cap_fcs = -1;
123 static int hf_btl2cap_sdulength = -1;
124 static int hf_btl2cap_continuation_to = -1;
125 static int hf_btl2cap_reassembled_in = -1;
127 /* Initialize the subtree pointers */
128 static gint ett_btl2cap = -1;
129 static gint ett_btl2cap_cmd = -1;
130 static gint ett_btl2cap_option = -1;
131 static gint ett_btl2cap_extfeatures = -1;
132 static gint ett_btl2cap_fixedchans = -1;
133 static gint ett_btl2cap_control = -1;
136 /* Initialize dissector table */
137 static dissector_table_t l2cap_psm_dissector_table;
138 static dissector_table_t l2cap_cid_dissector_table;
139 static dissector_table_t l2cap_service_dissector_table;
141 /* This table maps cid values to psm values.
142 * The same table is used both for SCID and DCID.
143 * For received CIDs we mask the cid with 0x8000 in this table
145 static emem_tree_t *cid_to_psm_table = NULL;
146 static emem_tree_t *psm_to_service_table = NULL;
148 typedef struct _config_data_t {
151 emem_tree_t *start_fragments; /* indexed by pinfo->fd->num */
153 typedef struct _psm_data_t {
155 gboolean local_service;
160 static const value_string command_code_vals[] = {
161 { 0x01, "Command Reject" },
162 { 0x02, "Connection Request" },
163 { 0x03, "Connection Response" },
164 { 0x04, "Configure Request" },
165 { 0x05, "Configure Response" },
166 { 0x06, "Disconnect Request" },
167 { 0x07, "Disconnect Response" },
168 { 0x08, "Echo Request" },
169 { 0x09, "Echo Response" },
170 { 0x0A, "Information Request" },
171 { 0x0B, "Information Response" },
172 { 0x0C, "Create Channel Request" },
173 { 0x0D, "Create Channel Response" },
174 { 0x0E, "Move Channel Request" },
175 { 0x0F, "Move Channel Response" },
176 { 0x10, "Move Channel Confirmation" },
177 { 0x11, "Move Channel Confirmation Response" },
182 static const value_string psm_vals[] = {
184 { 0x0003, "RFCOMM" },
185 { 0x0005, "TCS-BIN" },
186 { 0x0007, "TCS-BIN-CORDLESS" },
188 { 0x0011, "HID-Control" },
189 { 0x0013, "HID-Interrupt" },
191 { 0x0017, "AVCTP-Control" },
193 { 0x001B, "AVCTP-Browsing" },
194 { 0x001D, "UDI_C-Plane" },
199 static const value_string result_vals[] = {
200 { 0x0000, "Successful" },
201 { 0x0001, "Pending" },
202 { 0x0002, "Refused - PSM not supported" },
203 { 0x0003, "Refused - security block" },
204 { 0x0004, "Refused - no resources available" },
205 { 0x0005, "Refused - Controller ID not supported" },
209 static const value_string move_result_vals[] = {
210 { 0x0000, "Success" },
211 { 0x0001, "Pending" },
212 { 0x0002, "Refused - Controller ID not supported" },
213 { 0x0003, "Refused - New Controller ID is same as old" },
214 { 0x0004, "Refused - Configuration not supported" },
215 { 0x0005, "Refused - Move Channel collision" },
216 { 0x0006, "Refused - Channel not allowed to be moved" },
220 static const value_string move_result_confirmation_vals[] = {
221 { 0x0000, "Success - both sides succeed" },
222 { 0x0001, "Failure - one or both sides refuse" },
226 static const value_string configuration_result_vals[] = {
227 { 0x0000, "Success"},
228 { 0x0001, "Failure - unacceptable parameters" },
229 { 0x0002, "Failure - reject (no reason provided)" },
230 { 0x0003, "Failure - unknown options" },
231 { 0x0004, "Pending" },
232 { 0x0005, "Failure - flow spec rejected" },
236 static const value_string status_vals[] = {
237 { 0x0000, "No further information available" },
238 { 0x0001, "Authentication pending" },
239 { 0x0002, "Authorization pending" },
243 static const value_string reason_vals[] = {
244 { 0x0000, "Command not understood" },
245 { 0x0001, "Signaling MTU exceeded" },
246 { 0x0002, "Invalid CID in request" },
250 static const value_string info_type_vals[] = {
251 { 0x0001, "Connectionless MTU" },
252 { 0x0002, "Extended Features Mask" },
253 { 0x0003, "Fixed Channels Supported" },
257 static const value_string info_result_vals[] = {
258 { 0x0000, "Success" },
259 { 0x0001, "Not Supported" },
263 static const value_string option_servicetype_vals[] = {
264 { 0x00, "No traffic" },
265 { 0x01, "Best effort (Default)" },
266 { 0x02, "Guaranteed" },
270 static const value_string option_type_vals[] = {
271 { 0x01, "Maximum Transmission Unit" },
272 { 0x02, "Flush Timeout" },
273 { 0x03, "Quality of Service" },
274 { 0x04, "Retransmission and Flow Control" },
276 { 0x06, "Extended Flow Specification" },
277 { 0x07, "Extended Window Size" },
281 static const value_string option_retransmissionmode_vals[] = {
282 { 0x00, "Basic Mode" },
283 { 0x01, "Retransmission Mode" },
284 { 0x02, "Flow Control Mode" },
285 { 0x03, "Enhanced Retransmission Mode" },
286 { 0x04, "Streaming Mode" },
290 static const value_string control_sar_vals[] = {
291 { 0x00, "Unsegmented" },
294 { 0x03, "Continuation" },
298 static const value_string control_supervisory_vals[] = {
306 static const value_string control_type_vals[] = {
312 static const value_string option_fcs_vals[] = {
314 { 0x01, "16-bit FCS" },
318 static const value_string ctrl_id_code_vals[] = {
319 { 0x00, "Bluetooth BR/EDR" },
320 { 0x01, "Wifi 802.11" },
325 dissect_comrej(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree)
329 reason = tvb_get_letohs(tvb, offset);
330 proto_tree_add_item(tree, hf_btl2cap_rej_reason, tvb, offset, 2, TRUE);
334 case 0x0000: /* Command not understood */
337 case 0x0001: /* Signaling MTU exceeded */
338 proto_tree_add_item(tree, hf_btl2cap_sig_mtu, tvb, offset, 2, TRUE);
342 case 0x0002: /* Invalid CID in requets */
343 proto_tree_add_item(tree, hf_btl2cap_scid, tvb, offset, 2, TRUE);
346 proto_tree_add_item(tree, hf_btl2cap_dcid, tvb, offset, 2, TRUE);
359 dissect_connrequest(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, gboolean is_ch_request)
362 psm_data_t *psm_data;
363 const gchar *psm_str = "<NONE>";
365 psm=tvb_get_letohs(tvb, offset);
366 if( psm < BTL2CAP_DYNAMIC_PSM_START ) {
367 proto_tree_add_item(tree, hf_btl2cap_psm, tvb, offset, 2, TRUE);
368 psm_str = val_to_str(psm, psm_vals, "Unknown PSM");
371 guint32 *service, token;
374 item = proto_tree_add_item(tree, hf_btl2cap_psm_dynamic, tvb, offset, 2, TRUE);
375 token = psm | ((pinfo->p2p_dir == P2P_DIR_RECV)?0x80000000:0x00000000);
376 service = se_tree_lookup32(psm_to_service_table, token);
379 psm_str = val_to_str(*service, vs_service_classes, "Unknown PSM");
380 proto_item_append_text(item," (%s)", psm_str);
385 scid=tvb_get_letohs(tvb, offset);
386 proto_tree_add_item(tree, hf_btl2cap_scid, tvb, offset, 2, TRUE);
390 col_append_fstr(pinfo->cinfo, COL_INFO, " (%s, SCID: 0x%04x)", psm_str, scid);
392 col_append_fstr(pinfo->cinfo, COL_INFO, " (SCID: 0x%04x)", scid);
394 if( is_ch_request ) {
395 proto_tree_add_item(tree, hf_btl2cap_controller, tvb, offset, 1, TRUE);
399 if (pinfo->fd->flags.visited == 0) {
400 psm_data=se_alloc(sizeof(psm_data_t));
402 psm_data->local_service = (pinfo->p2p_dir == P2P_DIR_RECV) ? TRUE : FALSE;
404 psm_data->in.txwindow=0;
405 psm_data->in.start_fragments=se_tree_create_non_persistent(EMEM_TREE_TYPE_RED_BLACK, "bthci_l2cap fragment starts");
406 psm_data->out.mode=0;
407 psm_data->out.txwindow=0;
408 psm_data->out.start_fragments=se_tree_create_non_persistent(EMEM_TREE_TYPE_RED_BLACK, "bthci_l2cap fragment starts");
409 se_tree_insert32(cid_to_psm_table, scid|((pinfo->p2p_dir == P2P_DIR_RECV)?0x8000:0x0000), psm_data);
416 dissect_movechanrequest(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree)
421 icid = tvb_get_letohs(tvb, offset);
422 proto_tree_add_item(tree, hf_btl2cap_icid, tvb, offset, 2, TRUE);
425 ctrl_id = tvb_get_guint8(tvb, offset);
426 proto_tree_add_item(tree, hf_btl2cap_dcontroller, tvb, offset, 1, TRUE);
429 col_append_fstr(pinfo->cinfo, COL_INFO, " (ICID: 0x%04x, move to %s)", icid, val_to_str(ctrl_id, ctrl_id_code_vals, "Unknown controller"));
435 dissect_options(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree, int length, config_data_t *config_data)
437 proto_item *ti_option=NULL;
438 proto_tree *ti_option_subtree=NULL;
439 guint8 option_type, option_length;
442 option_type = tvb_get_guint8(tvb, offset);
443 option_length = tvb_get_guint8(tvb, offset+1);
445 ti_option = proto_tree_add_none_format(tree,
446 hf_btl2cap_option, tvb,
447 offset, option_length + 2,
449 ti_option_subtree = proto_item_add_subtree(ti_option, ett_btl2cap_option);
450 proto_tree_add_item(ti_option_subtree, hf_btl2cap_option_type, tvb, offset, 1, TRUE);
451 proto_tree_add_item(ti_option_subtree, hf_btl2cap_option_length, tvb, offset+1, 1, TRUE);
457 proto_tree_add_item(ti_option_subtree, hf_btl2cap_option_mtu, tvb, offset, 2, TRUE);
460 proto_item_append_text(ti_option, "MTU");
463 case 0x02: /* Flush timeout */
464 proto_tree_add_item(ti_option_subtree, hf_btl2cap_option_flushTO, tvb, offset, 2, TRUE);
467 proto_item_append_text(ti_option, "Flush Timeout");
471 proto_tree_add_item(ti_option_subtree, hf_btl2cap_option_flags, tvb, offset, 1, TRUE);
474 proto_tree_add_item(ti_option_subtree, hf_btl2cap_option_service_type, tvb, offset, 1, TRUE);
477 proto_tree_add_item(ti_option_subtree, hf_btl2cap_option_tokenrate, tvb, offset, 4, TRUE);
480 proto_tree_add_item(ti_option_subtree, hf_btl2cap_option_tokenbucketsize, tvb, offset, 4, TRUE);
483 proto_tree_add_item(ti_option_subtree, hf_btl2cap_option_peakbandwidth, tvb, offset, 4, TRUE);
486 proto_tree_add_item(ti_option_subtree, hf_btl2cap_option_latency, tvb, offset, 4, TRUE);
489 proto_tree_add_item(ti_option_subtree, hf_btl2cap_option_delayvariation, tvb, offset, 4, TRUE);
492 proto_item_append_text(ti_option, "QOS");
495 case 0x04: /* Retransmission and Flow Control*/
498 config_data->mode = tvb_get_guint8(tvb, offset);
499 config_data->txwindow = tvb_get_guint8(tvb, offset+1);
501 proto_tree_add_item(ti_option_subtree, hf_btl2cap_option_retransmissionmode, tvb, offset, 1, TRUE);
504 proto_tree_add_item(ti_option_subtree, hf_btl2cap_option_txwindow, tvb, offset, 1, TRUE);
507 proto_tree_add_item(ti_option_subtree, hf_btl2cap_option_maxtransmit, tvb, offset, 1, TRUE);
510 proto_tree_add_item(ti_option_subtree, hf_btl2cap_option_retransmittimeout, tvb, offset, 2, TRUE);
513 proto_tree_add_item(ti_option_subtree, hf_btl2cap_option_monitortimeout, tvb, offset, 2, TRUE);
516 proto_tree_add_item(ti_option_subtree, hf_btl2cap_option_mps, tvb, offset, 2, TRUE);
519 proto_item_append_text(ti_option, "Retransmission and Flow Control");
523 proto_tree_add_item(ti_option_subtree, hf_btl2cap_option_fcs, tvb, offset, 1, TRUE);
526 proto_item_append_text(ti_option, "FCS");
529 case 0x06: /* Extended Flow Specification */
530 proto_tree_add_item(ti_option_subtree, hf_btl2cap_option_identifier, tvb, offset, 1, TRUE);
533 proto_tree_add_item(ti_option_subtree, hf_btl2cap_option_service_type, tvb, offset, 1, TRUE);
536 proto_tree_add_item(ti_option_subtree, hf_btl2cap_option_sdu_size, tvb, offset, 2, TRUE);
539 proto_tree_add_item(ti_option_subtree, hf_btl2cap_option_sdu_arrival_time, tvb, offset, 4, TRUE);
542 proto_tree_add_item(ti_option_subtree, hf_btl2cap_option_access_latency, tvb, offset, 4, TRUE);
545 proto_tree_add_item(ti_option_subtree, hf_btl2cap_option_flush_to_us, tvb, offset, 4, TRUE);
548 proto_item_append_text(ti_option, "Extended Flow Specification");
551 case 0x07: /* Extended Window Size */
552 proto_tree_add_item(ti_option_subtree, hf_btl2cap_option_window, tvb, offset, 2, TRUE);
555 proto_item_append_text(ti_option, "Extended Window Size");
559 proto_item_append_text(ti_option, "unknown");
560 offset+=option_length;
564 length -= (option_length + 2);
572 dissect_configrequest(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree, guint16 length)
574 psm_data_t *psm_data;
575 config_data_t *config_data;
578 dcid = tvb_get_letohs(tvb, offset);
579 psm_data=se_tree_lookup32(cid_to_psm_table, dcid|((pinfo->p2p_dir==P2P_DIR_RECV)?0x0000:0x8000));
580 proto_tree_add_item(tree, hf_btl2cap_dcid, tvb, offset, 2, TRUE);
583 col_append_fstr(pinfo->cinfo, COL_INFO, " (DCID: 0x%04x)", dcid);
585 proto_tree_add_item(tree, hf_btl2cap_continuation_flag, tvb, offset, 2, TRUE);
588 if(tvb_length_remaining(tvb, offset)){
590 if(pinfo->p2p_dir==P2P_DIR_RECV)
591 config_data = &(psm_data->out);
593 config_data = &(psm_data->in);
596 offset=dissect_options(tvb, offset, pinfo, tree, length - 4, config_data);
604 dissect_inforequest(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree)
608 info_type=tvb_get_letohs(tvb, offset);
609 proto_tree_add_item(tree, hf_btl2cap_info_type, tvb, offset, 2, TRUE);
612 col_append_fstr(pinfo->cinfo, COL_INFO, " (%s)", val_to_str(info_type, info_type_vals, "Unknown type"));
617 dissect_inforesponse(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree)
619 guint16 info_type, result;
620 proto_item *ti_features=NULL;
621 proto_tree *ti_features_subtree=NULL;
624 info_type=tvb_get_letohs(tvb, offset);
625 proto_tree_add_item(tree, hf_btl2cap_info_type, tvb, offset, 2, TRUE);
628 result = tvb_get_letohs(tvb, offset);
629 proto_tree_add_item(tree, hf_btl2cap_info_result, tvb, offset, 2, TRUE);
632 col_append_fstr(pinfo->cinfo, COL_INFO, " (%s, %s)",
633 val_to_str(info_type, info_type_vals, "Unknown type"),
634 val_to_str(result, info_result_vals, "Unknown result"));
636 if(tvb_length_remaining(tvb, offset)) {
638 case 0x0001: /* Connectionless MTU */
639 proto_tree_add_item(tree, hf_btl2cap_info_mtu, tvb, offset, 2, TRUE);
643 case 0x0002: /* Extended Features */
644 ti_features = proto_tree_add_none_format(tree,
645 hf_btl2cap_info_extfeatures, tvb,
648 ti_features_subtree = proto_item_add_subtree(ti_features, ett_btl2cap_extfeatures);
649 features = tvb_get_letohl(tvb, offset);
651 proto_item_append_text(ti_features, "FlowControl ");
653 proto_item_append_text(ti_features, "Retransmission ");
655 proto_item_append_text(ti_features, "BiDirQOS ");
657 proto_item_append_text(ti_features, "EnhRetransmission ");
659 proto_item_append_text(ti_features, "Streaming ");
661 proto_item_append_text(ti_features, "FCS ");
663 proto_item_append_text(ti_features, "FlowSpec ");
665 proto_item_append_text(ti_features, "FixedChan ");
667 proto_item_append_text(ti_features, "WindowSize ");
669 proto_item_append_text(ti_features, "Unicast ");
670 proto_tree_add_item(ti_features_subtree, hf_btl2cap_info_flowcontrol, tvb, offset, 4, TRUE);
671 proto_tree_add_item(ti_features_subtree, hf_btl2cap_info_retransmission, tvb, offset, 4, TRUE);
672 proto_tree_add_item(ti_features_subtree, hf_btl2cap_info_bidirqos, tvb, offset, 4, TRUE);
673 proto_tree_add_item(ti_features_subtree, hf_btl2cap_info_enh_retransmission, tvb, offset, 4, TRUE);
674 proto_tree_add_item(ti_features_subtree, hf_btl2cap_info_streaming, tvb, offset, 4, TRUE);
675 proto_tree_add_item(ti_features_subtree, hf_btl2cap_info_fcs, tvb, offset, 4, TRUE);
676 proto_tree_add_item(ti_features_subtree, hf_btl2cap_info_flow_spec, tvb, offset, 4, TRUE);
677 proto_tree_add_item(ti_features_subtree, hf_btl2cap_info_fixedchan, tvb, offset, 4, TRUE);
678 proto_tree_add_item(ti_features_subtree, hf_btl2cap_info_window, tvb, offset, 4, TRUE);
679 proto_tree_add_item(ti_features_subtree, hf_btl2cap_info_unicast, tvb, offset, 4, TRUE);
684 case 0x0003: /* Fixed Channels Supported */
685 ti_features = proto_tree_add_none_format(tree,
686 hf_btl2cap_info_fixedchans, tvb,
688 "Fixed Channels Supported:");
689 ti_features_subtree = proto_item_add_subtree(ti_features, ett_btl2cap_fixedchans);
690 proto_tree_add_item(ti_features_subtree, hf_btl2cap_info_fixedchans_null, tvb, offset, 4, TRUE);
691 proto_tree_add_item(ti_features_subtree, hf_btl2cap_info_fixedchans_signal, tvb, offset, 4, TRUE);
692 proto_tree_add_item(ti_features_subtree, hf_btl2cap_info_fixedchans_connless, tvb, offset, 4, TRUE);
693 proto_tree_add_item(ti_features_subtree, hf_btl2cap_info_fixedchans_amp_man, tvb, offset, 4, TRUE);
695 proto_tree_add_item(ti_features_subtree, hf_btl2cap_info_fixedchans_amp_test, tvb, offset, 4, TRUE);
701 proto_tree_add_item(tree, hf_btl2cap_cmd_data, tvb, offset, -1, TRUE);
702 offset+=tvb_length_remaining(tvb, offset);
712 dissect_configresponse(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree, guint16 length)
714 psm_data_t *psm_data;
715 config_data_t *config_data;
716 guint16 scid, result;
718 scid = tvb_get_letohs(tvb, offset);
719 psm_data=se_tree_lookup32(cid_to_psm_table, scid|((pinfo->p2p_dir==P2P_DIR_RECV)?0x0000:0x8000));
720 proto_tree_add_item(tree, hf_btl2cap_scid, tvb, offset, 2, TRUE);
723 proto_tree_add_item(tree, hf_btl2cap_continuation_flag, tvb, offset, 2, TRUE);
726 result = tvb_get_letohs(tvb, offset);
727 proto_tree_add_item(tree, hf_btl2cap_configuration_result, tvb, offset, 2, TRUE);
730 col_append_fstr(pinfo->cinfo, COL_INFO, " - %s (SCID: 0x%04x)", val_to_str(result, configuration_result_vals, "Unknown"), scid);
732 if(tvb_length_remaining(tvb, offset)){
734 if(pinfo->p2p_dir==P2P_DIR_RECV)
735 config_data = &(psm_data->out);
737 config_data = &(psm_data->in);
740 offset=dissect_options(tvb, offset, pinfo, tree, length - 6, config_data);
747 dissect_connresponse(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
749 guint16 scid, dcid, result;
750 psm_data_t *psm_data;
752 dcid = tvb_get_letohs(tvb, offset);
753 proto_tree_add_item(tree, hf_btl2cap_dcid, tvb, offset, 2, TRUE);
756 scid = tvb_get_letohs(tvb, offset);
757 proto_tree_add_item(tree, hf_btl2cap_scid, tvb, offset, 2, TRUE);
760 result = tvb_get_letohs(tvb, offset);
761 proto_tree_add_item(tree, hf_btl2cap_result, tvb, offset, 2, TRUE);
764 proto_tree_add_item(tree, hf_btl2cap_status, tvb, offset, 2, TRUE);
768 col_append_fstr(pinfo->cinfo, COL_INFO, " - Success (SCID: 0x%04x, DCID: 0x%04x)", scid, dcid);
771 col_append_fstr(pinfo->cinfo, COL_INFO, " - %s (SCID: 0x%04x)", val_to_str(result, result_vals, "Unknown"), scid);
774 if (pinfo->fd->flags.visited == 0) {
775 if((psm_data=se_tree_lookup32(cid_to_psm_table, scid|((pinfo->p2p_dir==P2P_DIR_RECV)?0x0000:0x8000)))){
776 se_tree_insert32(cid_to_psm_table, dcid|((pinfo->p2p_dir == P2P_DIR_RECV)?0x8000:0x0000), psm_data);
784 dissect_chanresponse(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
786 return dissect_connresponse(tvb, offset, pinfo, tree);
790 dissect_movechanresponse(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree)
792 guint16 icid, result;
794 icid = tvb_get_letohs(tvb, offset);
795 proto_tree_add_item(tree, hf_btl2cap_icid, tvb, offset, 2, TRUE);
798 result = tvb_get_letohs(tvb, offset);
799 proto_tree_add_item(tree, hf_btl2cap_move_result, tvb, offset, 2, TRUE);
802 col_append_fstr(pinfo->cinfo, COL_INFO, " (ICID: 0x%04x, %s)", icid, val_to_str(result, move_result_vals, "Unknown result"));
808 dissect_movechanconfirmation(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree)
810 guint16 icid, result;
812 icid = tvb_get_letohs(tvb, offset);
813 proto_tree_add_item(tree, hf_btl2cap_icid, tvb, offset, 2, TRUE);
816 result = tvb_get_letohs(tvb, offset);
817 proto_tree_add_item(tree, hf_btl2cap_move_confirmation_result, tvb, offset, 2, TRUE);
820 col_append_fstr(pinfo->cinfo, COL_INFO, " (ICID: 0x%04x, %s)", icid, val_to_str(result, move_result_confirmation_vals, "Unknown result"));
826 dissect_movechanconfirmationresponse(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree)
830 icid = tvb_get_letohs(tvb, offset);
831 proto_tree_add_item(tree, hf_btl2cap_icid, tvb, offset, 2, TRUE);
834 col_append_fstr(pinfo->cinfo, COL_INFO, " (ICID: 0x%04x)", icid);
839 dissect_disconnrequestresponse(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree)
843 dcid = tvb_get_letohs(tvb, offset);
844 proto_tree_add_item(tree, hf_btl2cap_dcid, tvb, offset, 2, TRUE);
847 scid = tvb_get_letohs(tvb, offset);
848 proto_tree_add_item(tree, hf_btl2cap_scid, tvb, offset, 2, TRUE);
851 col_append_fstr(pinfo->cinfo, COL_INFO, " (SCID: 0x%04x, DCID: 0x%04x)", scid, dcid);
857 dissect_b_frame(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, proto_tree *btl2cap_tree, guint16 psm, gboolean local_service, guint16 length, int offset)
860 next_tvb = tvb_new_subset(tvb, offset, tvb_length_remaining(tvb, offset), length);
862 col_append_str(pinfo->cinfo, COL_INFO, "Connection oriented channel");
865 proto_item *psm_item;
866 guint32 *service =se_tree_lookup32(psm_to_service_table, (local_service<<31) | psm);
868 if( psm < BTL2CAP_DYNAMIC_PSM_START ) {
869 psm_item=proto_tree_add_uint(btl2cap_tree, hf_btl2cap_psm, tvb, offset, 0, psm);
872 psm_item=proto_tree_add_uint(btl2cap_tree, hf_btl2cap_psm_dynamic, tvb, offset, 0, psm);
874 proto_item_append_text(psm_item,": %s", val_to_str(*service, vs_service_classes, "Unknown service"));
876 PROTO_ITEM_SET_GENERATED(psm_item);
878 /* call next dissector */
879 if (!dissector_try_uint(l2cap_psm_dissector_table, (guint32) psm, next_tvb, pinfo, tree)) {
880 /* not a known fixed PSM, try to find a registered service to a dynamic PSM */
881 if(service != NULL && !dissector_try_uint(l2cap_service_dissector_table, *service, next_tvb, pinfo, tree)) {
882 /* unknown protocol. declare as data */
883 proto_tree_add_item(btl2cap_tree, hf_btl2cap_payload, tvb, offset, length, TRUE);
886 offset+=tvb_length_remaining(tvb, offset);
889 proto_tree_add_item(btl2cap_tree, hf_btl2cap_payload, tvb, offset, length, TRUE);
890 offset+=tvb_length_remaining(tvb, offset);
894 typedef struct _sdu_reassembly_t
901 int cur_off; /* counter used by reassembly */
905 dissect_i_frame(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, proto_tree *btl2cap_tree, psm_data_t *psm_data, guint16 length, int offset, config_data_t *config_data)
907 tvbuff_t *next_tvb = NULL;
908 guint16 control, segment;
910 proto_item* ti_control;
911 proto_tree* ti_control_subtree;
912 sdu_reassembly_t* mfp = NULL;
913 guint16 psm = (psm_data?psm_data->psm:0);
915 control = tvb_get_letohs(tvb, offset);
916 segment = (control & 0xC000) >> 14;
920 col_append_str(pinfo->cinfo, COL_INFO, "[I] Unsegmented SDU");
923 col_append_str(pinfo->cinfo, COL_INFO, "[I] Start SDU");
926 col_append_str(pinfo->cinfo, COL_INFO, "[I] End SDU");
929 col_append_str(pinfo->cinfo, COL_INFO, "[I] Continuation SDU");
932 ti_control = proto_tree_add_none_format(btl2cap_tree, hf_btl2cap_control, tvb,
933 offset, 2, "Control: %s reqseq:%d r:%d txseq:%d",
934 val_to_str((control & 0xC000) >> 14, control_sar_vals, "unknown"),
935 (control & 0x3F00) >> 8,
936 (control & 0x0080) >> 7,
937 (control & 0x007E) >> 1);
938 ti_control_subtree = proto_item_add_subtree(ti_control, ett_btl2cap_control);
939 proto_tree_add_item(ti_control_subtree, hf_btl2cap_control_sar, tvb, offset, 2, TRUE);
940 proto_tree_add_item(ti_control_subtree, hf_btl2cap_control_reqseq, tvb, offset, 2, TRUE);
941 proto_tree_add_item(ti_control_subtree, hf_btl2cap_control_retransmissiondisable, tvb, offset, 2, TRUE);
942 proto_tree_add_item(ti_control_subtree, hf_btl2cap_control_txseq, tvb, offset, 2, TRUE);
943 proto_tree_add_item(ti_control_subtree, hf_btl2cap_control_type, tvb, offset, 2, TRUE);
946 /*Segmented frames with SAR = start have an extra SDU length header field*/
947 if(segment == 0x01) {
949 sdulen = tvb_get_letohs(tvb, offset);
950 pi = proto_tree_add_item(btl2cap_tree, hf_btl2cap_sdulength, tvb, offset, 2, TRUE);
952 length -= 6; /*Control, SDUlength, FCS*/
954 /* Detect malformed data */
955 if (sdulen < length) {
957 expert_add_info_format(pinfo, pi, PI_MALFORMED, PI_WARN,
958 "SDU length less than length of first packet");
961 if(!pinfo->fd->flags.visited){
962 mfp=se_alloc(sizeof(sdu_reassembly_t));
963 mfp->first_frame=pinfo->fd->num;
966 mfp->reassembled=se_alloc(sdulen);
967 tvb_memcpy(tvb, mfp->reassembled, offset, length);
969 se_tree_insert32(config_data->start_fragments, pinfo->fd->num, mfp);
971 mfp=se_tree_lookup32(config_data->start_fragments, pinfo->fd->num);
973 if(mfp != NULL && mfp->last_frame){
975 item=proto_tree_add_uint(btl2cap_tree, hf_btl2cap_reassembled_in, tvb, 0, 0, mfp->last_frame);
976 PROTO_ITEM_SET_GENERATED(item);
977 col_append_fstr(pinfo->cinfo, COL_INFO, "[Reassembled in #%u] ", mfp->last_frame);
980 length -= 4; /*Control, FCS*/
982 if(segment == 0x02 || segment == 0x03) {
983 mfp=se_tree_lookup32_le(config_data->start_fragments, pinfo->fd->num);
984 if(!pinfo->fd->flags.visited){
985 if(mfp != NULL && !mfp->last_frame && (mfp->tot_len>=mfp->cur_off+length)){
986 tvb_memcpy(tvb, mfp->reassembled+mfp->cur_off, offset, length);
987 mfp->cur_off+=length;
989 mfp->last_frame=pinfo->fd->num;
995 item=proto_tree_add_uint(btl2cap_tree, hf_btl2cap_continuation_to, tvb, 0, 0, mfp->first_frame);
996 PROTO_ITEM_SET_GENERATED(item);
997 col_append_fstr(pinfo->cinfo, COL_INFO, "[Continuation to #%u] ", mfp->first_frame);
1000 if(segment == 0x02 && mfp != NULL && mfp->last_frame==pinfo->fd->num){
1001 next_tvb = tvb_new_child_real_data(tvb, (guint8*)mfp->reassembled, mfp->tot_len, mfp->tot_len);
1002 add_new_data_source(pinfo, next_tvb, "Reassembled L2CAP");
1004 /*pass up to higher layer if we have a complete packet*/
1005 if(segment == 0x00) {
1006 next_tvb = tvb_new_subset(tvb, offset, tvb_length_remaining(tvb, offset) - 2, length);
1010 guint32 *service =se_tree_lookup32(psm_to_service_table, ((psm_data?psm_data->local_service:0)<<31) | psm);
1011 proto_item *psm_item;
1013 if( psm < BTL2CAP_DYNAMIC_PSM_START ) {
1014 psm_item=proto_tree_add_uint(btl2cap_tree, hf_btl2cap_psm, tvb, offset, 0, psm);
1017 psm_item=proto_tree_add_uint(btl2cap_tree, hf_btl2cap_psm_dynamic, tvb, offset, 0, psm);
1019 proto_item_append_text(psm_item," (%s)", val_to_str(*service, vs_service_classes, "Unknown service"));
1021 PROTO_ITEM_SET_GENERATED(psm_item);
1023 /* call next dissector */
1024 if (!dissector_try_uint(l2cap_psm_dissector_table, (guint32) psm, next_tvb, pinfo, tree)) {
1025 /* not a known fixed PSM, try to find a registered service to a dynamic PSM */
1026 if(service != NULL && !dissector_try_uint(l2cap_service_dissector_table, *service, next_tvb, pinfo, tree)) {
1027 /* unknown protocol. declare as data */
1028 proto_tree_add_item(btl2cap_tree, hf_btl2cap_payload, next_tvb, 0, tvb_length(next_tvb), TRUE);
1033 proto_tree_add_item(btl2cap_tree, hf_btl2cap_payload, next_tvb, 0, tvb_length(next_tvb), TRUE);
1036 offset+=(tvb_length_remaining(tvb, offset) - 2);
1037 proto_tree_add_item(btl2cap_tree, hf_btl2cap_fcs, tvb, offset, 2, TRUE);
1042 dissect_s_frame(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, proto_tree *btl2cap_tree, guint16 psm _U_, guint16 length _U_, int offset, config_data_t *config_data _U_)
1044 proto_item* ti_control;
1045 proto_tree* ti_control_subtree;
1048 control = tvb_get_letohs(tvb, offset);
1049 switch((control & 0x000C) >> 2)
1052 col_append_str(pinfo->cinfo, COL_INFO, "[S] Receiver Ready");
1055 col_append_str(pinfo->cinfo, COL_INFO, "[S] Reject");
1058 col_append_str(pinfo->cinfo, COL_INFO, "[S] Unknown supervisory frame");
1061 ti_control = proto_tree_add_none_format(btl2cap_tree, hf_btl2cap_control, tvb,
1062 offset, 2, "Control: %s reqseq:%d r:%d",
1063 val_to_str((control & 0x000C) >> 2, control_supervisory_vals, "unknown"),
1064 (control & 0x3F00) >> 8,
1065 (control & 0x0080) >> 7);
1066 ti_control_subtree = proto_item_add_subtree(ti_control, ett_btl2cap_control);
1067 proto_tree_add_item(ti_control_subtree, hf_btl2cap_control_reqseq, tvb, offset, 2, TRUE);
1068 proto_tree_add_item(ti_control_subtree, hf_btl2cap_control_retransmissiondisable, tvb, offset, 2, TRUE);
1069 proto_tree_add_item(ti_control_subtree, hf_btl2cap_control_supervisory, tvb, offset, 2, TRUE);
1070 proto_tree_add_item(ti_control_subtree, hf_btl2cap_control_type, tvb, offset, 2, TRUE);
1072 proto_tree_add_item(ti_control_subtree, hf_btl2cap_fcs, tvb, offset, 2, TRUE);
1076 /* Code to actually dissect the packets
1077 * This dissector will only be called ontop of BTHCI ACL
1078 * and this dissector _REQUIRES_ that
1079 * pinfo->private_data points to a valid bthci_acl_data_t structure
1082 dissect_btl2cap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1085 proto_item *ti=NULL;
1086 proto_tree *btl2cap_tree=NULL;
1087 guint16 length, cid;
1090 tvbuff_t *next_tvb = NULL;
1091 psm_data_t *psm_data;
1092 bthci_acl_data_t *acl_data;
1093 btl2cap_data_t *l2cap_data;
1094 config_data_t *config_data;
1097 col_set_str(pinfo->cinfo, COL_PROTOCOL, "L2CAP");
1098 switch (pinfo->p2p_dir) {
1101 col_add_str(pinfo->cinfo, COL_INFO, "Sent ");
1105 col_add_str(pinfo->cinfo, COL_INFO, "Rcvd ");
1108 case P2P_DIR_UNKNOWN:
1109 col_clear(pinfo->cinfo, COL_INFO);
1113 col_add_fstr(pinfo->cinfo, COL_INFO, "Unknown direction %d ",
1119 ti=proto_tree_add_item(tree, proto_btl2cap, tvb, offset, -1, FALSE);
1120 btl2cap_tree=proto_item_add_subtree(ti, ett_btl2cap);
1123 length = tvb_get_letohs(tvb, offset);
1124 proto_tree_add_item(btl2cap_tree, hf_btl2cap_length, tvb, offset, 2, TRUE);
1127 cid = tvb_get_letohs(tvb, offset);
1128 proto_tree_add_item(btl2cap_tree, hf_btl2cap_cid, tvb, offset, 2, TRUE);
1131 acl_data=(bthci_acl_data_t *)pinfo->private_data;
1132 l2cap_data=ep_alloc(sizeof(btl2cap_data_t));
1133 l2cap_data->chandle=acl_data->chandle;
1134 l2cap_data->cid=cid;
1135 pd_save = pinfo->private_data;
1136 pinfo->private_data=l2cap_data;
1138 if(cid==BTL2CAP_FIXED_CID_SIGNAL){ /* This is a command packet*/
1139 while(offset<(length+4)) {
1140 proto_tree *btl2cap_cmd_tree=NULL;
1141 proto_item *ti_command=NULL;
1144 const gchar *cmd_str;
1146 ti_command=proto_tree_add_none_format(btl2cap_tree,
1147 hf_btl2cap_command, tvb,
1150 btl2cap_cmd_tree=proto_item_add_subtree(ti_command, ett_btl2cap_cmd);
1152 cmd_code=tvb_get_guint8(tvb, offset);
1153 proto_tree_add_item(btl2cap_cmd_tree, hf_btl2cap_cmd_code, tvb, offset, 1, TRUE);
1156 proto_tree_add_item(btl2cap_cmd_tree, hf_btl2cap_cmd_ident, tvb, offset, 1, TRUE);
1159 cmd_length=tvb_get_letohs(tvb, offset);
1160 proto_tree_add_item(btl2cap_cmd_tree, hf_btl2cap_cmd_length, tvb, offset, 2, TRUE);
1161 proto_item_set_len(ti_command, cmd_length+4);
1164 cmd_str = val_to_str(cmd_code, command_code_vals, "Unknown cmd");
1165 proto_item_append_text(ti_command,"%s", cmd_str);
1166 col_append_fstr(pinfo->cinfo, COL_INFO, "%s", cmd_str);
1169 case 0x01: /* Command Reject */
1170 offset=dissect_comrej(tvb, offset, pinfo, btl2cap_cmd_tree);
1173 case 0x02: /* Connection Request */
1174 offset=dissect_connrequest(tvb, offset, pinfo, btl2cap_cmd_tree, FALSE);
1177 case 0x03: /* Connection Response */
1178 offset=dissect_connresponse(tvb, offset, pinfo, btl2cap_cmd_tree);
1181 case 0x04: /* Configure Request */
1182 offset=dissect_configrequest(tvb, offset, pinfo, btl2cap_cmd_tree, cmd_length);
1185 case 0x05: /* Configure Response */
1186 offset=dissect_configresponse(tvb, offset, pinfo, btl2cap_cmd_tree, cmd_length);
1189 case 0x06: /* Disconnect Request */
1190 offset=dissect_disconnrequestresponse(tvb, offset, pinfo, btl2cap_cmd_tree);
1193 case 0x07: /* Disconnect Response */
1194 offset=dissect_disconnrequestresponse(tvb, offset, pinfo, btl2cap_cmd_tree);
1197 case 0x08: /* Echo Request */
1198 offset+=tvb_length_remaining(tvb, offset);
1201 case 0x09: /* Echo Response */
1202 offset+=tvb_length_remaining(tvb, offset);
1205 case 0x0a: /* Information Request */
1206 offset=dissect_inforequest(tvb, offset, pinfo, btl2cap_cmd_tree);
1209 case 0x0b: /* Information Response */
1210 offset=dissect_inforesponse(tvb, offset, pinfo, btl2cap_cmd_tree);
1213 case 0x0c: /* Create Channel Request */
1214 offset=dissect_connrequest(tvb, offset, pinfo, btl2cap_cmd_tree, TRUE);
1217 case 0x0d: /* Create Channel Response */
1218 offset=dissect_chanresponse(tvb, offset, pinfo, btl2cap_cmd_tree);
1221 case 0x0e: /* Move Channel Request */
1222 offset=dissect_movechanrequest(tvb, offset, pinfo, btl2cap_cmd_tree);
1225 case 0x0f: /* Move Channel Response */
1226 offset=dissect_movechanresponse(tvb, offset, pinfo, btl2cap_cmd_tree);
1229 case 0x10: /* Move Channel Confirmation */
1230 offset=dissect_movechanconfirmation(tvb, offset, pinfo, btl2cap_cmd_tree);
1233 case 0x11: /* Move Channel Confirmation Response */
1234 offset=dissect_movechanconfirmationresponse(tvb, offset, pinfo, btl2cap_cmd_tree);
1238 proto_tree_add_item(btl2cap_cmd_tree, hf_btl2cap_cmd_data, tvb, offset, -1, TRUE);
1239 offset+=tvb_length_remaining(tvb, offset);
1244 else if (cid == BTL2CAP_FIXED_CID_CONNLESS) { /* Connectionless reception channel */
1245 col_append_str(pinfo->cinfo, COL_INFO, "Connectionless reception channel");
1247 psm = tvb_get_letohs(tvb, offset);
1248 proto_tree_add_item(btl2cap_tree, hf_btl2cap_psm, tvb, offset, 2, TRUE);
1251 next_tvb = tvb_new_subset(tvb, offset, tvb_length_remaining(tvb, offset), length);
1253 /* call next dissector */
1254 if(!dissector_try_uint(l2cap_psm_dissector_table, (guint32) psm, next_tvb, pinfo, tree)) {
1255 /* not a known fixed PSM, try to find a registered service to a dynamic PSM */
1257 service=se_tree_lookup32(psm_to_service_table, ((pinfo->p2p_dir==P2P_DIR_RECV)?0x80000000:0) | psm);
1259 if(!service || !dissector_try_uint(l2cap_service_dissector_table, *service, next_tvb, pinfo, tree)) {
1260 /* unknown protocol. declare as data */
1261 proto_tree_add_item(btl2cap_tree, hf_btl2cap_payload, tvb, offset, length, TRUE);
1264 offset+=tvb_length_remaining(tvb, offset);
1266 else if(cid < BTL2CAP_FIXED_CID_MAX) {
1267 if (cid == BTL2CAP_FIXED_CID_AMP_MAN) {
1268 control = tvb_get_letohs(tvb, offset);
1270 dissect_s_frame(tvb, pinfo, tree, btl2cap_tree, 0 /* unused */, length, offset, NULL /* unused */);
1272 proto_item* ti_control;
1273 proto_tree* ti_control_subtree;
1275 ti_control = proto_tree_add_none_format(btl2cap_tree, hf_btl2cap_control, tvb,
1276 offset, 2, "Control: %s reqseq:%d r:%d txseq:%d",
1277 val_to_str((control & 0xC000) >> 14, control_sar_vals, "unknown"),
1278 (control & 0x3F00) >> 8,
1279 (control & 0x0080) >> 7,
1280 (control & 0x007E) >> 1);
1281 ti_control_subtree = proto_item_add_subtree(ti_control, ett_btl2cap_control);
1282 proto_tree_add_item(ti_control_subtree, hf_btl2cap_control_sar, tvb, offset, 2, TRUE);
1283 proto_tree_add_item(ti_control_subtree, hf_btl2cap_control_reqseq, tvb, offset, 2, TRUE);
1284 proto_tree_add_item(ti_control_subtree, hf_btl2cap_control_retransmissiondisable, tvb, offset, 2, TRUE);
1285 proto_tree_add_item(ti_control_subtree, hf_btl2cap_control_txseq, tvb, offset, 2, TRUE);
1286 proto_tree_add_item(ti_control_subtree, hf_btl2cap_control_type, tvb, offset, 2, TRUE);
1288 proto_tree_add_item(btl2cap_tree, hf_btl2cap_fcs, tvb, tvb_length(tvb)-2, 2, TRUE);
1290 next_tvb = tvb_new_subset(tvb, offset, tvb_length_remaining(tvb, offset)-2, length);
1294 next_tvb = tvb_new_subset(tvb, offset, tvb_length_remaining(tvb, offset), length);
1296 /* call next dissector */
1297 if(next_tvb && !dissector_try_uint(l2cap_cid_dissector_table, (guint32) cid,
1298 next_tvb, pinfo, tree)){
1299 /* unknown protocol. declare as data */
1300 proto_tree_add_item(btl2cap_tree, hf_btl2cap_payload, tvb, offset, length, TRUE);
1303 else /* if(cid >= BTL2CAP_FIXED_CID_MAX) */ { /* Connection oriented channel */
1304 if((psm_data=se_tree_lookup32(cid_to_psm_table, cid|((pinfo->p2p_dir==P2P_DIR_RECV)?0x0000:0x8000)))){
1306 if(pinfo->p2p_dir==P2P_DIR_RECV)
1307 config_data = &(psm_data->in);
1309 config_data = &(psm_data->out);
1310 if(config_data->mode == 0) {
1311 dissect_b_frame(tvb, pinfo, tree, btl2cap_tree, psm, psm_data->local_service, length, offset);
1313 control = tvb_get_letohs(tvb, offset);
1315 dissect_s_frame(tvb, pinfo, tree, btl2cap_tree, psm, length, offset, config_data);
1317 dissect_i_frame(tvb, pinfo, tree, btl2cap_tree, psm_data, length, offset, config_data);
1322 dissect_b_frame(tvb, pinfo, tree, btl2cap_tree, psm, FALSE, length, offset);
1325 pinfo->private_data = pd_save;
1330 btl2cap_sdp_tap_packet(void *arg _U_, packet_info *pinfo _U_, epan_dissect_t *edt _U_, const void *arg2)
1332 btsdp_data_t *sdp_data = (btsdp_data_t *) arg2;
1334 if( sdp_data->protocol == BTSDP_L2CAP_PROTOCOL_UUID ) {
1335 guint32 token, *psm_service;
1337 token = sdp_data->channel | ((sdp_data->flags & BTSDP_LOCAL_SERVICE_FLAG_MASK)<<31);
1339 psm_service=se_tree_lookup32(psm_to_service_table, token);
1341 psm_service=se_alloc0(sizeof(guint32));
1342 se_tree_insert32(psm_to_service_table, token, psm_service);
1344 *psm_service = sdp_data->service;
1350 /* Register the protocol with Wireshark */
1352 proto_register_btl2cap(void)
1355 /* Setup list of header fields See Section 1.6.1 for details*/
1356 static hf_register_info hf[] = {
1357 { &hf_btl2cap_length,
1358 { "Length", "btl2cap.length",
1359 FT_UINT16, BASE_DEC, NULL, 0x0,
1360 "L2CAP Payload Length", HFILL }
1363 { "CID", "btl2cap.cid",
1364 FT_UINT16, BASE_HEX, NULL, 0x0,
1365 "L2CAP Channel Identifier", HFILL }
1367 { &hf_btl2cap_payload,
1368 { "Payload", "btl2cap.payload",
1369 FT_BYTES, BASE_NONE, NULL, 0x0,
1370 "L2CAP Payload", HFILL }
1372 { &hf_btl2cap_command,
1373 { "Command", "btl2cap.command",
1374 FT_NONE, BASE_NONE, NULL, 0x0,
1375 "L2CAP Command", HFILL }
1377 { &hf_btl2cap_cmd_code,
1378 { "Command Code", "btl2cap.cmd_code",
1379 FT_UINT8, BASE_HEX, VALS(command_code_vals), 0x0,
1380 "L2CAP Command Code", HFILL }
1382 { &hf_btl2cap_cmd_ident,
1383 { "Command Identifier", "btl2cap.cmd_ident",
1384 FT_UINT8, BASE_HEX, NULL, 0x0,
1385 "L2CAP Command Identifier", HFILL }
1387 { &hf_btl2cap_cmd_length,
1388 { "Command Length", "btl2cap.cmd_length",
1389 FT_UINT8, BASE_DEC, NULL, 0x0,
1390 "L2CAP Command Length", HFILL }
1392 { &hf_btl2cap_cmd_data,
1393 { "Command Data", "btl2cap.cmd_data",
1394 FT_NONE, BASE_NONE, NULL, 0x0,
1395 "L2CAP Command Data", HFILL }
1398 { "PSM", "btl2cap.psm",
1399 FT_UINT16, BASE_HEX, VALS(psm_vals), 0x0,
1400 "Protocol/Service Multiplexer", HFILL }
1402 { &hf_btl2cap_psm_dynamic,
1403 { "Dynamic PSM", "btl2cap.psm",
1404 FT_UINT16, BASE_HEX, NULL, 0x0,
1405 "Dynamic Protocol/Service Multiplexer", HFILL }
1408 { "Source CID", "btl2cap.scid",
1409 FT_UINT16, BASE_HEX, NULL, 0x0,
1410 "Source Channel Identifier", HFILL }
1413 { "Destination CID", "btl2cap.dcid",
1414 FT_UINT16, BASE_HEX, NULL, 0x0,
1415 "Destination Channel Identifier", HFILL }
1418 { "Initiator CID", "btl2cap.icid",
1419 FT_UINT16, BASE_HEX, NULL, 0x0,
1420 "Initiator Channel Identifier", HFILL }
1422 { &hf_btl2cap_controller,
1423 { "Controller ID", "btl2cap.ctrl_id",
1424 FT_UINT8, BASE_DEC, VALS(ctrl_id_code_vals), 0x0,
1427 { &hf_btl2cap_dcontroller,
1428 { "Controller ID", "btl2cap.dctrl_id",
1429 FT_UINT8, BASE_DEC, VALS(ctrl_id_code_vals), 0x0,
1430 "Destination Controller ID", HFILL }
1432 { &hf_btl2cap_result,
1433 { "Result", "btl2cap.result",
1434 FT_UINT16, BASE_HEX, VALS(result_vals), 0x0,
1437 { &hf_btl2cap_move_result,
1438 { "Move Result", "btl2cap.move_result",
1439 FT_UINT16, BASE_HEX, VALS(move_result_vals), 0x0,
1442 { &hf_btl2cap_move_confirmation_result,
1443 { "Move Result", "btl2cap.move_result",
1444 FT_UINT16, BASE_HEX, VALS(move_result_confirmation_vals), 0x0,
1447 { &hf_btl2cap_status,
1448 { "Status", "btl2cap.status",
1449 FT_UINT16, BASE_HEX, VALS(status_vals), 0x0,
1452 { &hf_btl2cap_rej_reason,
1453 { "Reason", "btl2cap.rej_reason",
1454 FT_UINT16, BASE_HEX, VALS(reason_vals), 0x0,
1457 { &hf_btl2cap_sig_mtu,
1458 { "Maximum Signalling MTU", "btl2cap.sig_mtu",
1459 FT_UINT16, BASE_DEC, NULL, 0x0,
1462 { &hf_btl2cap_info_mtu,
1463 { "Remote Entity MTU", "btl2cap.info_mtu",
1464 FT_UINT16, BASE_DEC, NULL, 0x0,
1465 "Remote entity acceptable connectionless MTU", HFILL }
1467 { &hf_btl2cap_info_flowcontrol,
1468 { "Flow Control Mode", "btl2cap.info_flowcontrol",
1469 FT_UINT8, BASE_DEC, NULL, 0x01,
1470 "Flow Control mode support", HFILL }
1472 { &hf_btl2cap_info_retransmission,
1473 { "Retransmission Mode", "btl2cap.info_retransmission",
1474 FT_UINT8, BASE_DEC, NULL, 0x02,
1475 "Retransmission mode support", HFILL }
1477 { &hf_btl2cap_info_bidirqos,
1478 { "Bi-Directional QOS", "btl2cap.info_bidirqos",
1479 FT_UINT8, BASE_DEC, NULL, 0x04,
1480 "Bi-Directional QOS support", HFILL }
1482 { &hf_btl2cap_info_enh_retransmission,
1483 { "Enhancded Retransmission Mode", "btl2cap.info_enh_retransmission",
1484 FT_UINT8, BASE_DEC, NULL, 0x08,
1485 "Enhancded Retransmission mode support", HFILL }
1487 { &hf_btl2cap_info_streaming,
1488 { "Streaming Mode", "btl2cap.info_streaming",
1489 FT_UINT8, BASE_DEC, NULL, 0x10,
1490 "Streaming mode support", HFILL }
1492 { &hf_btl2cap_info_fcs,
1493 { "FCS", "btl2cap.info_fcs",
1494 FT_UINT8, BASE_DEC, NULL, 0x20,
1495 "FCS support", HFILL }
1497 { &hf_btl2cap_info_flow_spec,
1498 { "Extended Flow Specification for BR/EDR", "btl2cap.info_flow_spec",
1499 FT_UINT8, BASE_DEC, NULL, 0x40,
1500 "Extended Flow Specification for BR/EDR support", HFILL }
1502 { &hf_btl2cap_info_fixedchan,
1503 { "Fixed Channels", "btl2cap.info_fixedchan",
1504 FT_UINT8, BASE_DEC, NULL, 0x80,
1505 "Fixed Channels support", HFILL }
1507 { &hf_btl2cap_info_window,
1508 { "Extended Window Size", "btl2cap.info_window",
1509 FT_UINT8, BASE_DEC, NULL, 0x01,
1510 "Extended Window Size support", HFILL }
1512 { &hf_btl2cap_info_unicast,
1513 { "Unicast Connectionless Data Reception", "btl2cap.info_unicast",
1514 FT_UINT8, BASE_DEC, NULL, 0x02,
1515 "Unicast Connectionless Data Reception support", HFILL }
1517 { &hf_btl2cap_info_fixedchans,
1518 { "Fixed Channels", "btl2cap.info_fixedchans",
1519 FT_NONE, BASE_NONE, NULL, 0x0,
1522 { &hf_btl2cap_info_fixedchans_null,
1523 { "Null identifier", "btl2cap.info_fixedchans_null",
1524 FT_UINT32, BASE_DEC, NULL, 0x1,
1527 { &hf_btl2cap_info_fixedchans_signal,
1528 { "L2CAP signaling channel", "btl2cap.info_fixedchans_signal",
1529 FT_UINT32, BASE_DEC, NULL, 0x2,
1532 { &hf_btl2cap_info_fixedchans_connless,
1533 { "Connectionless reception", "btl2cap.info_fixedchans_connless",
1534 FT_UINT32, BASE_DEC, NULL, 0x4,
1537 { &hf_btl2cap_info_fixedchans_amp_man,
1538 { "AMP Manager protocol", "btl2cap.info_fixedchans_amp_man",
1539 FT_UINT32, BASE_DEC, NULL, 0x8,
1542 { &hf_btl2cap_info_fixedchans_amp_test,
1543 { "AMP Test Manager", "btl2cap.info_fixedchans_amp_test",
1544 FT_UINT32, BASE_DEC, NULL, 0x80000000,
1547 { &hf_btl2cap_info_type,
1548 { "Information Type", "btl2cap.info_type",
1549 FT_UINT16, BASE_HEX, VALS(info_type_vals), 0x0,
1550 "Type of implementation-specific information", HFILL }
1552 { &hf_btl2cap_info_result,
1553 { "Result", "btl2cap.info_result",
1554 FT_UINT16, BASE_HEX, VALS(info_result_vals), 0x0,
1555 "Information about the success of the request", HFILL }
1557 { &hf_btl2cap_info_extfeatures,
1558 { "Extended Features", "btl2cap.info_extfeatures",
1559 FT_NONE, BASE_NONE, NULL, 0x0,
1560 "Extended Features Mask", HFILL }
1562 { &hf_btl2cap_continuation_flag,
1563 { "Continuation Flag", "btl2cap.continuation",
1564 FT_BOOLEAN, 16, NULL, 0x0001,
1567 { &hf_btl2cap_configuration_result,
1568 { "Result", "btl2cap.conf_result",
1569 FT_UINT16, BASE_HEX, VALS(configuration_result_vals), 0x0,
1570 "Configuration Result", HFILL }
1572 { &hf_btl2cap_option_type,
1573 { "Type", "btl2cap.option_type",
1574 FT_UINT8, BASE_HEX, VALS(option_type_vals), 0x0,
1575 "Type of option", HFILL }
1577 { &hf_btl2cap_option_length,
1578 { "Length", "btl2cap.option_length",
1579 FT_UINT8, BASE_DEC, NULL, 0x0,
1580 "Number of octets in option payload", HFILL }
1582 { &hf_btl2cap_option_mtu,
1583 { "MTU", "btl2cap.option_mtu",
1584 FT_UINT16, BASE_DEC, NULL, 0x0,
1585 "Maximum Transmission Unit", HFILL }
1587 { &hf_btl2cap_option_flushTO,
1588 { "Flush Timeout (ms)", "btl2cap.option_flushto",
1589 FT_UINT16, BASE_DEC, NULL, 0x0,
1590 "Flush Timeout in milliseconds", HFILL }
1592 { &hf_btl2cap_option_flush_to_us,
1593 { "Flush Timeout (us)", "btl2cap.option_flushto",
1594 FT_UINT32, BASE_DEC, NULL, 0x0,
1595 "Flush Timeout (microseconds)", HFILL }
1597 { &hf_btl2cap_option_sdu_size,
1598 { "Maximum SDU Size", "btl2cap.option_sdu_size",
1599 FT_UINT16, BASE_DEC, NULL, 0x0,
1602 { &hf_btl2cap_option_sdu_arrival_time,
1603 { "SDU Inter-arrival Time (us)", "btl2cap.option_sdu_arrival_time",
1604 FT_UINT32, BASE_DEC, NULL, 0x0,
1605 "SDU Inter-arrival Time (microseconds)", HFILL }
1607 { &hf_btl2cap_option_identifier,
1608 { "Identifier", "btl2cap.option_ident",
1609 FT_UINT8, BASE_HEX, NULL, 0x0,
1610 "Flow Specification Identifier", HFILL }
1612 { &hf_btl2cap_option_access_latency,
1613 { "Access Latency (us)", "btl2cap.option_access_latency",
1614 FT_UINT32, BASE_DEC, NULL, 0x0,
1615 "Access Latency (microseconds)", HFILL }
1617 { &hf_btl2cap_option_flags,
1618 { "Flags", "btl2cap.option_flags",
1619 FT_UINT8, BASE_HEX, NULL, 0x0,
1620 "Flags - must be set to 0 (Reserved for future use)", HFILL }
1622 { &hf_btl2cap_option_service_type,
1623 { "Service Type", "btl2cap.option_servicetype",
1624 FT_UINT8, BASE_HEX, VALS(option_servicetype_vals), 0x0,
1625 "Level of service required", HFILL }
1627 { &hf_btl2cap_option_tokenrate,
1628 { "Token Rate (bytes/s)", "btl2cap.option_tokenrate",
1629 FT_UINT32, BASE_DEC, NULL, 0x0,
1630 "Rate at which traffic credits are granted (bytes/s)", HFILL }
1632 { &hf_btl2cap_option_tokenbucketsize,
1633 { "Token Bucket Size (bytes)", "btl2cap.option_tokenbsize",
1634 FT_UINT32, BASE_DEC, NULL, 0x0,
1635 "Size of the token bucket (bytes)", HFILL }
1637 { &hf_btl2cap_option_peakbandwidth,
1638 { "Peak Bandwidth (bytes/s)", "btl2cap.option_peakbandwidth",
1639 FT_UINT32, BASE_DEC, NULL, 0x0,
1640 "Limit how fast packets may be sent (bytes/s)", HFILL }
1642 { &hf_btl2cap_option_latency,
1643 { "Latency (microseconds)", "btl2cap.option_latency",
1644 FT_UINT32, BASE_DEC, NULL, 0x0,
1645 "Maximal acceptable delay (microseconds)", HFILL }
1647 { &hf_btl2cap_option_delayvariation,
1648 { "Delay Variation (microseconds)", "btl2cap.option_delayvar",
1649 FT_UINT32, BASE_DEC, NULL, 0x0,
1650 "Difference between maximum and minimum delay (microseconds)", HFILL }
1652 { &hf_btl2cap_option_retransmissionmode,
1653 { "Mode", "btl2cap.retransmissionmode",
1654 FT_UINT8, BASE_HEX, VALS(option_retransmissionmode_vals), 0x0,
1655 "Retransmission/Flow Control mode", HFILL }
1657 { &hf_btl2cap_option_txwindow,
1658 { "TxWindow", "btl2cap.txwindow",
1659 FT_UINT8, BASE_DEC, NULL, 0x0,
1660 "Retransmission window size", HFILL }
1662 { &hf_btl2cap_option_maxtransmit,
1663 { "MaxTransmit", "btl2cap.maxtransmit",
1664 FT_UINT8, BASE_DEC, NULL, 0x0,
1665 "Maximum I-frame retransmissions", HFILL }
1667 { &hf_btl2cap_option_retransmittimeout,
1668 { "Retransmit timeout (ms)", "btl2cap.retransmittimeout",
1669 FT_UINT16, BASE_DEC, NULL, 0x0,
1670 "Retransmission timeout (milliseconds)", HFILL }
1672 { &hf_btl2cap_option_monitortimeout,
1673 { "Monitor Timeout (ms)", "btl2cap.monitortimeout",
1674 FT_UINT16, BASE_DEC, NULL, 0x0,
1675 "S-frame transmission interval (milliseconds)", HFILL }
1677 { &hf_btl2cap_option_mps,
1678 { "MPS", "btl2cap.mps",
1679 FT_UINT16, BASE_DEC, NULL, 0x0,
1680 "Maximum PDU Payload Size", HFILL }
1682 { &hf_btl2cap_option_fcs,
1683 { "FCS", "btl2cap.option_fcs",
1684 FT_UINT16, BASE_HEX, VALS(option_fcs_vals), 0x0,
1685 "Frame Check Sequence", HFILL }
1687 { &hf_btl2cap_option_window,
1688 { "Extended Window Size", "btl2cap.option_window",
1689 FT_UINT16, BASE_DEC, NULL, 0x0,
1692 { &hf_btl2cap_option,
1693 { "Configuration Parameter Option", "btl2cap.conf_param_option",
1694 FT_NONE, BASE_NONE, NULL, 0x0,
1697 { &hf_btl2cap_control_sar,
1698 { "Segmentation and reassembly", "btl2cap.control_sar",
1699 FT_UINT16, BASE_HEX, VALS(control_sar_vals), 0xC000,
1702 { &hf_btl2cap_control_reqseq,
1703 { "ReqSeq", "btl2cap.control_reqseq",
1704 FT_UINT16, BASE_DEC, NULL, 0x3F00,
1705 "Request Sequence Number", HFILL }
1707 { &hf_btl2cap_control_txseq,
1708 { "TxSeq", "btl2cap.control_txseq",
1709 FT_UINT16, BASE_DEC, NULL, 0x007E,
1710 "Transmitted Sequence Number", HFILL }
1712 { &hf_btl2cap_control_retransmissiondisable,
1713 { "R", "btl2cap.control_retransmissiondisable",
1714 FT_UINT16, BASE_HEX, NULL, 0x0080,
1715 "Retransmission Disable", HFILL }
1717 { &hf_btl2cap_control_supervisory,
1718 { "S", "btl2cap.control_supervisory",
1719 FT_UINT16, BASE_HEX, VALS(control_supervisory_vals), 0x000C,
1720 "Supervisory Function", HFILL }
1722 { &hf_btl2cap_control_type,
1723 { "Frame Type", "btl2cap.control_type",
1724 FT_UINT16, BASE_HEX, VALS(control_type_vals), 0x0001,
1727 { &hf_btl2cap_control,
1728 { "Control field", "btl2cap.control",
1729 FT_NONE, BASE_NONE, NULL, 0x0,
1733 { "FCS", "btl2cap.fcs",
1734 FT_UINT16, BASE_HEX, NULL, 0,
1735 "Frame Check Sequence", HFILL }
1737 { &hf_btl2cap_sdulength,
1738 { "SDU Length", "btl2cap.sdulength",
1739 FT_UINT16, BASE_DEC, NULL, 0,
1742 { &hf_btl2cap_reassembled_in,
1743 { "This SDU is reassembled in frame", "btl2cap.reassembled_in",
1744 FT_FRAMENUM, BASE_NONE, NULL, 0,
1745 "This SDU is reassembled in frame #", HFILL }
1747 { &hf_btl2cap_continuation_to,
1748 { "This is a continuation to the SDU in frame", "btl2cap.continuation_to",
1749 FT_FRAMENUM, BASE_NONE, NULL, 0,
1750 "This is a continuation to the SDU in frame #", HFILL }
1754 /* Setup protocol subtree array */
1755 static gint *ett[] = {
1758 &ett_btl2cap_option,
1759 &ett_btl2cap_extfeatures,
1760 &ett_btl2cap_fixedchans,
1761 &ett_btl2cap_control
1764 /* Register the protocol name and description */
1765 proto_btl2cap = proto_register_protocol("Bluetooth L2CAP Protocol", "L2CAP", "btl2cap");
1767 register_dissector("btl2cap", dissect_btl2cap, proto_btl2cap);
1769 /* subdissector code */
1770 l2cap_psm_dissector_table = register_dissector_table("btl2cap.psm", "L2CAP PSM", FT_UINT16, BASE_HEX);
1771 l2cap_service_dissector_table = register_dissector_table("btl2cap.service", "L2CAP Service", FT_UINT16, BASE_HEX);
1772 l2cap_cid_dissector_table = register_dissector_table("btl2cap.cid", "L2CAP CID", FT_UINT16, BASE_HEX);
1774 /* Required function calls to register the header fields and subtrees used */
1775 proto_register_field_array(proto_btl2cap, hf, array_length(hf));
1776 proto_register_subtree_array(ett, array_length(ett));
1778 cid_to_psm_table=se_tree_create(EMEM_TREE_TYPE_RED_BLACK, "btl2cap scid to psm");
1779 psm_to_service_table=se_tree_create(EMEM_TREE_TYPE_RED_BLACK, "btl2cap psm to service uuid");
1784 proto_reg_handoff_btl2cap(void)
1786 /* tap into the btsdp dissector to look for l2cap PSM infomation that
1787 helps us determine the type of l2cap payload, i.e. which service is
1788 using the PSM channel so we know which sub-dissector to call */
1789 register_tap_listener("btsdp", NULL, NULL, 0, NULL, btl2cap_sdp_tap_packet, NULL);