GTK3 typo fixes:
[obnox/wireshark/wip.git] / gtk / rlc_lte_stat_dlg.c
index e90bc5b43458ba929b63f544c5aebfe618492884..bf9fb63538822ddac6708e607ac1f35b356bfcad 100644 (file)
@@ -24,7 +24,7 @@
 
 
 /* TODO:
-   - per-channel graph tap
+   - per-channel graph tap?
 */
 
 #ifdef HAVE_CONFIG_H
 #include <epan/tap.h>
 #include <epan/dissectors/packet-rlc-lte.h>
 
-#include "../register.h"
 #include "../simple_dialog.h"
 #include "../stat_menu.h"
 
 #include "gtk/dlg_utils.h"
 #include "gtk/gui_stat_menu.h"
-#include "gtk/tap_dfilter_dlg.h"
+#include "gtk/tap_param_dlg.h"
 #include "gtk/gui_utils.h"
 #include "gtk/help_dlg.h"
 #include "gtk/main.h"
 
+#include "gtk/old-gtk-compat.h"
+
 /**********************************************/
 /* Table column identifiers and title strings */
 
@@ -64,10 +65,14 @@ enum {
     UEID_COLUMN,
     UL_FRAMES_COLUMN,
     UL_BYTES_COLUMN,
+    UL_BW_COLUMN,
     UL_NACKS_COLUMN,
+    UL_MISSING_COLUMN,
     DL_FRAMES_COLUMN,
     DL_BYTES_COLUMN,
+    DL_BW_COLUMN,
     DL_NACKS_COLUMN,
+    DL_MISSING_COLUMN,
     UE_TABLE_COLUMN,
     NUM_UE_COLUMNS
 };
