2 * Copyright 2010 Martin Mathieson
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27 - per-channel graph tap?
34 #ifdef HAVE_SYS_TYPES_H
35 #include <sys/types.h>
42 #include "gtk/gtkglobals.h"
44 #include <epan/packet.h>
45 #include <epan/packet_info.h>
47 #include <epan/dissectors/packet-rlc-lte.h>
49 #include "../simple_dialog.h"
50 #include "../stat_menu.h"
52 #include "gtk/dlg_utils.h"
53 #include "gtk/gui_stat_menu.h"
54 #include "gtk/tap_param_dlg.h"
55 #include "gtk/gui_utils.h"
56 #include "gtk/help_dlg.h"
59 #include "gtk/old-gtk-compat.h"
61 /**********************************************/
62 /* Table column identifiers and title strings */
99 static const gchar *ue_titles[] = { "UEId",
100 "UL Frames", "UL Bytes", "UL MBit/sec", "UL NACKs", "UL Missing",
101 "DL Frames", "DL Bytes", "DL MBit/sec", "DL NACKs", "DL Missing"};
103 static const gchar *channel_titles[] = { "", "Mode",
104 "UL Frames", "UL Bytes", "UL MBit/sec", "UL ACKs", "UL NACKs", "UL Missing",
105 "DL Frames", "DL Bytes", "DL MBit/sec", "DL ACKs", "DL NACKs", "DL Missing"};
107 /* Stats kept for one channel */
108 typedef struct rlc_channel_stats {
116 nstime_t UL_time_start;
117 nstime_t UL_time_stop;
121 nstime_t DL_time_start;
122 nstime_t DL_time_stop;
138 /* Stats for one UE */
139 typedef struct rlc_lte_row_data {
140 /* Key for matching this row */
143 gboolean is_predefined_data;
146 guint32 UL_total_bytes;
147 nstime_t UL_time_start;
148 nstime_t UL_time_stop;
149 guint32 UL_total_nacks;
150 guint32 UL_total_missing;
153 guint32 DL_total_bytes;
154 nstime_t DL_time_start;
155 nstime_t DL_time_stop;
156 guint32 DL_total_nacks;
157 guint32 DL_total_missing;
159 rlc_channel_stats CCCH_stats;
160 rlc_channel_stats srb_stats[2];
161 rlc_channel_stats drb_stats[32];
165 /* Common channel stats */
166 typedef struct rlc_lte_common_stats {
171 } rlc_lte_common_stats;
174 /* One row/UE in the UE table */
175 typedef struct rlc_lte_ep {
176 struct rlc_lte_ep* next;
177 struct rlc_lte_row_data stats;
183 /* Used to keep track of whole RLC LTE statistics window */
184 typedef struct rlc_lte_stat_t {
185 GtkTreeView *ue_table;
186 rlc_lte_ep_t *ep_list;
187 guint32 total_frames;
191 /* Top-level dialog and labels */
196 GtkWidget *ul_filter_bt;
197 GtkWidget *dl_filter_bt;
198 GtkWidget *uldl_filter_bt;
199 GtkWidget *show_only_control_pdus_cb;
200 GtkWidget *show_dct_errors_cb;
201 GtkWidget *dct_error_substring_lb;
202 GtkWidget *dct_error_substring_te;
203 GtkWidget *sn_filter_lb;
204 GtkWidget *sn_filter_te;
207 rlc_lte_common_stats common_stats;
208 GtkWidget *common_bcch_frames;
209 GtkWidget *common_bcch_bytes;
210 GtkWidget *common_pcch_frames;
211 GtkWidget *common_pcch_bytes;
215 /* State used to attempt to re-select chosen UE/channel */
217 guint16 reselect_channel_type;
218 guint16 reselect_channel_id;
220 GtkTreeView *channel_table;
224 static int get_channel_selection(rlc_lte_stat_t *hs,
225 guint16 *ueid, guint8 *rlcMode,
226 guint16 *channelType, guint16 *channelId);
228 /* Show filter controls appropriate to current selection */
229 static void enable_filter_controls(guint8 enabled, guint8 rlcMode, rlc_lte_stat_t *hs)
231 guint8 show_dct_errors = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(hs->show_dct_errors_cb));
233 gtk_widget_set_sensitive(hs->ul_filter_bt, enabled);
234 gtk_widget_set_sensitive(hs->dl_filter_bt, enabled);
235 gtk_widget_set_sensitive(hs->uldl_filter_bt, enabled);
236 gtk_widget_set_sensitive(hs->show_dct_errors_cb, enabled);
238 /* Enabling substring control only if errors enabled */
239 gtk_widget_set_sensitive(hs->dct_error_substring_lb, enabled && show_dct_errors);
240 gtk_widget_set_sensitive(hs->dct_error_substring_te, enabled && show_dct_errors);
244 gtk_widget_set_sensitive(hs->show_only_control_pdus_cb, FALSE);
245 gtk_widget_set_sensitive(hs->sn_filter_lb, FALSE);
246 gtk_widget_set_sensitive(hs->sn_filter_te, FALSE);
249 gtk_widget_set_sensitive(hs->show_only_control_pdus_cb, FALSE);
250 gtk_widget_set_sensitive(hs->sn_filter_lb, TRUE);
251 gtk_widget_set_sensitive(hs->sn_filter_te, TRUE);
254 gtk_widget_set_sensitive(hs->show_only_control_pdus_cb, TRUE);
255 gtk_widget_set_sensitive(hs->sn_filter_lb, TRUE);
256 gtk_widget_set_sensitive(hs->sn_filter_te, TRUE);
260 gtk_widget_set_sensitive(hs->show_only_control_pdus_cb, FALSE);
261 gtk_widget_set_sensitive(hs->sn_filter_lb, FALSE);
262 gtk_widget_set_sensitive(hs->sn_filter_te, FALSE);
269 /* Reset the statistics window */
271 rlc_lte_stat_reset(void *phs)
273 rlc_lte_stat_t* rlc_lte_stat = (rlc_lte_stat_t *)phs;
274 rlc_lte_ep_t* list = rlc_lte_stat->ep_list;
279 if (rlc_lte_stat->dlg_w != NULL) {
280 g_snprintf(title, sizeof(title), "Wireshark: LTE RLC Traffic Statistics: %s (filter=\"%s\")",
281 cf_get_display_name(&cfile),
282 strlen(rlc_lte_stat->filter) ? rlc_lte_stat->filter : "none");
283 gtk_window_set_title(GTK_WINDOW(rlc_lte_stat->dlg_w), title);
286 g_snprintf(title, sizeof(title), "0 UEs");
287 gtk_frame_set_label(GTK_FRAME(rlc_lte_stat->ues_lb), title);
289 rlc_lte_stat->total_frames = 0;
290 memset(&rlc_lte_stat->common_stats, 0, sizeof(rlc_lte_common_stats));
292 /* Remove all entries from the UE list */
293 store = GTK_LIST_STORE(gtk_tree_view_get_model(rlc_lte_stat->ue_table));
294 gtk_list_store_clear(store);
300 rlc_lte_stat->ep_list = NULL;
304 /* Allocate a rlc_lte_ep_t struct to store info for new UE */
305 static rlc_lte_ep_t* alloc_rlc_lte_ep(struct rlc_lte_tap_info *si, packet_info *pinfo _U_)
314 if (!(ep = g_malloc(sizeof(rlc_lte_ep_t)))) {
318 /* Copy SI data into ep->stats */
319 ep->stats.ueid = si->ueid;
321 /* Counts for new UE are all 0 */
322 ep->stats.UL_frames = 0;
323 ep->stats.DL_frames = 0;
324 ep->stats.UL_total_bytes = 0;
325 ep->stats.DL_total_bytes = 0;
326 memset(&ep->stats.DL_time_start, 0, sizeof(nstime_t));
327 memset(&ep->stats.DL_time_stop, 0, sizeof(nstime_t));
328 ep->stats.UL_total_nacks = 0;
329 ep->stats.DL_total_nacks = 0;
330 ep->stats.UL_total_missing = 0;
331 ep->stats.DL_total_missing = 0;
333 memset(&ep->stats.CCCH_stats, 0, sizeof(rlc_channel_stats));
334 for (n=0; n < 2; n++) {
335 memset(&ep->stats.srb_stats[n], 0, sizeof(rlc_channel_stats));
337 for (n=0; n < 32; n++) {
338 memset(&ep->stats.drb_stats[n], 0, sizeof(rlc_channel_stats));
342 ep->iter_valid = FALSE;
348 /* Return string for RLC mode for display */
349 static const char *print_rlc_channel_mode(guint8 mode)
351 static char unknown[16];
354 case RLC_TM_MODE: return "TM";
355 case RLC_UM_MODE: return "UM";
356 case RLC_AM_MODE: return "AM";
357 case RLC_PREDEF: return "Predef";
360 g_snprintf(unknown, 32, "Unknown (%u)", mode);
366 /* Process stat struct for a RLC LTE frame */
368 rlc_lte_stat_packet(void *phs, packet_info *pinfo, epan_dissect_t *edt _U_,
371 /* Get reference to stat window instance */
372 rlc_lte_stat_t *hs = (rlc_lte_stat_t *)phs;
373 rlc_lte_ep_t *tmp = NULL, *te = NULL;
374 rlc_channel_stats *channel_stats = NULL;
376 /* Cast tap info struct */
377 struct rlc_lte_tap_info *si = (struct rlc_lte_tap_info *)phi;
384 /* Are we ignoring RLC frames that were found in MAC frames, or only those
385 that were logged separately? */
386 if ((!hs->show_mac && si->loggedInMACFrame) ||
387 (hs->show_mac && !si->loggedInMACFrame)) {
391 /* Inc top-level frame count */
394 /* Common channel stats */
395 switch (si->channelType) {
396 case CHANNEL_TYPE_BCCH_BCH:
397 case CHANNEL_TYPE_BCCH_DL_SCH:
398 hs->common_stats.bcch_frames++;
399 hs->common_stats.bcch_bytes += si->pduLength;
401 case CHANNEL_TYPE_PCCH:
402 hs->common_stats.pcch_frames++;
403 hs->common_stats.pcch_bytes += si->pduLength;
410 /* For per-UE data, must create a new row if none already existing */
412 /* Allocate new list */
413 hs->ep_list = alloc_rlc_lte_ep(si, pinfo);
414 /* Make it the first/only entry */
417 /* Look among existing rows for this UEId */
418 for (tmp = hs->ep_list; (tmp != NULL); tmp = tmp->next) {
419 if (tmp->stats.ueid == si->ueid) {
425 /* Not found among existing, so create a new one anyway */
427 if ((te = alloc_rlc_lte_ep(si, pinfo))) {
428 /* Add new item to end of list */
429 rlc_lte_ep_t *p = hs->ep_list;
439 /* Really should have a row pointer by now */
444 /* Update entry with details from si */
445 te->stats.ueid = si->ueid;
447 /* Top-level traffic stats */
448 if (si->direction == DIRECTION_UPLINK) {
449 /* Update time range */
450 if (te->stats.UL_frames == 0) {
451 te->stats.UL_time_start = si->time;
453 te->stats.UL_time_stop = si->time;
455 te->stats.UL_frames++;
456 te->stats.UL_total_bytes += si->pduLength;
459 /* Update time range */
460 if (te->stats.DL_frames == 0) {
461 te->stats.DL_time_start = si->time;
463 te->stats.DL_time_stop = si->time;
465 te->stats.DL_frames++;
466 te->stats.DL_total_bytes += si->pduLength;
469 /* Find channel struct */
470 switch (si->channelType) {
471 case CHANNEL_TYPE_CCCH:
472 channel_stats = &te->stats.CCCH_stats;
475 case CHANNEL_TYPE_SRB:
476 channel_stats = &te->stats.srb_stats[si->channelId-1];
479 case CHANNEL_TYPE_DRB:
480 channel_stats = &te->stats.drb_stats[si->channelId-1];
484 /* Shouldn't get here... */
488 if (channel_stats != NULL) {
489 channel_stats->inUse = TRUE;
490 channel_stats->iter_valid = FALSE;
491 channel_stats->rlcMode = si->rlcMode;
492 channel_stats->channelType = si->channelType;
493 channel_stats->channelId = si->channelId;
496 /* Giving up if no channel found... */
500 if (si->direction == DIRECTION_UPLINK) {
501 /* Update time range */
502 if (channel_stats->UL_frames == 0) {
503 channel_stats->UL_time_start = si->time;
505 channel_stats->UL_time_stop = si->time;
507 channel_stats->UL_frames++;
508 channel_stats->UL_bytes += si->pduLength;
509 channel_stats->UL_nacks += si->noOfNACKs;
510 channel_stats->UL_missing += si->missingSNs;
511 if (si->isControlPDU) {
512 channel_stats->UL_acks++;
514 te->stats.UL_total_nacks += si->noOfNACKs;
515 te->stats.UL_total_missing += si->missingSNs;
518 /* Update time range */
519 if (channel_stats->DL_frames == 0) {
520 channel_stats->DL_time_start = si->time;
522 channel_stats->DL_time_stop = si->time;
524 channel_stats->DL_frames++;
525 channel_stats->DL_bytes += si->pduLength;
526 channel_stats->DL_nacks += si->noOfNACKs;
527 channel_stats->DL_missing += si->missingSNs;
528 if (si->isControlPDU) {
529 channel_stats->DL_acks++;
531 te->stats.DL_total_nacks += si->noOfNACKs;
532 te->stats.DL_total_missing += si->missingSNs;
539 /* The channels for any UE would need to be re-added to the list */
540 static void invalidate_channel_iters(rlc_lte_stat_t *hs)
543 rlc_lte_ep_t *ep = hs->ep_list;
546 ep->stats.CCCH_stats.iter_valid = FALSE;
547 for (n=0; n < 2; n++) {
548 ep->stats.srb_stats[n].iter_valid = FALSE;
550 for (n=0; n < 32; n++) {
551 ep->stats.drb_stats[n].iter_valid = FALSE;
559 /* Calculate and return a bandwidth figure, in Mbs */
560 static float calculate_bw(nstime_t *start_time, nstime_t *stop_time, guint32 bytes)
562 if (memcmp(start_time, stop_time, sizeof(nstime_t)) != 0) {
563 float elapsed_ms = (((float)stop_time->secs - (float)start_time->secs) * 1000) +
564 (((float)stop_time->nsecs - (float)start_time->nsecs) / 1000000);
565 return ((bytes * 8) / elapsed_ms) / 1000;
574 /* Draw the channels table according to the current UE selection */
576 rlc_lte_channels(rlc_lte_ep_t *rlc_stat_ep, rlc_lte_stat_t *hs)
578 GtkListStore *channels_store = GTK_LIST_STORE(gtk_tree_view_get_model(hs->channel_table));
579 rlc_channel_stats *channel_stats;
583 /* Clear any existing rows */
584 gtk_list_store_clear(channels_store);
585 invalidate_channel_iters(hs);
587 if (rlc_stat_ep == NULL) {
591 /* Add one row for each channel */
594 channel_stats = &rlc_stat_ep->stats.CCCH_stats;
595 if (channel_stats->inUse) {
597 if (!channel_stats->iter_valid) {
598 /* Add to list control if not drawn this UE before */
599 gtk_list_store_append(channels_store, &channel_stats->iter);
600 channel_stats->iter_valid = TRUE;
603 /* Set each column for this row */
604 gtk_list_store_set(channels_store, &channel_stats->iter,
605 CHANNEL_NAME, "CCCH",
606 CHANNEL_MODE, print_rlc_channel_mode(channel_stats->rlcMode),
607 CHANNEL_UL_FRAMES, channel_stats->UL_frames,
608 CHANNEL_UL_BYTES, channel_stats->UL_bytes,
609 CHANNEL_DL_FRAMES, channel_stats->DL_frames,
610 CHANNEL_DL_BYTES, channel_stats->DL_bytes,
611 CHANNEL_TABLE_COLUMN, channel_stats,
617 for (n=0; n < 2; n++) {
618 channel_stats = &rlc_stat_ep->stats.srb_stats[n];
619 if (channel_stats->inUse) {
621 /* Calculate bandwidth */
622 float UL_bw = calculate_bw(&channel_stats->UL_time_start,
623 &channel_stats->UL_time_stop,
624 channel_stats->UL_bytes);
625 float DL_bw = calculate_bw(&channel_stats->DL_time_start,
626 &channel_stats->DL_time_stop,
627 channel_stats->DL_bytes);
629 if (!channel_stats->iter_valid) {
630 /* Add to list control if not drawn this UE before */
631 gtk_list_store_append(channels_store, &channel_stats->iter);
632 channel_stats->iter_valid = TRUE;
635 g_snprintf(buff, 32, "SRB-%u", n+1);
637 /* Set each column for this row */
638 gtk_list_store_set(channels_store, &channel_stats->iter,
640 CHANNEL_MODE, print_rlc_channel_mode(channel_stats->rlcMode),
641 CHANNEL_UL_FRAMES, channel_stats->UL_frames,
642 CHANNEL_UL_BYTES, channel_stats->UL_bytes,
643 CHANNEL_UL_BW, UL_bw,
644 CHANNEL_UL_ACKS, channel_stats->UL_acks,
645 CHANNEL_UL_NACKS, channel_stats->UL_nacks,
646 CHANNEL_UL_MISSING, channel_stats->UL_missing,
647 CHANNEL_DL_FRAMES, channel_stats->DL_frames,
648 CHANNEL_DL_BYTES, channel_stats->DL_bytes,
649 CHANNEL_DL_BW, DL_bw,
650 CHANNEL_DL_ACKS, channel_stats->DL_acks,
651 CHANNEL_DL_NACKS, channel_stats->DL_nacks,
652 CHANNEL_DL_MISSING, channel_stats->DL_missing,
653 CHANNEL_TABLE_COLUMN, channel_stats,
660 for (n=0; n < 32; n++) {
661 channel_stats = &rlc_stat_ep->stats.drb_stats[n];
662 if (channel_stats->inUse) {
664 /* Calculate bandwidth */
665 float UL_bw = calculate_bw(&channel_stats->UL_time_start,
666 &channel_stats->UL_time_stop,
667 channel_stats->UL_bytes);
668 float DL_bw = calculate_bw(&channel_stats->DL_time_start,
669 &channel_stats->DL_time_stop,
670 channel_stats->DL_bytes);
672 if (!channel_stats->iter_valid) {
673 /* Add to list control if not drawn this UE before */
674 gtk_list_store_append(channels_store, &channel_stats->iter);
675 channel_stats->iter_valid = TRUE;
678 g_snprintf(buff, 32, "DRB-%u", n+1);
680 /* Set each column for this row */
681 gtk_list_store_set(channels_store, &channel_stats->iter,
683 CHANNEL_MODE, print_rlc_channel_mode(channel_stats->rlcMode),
684 CHANNEL_UL_FRAMES, channel_stats->UL_frames,
685 CHANNEL_UL_BYTES, channel_stats->UL_bytes,
686 CHANNEL_UL_BW, UL_bw,
687 CHANNEL_UL_ACKS, channel_stats->UL_acks,
688 CHANNEL_UL_NACKS, channel_stats->UL_nacks,
689 CHANNEL_UL_MISSING, channel_stats->UL_missing,
690 CHANNEL_DL_FRAMES, channel_stats->DL_frames,
691 CHANNEL_DL_BYTES, channel_stats->DL_bytes,
692 CHANNEL_DL_BW, DL_bw,
693 CHANNEL_DL_ACKS, channel_stats->DL_acks,
694 CHANNEL_DL_NACKS, channel_stats->DL_nacks,
695 CHANNEL_DL_MISSING, channel_stats->DL_missing,
696 CHANNEL_TABLE_COLUMN, channel_stats,
704 /* (Re)draw the whole dialog window */
706 rlc_lte_stat_draw(void *phs)
709 guint16 number_of_ues = 0;
712 /* Look up the statistics window */
713 rlc_lte_stat_t *hs = (rlc_lte_stat_t *)phs;
714 rlc_lte_ep_t* list = hs->ep_list, *tmp = 0;
716 GtkListStore *ues_store;
717 GtkTreeSelection *sel;
720 rlc_channel_stats *channel_stats = NULL;
722 /* Common channel data */
723 g_snprintf(buff, sizeof(buff), "BCCH Frames: %u", hs->common_stats.bcch_frames);
724 gtk_label_set_text(GTK_LABEL(hs->common_bcch_frames), buff);
725 g_snprintf(buff, sizeof(buff), "BCCH Bytes: %u", hs->common_stats.bcch_bytes);
726 gtk_label_set_text(GTK_LABEL(hs->common_bcch_bytes), buff);
727 g_snprintf(buff, sizeof(buff), "PCCH Frames: %u", hs->common_stats.pcch_frames);
728 gtk_label_set_text(GTK_LABEL(hs->common_pcch_frames), buff);
729 g_snprintf(buff, sizeof(buff), "PCCH Bytes: %u", hs->common_stats.pcch_bytes);
730 gtk_label_set_text(GTK_LABEL(hs->common_pcch_bytes), buff);
732 /* Per-UE table entries */
733 ues_store = GTK_LIST_STORE(gtk_tree_view_get_model(hs->ue_table));
735 /* Set title that shows how many UEs currently in table */
736 for (tmp = list; (tmp!=NULL); tmp=tmp->next, number_of_ues++);
737 g_snprintf(title, sizeof(title), "%u UEs", number_of_ues);
738 gtk_frame_set_label(GTK_FRAME(hs->ues_lb), title);
740 /* Update title to include number of UEs and frames */
741 g_snprintf(title, sizeof(title), "Wireshark: LTE RLC Traffic Statistics: %s (%u UEs, %u frames) (filter=\"%s\")",
742 cf_get_display_name(&cfile),
745 strlen(hs->filter) ? hs->filter : "none");
746 gtk_window_set_title(GTK_WINDOW(hs->dlg_w), title);
749 /* For each row/UE in the model */
750 for (tmp = list; tmp; tmp=tmp->next) {
751 /* Calculate bandwidth */
752 float UL_bw = calculate_bw(&tmp->stats.UL_time_start,
753 &tmp->stats.UL_time_stop,
754 tmp->stats.UL_total_bytes);
755 float DL_bw = calculate_bw(&tmp->stats.DL_time_start,
756 &tmp->stats.DL_time_stop,
757 tmp->stats.DL_total_bytes);
759 if (tmp->iter_valid != TRUE) {
760 /* Add to list control if not drawn this UE before */
761 gtk_list_store_append(ues_store, &tmp->iter);
762 tmp->iter_valid = TRUE;
765 /* Set each column for this row */
766 gtk_list_store_set(ues_store, &tmp->iter,
767 UEID_COLUMN, tmp->stats.ueid,
768 UL_FRAMES_COLUMN, tmp->stats.UL_frames,
769 UL_BYTES_COLUMN, tmp->stats.UL_total_bytes,
771 UL_NACKS_COLUMN, tmp->stats.UL_total_nacks,
772 UL_MISSING_COLUMN, tmp->stats.UL_total_missing,
773 DL_FRAMES_COLUMN, tmp->stats.DL_frames,
774 DL_BYTES_COLUMN, tmp->stats.DL_total_bytes,
776 DL_NACKS_COLUMN, tmp->stats.DL_total_nacks,
777 DL_MISSING_COLUMN, tmp->stats.DL_total_missing,
778 UE_TABLE_COLUMN, tmp,
783 if (hs->reselect_ue != 0) {
784 GtkTreeIter *ue_iter = NULL;
785 rlc_lte_ep_t *ep = hs->ep_list;
787 if (ep->stats.ueid == hs->reselect_ue) {
793 if (ue_iter != NULL) {
794 gtk_tree_selection_select_iter(gtk_tree_view_get_selection(hs->ue_table), ue_iter);
798 /* If there is a UE selected, update its counters in details window */
799 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(hs->ue_table));
800 if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
803 gtk_tree_model_get(model, &iter, UE_TABLE_COLUMN, &ep, -1);
804 rlc_lte_channels(ep, hs);
806 /* Reselect channel? */
807 switch (hs->reselect_channel_type) {
808 case CHANNEL_TYPE_CCCH:
809 channel_stats = &(ep->stats.CCCH_stats);
811 case CHANNEL_TYPE_DRB:
812 channel_stats = &(ep->stats.drb_stats[hs->reselect_channel_id-1]);
814 case CHANNEL_TYPE_SRB:
815 channel_stats = &(ep->stats.srb_stats[hs->reselect_channel_id-1]);
821 if ((channel_stats != NULL) && channel_stats->inUse && channel_stats->iter_valid) {
822 gtk_tree_selection_select_iter(gtk_tree_view_get_selection(hs->channel_table), &channel_stats->iter);
827 /* When DCT errors check-box is toggled, enable substring controls accordingly */
828 static void rlc_lte_dct_errors_cb(GtkTreeSelection *sel _U_, gpointer data)
830 rlc_lte_stat_t *hs = (rlc_lte_stat_t*)data;
831 guint8 show_dct_errors = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(hs->show_dct_errors_cb));
833 gtk_widget_set_sensitive(hs->dct_error_substring_lb, show_dct_errors);
834 gtk_widget_set_sensitive(hs->dct_error_substring_te, show_dct_errors);
837 /* What to do when a UE list item is selected/unselected */
838 static void rlc_lte_select_ue_cb(GtkTreeSelection *sel, gpointer data)
843 rlc_lte_stat_t *hs = (rlc_lte_stat_t*)data;
845 if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
846 /* Show details of selected UE */
847 gtk_tree_model_get(model, &iter, UE_TABLE_COLUMN, &ep, -1);
848 hs->reselect_ue = ep->stats.ueid;
849 rlc_lte_channels(ep, hs);
852 rlc_lte_channels(NULL, hs);
855 /* Channel will be deselected */
856 enable_filter_controls(FALSE, 0, hs);
860 /* What to do when a channel list item is selected/unselected */
861 static void rlc_lte_select_channel_cb(GtkTreeSelection *sel, gpointer data)
865 rlc_lte_stat_t *hs = (rlc_lte_stat_t *)data;
867 if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
871 /* Remember selected channel */
872 get_channel_selection(hs, &ueid, &rlcMode,
873 &(hs->reselect_channel_type), &(hs->reselect_channel_id));
876 enable_filter_controls(TRUE, rlcMode, hs);
880 /* No channel selected - disable buttons */
881 enable_filter_controls(FALSE, 0, hs);
886 /* Destroy the stats window */
887 static void win_destroy_cb(GtkWindow *win _U_, gpointer data)
889 rlc_lte_stat_t *hs = (rlc_lte_stat_t *)data;
891 protect_thread_critical_region();
892 remove_tap_listener(hs);
893 unprotect_thread_critical_region();
895 if (hs->dlg_w != NULL) {
896 window_destroy(hs->dlg_w);
899 rlc_lte_stat_reset(hs);
906 toggle_show_mac(GtkWidget *widget, gpointer data)
908 rlc_lte_stat_t *hs = (rlc_lte_stat_t *)data;
911 hs->show_mac = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (widget));
914 cf_retap_packets(&cfile);
919 /* Check that a UE / channel is currently selected. If so, fill in out
920 parameters with details of channel.
921 Return TRUE if a channel is selected */
922 static int get_channel_selection(rlc_lte_stat_t *hs,
923 guint16 *ueid, guint8 *rlcMode,
924 guint16 *channelType, guint16 *channelId)
929 /* Check UE selection */
930 GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(hs->ue_table));
931 if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
934 gtk_tree_model_get(model, &iter, UE_TABLE_COLUMN, &ep, -1);
935 *ueid = ep->stats.ueid;
937 /* Check channel selection */
938 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(hs->channel_table));
939 if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
940 /* Find details of selected channel */
941 rlc_channel_stats *channel_stats;
942 gtk_tree_model_get(model, &iter, CHANNEL_TABLE_COLUMN, &channel_stats, -1);
943 *rlcMode = channel_stats->rlcMode;
944 *channelType = channel_stats->channelType;
945 *channelId = channel_stats->channelId;
959 /* Build and set a display filter to match the given channel settings */
960 typedef enum ChannelDirection_t {UL_Only, DL_Only, UL_and_DL} ChannelDirection_t;
961 static void set_channel_filter_expression(guint16 ueid,
965 ChannelDirection_t channelDirection,
969 const gchar *DCTErrorSubstring,
972 #define MAX_FILTER_LEN 1024
973 static char buffer[MAX_FILTER_LEN];
976 /* Show DCT errors */
978 if (strlen(DCTErrorSubstring) > 0) {
979 offset += g_snprintf(buffer+offset, MAX_FILTER_LEN-offset,
980 "(dct2000.error-comment and (dct2000.comment contains \"%s\")) or (",
984 offset += g_snprintf(buffer+offset, MAX_FILTER_LEN-offset,
985 "dct2000.error-comment or (");
989 /* Include dialog filter */
990 if (strlen(hs->filter)) {
991 offset += g_snprintf(buffer+offset, MAX_FILTER_LEN-offset, "%s and ", hs->filter);
994 /* Should we exclude MAC frames? */
996 offset += g_snprintf(buffer+offset, MAX_FILTER_LEN-offset, "not mac-lte and ");
999 offset += g_snprintf(buffer+offset, MAX_FILTER_LEN-offset, "mac-lte and ");
1003 offset += g_snprintf(buffer+offset, MAX_FILTER_LEN-offset, "(rlc-lte.ueid == %u) and ", ueid);
1004 offset += g_snprintf(buffer+offset, MAX_FILTER_LEN-offset, "(rlc-lte.channel-type == %u)", channelType);
1006 /* Channel-id for srb/drb */
1007 if ((channelType == CHANNEL_TYPE_SRB) || (channelType == CHANNEL_TYPE_DRB)) {
1008 offset += g_snprintf(buffer+offset, MAX_FILTER_LEN-offset, " and (rlc-lte.channel-id == %u)", channelId);
1011 /* Direction (also depends upon RLC mode) */
1012 switch (channelDirection) {
1014 if (rlcMode == RLC_AM_MODE) {
1015 /* Always filter status PDUs */
1016 offset += g_snprintf(buffer+offset, MAX_FILTER_LEN-offset,
1017 " and (rlc-lte.direction == 1 and rlc-lte.am.frame_type == 0)");
1018 if (!statusOnlyPDUs) {
1019 /* Also filter data */
1020 offset += g_snprintf(buffer+offset, MAX_FILTER_LEN-offset,
1021 " or (rlc-lte.direction == 0 and rlc-lte.am.frame_type == 1)");
1025 offset += g_snprintf(buffer+offset, MAX_FILTER_LEN-offset, " and (rlc-lte.direction == 0)");
1029 if (rlcMode == RLC_AM_MODE) {
1030 /* Always filter status PDs */
1031 offset += g_snprintf(buffer+offset, MAX_FILTER_LEN-offset,
1032 " and (rlc-lte.direction == 0 and rlc-lte.am.frame_type == 0)");
1033 if (!statusOnlyPDUs) {
1034 /* Also filter data */
1035 offset += g_snprintf(buffer+offset, MAX_FILTER_LEN-offset,
1036 " or (rlc-lte.direction == 1 and rlc-lte.am.frame_type == 1)");
1040 offset += g_snprintf(buffer+offset, MAX_FILTER_LEN-offset, " and (rlc-lte.direction == 1)");
1044 if (rlcMode == RLC_AM_MODE) {
1045 if (statusOnlyPDUs) {
1046 g_snprintf(buffer+offset, MAX_FILTER_LEN-offset, " and (rlc-lte.am.frame_type == 0)");
1054 /* Filter on a specific sequence number */
1055 if (filterOnSN != -1) {
1058 offset += g_snprintf(buffer+offset, MAX_FILTER_LEN-offset,
1059 " and ((rlc-lte.am.fixed.sn == %u) or "
1060 "(rlc-lte.am.ack-sn == %u) or "
1061 "(rlc-lte.am.nack-sn == %u))",
1062 filterOnSN, (filterOnSN+1) % 1024, filterOnSN);
1065 offset += g_snprintf(buffer+offset, MAX_FILTER_LEN-offset,
1066 " and (rlc-lte.um.sn == %u)", filterOnSN);
1074 /* Close () if open */
1075 if (showDCTErrors) {
1076 offset += g_snprintf(buffer+offset, MAX_FILTER_LEN-offset, ")");
1080 /* Set its value to our new string */
1081 gtk_entry_set_text(GTK_ENTRY(main_display_filter_widget), buffer);
1083 /* Run the filter */
1084 main_filter_packets(&cfile, buffer, TRUE);
1087 /* Respond to UL filter button being clicked by building and using filter */
1088 static void ul_filter_clicked(GtkWindow *win _U_, rlc_lte_stat_t* hs)
1092 guint16 channelType;
1095 const gchar *sn_string = "";
1097 /* Read SN to filter on (if present) */
1098 sn_string = gtk_entry_get_text(GTK_ENTRY(hs->sn_filter_te));
1099 if (strlen(sn_string) > 0) {
1100 sn = atoi(sn_string);
1103 if (!get_channel_selection(hs, &ueid, &rlcMode, &channelType, &channelId)) {
1107 set_channel_filter_expression(ueid, rlcMode, channelType, channelId, UL_Only, sn,
1108 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(hs->show_only_control_pdus_cb)),
1109 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(hs->show_dct_errors_cb)),
1110 gtk_entry_get_text(GTK_ENTRY(hs->dct_error_substring_te)),
1114 /* Respond to DL filter button being clicked by building and using filter */
1115 static void dl_filter_clicked(GtkWindow *win _U_, rlc_lte_stat_t* hs)
1119 guint16 channelType;
1122 const gchar *sn_string = "";
1124 /* Read SN to filter on (if present) */
1125 sn_string = gtk_entry_get_text(GTK_ENTRY(hs->sn_filter_te));
1126 if (strlen(sn_string) > 0) {
1127 sn = atoi(sn_string);
1130 if (!get_channel_selection(hs, &ueid, &rlcMode, &channelType, &channelId)) {
1134 set_channel_filter_expression(ueid, rlcMode, channelType, channelId, DL_Only, sn,
1135 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(hs->show_only_control_pdus_cb)),
1136 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(hs->show_dct_errors_cb)),
1137 gtk_entry_get_text(GTK_ENTRY(hs->dct_error_substring_te)),
1141 /* Respond to UL/DL filter button being clicked by building and using filter */
1142 static void uldl_filter_clicked(GtkWindow *win _U_, rlc_lte_stat_t* hs)
1146 guint16 channelType;
1149 const gchar *sn_string = "";
1151 /* Read SN to filter on (if present) */
1152 sn_string = gtk_entry_get_text(GTK_ENTRY(hs->sn_filter_te));
1153 if (strlen(sn_string) > 0) {
1154 sn = atoi(sn_string);
1157 if (!get_channel_selection(hs, &ueid, &rlcMode, &channelType, &channelId)) {
1161 set_channel_filter_expression(ueid, rlcMode, channelType, channelId, UL_and_DL, sn,
1162 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(hs->show_only_control_pdus_cb)),
1163 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(hs->show_dct_errors_cb)),
1164 gtk_entry_get_text(GTK_ENTRY(hs->dct_error_substring_te)),
1169 /* Create a new RLC LTE stats dialog */
1170 static void gtk_rlc_lte_stat_init(const char *optarg, void *userdata _U_)
1173 const char *filter = NULL;
1174 GString *error_string;
1175 GtkWidget *ues_scrolled_window;
1176 GtkWidget *channels_scrolled_window;
1178 GtkWidget *top_level_vbox;
1180 GtkWidget *pdu_source_lb;
1181 GtkWidget *common_channel_lb;
1182 GtkWidget *channels_lb;
1183 GtkWidget *filter_buttons_lb;
1185 GtkWidget *common_row_hbox;
1186 GtkWidget *show_mac_cb;
1188 GtkWidget *channels_vb;
1189 GtkWidget *filter_vb;
1190 GtkWidget *filter_buttons_hb;
1191 GtkWidget *sn_filter_hb;
1193 GtkWidget *close_bt;
1195 GtkListStore *store;
1197 GtkTreeView *tree_view;
1198 GtkCellRenderer *renderer;
1199 GtkTreeViewColumn *column;
1200 GtkTreeSelection *sel;
1204 /* Check for a filter string */
1205 if (strncmp(optarg, "rlc-lte,stat,", 13) == 0) {
1206 /* Skip those characters from filter to display */
1207 filter = optarg + 13;
1216 hs = g_malloc(sizeof(rlc_lte_stat_t));
1219 /* Copy filter (so can be used for window title at reset) */
1221 hs->filter = g_strdup(filter);
1229 g_snprintf(title, sizeof(title), "Wireshark: LTE RLC Statistics: %s",
1230 cf_get_display_name(&cfile));
1231 hs->dlg_w = window_new_with_geom(GTK_WINDOW_TOPLEVEL, title, "LTE RLC Statistics");
1234 gtk_window_set_default_size(GTK_WINDOW(hs->dlg_w), 750, 300);
1236 /* Will stack widgets vertically inside dlg */
1237 top_level_vbox = gtk_vbox_new(FALSE, 3); /* FALSE = not homogeneous */
1238 gtk_container_add(GTK_CONTAINER(hs->dlg_w), top_level_vbox);
1239 gtk_container_set_border_width(GTK_CONTAINER(top_level_vbox), 6);
1240 gtk_widget_show(top_level_vbox);
1242 /**********************************************/
1243 /* Exclude-MAC checkbox */
1244 pdu_source_lb = gtk_frame_new("PDUs to use");
1245 show_mac_cb = gtk_check_button_new_with_mnemonic("Show RLC PDUs found inside logged MAC frames");
1246 gtk_container_add(GTK_CONTAINER(pdu_source_lb), show_mac_cb);
1247 gtk_widget_set_tooltip_text(show_mac_cb, "Can either use separately-logged RLC PDUs, OR find them "
1248 "decoded inside MAC PDUs (enabled in MAC dissector preferences)");
1251 /* MAC on by default */
1252 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(show_mac_cb), TRUE);
1253 hs->show_mac = TRUE;
1254 gtk_box_pack_start(GTK_BOX(top_level_vbox), pdu_source_lb, FALSE, FALSE, 0);
1255 /* TODO: add tooltips... */
1256 g_signal_connect(show_mac_cb, "toggled", G_CALLBACK(toggle_show_mac), hs);
1259 /**********************************************/
1260 /* Common Channel data */
1261 /**********************************************/
1262 common_channel_lb = gtk_frame_new("Common Channel Data");
1264 /* Will add BCCH and PCCH counters into one row */
1265 common_row_hbox = gtk_hbox_new(FALSE, 0);
1266 gtk_container_add(GTK_CONTAINER(common_channel_lb), common_row_hbox);
1267 gtk_container_set_border_width(GTK_CONTAINER(common_row_hbox), 5);
1268 gtk_box_pack_start(GTK_BOX(top_level_vbox), common_channel_lb, FALSE, FALSE, 0);
1270 /* Create labels (that will hold label and counter value) */
1271 hs->common_bcch_frames = gtk_label_new("BCCH Frames:");
1272 gtk_misc_set_alignment(GTK_MISC(hs->common_bcch_frames), 0.0f, .5f);
1273 gtk_container_add(GTK_CONTAINER(common_row_hbox), hs->common_bcch_frames);
1274 gtk_widget_show(hs->common_bcch_frames);
1276 hs->common_bcch_bytes = gtk_label_new("BCCH Bytes:");
1277 gtk_misc_set_alignment(GTK_MISC(hs->common_bcch_bytes), 0.0f, .5f);
1278 gtk_container_add(GTK_CONTAINER(common_row_hbox), hs->common_bcch_bytes);
1279 gtk_widget_show(hs->common_bcch_bytes);
1281 hs->common_pcch_frames = gtk_label_new("PCCH Frames:");
1282 gtk_misc_set_alignment(GTK_MISC(hs->common_pcch_frames), 0.0f, .5f);
1283 gtk_container_add(GTK_CONTAINER(common_row_hbox), hs->common_pcch_frames);
1284 gtk_widget_show(hs->common_pcch_frames);
1286 hs->common_pcch_bytes = gtk_label_new("PCCH Bytes:");
1287 gtk_misc_set_alignment(GTK_MISC(hs->common_pcch_bytes), 0.0f, .5f);
1288 gtk_container_add(GTK_CONTAINER(common_row_hbox), hs->common_pcch_bytes);
1289 gtk_widget_show(hs->common_pcch_bytes);
1292 /**********************************************/
1294 /**********************************************/
1296 hs->ues_lb = gtk_frame_new("UE Data (0 UEs)");
1297 ues_vb = gtk_vbox_new(FALSE, 0);
1298 gtk_container_add(GTK_CONTAINER(hs->ues_lb), ues_vb);
1299 gtk_container_set_border_width(GTK_CONTAINER(ues_vb), 5);
1301 ues_scrolled_window = scrolled_window_new(NULL, NULL);
1302 gtk_box_pack_start(GTK_BOX(ues_vb), ues_scrolled_window, TRUE, TRUE, 0);
1303 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(ues_scrolled_window),
1306 /* Create the table of UE data */
1307 store = gtk_list_store_new(NUM_UE_COLUMNS, G_TYPE_INT,
1308 G_TYPE_INT, G_TYPE_INT, G_TYPE_FLOAT, G_TYPE_INT, G_TYPE_INT, /* UL */
1309 G_TYPE_INT, G_TYPE_INT, G_TYPE_FLOAT, G_TYPE_INT, G_TYPE_INT, /* DL */
1311 hs->ue_table = GTK_TREE_VIEW(tree_view_new(GTK_TREE_MODEL(store)));
1312 gtk_container_add(GTK_CONTAINER (ues_scrolled_window), GTK_WIDGET(hs->ue_table));
1313 g_object_unref(G_OBJECT(store));
1315 tree_view = hs->ue_table;
1316 gtk_tree_view_set_headers_visible(tree_view, TRUE);
1317 gtk_tree_view_set_headers_clickable(tree_view, TRUE);
1319 /* Create the titles for each column of the per-UE table */
1320 for (i = 0; i < UE_TABLE_COLUMN; i++) {
1321 renderer = gtk_cell_renderer_text_new();
1322 column = gtk_tree_view_column_new_with_attributes(ue_titles[i], renderer,
1324 gtk_tree_view_column_set_sort_column_id(column, i);
1327 /* Expand first column (RNTI, which is Key) */
1328 gtk_tree_view_column_set_expand(column, TRUE);
1330 /* For other columns, set all of the free space to be on the left */
1331 g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL);
1333 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
1334 gtk_tree_view_column_set_resizable(column, TRUE);
1335 gtk_tree_view_append_column(tree_view, column);
1338 /* Set callback function for selecting a row in the UE table */
1339 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(hs->ue_table));
1340 gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
1341 g_signal_connect(sel, "changed", G_CALLBACK(rlc_lte_select_ue_cb), hs);
1343 gtk_box_pack_start(GTK_BOX(top_level_vbox), hs->ues_lb, TRUE, TRUE, 0);
1346 /**********************************************/
1347 /* Channels of selected UE */
1348 /**********************************************/
1349 channels_lb = gtk_frame_new("Channels of selected UE");
1351 channels_vb = gtk_vbox_new(FALSE, 6);
1352 gtk_container_add(GTK_CONTAINER(channels_lb), channels_vb);
1353 gtk_container_set_border_width(GTK_CONTAINER(channels_vb), 5);
1355 channels_scrolled_window = scrolled_window_new(NULL, NULL);
1356 gtk_box_pack_start(GTK_BOX(channels_vb), channels_scrolled_window, TRUE, TRUE, 0);
1357 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(channels_scrolled_window),
1360 /* Create the table of UE data */
1361 store = gtk_list_store_new(NUM_CHANNEL_COLUMNS,
1362 G_TYPE_STRING, G_TYPE_STRING, /* name & type */
1363 G_TYPE_INT, G_TYPE_INT, G_TYPE_FLOAT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, /* UL */
1364 G_TYPE_INT, G_TYPE_INT, G_TYPE_FLOAT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, /* DL */
1366 hs->channel_table = GTK_TREE_VIEW(tree_view_new(GTK_TREE_MODEL(store)));
1367 gtk_container_add(GTK_CONTAINER (channels_scrolled_window), GTK_WIDGET(hs->channel_table));
1368 g_object_unref(G_OBJECT(store));
1370 tree_view = hs->channel_table;
1371 gtk_tree_view_set_headers_visible(tree_view, TRUE);
1372 gtk_tree_view_set_headers_clickable(tree_view, TRUE);
1374 /* Create the titles for each column of the per-UE table */
1375 for (i = 0; i < CHANNEL_TABLE_COLUMN; i++) {
1376 renderer = gtk_cell_renderer_text_new();
1377 column = gtk_tree_view_column_new_with_attributes(channel_titles[i], renderer,
1379 gtk_tree_view_column_set_sort_column_id(column, i);
1382 /* Expand first column (Type) */
1383 gtk_tree_view_column_set_expand(column, TRUE);
1385 /* For other columns, set all of the free space to be on the left */
1386 g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL);
1388 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
1389 gtk_tree_view_column_set_resizable(column, TRUE);
1390 gtk_tree_view_append_column(tree_view, column);
1393 /* Set callback function for selecting a row in the channel table */
1394 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(hs->channel_table));
1395 gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
1396 g_signal_connect(sel, "changed", G_CALLBACK(rlc_lte_select_channel_cb), hs);
1398 gtk_box_pack_start(GTK_BOX(top_level_vbox), channels_lb, TRUE, TRUE, 0);
1401 /**********************************************/
1402 /* Channel filters */
1403 /**********************************************/
1405 filter_buttons_lb = gtk_frame_new("Filter on selected channel");
1407 filter_vb = gtk_vbox_new(FALSE, 3);
1408 gtk_container_add(GTK_CONTAINER(filter_buttons_lb), filter_vb);
1410 /* Horizontal row of filter buttons */
1411 filter_buttons_hb = gtk_hbox_new(FALSE, 6);
1412 gtk_container_add(GTK_CONTAINER(filter_vb), filter_buttons_hb);
1413 gtk_container_set_border_width(GTK_CONTAINER(filter_buttons_hb), 2);
1416 hs->ul_filter_bt = gtk_button_new_with_label("Set UL display filter for this channel");
1417 gtk_box_pack_start(GTK_BOX(filter_buttons_hb), hs->ul_filter_bt, TRUE, TRUE, 0);
1418 g_signal_connect(hs->ul_filter_bt, "clicked", G_CALLBACK(ul_filter_clicked), hs);
1419 gtk_widget_show(hs->ul_filter_bt);
1420 gtk_widget_set_tooltip_text(hs->ul_filter_bt, "Generate and set a display filter to show frames "
1421 "associated with the channel, in the UL direction only. "
1422 "N.B. DL Status PDUs sent on this channel will also be shown for AM");
1425 hs->dl_filter_bt = gtk_button_new_with_label("Set DL display filter for this channel");
1426 gtk_box_pack_start(GTK_BOX(filter_buttons_hb), hs->dl_filter_bt, TRUE, TRUE, 0);
1427 g_signal_connect(hs->dl_filter_bt, "clicked", G_CALLBACK(dl_filter_clicked), hs);
1428 gtk_widget_show(hs->dl_filter_bt);
1429 gtk_widget_set_tooltip_text(hs->dl_filter_bt, "Generate and set a display filter to show frames "
1430 "associated with the channel, in the DL direction only. "
1431 "N.B. UL Status PDUs sent on this channel will also be shown for AM");
1434 hs->uldl_filter_bt = gtk_button_new_with_label("Set UL / DL display filter for this channel");
1435 gtk_box_pack_start(GTK_BOX(filter_buttons_hb), hs->uldl_filter_bt, TRUE, TRUE, 0);
1436 g_signal_connect(hs->uldl_filter_bt, "clicked", G_CALLBACK(uldl_filter_clicked), hs);
1437 gtk_widget_show(hs->uldl_filter_bt);
1438 gtk_widget_set_tooltip_text(hs->uldl_filter_bt, "Generate and set a display filter to show frames "
1439 "associated with the channel, in UL and DL");
1441 /* Allow filtering on specific SN number. */
1442 /* Row with label and text entry control */
1443 sn_filter_hb = gtk_hbox_new(FALSE, 3);
1444 gtk_container_add(GTK_CONTAINER(filter_vb), sn_filter_hb);
1445 gtk_widget_show(sn_filter_hb);
1447 /* Allow filtering only to select status PDUs for AM */
1448 hs->show_only_control_pdus_cb = gtk_check_button_new_with_mnemonic("Show only status PDUs");
1449 gtk_container_add(GTK_CONTAINER(sn_filter_hb), hs->show_only_control_pdus_cb);
1450 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(hs->show_only_control_pdus_cb), FALSE);
1451 gtk_widget_set_tooltip_text(hs->show_only_control_pdus_cb, "Generated filters will only show AM status PDUs "
1452 "(i.e. if you filter on UL you'll see ACKs/NACK replies sent in the DL)");
1454 /* Allow DCT errors to be shown... */
1455 hs->show_dct_errors_cb = gtk_check_button_new_with_mnemonic("Show DCT2000 error strings...");
1456 gtk_container_add(GTK_CONTAINER(sn_filter_hb), hs->show_dct_errors_cb);
1457 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(hs->show_dct_errors_cb), FALSE);
1458 g_signal_connect(hs->show_dct_errors_cb, "toggled", G_CALLBACK(rlc_lte_dct_errors_cb), hs);
1459 gtk_widget_set_tooltip_text(hs->show_dct_errors_cb, "When checked, generated filters will "
1460 "include DCT2000 error strings");
1462 /* ... optionally limited by a substring */
1463 hs->dct_error_substring_lb = gtk_label_new("...containing");
1464 gtk_box_pack_start(GTK_BOX(sn_filter_hb), hs->dct_error_substring_lb, FALSE, FALSE, 0);
1465 gtk_widget_show(hs->dct_error_substring_lb);
1467 hs->dct_error_substring_te = gtk_entry_new();
1468 gtk_box_pack_start(GTK_BOX(sn_filter_hb), hs->dct_error_substring_te, FALSE, FALSE, 0);
1469 gtk_widget_show(hs->dct_error_substring_te);
1470 gtk_widget_set_tooltip_text(hs->dct_error_substring_te,
1471 "If given, only match error strings containing this substring");
1473 /* Allow filtering of a particular sequence number */
1474 hs->sn_filter_te = gtk_entry_new();
1475 gtk_box_pack_end(GTK_BOX(sn_filter_hb), hs->sn_filter_te, FALSE, FALSE, 0);
1476 gtk_widget_show(hs->sn_filter_te);
1477 gtk_widget_set_tooltip_text(hs->sn_filter_te, "Can limit generated filters to a given sequence number (0-1023). "
1478 "Will also include relevant AM status PDUs");
1480 hs->sn_filter_lb = gtk_label_new("Sequence number to filter on:");
1481 gtk_box_pack_end(GTK_BOX(sn_filter_hb), hs->sn_filter_lb, FALSE, FALSE, 0);
1482 gtk_widget_show(hs->sn_filter_lb);
1485 /* Add filters box to top-level window */
1486 gtk_box_pack_start(GTK_BOX(top_level_vbox), filter_buttons_lb, FALSE, FALSE, 0);
1488 enable_filter_controls(FALSE, 0, hs);
1490 /**********************************************/
1491 /* Register the tap listener */
1492 /**********************************************/
1494 error_string = register_tap_listener("rlc-lte", hs,
1497 rlc_lte_stat_packet,
1500 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", error_string->str);
1501 g_string_free(error_string, TRUE);
1507 /************************************/
1508 /* Bottom button row. */
1509 /************************************/
1511 bbox = dlg_button_row_new(GTK_STOCK_CLOSE, GTK_STOCK_HELP, NULL);
1512 gtk_box_pack_end(GTK_BOX(top_level_vbox), bbox, FALSE, FALSE, 0);
1514 /* Add the close button */
1515 close_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_CLOSE);
1516 window_set_cancel_button(hs->dlg_w, close_bt, window_cancel_button_cb);
1518 help_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_HELP);
1519 g_signal_connect(help_bt, "clicked", G_CALLBACK(topic_cb), (gpointer)HELP_STATS_LTE_RLC_TRAFFIC_DIALOG);
1522 g_signal_connect(hs->dlg_w, "delete_event", G_CALLBACK(window_delete_event_cb), NULL);
1523 g_signal_connect(hs->dlg_w, "destroy", G_CALLBACK(win_destroy_cb), hs);
1525 /* Show the window */
1526 gtk_widget_show_all(hs->dlg_w);
1527 window_present(hs->dlg_w);
1530 cf_retap_packets(&cfile);
1531 gdk_window_raise(gtk_widget_get_window(hs->dlg_w));
1535 static tap_param rlc_lte_stat_params[] = {
1536 { PARAM_FILTER, "Filter", NULL }
1539 static tap_param_dlg rlc_lte_stat_dlg = {
1542 gtk_rlc_lte_stat_init,
1544 G_N_ELEMENTS(rlc_lte_stat_params),
1549 /* Register this tap listener (need void on own so line register function found) */
1551 register_tap_listener_rlc_lte_stat(void)
1553 register_dfilter_stat(&rlc_lte_stat_dlg, "_LTE/_RLC", REGISTER_STAT_GROUP_TELEPHONY);
1555 #ifdef MAIN_MENU_USE_UIMANAGER
1556 void rlc_lte_stat_cb(GtkAction *action, gpointer user_data _U_)
1558 tap_param_dlg_cb(action, &rlc_lte_stat_dlg);