aboutsummaryrefslogtreecommitdiffstats
path: root/epan/dissectors/packet-btl2cap.c
diff options
context:
space:
mode:
Diffstat (limited to 'epan/dissectors/packet-btl2cap.c')
-rw-r--r--epan/dissectors/packet-btl2cap.c320
1 files changed, 207 insertions, 113 deletions
diff --git a/epan/dissectors/packet-btl2cap.c b/epan/dissectors/packet-btl2cap.c
index ce725997ff..c4a4bf9fed 100644
--- a/epan/dissectors/packet-btl2cap.c
+++ b/epan/dissectors/packet-btl2cap.c
@@ -37,6 +37,8 @@
#include <etypes.h>
#include <epan/emem.h>
#include <epan/expert.h>
+#include <epan/tap.h>
+#include "packet-btsdp.h"
#include "packet-bthci_acl.h"
#include "packet-btl2cap.h"
@@ -51,6 +53,7 @@ static int hf_btl2cap_cmd_ident = -1;
static int hf_btl2cap_cmd_length = -1;
static int hf_btl2cap_cmd_data = -1;
static int hf_btl2cap_psm = -1;
+static int hf_btl2cap_psm_dynamic = -1;
static int hf_btl2cap_scid = -1;
static int hf_btl2cap_dcid = -1;
static int hf_btl2cap_icid = -1;
@@ -133,12 +136,15 @@ static gint ett_btl2cap_control = -1;
/* Initialize dissector table */
static dissector_table_t l2cap_psm_dissector_table;
static dissector_table_t l2cap_cid_dissector_table;
+static dissector_table_t l2cap_service_dissector_table;
/* This table maps cid values to psm values.
* The same table is used both for SCID and DCID.
* For received CIDs we mask the cid with 0x8000 in this table
*/
static emem_tree_t *cid_to_psm_table = NULL;
+static emem_tree_t *psm_to_service_table = NULL;
+
typedef struct _config_data_t {
guint8 mode;
guint8 txwindow;
@@ -146,6 +152,7 @@ typedef struct _config_data_t {
} config_data_t;
typedef struct _psm_data_t {
guint16 psm;
+ gboolean local_service;
config_data_t in;
config_data_t out;
} psm_data_t;
@@ -178,40 +185,41 @@ static const value_string psm_vals[] = {
{ 0x0005, "TCS-BIN" },
{ 0x0007, "TCS-BIN-CORDLESS" },
{ 0x000F, "BNEP" },
- { 0x0011, "HID_CONTROL" },
- { 0x0013, "HID_INTERRUPT" },
+ { 0x0011, "HID-Control" },
+ { 0x0013, "HID-Interrupt" },
{ 0x0015, "UPnP" },
- { 0x0017, "AVCTP" },
+ { 0x0017, "AVCTP-Control" },
{ 0x0019, "AVDTP" },
+ { 0x001B, "AVCTP-Browsing" },
{ 0x001D, "UDI_C-Plane" },
{ 0, NULL }
};
static const value_string result_vals[] = {
- { 0x0000, "Connection successful" },
- { 0x0001, "Connection pending" },
- { 0x0002, "Connection refused - PSM not supported" },
- { 0x0003, "Connection refused - security block" },
- { 0x0004, "Connection refused - no resources available" },
- { 0x0005, "Connection refused - Controller ID not supported" },
+ { 0x0000, "Successful" },
+ { 0x0001, "Pending" },
+ { 0x0002, "Refused - PSM not supported" },
+ { 0x0003, "Refused - security block" },
+ { 0x0004, "Refused - no resources available" },
+ { 0x0005, "Refused - Controller ID not supported" },
{ 0, NULL }
};
static const value_string move_result_vals[] = {
- { 0x0000, "Move success" },
- { 0x0001, "Move pending" },
- { 0x0002, "Move refused - Controller ID not supported" },
- { 0x0003, "Move refused - New Controller ID is same as old" },
- { 0x0004, "Move refused - Configuration not supported" },
- { 0x0005, "Move refused - Move Channel collision" },
- { 0x0006, "Move refused - Channel not allowed to be moved" },
+ { 0x0000, "Success" },
+ { 0x0001, "Pending" },
+ { 0x0002, "Refused - Controller ID not supported" },
+ { 0x0003, "Refused - New Controller ID is same as old" },
+ { 0x0004, "Refused - Configuration not supported" },
+ { 0x0005, "Refused - Move Channel collision" },
+ { 0x0006, "Refused - Channel not allowed to be moved" },
{ 0, NULL }
};
static const value_string move_result_confirmation_vals[] = {
- { 0x0000, "Move success - both sides succeed" },
- { 0x0001, "Move failure - one or both sides refuse" },
+ { 0x0000, "Success - both sides succeed" },
+ { 0x0001, "Failure - one or both sides refuse" },
{ 0, NULL }
};
@@ -307,6 +315,12 @@ static const value_string option_fcs_vals[] = {
{ 0, NULL }
};
+static const value_string ctrl_id_code_vals[] = {
+ { 0x00, "Bluetooth BR/EDR" },
+ { 0x01, "Wifi 802.11" },
+ { 0, NULL }
+};
+
static int
dissect_comrej(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree)
{
@@ -342,55 +356,50 @@ dissect_comrej(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tr
}
static int
-dissect_connrequest(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
+dissect_connrequest(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, gboolean is_ch_request)
{
guint16 scid, psm;
psm_data_t *psm_data;
+ const gchar *psm_str = "<NONE>";
psm=tvb_get_letohs(tvb, offset);
- proto_tree_add_item(tree, hf_btl2cap_psm, tvb, offset, 2, TRUE);
- offset+=2;
-
- scid=tvb_get_letohs(tvb, offset);
- proto_tree_add_item(tree, hf_btl2cap_scid, tvb, offset, 2, TRUE);
- offset+=2;
-
- if (pinfo->fd->flags.visited == 0) {
- psm_data=se_alloc(sizeof(psm_data_t));
- psm_data->psm=psm;
- psm_data->in.mode=0;
- psm_data->in.txwindow=0;
- psm_data->in.start_fragments=se_tree_create_non_persistent(EMEM_TREE_TYPE_RED_BLACK, "bthci_l2cap fragment starts");
- psm_data->out.mode=0;
- psm_data->out.txwindow=0;
- psm_data->out.start_fragments=se_tree_create_non_persistent(EMEM_TREE_TYPE_RED_BLACK, "bthci_l2cap fragment starts");
- se_tree_insert32(cid_to_psm_table, scid|((pinfo->p2p_dir == P2P_DIR_RECV)?0x8000:0x0000), psm_data);
-
+ if( psm < BTL2CAP_DYNAMIC_PSM_START ) {
+ proto_tree_add_item(tree, hf_btl2cap_psm, tvb, offset, 2, TRUE);
+ psm_str = val_to_str(psm, psm_vals, "Unknown PSM");
}
- return offset;
-}
-
+ else {
+ guint32 *service, token;
+ proto_item *item;
-static int
-dissect_chanrequest(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
-{
- guint16 scid, psm;
- psm_data_t *psm_data;
+ item = proto_tree_add_item(tree, hf_btl2cap_psm_dynamic, tvb, offset, 2, TRUE);
+ token = psm | ((pinfo->p2p_dir == P2P_DIR_RECV)?0x80000000:0x00000000);
+ service = se_tree_lookup32(psm_to_service_table, token);
- psm=tvb_get_letohs(tvb, offset);
- proto_tree_add_item(tree, hf_btl2cap_psm, tvb, offset, 2, TRUE);
+ if( service ) {
+ psm_str = val_to_str(*service, vs_service_classes, "Unknown PSM");
+ proto_item_append_text(item," (%s)", psm_str);
+ }
+ }
offset+=2;
scid=tvb_get_letohs(tvb, offset);
proto_tree_add_item(tree, hf_btl2cap_scid, tvb, offset, 2, TRUE);
offset+=2;
- proto_tree_add_item(tree, hf_btl2cap_controller, tvb, offset, 1, TRUE);
- offset+=1;
+ if( psm_str )
+ col_append_fstr(pinfo->cinfo, COL_INFO, " (%s, SCID: 0x%04x)", psm_str, scid);
+ else
+ col_append_fstr(pinfo->cinfo, COL_INFO, " (SCID: 0x%04x)", scid);
+
+ if( is_ch_request ) {
+ proto_tree_add_item(tree, hf_btl2cap_controller, tvb, offset, 1, TRUE);
+ offset+=1;
+ }
if (pinfo->fd->flags.visited == 0) {
psm_data=se_alloc(sizeof(psm_data_t));
psm_data->psm=psm;
+ psm_data->local_service = (pinfo->p2p_dir == P2P_DIR_RECV) ? TRUE : FALSE;
psm_data->in.mode=0;
psm_data->in.txwindow=0;
psm_data->in.start_fragments=se_tree_create_non_persistent(EMEM_TREE_TYPE_RED_BLACK, "bthci_l2cap fragment starts");
@@ -406,12 +415,19 @@ dissect_chanrequest(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *t
static int
dissect_movechanrequest(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree)
{
+ guint16 icid;
+ guint8 ctrl_id;
+
+ icid = tvb_get_letohs(tvb, offset);
proto_tree_add_item(tree, hf_btl2cap_icid, tvb, offset, 2, TRUE);
offset+=2;
+ ctrl_id = tvb_get_guint8(tvb, offset);
proto_tree_add_item(tree, hf_btl2cap_dcontroller, tvb, offset, 1, TRUE);
offset+=1;
+ 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"));
+
return offset;
}
@@ -564,6 +580,8 @@ dissect_configrequest(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_t
proto_tree_add_item(tree, hf_btl2cap_dcid, tvb, offset, 2, TRUE);
offset+=2;
+ col_append_fstr(pinfo->cinfo, COL_INFO, " (DCID: 0x%04x)", dcid);
+
proto_tree_add_item(tree, hf_btl2cap_continuation_flag, tvb, offset, 2, TRUE);
offset+=2;
@@ -585,16 +603,20 @@ dissect_configrequest(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_t
static int
dissect_inforequest(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree)
{
+ guint16 info_type;
+
+ info_type=tvb_get_letohs(tvb, offset);
proto_tree_add_item(tree, hf_btl2cap_info_type, tvb, offset, 2, TRUE);
offset+=2;
+ col_append_fstr(pinfo->cinfo, COL_INFO, " (%s)", val_to_str(info_type, info_type_vals, "Unknown type"));
return offset;
}
static int
dissect_inforesponse(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree)
{
- guint16 info_type;
+ guint16 info_type, result;
proto_item *ti_features=NULL;
proto_tree *ti_features_subtree=NULL;
guint32 features;
@@ -603,9 +625,14 @@ dissect_inforesponse(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tr
proto_tree_add_item(tree, hf_btl2cap_info_type, tvb, offset, 2, TRUE);
offset+=2;
+ result = tvb_get_letohs(tvb, offset);
proto_tree_add_item(tree, hf_btl2cap_info_result, tvb, offset, 2, TRUE);
offset+=2;
+ col_append_fstr(pinfo->cinfo, COL_INFO, " (%s, %s)",
+ val_to_str(info_type, info_type_vals, "Unknown type"),
+ val_to_str(result, info_result_vals, "Unknown result"));
+
if(tvb_length_remaining(tvb, offset)) {
switch(info_type){
case 0x0001: /* Connectionless MTU */
@@ -686,7 +713,7 @@ dissect_configresponse(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_
{
psm_data_t *psm_data;
config_data_t *config_data;
- guint16 scid;
+ guint16 scid, result;
scid = tvb_get_letohs(tvb, offset);
psm_data=se_tree_lookup32(cid_to_psm_table, scid|((pinfo->p2p_dir==P2P_DIR_RECV)?0x0000:0x8000));
@@ -696,9 +723,12 @@ dissect_configresponse(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_
proto_tree_add_item(tree, hf_btl2cap_continuation_flag, tvb, offset, 2, TRUE);
offset+=2;
+ result = tvb_get_letohs(tvb, offset);
proto_tree_add_item(tree, hf_btl2cap_configuration_result, tvb, offset, 2, TRUE);
offset+=2;
+ col_append_fstr(pinfo->cinfo, COL_INFO, " - %s (SCID: 0x%04x)", val_to_str(result, configuration_result_vals, "Unknown"), scid);
+
if(tvb_length_remaining(tvb, offset)){
if (psm_data)
if(pinfo->p2p_dir==P2P_DIR_RECV)
@@ -716,7 +746,7 @@ dissect_configresponse(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_
static int
dissect_connresponse(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
{
- guint16 scid, dcid;
+ guint16 scid, dcid, result;
psm_data_t *psm_data;
dcid = tvb_get_letohs(tvb, offset);
@@ -727,12 +757,20 @@ dissect_connresponse(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *
proto_tree_add_item(tree, hf_btl2cap_scid, tvb, offset, 2, TRUE);
offset+=2;
+ result = tvb_get_letohs(tvb, offset);
proto_tree_add_item(tree, hf_btl2cap_result, tvb, offset, 2, TRUE);
offset+=2;
proto_tree_add_item(tree, hf_btl2cap_status, tvb, offset, 2, TRUE);
offset+=2;
+ if(!result) {
+ col_append_fstr(pinfo->cinfo, COL_INFO, " - Success (SCID: 0x%04x, DCID: 0x%04x)", scid, dcid);
+ }
+ else {
+ col_append_fstr(pinfo->cinfo, COL_INFO, " - %s (SCID: 0x%04x)", val_to_str(result, result_vals, "Unknown"), scid);
+ }
+
if (pinfo->fd->flags.visited == 0) {
if((psm_data=se_tree_lookup32(cid_to_psm_table, scid|((pinfo->p2p_dir==P2P_DIR_RECV)?0x0000:0x8000)))){
se_tree_insert32(cid_to_psm_table, dcid|((pinfo->p2p_dir == P2P_DIR_RECV)?0x8000:0x0000), psm_data);
@@ -751,50 +789,72 @@ dissect_chanresponse(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *
static int
dissect_movechanresponse(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree)
{
+ guint16 icid, result;
+
+ icid = tvb_get_letohs(tvb, offset);
proto_tree_add_item(tree, hf_btl2cap_icid, tvb, offset, 2, TRUE);
offset+=2;
+ result = tvb_get_letohs(tvb, offset);
proto_tree_add_item(tree, hf_btl2cap_move_result, tvb, offset, 2, TRUE);
offset+=2;
+ col_append_fstr(pinfo->cinfo, COL_INFO, " (ICID: 0x%04x, %s)", icid, val_to_str(result, move_result_vals, "Unknown result"));
+
return offset;
}
static int
dissect_movechanconfirmation(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree)
{
+ guint16 icid, result;
+
+ icid = tvb_get_letohs(tvb, offset);
proto_tree_add_item(tree, hf_btl2cap_icid, tvb, offset, 2, TRUE);
offset+=2;
+ result = tvb_get_letohs(tvb, offset);
proto_tree_add_item(tree, hf_btl2cap_move_confirmation_result, tvb, offset, 2, TRUE);
offset+=2;
+ col_append_fstr(pinfo->cinfo, COL_INFO, " (ICID: 0x%04x, %s)", icid, val_to_str(result, move_result_confirmation_vals, "Unknown result"));
+
return offset;
}
static int
dissect_movechanconfirmationresponse(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree)
{
+ guint16 icid;
+
+ icid = tvb_get_letohs(tvb, offset);
proto_tree_add_item(tree, hf_btl2cap_icid, tvb, offset, 2, TRUE);
offset+=2;
+ col_append_fstr(pinfo->cinfo, COL_INFO, " (ICID: 0x%04x)", icid);
return offset;
}
static int
dissect_disconnrequestresponse(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree)
{
+ guint16 scid, dcid;
+
+ dcid = tvb_get_letohs(tvb, offset);
proto_tree_add_item(tree, hf_btl2cap_dcid, tvb, offset, 2, TRUE);
offset+=2;
+ scid = tvb_get_letohs(tvb, offset);
proto_tree_add_item(tree, hf_btl2cap_scid, tvb, offset, 2, TRUE);
offset+=2;
+ col_append_fstr(pinfo->cinfo, COL_INFO, " (SCID: 0x%04x, DCID: 0x%04x)", scid, dcid);
+
return offset;
}
static void
-dissect_b_frame(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, proto_tree *btl2cap_tree, guint16 psm, guint16 length, int offset)
+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)
{
tvbuff_t *next_tvb;
next_tvb = tvb_new_subset(tvb, offset, tvb_length_remaining(tvb, offset), length);
@@ -803,18 +863,29 @@ dissect_b_frame(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, proto_tree
if(psm){
proto_item *psm_item;
+ guint32 *service =se_tree_lookup32(psm_to_service_table, (local_service<<31) | psm);
+ if( psm < BTL2CAP_DYNAMIC_PSM_START ) {
psm_item=proto_tree_add_uint(btl2cap_tree, hf_btl2cap_psm, tvb, offset, 0, psm);
+ }
+ else {
+ psm_item=proto_tree_add_uint(btl2cap_tree, hf_btl2cap_psm_dynamic, tvb, offset, 0, psm);
+ if( service )
+ proto_item_append_text(psm_item,": %s", val_to_str(*service, vs_service_classes, "Unknown service"));
+ }
PROTO_ITEM_SET_GENERATED(psm_item);
/* call next dissector */
- if (!dissector_try_uint(l2cap_psm_dissector_table, (guint32) psm,
- next_tvb, pinfo, tree)) {
- /* unknown protocol. declare as data */
- proto_tree_add_item(btl2cap_tree, hf_btl2cap_payload, tvb, offset, length, TRUE);
+ if (!dissector_try_uint(l2cap_psm_dissector_table, (guint32) psm, next_tvb, pinfo, tree)) {
+ /* not a known fixed PSM, try to find a registered service to a dynamic PSM */
+ if(service && !dissector_try_uint(l2cap_service_dissector_table, *service, next_tvb, pinfo, tree)) {
+ /* unknown protocol. declare as data */
+ proto_tree_add_item(btl2cap_tree, hf_btl2cap_payload, tvb, offset, length, TRUE);
+ }
}
offset+=tvb_length_remaining(tvb, offset);
- } else {
+ }
+ else {
proto_tree_add_item(btl2cap_tree, hf_btl2cap_payload, tvb, offset, length, TRUE);
offset+=tvb_length_remaining(tvb, offset);
}
@@ -936,18 +1007,29 @@ dissect_i_frame(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, proto_tree
}
if(next_tvb) {
if(psm){
+ guint32 *service =se_tree_lookup32(psm_to_service_table, ((psm_data?psm_data->local_service:0)<<31) | psm);
proto_item *psm_item;
+ if( psm < BTL2CAP_DYNAMIC_PSM_START ) {
psm_item=proto_tree_add_uint(btl2cap_tree, hf_btl2cap_psm, tvb, offset, 0, psm);
+ }
+ else {
+ psm_item=proto_tree_add_uint(btl2cap_tree, hf_btl2cap_psm_dynamic, tvb, offset, 0, psm);
+ if(service)
+ proto_item_append_text(psm_item," (%s)", val_to_str(*service, vs_service_classes, "Unknown service"));
+ }
PROTO_ITEM_SET_GENERATED(psm_item);
/* call next dissector */
- if (!dissector_try_uint(l2cap_psm_dissector_table, (guint32) psm,
- next_tvb, pinfo, tree)) {
+ if (!dissector_try_uint(l2cap_psm_dissector_table, (guint32) psm, next_tvb, pinfo, tree)) {
+ /* not a known fixed PSM, try to find a registered service to a dynamic PSM */
+ if(service && !dissector_try_uint(l2cap_service_dissector_table, *service, next_tvb, pinfo, tree)) {
/* unknown protocol. declare as data */
proto_tree_add_item(btl2cap_tree, hf_btl2cap_payload, next_tvb, 0, tvb_length(next_tvb), TRUE);
}
- } else {
+ }
+ }
+ else {
proto_tree_add_item(btl2cap_tree, hf_btl2cap_payload, next_tvb, 0, tvb_length(next_tvb), TRUE);
}
}
@@ -1041,6 +1123,7 @@ dissect_btl2cap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
proto_item *ti_command=NULL;
guint8 cmd_code;
guint16 cmd_length;
+ const gchar *cmd_str;
ti_command=proto_tree_add_none_format(btl2cap_tree,
hf_btl2cap_command, tvb,
@@ -1060,131 +1143,105 @@ dissect_btl2cap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
proto_item_set_len(ti_command, cmd_length+4);
offset+=2;
+ cmd_str = val_to_str(cmd_code, command_code_vals, "Unknown cmd");
+ proto_item_append_text(ti_command,"%s", cmd_str);
+ col_append_fstr(pinfo->cinfo, COL_INFO, "%s", cmd_str);
+
switch(cmd_code) {
case 0x01: /* Command Reject */
offset=dissect_comrej(tvb, offset, pinfo, btl2cap_cmd_tree);
- proto_item_append_text(ti_command, "Command Reject");
- col_append_str(pinfo->cinfo, COL_INFO, "Command Reject");
break;
case 0x02: /* Connection Request */
- offset=dissect_connrequest(tvb, offset, pinfo, btl2cap_cmd_tree);
- proto_item_append_text(ti_command, "Connection Request");
- col_append_str(pinfo->cinfo, COL_INFO, "Connection Request");
+ offset=dissect_connrequest(tvb, offset, pinfo, btl2cap_cmd_tree, FALSE);
break;
case 0x03: /* Connection Response */
offset=dissect_connresponse(tvb, offset, pinfo, btl2cap_cmd_tree);
- proto_item_append_text(ti_command, "Connection Response");
- col_append_str(pinfo->cinfo, COL_INFO, "Connection Response");
break;
case 0x04: /* Configure Request */
offset=dissect_configrequest(tvb, offset, pinfo, btl2cap_cmd_tree, cmd_length);
- proto_item_append_text(ti_command, "Configure Request");
- col_append_str(pinfo->cinfo, COL_INFO, "Configure Request");
break;
case 0x05: /* Configure Response */
offset=dissect_configresponse(tvb, offset, pinfo, btl2cap_cmd_tree, cmd_length);
- proto_item_append_text(ti_command, "Configure Response");
- col_append_str(pinfo->cinfo, COL_INFO, "Configure Response");
break;
case 0x06: /* Disconnect Request */
offset=dissect_disconnrequestresponse(tvb, offset, pinfo, btl2cap_cmd_tree);
- proto_item_append_text(ti_command, "Disconnect Request");
- col_append_str(pinfo->cinfo, COL_INFO, "Disconnect Request");
break;
case 0x07: /* Disconnect Response */
offset=dissect_disconnrequestresponse(tvb, offset, pinfo, btl2cap_cmd_tree);
- proto_item_append_text(ti_command, "Disconnect Response");
- col_append_str(pinfo->cinfo, COL_INFO, "Disconnect Response");
break;
case 0x08: /* Echo Request */
- proto_item_append_text(ti_command, "Echo Request");
offset+=tvb_length_remaining(tvb, offset);
- col_append_str(pinfo->cinfo, COL_INFO, "Echo Request");
break;
case 0x09: /* Echo Response */
- proto_item_append_text(ti_command, "Echo Response");
offset+=tvb_length_remaining(tvb, offset);
- col_append_str(pinfo->cinfo, COL_INFO, "Echo Response");
break;
case 0x0a: /* Information Request */
offset=dissect_inforequest(tvb, offset, pinfo, btl2cap_cmd_tree);
-
- proto_item_append_text(ti_command, "Information Request");
- col_append_str(pinfo->cinfo, COL_INFO, "Information Request");
break;
case 0x0b: /* Information Response */
offset=dissect_inforesponse(tvb, offset, pinfo, btl2cap_cmd_tree);
- proto_item_append_text(ti_command, "Information Response");
- col_append_str(pinfo->cinfo, COL_INFO, "Information Response");
break;
case 0x0c: /* Create Channel Request */
- offset=dissect_chanrequest(tvb, offset, pinfo, btl2cap_cmd_tree);
- proto_item_append_text(ti_command, "Create Channel Request");
- col_append_str(pinfo->cinfo, COL_INFO, "Create Channel Request");
+ offset=dissect_connrequest(tvb, offset, pinfo, btl2cap_cmd_tree, TRUE);
break;
case 0x0d: /* Create Channel Response */
offset=dissect_chanresponse(tvb, offset, pinfo, btl2cap_cmd_tree);
- proto_item_append_text(ti_command, "Create Channel Response");
- col_append_str(pinfo->cinfo, COL_INFO, "Create Channel Response");
break;
case 0x0e: /* Move Channel Request */
offset=dissect_movechanrequest(tvb, offset, pinfo, btl2cap_cmd_tree);
- proto_item_append_text(ti_command, "Move Channel Request");
- col_append_str(pinfo->cinfo, COL_INFO, "Move Channel Request");
break;
case 0x0f: /* Move Channel Response */
offset=dissect_movechanresponse(tvb, offset, pinfo, btl2cap_cmd_tree);
- proto_item_append_text(ti_command, "Move Channel Response");
- col_append_str(pinfo->cinfo, COL_INFO, "Move Channel Response");
break;
case 0x10: /* Move Channel Confirmation */
offset=dissect_movechanconfirmation(tvb, offset, pinfo, btl2cap_cmd_tree);
- proto_item_append_text(ti_command, "Move Channel Confirmation");
- col_append_str(pinfo->cinfo, COL_INFO, "Move Channel Confirmation");
break;
case 0x11: /* Move Channel Confirmation Response */
offset=dissect_movechanconfirmationresponse(tvb, offset, pinfo, btl2cap_cmd_tree);
- proto_item_append_text(ti_command, "Move Channel Confirmation Response");
- col_append_str(pinfo->cinfo, COL_INFO, "Move Channel Confirmation Response");
break;
- default:
- proto_tree_add_item(btl2cap_cmd_tree, hf_btl2cap_cmd_data, tvb, offset, -1, TRUE);
- offset+=tvb_length_remaining(tvb, offset);
- break;
+ default:
+ proto_tree_add_item(btl2cap_cmd_tree, hf_btl2cap_cmd_data, tvb, offset, -1, TRUE);
+ offset+=tvb_length_remaining(tvb, offset);
+ break;
}
}
- } else if (cid == BTL2CAP_FIXED_CID_CONNLESS) { /* Connectionless reception channel */
+ }
+ else if (cid == BTL2CAP_FIXED_CID_CONNLESS) { /* Connectionless reception channel */
col_append_str(pinfo->cinfo, COL_INFO, "Connectionless reception channel");
psm = tvb_get_letohs(tvb, offset);
proto_tree_add_item(btl2cap_tree, hf_btl2cap_psm, tvb, offset, 2, TRUE);
offset+=2;
-
next_tvb = tvb_new_subset(tvb, offset, tvb_length_remaining(tvb, offset), length);
/* call next dissector */
- if(!dissector_try_uint(l2cap_psm_dissector_table, (guint32) psm,
- next_tvb, pinfo, tree)){
- /* unknown protocol. declare as data */
- proto_tree_add_item(btl2cap_tree, hf_btl2cap_payload, tvb, offset, length, TRUE);
+ if(!dissector_try_uint(l2cap_psm_dissector_table, (guint32) psm, next_tvb, pinfo, tree)) {
+ /* not a known fixed PSM, try to find a registered service to a dynamic PSM */
+ guint32 *service;
+ service=se_tree_lookup32(psm_to_service_table, ((pinfo->p2p_dir==P2P_DIR_RECV)?0x80000000:0) | psm);
+
+ if(!service || !dissector_try_uint(l2cap_service_dissector_table, *service, next_tvb, pinfo, tree)) {
+ /* unknown protocol. declare as data */
+ proto_tree_add_item(btl2cap_tree, hf_btl2cap_payload, tvb, offset, length, TRUE);
+ }
}
offset+=tvb_length_remaining(tvb, offset);
}
@@ -1233,7 +1290,7 @@ dissect_btl2cap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
else
config_data = &(psm_data->out);
if(config_data->mode == 0) {
- dissect_b_frame(tvb, pinfo, tree, btl2cap_tree, psm, length, offset);
+ 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) {
@@ -1244,13 +1301,34 @@ dissect_btl2cap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
}
} else {
psm=0;
- dissect_b_frame(tvb, pinfo, tree, btl2cap_tree, psm, length, offset);
+ dissect_b_frame(tvb, pinfo, tree, btl2cap_tree, psm, FALSE, length, offset);
}
}
pinfo->private_data = pd_save;
}
+static int
+btl2cap_sdp_tap_packet(void *arg _U_, packet_info *pinfo _U_, epan_dissect_t *edt _U_, const void *arg2)
+{
+ btsdp_data_t *sdp_data = (btsdp_data_t *) arg2;
+
+ if( sdp_data->protocol == BTSDP_L2CAP_PROTOCOL_UUID ) {
+ guint32 token, *psm_service;
+
+ token = sdp_data->channel | ((sdp_data->flags & BTSDP_LOCAL_SERVICE_FLAG_MASK)<<31);
+
+ psm_service=se_tree_lookup32(psm_to_service_table, token);
+ if(!psm_service){
+ psm_service=se_alloc0(sizeof(guint32));
+ se_tree_insert32(psm_to_service_table, token, psm_service);
+ }
+ *psm_service = sdp_data->service;
+ }
+ return 0;
+}
+
+
/* Register the protocol with Wireshark */
void
proto_register_btl2cap(void)
@@ -1303,6 +1381,11 @@ proto_register_btl2cap(void)
FT_UINT16, BASE_HEX, VALS(psm_vals), 0x0,
"Protocol/Service Multiplexer", HFILL }
},
+ { &hf_btl2cap_psm_dynamic,
+ { "Dynamic PSM", "btl2cap.psm",
+ FT_UINT16, BASE_HEX, NULL, 0x0,
+ "Dynamic Protocol/Service Multiplexer", HFILL }
+ },
{ &hf_btl2cap_scid,
{ "Source CID", "btl2cap.scid",
FT_UINT16, BASE_HEX, NULL, 0x0,
@@ -1320,12 +1403,12 @@ proto_register_btl2cap(void)
},
{ &hf_btl2cap_controller,
{ "Controller ID", "btl2cap.ctrl_id",
- FT_UINT8, BASE_DEC, NULL, 0x0,
+ FT_UINT8, BASE_DEC, VALS(ctrl_id_code_vals), 0x0,
NULL, HFILL }
},
{ &hf_btl2cap_dcontroller,
{ "Controller ID", "btl2cap.dctrl_id",
- FT_UINT8, BASE_DEC, NULL, 0x0,
+ FT_UINT8, BASE_DEC, VALS(ctrl_id_code_vals), 0x0,
"Destination Controller ID", HFILL }
},
{ &hf_btl2cap_result,
@@ -1661,12 +1744,13 @@ proto_register_btl2cap(void)
};
/* Register the protocol name and description */
- proto_btl2cap = proto_register_protocol("Bluetooth L2CAP Packet", "L2CAP", "btl2cap");
+ proto_btl2cap = proto_register_protocol("Bluetooth L2CAP Protocol", "L2CAP", "btl2cap");
register_dissector("btl2cap", dissect_btl2cap, proto_btl2cap);
/* subdissector code */
l2cap_psm_dissector_table = register_dissector_table("btl2cap.psm", "L2CAP PSM", FT_UINT16, BASE_HEX);
+ l2cap_service_dissector_table = register_dissector_table("btl2cap.service", "L2CAP Service", FT_UINT16, BASE_HEX);
l2cap_cid_dissector_table = register_dissector_table("btl2cap.cid", "L2CAP CID", FT_UINT16, BASE_HEX);
/* Required function calls to register the header fields and subtrees used */
@@ -1674,7 +1758,17 @@ proto_register_btl2cap(void)
proto_register_subtree_array(ett, array_length(ett));
cid_to_psm_table=se_tree_create(EMEM_TREE_TYPE_RED_BLACK, "btl2cap scid to psm");
+ psm_to_service_table=se_tree_create(EMEM_TREE_TYPE_RED_BLACK, "btl2cap psm to service uuid");
+}
+
+void
+proto_reg_handoff_btl2cap(void)
+{
+ /* tap into the btsdp dissector to look for l2cap PSM infomation that
+ helps us determine the type of l2cap payload, i.e. which service is
+ using the PSM channel so we know which sub-dissector to call */
+ register_tap_listener("btsdp", NULL, NULL, 0, NULL, btl2cap_sdp_tap_packet, NULL);
}