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
28 - apply top-level filter (e.g. to tap only one sector)
29 - common channel stats
36 #ifdef HAVE_SYS_TYPES_H
37 #include <sys/types.h>
44 #include "gtk/gtkglobals.h"
46 #include <epan/packet.h>
47 #include <epan/packet_info.h>
49 #include <epan/dissectors/packet-rlc-lte.h>
51 #include "../register.h"
52 #include "../simple_dialog.h"
53 #include "../stat_menu.h"
55 #include "gtk/dlg_utils.h"
56 #include "gtk/gui_stat_menu.h"
57 #include "gtk/gui_utils.h"
58 #include "gtk/help_dlg.h"
61 /**********************************************/
62 /* Table column identifiers and title strings */
89 static const gchar *ue_titles[] = { "UEId",
90 "UL Frames", "UL Bytes",
91 "DL Frames", "DL Bytes"};
93 static const gchar *channel_titles[] = { "", "Mode",
94 "UL Frames", "UL Bytes", "UL ACKs", "UL NACKs",
95 "DL Frames", "DL Bytes", "DL ACKs", "DL NACKs"};
97 /* Stats kept for one channel */
98 typedef struct rlc_channel_stats {
119 /* Stats for one UE */
120 typedef struct rlc_lte_row_data {
121 /* Key for matching this row */
124 gboolean is_predefined_data;
127 guint32 UL_total_bytes;
130 guint32 DL_total_bytes;
132 rlc_channel_stats CCCH_stats;
133 rlc_channel_stats srb_stats[2];
134 rlc_channel_stats drb_stats[32];
138 /* One row/UE in the UE table */
139 typedef struct rlc_lte_ep {
140 struct rlc_lte_ep* next;
141 struct rlc_lte_row_data stats;
147 /* Top-level dialog and labels */
148 static GtkWidget *rlc_lte_stat_dlg_w = NULL;
149 static GtkWidget *rlc_lte_stat_ues_lb = NULL;
150 static GtkWidget *rlc_lte_stat_channels_lb = NULL;
151 static GtkWidget *rlc_lte_stat_filter_buttons_lb = NULL;
153 GtkWidget *ul_filter_bt;
154 GtkWidget *dl_filter_bt;
155 GtkWidget *uldl_filter_bt;
157 gboolean s_show_mac = FALSE;
161 /* Used to keep track of whole RLC LTE statistics window */
162 typedef struct rlc_lte_stat_t {
163 GtkTreeView *ue_table;
164 rlc_lte_ep_t *ep_list;
165 guint32 total_frames;
167 GtkTreeView *channel_table;
171 static void enable_filter_buttons(guint8 enabled)
173 gtk_widget_set_sensitive(ul_filter_bt, enabled);
174 gtk_widget_set_sensitive(dl_filter_bt, enabled);
175 gtk_widget_set_sensitive(uldl_filter_bt, enabled);
180 /* Reset the statistics window */
182 rlc_lte_stat_reset(void *phs)
184 rlc_lte_stat_t* rlc_lte_stat = (rlc_lte_stat_t *)phs;
185 rlc_lte_ep_t* list = rlc_lte_stat->ep_list;
190 if (rlc_lte_stat_dlg_w != NULL) {
191 g_snprintf(title, sizeof(title), "Wireshark: LTE RLC Traffic Statistics: %s",
192 cf_get_display_name(&cfile));
193 gtk_window_set_title(GTK_WINDOW(rlc_lte_stat_dlg_w), title);
196 g_snprintf(title, sizeof(title), "0 UEs");
197 gtk_frame_set_label(GTK_FRAME(rlc_lte_stat_ues_lb), title);
199 rlc_lte_stat->total_frames = 0;
201 /* Remove all entries from the UE list */
202 store = GTK_LIST_STORE(gtk_tree_view_get_model(rlc_lte_stat->ue_table));
203 gtk_list_store_clear(store);
209 rlc_lte_stat->ep_list = NULL;
213 /* Allocate a rlc_lte_ep_t struct to store info for new UE */
214 static rlc_lte_ep_t* alloc_rlc_lte_ep(struct rlc_lte_tap_info *si, packet_info *pinfo _U_)
223 if (!(ep = g_malloc(sizeof(rlc_lte_ep_t)))) {
227 /* Copy SI data into ep->stats */
228 ep->stats.ueid = si->ueid;
230 /* Counts for new UE are all 0 */
231 ep->stats.UL_frames = 0;
232 ep->stats.DL_frames = 0;
233 ep->stats.UL_total_bytes = 0;
234 ep->stats.DL_total_bytes = 0;
236 memset(&ep->stats.CCCH_stats, 0, sizeof(rlc_channel_stats));
237 for (n=0; n < 2; n++) {
238 memset(&ep->stats.srb_stats[n], 0, sizeof(rlc_channel_stats));
240 for (n=0; n < 32; n++) {
241 memset(&ep->stats.drb_stats[n], 0, sizeof(rlc_channel_stats));
245 ep->iter_valid = FALSE;
251 /* Return string for RLC mode for display */
252 static const char *print_rlc_channel_mode(guint8 mode)
254 static char unknown[16];
257 case RLC_TM_MODE: return "TM";
258 case RLC_UM_MODE: return "UM";
259 case RLC_AM_MODE: return "AM";
260 case RLC_PREDEF: return "Predef";
263 g_snprintf(unknown, 32, "Unknown (%u)", mode);
269 /* Process stat struct for a RLC LTE frame */
271 rlc_lte_stat_packet(void *phs, packet_info *pinfo, epan_dissect_t *edt _U_,
274 /* Get reference to stat window instance */
275 rlc_lte_stat_t *hs = (rlc_lte_stat_t *)phs;
276 rlc_lte_ep_t *tmp = NULL, *te = NULL;
277 rlc_channel_stats *channel_stats = NULL;
279 /* Cast tap info struct */
280 struct rlc_lte_tap_info *si = (struct rlc_lte_tap_info *)phi;
287 /* Are we ignoring RLC frames that were found in MAC frames, or only those
288 that were logged separately? */
289 if (!s_show_mac && si->loggedInMACFrame) {
293 /* Inc top-level frame count */
296 /* For per-UE data, must create a new row if none already existing */
298 /* Allocate new list */
299 hs->ep_list = alloc_rlc_lte_ep(si, pinfo);
300 /* Make it the first/only entry */
303 /* Look among existing rows for this UEId */
304 for (tmp = hs->ep_list;(tmp != NULL); tmp = tmp->next) {
305 if (tmp->stats.ueid == si->ueid) {
311 /* Not found among existing, so create a new one anyway */
313 if ((te = alloc_rlc_lte_ep(si, pinfo))) {
314 /* Add new item to end of list */
315 rlc_lte_ep_t *p = hs->ep_list;
325 /* Really should have a row pointer by now */
330 /* Update entry with details from si */
331 te->stats.ueid = si->ueid;
333 /* Top-level traffic stats */
334 if (si->direction == DIRECTION_UPLINK) {
335 te->stats.UL_frames++;
336 te->stats.UL_total_bytes += si->pduLength;
339 te->stats.DL_frames++;
340 te->stats.DL_total_bytes += si->pduLength;
343 /* Find channel struct */
344 switch (si->channelType) {
345 case CHANNEL_TYPE_CCCH:
346 channel_stats = &te->stats.CCCH_stats;
349 case CHANNEL_TYPE_SRB:
350 channel_stats = &te->stats.srb_stats[si->channelId-1];
353 case CHANNEL_TYPE_DRB:
354 channel_stats = &te->stats.drb_stats[si->channelId-1];
357 case CHANNEL_TYPE_BCCH:
358 case CHANNEL_TYPE_PCCH:
359 /* TODO: count these common channels separately? */
363 if (channel_stats != NULL) {
364 channel_stats->inUse = TRUE;
365 channel_stats->iter_valid = FALSE;
366 channel_stats->rlcMode = si->rlcMode;
367 channel_stats->channelType = si->channelType;
368 channel_stats->channelId = si->channelId;
371 if (si->direction == DIRECTION_UPLINK) {
372 channel_stats->UL_frames++;
373 channel_stats->UL_bytes += si->pduLength;
374 channel_stats->UL_nacks += si->noOfNACKs;
375 if (si->isControlPDU) {
376 channel_stats->UL_acks++;
380 channel_stats->DL_frames++;
381 channel_stats->DL_bytes += si->pduLength;
382 channel_stats->DL_nacks += si->noOfNACKs;
383 if (si->isControlPDU) {
384 channel_stats->DL_acks++;
392 /* The channels for any UE would need to be re-added to the list */
393 static void invalidate_channel_iters(rlc_lte_stat_t *hs)
396 rlc_lte_ep_t *ep = hs->ep_list;
399 ep->stats.CCCH_stats.iter_valid = FALSE;
400 for (n=0; n < 2; n++) {
401 ep->stats.srb_stats[n].iter_valid = FALSE;
403 for (n=0; n < 32; n++) {
404 ep->stats.drb_stats[n].iter_valid = FALSE;
412 /* Draw the channels table according to the current UE selection */
414 rlc_lte_channels(rlc_lte_ep_t *rlc_stat_ep, rlc_lte_stat_t *hs)
416 GtkListStore *channels_store = GTK_LIST_STORE(gtk_tree_view_get_model(hs->channel_table));
417 rlc_channel_stats *channel_stats;
421 /* Clear any existing rows */
422 gtk_list_store_clear(channels_store);
423 invalidate_channel_iters(hs);
425 if (rlc_stat_ep == NULL) {
429 /* Add one row for each channel */
432 channel_stats = &rlc_stat_ep->stats.CCCH_stats;
433 if (channel_stats->inUse) {
435 if (!channel_stats->iter_valid) {
436 /* Add to list control if not drawn this UE before */
437 gtk_list_store_append(channels_store, &channel_stats->iter);
438 channel_stats->iter_valid = TRUE;
441 /* Set each column for this row */
442 gtk_list_store_set(channels_store, &channel_stats->iter,
443 CHANNEL_NAME, "CCCH",
444 CHANNEL_MODE, print_rlc_channel_mode(channel_stats->rlcMode),
445 CHANNEL_UL_FRAMES, channel_stats->UL_frames,
446 CHANNEL_UL_BYTES, channel_stats->UL_bytes,
447 CHANNEL_DL_FRAMES, channel_stats->DL_frames,
448 CHANNEL_DL_BYTES, channel_stats->DL_bytes,
449 CHANNEL_TABLE_COLUMN, channel_stats,
455 for (n=0; n < 2; n++) {
456 channel_stats = &rlc_stat_ep->stats.srb_stats[n];
457 if (channel_stats->inUse) {
459 if (!channel_stats->iter_valid) {
460 /* Add to list control if not drawn this UE before */
461 gtk_list_store_append(channels_store, &channel_stats->iter);
462 channel_stats->iter_valid = TRUE;
465 g_snprintf(buff, 32, "SRB-%u", n+1);
467 /* Set each column for this row */
468 gtk_list_store_set(channels_store, &channel_stats->iter,
470 CHANNEL_MODE, print_rlc_channel_mode(channel_stats->rlcMode),
471 CHANNEL_UL_FRAMES, channel_stats->UL_frames,
472 CHANNEL_UL_BYTES, channel_stats->UL_bytes,
473 CHANNEL_UL_ACKS, channel_stats->UL_acks,
474 CHANNEL_UL_NACKS, channel_stats->UL_nacks,
475 CHANNEL_DL_FRAMES, channel_stats->DL_frames,
476 CHANNEL_DL_BYTES, channel_stats->DL_bytes,
477 CHANNEL_DL_ACKS, channel_stats->DL_acks,
478 CHANNEL_DL_NACKS, channel_stats->DL_nacks,
479 CHANNEL_TABLE_COLUMN, channel_stats,
486 for (n=0; n < 32; n++) {
487 channel_stats = &rlc_stat_ep->stats.drb_stats[n];
488 if (channel_stats->inUse) {
490 if (!channel_stats->iter_valid) {
491 /* Add to list control if not drawn this UE before */
492 gtk_list_store_append(channels_store, &channel_stats->iter);
493 channel_stats->iter_valid = TRUE;
496 g_snprintf(buff, 32, "DRB-%u", n+1);
498 /* Set each column for this row */
499 gtk_list_store_set(channels_store, &channel_stats->iter,
501 CHANNEL_MODE, print_rlc_channel_mode(channel_stats->rlcMode),
502 CHANNEL_UL_FRAMES, channel_stats->UL_frames,
503 CHANNEL_UL_BYTES, channel_stats->UL_bytes,
504 CHANNEL_UL_ACKS, channel_stats->UL_acks,
505 CHANNEL_UL_NACKS, channel_stats->UL_nacks,
506 CHANNEL_DL_FRAMES, channel_stats->DL_frames,
507 CHANNEL_DL_BYTES, channel_stats->DL_bytes,
508 CHANNEL_DL_ACKS, channel_stats->DL_acks,
509 CHANNEL_DL_NACKS, channel_stats->DL_nacks,
510 CHANNEL_TABLE_COLUMN, channel_stats,
518 /* (Re)draw the whole dialog window */
520 rlc_lte_stat_draw(void *phs)
522 guint16 number_of_ues = 0;
525 /* Look up the statistics window */
526 rlc_lte_stat_t *hs = (rlc_lte_stat_t *)phs;
527 rlc_lte_ep_t* list = hs->ep_list, *tmp = 0;
529 GtkListStore *ues_store;
530 GtkTreeSelection *sel;
535 /* Per-UE table entries */
536 ues_store = GTK_LIST_STORE(gtk_tree_view_get_model(hs->ue_table));
538 /* Set title that shows how many UEs currently in table */
539 for (tmp = list; (tmp!=NULL); tmp=tmp->next, number_of_ues++);
540 g_snprintf(title, sizeof(title), "%u UEs", number_of_ues);
541 gtk_frame_set_label(GTK_FRAME(rlc_lte_stat_ues_lb), title);
543 /* Update title to include number of UEs and frames */
544 g_snprintf(title, sizeof(title), "Wireshark: LTE RLC Traffic Statistics: %s (%u UEs, %u frames)",
545 cf_get_display_name(&cfile),
548 gtk_window_set_title(GTK_WINDOW(rlc_lte_stat_dlg_w), title);
551 /* For each row/UE in the model */
552 for (tmp = list; tmp; tmp=tmp->next) {
553 if (tmp->iter_valid != TRUE) {
554 /* Add to list control if not drawn this UE before */
555 gtk_list_store_append(ues_store, &tmp->iter);
556 tmp->iter_valid = TRUE;
559 /* Set each column for this row */
560 gtk_list_store_set(ues_store, &tmp->iter,
561 UEID_COLUMN, tmp->stats.ueid,
562 UL_FRAMES_COLUMN, tmp->stats.UL_frames,
563 UL_BYTES_COLUMN, tmp->stats.UL_total_bytes,
564 DL_FRAMES_COLUMN, tmp->stats.DL_frames,
565 DL_BYTES_COLUMN, tmp->stats.DL_total_bytes,
570 /* If there is a UE selected, update its counters in details window */
571 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(hs->ue_table));
572 if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
575 gtk_tree_model_get(model, &iter, TABLE_COLUMN, &ep, -1);
576 rlc_lte_channels(ep, hs);
581 /* What to do when a UE list item is selected/unselected */
582 static void rlc_lte_select_ue_cb(GtkTreeSelection *sel, gpointer data)
588 if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
589 /* Show details of selected UE */
590 gtk_tree_model_get(model, &iter, TABLE_COLUMN, &ep, -1);
591 rlc_lte_channels(ep, (rlc_lte_stat_t*)data);
594 rlc_lte_channels(NULL, (rlc_lte_stat_t*)data);
597 /* Channel will be deselected */
598 enable_filter_buttons(FALSE);
602 /* What to do when a channel list item is selected/unselected */
603 static void rlc_lte_select_channel_cb(GtkTreeSelection *sel, gpointer data _U_)
609 if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
611 enable_filter_buttons(TRUE);
613 /* Show details of selected UE */
614 gtk_tree_model_get(model, &iter, TABLE_COLUMN, &ep, -1);
617 /* Disable buttons */
618 enable_filter_buttons(FALSE);
623 /* Destroy the stats window */
624 static void win_destroy_cb(GtkWindow *win _U_, gpointer data)
626 rlc_lte_stat_t *hs = (rlc_lte_stat_t *)data;
628 protect_thread_critical_region();
629 remove_tap_listener(hs);
630 unprotect_thread_critical_region();
632 if (rlc_lte_stat_dlg_w != NULL) {
633 window_destroy(rlc_lte_stat_dlg_w);
634 rlc_lte_stat_dlg_w = NULL;
636 rlc_lte_stat_reset(hs);
643 toggle_show_mac(GtkWidget *widget, gpointer data _U_)
646 s_show_mac = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (widget));
649 cf_retap_packets(&cfile);
653 /* Check that a UE / channel is currently selected. If so, fill in out
654 parameters with details of channel.
655 Return TRUE if a channel is selected */
656 static int get_channel_selection(rlc_lte_stat_t *hs,
657 guint16 *ueid, guint8 *rlcMode,
658 guint16 *channelType, guint16 *channelId)
663 /* Check UE selection */
664 GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(hs->ue_table));
665 if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
668 gtk_tree_model_get(model, &iter, TABLE_COLUMN, &ep, -1);
669 *ueid = ep->stats.ueid;
671 /* Check channel selection */
672 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(hs->channel_table));
673 if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
674 /* Find details of selected channel */
675 rlc_channel_stats *channel_stats;
676 gtk_tree_model_get(model, &iter, CHANNEL_TABLE_COLUMN, &channel_stats, -1);
677 *rlcMode = channel_stats->rlcMode;
678 *channelType = channel_stats->channelType;
679 *channelId = channel_stats->channelId;
693 /* Build and set a display filter to match the given channel settings */
694 typedef enum ChannelDirection_t {UL_Only, DL_Only, UL_and_DL} ChannelDirection_t;
695 static void set_channel_filter_expression(guint16 ueid,
699 ChannelDirection_t channelDirection)
701 static char buffer[256];
704 /* Should we exclude MAC frames? */
706 offset += g_snprintf(buffer+offset, 256-offset, "not mac-lte and ");
710 offset += g_snprintf(buffer+offset, 256-offset, "(rlc-lte.ueid == %u) and ", ueid);
711 offset += g_snprintf(buffer+offset, 256-offset, "(rlc-lte.channel-type == %u)", channelType);
713 /* Channel-id for srb/drb */
714 if ((channelType == CHANNEL_TYPE_SRB) || (channelType == CHANNEL_TYPE_DRB)) {
715 offset += g_snprintf(buffer+offset, 256-offset, " and (rlc-lte.channel-id == %u)", channelId);
718 /* Direction (also depends upon RLC mode) */
719 switch (channelDirection) {
721 if (rlcMode == RLC_AM_MODE) {
722 offset += g_snprintf(buffer+offset, 256-offset,
723 " and (rlc-lte.direction == 0 and rlc-lte.am.frame_type == 1) or "
724 "(rlc-lte.direction == 1 and rlc-lte.am.frame_type == 0)");
727 offset += g_snprintf(buffer+offset, 256-offset, " and (rlc-lte.direction == 0)");
731 if (rlcMode == RLC_AM_MODE) {
732 offset += g_snprintf(buffer+offset, 256-offset,
733 " and (rlc-lte.direction == 1 and rlc-lte.am.frame_type == 1) or "
734 "(rlc-lte.direction == 0 and rlc-lte.am.frame_type == 0)");
737 offset += g_snprintf(buffer+offset, 256-offset, " and (rlc-lte.direction == 1)");
745 /* Set its value to our new string */
746 gtk_entry_set_text(GTK_ENTRY(main_display_filter_widget), buffer);
749 main_filter_packets(&cfile, buffer, TRUE);
752 /* Respond to UL filter button being clicked by building and using filter */
753 static void ul_filter_clicked(GtkWindow *win _U_, rlc_lte_stat_t* hs)
760 if (!get_channel_selection(hs, &ueid, &rlcMode, &channelType, &channelId)) {
764 set_channel_filter_expression(ueid, rlcMode, channelType, channelId, UL_Only);
767 /* Respond to DL filter button being clicked by building and using filter */
768 static void dl_filter_clicked(GtkWindow *win _U_, rlc_lte_stat_t* hs)
775 if (!get_channel_selection(hs, &ueid, &rlcMode, &channelType, &channelId)) {
779 set_channel_filter_expression(ueid, rlcMode, channelType, channelId, DL_Only);
782 /* Respond to UL/DL filter button being clicked by building and using filter */
783 static void uldl_filter_clicked(GtkWindow *win _U_, rlc_lte_stat_t* hs)
790 if (!get_channel_selection(hs, &ueid, &rlcMode, &channelType, &channelId)) {
794 set_channel_filter_expression(ueid, rlcMode, channelType, channelId, UL_and_DL);
798 /* Create a new RLC LTE stats dialog */
799 static void rlc_lte_stat_dlg_create(void)
802 GString *error_string;
803 GtkWidget *ues_scrolled_window;
804 GtkWidget *channels_scrolled_window;
806 GtkWidget *top_level_vbox;
808 GtkWidget *show_mac_cb;
810 GtkWidget *channels_vb;
811 GtkWidget *filter_buttons_hb;
818 GtkTreeView *tree_view;
819 GtkCellRenderer *renderer;
820 GtkTreeViewColumn *column;
821 GtkTreeSelection *sel;
826 hs = g_malloc(sizeof(rlc_lte_stat_t));
830 g_snprintf(title, sizeof(title), "Wireshark: LTE RLC Statistics: %s",
831 cf_get_display_name(&cfile));
832 rlc_lte_stat_dlg_w = window_new_with_geom(GTK_WINDOW_TOPLEVEL, title, "LTE RLC Statistics");
835 gtk_window_set_default_size(GTK_WINDOW(rlc_lte_stat_dlg_w), 750, 300);
837 /* Will stack widgets vertically inside dlg */
838 top_level_vbox = gtk_vbox_new(FALSE, 3); /* FALSE = not homogeneous */
839 gtk_container_add(GTK_CONTAINER(rlc_lte_stat_dlg_w), top_level_vbox);
841 gtk_container_set_border_width(GTK_CONTAINER(top_level_vbox), 6);
842 gtk_widget_show(top_level_vbox);
844 /**********************************************/
845 /* Exclude-MAC checkbox */
846 show_mac_cb = gtk_check_button_new_with_mnemonic("Show RLC PDUs found inside logged MAC frames");
847 gtk_container_add(GTK_CONTAINER(top_level_vbox), show_mac_cb);
848 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(show_mac_cb), FALSE);
849 /* TODO: add tooltip */
850 g_signal_connect(show_mac_cb, "toggled", G_CALLBACK(toggle_show_mac), hs);
853 /**********************************************/
855 /**********************************************/
857 rlc_lte_stat_ues_lb = gtk_frame_new("UE Data (0 UEs)");
858 ues_vb = gtk_vbox_new(FALSE, 0);
859 gtk_container_add(GTK_CONTAINER(rlc_lte_stat_ues_lb), ues_vb);
860 gtk_container_set_border_width(GTK_CONTAINER(ues_vb), 5);
862 ues_scrolled_window = scrolled_window_new(NULL, NULL);
863 gtk_box_pack_start(GTK_BOX(ues_vb), ues_scrolled_window, TRUE, TRUE, 0);
864 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(ues_scrolled_window),
867 /* Create the table of UE data */
868 store = gtk_list_store_new(NUM_UE_COLUMNS, G_TYPE_INT,
869 G_TYPE_INT, G_TYPE_INT, /* UL */
870 G_TYPE_INT, G_TYPE_INT, /* DL */
872 hs->ue_table = GTK_TREE_VIEW(tree_view_new(GTK_TREE_MODEL(store)));
873 gtk_container_add(GTK_CONTAINER (ues_scrolled_window), GTK_WIDGET(hs->ue_table));
874 g_object_unref(G_OBJECT(store));
876 tree_view = hs->ue_table;
877 gtk_tree_view_set_headers_visible(tree_view, TRUE);
878 gtk_tree_view_set_headers_clickable(tree_view, TRUE);
880 /* Create the titles for each column of the per-UE table */
881 for (i = 0; i < TABLE_COLUMN; i++) {
882 renderer = gtk_cell_renderer_text_new();
883 column = gtk_tree_view_column_new_with_attributes(ue_titles[i], renderer,
885 gtk_tree_view_column_set_sort_column_id(column, i);
888 /* Expand first column (RNTI, which is Key) */
889 gtk_tree_view_column_set_expand(column, TRUE);
891 /* For other columns, set all of the free space to be on the left */
892 g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL);
894 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
895 gtk_tree_view_column_set_resizable(column, TRUE);
896 gtk_tree_view_append_column(tree_view, column);
899 /* Set callback function for selecting a row in the UE table */
900 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(hs->ue_table));
901 gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
902 g_signal_connect(sel, "changed", G_CALLBACK(rlc_lte_select_ue_cb), hs);
904 gtk_box_pack_start(GTK_BOX(top_level_vbox), rlc_lte_stat_ues_lb, TRUE, TRUE, 0);
907 /**********************************************/
908 /* Channels of selected UE */
909 /**********************************************/
910 rlc_lte_stat_channels_lb = gtk_frame_new("Channels of selected UE");
912 channels_vb = gtk_vbox_new(FALSE, 6);
913 gtk_container_add(GTK_CONTAINER(rlc_lte_stat_channels_lb), channels_vb);
914 gtk_container_set_border_width(GTK_CONTAINER(channels_vb), 5);
916 channels_scrolled_window = scrolled_window_new(NULL, NULL);
917 gtk_box_pack_start(GTK_BOX(channels_vb), channels_scrolled_window, TRUE, TRUE, 0);
918 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(channels_scrolled_window),
921 /* Create the table of UE data */
922 store = gtk_list_store_new(NUM_CHANNEL_COLUMNS,
923 G_TYPE_STRING, G_TYPE_STRING, /* name & type */
924 G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, /* UL */
925 G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, /* DL */
927 hs->channel_table = GTK_TREE_VIEW(tree_view_new(GTK_TREE_MODEL(store)));
928 gtk_container_add(GTK_CONTAINER (channels_scrolled_window), GTK_WIDGET(hs->channel_table));
929 g_object_unref(G_OBJECT(store));
931 tree_view = hs->channel_table;
932 gtk_tree_view_set_headers_visible(tree_view, TRUE);
933 gtk_tree_view_set_headers_clickable(tree_view, TRUE);
935 /* Create the titles for each column of the per-UE table */
936 for (i = 0; i < CHANNEL_TABLE_COLUMN; i++) {
937 renderer = gtk_cell_renderer_text_new();
938 column = gtk_tree_view_column_new_with_attributes(channel_titles[i], renderer,
940 gtk_tree_view_column_set_sort_column_id(column, i);
943 /* Expand first column (Type) */
944 gtk_tree_view_column_set_expand(column, TRUE);
946 /* For other columns, set all of the free space to be on the left */
947 g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL);
949 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
950 gtk_tree_view_column_set_resizable(column, TRUE);
951 gtk_tree_view_append_column(tree_view, column);
954 /* Set callback function for selecting a row in the channel table */
955 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(hs->channel_table));
956 gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
957 g_signal_connect(sel, "changed", G_CALLBACK(rlc_lte_select_channel_cb), hs);
959 gtk_box_pack_start(GTK_BOX(top_level_vbox), rlc_lte_stat_channels_lb, TRUE, TRUE, 0);
962 /**********************************************/
963 /* Channel filter buttons */
964 /**********************************************/
966 rlc_lte_stat_filter_buttons_lb = gtk_frame_new("Filter on selected channel");
968 filter_buttons_hb = gtk_hbox_new(FALSE, 6);
969 gtk_container_add(GTK_CONTAINER(rlc_lte_stat_filter_buttons_lb), filter_buttons_hb);
970 gtk_container_set_border_width(GTK_CONTAINER(filter_buttons_hb), 2);
974 ul_filter_bt = gtk_button_new_with_label("Set UL display filter for this channel");
975 gtk_box_pack_start(GTK_BOX(filter_buttons_hb), ul_filter_bt, TRUE, TRUE, 0);
976 g_signal_connect(ul_filter_bt, "clicked", G_CALLBACK(ul_filter_clicked), hs);
977 gtk_widget_show(ul_filter_bt);
979 dl_filter_bt = gtk_button_new_with_label("Set DL display filter for this channel");
980 gtk_box_pack_start(GTK_BOX(filter_buttons_hb), dl_filter_bt, TRUE, TRUE, 0);
981 g_signal_connect(dl_filter_bt, "clicked", G_CALLBACK(dl_filter_clicked), hs);
982 gtk_widget_show(dl_filter_bt);
984 uldl_filter_bt = gtk_button_new_with_label("Set UL / DL display filter for this channel");
985 gtk_box_pack_start(GTK_BOX(filter_buttons_hb), uldl_filter_bt, TRUE, TRUE, 0);
986 g_signal_connect(uldl_filter_bt, "clicked", G_CALLBACK(uldl_filter_clicked), hs);
987 gtk_widget_show(uldl_filter_bt);
989 gtk_box_pack_start(GTK_BOX(top_level_vbox), rlc_lte_stat_filter_buttons_lb, TRUE, TRUE, 0);
991 enable_filter_buttons(FALSE);
993 /**********************************************/
994 /* Register the tap listener */
995 /**********************************************/
997 error_string = register_tap_listener("rlc-lte", hs, NULL, 0,
1002 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", error_string->str);
1003 g_string_free(error_string, TRUE);
1009 /************************************/
1010 /* Bottom utton row. */
1011 /************************************/
1013 bbox = dlg_button_row_new (GTK_STOCK_CLOSE, GTK_STOCK_HELP, NULL);
1014 gtk_box_pack_end (GTK_BOX(top_level_vbox), bbox, FALSE, FALSE, 0);
1016 /* Add the close button */
1017 close_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_CLOSE);
1018 window_set_cancel_button(rlc_lte_stat_dlg_w, close_bt, window_cancel_button_cb);
1020 help_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_HELP);
1021 g_signal_connect(help_bt, "clicked", G_CALLBACK(topic_cb), (gpointer)HELP_STATS_LTE_RLC_TRAFFIC_DIALOG);
1024 g_signal_connect(rlc_lte_stat_dlg_w, "delete_event", G_CALLBACK(window_delete_event_cb), NULL);
1025 g_signal_connect(rlc_lte_stat_dlg_w, "destroy", G_CALLBACK(win_destroy_cb), hs);
1027 /* Show the window */
1028 gtk_widget_show_all(rlc_lte_stat_dlg_w);
1029 window_present(rlc_lte_stat_dlg_w);
1032 cf_retap_packets(&cfile);
1033 gdk_window_raise(rlc_lte_stat_dlg_w->window);
1037 /* Show window, creating if necessary */
1038 static void rlc_lte_stat_launch(GtkWidget *w _U_, gpointer data _U_)
1040 if (rlc_lte_stat_dlg_w) {
1041 reactivate_window(rlc_lte_stat_dlg_w);
1043 rlc_lte_stat_dlg_create();
1047 /* Register this tap listener (need void on own so line register function found) */
1049 register_tap_listener_rlc_lte_stat(void)
1051 register_stat_menu_item("_LTE RLC...", REGISTER_STAT_GROUP_TELEPHONY,
1052 rlc_lte_stat_launch, NULL, NULL, NULL);