GSM SMS: take into consideration TP-OA/TP-DA fields and direction for reassembly

Bug: 13572
Change-Id: Ieb1b972f95bc5c445597dd9aa2a0d8e7e9985238
Reviewed-on: https://code.wireshark.org/review/21013
Reviewed-by: Michael Mann <mmann78@netscape.net>
This commit is contained in:
Pascal Quantin 2017-04-11 11:23:03 +02:00 committed by Michael Mann
parent 5bcd2f681e
commit 87fc4cc5d7
1 changed files with 154 additions and 16 deletions

View File

@ -41,6 +41,7 @@
#include <epan/prefs.h>
#include <epan/reassemble.h>
#include <epan/charsets.h>
#include <epan/proto_data.h>
#include "packet-gsm_sms.h"
void proto_register_gsm_sms(void);
@ -335,6 +336,120 @@ typedef struct {
guint8 fill_bits;
} sm_fragment_params;
typedef struct {
const gchar *address;
int p2p_dir;
guint32 id;
} sm_fragment_params_key;
static guint
sm_fragment_params_hash(gconstpointer k)
{
const sm_fragment_params_key* key = (const sm_fragment_params_key*) k;
guint hash_val;
hash_val = (wmem_str_hash(key->address) ^ key->id) + key->p2p_dir;
return hash_val;
}
static gboolean
sm_fragment_params_equal(gconstpointer v1, gconstpointer v2)
{
const sm_fragment_params_key *key1 = (const sm_fragment_params_key*)v1;
const sm_fragment_params_key *key2 = (const sm_fragment_params_key*)v2;
return (key1->id == key2->id) &&
(key1->p2p_dir == key2->p2p_dir) &&
!g_strcmp0(key1->address, key2->address);
}
typedef struct {
const gchar *address;
int p2p_dir;
guint32 id;
} sm_fragment_key;
static guint
sm_fragment_hash(gconstpointer k)
{
const sm_fragment_key* key = (const sm_fragment_key*) k;
guint hash_val;
hash_val = (wmem_str_hash(key->address) ^ key->id) + key->p2p_dir;
return hash_val;
}
static gint
sm_fragment_equal(gconstpointer k1, gconstpointer k2)
{
const sm_fragment_key* key1 = (const sm_fragment_key*) k1;
const sm_fragment_key* key2 = (const sm_fragment_key*) k2;
return (key1->id == key2->id) &&
(key1->p2p_dir == key2->p2p_dir) &&
!g_strcmp0(key1->address, key2->address);
}
static gpointer
sm_fragment_temporary_key(const packet_info *pinfo,
const guint32 id, const void *data)
{
const gchar* addr = (const char*)data;
sm_fragment_key *key = g_slice_new(sm_fragment_key);
key->address = addr;
key->p2p_dir = pinfo->p2p_dir;
key->id = id;
return (gpointer)key;
}
static gpointer
sm_fragment_persistent_key(const packet_info *pinfo,
const guint32 id, const void *data)
{
const gchar* addr = (const char*)data;
sm_fragment_key *key = g_slice_new(sm_fragment_key);
key->address = wmem_strdup(NULL, addr);
key->p2p_dir = pinfo->p2p_dir;
key->id = id;
return (gpointer)key;
}
static void
sm_fragment_free_temporary_key(gpointer ptr)
{
sm_fragment_key *key = (sm_fragment_key *)ptr;
if(key)
g_slice_free(sm_fragment_key, key);
}
static void
sm_fragment_free_persistent_key(gpointer ptr)
{
sm_fragment_key *key = (sm_fragment_key *)ptr;
if(key) {
wmem_free(NULL, (void*)key->address);
g_slice_free(sm_fragment_key, key);
}
}
const reassembly_table_functions
sm_reassembly_table_functions = {
sm_fragment_hash,
sm_fragment_equal,
sm_fragment_temporary_key,
sm_fragment_persistent_key,
sm_fragment_free_temporary_key,
sm_fragment_free_persistent_key
};
/*
* this is the GSM 03.40 definition with the bit 2
* set to 1 for uplink messages
@ -526,9 +641,13 @@ dis_field_addr(tvbuff_t *tvb, packet_info* pinfo, proto_tree *tree, guint32 *off
if (g_ascii_strncasecmp(title, "TP-O", 4) == 0) {
proto_tree_add_string(subtree, hf_gsm_sms_tp_oa, tvb,
offset, numdigocts, addrstr);
p_add_proto_data(pinfo->pool, pinfo, proto_gsm_sms, 0,
wmem_strdup(pinfo->pool, addrstr));
} else if (g_ascii_strncasecmp(title, "TP-D", 4) == 0) {
proto_tree_add_string(subtree, hf_gsm_sms_tp_da, tvb,
offset, numdigocts, addrstr);
p_add_proto_data(pinfo->pool, pinfo, proto_gsm_sms, 0,
wmem_strdup(pinfo->pool, addrstr));
} else if (g_ascii_strncasecmp(title, "TP-R", 4) == 0) {
proto_tree_add_string(subtree, hf_gsm_sms_tp_ra, tvb,
offset, numdigocts, addrstr);
@ -1824,11 +1943,16 @@ dis_field_ud(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 offset
gboolean is_fragmented = FALSE;
gboolean save_fragmented = FALSE, try_gsm_sms_ud_reassemble = FALSE;
sm_fragment_params *p_frag_params;
gsm_sms_udh_fields_t udh_fields;
sm_fragment_params *p_frag_params;
sm_fragment_params_key *p_frag_params_key, frag_params_key;
const gchar *addr;
gsm_sms_udh_fields_t udh_fields;
memset(&udh_fields, 0, sizeof(udh_fields));
fill_bits = 0;
addr = (gchar*)p_get_proto_data(pinfo->pool, pinfo, proto_gsm_sms, 0);
if (addr == NULL)
addr = "";
subtree =
proto_tree_add_subtree(tree, tvb,
@ -1862,7 +1986,7 @@ dis_field_ud(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 offset
fd_sm = fragment_add_seq_check (&g_sm_reassembly_table, tvb, offset,
pinfo,
udh_fields.sm_id, /* guint32 ID for fragments belonging together */
NULL,
addr,
udh_fields.frag-1, /* guint32 fragment sequence number */
length, /* guint32 fragment length */
(udh_fields.frag != udh_fields.frags)); /* More fragments? */
@ -1889,14 +2013,18 @@ dis_field_ud(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 offset
" (Short Message fragment %u of %u)", udh_fields.frag, udh_fields.frags);
}
/* Store udl and length for later decoding of reassembled SMS */
p_frag_params = wmem_new0(wmem_file_scope(), sm_fragment_params);
p_frag_params->udl = udl;
p_frag_params->fill_bits = fill_bits;
p_frag_params->length = length;
wmem_map_insert(g_sm_fragment_params_table,
GUINT_TO_POINTER((guint)((udh_fields.sm_id<<16)|(udh_fields.frag-1))),
p_frag_params);
if (!PINFO_FD_VISITED(pinfo)) {
/* Store udl and length for later decoding of reassembled SMS */
p_frag_params_key = wmem_new(wmem_file_scope(), sm_fragment_params_key);
p_frag_params_key->address = wmem_strdup(wmem_file_scope(), addr);
p_frag_params_key->p2p_dir = pinfo->p2p_dir;
p_frag_params_key->id = (udh_fields.sm_id<<16)|(udh_fields.frag-1);
p_frag_params = wmem_new0(wmem_file_scope(), sm_fragment_params);
p_frag_params->udl = udl;
p_frag_params->fill_bits = fill_bits;
p_frag_params->length = length;
wmem_map_insert(g_sm_fragment_params_table, p_frag_params_key, p_frag_params);
}
} /* Else: not fragmented */
if (! sm_tvb) /* One single Short Message, or not reassembled */
sm_tvb = tvb_new_subset_remaining (tvb, offset);
@ -1938,8 +2066,11 @@ dis_field_ud(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 offset
total_sms_len = 0;
for(i = 0 ; i < udh_fields.frags; i++)
{
frag_params_key.address = addr;
frag_params_key.p2p_dir = pinfo->p2p_dir;
frag_params_key.id = (udh_fields.sm_id<<16)|i;
p_frag_params = (sm_fragment_params*)wmem_map_lookup(g_sm_fragment_params_table,
GUINT_TO_POINTER((guint)((udh_fields.sm_id<<16)|i)));
&frag_params_key);
if (p_frag_params) {
proto_tree_add_item(subtree, hf_gsm_sms_text, sm_tvb, total_sms_len,
@ -1966,8 +2097,11 @@ dis_field_ud(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 offset
total_sms_len = 0;
for(i = 0 ; i < udh_fields.frags; i++)
{
frag_params_key.address = addr;
frag_params_key.p2p_dir = pinfo->p2p_dir;
frag_params_key.id = (udh_fields.sm_id<<16)|i;
p_frag_params = (sm_fragment_params*)wmem_map_lookup(g_sm_fragment_params_table,
GUINT_TO_POINTER((guint)((udh_fields.sm_id<<16)|i)));
&frag_params_key);
if (p_frag_params) {
proto_tree_add_ts_23_038_7bits_item(subtree, hf_gsm_sms_text, sm_tvb,
@ -2011,8 +2145,11 @@ dis_field_ud(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint32 offset
total_sms_len = 0;
for(i = 0 ; i < udh_fields.frags; i++)
{
frag_params_key.address = addr;
frag_params_key.p2p_dir = pinfo->p2p_dir;
frag_params_key.id = (udh_fields.sm_id<<16)|i;
p_frag_params = (sm_fragment_params*)wmem_map_lookup(g_sm_fragment_params_table,
GUINT_TO_POINTER((guint)((udh_fields.sm_id<<16)|i)));
&frag_params_key);
if (p_frag_params) {
proto_tree_add_item(subtree, hf_gsm_sms_text, sm_tvb, total_sms_len,
@ -3345,10 +3482,11 @@ proto_register_gsm_sms(void)
register_dissector("gsm_sms", dissect_gsm_sms, proto_gsm_sms);
g_sm_fragment_params_table = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), g_direct_hash, g_direct_equal);
g_sm_fragment_params_table = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(),
sm_fragment_params_hash, sm_fragment_params_equal);
reassembly_table_register(&g_sm_reassembly_table,
&addresses_reassembly_table_functions);
&sm_reassembly_table_functions);
}