@@ -77,23 +82,27 @@ enum {
     CHANNEL_MODE,
     CHANNEL_UL_FRAMES,
     CHANNEL_UL_BYTES,
+    CHANNEL_UL_BW,
     CHANNEL_UL_ACKS,
     CHANNEL_UL_NACKS,
+    CHANNEL_UL_MISSING,
     CHANNEL_DL_FRAMES,
     CHANNEL_DL_BYTES,
+    CHANNEL_DL_BW,
     CHANNEL_DL_ACKS,
     CHANNEL_DL_NACKS,
+    CHANNEL_DL_MISSING,
     CHANNEL_TABLE_COLUMN,
     NUM_CHANNEL_COLUMNS
 };
 
 static const gchar *ue_titles[] = { "UEId",
-                                    "UL Frames", "UL Bytes", "UL NACKs",
-                                    "DL Frames", "DL Bytes", "DL NACKs"};
+                                    "UL Frames", "UL Bytes", "UL MBit/sec", "UL NACKs", "UL Missing",
+                                    "DL Frames", "DL Bytes", "DL MBit/sec", "DL NACKs", "DL Missing"};
 
 static const gchar *channel_titles[] = { "", "Mode",
-                                         "UL Frames", "UL Bytes", "UL ACKs", "UL NACKs",
-                                         "DL Frames", "DL Bytes", "DL ACKs", "DL NACKs"};
+                                         "UL Frames", "UL Bytes", "UL MBit/sec", "UL ACKs", "UL NACKs", "UL Missing",
+                                         "DL Frames", "DL Bytes", "DL MBit/sec", "DL ACKs", "DL NACKs", "DL Missing"};
 
 /* Stats kept for one channel */
 typedef struct rlc_channel_stats {
@@ -102,35 +111,50 @@ typedef struct rlc_channel_stats {
     guint16  channelType;
     guint16  channelId;
 
-    guint32 UL_frames;
-    guint32 UL_bytes;
-    guint32 DL_frames;
-    guint32 DL_bytes;
+    guint32  UL_frames;
+    guint32  UL_bytes;
+    nstime_t UL_time_start;
+    nstime_t UL_time_stop;
+
+    guint32  DL_frames;
+    guint32  DL_bytes;
+    nstime_t DL_time_start;
+    nstime_t DL_time_stop;
 
-    guint32 UL_acks;
-    guint32 UL_nacks;
+    guint32  UL_acks;
+    guint32  UL_nacks;
 
-    guint32 DL_acks;
-    guint32 DL_nacks;
+    guint32  DL_acks;
+    guint32  DL_nacks;
+
+    guint32  UL_missing;
+    guint32  DL_missing;
 
     GtkTreeIter iter;
     gboolean iter_valid;
 } rlc_channel_stats;
 
+
 /* Stats for one UE */
 typedef struct rlc_lte_row_data {
     /* Key for matching this row */
-    guint16 ueid;
+    guint16  ueid;
 
     gboolean is_predefined_data;
 
-    guint32 UL_frames;
-    guint32 UL_total_bytes;
-    guint32 UL_total_nacks;
+    guint32  UL_frames;
+    guint32  UL_total_bytes;
+    nstime_t UL_time_start;
+    nstime_t UL_time_stop;
+    guint32  UL_total_nacks;
+    guint32  UL_total_missing;
 
-    guint32 DL_frames;
-    guint32 DL_total_bytes;
-    guint32 DL_total_nacks;
+    guint32  DL_frames;
+    guint32  DL_total_bytes;
+    nstime_t DL_time_start;
+    nstime_t DL_time_stop;
+    guint32  DL_total_nacks;
+    guint32  DL_total_missing;
 
     rlc_channel_stats CCCH_stats;
     rlc_channel_stats srb_stats[2];
@@ -151,7 +175,7 @@ typedef struct rlc_lte_common_stats {
 typedef struct rlc_lte_ep {
     struct rlc_lte_ep* next;
     struct rlc_lte_row_data stats;
-    GtkTreeIter iter;                                         
+    GtkTreeIter iter;
     gboolean iter_valid;
 } rlc_lte_ep_t;
 
@@ -173,6 +197,9 @@ typedef struct rlc_lte_stat_t {
     GtkWidget  *dl_filter_bt;
     GtkWidget  *uldl_filter_bt;
     GtkWidget  *show_only_control_pdus_cb;
+    GtkWidget  *show_dct_errors_cb;
+    GtkWidget  *dct_error_substring_lb;
+    GtkWidget  *dct_error_substring_te;
     GtkWidget  *sn_filter_lb;
     GtkWidget  *sn_filter_te;
 
@@ -201,9 +228,16 @@ static int get_channel_selection(rlc_lte_stat_t *hs,
 /* Show filter controls appropriate to current selection */
 static void enable_filter_controls(guint8 enabled, guint8 rlcMode, rlc_lte_stat_t *hs)
 {
+    guint8 show_dct_errors = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(hs->show_dct_errors_cb));
+
     gtk_widget_set_sensitive(hs->ul_filter_bt, enabled);
     gtk_widget_set_sensitive(hs->dl_filter_bt, enabled);
     gtk_widget_set_sensitive(hs->uldl_filter_bt, enabled);
+    gtk_widget_set_sensitive(hs->show_dct_errors_cb, enabled);
+
+    /* Enabling substring control only if errors enabled */
+    gtk_widget_set_sensitive(hs->dct_error_substring_lb, enabled && show_dct_errors);
+    gtk_widget_set_sensitive(hs->dct_error_substring_te, enabled && show_dct_errors);
 
     switch (rlcMode) {
         case RLC_TM_MODE:
@@ -245,7 +279,7 @@ rlc_lte_stat_reset(void *phs)
     if (rlc_lte_stat->dlg_w != NULL) {
         g_snprintf(title, sizeof(title), "Wireshark: LTE RLC Traffic Statistics: %s (filter=\"%s\")",
                    cf_get_display_name(&cfile),
-                   rlc_lte_stat->filter ? rlc_lte_stat->filter : "none");
+                   strlen(rlc_lte_stat->filter) ? rlc_lte_stat->filter : "none");
         gtk_window_set_title(GTK_WINDOW(rlc_lte_stat->dlg_w), title);
     }
 
@@ -289,8 +323,12 @@ static rlc_lte_ep_t* alloc_rlc_lte_ep(struct rlc_lte_tap_info *si, packet_info *
     ep->stats.DL_frames = 0;
     ep->stats.UL_total_bytes = 0;
     ep->stats.DL_total_bytes = 0;
+    memset(&ep->stats.DL_time_start, 0, sizeof(nstime_t));
+    memset(&ep->stats.DL_time_stop, 0, sizeof(nstime_t));
     ep->stats.UL_total_nacks = 0;
     ep->stats.DL_total_nacks = 0;
+    ep->stats.UL_total_missing = 0;
+    ep->stats.DL_total_missing = 0;
 
     memset(&ep->stats.CCCH_stats, 0, sizeof(rlc_channel_stats));
     for (n=0; n < 2; n++) {
@@ -345,7 +383,8 @@ rlc_lte_stat_packet(void *phs, packet_info *pinfo, epan_dissect_t *edt _U_,
 
     /* Are we ignoring RLC frames that were found in MAC frames, or only those
        that were logged separately? */
-    if (!hs->show_mac && si->loggedInMACFrame) {
+    if ((!hs->show_mac && si->loggedInMACFrame) ||
+        (hs->show_mac && !si->loggedInMACFrame)) {
         return 0;
     }
 
@@ -354,11 +393,11 @@ rlc_lte_stat_packet(void *phs, packet_info *pinfo, epan_dissect_t *edt _U_,
 
     /* Common channel stats */
     switch (si->channelType) {
-        case CHANNEL_TYPE_BCCH:
+        case CHANNEL_TYPE_BCCH_BCH:
+        case CHANNEL_TYPE_BCCH_DL_SCH:
             hs->common_stats.bcch_frames++;
             hs->common_stats.bcch_bytes += si->pduLength;
             return 1;
-
         case CHANNEL_TYPE_PCCH:
             hs->common_stats.pcch_frames++;
             hs->common_stats.pcch_bytes += si->pduLength;
@@ -376,7 +415,7 @@ rlc_lte_stat_packet(void *phs, packet_info *pinfo, epan_dissect_t *edt _U_,
         te = hs->ep_list;
     } else {
         /* Look among existing rows for this UEId */
-        for (tmp = hs->ep_list;(tmp != NULL); tmp = tmp->next) {
+        for (tmp = hs->ep_list; (tmp != NULL); tmp = tmp->next) {
             if (tmp->stats.ueid == si->ueid) {
                 te = tmp;
                 break;
@@ -407,10 +446,22 @@ rlc_lte_stat_packet(void *phs, packet_info *pinfo, epan_dissect_t *edt _U_,
 
     /* Top-level traffic stats */
     if (si->direction == DIRECTION_UPLINK) {
+        /* Update time range */
+        if (te->stats.UL_frames == 0) {
+            te->stats.UL_time_start = si->time;
+        }
+        te->stats.UL_time_stop = si->time;
+
         te->stats.UL_frames++;
         te->stats.UL_total_bytes += si->pduLength;
     }
     else {
+        /* Update time range */
+        if (te->stats.DL_frames == 0) {
+            te->stats.DL_time_start = si->time;
+        }
+        te->stats.DL_time_stop = si->time;
+
         te->stats.DL_frames++;
         te->stats.DL_total_bytes += si->pduLength;
     }
@@ -441,24 +492,44 @@ rlc_lte_stat_packet(void *phs, packet_info *pinfo, epan_dissect_t *edt _U_,
         channel_stats->channelType = si->channelType;
         channel_stats->channelId = si->channelId;
     }
+    else {
+        /* Giving up if no channel found... */
+        return 0;
+    }
 
     if (si->direction == DIRECTION_UPLINK) {
+        /* Update time range */
+        if (channel_stats->UL_frames == 0) {
+            channel_stats->UL_time_start = si->time;
+        }
+        channel_stats->UL_time_stop = si->time;
+
         channel_stats->UL_frames++;
         channel_stats->UL_bytes += si->pduLength;
         channel_stats->UL_nacks += si->noOfNACKs;
+        channel_stats->UL_missing += si->missingSNs;
         if (si->isControlPDU) {
             channel_stats->UL_acks++;
         }
         te->stats.UL_total_nacks += si->noOfNACKs;
+        te->stats.UL_total_missing += si->missingSNs;
     }
     else {
+        /* Update time range */
+        if (channel_stats->DL_frames == 0) {
+            channel_stats->DL_time_start = si->time;
+        }
+        channel_stats->DL_time_stop = si->time;
+
         channel_stats->DL_frames++;
         channel_stats->DL_bytes += si->pduLength;
         channel_stats->DL_nacks += si->noOfNACKs;
+        channel_stats->DL_missing += si->missingSNs;
         if (si->isControlPDU) {
             channel_stats->DL_acks++;
         }
         te->stats.DL_total_nacks += si->noOfNACKs;
+        te->stats.DL_total_missing += si->missingSNs;
     }
 
     return 1;
@@ -485,6 +556,21 @@ static void invalidate_channel_iters(rlc_lte_stat_t *hs)
 }
 
 
+/* Calculate and return a bandwidth figure, in Mbs */
+static float calculate_bw(nstime_t *start_time, nstime_t *stop_time, guint32 bytes)
+{
+    if (memcmp(start_time, stop_time, sizeof(nstime_t)) != 0) {
+        float elapsed_ms = (((float)stop_time->secs - (float)start_time->secs) * 1000) +
+                           (((float)stop_time->nsecs - (float)start_time->nsecs) / 1000000);
+        return ((bytes * 8) / elapsed_ms) / 1000;
+    }
+    else {
+        return 0.0;
+    }
+}
+
+
+
 /* Draw the channels table according to the current UE selection */
 static void
 rlc_lte_channels(rlc_lte_ep_t *rlc_stat_ep, rlc_lte_stat_t *hs)
@@ -532,6 +618,14 @@ rlc_lte_channels(rlc_lte_ep_t *rlc_stat_ep, rlc_lte_stat_t *hs)
         channel_stats = &rlc_stat_ep->stats.srb_stats[n];
         if (channel_stats->inUse) {
 
+            /* Calculate bandwidth */
+            float UL_bw = calculate_bw(&channel_stats->UL_time_start,
+                                       &channel_stats->UL_time_stop,
+                                       channel_stats->UL_bytes);
+            float DL_bw = calculate_bw(&channel_stats->DL_time_start,
+                                       &channel_stats->DL_time_stop,
+                                       channel_stats->DL_bytes);
+
             if (!channel_stats->iter_valid) {
                 /* Add to list control if not drawn this UE before */
                 gtk_list_store_append(channels_store, &channel_stats->iter);
@@ -546,12 +640,16 @@ rlc_lte_channels(rlc_lte_ep_t *rlc_stat_ep, rlc_lte_stat_t *hs)
                                CHANNEL_MODE, print_rlc_channel_mode(channel_stats->rlcMode),
                                CHANNEL_UL_FRAMES, channel_stats->UL_frames,
                                CHANNEL_UL_BYTES, channel_stats->UL_bytes,
+                               CHANNEL_UL_BW, UL_bw,
                                CHANNEL_UL_ACKS, channel_stats->UL_acks,
                                CHANNEL_UL_NACKS, channel_stats->UL_nacks,
+                               CHANNEL_UL_MISSING, channel_stats->UL_missing,
                                CHANNEL_DL_FRAMES, channel_stats->DL_frames,
                                CHANNEL_DL_BYTES, channel_stats->DL_bytes,
+                               CHANNEL_DL_BW, DL_bw,
                                CHANNEL_DL_ACKS, channel_stats->DL_acks,
                                CHANNEL_DL_NACKS, channel_stats->DL_nacks,
+                               CHANNEL_DL_MISSING, channel_stats->DL_missing,
                                CHANNEL_TABLE_COLUMN, channel_stats,
                                -1);
         }
@@ -563,6 +661,14 @@ rlc_lte_channels(rlc_lte_ep_t *rlc_stat_ep, rlc_lte_stat_t *hs)
         channel_stats = &rlc_stat_ep->stats.drb_stats[n];
         if (channel_stats->inUse) {
 
+            /* Calculate bandwidth */
+            float UL_bw = calculate_bw(&channel_stats->UL_time_start,
+                                       &channel_stats->UL_time_stop,
+                                       channel_stats->UL_bytes);
+            float DL_bw = calculate_bw(&channel_stats->DL_time_start,
+                                       &channel_stats->DL_time_stop,
+                                       channel_stats->DL_bytes);
+
             if (!channel_stats->iter_valid) {
                 /* Add to list control if not drawn this UE before */
                 gtk_list_store_append(channels_store, &channel_stats->iter);
@@ -577,12 +683,16 @@ rlc_lte_channels(rlc_lte_ep_t *rlc_stat_ep, rlc_lte_stat_t *hs)
                                CHANNEL_MODE, print_rlc_channel_mode(channel_stats->rlcMode),
                                CHANNEL_UL_FRAMES, channel_stats->UL_frames,
                                CHANNEL_UL_BYTES, channel_stats->UL_bytes,
+                               CHANNEL_UL_BW, UL_bw,
                                CHANNEL_UL_ACKS, channel_stats->UL_acks,
                                CHANNEL_UL_NACKS, channel_stats->UL_nacks,
+                               CHANNEL_UL_MISSING, channel_stats->UL_missing,
                                CHANNEL_DL_FRAMES, channel_stats->DL_frames,
                                CHANNEL_DL_BYTES, channel_stats->DL_bytes,
+                               CHANNEL_DL_BW, DL_bw,
                                CHANNEL_DL_ACKS, channel_stats->DL_acks,
                                CHANNEL_DL_NACKS, channel_stats->DL_nacks,
+                               CHANNEL_DL_MISSING, channel_stats->DL_missing,
                                CHANNEL_TABLE_COLUMN, channel_stats,
                                -1);
         }
@@ -632,12 +742,20 @@ rlc_lte_stat_draw(void *phs)
                cf_get_display_name(&cfile),
                number_of_ues,
                hs->total_frames,
-               hs->filter ? hs->filter : "none");
+               strlen(hs->filter) ? hs->filter : "none");
     gtk_window_set_title(GTK_WINDOW(hs->dlg_w), title);
 
 
     /* For each row/UE in the model */
     for (tmp = list; tmp; tmp=tmp->next) {
+        /* Calculate bandwidth */
+        float UL_bw = calculate_bw(&tmp->stats.UL_time_start,
+                                   &tmp->stats.UL_time_stop,
+                                   tmp->stats.UL_total_bytes);
+        float DL_bw = calculate_bw(&tmp->stats.DL_time_start,
+                                   &tmp->stats.DL_time_stop,
+                                   tmp->stats.DL_total_bytes);
+
         if (tmp->iter_valid != TRUE) {
             /* Add to list control if not drawn this UE before */
             gtk_list_store_append(ues_store, &tmp->iter);
@@ -649,10 +767,14 @@ rlc_lte_stat_draw(void *phs)
                            UEID_COLUMN, tmp->stats.ueid,
                            UL_FRAMES_COLUMN, tmp->stats.UL_frames,
                            UL_BYTES_COLUMN, tmp->stats.UL_total_bytes,
+                           UL_BW_COLUMN, UL_bw,
                            UL_NACKS_COLUMN, tmp->stats.UL_total_nacks,
+                           UL_MISSING_COLUMN, tmp->stats.UL_total_missing,
                            DL_FRAMES_COLUMN, tmp->stats.DL_frames,
                            DL_BYTES_COLUMN, tmp->stats.DL_total_bytes,
+                           DL_BW_COLUMN, DL_bw,
                            DL_NACKS_COLUMN, tmp->stats.DL_total_nacks,
+                           DL_MISSING_COLUMN, tmp->stats.DL_total_missing,
                            UE_TABLE_COLUMN, tmp,
                            -1);
     }
@@ -702,6 +824,15 @@ rlc_lte_stat_draw(void *phs)
     }
 }
 
+/* When DCT errors check-box is toggled, enable substring controls accordingly */
+static void rlc_lte_dct_errors_cb(GtkTreeSelection *sel _U_, gpointer data)
+{
+    rlc_lte_stat_t *hs = (rlc_lte_stat_t*)data;
+    guint8 show_dct_errors = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(hs->show_dct_errors_cb));
+
+    gtk_widget_set_sensitive(hs->dct_error_substring_lb, show_dct_errors);
+    gtk_widget_set_sensitive(hs->dct_error_substring_te, show_dct_errors);
+}
 
 /* What to do when a UE list item is selected/unselected */
 static void rlc_lte_select_ue_cb(GtkTreeSelection *sel, gpointer data)
@@ -834,14 +965,29 @@ static void set_channel_filter_expression(guint16  ueid,
                                           ChannelDirection_t channelDirection,
                                           gint     filterOnSN,
                                           gint     statusOnlyPDUs,
+                                          gint     showDCTErrors,
+                                          const gchar    *DCTErrorSubstring,
                                           rlc_lte_stat_t *hs)
 {
     #define MAX_FILTER_LEN 1024
     static char buffer[MAX_FILTER_LEN];
     int offset = 0;
 
+    /* Show DCT errors */
+    if (showDCTErrors) {
+        if (strlen(DCTErrorSubstring) > 0) {
+            offset += g_snprintf(buffer+offset, MAX_FILTER_LEN-offset,
+                                 "(dct2000.error-comment and (dct2000.comment contains \"%s\")) or (",
+                                 DCTErrorSubstring);
+        }
+        else {
+            offset += g_snprintf(buffer+offset, MAX_FILTER_LEN-offset,
+                                 "dct2000.error-comment or (");
+        }
+    }
+
     /* Include dialog filter */
-    if (hs->filter) {
+    if (strlen(hs->filter)) {
         offset += g_snprintf(buffer+offset, MAX_FILTER_LEN-offset, "%s and ", hs->filter);
     }
 
@@ -849,6 +995,9 @@ static void set_channel_filter_expression(guint16  ueid,
     if (!hs->show_mac) {
         offset += g_snprintf(buffer+offset, MAX_FILTER_LEN-offset, "not mac-lte and ");
     }
+    else {
+        offset += g_snprintf(buffer+offset, MAX_FILTER_LEN-offset, "mac-lte and ");
+    }
 
     /* UEId */
     offset += g_snprintf(buffer+offset, MAX_FILTER_LEN-offset, "(rlc-lte.ueid == %u) and ", ueid);
@@ -922,6 +1071,12 @@ static void set_channel_filter_expression(guint16  ueid,
         }
     }
 
+    /* Close () if open */
+    if (showDCTErrors) {
+        offset += g_snprintf(buffer+offset, MAX_FILTER_LEN-offset, ")");
+    }
+
+
     /* Set its value to our new string */
     gtk_entry_set_text(GTK_ENTRY(main_display_filter_widget), buffer);
 
@@ -951,6 +1106,8 @@ static void ul_filter_clicked(GtkWindow *win _U_, rlc_lte_stat_t* hs)
 
     set_channel_filter_expression(ueid, rlcMode, channelType, channelId, UL_Only, sn,
                                   gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(hs->show_only_control_pdus_cb)),
+                                  gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(hs->show_dct_errors_cb)),
+                                  gtk_entry_get_text(GTK_ENTRY(hs->dct_error_substring_te)),
                                   hs);
 }
 
@@ -976,6 +1133,8 @@ static void dl_filter_clicked(GtkWindow *win _U_, rlc_lte_stat_t* hs)
 
     set_channel_filter_expression(ueid, rlcMode, channelType, channelId, DL_Only, sn,
                                   gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(hs->show_only_control_pdus_cb)),
+                                  gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(hs->show_dct_errors_cb)),
+                                  gtk_entry_get_text(GTK_ENTRY(hs->dct_error_substring_te)),
                                   hs);
 }
 
@@ -1001,6 +1160,8 @@ static void uldl_filter_clicked(GtkWindow *win _U_, rlc_lte_stat_t* hs)
 
     set_channel_filter_expression(ueid, rlcMode, channelType, channelId, UL_and_DL, sn,
                                   gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(hs->show_only_control_pdus_cb)),
+                                  gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(hs->show_dct_errors_cb)),
+                                  gtk_entry_get_text(GTK_ENTRY(hs->dct_error_substring_te)),
                                   hs);
 }
 
@@ -1031,7 +1192,6 @@ static void gtk_rlc_lte_stat_init(const char *optarg, void *userdata _U_)
 
     GtkWidget         *close_bt;
     GtkWidget         *help_bt;
-
     GtkListStore      *store;
 
     GtkTreeView       *tree_view;
@@ -1084,7 +1244,13 @@ static void gtk_rlc_lte_stat_init(const char *optarg, void *userdata _U_)
     pdu_source_lb = gtk_frame_new("PDUs to use");
     show_mac_cb = gtk_check_button_new_with_mnemonic("Show RLC PDUs found inside logged MAC frames");
     gtk_container_add(GTK_CONTAINER(pdu_source_lb), show_mac_cb);
-    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(show_mac_cb), FALSE);
+    gtk_widget_set_tooltip_text(show_mac_cb, "Can either use separately-logged RLC PDUs, OR find them "
+                         "decoded inside MAC PDUs (enabled in MAC dissector preferences)");
+
+
+    /* MAC on by default */
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(show_mac_cb), TRUE);
+    hs->show_mac = TRUE;
     gtk_box_pack_start(GTK_BOX(top_level_vbox), pdu_source_lb, FALSE, FALSE, 0);
     /* TODO: add tooltips... */
     g_signal_connect(show_mac_cb, "toggled", G_CALLBACK(toggle_show_mac), hs);
@@ -1139,8 +1305,8 @@ static void gtk_rlc_lte_stat_init(const char *optarg, void *userdata _U_)
 
     /* Create the table of UE data */
     store = gtk_list_store_new(NUM_UE_COLUMNS, G_TYPE_INT,
-                               G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, /* UL */
-                               G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, /* DL */
+                               G_TYPE_INT, G_TYPE_INT, G_TYPE_FLOAT, G_TYPE_INT, G_TYPE_INT, /* UL */
+                               G_TYPE_INT, G_TYPE_INT, G_TYPE_FLOAT, G_TYPE_INT, G_TYPE_INT, /* DL */
                                G_TYPE_POINTER);
     hs->ue_table = GTK_TREE_VIEW(tree_view_new(GTK_TREE_MODEL(store)));
     gtk_container_add(GTK_CONTAINER (ues_scrolled_window), GTK_WIDGET(hs->ue_table));
@@ -1194,8 +1360,8 @@ static void gtk_rlc_lte_stat_init(const char *optarg, void *userdata _U_)
     /* Create the table of UE data */
     store = gtk_list_store_new(NUM_CHANNEL_COLUMNS,
                                G_TYPE_STRING, G_TYPE_STRING, /* name & type */
-                               G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, /* UL */
-                               G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, /* DL */
+                               G_TYPE_INT, G_TYPE_INT, G_TYPE_FLOAT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, /* UL */
+                               G_TYPE_INT, G_TYPE_INT, G_TYPE_FLOAT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, /* DL */
                                G_TYPE_POINTER);
     hs->channel_table = GTK_TREE_VIEW(tree_view_new(GTK_TREE_MODEL(store)));
     gtk_container_add(GTK_CONTAINER (channels_scrolled_window), GTK_WIDGET(hs->channel_table));
@@ -1251,18 +1417,26 @@ static void gtk_rlc_lte_stat_init(const char *optarg, void *userdata _U_)
     gtk_box_pack_start(GTK_BOX(filter_buttons_hb), hs->ul_filter_bt, TRUE, TRUE, 0);
     g_signal_connect(hs->ul_filter_bt, "clicked", G_CALLBACK(ul_filter_clicked), hs);
     gtk_widget_show(hs->ul_filter_bt);
+    gtk_widget_set_tooltip_text(hs->ul_filter_bt, "Generate and set a display filter to show frames "
+                         "associated with the channel, in the UL direction only. "
+                         "N.B. DL Status PDUs sent on this channel will also be shown for AM");
 
     /* DL only */
     hs->dl_filter_bt = gtk_button_new_with_label("Set DL display filter for this channel");
     gtk_box_pack_start(GTK_BOX(filter_buttons_hb), hs->dl_filter_bt, TRUE, TRUE, 0);
     g_signal_connect(hs->dl_filter_bt, "clicked", G_CALLBACK(dl_filter_clicked), hs);
     gtk_widget_show(hs->dl_filter_bt);
+    gtk_widget_set_tooltip_text(hs->dl_filter_bt, "Generate and set a display filter to show frames "
+                         "associated with the channel, in the DL direction only. "
+                         "N.B. UL Status PDUs sent on this channel will also be shown for AM");
 
     /* UL and DL */
     hs->uldl_filter_bt = gtk_button_new_with_label("Set UL / DL display filter for this channel");
     gtk_box_pack_start(GTK_BOX(filter_buttons_hb), hs->uldl_filter_bt, TRUE, TRUE, 0);
     g_signal_connect(hs->uldl_filter_bt, "clicked", G_CALLBACK(uldl_filter_clicked), hs);
     gtk_widget_show(hs->uldl_filter_bt);
+    gtk_widget_set_tooltip_text(hs->uldl_filter_bt, "Generate and set a display filter to show frames "
+                         "associated with the channel, in UL and DL");
 
     /* Allow filtering on specific SN number. */
     /* Row with label and text entry control  */
@@ -1274,10 +1448,34 @@ static void gtk_rlc_lte_stat_init(const char *optarg, void *userdata _U_)
     hs->show_only_control_pdus_cb = gtk_check_button_new_with_mnemonic("Show only status PDUs");
     gtk_container_add(GTK_CONTAINER(sn_filter_hb), hs->show_only_control_pdus_cb);
     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(hs->show_only_control_pdus_cb), FALSE);
