Bluetooth: Fix wrong recognized RFCOMM services
It seems that RFCOMM service can be dynamically changed while connection is still alive. In other words: host can connect to remote device and set one RFCOMM service (remote service), but later remote device can change service to one of host service without any disconnection. This patch add support for this case. Also improve searching for useful UUID service through SDP. Change-Id: I9e03b9b965d6b0d9761b4a451cdeb4a1a33ca017 Reviewed-on: https://code.wireshark.org/review/808 Reviewed-by: Anders Broman <a.broman58@gmail.com>
This commit is contained in:
parent
ab42220b65
commit
a99a0360c4
|
@ -128,6 +128,13 @@ static dissector_handle_t btgnss_handle;
|
|||
static dissector_table_t rfcomm_service_dissector_table;
|
||||
static dissector_table_t rfcomm_channel_dissector_table;
|
||||
|
||||
static wmem_tree_t *service_directions = NULL;
|
||||
|
||||
typedef struct {
|
||||
guint32 direction;
|
||||
guint32 end_in;
|
||||
} service_direction_t;
|
||||
|
||||
typedef struct {
|
||||
guint channel;
|
||||
gchar* payload_proto_name;
|
||||
|
@ -204,6 +211,8 @@ static const value_string vs_frame_type_short[] = {
|
|||
{0, NULL}
|
||||
};
|
||||
|
||||
#define FRAME_TYPE_SABM 0x2F
|
||||
#define FRAME_TYPE_UIH 0xEF
|
||||
|
||||
static const value_string vs_ctl[] = {
|
||||
/* masked 0xfc */
|
||||
|
@ -616,22 +625,73 @@ dissect_btrfcomm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data
|
|||
/* payload length */
|
||||
offset = dissect_btrfcomm_payload_length(tvb, offset, rfcomm_tree, &frame_len);
|
||||
|
||||
if (dlci && (frame_len || (frame_type == 0xef) || (frame_type == 0x2f))) {
|
||||
wmem_tree_key_t key[10];
|
||||
guint32 k_interface_id;
|
||||
guint32 k_adapter_id;
|
||||
guint32 k_sdp_psm;
|
||||
guint32 k_direction;
|
||||
guint32 k_bd_addr_oui;
|
||||
guint32 k_bd_addr_id;
|
||||
guint32 k_service_type;
|
||||
guint32 k_service_channel;
|
||||
guint32 k_frame_number;
|
||||
if (dlci && (frame_len || (frame_type == FRAME_TYPE_UIH) || (frame_type == FRAME_TYPE_SABM))) {
|
||||
wmem_tree_key_t key[10];
|
||||
guint32 k_interface_id;
|
||||
guint32 k_adapter_id;
|
||||
guint32 k_psm;
|
||||
guint32 k_direction;
|
||||
guint32 k_bd_addr_oui;
|
||||
guint32 k_bd_addr_id;
|
||||
guint32 k_service_type;
|
||||
guint32 k_frame_number;
|
||||
guint32 k_chandle;
|
||||
guint32 k_channel;
|
||||
service_direction_t *service_direction;
|
||||
wmem_tree_t *subtree;
|
||||
|
||||
k_interface_id = l2cap_data->interface_id;
|
||||
k_adapter_id = l2cap_data->adapter_id;
|
||||
k_sdp_psm = SDP_PSM_DEFAULT;
|
||||
k_direction = (l2cap_data->is_local_psm) ? P2P_DIR_SENT : P2P_DIR_RECV;
|
||||
k_chandle = l2cap_data->chandle;
|
||||
k_psm = l2cap_data->psm;
|
||||
k_channel = dlci >> 1;
|
||||
k_frame_number = pinfo->fd->num;
|
||||
|
||||
key[0].length = 1;
|
||||
key[0].key = &k_interface_id;
|
||||
key[1].length = 1;
|
||||
key[1].key = &k_adapter_id;
|
||||
key[2].length = 1;
|
||||
key[2].key = &k_chandle;
|
||||
key[3].length = 1;
|
||||
key[3].key = &k_psm;
|
||||
key[4].length = 1;
|
||||
key[4].key = &k_channel;
|
||||
|
||||
if (!pinfo->fd->flags.visited && frame_type == FRAME_TYPE_SABM) {
|
||||
key[5].length = 0;
|
||||
key[5].key = NULL;
|
||||
|
||||
subtree = (wmem_tree_t *) wmem_tree_lookup32_array(service_directions, key);
|
||||
service_direction = (subtree) ? (service_direction_t *) wmem_tree_lookup32_le(subtree, k_frame_number) : NULL;
|
||||
if (service_direction && service_direction->end_in == G_MAXUINT32) {
|
||||
service_direction->end_in = k_frame_number;
|
||||
}
|
||||
|
||||
key[5].length = 1;
|
||||
key[5].key = &k_frame_number;
|
||||
key[6].length = 0;
|
||||
key[6].key = NULL;
|
||||
|
||||
service_direction = wmem_new(wmem_file_scope(), service_direction_t);
|
||||
service_direction->direction = (pinfo->p2p_dir == P2P_DIR_RECV) ? P2P_DIR_SENT : P2P_DIR_RECV;
|
||||
service_direction->end_in = G_MAXUINT32;
|
||||
|
||||
wmem_tree_insert32_array(service_directions, key, service_direction);
|
||||
}
|
||||
|
||||
key[5].length = 0;
|
||||
key[5].key = NULL;
|
||||
|
||||
subtree = (wmem_tree_t *) wmem_tree_lookup32_array(service_directions, key);
|
||||
service_direction = (subtree) ? (service_direction_t *) wmem_tree_lookup32_le(subtree, k_frame_number) : NULL;
|
||||
if (service_direction && service_direction->end_in > k_frame_number) {
|
||||
k_direction = service_direction->direction;
|
||||
} else {
|
||||
k_direction = (l2cap_data->is_local_psm) ? P2P_DIR_SENT : P2P_DIR_RECV;
|
||||
}
|
||||
|
||||
k_psm = SDP_PSM_DEFAULT;
|
||||
if (k_direction == P2P_DIR_RECV) {
|
||||
k_bd_addr_oui = l2cap_data->remote_bd_addr_oui;
|
||||
k_bd_addr_id = l2cap_data->remote_bd_addr_id;
|
||||
|
@ -640,15 +700,9 @@ dissect_btrfcomm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data
|
|||
k_bd_addr_id = 0;
|
||||
}
|
||||
k_service_type = BTSDP_RFCOMM_PROTOCOL_UUID;
|
||||
k_service_channel = dlci >> 1;
|
||||
k_frame_number = pinfo->fd->num;
|
||||
|
||||
key[0].length = 1;
|
||||
key[0].key = &k_interface_id;
|
||||
key[1].length = 1;
|
||||
key[1].key = &k_adapter_id;
|
||||
key[2].length = 1;
|
||||
key[2].key = &k_sdp_psm;
|
||||
key[2].key = &k_psm;
|
||||
key[3].length = 1;
|
||||
key[3].key = &k_direction;
|
||||
key[4].length = 1;
|
||||
|
@ -658,7 +712,7 @@ dissect_btrfcomm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data
|
|||
key[6].length = 1;
|
||||
key[6].key = &k_service_type;
|
||||
key[7].length = 1;
|
||||
key[7].key = &k_service_channel;
|
||||
key[7].key = &k_channel;
|
||||
key[8].length = 1;
|
||||
key[8].key = &k_frame_number;
|
||||
key[9].length = 0;
|
||||
|
@ -685,12 +739,12 @@ dissect_btrfcomm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data
|
|||
|
||||
col_append_fstr(pinfo->cinfo, COL_INFO, "%s Channel=%u ",
|
||||
val_to_str_const(frame_type, vs_frame_type_short, "Unknown"), dlci >> 1);
|
||||
if (dlci && (frame_type == 0x2f))
|
||||
if (dlci && (frame_type == FRAME_TYPE_SABM))
|
||||
col_append_fstr(pinfo->cinfo, COL_INFO, "(%s) ",
|
||||
val_to_str_ext_const(service_info->uuid.bt_uuid, &bt_sig_uuid_vals_ext, "Unknown"));
|
||||
|
||||
/* UID frame */
|
||||
if ((frame_type == 0xef) && dlci && pf_flag) {
|
||||
if ((frame_type == FRAME_TYPE_UIH) && dlci && pf_flag) {
|
||||
col_append_str(pinfo->cinfo, COL_INFO, "UID ");
|
||||
|
||||
/* add credit based flow control byte */
|
||||
|
@ -1072,6 +1126,8 @@ proto_register_btrfcomm(void)
|
|||
expert_btrfcomm = expert_register_protocol(proto_btrfcomm);
|
||||
expert_register_field_array(expert_btrfcomm, ei, array_length(ei));
|
||||
|
||||
service_directions = wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
|
||||
|
||||
rfcomm_service_dissector_table = register_dissector_table("btrfcomm.service", "BT RFCOMM Service", FT_UINT16, BASE_HEX);
|
||||
rfcomm_channel_dissector_table = register_dissector_table("btrfcomm.channel", "BT RFCOMM Channel", FT_UINT16, BASE_DEC);
|
||||
|
||||
|
|
|
@ -347,6 +347,9 @@ static expert_field ei_data_element_value_large = EI_INIT;
|
|||
|
||||
static dissector_handle_t btsdp_handle;
|
||||
|
||||
static dissector_table_t btrfcomm_service_table;
|
||||
static dissector_table_t btl2cap_service_table;
|
||||
|
||||
static wmem_tree_t *tid_requests = NULL;
|
||||
static wmem_tree_t *continuation_states = NULL;
|
||||
static wmem_tree_t *record_handle_services = NULL;
|
||||
|
@ -858,16 +861,27 @@ service_info_t* btsdp_get_service_info(wmem_tree_key_t* key)
|
|||
}
|
||||
|
||||
static uuid_t
|
||||
get_most_specified_uuid(wmem_array_t *uuid_array)
|
||||
get_specified_uuid(wmem_array_t *uuid_array)
|
||||
{
|
||||
uuid_t uuid;
|
||||
|
||||
/* TODO: For now try to use first (most specified) UUID, this may sometimes fail */
|
||||
/* Try to find UUID that is already use in RFCOMM or L2CAP, otherwise try to
|
||||
return last one (most generic).
|
||||
NOTE: UUIDs in array are from (most specified) to (most generic) */
|
||||
if (uuid_array) {
|
||||
guint32 i_uuid;
|
||||
guint32 size;
|
||||
uuid_t *p_uuid = NULL;
|
||||
|
||||
if (wmem_array_get_count(uuid_array) > 0)
|
||||
p_uuid = (uuid_t *) wmem_array_index(uuid_array, 0);
|
||||
size = wmem_array_get_count(uuid_array);
|
||||
|
||||
for (i_uuid = 0; i_uuid < size; i_uuid += 1) {
|
||||
p_uuid = (uuid_t *) wmem_array_index(uuid_array, i_uuid);
|
||||
if (dissector_get_uint_handle(btrfcomm_service_table, p_uuid->bt_uuid))
|
||||
break;
|
||||
if (dissector_get_uint_handle(btl2cap_service_table, p_uuid->bt_uuid))
|
||||
break;
|
||||
}
|
||||
|
||||
if (p_uuid) return *p_uuid;
|
||||
}
|
||||
|
@ -3617,7 +3631,7 @@ dissect_sdp_service_attribute_list(proto_tree *tree, tvbuff_t *tvb, gint offset,
|
|||
number_of_attributes += 1;
|
||||
}
|
||||
|
||||
uuid = get_most_specified_uuid(uuid_array);
|
||||
uuid = get_specified_uuid(uuid_array);
|
||||
if (uuid.size == 0 && service_uuid)
|
||||
uuid = *service_uuid;
|
||||
|
||||
|
@ -3950,7 +3964,7 @@ dissect_sdp_service_attribute_request(proto_tree *tree, tvbuff_t *tvb,
|
|||
offset += 2;
|
||||
|
||||
uuid_array = get_uuids(pinfo, record_handle, l2cap_data);
|
||||
uuid = get_most_specified_uuid(uuid_array);
|
||||
uuid = get_specified_uuid(uuid_array);
|
||||
|
||||
offset += dissect_attribute_id_list(tree, tvb, offset, pinfo, &uuid);
|
||||
|
||||
|
@ -3988,7 +4002,7 @@ dissect_sdp_service_attribute_response(proto_tree *tree, tvbuff_t *tvb,
|
|||
wmem_array_t *uuid_array;
|
||||
|
||||
uuid_array = get_uuids(pinfo, record_handle, l2cap_data);
|
||||
uuid = get_most_specified_uuid(uuid_array);
|
||||
uuid = get_specified_uuid(uuid_array);
|
||||
} else {
|
||||
memset(&uuid, 0, sizeof(uuid_t));
|
||||
}
|
||||
|
@ -4081,7 +4095,7 @@ dissect_sdp_service_search_attribute_request(proto_tree *tree, tvbuff_t *tvb,
|
|||
proto_tree_add_item(tree, hf_maximum_attribute_byte_count, tvb, offset, 2, ENC_BIG_ENDIAN);
|
||||
offset += 2;
|
||||
|
||||
uuid = get_most_specified_uuid(uuid_array);
|
||||
uuid = get_specified_uuid(uuid_array);
|
||||
|
||||
offset += dissect_attribute_id_list(tree, tvb, offset, pinfo, &uuid);
|
||||
|
||||
|
@ -4115,7 +4129,7 @@ dissect_sdp_service_search_attribute_response(proto_tree *tree, tvbuff_t *tvb,
|
|||
PDU_TYPE_SERVICE_SEARCH_ATTRIBUTE, &new_tvb, &is_first,
|
||||
&is_continued, &uuid_array, NULL, l2cap_data);
|
||||
|
||||
uuid = get_most_specified_uuid(uuid_array);
|
||||
uuid = get_specified_uuid(uuid_array);
|
||||
|
||||
if (is_first && !is_continued) {
|
||||
dissect_sdp_service_attribute_list_array(tree, tvb, offset, pinfo,
|
||||
|
@ -5668,6 +5682,9 @@ proto_reg_handoff_btsdp(void)
|
|||
{
|
||||
dissector_add_uint("btl2cap.psm", BTL2CAP_PSM_SDP, btsdp_handle);
|
||||
dissector_add_handle("btl2cap.cid", btsdp_handle);
|
||||
|
||||
btrfcomm_service_table = find_dissector_table("btrfcomm.service");
|
||||
btl2cap_service_table = find_dissector_table("btl2cap.service");
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in New Issue