aboutsummaryrefslogtreecommitdiffstats
path: root/epan
diff options
context:
space:
mode:
Diffstat (limited to 'epan')
-rw-r--r--epan/dissectors/Makefile.common1
-rw-r--r--epan/dissectors/packet-btl2cap.c320
-rw-r--r--epan/dissectors/packet-btl2cap.h13
-rw-r--r--epan/dissectors/packet-btobex.c985
-rw-r--r--epan/dissectors/packet-btrfcomm.c324
-rw-r--r--epan/dissectors/packet-btsdp.c530
6 files changed, 1346 insertions, 827 deletions
diff --git a/epan/dissectors/Makefile.common b/epan/dissectors/Makefile.common
index 8b893c77bd..3dc8037524 100644
--- a/epan/dissectors/Makefile.common
+++ b/epan/dissectors/Makefile.common
@@ -1030,6 +1030,7 @@ DISSECTOR_INCLUDES = \
packet-bthci_acl.h \
packet-btl2cap.h \
packet-btrfcomm.h \
+ packet-btsdp.h \
packet-camel.h \
packet-chdlc.h \
packet-cdt.h \
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);
}
diff --git a/epan/dissectors/packet-btl2cap.h b/epan/dissectors/packet-btl2cap.h
index 42bef4fe02..53c0ac38a2 100644
--- a/epan/dissectors/packet-btl2cap.h
+++ b/epan/dissectors/packet-btl2cap.h
@@ -24,9 +24,16 @@
#ifndef __PACKET_BTL2CAP_H__
#define __PACKET_BTL2CAP_H__
-#define BTL2CAP_PSM_SDP 0x0001
-#define BTL2CAP_PSM_RFCOMM 0x0003
-#define BTL2CAP_PSM_BNEP 0x000f
+#define BTL2CAP_PSM_SDP 0x0001
+#define BTL2CAP_PSM_RFCOMM 0x0003
+#define BTL2CAP_PSM_BNEP 0x000f
+#define BTL2CAP_PSM_HID_CTRL 0x0011
+#define BTL2CAP_PSM_HID_INTR 0x0013
+#define BTL2CAP_PSM_AVCTP_CTRL 0x0017
+#define BTL2CAP_PSM_AVDTP 0x0019
+#define BTL2CAP_PSM_AVCTP_BRWS 0x001b
+
+#define BTL2CAP_DYNAMIC_PSM_START 0x1000
#define BTL2CAP_FIXED_CID_NULL 0x0000
#define BTL2CAP_FIXED_CID_SIGNAL 0x0001
diff --git a/epan/dissectors/packet-btobex.c b/epan/dissectors/packet-btobex.c
index c5890439c9..2c807916ac 100644
--- a/epan/dissectors/packet-btobex.c
+++ b/epan/dissectors/packet-btobex.c
@@ -1,7 +1,7 @@
/* packet-btobex.c
- * Routines for the Bluetooth OBEX dissection
+ * Routines for Bluetooth OBEX dissection
*
- * Allan M. Madsen 2010
+ * Copyright 2010, Allan M. Madsen
*
* $Id$
*
@@ -36,6 +36,7 @@
#include <epan/emem.h>
#include <epan/reassemble.h>
#include "packet-btl2cap.h"
+#include "packet-btsdp.h"
/* Initialize the protocol and registered fields */
static int proto_btobex = -1;
@@ -55,7 +56,6 @@ static int hf_hdr_val_unicode = -1;
static int hf_hdr_val_byte_seq = -1;
static int hf_hdr_val_byte = -1;
static int hf_hdr_val_long = -1;
-static int hf_data = -1;
/* ************************************************************************* */
/* Header values for reassembly */
@@ -209,7 +209,7 @@ static const value_string header_id_vals[] = {
{ 0x4f, "Object Class" },
{ 0xc0, "Count" },
{ 0xc3, "Length" },
- { 0xC4, "Time" },
+ { 0xc4, "Time" },
{ 0xcb, "Connection Id" },
{ 0x30, "User Defined" },
{ 0x31, "User Defined" },
@@ -230,521 +230,532 @@ static const value_string header_id_vals[] = {
{ 0, NULL }
};
-static void defragment_init(void)
+static void
+defragment_init(void)
{
- fragment_table_init(&fragment_table);
- reassembled_table_init(&reassembled_table);
+ fragment_table_init(&fragment_table);
+ reassembled_table_init(&reassembled_table);
}
-static int is_ascii_str(const guint8 *str, int length)
+static int
+is_ascii_str(const guint8 *str, int length)
{
- int i;
+ int i;
- if( (length < 1) || (str[length-1] != '\0') )
- return 0;
+ if( (length < 1) || (str[length-1] != '\0') )
+ return 0;
- for(i=0; i<length-1; i++)
- {
- if( (str[i] < 0x20) && (str[i] != 0x0a) ) /* not strict ascii */
- break;
- }
+ for(i=0; i<length-1; i++) {
+ if( (str[i] < 0x20) && (str[i] != 0x0a) ) /* not strict ascii */
+ break;
+ }
- if(i<(length-1))
- return 0;
+ if(i<(length-1))
+ return 0;
- return 1;
+ return 1;
}
-static int display_unicode_string(tvbuff_t *tvb, proto_tree *tree, int offset, char **data)
+static int
+display_unicode_string(tvbuff_t *tvb, proto_tree *tree, int offset, char **data)
{
- char *str, *p;
- int len;
- int charoffset;
- guint16 character;
-
- /* display a unicode string from the tree and return new offset */
- /*
- * Get the length of the string.
- */
- len = 0;
- while ((character = tvb_get_ntohs(tvb, offset + len)) != '\0')
- len += 2;
- len += 2; /* count the '\0' too */
-
- /*
- * Allocate a buffer for the string; "len" is the length in
- * bytes, not the length in characters.
- */
- str = ep_alloc(len/2);
-
- /* - this assumes the string is just ISO 8859-1 */
- charoffset = offset;
- p = str;
- while ((character = tvb_get_ntohs(tvb, charoffset)) != '\0') {
- *p++ = (char) character;
- charoffset += 2;
- }
- *p = '\0';
-
- if(!is_ascii_str(str, len/2))
- {
- *str = '\0';
- }
-
- proto_tree_add_string(tree, hf_hdr_val_unicode, tvb, offset, len, str);
-
- if (data)
- *data = str;
-
- return offset+len;
+ char *str, *p;
+ int len;
+ int charoffset;
+ guint16 character;
+
+ /* display a unicode string from the tree and return new offset */
+ /*
+ * Get the length of the string.
+ */
+ len = 0;
+ while ((character = tvb_get_ntohs(tvb, offset + len)) != '\0')
+ len += 2;
+
+ len += 2; /* count the '\0' too */
+
+ /*
+ * Allocate a buffer for the string; "len" is the length in
+ * bytes, not the length in characters.
+ */
+ str = ep_alloc(len/2);
+
+ /* - this assumes the string is just ISO 8859-1 */
+ charoffset = offset;
+ p = str;
+ while ((character = tvb_get_ntohs(tvb, charoffset)) != '\0') {
+ *p++ = (char) character;
+ charoffset += 2;
+ }
+ *p = '\0';
+
+ if(!is_ascii_str(str, len/2)) {
+ *str = '\0';
+ }
+
+ proto_tree_add_string(tree, hf_hdr_val_unicode, tvb, offset, len, str);
+
+ if (data)
+ *data = str;
+
+ return offset+len;
}
static int
dissect_headers(proto_tree *tree, tvbuff_t *tvb, int offset, packet_info *pinfo)
{
- proto_tree *hdrs_tree=NULL;
- proto_item *hdrs=NULL;
- proto_tree *hdr_tree=NULL;
- proto_item *hdr=NULL;
- proto_item *handle_item;
- gint item_length = -1;
- guint8 hdr_id, i;
- const guint8 *ptr;
-
- if(tvb_length_remaining(tvb, offset)>0)
- {
- hdrs = proto_tree_add_text(tree, tvb, offset, item_length, "Headers");
- hdrs_tree=proto_item_add_subtree(hdrs, ett_btobex_hdrs);
- }
- else
- {
- return offset;
- }
-
- while(tvb_length_remaining(tvb, offset)>0)
- {
- hdr_id = tvb_get_guint8(tvb, offset);
-
- switch(0xC0 & hdr_id)
- {
- case 0x00:
- item_length = tvb_get_ntohs(tvb, offset+1);
- break;
- case 0x40: /* byte sequence */
- item_length = tvb_get_ntohs(tvb, offset+1);
- break;
- case 0x80: /* 1 byte */
- item_length = 2;
- break;
- case 0xc0: /* 4 bytes */
- item_length = 5;
- break;
- }
-
- hdr = proto_tree_add_text(hdrs_tree, tvb, offset, item_length, "%s", val_to_str(hdr_id, header_id_vals, "Unknown"));
- hdr_tree=proto_item_add_subtree(hdr, ett_btobex_hdr);
-
- proto_tree_add_item(hdr_tree, hf_hdr_id, tvb, offset, 1, FALSE);
-
- offset++;
-
- switch(0xC0 & hdr_id)
- {
- case 0x00: /* null terminated unicode */
- {
- proto_tree_add_item(hdr_tree, hf_hdr_length, tvb, offset, 2, FALSE);
- offset += 2;
-
- if( (item_length - 3) > 0 )
- {
- char *str;
- display_unicode_string(tvb, hdr_tree, offset, &str);
-
- proto_item_append_text(hdr_tree, " (\"%s\")", str);
-
- col_append_fstr(pinfo->cinfo, COL_INFO, " \"%s\"", str);
- }
- else
- {
- col_append_str(pinfo->cinfo, COL_INFO, " \"\"");
- }
-
- offset += item_length - 3;
- }
- break;
- case 0x40: /* byte sequence */
- proto_tree_add_item(hdr_tree, hf_hdr_length, tvb, offset, 2, FALSE);
- offset += 2;
-
- handle_item = proto_tree_add_item(hdr_tree, hf_hdr_val_byte_seq, tvb, offset, item_length - 3, FALSE);
-
- if( ((hdr_id == 0x46) || (hdr_id == 0x4a)) && (item_length == 19) ) /* target or who */
- {
- ptr = tvb_get_ptr(tvb, offset, item_length - 3);
- for( i=0; target_vals[i].strptr != NULL; i++)
- {
- if( memcmp(ptr, target_vals[i].value, 16) == 0 )
- {
- proto_item_append_text(handle_item, ": %s", target_vals[i].strptr);
-
- proto_item_append_text(hdr_tree, " (%s)", target_vals[i].strptr);
-
- col_append_fstr(pinfo->cinfo, COL_INFO, " - %s", target_vals[i].strptr);
- }
- }
- }
-
- if( !tvb_strneql(tvb, offset, "<?xml", 5) )
- {
- tvbuff_t* next_tvb = tvb_new_subset(tvb, offset, -1, -1);
-
- call_dissector(xml_handle, next_tvb, pinfo, tree);
- }
- else if(is_ascii_str(tvb_get_ptr(tvb, offset,item_length - 3), item_length - 3))
- {
- proto_item_append_text(hdr_tree, " (\"%s\")", tvb_get_ptr(tvb, offset,item_length - 3));
-
- col_append_fstr(pinfo->cinfo, COL_INFO, " \"%s\"", tvb_get_ptr(tvb, offset,item_length - 3));
- }
-
- offset += item_length - 3;
- break;
- case 0x80: /* 1 byte */
- proto_item_append_text(hdr_tree, " (%i)", tvb_get_ntohl(tvb, offset));
- proto_tree_add_item(hdr_tree, hf_hdr_val_byte, tvb, offset, 1, FALSE);
- offset++;
- break;
- case 0xc0: /* 4 bytes */
- proto_item_append_text(hdr_tree, " (%i)", tvb_get_ntohl(tvb, offset));
- proto_tree_add_item(hdr_tree, hf_hdr_val_long, tvb, offset, 4, FALSE);
- offset += 4;
- break;
- default:
- break;
- }
-
- }
-
- return offset;
+ proto_tree *hdrs_tree=NULL;
+ proto_item *hdrs=NULL;
+ proto_tree *hdr_tree=NULL;
+ proto_item *hdr=NULL;
+ proto_item *handle_item;
+ gint item_length = -1;
+ guint8 hdr_id, i;
+ const guint8 *ptr;
+
+ if(tvb_length_remaining(tvb, offset)>0) {
+ hdrs = proto_tree_add_text(tree, tvb, offset, item_length, "Headers");
+ hdrs_tree=proto_item_add_subtree(hdrs, ett_btobex_hdrs);
+ }
+ else {
+ return offset;
+ }
+
+ while(tvb_length_remaining(tvb, offset)>0) {
+ hdr_id = tvb_get_guint8(tvb, offset);
+
+ switch(0xC0 & hdr_id)
+ {
+ case 0x00: /* null terminated unicode */
+ item_length = tvb_get_ntohs(tvb, offset+1);
+ break;
+ case 0x40: /* byte sequence */
+ item_length = tvb_get_ntohs(tvb, offset+1);
+ break;
+ case 0x80: /* 1 byte */
+ item_length = 2;
+ break;
+ case 0xc0: /* 4 bytes */
+ item_length = 5;
+ break;
+ }
+
+ hdr = proto_tree_add_text(hdrs_tree, tvb, offset, item_length, "%s", val_to_str(hdr_id, header_id_vals, "Unknown"));
+ hdr_tree=proto_item_add_subtree(hdr, ett_btobex_hdr);
+
+ proto_tree_add_item(hdr_tree, hf_hdr_id, tvb, offset, 1, FALSE);
+
+ offset++;
+
+ switch(0xC0 & hdr_id)
+ {
+ case 0x00: /* null terminated unicode */
+ {
+ proto_tree_add_item(hdr_tree, hf_hdr_length, tvb, offset, 2, FALSE);
+ offset += 2;
+
+ if( (item_length - 3) > 0 ) {
+ char *str;
+
+ display_unicode_string(tvb, hdr_tree, offset, &str);
+ proto_item_append_text(hdr_tree, " (\"%s\")", str);
+ col_append_fstr(pinfo->cinfo, COL_INFO, " \"%s\"", str);
+ }
+ else {
+ col_append_str(pinfo->cinfo, COL_INFO, " \"\"");
+ }
+
+ offset += item_length - 3;
+ }
+ break;
+ case 0x40: /* byte sequence */
+ proto_tree_add_item(hdr_tree, hf_hdr_length, tvb, offset, 2, FALSE);
+ offset += 2;
+
+ handle_item = proto_tree_add_item(hdr_tree, hf_hdr_val_byte_seq, tvb, offset, item_length - 3, FALSE);
+
+ if( ((hdr_id == 0x46) || (hdr_id == 0x4a)) && (item_length == 19) ) { /* target or who */
+ ptr = tvb_get_ptr(tvb, offset, item_length - 3);
+ for( i=0; target_vals[i].strptr != NULL; i++) {
+ if( memcmp(ptr, target_vals[i].value, 16) == 0 ) {
+ proto_item_append_text(handle_item, ": %s", target_vals[i].strptr);
+ proto_item_append_text(hdr_tree, " (%s)", target_vals[i].strptr);
+ col_append_fstr(pinfo->cinfo, COL_INFO, " - %s", target_vals[i].strptr);
+ }
+ }
+ }
+
+ if( !tvb_strneql(tvb, offset, "<?xml", 5) )
+ {
+ tvbuff_t* next_tvb = tvb_new_subset(tvb, offset, -1, -1);
+
+ call_dissector(xml_handle, next_tvb, pinfo, tree);
+ }
+ else if(is_ascii_str(tvb_get_ptr(tvb, offset,item_length - 3), item_length - 3))
+ {
+ proto_item_append_text(hdr_tree, " (\"%s\")", tvb_get_ptr(tvb, offset,item_length - 3));
+ col_append_fstr(pinfo->cinfo, COL_INFO, " \"%s\"", tvb_get_ptr(tvb, offset,item_length - 3));
+ }
+
+ offset += item_length - 3;
+ break;
+ case 0x80: /* 1 byte */
+ proto_item_append_text(hdr_tree, " (%i)", tvb_get_ntohl(tvb, offset));
+ proto_tree_add_item(hdr_tree, hf_hdr_val_byte, tvb, offset, 1, FALSE);
+ offset++;
+ break;
+ case 0xc0: /* 4 bytes */
+ proto_item_append_text(hdr_tree, " (%i)", tvb_get_ntohl(tvb, offset));
+ proto_tree_add_item(hdr_tree, hf_hdr_val_long, tvb, offset, 4, FALSE);
+ offset += 4;
+ break;
+ default:
+ break;
+ }
+ }
+
+ return offset;
}
static void
dissect_btobex(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
- proto_item *ti;
- proto_tree *st;
- fragment_data *frag_msg = NULL;
- gboolean save_fragmented, complete;
- tvbuff_t* new_tvb = NULL;
- tvbuff_t* next_tvb = NULL;
- guint32 no_of_segments = 0;
- int offset=0;
-
- save_fragmented = pinfo->fragmented;
-
- frag_msg = NULL;
- complete = FALSE;
-
- if( fragment_get(pinfo, pinfo->p2p_dir, fragment_table) )
- {
- /* not the first fragment */
- frag_msg = fragment_add_seq_next(tvb, 0, pinfo, pinfo->p2p_dir,
- fragment_table, reassembled_table, tvb_length(tvb), TRUE);
-
- new_tvb = process_reassembled_data(tvb, 0, pinfo,
- "Reassembled Obex packet", frag_msg, &btobex_frag_items, NULL, tree);
-
- if(frag_msg != NULL) /* last fragment */
- complete = TRUE;
-
- }
- else
- {
- if(tvb_length(tvb) < tvb_get_ntohs(tvb, offset+1))
- {
- /* first fragment in a sequence */
- no_of_segments = tvb_get_ntohs(tvb, offset+1)/tvb_length(tvb);
- if ( tvb_get_ntohs(tvb, offset+1) > (no_of_segments * tvb_length(tvb)))
- no_of_segments++;
-
- frag_msg = fragment_add_seq_next(tvb, 0, pinfo, pinfo->p2p_dir,
- fragment_table, reassembled_table, tvb_length(tvb), TRUE);
-
- fragment_set_tot_len(pinfo, pinfo->p2p_dir, fragment_table, no_of_segments-1);
-
- new_tvb = process_reassembled_data(tvb, 0, pinfo,
- "Reassembled Obex packet", frag_msg, &btobex_frag_items, NULL, tree);
-
- pinfo->fragmented = TRUE;
- }
- else if( tvb_length(tvb) == tvb_get_ntohs(tvb, offset+1) )
- {
- /* non-fragmented */
- complete = TRUE;
- pinfo->fragmented = FALSE;
- }
- }
-
- if (new_tvb) { /* take it all */
- next_tvb = new_tvb;
- complete = TRUE;
- } else { /* make a new subset */
- next_tvb = tvb_new_subset(tvb, offset, -1, -1);
- }
-
- if( complete )
- {
- guint8 code;
-
- /* fully dissectable packet ready */
- col_set_str(pinfo->cinfo, COL_PROTOCOL, "OBEX");
-
- ti = proto_tree_add_item(tree, proto_btobex, next_tvb, 0, -1, FALSE);
- st = proto_item_add_subtree(ti, ett_btobex);
-
- /* op/response code */
- code = tvb_get_guint8(next_tvb, offset) & BTOBEX_CODE_VALS_MASK;
-
- col_add_fstr(pinfo->cinfo, COL_INFO, "%s %s",
- pinfo->p2p_dir==P2P_DIR_SENT?"Sent":"Rcvd",
- val_to_str(code, code_vals, "Unknown"));
-
- if( (code < BTOBEX_CODE_VALS_CONTINUE) || (code == BTOBEX_CODE_VALS_ABORT))
- {
- proto_tree_add_item(st, hf_opcode, next_tvb, offset, 1, FALSE);
- last_opcode[pinfo->p2p_dir] = code;
- }
- else
- {
- proto_tree_add_item(st, hf_response_code, next_tvb, offset, 1, FALSE);
- }
- proto_tree_add_item(st, hf_final_flag, next_tvb, offset, 1, FALSE);
- offset++;
-
- /* length */
- proto_tree_add_item(st, hf_length, next_tvb, offset, 2, FALSE);
- offset += 2;
-
- switch(code)
- {
- case BTOBEX_CODE_VALS_CONNECT:
- proto_tree_add_item(st, hf_version, next_tvb, offset, 1, FALSE);
- offset++;
-
- proto_tree_add_item(st, hf_flags, next_tvb, offset, 1, FALSE);
- offset++;
-
- proto_tree_add_item(st, hf_max_pkt_len, next_tvb, offset, 2, FALSE);
- offset += 2;
- break;
-
- case BTOBEX_CODE_VALS_PUT:
- case BTOBEX_CODE_VALS_GET:
- col_append_fstr(pinfo->cinfo, COL_INFO, " %s",
- (tvb_get_guint8(next_tvb, offset) & 0x80)==0x80?"final":"continue");
- break;
-
- case BTOBEX_CODE_VALS_SET_PATH:
- proto_tree_add_item(st, hf_flags, next_tvb, offset, 1, FALSE);
- proto_tree_add_item(st, hf_set_path_flags_0, next_tvb, offset, 1, FALSE);
- proto_tree_add_item(st, hf_set_path_flags_1, next_tvb, offset, 1, FALSE);
- offset++;
-
- proto_tree_add_item(st, hf_constants, next_tvb, offset, 1, FALSE);
- offset++;
- break;
-
- case BTOBEX_CODE_VALS_DISCONNECT:
- case BTOBEX_CODE_VALS_ABORT:
- break;
-
- default:
- {
- guint8 response_opcode = last_opcode[(pinfo->p2p_dir + 1) & 0x01];
-
- if(response_opcode == BTOBEX_CODE_VALS_CONNECT)
- {
- proto_tree_add_item(st, hf_version, next_tvb, offset, 1, FALSE);
- offset++;
-
- proto_tree_add_item(st, hf_flags, next_tvb, offset, 1, FALSE);
- offset++;
-
- proto_tree_add_item(st, hf_max_pkt_len, next_tvb, offset, 2, FALSE);
- offset += 2;
- }
- }
- break;
- }
-
- offset = dissect_headers(st, next_tvb, offset, pinfo);
- }
- else
- {
- /* packet fragment */
- col_add_fstr(pinfo->cinfo, COL_INFO, "%s Obex fragment",
- pinfo->p2p_dir==P2P_DIR_SENT?"Sent":"Rcvd");
-
- call_dissector(data_handle, next_tvb, pinfo, tree);
- }
-
- pinfo->fragmented = save_fragmented;
+ proto_item *ti;
+ proto_tree *st;
+ fragment_data *frag_msg = NULL;
+ gboolean save_fragmented, complete;
+ tvbuff_t* new_tvb = NULL;
+ tvbuff_t* next_tvb = NULL;
+ guint32 no_of_segments = 0;
+ int offset=0;
+
+ save_fragmented = pinfo->fragmented;
+
+ frag_msg = NULL;
+ complete = FALSE;
+
+ if( fragment_get(pinfo, pinfo->p2p_dir, fragment_table) ) {
+ /* not the first fragment */
+ frag_msg = fragment_add_seq_next(tvb, 0, pinfo, pinfo->p2p_dir,
+ fragment_table, reassembled_table, tvb_length(tvb), TRUE);
+
+ new_tvb = process_reassembled_data(tvb, 0, pinfo,
+ "Reassembled Obex packet", frag_msg, &btobex_frag_items, NULL, tree);
+
+ pinfo->fragmented = TRUE;
+ }
+ else {
+ if(tvb_length(tvb) < tvb_get_ntohs(tvb, offset+1)) {
+ /* first fragment in a sequence */
+ no_of_segments = tvb_get_ntohs(tvb, offset+1)/tvb_length(tvb);
+ if ( tvb_get_ntohs(tvb, offset+1) > (no_of_segments * tvb_length(tvb)))
+ no_of_segments++;
+
+ frag_msg = fragment_add_seq_next(tvb, 0, pinfo, pinfo->p2p_dir,
+ fragment_table, reassembled_table, tvb_length(tvb), TRUE);
+
+ fragment_set_tot_len(pinfo, pinfo->p2p_dir, fragment_table, no_of_segments-1);
+
+ new_tvb = process_reassembled_data(tvb, 0, pinfo,
+ "Reassembled Obex packet", frag_msg, &btobex_frag_items, NULL, tree);
+
+ pinfo->fragmented = TRUE;
+ }
+ else if( tvb_length(tvb) == tvb_get_ntohs(tvb, offset+1) ) {
+ /* non-fragmented */
+ complete = TRUE;
+ pinfo->fragmented = FALSE;
+ }
+ }
+
+ if (new_tvb) { /* take it all */
+ next_tvb = new_tvb;
+ complete = TRUE;
+ }
+ else { /* make a new subset */
+ next_tvb = tvb_new_subset(tvb, offset, -1, -1);
+ }
+
+ if( complete ) {
+ guint8 code, final_flag;
+
+ /* fully dissectable packet ready */
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "OBEX");
+
+ ti = proto_tree_add_item(tree, proto_btobex, next_tvb, 0, -1, FALSE);
+ st = proto_item_add_subtree(ti, ett_btobex);
+
+ /* op/response code */
+ code = tvb_get_guint8(next_tvb, offset) & BTOBEX_CODE_VALS_MASK;
+ final_flag = tvb_get_guint8(next_tvb, offset) & 0x80;
+
+ col_add_fstr(pinfo->cinfo, COL_INFO, "%s %s",
+ pinfo->p2p_dir==P2P_DIR_SENT?"Sent":"Rcvd",
+ val_to_str(code, code_vals, "Unknown"));
+
+ if( (code < BTOBEX_CODE_VALS_CONTINUE) || (code == BTOBEX_CODE_VALS_ABORT)) {
+ proto_tree_add_item(st, hf_opcode, next_tvb, offset, 1, FALSE);
+ last_opcode[pinfo->p2p_dir] = code;
+ }
+ else {
+ proto_tree_add_item(st, hf_response_code, next_tvb, offset, 1, FALSE);
+ }
+ proto_tree_add_item(st, hf_final_flag, next_tvb, offset, 1, FALSE);
+ offset++;
+
+ /* length */
+ proto_tree_add_item(st, hf_length, next_tvb, offset, 2, FALSE);
+ offset += 2;
+
+ switch(code)
+ {
+ case BTOBEX_CODE_VALS_CONNECT:
+ proto_tree_add_item(st, hf_version, next_tvb, offset, 1, FALSE);
+ offset++;
+
+ proto_tree_add_item(st, hf_flags, next_tvb, offset, 1, FALSE);
+ offset++;
+
+ proto_tree_add_item(st, hf_max_pkt_len, next_tvb, offset, 2, FALSE);
+ offset += 2;
+ break;
+
+ case BTOBEX_CODE_VALS_PUT:
+ case BTOBEX_CODE_VALS_GET:
+ col_append_fstr(pinfo->cinfo, COL_INFO, " %s", final_flag==0x80?"final":"continue");
+ break;
+
+ case BTOBEX_CODE_VALS_SET_PATH:
+ proto_tree_add_item(st, hf_flags, next_tvb, offset, 1, FALSE);
+ proto_tree_add_item(st, hf_set_path_flags_0, next_tvb, offset, 1, FALSE);
+ proto_tree_add_item(st, hf_set_path_flags_1, next_tvb, offset, 1, FALSE);
+ offset++;
+
+ proto_tree_add_item(st, hf_constants, next_tvb, offset, 1, FALSE);
+ offset++;
+ break;
+
+ case BTOBEX_CODE_VALS_DISCONNECT:
+ case BTOBEX_CODE_VALS_ABORT:
+ break;
+
+ default:
+ {
+ guint8 response_opcode = last_opcode[(pinfo->p2p_dir + 1) & 0x01];
+
+ if(response_opcode == BTOBEX_CODE_VALS_CONNECT) {
+ proto_tree_add_item(st, hf_version, next_tvb, offset, 1, FALSE);
+ offset++;
+
+ proto_tree_add_item(st, hf_flags, next_tvb, offset, 1, FALSE);
+ offset++;
+
+ proto_tree_add_item(st, hf_max_pkt_len, next_tvb, offset, 2, FALSE);
+ offset += 2;
+ }
+ }
+ break;
+ }
+
+ offset = dissect_headers(st, next_tvb, offset, pinfo);
+ }
+ else
+ {
+ /* packet fragment */
+ col_add_fstr(pinfo->cinfo, COL_INFO, "%s Obex fragment",
+ pinfo->p2p_dir==P2P_DIR_SENT?"Sent":"Rcvd");
+
+ call_dissector(data_handle, next_tvb, pinfo, tree);
+ }
+
+ pinfo->fragmented = save_fragmented;
}
void
proto_register_btobex(void)
{
- static hf_register_info hf[] = {
- {&hf_opcode,
- {"Opcode", "btobex.opcode",
- FT_UINT8, BASE_HEX, VALS(code_vals), BTOBEX_CODE_VALS_MASK,
- "Request Opcode", HFILL}
- },
- {&hf_response_code,
- {"Response Code", "btobex.resp_code",
- FT_UINT8, BASE_HEX, VALS(code_vals), BTOBEX_CODE_VALS_MASK,
- NULL, HFILL}
- },
- {&hf_final_flag,
- {"Final Flag", "btobex.final_flag",
- FT_BOOLEAN, BASE_HEX, TFS(&true_false), 0x80,
- NULL, HFILL}
- },
- {&hf_length,
- {"Packet Length", "btobex.pkt_len",
- FT_UINT16, BASE_DEC, NULL, 0,
- NULL, HFILL}
- },
- {&hf_version,
- {"Version", "btobex.version",
- FT_UINT8, BASE_HEX, VALS(version_vals), 0x00,
- "Obex Version", HFILL}
- },
- {&hf_flags,
- {"Flags", "btobex.flags",
- FT_UINT8, BASE_HEX, NULL, 0x00,
- NULL, HFILL}
- },
- {&hf_constants,
- {"Constants", "btobex.constants",
- FT_UINT8, BASE_HEX, NULL, 0x00,
- NULL, HFILL}
- },
- {&hf_max_pkt_len,
- {"Max. Packet Length", "btobex.max_pkt_len",
- FT_UINT16, BASE_DEC, NULL, 0,
- "Maximum Packet Length", HFILL}
- },
- {&hf_set_path_flags_0,
- {"Go back one folder (../) first", "btobex.set_path_flags_0",
- FT_BOOLEAN, 8, TFS(&true_false), 0x01,
- NULL, HFILL}
- },
- {&hf_set_path_flags_1,
- {"Do not create folder, if not existing", "btobex.set_path_flags_1",
- FT_BOOLEAN, 8, TFS(&true_false), 0x02,
- NULL, HFILL}
- },
- {&hf_hdr_id,
- {"Header Id", "btobex.hdr_id",
- FT_UINT8, BASE_HEX, VALS(header_id_vals), 0x00,
- NULL, HFILL}
- },
- {&hf_hdr_length,
- {"Length", "btobex.pkt_hdr_len",
- FT_UINT16, BASE_DEC, NULL, 0,
- "Header Length", HFILL}
- },
- {&hf_hdr_val_unicode,
- { "Value", "btobex.pkt_hdr_val_uc",
- FT_STRING, BASE_NONE, NULL, 0,
- "Unicode Value", HFILL }
- },
- {&hf_hdr_val_byte_seq,
- {"Value", "btobex.hdr_val_byte_seq",
- FT_BYTES, BASE_NONE, NULL, 0,
- "Byte Value", HFILL}
- },
- {&hf_hdr_val_byte,
- {"Value", "btobex.hdr_val_byte",
- FT_UINT8, BASE_HEX, NULL, 0,
- "Byte Sequence Value", HFILL}
- },
- {&hf_hdr_val_long,
- {"Value", "btobex.hdr_val_long",
- FT_UINT32, BASE_DEC, NULL, 0,
- "4-byte Value", HFILL}
- },
- {&hf_data,
- {"Obex Data", "btobex.data",
- FT_NONE, BASE_NONE, NULL, 0,
- NULL, HFILL}
- },
-
- /* for fragmentation */
- { &hf_btobex_fragment_overlap,
- { "Fragment overlap", "btobex.fragment.overlap", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
- "Fragment overlaps with other fragments", HFILL }},
-
- { &hf_btobex_fragment_overlap_conflict,
- { "Conflicting data in fragment overlap", "btobex.fragment.overlap.conflict", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
- "Overlapping fragments contained conflicting data", HFILL }},
-
- { &hf_btobex_fragment_multiple_tails,
- { "Multiple tail fragments found", "btobex.fragment.multipletails", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
- "Several tails were found when defragmenting the packet", HFILL }},
-
- { &hf_btobex_fragment_too_long_fragment,
- { "Fragment too long", "btobex.fragment.toolongfragment", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
- "Fragment contained data past end of packet", HFILL }},
-
- { &hf_btobex_fragment_error,
- { "Defragmentation error", "btobex.fragment.error", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
- "Defragmentation error due to illegal fragments", HFILL }},
-
- { &hf_btobex_fragment,
- { "OBEX Fragment", "btobex.fragment", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
- "btobex Fragment", HFILL }},
-
- { &hf_btobex_fragments,
- { "OBEX Fragments", "btobex.fragments", FT_NONE, BASE_NONE, NULL, 0x0,
- "btobex Fragments", HFILL }},
-
- { &hf_btobex_reassembled_in,
- { "Reassembled OBEX in frame", "btobex.reassembled_in", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
- "This OBEX frame is reassembled in this frame", HFILL }},
-
- { &hf_btobex_reassembled_length,
- { "Reassembled OBEX length", "btobex.reassembled.length", FT_UINT32, BASE_DEC, NULL, 0x0,
- "The total length of the reassembled payload", HFILL }}
- };
-
- /* Setup protocol subtree array */
- static gint *ett[] = {
- &ett_btobex,
- &ett_btobex_hdrs,
- &ett_btobex_hdr,
- &ett_btobex_fragment,
- &ett_btobex_fragments
- };
-
- proto_btobex = proto_register_protocol("Bluetooth OBEX", "OBEX", "btobex");
-
- register_dissector("btobex", dissect_btobex, proto_btobex);
-
- /* Required function calls to register the header fields and subtrees used */
- proto_register_field_array(proto_btobex, hf, array_length(hf));
- proto_register_subtree_array(ett, array_length(ett));
-
- register_init_routine(&defragment_init);
+ static hf_register_info hf[] = {
+ {&hf_opcode,
+ {"Opcode", "btobex.opcode",
+ FT_UINT8, BASE_HEX, VALS(code_vals), BTOBEX_CODE_VALS_MASK,
+ "Request Opcode", HFILL}
+ },
+ {&hf_response_code,
+ {"Response Code", "btobex.resp_code",
+ FT_UINT8, BASE_HEX, VALS(code_vals), BTOBEX_CODE_VALS_MASK,
+ NULL, HFILL}
+ },
+ {&hf_final_flag,
+ {"Final Flag", "btobex.final_flag",
+ FT_BOOLEAN, BASE_HEX, TFS(&true_false), 0x80,
+ NULL, HFILL}
+ },
+ {&hf_length,
+ {"Packet Length", "btobex.pkt_len",
+ FT_UINT16, BASE_DEC, NULL, 0,
+ NULL, HFILL}
+ },
+ {&hf_version,
+ {"Version", "btobex.version",
+ FT_UINT8, BASE_HEX, VALS(version_vals), 0x00,
+ "Obex Protocol Version", HFILL}
+ },
+ {&hf_flags,
+ {"Flags", "btobex.flags",
+ FT_UINT8, BASE_HEX, NULL, 0x00,
+ NULL, HFILL}
+ },
+ {&hf_constants,
+ {"Constants", "btobex.constants",
+ FT_UINT8, BASE_HEX, NULL, 0x00,
+ NULL, HFILL}
+ },
+ {&hf_max_pkt_len,
+ {"Max. Packet Length", "btobex.max_pkt_len",
+ FT_UINT16, BASE_DEC, NULL, 0,
+ NULL, HFILL}
+ },
+ {&hf_set_path_flags_0,
+ {"Go back one folder (../) first", "btobex.set_path_flags_0",
+ FT_BOOLEAN, 8, TFS(&true_false), 0x01,
+ NULL, HFILL}
+ },
+ {&hf_set_path_flags_1,
+ {"Do not create folder, if not existing", "btobex.set_path_flags_1",
+ FT_BOOLEAN, 8, TFS(&true_false), 0x02,
+ NULL, HFILL}
+ },
+ {&hf_hdr_id,
+ {"Header Id", "btobex.hdr_id",
+ FT_UINT8, BASE_HEX, VALS(header_id_vals), 0x00,
+ NULL, HFILL}
+ },
+ {&hf_hdr_length,
+ {"Length", "btobex.pkt_hdr_len",
+ FT_UINT16, BASE_DEC, NULL, 0,
+ "Header Length", HFILL}
+ },
+ {&hf_hdr_val_unicode,
+ { "Value", "btobex.pkt_hdr_val_uc",
+ FT_STRING, BASE_NONE, NULL, 0,
+ "Unicode Value", HFILL }
+ },
+ {&hf_hdr_val_byte_seq,
+ {"Value", "btobex.hdr_val_byte_seq",
+ FT_BYTES, BASE_NONE, NULL, 0,
+ "Byte Value", HFILL}
+ },
+ {&hf_hdr_val_byte,
+ {"Value", "btobex.hdr_val_byte",
+ FT_UINT8, BASE_HEX, NULL, 0,
+ "Byte Sequence Value", HFILL}
+ },
+ {&hf_hdr_val_long,
+ {"Value", "btobex.hdr_val_long",
+ FT_UINT32, BASE_DEC, NULL, 0,
+ "4-byte Value", HFILL}
+ },
+
+ /* for fragmentation */
+ { &hf_btobex_fragment_overlap,
+ { "Fragment overlap", "btobex.fragment.overlap", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
+ "Fragment overlaps with other fragments", HFILL }
+ },
+ { &hf_btobex_fragment_overlap_conflict,
+ { "Conflicting data in fragment overlap", "btobex.fragment.overlap.conflict", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
+ "Overlapping fragments contained conflicting data", HFILL }
+ },
+ { &hf_btobex_fragment_multiple_tails,
+ { "Multiple tail fragments found", "btobex.fragment.multipletails", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
+ "Several tails were found when defragmenting the packet", HFILL }
+ },
+ { &hf_btobex_fragment_too_long_fragment,
+ { "Fragment too long", "btobex.fragment.toolongfragment", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
+ "Fragment contained data past end of packet", HFILL }
+ },
+ { &hf_btobex_fragment_error,
+ { "Defragmentation error", "btobex.fragment.error", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
+ "Defragmentation error due to illegal fragments", HFILL }
+ },
+ { &hf_btobex_fragment,
+ { "OBEX Fragment", "btobex.fragment", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
+ "btobex Fragment", HFILL }
+ },
+ { &hf_btobex_fragments,
+ { "OBEX Fragments", "btobex.fragments", FT_NONE, BASE_NONE, NULL, 0x0,
+ "btobex Fragments", HFILL }
+ },
+ { &hf_btobex_reassembled_in,
+ { "Reassembled OBEX in frame", "btobex.reassembled_in", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
+ "This OBEX frame is reassembled in this frame", HFILL }
+ },
+ { &hf_btobex_reassembled_length,
+ { "Reassembled OBEX length", "btobex.reassembled.length", FT_UINT32, BASE_DEC, NULL, 0x0,
+ "The total length of the reassembled payload", HFILL }
+ }
+ };
+
+ /* Setup protocol subtree array */
+ static gint *ett[] = {
+ &ett_btobex,
+ &ett_btobex_hdrs,
+ &ett_btobex_hdr,
+ &ett_btobex_fragment,
+ &ett_btobex_fragments
+ };
+
+ proto_btobex = proto_register_protocol("Bluetooth OBEX Protocol", "OBEX", "btobex");
+
+ register_dissector("btobex", dissect_btobex, proto_btobex);
+
+ /* Required function calls to register the header fields and subtrees used */
+ proto_register_field_array(proto_btobex, hf, array_length(hf));
+ proto_register_subtree_array(ett, array_length(ett));
+
+ register_init_routine(&defragment_init);
}
void
proto_reg_handoff_btobex(void)
{
- xml_handle = find_dissector("xml");
- data_handle = find_dissector("data");
+ dissector_handle_t btobex_handle;
+
+ btobex_handle = find_dissector("btobex");
+
+ /* register in rfcomm and l2cap the profiles/services this dissector should handle */
+ dissector_add_uint("btrfcomm.service", BTSDP_OPP_SERVICE_UUID, btobex_handle);
+ dissector_add_uint("btrfcomm.service", BTSDP_FTP_SERVICE_UUID, btobex_handle);
+ dissector_add_uint("btrfcomm.service", BTSDP_BPP_SERVICE_UUID, btobex_handle);
+ dissector_add_uint("btrfcomm.service", BTSDP_BPP_STATUS_SERVICE_UUID, btobex_handle);
+ dissector_add_uint("btrfcomm.service", BTSDP_BIP_SERVICE_UUID, btobex_handle);
+ dissector_add_uint("btrfcomm.service", BTSDP_BIP_RESPONDER_SERVICE_UUID, btobex_handle);
+ dissector_add_uint("btrfcomm.service", BTSDP_BIP_AUTO_ARCH_SERVICE_UUID, btobex_handle);
+ dissector_add_uint("btrfcomm.service", BTSDP_BIP_REF_OBJ_SERVICE_UUID, btobex_handle);
+ dissector_add_uint("btrfcomm.service", BTSDP_PBAP_PCE_SERVICE_UUID, btobex_handle);
+ dissector_add_uint("btrfcomm.service", BTSDP_PBAP_PSE_SERVICE_UUID, btobex_handle);
+ dissector_add_uint("btrfcomm.service", BTSDP_PBAP_SERVICE_UUID, btobex_handle);
+ dissector_add_uint("btrfcomm.service", BTSDP_MAP_SERVICE_UUID, btobex_handle);
+ dissector_add_uint("btrfcomm.service", BTSDP_MAP_ACCESS_SRV_SERVICE_UUID, btobex_handle);
+ dissector_add_uint("btrfcomm.service", BTSDP_MAP_NOIYFY_SRV_SERVICE_UUID, btobex_handle);
+
+ dissector_add_uint("btl2cap.service", BTSDP_OPP_SERVICE_UUID, btobex_handle);
+ dissector_add_uint("btl2cap.service", BTSDP_FTP_SERVICE_UUID, btobex_handle);
+ dissector_add_uint("btl2cap.service", BTSDP_BPP_SERVICE_UUID, btobex_handle);
+ dissector_add_uint("btl2cap.service", BTSDP_BPP_STATUS_SERVICE_UUID, btobex_handle);
+ dissector_add_uint("btl2cap.service", BTSDP_BIP_SERVICE_UUID, btobex_handle);
+ dissector_add_uint("btl2cap.service", BTSDP_BIP_RESPONDER_SERVICE_UUID, btobex_handle);
+ dissector_add_uint("btl2cap.service", BTSDP_BIP_AUTO_ARCH_SERVICE_UUID, btobex_handle);
+ dissector_add_uint("btl2cap.service", BTSDP_BIP_REF_OBJ_SERVICE_UUID, btobex_handle);
+ dissector_add_uint("btl2cap.service", BTSDP_PBAP_PCE_SERVICE_UUID, btobex_handle);
+ dissector_add_uint("btl2cap.service", BTSDP_PBAP_PSE_SERVICE_UUID, btobex_handle);
+ dissector_add_uint("btl2cap.service", BTSDP_PBAP_SERVICE_UUID, btobex_handle);
+ dissector_add_uint("btl2cap.service", BTSDP_MAP_SERVICE_UUID, btobex_handle);
+ dissector_add_uint("btl2cap.service", BTSDP_MAP_ACCESS_SRV_SERVICE_UUID, btobex_handle);
+ dissector_add_uint("btl2cap.service", BTSDP_MAP_NOIYFY_SRV_SERVICE_UUID, btobex_handle);
+
+ xml_handle = find_dissector("xml");
+ data_handle = find_dissector("data");
}
diff --git a/epan/dissectors/packet-btrfcomm.c b/epan/dissectors/packet-btrfcomm.c
index 0134abb144..1c03cd3251 100644
--- a/epan/dissectors/packet-btrfcomm.c
+++ b/epan/dissectors/packet-btrfcomm.c
@@ -1,5 +1,10 @@
/* packet-btrfcomm.c
* Routines for Bluetooth RFCOMM protocol dissection
+ * and RFCOMM based profile dissection:
+ * - Handsfree Profile (HFP)
+ * - Dial-Up Networking (DUN) Profile
+ * - Serial Port Profile (SPP)
+ *
* Copyright 2002, Wolfgang Hansmann <hansmann@cs.uni-bonn.de>
*
* Refactored for wireshark checkin
@@ -38,6 +43,8 @@
#include <etypes.h>
#include <epan/emem.h>
#include <epan/expert.h>
+#include <epan/tap.h>
+#include "packet-btsdp.h"
#include "packet-btl2cap.h"
#include "packet-btrfcomm.h"
@@ -70,9 +77,15 @@ static int hf_msc_l = -1;
static int hf_fcs = -1;
+static int hf_at_cmd = -1;
+static int hf_dun_at_cmd = -1;
+static int hf_data = -1;
+
/* Initialize the protocol and registered fields */
static int proto_btrfcomm = -1;
-
+static int proto_bthf = -1;
+static int proto_btdun = -1;
+static int proto_btspp = -1;
/* Initialize the subtree pointers */
static gint ett_btrfcomm = -1;
@@ -83,8 +96,15 @@ static gint ett_mcc = -1;
static gint ett_ctrl_pn_ci = -1;
static gint ett_ctrl_pn_v24 = -1;
+static gint ett_bthf = -1;
+static gint ett_btdun = -1;
+static gint ett_btspp = -1;
+
static emem_tree_t *dlci_table;
+/* Initialize dissector table */
+dissector_table_t rfcomm_service_dissector_table;
+
typedef struct _dlci_stream_t {
int len;
int current;
@@ -94,11 +114,12 @@ typedef struct _dlci_stream_t {
} dlci_stream_t;
typedef struct _dlci_state_t {
+ guint32 service;
char do_credit_fc;
- dlci_stream_t direction[2];
} dlci_state_t;
-static dissector_handle_t btobex_handle;
+static dissector_handle_t data_handle;
+static dissector_handle_t ppp_handle;
static const value_string vs_ctl_pn_i[] = {
{0x0, "use UIH Frames"},
@@ -266,12 +287,17 @@ dissect_ctrl_pn(packet_info *pinfo, proto_tree *t, tvbuff_t *tvb, int offset, in
offset++;
if(!pinfo->fd->flags.visited){
- dlci_state=se_tree_lookup32(dlci_table, dlci);
+ guint32 token;
+
+ if( pinfo->p2p_dir == cr_flag )
+ token = dlci | 0x01; /* local service */
+ else
+ token = dlci;
+
+ dlci_state=se_tree_lookup32(dlci_table, token);
if(!dlci_state){
dlci_state=se_alloc0(sizeof(dlci_state_t));
- dlci_state->direction[0].current=-1;
- dlci_state->direction[1].current=-1;
- se_tree_insert32(dlci_table, dlci, dlci_state);
+ se_tree_insert32(dlci_table, token, dlci_state);
}
if(!cl){
@@ -480,7 +506,7 @@ dissect_btrfcomm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
guint8 dlci, cr_flag, ea_flag;
guint8 frame_type, pf_flag;
guint16 frame_len;
- dlci_state_t *dlci_state;
+ dlci_state_t *dlci_state = NULL;
ti = proto_tree_add_item(tree, proto_btrfcomm, tvb, offset, -1, TRUE);
rfcomm_tree = proto_item_add_subtree(ti, ett_btrfcomm);
@@ -493,29 +519,32 @@ dissect_btrfcomm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
/* flags and dlci */
offset=dissect_btrfcomm_Address(tvb, offset, rfcomm_tree, &ea_flag, &cr_flag, &dlci);
-
-
- dlci_state=se_tree_lookup32(dlci_table, dlci);
- if(!dlci_state){
- dlci_state=se_alloc0(sizeof(dlci_state_t));
- dlci_state->direction[0].current=-1;
- dlci_state->direction[1].current=-1;
- se_tree_insert32(dlci_table, dlci, dlci_state);
- }
-
/* pf and frame type */
offset=dissect_btrfcomm_Control(tvb, offset, rfcomm_tree, &pf_flag, &frame_type);
-
-
+ /* payload length */
+ offset=dissect_btrfcomm_PayloadLen(tvb, offset, rfcomm_tree, &frame_len);
+
+ if (dlci && (frame_len || (frame_type == 0xef) || (frame_type == 0x2f) )) {
+ guint32 token;
+
+ if( pinfo->p2p_dir == cr_flag )
+ token = dlci | 0x01; /* local service */
+ else
+ token = dlci;
+
+ dlci_state=se_tree_lookup32(dlci_table, token);
+ if(!dlci_state){
+ dlci_state=se_alloc0(sizeof(dlci_state_t));
+ se_tree_insert32(dlci_table, token, dlci_state);
+ }
+ }
+
if ((check_col(pinfo->cinfo, COL_INFO))){
col_append_fstr(pinfo->cinfo, COL_INFO, "%s DLCI=%d ", val_to_str(frame_type, vs_frame_type_short, "Unknown"), dlci);
+ if(dlci && (frame_type == 0x2f))
+ col_append_fstr(pinfo->cinfo, COL_INFO, "(%s) ", val_to_str(dlci_state->service, vs_service_classes, "Unknown"));
}
-
- /* payload length */
- offset=dissect_btrfcomm_PayloadLen(tvb, offset, rfcomm_tree, &frame_len);
-
-
/* UID frame */
if(frame_type==0xef && dlci && pf_flag) {
col_append_str(pinfo->cinfo, COL_INFO, "UID ");
@@ -570,8 +599,11 @@ dissect_btrfcomm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
proto_item_set_len(mcc_ti, offset-start_offset);
}
- /* dissect everything as OBEX for now */
- if(dlci && frame_len && btobex_handle){
+
+ /* try to find a higher layer dissector that has registered to handle data
+ * for this kind of service, if none is found dissect it as raw "data"
+ */
+ if(dlci&&frame_len){
tvbuff_t *next_tvb;
btl2cap_data_t *l2cap_data;
btrfcomm_data_t rfcomm_data;
@@ -583,7 +615,12 @@ dissect_btrfcomm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
rfcomm_data.chandle = l2cap_data->chandle;
rfcomm_data.cid = l2cap_data->cid;
rfcomm_data.dlci = dlci;
- call_dissector(btobex_handle, next_tvb, pinfo, tree);
+
+ if(!dissector_try_uint(rfcomm_service_dissector_table, dlci_state->service,
+ next_tvb, pinfo, tree)){
+ /* unknown service, let the data dissector handle it */
+ call_dissector(data_handle, next_tvb, pinfo, tree);
+ }
}
proto_tree_add_item(rfcomm_tree, hf_fcs, tvb, fcs_offset, 1, TRUE);
@@ -730,7 +767,7 @@ proto_register_btrfcomm(void)
};
/* Register the protocol name and description */
- proto_btrfcomm = proto_register_protocol("Bluetooth RFCOMM Packet", "RFCOMM", "btrfcomm");
+ proto_btrfcomm = proto_register_protocol("Bluetooth RFCOMM Protocol", "RFCOMM", "btrfcomm");
register_dissector("btrfcomm", dissect_btrfcomm, proto_btrfcomm);
@@ -738,18 +775,241 @@ proto_register_btrfcomm(void)
proto_register_field_array(proto_btrfcomm, hf, array_length(hf));
proto_register_subtree_array(ett, array_length(ett));
+ rfcomm_service_dissector_table = register_dissector_table("btrfcomm.service", "RFCOMM SERVICE", FT_UINT16, BASE_HEX);
+
dlci_table=se_tree_create(EMEM_TREE_TYPE_RED_BLACK, "RFCOMM dlci table");
}
+static int
+btrfcomm_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_RFCOMM_PROTOCOL_UUID ) {
+ guint32 token;
+ dlci_state_t *dlci_state;
+
+ /* rfcomm channel * 2 = dlci */
+ token = (sdp_data->channel<<1) | (sdp_data->flags & BTSDP_LOCAL_SERVICE_FLAG_MASK);
+
+ dlci_state=se_tree_lookup32(dlci_table, token);
+ if(!dlci_state){
+ dlci_state=se_alloc0(sizeof(dlci_state_t));
+ se_tree_insert32(dlci_table, token, dlci_state);
+ }
+ dlci_state->service = sdp_data->service;
+ }
+ return 0;
+}
void
proto_reg_handoff_btrfcomm(void)
{
dissector_handle_t btrfcomm_handle;
- btobex_handle = find_dissector("btobex");
-
- btrfcomm_handle = find_dissector("btrfcomm");
+ btrfcomm_handle = find_dissector("btrfcomm");
dissector_add_uint("btl2cap.psm", BTL2CAP_PSM_RFCOMM, btrfcomm_handle);
+
+ data_handle = find_dissector("data");
+
+ /* tap into the btsdp dissector to look for rfcomm channel infomation that
+ helps us determine the type of rfcomm payload, i.e. which service is
+ using the channels so we know which sub-dissector to call */
+ register_tap_listener("btsdp", NULL, NULL, 0, NULL, btrfcomm_sdp_tap_packet, NULL);
}
+/* Bluetooth Handsfree (HF) profile dissection */
+static void
+dissect_bthf(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ proto_item *ti;
+ proto_tree *st;
+
+ guint length = tvb_length(tvb);
+
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "HANDSFREE");
+
+ ti = proto_tree_add_item(tree, proto_bthf, tvb, 0, -1, FALSE);
+ st = proto_item_add_subtree(ti, ett_bthf);
+
+ col_add_fstr(pinfo->cinfo, COL_INFO, "%s \"%s\"",
+ pinfo->p2p_dir==P2P_DIR_SENT?"Sent":"Rcvd", tvb_format_text(tvb, 0, length));
+
+ proto_tree_add_item(st, hf_at_cmd, tvb, 0, -1, TRUE);
+}
+
+void
+proto_register_bthf(void)
+{
+ static hf_register_info hf[] = {
+ {&hf_at_cmd,
+ {"AT Cmd", "bthf.atcmd",
+ FT_STRING, BASE_NONE, NULL, 0,
+ "AT Command", HFILL}
+ },
+ };
+
+ /* Setup protocol subtree array */
+ static gint *ett[] = {
+ &ett_bthf,
+ };
+
+ proto_bthf = proto_register_protocol("Bluetooth Handsfree Packet", "BTHF", "bthf");
+
+ /* Required function calls to register the header fields and subtrees used */
+ proto_register_field_array(proto_bthf, hf, array_length(hf));
+ proto_register_subtree_array(ett, array_length(ett));
+}
+
+void
+proto_reg_handoff_bthf(void)
+{
+ dissector_handle_t bthf_handle;
+
+ bthf_handle = create_dissector_handle(dissect_bthf, proto_bthf);
+
+ dissector_add_uint("btrfcomm.service", BTSDP_HFP_SERVICE_UUID, bthf_handle);
+ dissector_add_uint("btrfcomm.service", BTSDP_HFP_GW_SERVICE_UUID, bthf_handle);
+}
+
+/* Bluetooth Dial-Up Networking (DUN) profile dissection */
+static void
+dissect_btdun(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ proto_item *ti;
+ proto_tree *st;
+ gboolean is_at_cmd;
+ guint i, length;
+
+ length = tvb_length(tvb);
+
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "DUN");
+
+ ti = proto_tree_add_item(tree, proto_btdun, tvb, 0, -1, FALSE);
+ st = proto_item_add_subtree(ti, ett_btdun);
+
+ is_at_cmd = TRUE;
+ for(i=0;i<length && is_at_cmd;i++) {
+ is_at_cmd = tvb_get_guint8(tvb, i) < 0x7d;
+ }
+
+ if( is_at_cmd) {
+ /* presumably an AT command */
+ col_add_fstr(pinfo->cinfo, COL_INFO, "%s \"%s\"",
+ pinfo->p2p_dir==P2P_DIR_SENT?"Sent":"Rcvd", tvb_format_text(tvb, 0, length));
+
+ proto_tree_add_item(st, hf_dun_at_cmd, tvb, 0, -1, TRUE);
+ }
+ else {
+ /* ... or raw PPP */
+ if( ppp_handle )
+ call_dissector(ppp_handle, tvb, pinfo, tree);
+ else {
+ /* TODO: remove the above 'if' and this 'else-body' when "ppp_raw_hdlc" is available, requires that it is
+ made non-anonymous in ppp dissector to use */
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "PPP");
+ col_add_fstr(pinfo->cinfo, COL_INFO, "%s <PPP frame>", pinfo->p2p_dir==P2P_DIR_SENT?"Sent":"Rcvd");
+
+ call_dissector(data_handle, tvb, pinfo, tree);
+ }
+ }
+}
+
+void
+proto_register_btdun(void)
+{
+ static hf_register_info hf[] = {
+ {&hf_dun_at_cmd,
+ {"AT Cmd", "btdun.atcmd",
+ FT_STRING, BASE_NONE, NULL, 0,
+ "AT Command", HFILL}
+ },
+ };
+
+ /* Setup protocol subtree array */
+ static gint *ett[] = {
+ &ett_btdun,
+ };
+
+ proto_btdun = proto_register_protocol("Bluetooth DUN Packet", "BTDUN", "btdun");
+
+ /* Required function calls to register the header fields and subtrees used */
+ proto_register_field_array(proto_bthf, hf, array_length(hf));
+ proto_register_subtree_array(ett, array_length(ett));
+}
+
+void
+proto_reg_handoff_btdun(void)
+{
+ dissector_handle_t btdun_handle;
+
+ btdun_handle = create_dissector_handle(dissect_btdun, proto_btdun);
+
+ dissector_add_uint("btrfcomm.service", BTSDP_DUN_SERVICE_UUID, btdun_handle);
+
+ ppp_handle = find_dissector("ppp_raw_hdlc");
+}
+
+/* Bluetooth Serial Port profile (SPP) dissection */
+static void
+dissect_btspp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ proto_item *ti;
+ proto_tree *st;
+ gboolean ascii_only;
+ guint i, length = tvb_length(tvb);
+
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, "SPP");
+
+ ti = proto_tree_add_item(tree, proto_btspp, tvb, 0, -1, FALSE);
+ st = proto_item_add_subtree(ti, ett_btspp);
+
+ length = MIN(length,60);
+ ascii_only = TRUE;
+ for(i=0;i<length && ascii_only;i++) {
+ ascii_only = tvb_get_guint8(tvb, i) < 0x80;
+ }
+
+ if(ascii_only) {
+ col_add_fstr(pinfo->cinfo, COL_INFO, "%s \"%s%s\"",
+ pinfo->p2p_dir==P2P_DIR_SENT?"Sent":"Rcvd",
+ tvb_format_text(tvb, 0, length),
+ tvb_length(tvb) > length ? "...":"");
+ }
+
+ proto_tree_add_item(st, hf_data, tvb, 0, -1, TRUE);
+}
+
+void
+proto_register_btspp(void)
+{
+ static hf_register_info hf[] = {
+ {&hf_data,
+ {"Data", "btspp.data",
+ FT_BYTES, BASE_NONE, NULL, 0,
+ NULL, HFILL}},
+ };
+
+ /* Setup protocol subtree array */
+ static gint *ett[] = {
+ &ett_btspp,
+ };
+
+ proto_btspp = proto_register_protocol("Bluetooth SPP Packet", "BTSPP", "btspp");
+
+ /* Required function calls to register the header fields and subtrees used */
+ proto_register_field_array(proto_bthf, hf, array_length(hf));
+ proto_register_subtree_array(ett, array_length(ett));
+}
+
+void
+proto_reg_handoff_btspp(void)
+{
+ dissector_handle_t btspp_handle;
+
+ btspp_handle = create_dissector_handle(dissect_btspp, proto_btspp);
+
+ dissector_add_uint("btrfcomm.service", BTSDP_SPP_SERVICE_UUID, btspp_handle);
+}
+
+
diff --git a/epan/dissectors/packet-btsdp.c b/epan/dissectors/packet-btsdp.c
index 59454a548b..2168dd67bc 100644
--- a/epan/dissectors/packet-btsdp.c
+++ b/epan/dissectors/packet-btsdp.c
@@ -37,7 +37,9 @@
#include <epan/value_string.h>
#include <epan/emem.h>
#include <etypes.h>
-#include "packet-btl2cap.h"
+#include <epan/tap.h>
+#include <epan/dissectors/packet-btsdp.h>
+#include <epan/dissectors/packet-btl2cap.h>
/* Initialize the protocol and registered fields */
static int proto_btsdp = -1;
@@ -58,135 +60,71 @@ static gint ett_btsdp_attribute = -1;
static gint ett_btsdp_service_search_pattern = -1;
static gint ett_btsdp_attribute_idlist = -1;
+static int btsdp_tap = -1;
+
+/* This table maps rfcomm service channels and dynamic l2cap
+ * PSM's to profile service uuids.
+ * The same table is used both for local and remote servers.
+ * For received CIDs we mask the cid with 0x8000 in this table
+ */
+static emem_tree_t *service_table = NULL;
+
static const value_string vs_pduid[] = {
- {0x1, "SDP_ErrorResponse"},
- {0x2, "SDP_ServiceSearchRequest"},
- {0x3, "SDP_ServiceSearchResponse"},
- {0x4, "SDP_ServiceAttributeRequest"},
- {0x5, "SDP_ServiceAttributeResponse"},
- {0x6, "SDP_ServiceSearchAttributeRequest"},
- {0x7, "SDP_ServiceSearchAttributeResponse"},
+ {0x1, "Error Response"},
+ {0x2, "Service Search Request"},
+ {0x3, "Service Search Response"},
+ {0x4, "Service Attribute Request"},
+ {0x5, "Service Attribute Response"},
+ {0x6, "Service Search Attribute Request"},
+ {0x7, "Service Search Attribute Response"},
{0, NULL}
};
static const value_string vs_general_attribute_id[] = {
- {0x0000, "ServiceRecordHandle"},
- {0x0001, "ServiceClassIDList"},
- {0x0002, "ServiceRecordState"},
- {0x0003, "ServiceID"},
- {0x0004, "ProtocolDescriptorList"},
- {0x0005, "BrowseGroupList"},
- {0x0006, "LanguageBaseAttributeIDList"},
- {0x0007, "ServiceinfoTimeToLive"},
- {0x0008, "ServiceAvailability"},
- {0x0009, "BluetoothProfileDescriptorList"},
- {0x000a, "DocumentationURL"},
- {0x000b, "ClientExecutableURL"},
- {0x000c, "IconURL"},
+ {0x0000, "Service Record Handle"},
+ {0x0001, "Service Class ID List"},
+ {0x0002, "Service Record State"},
+ {0x0003, "Service ID"},
+ {0x0004, "Protocol Descriptor List"},
+ {0x0005, "Browse Group List"},
+ {0x0006, "Language Base Attribute ID List"},
+ {0x0007, "Serviceinfo Time To Live"},
+ {0x0008, "Service Availability"},
+ {0x0009, "Bluetooth Profile Descriptor List"},
+ {0x000a, "Documentation URL"},
+ {0x000b, "Client Executable URL"},
+ {0x000c, "Icon URL"},
+ {0x000d, "Additional Protocol Descriptor Lists"},
{0x0100, "Service Name"},
{0x0101, "Service Description"},
- {0x0102, "Service Provider"},
+ {0x0102, "Provider Name"},
+ {0x0200, "GOEP L2CAP PSM/Group Id/IP Subnet"},
+ {0x0201, "Service Database State"},
+ {0x0300, "Service Version"},
+ {0x0301, "Data Exchange Spec/Network/Supported Data Stores List"},
+ {0x0302, "Remote Audio Volume Control/MCAP Supported Features"},
+ {0x0303, "Supported Formats"},
+ {0x0304, "Fax Class 2 Support"},
+ {0x0305, "Audio Feedback Support"},
+ {0x0306, "Network Address"},
+ {0x0307, "WAP Gateway"},
+ {0x0308, "Home Page URL"},
+ {0x0309, "WAP Stack Type"},
+ {0x030a, "Security Description"},
+ {0x030b, "Net Access Type"},
+ {0x030c, "Max Net Accessrate"},
+ {0x030d, "IPv4 Subnet"},
+ {0x030e, "IPv6 Subnet"},
+ {0x0310, "Supported Capabilities"},
+ {0x0311, "Supported Features"},
+ {0x0312, "Supported Functions"},
+ {0x0313, "Total Imaging Data Capacity"},
+ {0x0314, "Supported Repositories"},
+ {0x0315, "MAS Instance ID"},
+ {0x0316, "Supported Message Types"},
{0, NULL}
};
-static const value_string vs_service_classes[] = {
-
- {0x0001, "SDP"},
- {0x0002, "UDP"},
- {0x0003, "RFCOMM"},
- {0x0004, "TCP"},
- {0x0005, "TCS-BIN"},
- {0x0006, "TCS-AT"},
- {0x0008, "OBEX"},
- {0x0009, "IP"},
- {0x000A, "FTP"},
- {0x000C, "HTTP"},
- {0x000E, "WSP"},
- {0x000F, "BNEP"},
- {0x0010, "UPNP"},
- {0x0011, "HIDP"},
- {0x0012, "HardcopyControlChannel"},
- {0x0014, "HardcopyDataChannel"},
- {0x0016, "HardcopyNotification"},
- {0x0017, "AVCTP"},
- {0x0019, "AVDTP"},
- {0x001B, "CMPT"},
- {0x001D, "UDI_C-Plane"},
- {0x001E, "MCAPControlChannel"},
- {0x001F, "MCAPDataChannel"},
- {0x0100, "L2CAP"},
- {0x1000, "ServiceDiscoveryServerServiceClassID"},
- {0x1001, "BrowseGroupDescriptorServiceClassID"},
- {0x1002, "PublicBrowseGroup"},
- {0x1101, "SerialPort"},
- {0x1102, "LANAccessUsingPPP"},
- {0x1103, "DialupNetworking"},
- {0x1104, "IrMCSync"},
- {0x1105, "OBEXObjectPush"},
- {0x1106, "OBEXFileTransfer"},
- {0x1107, "IrMCSyncCommand"},
- {0x1108, "Headset"},
- {0x1109, "CordlessTelephony"},
- {0x110A, "AudioSource"},
- {0x110B, "AudioSink"},
- {0x110C, "A/V_RemoteControlTarget"},
- {0x110D, "AdvancedAudioDistribution"},
- {0x110E, "A/V_RemoteControl"},
- {0x110F, "VideoConferencing"},
- {0x1110, "Intercom"},
- {0x1111, "Fax"},
- {0x1112, "HeadsetAudioGateway"},
- {0x1113, "WAP"},
- {0x1114, "WAP_CLIENT"},
- {0x1115, "PANU"},
- {0x1116, "NAP"},
- {0x1117, "GN"},
- {0x1118, "DirectPrinting"},
- {0x1119, "ReferencePrinting"},
- {0x111A, "Imaging"},
- {0x111B, "ImagingResponder"},
- {0x111C, "ImagingAutomaticArchive"},
- {0x111D, "ImagingReferencedObjects"},
- {0x111E, "Handsfree"},
- {0x111F, "HandsfreeAudioGateway"},
- {0x1120, "DirectPrintingReferenceObjectsService"},
- {0x1121, "ReflectedUI"},
- {0x1122, "BasicPrinting"},
- {0x1123, "PrintingStatus"},
- {0x1124, "HumanInterfaceDeviceService"},
- {0x1125, "HardcopyCableReplacement"},
- {0x1126, "HCR_Print"},
- {0x1127, "HCR_Scan"},
- {0x1128, "Common_ISDN_Access"},
- {0x1129, "VideoConferencingGW"},
- {0x112A, "UDI_MT"},
- {0x112B, "UDI_TA"},
- {0x112C, "Audio/Video"},
- {0x112D, "SIM_Access"},
- {0x112E, "PBAP client"},
- {0x112F, "PBAP server"},
- {0x1130, "PBAP"},
- {0x1200, "PnPInformation"},
- {0x1201, "GenericNetworking"},
- {0x1202, "GenericFileTransfer"},
- {0x1203, "GenericAudio"},
- {0x1204, "GenericTelephony"},
- {0x1205, "UPNP_Service"},
- {0x1206, "UPNP_IP_Service"},
- {0x1300, "ESDP_UPNP_IP_PAN"},
- {0x1301, "ESDP_UPNP_IP_LAP"},
- {0x1302, "ESDP_UPNP_L2CAP"},
- {0x1303, "VideoSource"},
- {0x1304, "VideoSink"},
- {0x1305, "VideoDistribution"},
- {0x1400, "Medical Device Profile"},
- {0x1401, "MDP Source"},
- {0x1402, "MDP Sink"},
- {0, NULL}
-};
-
-
-
static int
get_type_length(tvbuff_t *tvb, int offset, int *length)
{
@@ -262,7 +200,7 @@ get_int_by_size(tvbuff_t *tvb, int off, int size)
static int
-dissect_attribute_id_list(proto_tree *t, tvbuff_t *tvb, int offset)
+dissect_attribute_id_list(proto_tree *t, tvbuff_t *tvb, int offset, packet_info *pinfo)
{
proto_item *ti;
proto_tree *st;
@@ -271,7 +209,7 @@ dissect_attribute_id_list(proto_tree *t, tvbuff_t *tvb, int offset)
const char *att_name;
start_offset=offset;
- ti = proto_tree_add_text(t, tvb, offset, 2, "AttributeIDList");
+ ti = proto_tree_add_text(t, tvb, offset, 2, "Attribute ID List");
st = proto_item_add_subtree(ti, ett_btsdp_attribute_idlist);
offset = get_type_length(tvb, offset, &bytes_to_go);
@@ -287,8 +225,13 @@ dissect_attribute_id_list(proto_tree *t, tvbuff_t *tvb, int offset)
proto_tree_add_text(st, tvb, offset, 3, "%s (0x%04x)", att_name, id);
offset+=3;
bytes_to_go-=3;
- } else if (byte0 == 0x0a) { /* 32 bit attribute range */
+ col_append_fstr(pinfo->cinfo, COL_INFO, " (%s) ", att_name);
+
+ } else if (byte0 == 0x0a) { /* 32 bit attribute range */
+ col_append_fstr(pinfo->cinfo, COL_INFO, " (0x%04x - 0x%04x) ",
+ tvb_get_ntohs(tvb, offset + 1), tvb_get_ntohs(tvb, offset + 3));
+
proto_tree_add_text(st, tvb, offset, 5, "0x%04x - 0x%04x",
tvb_get_ntohs(tvb, offset + 1),
tvb_get_ntohs(tvb, offset + 3));
@@ -311,6 +254,121 @@ dissect_sdp_error_response(proto_tree *t, tvbuff_t *tvb, int offset) {
return offset;
}
+static int
+get_sdp_type(tvbuff_t *tvb, int offset, guint16 id, guint8 *type, guint8 **val, guint32 *service, guint32 *service_val)
+{
+ int size, start_offset, type_size;
+ guint8 byte0;
+ guint8 size_index;
+
+ byte0=tvb_get_guint8(tvb, offset);
+ *type = (byte0>>3) & 0x1f;
+ size_index = byte0 & 0x07;
+
+ start_offset=offset;
+ offset = get_type_length(tvb, offset, &size);
+ type_size = offset - start_offset + size;
+
+ switch (*type) {
+ case 0: { /* null */
+ *val = NULL;
+ break;
+ }
+ case 1: /* unsigned integer */
+ case 2: /* signed integer */
+ case 3: { /* uuid */
+ *val = ep_alloc(size);
+
+ if (size == 1) {
+ *((guint8 *) *val) = tvb_get_guint8(tvb, offset);
+ }
+ else if (size == 2) {
+ *((guint16 *) *val) = tvb_get_ntohs(tvb, offset);
+ }
+ else if (size == 4) {
+ *((guint32 *) *val) = tvb_get_ntohl(tvb, offset);
+ }
+ else if (size == 8) {
+ *((guint64 *) *val) = tvb_get_ntoh64(tvb, offset);
+ }
+ else if (size == 16) {
+ /* store the short UUID part of the 128-bit base UUID */
+ *((guint32 *) *val) = tvb_get_ntohl(tvb, offset);
+ }
+ break;
+ }
+ case 8: /* fall through */
+ case 4: {
+ *val = tvb_bytes_to_str(tvb, offset, size);
+ break;
+ }
+ case 5: {
+ *val = ep_alloc(sizeof(type_size));
+ *((guint8 *) *val) = tvb_get_guint8(tvb, offset);
+ break;
+ }
+ case 6: /* Data Element sequence */
+ case 7: /* Data Element alternative */ {
+ gboolean flag = FALSE;
+ int bytes_to_go = size;
+ int len;
+ guint32 value = 0;
+
+ while(bytes_to_go > 0) {
+ size = get_sdp_type(tvb, offset, id, type, val, service, service_val);
+ if (size < 1 || *val == NULL) {
+ break;
+ }
+
+ get_type_length(tvb, offset, &len);
+ offset += size;
+ bytes_to_go -= size;
+
+ if( len == 1 ) {
+ value = *((guint8 *) *val);
+ }
+ else if( len == 2 ) {
+ value = *((guint16 *) *val);
+ }
+ else if ( len == 4 ) {
+ value = *((guint32 *) *val);
+ }
+ else if ( len == 16 ) {
+ value = *((guint32 *) *val);
+ }
+
+ /* pick special values of interest */
+ /* protocol or additional protocol list with UUID values for L2CAP or RFCOMM */
+ if ( ((id == 4) || (id == 0xd)) && (*type == 3) && ((value == 0x100) || (value == 0x0003)) ) {
+ *service = value;
+ flag = TRUE;
+ }
+ /* profile descriptor list with UUID */
+ else if ( (id == 9) && (*type == 3) ) {
+ *service = value;
+ flag = TRUE;
+ }
+ /* service class id list with UUID */
+ else if ( (id == 1) && (*type == 3) ) {
+ *service = value;
+ flag = TRUE;
+ }
+ /* unsigned int found after value of interest */
+ else if ( (flag == TRUE) && *type == 1) {
+ *service_val = value;
+ flag = FALSE;
+ }
+ else {
+ flag = FALSE;
+ }
+ }
+ break;
+ }
+ }
+
+ return type_size;
+}
+
static int
dissect_sdp_type(proto_tree *t, tvbuff_t *tvb, int offset, char **attr_val)
@@ -361,25 +419,21 @@ dissect_sdp_type(proto_tree *t, tvbuff_t *tvb, int offset, char **attr_val)
break;
}
case 3: {
+ guint32 id;
+ const char *uuid_name;
char *ptr = tvb_bytes_to_str(tvb, offset, size);
if(size == 2){
-
- guint16 id = tvb_get_ntohs(tvb, offset);
- const char *uuid_name = val_to_str(id, vs_service_classes, "Unknown");
-
- proto_tree_add_text(t, tvb, start_offset, type_size,
- "%s(0x%s) ", uuid_name, ptr);
- if(strpos<MAX_SDP_LEN){
- strpos+=g_snprintf(str+strpos, MAX_SDP_LEN-strpos, "UUID:%s (0x%s) ", uuid_name, ptr);
- }
+ id = tvb_get_ntohs(tvb, offset);
} else {
+ id = tvb_get_ntohl(tvb, offset);
+ }
+ uuid_name = val_to_str(id, vs_service_classes, "Unknown service");
- proto_tree_add_text(t, tvb, start_offset, type_size,
- "UUID 0x%s ", ptr);
- if(strpos<MAX_SDP_LEN){
- strpos+=g_snprintf(str+strpos, MAX_SDP_LEN-strpos, "0x%s ", ptr);
- }
+ proto_tree_add_text(t, tvb, start_offset, type_size, "%s (0x%s) ", uuid_name, ptr);
+
+ if(strpos<MAX_SDP_LEN){
+ strpos+=g_snprintf(str+strpos, MAX_SDP_LEN-strpos, ": %s", uuid_name);
}
break;
}
@@ -458,9 +512,8 @@ dissect_sdp_type(proto_tree *t, tvbuff_t *tvb, int offset, char **attr_val)
static int
-dissect_sdp_service_attribute(proto_tree *tree, tvbuff_t *tvb, int offset)
+dissect_sdp_service_attribute(proto_tree *tree, tvbuff_t *tvb, int offset, packet_info *pinfo, guint32 token)
{
-
proto_tree *st, *ti_sa, *ti_av;
int size;
const char *att_name;
@@ -474,15 +527,60 @@ dissect_sdp_service_attribute(proto_tree *tree, tvbuff_t *tvb, int offset)
"Service Attribute: id = %s (0x%x)", att_name, id);
st = proto_item_add_subtree(ti_sa, ett_btsdp_attribute);
-
proto_tree_add_text(st, tvb, offset, 3, "Attribute ID: %s (0x%x)", att_name, id);
ti_av = proto_tree_add_text(st, tvb, offset + 3, -1, "Attribute Value");
st = proto_item_add_subtree(ti_av, ett_btsdp_attribute);
-
size = dissect_sdp_type(st, tvb, offset + 3, &attr_val);
proto_item_append_text(ti_sa, ", value = %s", attr_val);
+ if( pinfo->fd->flags.visited ==0) {
+ guint8 *val, type;
+ guint32 service, service_val;
+ btsdp_data_t *service_item;
+
+ service_item=se_tree_lookup32(service_table, token);
+
+ if(service_item != NULL) {
+ if(id == 4 || (id == 9) || (id == 0xd)) { /* profile/protocol discriptor list/additional protocol list */
+ get_sdp_type(tvb, offset+ 3, id, &type, &val, &service, &service_val);
+
+ if( (service == BTSDP_L2CAP_PROTOCOL_UUID)
+ || (service == BTSDP_RFCOMM_PROTOCOL_UUID) ) {
+ service_item->channel = service_val;
+ service_item->protocol = (guint16) service;
+ }
+ else {
+ service_item->service = service;
+ }
+
+ service_item->flags = 0;
+ if(id == 0xd) {
+ service_item->flags = BTSDP_SECONDARY_CHANNEL_FLAG_MASK;
+ }
+ }
+ else if( id == 1) { /* service class id list */
+ get_sdp_type(tvb, offset+ 3, id, &type, &val, &service, &service_val);
+ service_item->service = service;
+ }
+ else if(id == 0x200) { /* GOEP L2CAP PSM? */
+ guint16 *psm;
+
+ get_sdp_type(tvb, offset+ 3, id, &type, (guint8 **) &psm, &service, &service_val);
+
+ if( (type == 1) && (*psm > 0x1000) && (*psm & 0x1) ) {
+ service_item->channel = *psm;
+ service_item->protocol = BTSDP_L2CAP_PROTOCOL_UUID;
+ service_item->flags = 0;
+ }
+ }
+
+ if( service_item->service != 0 && service_item->channel != 0 ) {
+ service_item->flags |= token >>15; /* set flag when local service */
+ tap_queue_packet(btsdp_tap, NULL, (void *) service_item);
+ }
+ }
+ }
proto_item_set_len(ti_sa, size + 3);
proto_item_set_len(ti_av, size);
@@ -492,7 +590,7 @@ dissect_sdp_service_attribute(proto_tree *tree, tvbuff_t *tvb, int offset)
static int
-dissect_sdp_service_attribute_list(proto_tree *tree, tvbuff_t *tvb, int offset)
+dissect_sdp_service_attribute_list(proto_tree *tree, tvbuff_t *tvb, int offset, packet_info *pinfo, guint32 token)
{
proto_item *ti;
proto_tree *st;
@@ -500,7 +598,7 @@ dissect_sdp_service_attribute_list(proto_tree *tree, tvbuff_t *tvb, int offset)
offset = get_type_length(tvb, offset, &len);
- ti = proto_tree_add_text(tree, tvb, start_offset, -1, "AttributeList");
+ ti = proto_tree_add_text(tree, tvb, start_offset, -1, "Attribute List");
st = proto_item_add_subtree(ti, ett_btsdp_attribute);
if(!len){
@@ -508,7 +606,7 @@ dissect_sdp_service_attribute_list(proto_tree *tree, tvbuff_t *tvb, int offset)
}
while (offset - start_offset < len) {
- offset = dissect_sdp_service_attribute(st, tvb, offset);
+ offset = dissect_sdp_service_attribute(st, tvb, offset, pinfo, token);
}
proto_item_set_len(ti, offset - start_offset);
@@ -518,7 +616,7 @@ dissect_sdp_service_attribute_list(proto_tree *tree, tvbuff_t *tvb, int offset)
static int
-dissect_sdp_service_attribute_list_array(proto_tree *tree, tvbuff_t *tvb, int offset)
+dissect_sdp_service_attribute_list_array(proto_tree *tree, tvbuff_t *tvb, int offset, packet_info *pinfo, guint32 token)
{
proto_item *ti;
proto_tree *st;
@@ -526,12 +624,12 @@ dissect_sdp_service_attribute_list_array(proto_tree *tree, tvbuff_t *tvb, int of
start_offset=offset;
offset = get_type_length(tvb, offset, &len);
- ti = proto_tree_add_text(tree, tvb, start_offset, offset-start_offset+len, "AttributeLists");
+ ti = proto_tree_add_text(tree, tvb, start_offset, offset-start_offset+len, "Attribute Lists");
st = proto_item_add_subtree(ti, ett_btsdp_attribute);
start_offset=offset;
while(offset-start_offset < len) {
- offset = dissect_sdp_service_attribute_list(st, tvb, offset);
+ offset = dissect_sdp_service_attribute_list(st, tvb, offset, pinfo, token);
}
return offset;
@@ -540,38 +638,50 @@ dissect_sdp_service_attribute_list_array(proto_tree *tree, tvbuff_t *tvb, int of
static int
-dissect_sdp_service_search_attribute_response(proto_tree *tree, tvbuff_t *tvb, int offset)
+dissect_sdp_service_search_attribute_response(proto_tree *tree, tvbuff_t *tvb, int offset, packet_info *pinfo, guint32 token)
{
-
proto_tree_add_item(tree, hf_ssares_al_bytecount, tvb, offset, 2, FALSE);
offset += 2;
- offset += dissect_sdp_service_attribute_list_array(tree, tvb, offset);
+ offset += dissect_sdp_service_attribute_list_array(tree, tvb, offset, pinfo, token);
return offset;
}
static int
-dissect_sdp_service_search_attribute_request(proto_tree *t, tvbuff_t *tvb, int offset)
+dissect_sdp_service_search_attribute_request(proto_tree *t, tvbuff_t *tvb, int offset, packet_info *pinfo, guint32 token)
{
proto_tree *st;
proto_item *ti;
int start_offset;
int size, bytes_to_go;
char *str;
+ btsdp_data_t *service_item = NULL;
start_offset = offset;
- ti = proto_tree_add_text(t, tvb, offset, 2, "ServiceSearchPattern");
+ ti = proto_tree_add_text(t, tvb, offset, 2, "Service Search Pattern");
st = proto_item_add_subtree(ti, ett_btsdp_attribute);
offset = get_type_length(tvb, offset, &bytes_to_go);
proto_item_set_len(ti, offset - start_offset + bytes_to_go);
-
while(bytes_to_go>0) {
+ if (pinfo->fd->flags.visited == 0) {
+ service_item=se_tree_lookup32(service_table, token);
+
+ if(service_item == NULL) {
+ service_item=se_alloc(sizeof(btsdp_data_t));
+ se_tree_insert32(service_table, token, service_item);
+ }
+ service_item->channel = 0;
+ service_item->service = 0;
+ }
+
size = dissect_sdp_type(st, tvb, offset, &str);
proto_item_append_text(st, " %s", str);
+ col_append_fstr(pinfo->cinfo, COL_INFO, "%s", str);
+
if (size < 1) {
break;
}
@@ -580,27 +690,26 @@ dissect_sdp_service_search_attribute_request(proto_tree *t, tvbuff_t *tvb, int o
}
/* dissect maximum attribute byte count */
- proto_tree_add_text(t, tvb, offset, 2, "MaximumAttributeByteCount: %d", tvb_get_ntohs(tvb, offset));
+ proto_tree_add_text(t, tvb, offset, 2, "Maximum Attribute Byte Count: %d", tvb_get_ntohs(tvb, offset));
offset+=2;
+ offset += dissect_attribute_id_list(t, tvb, offset, pinfo);
- offset += dissect_attribute_id_list(t, tvb, offset);
-
- proto_tree_add_text(t, tvb, offset, -1, "ContinuationState");
+ proto_tree_add_text(t, tvb, offset, -1, "Continuation State");
return offset;
}
static int
-dissect_sdp_service_attribute_response(proto_tree *t, tvbuff_t *tvb, int offset)
+dissect_sdp_service_attribute_response(proto_tree *t, tvbuff_t *tvb, int offset, packet_info *pinfo, guint32 token)
{
- proto_tree_add_text(t, tvb, offset, 2, "AttributeListByteCount: %d",
+ proto_tree_add_text(t, tvb, offset, 2, "Attribute List Byte Count: %d",
tvb_get_ntohs(tvb, offset));
offset+=2;
- offset = dissect_sdp_service_attribute_list(t, tvb, offset);
+ offset = dissect_sdp_service_attribute_list(t, tvb, offset, pinfo, token);
- proto_tree_add_text(t, tvb, offset, -1, "ContinuationState");
+ proto_tree_add_text(t, tvb, offset, -1, "Continuation State");
offset+=tvb_length_remaining(tvb, offset);
return offset;
@@ -608,33 +717,34 @@ dissect_sdp_service_attribute_response(proto_tree *t, tvbuff_t *tvb, int offset)
static int
-dissect_sdp_service_attribute_request(proto_tree *t, tvbuff_t *tvb, int offset)
+dissect_sdp_service_attribute_request(proto_tree *t, tvbuff_t *tvb, int offset, packet_info *pinfo)
{
- proto_tree_add_text(t, tvb, offset, 4, "ServiceRecordHandle: 0x%x",
+ proto_tree_add_text(t, tvb, offset, 4, "Service Record Handle: 0x%x",
tvb_get_ntohl(tvb, offset));
offset+=4;
- proto_tree_add_text(t, tvb, offset, 2, "MaximumAttributeByteCount: %d",
+ proto_tree_add_text(t, tvb, offset, 2, "Maximum Attribute Byte Count: %d",
tvb_get_ntohs(tvb, offset));
offset+=2;
- offset += dissect_attribute_id_list(t, tvb, offset);
+ offset += dissect_attribute_id_list(t, tvb, offset, pinfo);
- proto_tree_add_text(t, tvb, offset, -1, "ContinuationState");
+ proto_tree_add_text(t, tvb, offset, -1, "Continuation State");
offset+=tvb_length_remaining(tvb, offset);
return offset;
}
static int
-dissect_sdp_service_search_request(proto_tree *t, tvbuff_t *tvb, int offset)
+dissect_sdp_service_search_request(proto_tree *t, tvbuff_t *tvb, int offset, packet_info *pinfo, guint32 token)
{
- int start_offset, bytes_to_go, size;
+ int start_offset, bytes_to_go, size;
proto_item *ti;
proto_tree *st;
start_offset=offset;
- ti = proto_tree_add_text(t, tvb, offset, 2, "ServiceSearchPattern");
+
+ ti = proto_tree_add_text(t, tvb, offset, 2, "Service Search Pattern");
st = proto_item_add_subtree(ti, ett_btsdp_service_search_pattern);
offset = get_type_length(tvb, offset, &bytes_to_go);
@@ -642,8 +752,33 @@ dissect_sdp_service_search_request(proto_tree *t, tvbuff_t *tvb, int offset)
while(bytes_to_go>0){
char *str;
+ btsdp_data_t *service_item = NULL;
+
+ if (pinfo->fd->flags.visited == 0) {
+ guint32 service, service_val;
+ guint8 type, *val = NULL;
+
+ service_item=se_tree_lookup32(service_table, token);
+
+ if(service_item == NULL) {
+ service_item=se_alloc(sizeof(btsdp_data_t));
+ se_tree_insert32(service_table, token, service_item);
+ }
+ service_item->channel = 0;
+ service_item->service = 0;
+
+ get_sdp_type(tvb, offset, 4, &type, &val, &service, &service_val);
+
+ if( type==3 && val != NULL)
+ service_item->service = *((guint32 *) val);
+ }
+
size = dissect_sdp_type(st, tvb, offset, &str);
+
proto_item_append_text(st, " %s", str);
+
+ col_append_fstr(pinfo->cinfo, COL_INFO, "%s", str);
+
if (size < 1) {
break;
}
@@ -652,12 +787,11 @@ dissect_sdp_service_search_request(proto_tree *t, tvbuff_t *tvb, int offset)
}
/* dissect maximum service record count */
-
- proto_tree_add_text(t, tvb, offset, 2, "MaximumServiceRecordCount: %d",
+ proto_tree_add_text(t, tvb, offset, 2, "Maximum Service Record Count: %d",
tvb_get_ntohs(tvb, offset));
offset+=2;
- proto_tree_add_text(t, tvb, offset, -1, "ContinuationState");
+ proto_tree_add_text(t, tvb, offset, -1, "Continuation State");
offset+=tvb_length_remaining(tvb, offset);
return offset;
}
@@ -678,7 +812,7 @@ dissect_sdp_service_search_response(proto_tree *t, tvbuff_t *tvb, int offset)
offset+=2;
ti = proto_tree_add_text(t, tvb, offset,
- curr_count * 4, "ServiceRecordHandleList");
+ curr_count * 4, "Service Record Handle List");
st = proto_item_add_subtree(ti, ett_btsdp_ssr);
while(curr_count>0){
@@ -687,7 +821,7 @@ dissect_sdp_service_search_response(proto_tree *t, tvbuff_t *tvb, int offset)
curr_count--;
}
- proto_tree_add_text(t, tvb, offset, -1, "ContinuationState");
+ proto_tree_add_text(t, tvb, offset, -1, "Continuation State");
offset+=tvb_length_remaining(tvb, offset);
return offset;
@@ -700,7 +834,8 @@ dissect_btsdp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
proto_item *ti;
proto_tree *st;
guint8 pdu;
- guint16 plen;
+ guint16 tid, plen, acl_handle;
+ guint32 token;
const char *pdu_name;
int offset=0;
@@ -720,6 +855,7 @@ dissect_btsdp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
offset++;
/* tid */
+ tid = tvb_get_ntohs(tvb, offset);
proto_tree_add_item(st, hf_tid, tvb, offset, 2, FALSE);
offset+=2;
@@ -728,32 +864,37 @@ dissect_btsdp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
proto_tree_add_item(st, hf_plen, tvb, offset, 2, FALSE);
offset+=2;
+ acl_handle = ((btl2cap_data_t *) pinfo->private_data)->chandle;
+ if( pdu & 0x01)
+ token = acl_handle | ((pinfo->p2p_dir != P2P_DIR_RECV)?0x8000:0x0000);
+ else
+ token = acl_handle | ((pinfo->p2p_dir == P2P_DIR_RECV)?0x8000:0x0000);
+
switch(pdu) {
case 0x1:
offset=dissect_sdp_error_response(st, tvb, offset);
break;
case 0x2:
- offset=dissect_sdp_service_search_request(st, tvb, offset);
+ offset=dissect_sdp_service_search_request(st, tvb, offset, pinfo, token);
break;
case 0x3:
offset=dissect_sdp_service_search_response(st, tvb, offset);
break;
case 0x4:
- offset=dissect_sdp_service_attribute_request(st, tvb, offset);
+ offset=dissect_sdp_service_attribute_request(st, tvb, offset, pinfo);
break;
case 0x5:
- offset=dissect_sdp_service_attribute_response(st, tvb, offset);
+ offset=dissect_sdp_service_attribute_response(st, tvb, offset, pinfo, token);
break;
case 0x6:
- offset=dissect_sdp_service_search_attribute_request(st, tvb, offset);
+ offset=dissect_sdp_service_search_attribute_request(st, tvb, offset, pinfo, token);
break;
case 07:
- offset=dissect_sdp_service_search_attribute_response(st, tvb, offset);
+ offset=dissect_sdp_service_search_attribute_response(st, tvb, offset, pinfo, token);
break;
}
}
-
void
proto_register_btsdp(void)
{
@@ -764,34 +905,34 @@ proto_register_btsdp(void)
"PDU type", HFILL}
},
{&hf_tid,
- {"TransactionID", "btsdp.tid",
+ {"Transaction Id", "btsdp.tid",
FT_UINT16, BASE_HEX, NULL, 0,
- "Transaction ID", HFILL}
+ NULL, HFILL}
},
{&hf_plen,
- {"ParameterLength", "btsdp.len",
+ {"Parameter Length", "btsdp.len",
FT_UINT16, BASE_DEC, NULL, 0,
NULL, HFILL}
},
{&hf_error_code,
- {"ErrorCode", "btsdp.error_code",
+ {"Error Code", "btsdp.error_code",
FT_UINT16, BASE_HEX, NULL, 0,
- "Error Code", HFILL}
+ NULL, HFILL}
},
{&hf_ssr_total_count,
- {"TotalServiceRecordCount", "btsdp.ssr.total_count",
+ {"Total Service Record Count", "btsdp.ssr.total_count",
FT_UINT16, BASE_DEC, NULL, 0,
"Total count of service records", HFILL}
},
{&hf_ssr_current_count,
- {"CurrentServiceRecordCount", "btsdp.ssr.current_count",
+ {"Current Service Record Count", "btsdp.ssr.current_count",
FT_UINT16, BASE_DEC, NULL, 0,
- "count of service records in this message", HFILL}
+ "Count of service records in this message", HFILL}
},
{&hf_ssares_al_bytecount,
- {"AttributeListsByteCount", "btsdp.ssares.byte_count",
+ {"Attribute Lists Byte Count", "btsdp.ssares.byte_count",
FT_UINT16, BASE_DEC, NULL, 0,
- "count of bytes in attribute list response", HFILL}
+ "Count of bytes in attribute list response", HFILL}
}
};
@@ -806,13 +947,17 @@ proto_register_btsdp(void)
&ett_btsdp_attribute_idlist
};
- proto_btsdp = proto_register_protocol("Bluetooth SDP", "BTSDP", "btsdp");
+ proto_btsdp = proto_register_protocol("Bluetooth SDP Protocol", "BTSDP", "btsdp");
register_dissector("btsdp", dissect_btsdp, proto_btsdp);
+ btsdp_tap = register_tap("btsdp");
+
/* Required function calls to register the header fields and subtrees used */
proto_register_field_array(proto_btsdp, hf, array_length(hf));
proto_register_subtree_array(ett, array_length(ett));
+
+ service_table=se_tree_create(EMEM_TREE_TYPE_RED_BLACK, "mapping of rfcomm channel/l2cap PSM to service uuid");
}
@@ -824,3 +969,4 @@ proto_reg_handoff_btsdp(void)
btsdp_handle = find_dissector("btsdp");
dissector_add_uint("btl2cap.psm", BTL2CAP_PSM_SDP, btsdp_handle);
}
+