-
+    gtk_widget_set_tooltip_text(hs->show_only_control_pdus_cb, "Generated filters will only show AM status PDUs "
+                         "(i.e. if you filter on UL you'll see ACKs/NACK replies sent in the DL)");
+
+    /* Allow DCT errors to be shown... */
+    hs->show_dct_errors_cb = gtk_check_button_new_with_mnemonic("Show DCT2000 error strings...");
+    gtk_container_add(GTK_CONTAINER(sn_filter_hb), hs->show_dct_errors_cb);
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(hs->show_dct_errors_cb), FALSE);
+    g_signal_connect(hs->show_dct_errors_cb, "toggled", G_CALLBACK(rlc_lte_dct_errors_cb), hs);
+    gtk_widget_set_tooltip_text(hs->show_dct_errors_cb, "When checked, generated filters will "
+                         "include DCT2000 error strings");
+
+    /* ... optionally limited by a substring */
+    hs->dct_error_substring_lb = gtk_label_new("...containing");
+    gtk_box_pack_start(GTK_BOX(sn_filter_hb), hs->dct_error_substring_lb, FALSE, FALSE, 0);
+    gtk_widget_show(hs->dct_error_substring_lb);
+
+    hs->dct_error_substring_te = gtk_entry_new();
+    gtk_box_pack_start(GTK_BOX(sn_filter_hb), hs->dct_error_substring_te, FALSE, FALSE, 0);
+    gtk_widget_show(hs->dct_error_substring_te);
+    gtk_widget_set_tooltip_text(hs->dct_error_substring_te,
+                         "If given, only match error strings containing this substring");
+
+    /* Allow filtering of a particular sequence number */
     hs->sn_filter_te = gtk_entry_new();
     gtk_box_pack_end(GTK_BOX(sn_filter_hb), hs->sn_filter_te, FALSE, FALSE, 0);
     gtk_widget_show(hs->sn_filter_te);
