Compare commits

...

5 Commits

Author SHA1 Message Date
Pau Espin ea2231458a gsm_osmux: Use proper sizes for structo smuxh fields
Change-Id: I93de7ffdbd3c43494bc6a5dd1f44f6f45d6b54f8
2017-05-12 11:47:59 +02:00
Pau Espin ad60fe0238 gsm_osmux: Add support to follow Osmux streams and show its statistics
Change-Id: I5262b3b1ac5a6f5bc6ac932eedbb889847131d9c
2017-05-12 11:47:12 +02:00
Pau Espin 4814685f20 gsm_osmux: Support multiple OSmux frames per packet
Also split and show all AMR payloads

Change-Id: I5bde4e87dc51fd4a996a14117813ea89d7005d38
2017-05-12 11:47:07 +02:00
Pau Espin ba92095873 gsm_osmux: Add RTP Marker field
GSM Osmux recently got support to bring RTP Marker (M) bit. It should be
mostly backwards compatible as the first bit was reserved and not used
before for the FieldType.

Support was added in libosmo-netif commit e98afe5808176efb60298a2f764e8e11efaf580b
This bit is documented in the protocol documentation recently available: http://ftp.osmocom.org/docs/latest/osmux-reference.pdf

Change-Id: Ia0508971519b3df9499d963404bb8a0e3c4b9c33
2017-05-12 10:44:50 +02:00
Pau Espin f15b779d0b GTK+Qt: Show non-plugin stats_tree entries on the menu bar
Change-Id: I565b0d2d43dd98781f77a302a20bd841e3e4650e
2017-05-12 10:44:44 +02:00
7 changed files with 445 additions and 155 deletions

View File

@ -1569,7 +1569,6 @@ DISSECTOR_INCLUDES = \
packet-gsm_a_common.h \
packet-gsm_a_rr.h \
packet-gsm_map.h \
packet-gsm_osmux.h \
packet-gsm_rlcmac.h \
packet-gsm_sms.h \
packet-gsmtap.h \

View File

