Wireshark-dev: [Wireshark-dev] [RFC] btl2cap: dissect extended control field
From: Emeltchenko Andrei <Andrei.Emeltchenko.news@xxxxxxxxx>
Date: Wed, 7 Sep 2011 10:20:53 +0300
From: Andrei Emeltchenko <andrei.emeltchenko@xxxxxxxxx>
Adds support for parsing extended control field. Extended control
field may be used for ERTM and streaming mode (if EWS specified).
Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@xxxxxxxxx>
---
epan/dissectors/packet-btl2cap.c | 173 +++++++++++++++++++++++++++++---------
1 files changed, 132 insertions(+), 41 deletions(-)
diff --git a/epan/dissectors/packet-btl2cap.c b/epan/dissectors/packet-btl2cap.c
index ac0a909..813e47d 100644
--- a/epan/dissectors/packet-btl2cap.c
+++ b/epan/dissectors/packet-btl2cap.c
@@ -114,11 +114,16 @@ static int hf_btl2cap_option_sdu_arrival_time = -1;
static int hf_btl2cap_option_access_latency = -1;
static int hf_btl2cap_control = -1;
static int hf_btl2cap_control_sar = -1;
+static int hf_btl2cap_control_sar_ext = -1;
static int hf_btl2cap_control_reqseq = -1;
+static int hf_btl2cap_control_reqseq_ext = -1;
static int hf_btl2cap_control_txseq = -1;
+static int hf_btl2cap_control_txseq_ext = -1;
static int hf_btl2cap_control_retransmissiondisable = -1;
static int hf_btl2cap_control_supervisory = -1;
+static int hf_btl2cap_control_supervisory_ext = -1;
static int hf_btl2cap_control_type = -1;
+static int hf_btl2cap_control_type_ext = -1;
static int hf_btl2cap_fcs = -1;
static int hf_btl2cap_sdulength = -1;
static int hf_btl2cap_continuation_to = -1;
@@ -152,7 +157,8 @@ typedef struct _config_data_t {
} config_data_t;
typedef struct _psm_data_t {
guint16 psm;
- gboolean local_service;
+ gboolean local_service;
+ gboolean ext_ctrl;
config_data_t in;
config_data_t out;
} psm_data_t;
@@ -432,7 +438,7 @@ dissect_movechanrequest(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto
}
static int
-dissect_options(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree, int length, config_data_t *config_data)
+dissect_options(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree, int length, config_data_t *config_data, psm_data_t *psm_data)
{
proto_item *ti_option=NULL;
proto_tree *ti_option_subtree=NULL;
@@ -549,6 +555,9 @@ dissect_options(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *t
break;
case 0x07: /* Extended Window Size */
+ if (psm_data)
+ psm_data->ext_ctrl = 1;
+
proto_tree_add_item(ti_option_subtree, hf_btl2cap_option_window, tvb, offset, 2, TRUE);
offset+=2;
@@ -593,7 +602,7 @@ dissect_configrequest(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_t
config_data = &(psm_data->in);
else
config_data = NULL;
- offset=dissect_options(tvb, offset, pinfo, tree, length - 4, config_data);
+ offset=dissect_options(tvb, offset, pinfo, tree, length - 4, config_data, psm_data);
}
return offset;
@@ -737,7 +746,7 @@ dissect_configresponse(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_
config_data = &(psm_data->in);
else
config_data = NULL;
- offset=dissect_options(tvb, offset, pinfo, tree, length - 6, config_data);
+ offset=dissect_options(tvb, offset, pinfo, tree, length - 6, config_data, psm_data);
}
return offset;
@@ -905,15 +914,21 @@ static void
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)
{
tvbuff_t *next_tvb = NULL;
- guint16 control, segment;
+ guint32 control, segment;
guint16 sdulen;
proto_item* ti_control;
proto_tree* ti_control_subtree;
sdu_reassembly_t* mfp = NULL;
guint16 psm = (psm_data?psm_data->psm:0);
- control = tvb_get_letohs(tvb, offset);
- segment = (control & 0xC000) >> 14;
+ if (psm_data->ext_ctrl) {
+ control = tvb_get_letohl(tvb, offset);
+ segment = (control & 0x00030000) >> 16;
+ } else {
+ control = tvb_get_letohs(tvb, offset);
+ segment = (control & 0xC000) >> 14;
+ }
+
switch(segment)
{
case 0:
@@ -929,19 +944,36 @@ dissect_i_frame(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, proto_tree
col_append_str(pinfo->cinfo, COL_INFO, "[I] Continuation SDU");
break;
}
- ti_control = proto_tree_add_none_format(btl2cap_tree, hf_btl2cap_control, tvb,
- offset, 2, "Control: %s reqseq:%d r:%d txseq:%d",
- val_to_str((control & 0xC000) >> 14, control_sar_vals, "unknown"),
- (control & 0x3F00) >> 8,
- (control & 0x0080) >> 7,
- (control & 0x007E) >> 1);
- ti_control_subtree = proto_item_add_subtree(ti_control, ett_btl2cap_control);
- proto_tree_add_item(ti_control_subtree, hf_btl2cap_control_sar, tvb, offset, 2, TRUE);
- proto_tree_add_item(ti_control_subtree, hf_btl2cap_control_reqseq, tvb, offset, 2, TRUE);
- proto_tree_add_item(ti_control_subtree, hf_btl2cap_control_retransmissiondisable, tvb, offset, 2, TRUE);
- proto_tree_add_item(ti_control_subtree, hf_btl2cap_control_txseq, tvb, offset, 2, TRUE);
- proto_tree_add_item(ti_control_subtree, hf_btl2cap_control_type, tvb, offset, 2, TRUE);
- offset += 2;
+
+ if (psm_data->ext_ctrl) {
+ ti_control = proto_tree_add_none_format(btl2cap_tree, hf_btl2cap_control, tvb,
+ offset, 4, "Control: %s reqseq:%d F:%d txseq:%d",
+ val_to_str((control & 0x00030000) >> 16, control_sar_vals, "unknown"),
+ (control & 0x0000FFFC) >> 2,
+ (control & 0x00000002) >> 1,
+ (control & 0xFFFC0000) >> 18);
+
+ ti_control_subtree = proto_item_add_subtree(ti_control, ett_btl2cap_control);
+ proto_tree_add_item(ti_control_subtree, hf_btl2cap_control_sar_ext, tvb, offset, 4, TRUE);
+ proto_tree_add_item(ti_control_subtree, hf_btl2cap_control_reqseq_ext, tvb, offset, 4, TRUE);
+ proto_tree_add_item(ti_control_subtree, hf_btl2cap_control_txseq_ext, tvb, offset, 4, TRUE);
+ proto_tree_add_item(ti_control_subtree, hf_btl2cap_control_type_ext, tvb, offset, 4, TRUE);
+ offset += 4;
+ } else {
+ ti_control = proto_tree_add_none_format(btl2cap_tree, hf_btl2cap_control, tvb,
+ offset, 2, "Control: %s reqseq:%d r:%d txseq:%d",
+ val_to_str((control & 0xC000) >> 14, control_sar_vals, "unknown"),
+ (control & 0x3F00) >> 8,
+ (control & 0x0080) >> 7,
+ (control & 0x007E) >> 1);
+ ti_control_subtree = proto_item_add_subtree(ti_control, ett_btl2cap_control);
+ proto_tree_add_item(ti_control_subtree, hf_btl2cap_control_sar, tvb, offset, 2, TRUE);
+ proto_tree_add_item(ti_control_subtree, hf_btl2cap_control_reqseq, tvb, offset, 2, TRUE);
+ proto_tree_add_item(ti_control_subtree, hf_btl2cap_control_retransmissiondisable, tvb, offset, 2, TRUE);
+ proto_tree_add_item(ti_control_subtree, hf_btl2cap_control_txseq, tvb, offset, 2, TRUE);
+ proto_tree_add_item(ti_control_subtree, hf_btl2cap_control_type, tvb, offset, 2, TRUE);
+ offset += 2;
+ }
/*Segmented frames with SAR = start have an extra SDU length header field*/
if(segment == 0x01) {
@@ -1039,14 +1071,21 @@ dissect_i_frame(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, proto_tree
}
static void
-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_)
+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_, gboolean ext_ctrl)
{
proto_item* ti_control;
proto_tree* ti_control_subtree;
- guint16 control;
+ guint32 control;
+ guint16 supervise;
- control = tvb_get_letohs(tvb, offset);
- switch((control & 0x000C) >> 2)
+ if (ext_ctrl)
+ control = tvb_get_letohl(tvb, offset);
+ else
+ control = tvb_get_letohs(tvb, offset);
+
+ supervise = ext_ctrl ? (control & 0x00030000) >> 16 : (control & 0x000C) >> 2;
+
+ switch(supervise)
{
case 0:
col_append_str(pinfo->cinfo, COL_INFO, "[S] Receiver Ready");
@@ -1054,25 +1093,48 @@ dissect_s_frame(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, proto_t
case 1:
col_append_str(pinfo->cinfo, COL_INFO, "[S] Reject");
break;
+ case 2:
+ col_append_str(pinfo->cinfo, COL_INFO, "[S] Receiver Not Ready");
+ break;
+ case 3:
+ col_append_str(pinfo->cinfo, COL_INFO, "[S] Select Reject");
+ break;
default:
col_append_str(pinfo->cinfo, COL_INFO, "[S] Unknown supervisory frame");
break;
}
- ti_control = proto_tree_add_none_format(btl2cap_tree, hf_btl2cap_control, tvb,
- offset, 2, "Control: %s reqseq:%d r:%d",
- val_to_str((control & 0x000C) >> 2, control_supervisory_vals, "unknown"),
- (control & 0x3F00) >> 8,
- (control & 0x0080) >> 7);
- ti_control_subtree = proto_item_add_subtree(ti_control, ett_btl2cap_control);
- proto_tree_add_item(ti_control_subtree, hf_btl2cap_control_reqseq, tvb, offset, 2, TRUE);
- proto_tree_add_item(ti_control_subtree, hf_btl2cap_control_retransmissiondisable, tvb, offset, 2, TRUE);
- proto_tree_add_item(ti_control_subtree, hf_btl2cap_control_supervisory, tvb, offset, 2, TRUE);
- proto_tree_add_item(ti_control_subtree, hf_btl2cap_control_type, tvb, offset, 2, TRUE);
- offset += 2;
+
+ if (ext_ctrl) {
+ ti_control = proto_tree_add_none_format(btl2cap_tree, hf_btl2cap_control, tvb,
+ offset, 4, "ExtControl: %s reqseq:%d P:%d",
+ val_to_str((control & 0x00030000) >> 16, control_supervisory_vals, "unknown"),
+ (control & 0x0000FFFC) >> 2,
+ (control & 0x00040000) >> 18);
+
+ ti_control_subtree = proto_item_add_subtree(ti_control, ett_btl2cap_control);
+ proto_tree_add_item(ti_control_subtree, hf_btl2cap_control_reqseq_ext, tvb, offset, 4, TRUE);
+ proto_tree_add_item(ti_control_subtree, hf_btl2cap_control_supervisory_ext, tvb, offset, 4, TRUE);
+ proto_tree_add_item(ti_control_subtree, hf_btl2cap_control_type_ext, tvb, offset, 4, TRUE);
+ offset += 4;
+ } else {
+ ti_control = proto_tree_add_none_format(btl2cap_tree, hf_btl2cap_control, tvb,
+ offset, 2, "Control: %s reqseq:%d r:%d",
+ val_to_str((control & 0x000C) >> 2, control_supervisory_vals, "unknown"),
+ (control & 0x3F00) >> 8,
+ (control & 0x0080) >> 7);
+ ti_control_subtree = proto_item_add_subtree(ti_control, ett_btl2cap_control);
+ proto_tree_add_item(ti_control_subtree, hf_btl2cap_control_reqseq, tvb, offset, 2, TRUE);
+ proto_tree_add_item(ti_control_subtree, hf_btl2cap_control_retransmissiondisable, tvb, offset, 2, TRUE);
+ proto_tree_add_item(ti_control_subtree, hf_btl2cap_control_supervisory, tvb, offset, 2, TRUE);
+ proto_tree_add_item(ti_control_subtree, hf_btl2cap_control_type, tvb, offset, 2, TRUE);
+ offset += 2;
+ }
+
proto_tree_add_item(ti_control_subtree, hf_btl2cap_fcs, tvb, offset, 2, TRUE);
offset += 2;
}
+
/* Code to actually dissect the packets
* This dissector will only be called ontop of BTHCI ACL
* and this dissector _REQUIRES_ that
@@ -1267,7 +1329,7 @@ dissect_btl2cap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
if (cid == BTL2CAP_FIXED_CID_AMP_MAN) {
control = tvb_get_letohs(tvb, offset);
if(control & 0x1) {
- dissect_s_frame(tvb, pinfo, tree, btl2cap_tree, 0 /* unused */, length, offset, NULL /* unused */);
+ dissect_s_frame(tvb, pinfo, tree, btl2cap_tree, 0 /* unused */, length, offset, NULL /* unused */, 0);
} else {
proto_item* ti_control;
proto_tree* ti_control_subtree;
@@ -1310,12 +1372,15 @@ dissect_btl2cap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
if(config_data->mode == 0) {
dissect_b_frame(tvb, pinfo, tree, btl2cap_tree, psm, psm_data->local_service, length, offset);
} else {
- control = tvb_get_letohs(tvb, offset);
- if(control & 0x1) {
- dissect_s_frame(tvb, pinfo, tree, btl2cap_tree, psm, length, offset, config_data);
- } else {
+ if (psm_data->ext_ctrl)
+ control = tvb_get_letohl(tvb, offset);
+ else
+ control = tvb_get_letohs(tvb, offset);
+
+ if (control & 0x01)
+ dissect_s_frame(tvb, pinfo, tree, btl2cap_tree, psm, length, offset, config_data, psm_data->ext_ctrl);
+ else
dissect_i_frame(tvb, pinfo, tree, btl2cap_tree, psm_data, length, offset, config_data);
- }
}
} else {
psm=0;
@@ -1699,16 +1764,31 @@ proto_register_btl2cap(void)
FT_UINT16, BASE_HEX, VALS(control_sar_vals), 0xC000,
NULL, HFILL }
},
+ { &hf_btl2cap_control_sar_ext,
+ { "Segmentation and reassembly", "btl2cap.control_sar",
+ FT_UINT32, BASE_HEX, VALS(control_sar_vals), 0x00030000,
+ NULL, HFILL }
+ },
{ &hf_btl2cap_control_reqseq,
{ "ReqSeq", "btl2cap.control_reqseq",
FT_UINT16, BASE_DEC, NULL, 0x3F00,
"Request Sequence Number", HFILL }
},
+ { &hf_btl2cap_control_reqseq_ext,
+ { "ReqSeq", "btl2cap.control_reqseq_ext",
+ FT_UINT32, BASE_DEC, NULL, 0x0000FFFC,
+ "Request Sequence Number", HFILL }
+ },
{ &hf_btl2cap_control_txseq,
{ "TxSeq", "btl2cap.control_txseq",
FT_UINT16, BASE_DEC, NULL, 0x007E,
"Transmitted Sequence Number", HFILL }
},
+ { &hf_btl2cap_control_txseq_ext,
+ { "TxSeq", "btl2cap.control_txseq_ext",
+ FT_UINT32, BASE_DEC, NULL, 0xFFFC0000,
+ "Transmitted Sequence Number", HFILL }
+ },
{ &hf_btl2cap_control_retransmissiondisable,
{ "R", "btl2cap.control_retransmissiondisable",
FT_UINT16, BASE_HEX, NULL, 0x0080,
@@ -1719,11 +1799,22 @@ proto_register_btl2cap(void)
FT_UINT16, BASE_HEX, VALS(control_supervisory_vals), 0x000C,
"Supervisory Function", HFILL }
},
+ { &hf_btl2cap_control_supervisory_ext,
+ { "S", "btl2cap.control_supervisory",
+ FT_UINT32, BASE_HEX, VALS(control_supervisory_vals), 0x00030000,
+ "Supervisory Function", HFILL }
+ },
{ &hf_btl2cap_control_type,
{ "Frame Type", "btl2cap.control_type",
FT_UINT16, BASE_HEX, VALS(control_type_vals), 0x0001,
NULL, HFILL }
},
+ { &hf_btl2cap_control_type_ext,
+ { "Frame Type", "btl2cap.control_type",
+ FT_UINT32, BASE_HEX, VALS(control_type_vals), 0x00000001,
+ NULL, HFILL }
+ },
+
{ &hf_btl2cap_control,
{ "Control field", "btl2cap.control",
FT_NONE, BASE_NONE, NULL, 0x0,
--
1.7.4.1
- Prev by Date: Re: [Wireshark-dev] RFC: Add fallback path to get_datafile_dir
- Next by Date: [Wireshark-dev] Built-in dissector depends on a plugin dissector in 1.6.x
- Previous by thread: Re: [Wireshark-dev] Bug 6017 - New Cisco FabricPath dissector forwireshark
- Next by thread: [Wireshark-dev] Built-in dissector depends on a plugin dissector in 1.6.x
- Index(es):