+    gtk_widget_set_tooltip_text(hs->sn_filter_te, "Can limit generated filters to a given sequence number (0-1023). "
+                         "Will also include relevant AM status PDUs");
 
     hs->sn_filter_lb = gtk_label_new("Sequence number to filter on:");
     gtk_box_pack_end(GTK_BOX(sn_filter_hb), hs->sn_filter_lb, FALSE, FALSE, 0);
@@ -1330,15 +1528,21 @@ static void gtk_rlc_lte_stat_init(const char *optarg, void *userdata _U_)
 
     /* Retap */
     cf_retap_packets(&cfile);
-    gdk_window_raise(hs->dlg_w->window);
+    gdk_window_raise(gtk_widget_get_window(hs->dlg_w));
 }
 
 
-static tap_dfilter_dlg rlc_lte_stat_dlg = {
+static tap_param rlc_lte_stat_params[] = {
+       { PARAM_FILTER, "Filter", NULL }
+};
+
+static tap_param_dlg rlc_lte_stat_dlg = {
     "LTE RLC Stats",
     "rlc-lte,stat",
     gtk_rlc_lte_stat_init,
-    -1
+    -1,
+    G_N_ELEMENTS(rlc_lte_stat_params),
+    rlc_lte_stat_params
 };
 
 
@@ -1346,6 +1550,11 @@ static tap_dfilter_dlg rlc_lte_stat_dlg = {
 void
 register_tap_listener_rlc_lte_stat(void)
 {
-    register_dfilter_stat(&rlc_lte_stat_dlg, "_LTE RLC...", REGISTER_STAT_GROUP_TELEPHONY);
+    register_dfilter_stat(&rlc_lte_stat_dlg, "_LTE/_RLC", REGISTER_STAT_GROUP_TELEPHONY);
 }
-
+#ifdef MAIN_MENU_USE_UIMANAGER
+void rlc_lte_stat_cb(GtkAction *action, gpointer user_data _U_)
+{
+       tap_param_dlg_cb(action, &rlc_lte_stat_dlg);
+}
+#endif