@ -21,6 +21,13 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* FIXME: I didn't find a way yet to reliably differentiate between streams
* using same IPs+PORTs+CID over time. That means: if a recording session is
* long enough, a call may have allocated a CID which was already used by
* someone else in the past, and wireshark will handle those two calls as the
* same stream. This is bad specially for statistics such as jitter.
*/
#include "config.h"
#include <string.h>
@ -31,25 +38,72 @@
#include <epan/tap.h>
#include <epan/to_str.h>
#include <epan/strutil.h>
#include "packet-gsm_osmux.h"
void proto_register_osmux(void);
void proto_reg_handoff_osmux(void);
#define OSMUX_FT_SIGNAL 0x00
#define OSMUX_FT_AMR 0x01
#define OSMUX_FT_DUMMY 0x02
static const value_string osmux_ft_vals[] =
{
{0x00, "Signalling"},
{0x01, "AMR"},
{0x02, "Dummy"},
{OSMUX_FT_SIGNAL, "Signalling"},
{OSMUX_FT_AMR, "AMR"},
{OSMUX_FT_DUMMY, "Dummy"},
{0, NULL}
};
#define AMR_FT_0 0
#define AMR_FT_1 1
#define AMR_FT_2 2
#define AMR_FT_3 3
#define AMR_FT_4 4
#define AMR_FT_5 5
#define AMR_FT_6 6
#define AMR_FT_7 7
#define AMR_FT_SID 8
#define AMR_FT_MAX 9
static const value_string amr_ft_names[] =
{
{AMR_FT_0, "AMR 4.75"},
{AMR_FT_1, "AMR 5.15"},
{AMR_FT_2, "AMR 5.90"},
{AMR_FT_3, "AMR 6.70"},
{AMR_FT_4, "AMR 7.40"},
{AMR_FT_5, "AMR 7.95"},
{AMR_FT_6, "AMR 10.2"},
{AMR_FT_7, "AMR 12.2"},
{AMR_FT_SID, "AMR SID"},
{0, NULL}
};
/* Code to calculate payload size */
struct amr_size_entry { guint8 ft, size; };
static struct amr_size_entry amr_ft_bytes[] =
{
{AMR_FT_0, 12},
{AMR_FT_1, 13},
{AMR_FT_2, 15},
{AMR_FT_3, 17},
{AMR_FT_4, 19},
{AMR_FT_5, 20},
{AMR_FT_6, 26},
{AMR_FT_7, 31},
{AMR_FT_SID, 6}
};
#define OSMUX_AMR_HEADER_LEN 4
/* Initialize the protocol and registered fields */
static dissector_handle_t osmux_handle;
static int proto_osmux = -1;
static int osmux_tap = -1;
static int hf_osmux_stream_id = -1;
static int hf_osmux_ft_ctr = -1;
static int hf_osmux_rtp_m = -1;
static int hf_osmux_ft = -1;
static int hf_osmux_ctr = -1;
static int hf_osmux_amr_f = -1;
@ -66,12 +120,180 @@ static gint ett_osmux = -1;
static gint ett_osmux_ft_ctr = -1;
static gint ett_osmux_amr_ft_cmr = -1;
/* Stream handling */
static wmem_map_t *osmux_stream_hash;
static guint32 osmux_next_stream_id;
struct osmux_stream_key {
address src;
address dst;
port_type ptype;
guint32 srcport;
guint32 destport;
guint32 cid;
};
struct osmux_stats_tree {
gint node_id;
gboolean amr_received;
guint32 last_seq;
guint32 prev_seq;
nstime_t prev_ts;
double jitter;
};
struct osmux_stream {
struct osmux_stream_key *key;
struct osmux_stats_tree stats;
guint32 id;
};
/* Tap structure of Osmux header */
struct osmux_hdr {
gboolean rtp_m;
guint8 ft;
guint8 ctr;
gboolean amr_f;
gboolean amr_q;
guint8 seq;
guint8 circuit_id;
guint8 amr_cmr;
guint8 amr_ft;
gboolean is_old_dummy;
struct osmux_stream *stream;
};
static guint8
amr_ft_to_bytes(guint8 amr_ft)
{
if (amr_ft >= AMR_FT_MAX) /* malformed packet ? */
return 0;
return amr_ft_bytes[amr_ft].size;
}
/*
* Hash Functions
*/
static gint
osmux_equal(gconstpointer v, gconstpointer w)
{
const struct osmux_stream_key *v1 = (const struct osmux_stream_key *)v;
const struct osmux_stream_key *v2 = (const struct osmux_stream_key *)w;
if (v1->ptype != v2->ptype)
return 0; /* different types of port */
if (v1->srcport == v2->srcport &&
v1->destport == v2->destport &&
addresses_equal(&v1->src, &v2->src) &&
addresses_equal(&v1->dst, &v2->dst) &&
v1->cid == v2->cid) {
return 1;
}
return 0;
}
static guint
osmux_hash (gconstpointer v)
{
const struct osmux_stream_key *key = (const struct osmux_stream_key *)v;
guint hash_val;
address tmp_addr;
hash_val = 0;
tmp_addr.len = 4;
hash_val = add_address_to_hash(hash_val, &key->src);
tmp_addr.data = &key->srcport;
hash_val = add_address_to_hash(hash_val, &tmp_addr);
hash_val = add_address_to_hash(hash_val, &key->dst);
tmp_addr.data = &key->destport;
hash_val = add_address_to_hash(hash_val, &tmp_addr);
tmp_addr.data = &key->cid;
hash_val = add_address_to_hash(hash_val, &tmp_addr);
hash_val += ( hash_val << 3 );
hash_val ^= ( hash_val >> 11 );
hash_val += ( hash_val << 15 );
return hash_val;
}
static void stream_str(struct osmux_stream *stream, gchar *buf, guint buf_len)
{
gchar *ip_str, *ip2_str;
ip_str = address_to_str(NULL, &stream->key->src);
ip2_str = address_to_str(NULL, &stream->key->dst);
g_snprintf(buf, buf_len, "%u ([%s:%u->%s:%u]:%u)", stream->id,
ip_str, stream->key->srcport, ip2_str, stream->key->destport,
stream->key->cid);
wmem_free(NULL, ip_str);
wmem_free(NULL, ip2_str);
}
static struct osmux_stream *
get_stream(packet_info *pinfo, guint32 cid)
{
struct osmux_stream_key key, *new_key;
struct osmux_stream *stream;
copy_address_shallow(&key.src, &pinfo->src);
copy_address_shallow(&key.dst, &pinfo->dst);
key.ptype = pinfo->ptype;
key.srcport = pinfo->srcport;
key.destport = pinfo->destport;
key.cid = cid;
stream = (struct osmux_stream *) wmem_map_lookup(osmux_stream_hash, &key);
if (!stream) {
new_key = wmem_new(wmem_file_scope(), struct osmux_stream_key);
*new_key = key;
copy_address_wmem(wmem_file_scope(), &new_key->src, &key.src);
copy_address_wmem(wmem_file_scope(), &new_key->dst, &key.dst);
stream = wmem_new(wmem_file_scope(), struct osmux_stream);
stream->key = new_key;
memset(&stream->stats, 0, sizeof(struct osmux_stats_tree));
stream->id = osmux_next_stream_id;
osmux_next_stream_id++;
wmem_map_insert(osmux_stream_hash, new_key, stream);
gchar buf[160];
stream_str(stream, buf, sizeof(buf));
}
return stream;
}
static void finish_process_pkt(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, struct osmux_hdr *osmuxh)
{
tvbuff_t *analysis_tvb;
guint32 *analysis_buf;
osmuxh->stream = get_stream(pinfo, osmuxh->circuit_id);
if (tree) {
analysis_buf = (guint32*)wmem_alloc(pinfo->pool, sizeof(guint32));
*analysis_buf = osmuxh->stream->id;
analysis_tvb = tvb_new_child_real_data(tvb, (guint8*) analysis_buf, sizeof(guint32), sizeof(guint32));
add_new_data_source(pinfo, analysis_tvb, "OSMUX Stream Analysis");
proto_tree_add_item(tree, hf_osmux_stream_id, analysis_tvb, 0, sizeof(guint32), ENC_LITTLE_ENDIAN);
}
tap_queue_packet(osmux_tap, pinfo, osmuxh);
}
/* Code to actually dissect the packets */
static gint
dissect_osmux(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
{
static const gint *ft_ctr_fields[] = {
&hf_osmux_rtp_m,
&hf_osmux_ft,
&hf_osmux_ctr,
&hf_osmux_amr_f,
@ -86,123 +308,204 @@ dissect_osmux(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U
int offset = 0;
struct osmux_hdr *osmuxh;
proto_item *ti;
proto_tree *osmux_tree = NULL;
guint8 ft_ctr;
guint32 cid;
guint64 amr_ft_cmr;
col_set_str(pinfo->cinfo, COL_PROTOCOL, "Osmux");
col_clear(pinfo->cinfo, COL_INFO);
osmuxh = wmem_new0(wmem_packet_scope(), struct osmux_hdr);
while (tvb_reported_length_remaining(tvb, offset) >= 2) {
ft_ctr = tvb_get_guint8(tvb, offset);
struct osmux_hdr *osmuxh;
proto_item *ti;
proto_tree *osmux_tree = NULL;
guint8 ft_ctr;
guint64 amr_ft_cmr;
guint8 i;
guint32 size;
osmuxh->ft = ft_ctr >> 5;
osmuxh->ctr = (ft_ctr >> 2) & 0x7;
osmuxh->amr_q = !!(ft_ctr & 0x02);
osmuxh->amr_f = !!(ft_ctr & 0x01);
osmuxh = wmem_new0(wmem_packet_scope(), struct osmux_hdr);
col_append_fstr(pinfo->cinfo, COL_INFO, "Osmux ");
ft_ctr = tvb_get_guint8(tvb, offset);
ti = proto_tree_add_protocol_format(tree, proto_osmux, tvb, offset, -1,
"Osmux type %s frame",
val_to_str(osmuxh->ft, osmux_ft_vals, "unknown 0x%02x"));
osmux_tree = proto_item_add_subtree(ti, ett_osmux);
osmuxh->rtp_m = ft_ctr >> 7;
osmuxh->ft = (ft_ctr >> 5) & 0x3;
osmuxh->ctr = (ft_ctr >> 2) & 0x7;
osmuxh->amr_q = !!(ft_ctr & 0x02);
osmuxh->amr_f = !!(ft_ctr & 0x01);
/* Two-byte dummy packets for firewalls (starts with 0x23) */
if (ft_ctr == 0x23 && tvb_reported_length(tvb) >= 2) {
proto_tree_add_item_ret_uint(osmux_tree, hf_osmux_circuit_id, tvb, offset+1, 1, ENC_BIG_ENDIAN, &cid);
col_append_fstr(pinfo->cinfo, COL_INFO, "Dummy frame (CID %u)", cid);
return 2;
col_append_sep_str(pinfo->cinfo, COL_INFO, ", ", "Osmux ");
col_append_fstr(pinfo->cinfo, COL_INFO, "%s ",
val_to_str(osmuxh->ft, osmux_ft_vals,
"unknown 0x%02x"));
if (osmuxh->rtp_m)
col_append_fstr(pinfo->cinfo, COL_INFO, "(M) ");
ti = proto_tree_add_protocol_format(tree, proto_osmux, tvb, offset, -1,
"Osmux type %s frame",
val_to_str(osmuxh->ft, osmux_ft_vals, "unknown 0x%02x"));
osmux_tree = proto_item_add_subtree(ti, ett_osmux);
proto_tree_add_bitmask(osmux_tree, tvb, offset, hf_osmux_ft_ctr,
ett_osmux_ft_ctr, ft_ctr_fields, ENC_BIG_ENDIAN);
offset++;
/* Old versions of the protocol used to send dummy packets of only 2 bytes (control + cid):_*/
if (ft_ctr == 0x23 && tvb_reported_length_remaining(tvb, offset - 1) == 2) {
osmuxh->is_old_dummy = TRUE;
osmuxh->circuit_id = tvb_get_guint8(tvb, offset);
proto_tree_add_item(osmux_tree, hf_osmux_circuit_id, tvb, offset, 1, ENC_BIG_ENDIAN);
col_append_fstr(pinfo->cinfo, COL_INFO, "Old Dummy (CID %u)", osmuxh->circuit_id);
finish_process_pkt(tvb, pinfo, tree, osmuxh);
return tvb_reported_length(tvb);
}
osmuxh->seq = tvb_get_guint8(tvb, offset);
proto_tree_add_item(osmux_tree, hf_osmux_seq, tvb, offset, 1, ENC_BIG_ENDIAN);
offset++;
osmuxh->circuit_id = tvb_get_guint8(tvb, offset);
proto_tree_add_item(osmux_tree, hf_osmux_circuit_id, tvb, offset, 1, ENC_BIG_ENDIAN);
offset++;
col_append_fstr(pinfo->cinfo, COL_INFO, "(CID %u) ", osmuxh->circuit_id);
proto_tree_add_bitmask_ret_uint64(osmux_tree, tvb, offset, hf_osmux_amr_ft_cmr,
ett_osmux_amr_ft_cmr, amr_ft_cmr_fields, ENC_BIG_ENDIAN, &amr_ft_cmr);
offset++;
osmuxh->amr_ft = (guint32)(amr_ft_cmr & 0xf0) >> 4;
osmuxh->amr_cmr = (guint32)amr_ft_cmr & 0x0f;
size = amr_ft_to_bytes(osmuxh->amr_ft);
for (i = 0; i < osmuxh->ctr + 1; i++) {
proto_tree_add_item(osmux_tree, hf_osmux_amr_data, tvb, offset, size, ENC_NA);
offset += size;
}
finish_process_pkt(tvb, pinfo, tree, osmuxh);
}
col_append_fstr(pinfo->cinfo, COL_INFO, "%s ",
val_to_str(osmuxh->ft, osmux_ft_vals,
"unknown 0x%02x"));
proto_tree_add_bitmask(osmux_tree, tvb, offset, hf_osmux_ft_ctr,
ett_osmux_ft_ctr, ft_ctr_fields, ENC_BIG_ENDIAN);
offset++;
proto_tree_add_item_ret_uint(osmux_tree, hf_osmux_seq, tvb, offset, 1, ENC_BIG_ENDIAN, &osmuxh->seq);
offset++;
proto_tree_add_item_ret_uint(osmux_tree, hf_osmux_circuit_id, tvb, offset, 1, ENC_BIG_ENDIAN, &osmuxh->circuit_id);
offset++;
proto_tree_add_bitmask_ret_uint64(osmux_tree, tvb, offset, hf_osmux_amr_ft_cmr,
ett_osmux_amr_ft_cmr, amr_ft_cmr_fields, ENC_BIG_ENDIAN, &amr_ft_cmr);
offset++;
osmuxh->amr_ft = (guint32)(amr_ft_cmr & 0xf0) >> 4;
osmuxh->amr_cmr = (guint32)amr_ft_cmr & 0x0f;
proto_tree_add_item(osmux_tree, hf_osmux_amr_data, tvb, offset, tvb_reported_length_remaining(tvb, offset), ENC_NA);
tap_queue_packet(osmux_tap, pinfo, osmuxh);
return tvb_reported_length(tvb);
}
/* Statistics */
static const gchar *st_str_pkts = "Osmux Packets";
static const gchar *st_str_pkts_by_cid = "Osmux Packets by CID";
static const gchar *st_str_pkts_by_ctr = "Osmux Packets by AMR frame count";
static const gchar *st_str_pkts_by_src = "Osmux Packets by src Addr";
static const gchar *st_str_pkts_by_dst = "Osmux Packets by dst Addr";
static const gchar *st_str_pkts_by_conn = "Osmux Packets by stream";
static const gchar *st_str_total_pkts = "Osmux Total Packets";
static const gchar *st_str_conn = "Osmux Streams";
static const gchar *st_str_pkts = "Count: Osmux Packets";
static const gchar *st_str_amr = "Count: AMR frames";
static const gchar *st_str_rtp_m = "Field: RTP Marker (M)";
static const gchar *st_str_seq_rep = "SeqNum Analysis: Consecutive Repeated";
static const gchar *st_str_seq_lost = "SeqNum Analysis: Lost";
static const gchar *st_str_seq_ord = "SeqNum Analysis: In Order";
static const gchar *st_str_seq_ooo = "SeqNum Analysis: Out Of Order";
static const gchar *st_str_jit_rtt = "Jitter Analysis: Relative Transmit Time [ms]";
static const gchar *st_str_jit_rtt_abs = "Jitter Analysis: Relative Transmit Time (abs) [ms]";
static const gchar *st_str_jit_jit = "Jitter Analysis: Jitter [ms]";
static int st_osmux_stats = -1;
static int st_osmux_stats_cid = -1;
static int st_osmux_stats_ctr = -1;
static int st_osmux_stats_src = -1;
static int st_osmux_stats_dst = -1;
static int st_osmux_stats_conn = -1;
static void osmux_stats_tree_init(stats_tree *st)
{
st_osmux_stats = stats_tree_create_node(st, st_str_pkts, 0, TRUE);
st_osmux_stats_cid = stats_tree_create_node(st, st_str_pkts_by_cid, st_osmux_stats, TRUE);
st_osmux_stats_ctr = stats_tree_create_node(st, st_str_pkts_by_ctr, st_osmux_stats, TRUE);
st_osmux_stats_src = stats_tree_create_node(st, st_str_pkts_by_src, st_osmux_stats, TRUE);
st_osmux_stats_dst = stats_tree_create_node(st, st_str_pkts_by_dst, st_osmux_stats, TRUE);
st_osmux_stats_conn = stats_tree_create_node(st, st_str_pkts_by_conn, st_osmux_stats, TRUE);
st_osmux_stats = stats_tree_create_node(st, st_str_total_pkts, 0, TRUE);
st_osmux_stats_conn = stats_tree_create_node(st, st_str_conn, st_osmux_stats, TRUE);
}
static int osmux_stats_tree_packet(stats_tree *st, packet_info *pinfo,
static void stream_hash_clean_tree_id(gpointer key _U_, gpointer value, gpointer user_data _U_) {
struct osmux_stream *stream = (struct osmux_stream *)value;
memset(&stream->stats, 0, sizeof(struct osmux_stats_tree));
}
static void osmux_stats_tree_cleanup(stats_tree *st _U_)
{
wmem_map_foreach(osmux_stream_hash, stream_hash_clean_tree_id, NULL);
}
static int osmux_stats_tree_packet(stats_tree *st, packet_info *pinfo _U_,
epan_dissect_t *edt _U_, const void *p _U_)
{
gchar *ip_str, *ip2_str;
gchar temp[40];
gchar stream_name[160];
gchar ft_name[40];
struct osmux_hdr *osmuxh = (struct osmux_hdr*) p;
struct osmux_stream *stream = osmuxh->stream;
stream_str(stream, stream_name, sizeof(stream_name));
tick_stat_node(st, st_str_total_pkts, 0, TRUE);
if (!stream->stats.node_id) {
tick_stat_node(st, st_str_conn, st_osmux_stats, TRUE);
stream->stats.node_id = stats_tree_create_node(st, stream_name, st_osmux_stats_conn, TRUE);
}
tick_stat_node(st, stream_name, st_osmux_stats_conn, TRUE);
tick_stat_node(st, st_str_pkts, stream->stats.node_id, TRUE);
g_snprintf(ft_name, sizeof(ft_name), "Field: FT: %s",
osmuxh->is_old_dummy ? "Old Dummy" : osmux_ft_vals[osmuxh->ft].strptr);
tick_stat_node(st, ft_name, stream->stats.node_id, TRUE);
tick_stat_node(st, st_str_pkts, 0, FALSE);
if (osmuxh->ft == OSMUX_FT_AMR && !osmuxh->is_old_dummy) {
tick_stat_node(st, st_str_pkts_by_cid, st_osmux_stats, FALSE);
g_snprintf(temp, 30, "%i", osmuxh->circuit_id);
tick_stat_node(st, temp, st_osmux_stats_cid, TRUE);
increase_stat_node(st, st_str_amr, stream->stats.node_id, TRUE, osmuxh->ctr+1);
avg_stat_node_add_value_notick(st, st_str_amr, stream->stats.node_id, TRUE, osmuxh->ctr+1);
tick_stat_node(st, st_str_pkts_by_ctr, st_osmux_stats, FALSE);
g_snprintf(temp, 30, "%i", osmuxh->ctr);
tick_stat_node(st, temp, st_osmux_stats_ctr, TRUE);
increase_stat_node(st, st_str_rtp_m, stream->stats.node_id, TRUE, osmuxh->rtp_m);
avg_stat_node_add_value_notick(st, st_str_rtp_m, stream->stats.node_id, TRUE, osmuxh->rtp_m);
tick_stat_node(st, st_str_pkts_by_src, 0, FALSE);
ip_str = address_to_str(NULL, &pinfo->src);
tick_stat_node(st, ip_str, st_osmux_stats_src, TRUE);
tick_stat_node(st, st_str_pkts_by_dst, 0, FALSE);
ip2_str = address_to_str(NULL, &pinfo->dst);
tick_stat_node(st, ip2_str, st_osmux_stats_dst, TRUE);
/* Calculate relative transmit time */
if ((stream->stats.prev_ts.secs == 0 && stream->stats.prev_ts.nsecs == 0) || osmuxh->rtp_m) {
avg_stat_node_add_value(st, st_str_jit_rtt, stream->stats.node_id, TRUE, 0);
avg_stat_node_add_value(st, st_str_jit_rtt_abs, stream->stats.node_id, TRUE, 0);
avg_stat_node_add_value(st, st_str_jit_jit, stream->stats.node_id, TRUE, 0);
stream->stats.jitter = 0;
} else {
nstime_t diff_rx;
gint32 diff_rx_ms, diff_tx_ms, Dij;
guint32 abs_Dij;
nstime_delta(&diff_rx, &pinfo->abs_ts, &stream->stats.prev_ts);
diff_rx_ms = (guint32) nstime_to_msec(&diff_rx);
diff_tx_ms = (osmuxh->seq - stream->stats.prev_seq)*(osmuxh->ctr+1)*20; /* SAMPLE RATE is 20msec/AMRframe */
Dij = diff_rx_ms - diff_tx_ms;
abs_Dij = Dij * ( Dij >= 0 ? 1 : -1 );
stream->stats.jitter = stream->stats.jitter + ((double) abs_Dij - stream->stats.jitter)/16.0;
avg_stat_node_add_value(st, st_str_jit_rtt, stream->stats.node_id, TRUE, Dij);
avg_stat_node_add_value(st, st_str_jit_rtt_abs, stream->stats.node_id, TRUE, abs_Dij);
avg_stat_node_add_value(st, st_str_jit_jit, stream->stats.node_id, TRUE, (gint) stream->stats.jitter);
}
stream->stats.prev_ts = pinfo->abs_ts;
stream->stats.prev_seq = osmuxh->seq;
tick_stat_node(st, st_str_pkts_by_conn, 0, FALSE);
g_snprintf(temp, 40, "%s->%s:%i", ip_str, ip2_str, osmuxh->circuit_id);
tick_stat_node(st, temp, st_osmux_stats_conn, TRUE);
/* Check sequence numbers */
//fprintf(stderr, "%s %u\t->\t%u", stream_name, stream->stats.last_seq, osmuxh->seq);
if (!stream->stats.amr_received || (stream->stats.last_seq + 1) % 256 == osmuxh->seq ) {
/* normal case */
//fprintf(stderr, "\t%s: +1\n", st_str_seq_ord);
tick_stat_node(st, st_str_seq_ord, stream->stats.node_id, TRUE);
stream->stats.last_seq = osmuxh->seq;
stream->stats.amr_received = TRUE;
} else if (stream->stats.last_seq == osmuxh->seq) {
/* Last packet is repeated */
//fprintf(stderr, "\t%s: +1\n", st_str_seq_rep);
tick_stat_node(st, st_str_seq_rep, stream->stats.node_id, TRUE);
} else if ((stream->stats.last_seq + 1) % 256 < osmuxh->seq) {
/* Normal packet loss */
//fprintf(stderr, "\t%s: %d\n", st_str_seq_lost, osmuxh->seq - stream->stats.last_seq - 1);
increase_stat_node(st, st_str_seq_lost, stream->stats.node_id, TRUE, osmuxh->seq - stream->stats.last_seq - 1);
stream->stats.last_seq = osmuxh->seq;
} else if (stream->stats.last_seq - osmuxh->seq > 0x008F) {
/* If last_Seq is a lot higher, a wraparound occurred with packet loss */
//fprintf(stderr, "\t%s: (wrap) %d\n", st_str_seq_lost, 255 - stream->stats.last_seq + osmuxh->seq);
increase_stat_node(st, st_str_seq_lost, stream->stats.node_id, TRUE, 255 - stream->stats.last_seq + osmuxh->seq);
stream->stats.last_seq = osmuxh->seq;
} else if (stream->stats.last_seq > osmuxh->seq || osmuxh->seq - stream->stats.last_seq > 0x008F) {
/* Out of order packet */
//fprintf(stderr, "\t%s: +1, ", st_str_seq_ooo);
//fprintf(stderr, "\t%s: -1\n", st_str_seq_lost);
tick_stat_node(st, st_str_seq_ooo, stream->stats.node_id, TRUE);
increase_stat_node(st, st_str_seq_lost, stream->stats.node_id, TRUE, -1);
}
wmem_free(NULL, ip_str);
wmem_free(NULL, ip2_str);
}
return 1;
}
@ -210,14 +513,24 @@ static int osmux_stats_tree_packet(stats_tree *st, packet_info *pinfo,
void proto_register_osmux(void)
{
static hf_register_info hf[] = {
{&hf_osmux_stream_id,
{"OSmux Stream ID", "osmux.stream_id",
FT_UINT32, BASE_DEC, NULL, 0x00,
"ID for a specific OSMUX flow", HFILL}
},
{&hf_osmux_ft_ctr,
{"FTCTRByte", "osmux.ft_ctr",
FT_UINT8, BASE_DEC, NULL, 0x00,
"Byte with Fieldtype, Counter", HFILL}
},
{&hf_osmux_rtp_m,
{"RTP Marker", "osmux.rtp_m",
FT_BOOLEAN, 8, NULL, 0x80,
"Type of data in packet", HFILL}
},
{&hf_osmux_ft,
{"FieldType", "osmux.ft",
FT_UINT8, BASE_DEC, VALS(osmux_ft_vals), 0xe0,
FT_UINT8, BASE_DEC, VALS(osmux_ft_vals), 0x60,
"Type of data in packet", HFILL}
},
{&hf_osmux_ctr,
@ -252,7 +565,7 @@ void proto_register_osmux(void)
},
{&hf_osmux_amr_ft,
{"AMR ft", "osmux.amr_ft",
FT_UINT8, BASE_HEX, NULL, 0xf0,
FT_UINT8, BASE_HEX,VALS(amr_ft_names), 0xf0,
"AMR parameter ft", HFILL}
},
{&hf_osmux_amr_cmr,
@ -277,6 +590,10 @@ void proto_register_osmux(void)
proto_register_field_array(proto_osmux, hf, array_length(hf));
proto_register_subtree_array(ett, array_length(ett));
osmux_stream_hash = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(),
osmux_hash, osmux_equal);
}
@ -289,7 +606,7 @@ void proto_reg_handoff_osmux(void)
stats_tree_register("osmux", "osmux", "Osmux/Packets", 0,
osmux_stats_tree_packet, osmux_stats_tree_init,
NULL);
osmux_stats_tree_cleanup);
}
/*

View File

@ -1,50 +0,0 @@
/* packet-gsm_osmux.h
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef PACKET_GSM_OSMUX_H
#define PACKET_GSM_OSMUX_H
/* Tap structure of Osmux header */
struct osmux_hdr {
guint32 ft;
guint32 ctr;
guint32 amr_f;
guint32 amr_q;
guint32 seq;
guint32 circuit_id;
guint32 amr_cmr;
guint32 amr_ft;
};
#endif
/*
* Editor modelines - http://www.wireshark.org/tools/modelines.html
*
* Local variables:
* c-basic-offset: 4
* tab-width: 8
* indent-tabs-mode: nil
* End:
*
* vi: set shiftwidth=4 tabstop=8 expandtab:
* :indentSize=4:tabSize=8:noTabs=true:
*/

View File

@ -136,7 +136,7 @@ GtkWidget *popup_menu_object;
static void menu_open_recent_file_cmd_cb(GtkAction *action, gpointer data _U_ );
static void add_recent_items (guint merge_id, GtkUIManager *ui_manager);
static void add_tap_plugins (guint merge_id, GtkUIManager *ui_manager);
static void add_tap (guint merge_id, GtkUIManager *ui_manager);
static void menus_init(void);
static void merge_menu_items(GList *node);
@ -3284,7 +3284,7 @@ menus_init(void)
/* Add statistics tap plug-in to the menu
*/
merge_id = gtk_ui_manager_new_merge_id (ui_manager_main_menubar);
add_tap_plugins (merge_id, ui_manager_main_menubar);
add_tap (merge_id, ui_manager_main_menubar);
statusbar_profiles_action_group = gtk_action_group_new ("StatusBarProfilesPopUpMenuActionGroup");
@ -3891,7 +3891,7 @@ add_recent_items (guint merge_id, GtkUIManager *ui_manager)
#define MENU_STATISTICS_PATH "/Menubar/StatisticsMenu"
static void
add_tap_plugins (guint merge_id, GtkUIManager *ui_manager)
add_tap_entries (guint merge_id, GtkUIManager *ui_manager, gboolean plugin)
{
GtkActionGroup *action_group;
GtkAction *action;
@ -3906,22 +3906,33 @@ add_tap_plugins (guint merge_id, GtkUIManager *ui_manager)
gchar *stat_name;
gchar *sep;
action_group = gtk_action_group_new ("tap-plugins-group");
gchar *action_group_str;
gchar *merge_id_str;
if (plugin) {
action_group_str = "tap-plugins-group";
merge_id_str = "tap-plugins-merge-id";
} else {
action_group_str = "tap-group";
merge_id_str = "tap-merge-id";
}
action_group = gtk_action_group_new (action_group_str);
submenu_statistics = gtk_ui_manager_get_widget(ui_manager_main_menubar, MENU_STATISTICS_PATH);
if(!submenu_statistics){
g_warning("add_tap_plugins: No submenu_statistics found, path= MENU_STATISTICS_PATH");
if (!submenu_statistics) {
g_warning("add_tap_entries: No submenu_statistics found, path=" MENU_STATISTICS_PATH);
return;
}
gtk_ui_manager_insert_action_group (ui_manager_main_menubar, action_group, 0);
g_object_set_data (G_OBJECT (ui_manager_main_menubar),
"tap-plugins-merge-id", GUINT_TO_POINTER (merge_id));
merge_id_str, GUINT_TO_POINTER (merge_id));
cfg_list = stats_tree_get_cfg_list();
iter = g_list_first(cfg_list);
while (iter) {
stats_tree_cfg *cfg = (stats_tree_cfg*)iter->data;
if (cfg->plugin) {
if (cfg->plugin == plugin) {
stat_name_buf = g_strdup(cfg->name);
submenu_path_size = (gsize)(strlen(MENU_STATISTICS_PATH)+strlen(cfg->name)+strlen(cfg->abbr)+1); /* worst case length */
submenu_path = (gchar *)g_malloc(submenu_path_size);
@ -3984,6 +3995,13 @@ add_tap_plugins (guint merge_id, GtkUIManager *ui_manager)
g_list_free(cfg_list);
}
static void
add_tap(guint merge_id, GtkUIManager *ui_manager)
{
add_tap_entries(merge_id, ui_manager, FALSE);
add_tap_entries(merge_id, ui_manager, TRUE);
}
/* Open a file by its name
(Beware: will not ask to close existing capture file!) */
void

View File

@ -398,7 +398,7 @@ MainWindow::MainWindow(QWidget *parent) :
connect(wsApp, SIGNAL(appInitialized()), this, SLOT(applyGlobalCommandLineOptions()));
connect(wsApp, SIGNAL(appInitialized()), this, SLOT(zoomText()));
connect(wsApp, SIGNAL(appInitialized()), this, SLOT(initViewColorizeMenu()));
connect(wsApp, SIGNAL(appInitialized()), this, SLOT(addStatsPluginsToMenu()));
connect(wsApp, SIGNAL(appInitialized()), this, SLOT(addStatsToMenu()));
connect(wsApp, SIGNAL(appInitialized()), this, SLOT(addDynamicMenus()));
connect(wsApp, SIGNAL(appInitialized()), this, SLOT(addPluginIFStructures()));
connect(wsApp, SIGNAL(appInitialized()), this, SLOT(initConversationMenus()));

View File

@ -238,6 +238,7 @@ private:
void removeMenuActions(QList<QAction *> &actions, int menu_group);
void goToConversationFrame(bool go_next);
void colorizeWithFilter(QByteArray filter, int color_number = -1);
void addStatsEntriesToMenu(bool plugin);
signals:
void setCaptureFile(capture_file *cf);
@ -337,7 +338,7 @@ private slots:
void showAccordionFrame(AccordionFrame *show_frame, bool toggle = false);
void showColumnEditor(int column);
void showPreferenceEditor(); // module_t *, pref *
void addStatsPluginsToMenu();
void addStatsToMenu();
void addDynamicMenus();
void reloadDynamicMenus();
void addPluginIFStructures();

View File

@ -1623,7 +1623,7 @@ void MainWindow::initViewColorizeMenu()
#endif
}
void MainWindow::addStatsPluginsToMenu() {
void MainWindow::addStatsEntriesToMenu(bool plugin) {
GList *cfg_list = stats_tree_get_cfg_list();
GList *iter = g_list_first(cfg_list);
QAction *stats_tree_action;
@ -1632,7 +1632,7 @@ void MainWindow::addStatsPluginsToMenu() {
while (iter) {
stats_tree_cfg *cfg = (stats_tree_cfg*)iter->data;
if (cfg->plugin) {
if (cfg->plugin == plugin) {
if (first_item) {
main_ui_->menuStatistics->addSeparator();
first_item = false;
@ -1659,6 +1659,11 @@ void MainWindow::addStatsPluginsToMenu() {
g_list_free(cfg_list);
}
void MainWindow::addStatsToMenu() {
addStatsEntriesToMenu(false);
addStatsEntriesToMenu(true);
}
void MainWindow::setFeaturesEnabled(bool enabled)
{
main_ui_->menuBar->setEnabled(enabled);