Have tap listeners specify whether the "packet" routine requires
[obnox/wireshark/wip.git] / gtk / mac_lte_stat_dlg.c
1 /* mac_lte_stat_dlg.c
2  * Copyright 2009 Martin Mathieson
3  * (originally based upon wlan_stat_dlg.c)
4  *
5  * $Id$
6  *
7  * Wireshark - Network traffic analyzer
8  * By Gerald Combs <gerald@wireshark.org>
9  * Copyright 1998 Gerald Combs
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  */
25
26
27 /* TODO:
28    - limit by display filter
29    - Help button and documentation
30    - CSV export?
31 */
32
33 #ifdef HAVE_CONFIG_H
34 #include "config.h"
35 #endif
36
37 #ifdef HAVE_SYS_TYPES_H
38 #include <sys/types.h>
39 #endif
40
41 #include <string.h>
42
43 #include <gtk/gtk.h>
44
45 #include <epan/packet.h>
46 #include <epan/packet_info.h>
47 #include <epan/tap.h>
48 #include <epan/dissectors/packet-mac-lte.h>
49
50 #include "../register.h"
51 #include "../simple_dialog.h"
52 #include "../stat_menu.h"
53
54 #include "gtk/dlg_utils.h"
55 #include "gtk/gui_stat_menu.h"
56 #include "gtk/gui_utils.h"
57 #include "gtk/help_dlg.h"
58 #include "gtk/main.h"
59
60 /**********************************************/
61 /* Table column identifiers and title strings */
62
63 enum {
64     RNTI_COLUMN,
65     UL_FRAMES_COLUMN,
66     UL_BYTES_COLUMN,
67     UL_CRC_ERRORS_COLUMN,
68     UL_RETX_FRAMES_COLUMN,
69     DL_FRAMES_COLUMN,
70     DL_BYTES_COLUMN,
71     DL_CRC_ERRORS_COLUMN,
72     DL_RETX_FRAMES_COLUMN,
73     TABLE_COLUMN,
74     NUM_UE_COLUMNS
75 };
76
77 enum {
78     CCCH_COLUMN=1,
79     LCID1_COLUMN,
80     LCID2_COLUMN,
81     LCID3_COLUMN,
82     LCID4_COLUMN,
83     LCID5_COLUMN,
84     LCID6_COLUMN,
85     LCID7_COLUMN,
86     LCID8_COLUMN,
87     LCID9_COLUMN,
88     LCID10_COLUMN,
89     PREDEFINED_COLUMN,
90     NUM_CHANNEL_COLUMNS
91 };
92
93 static const gchar *ue_titles[] = { "RNTI",
94                                  "UL Frames", "UL Bytes", "UL CRC Errors", "UL ReTX Frames",
95                                  "DL Frames", "DL Bytes", "DL CRC Errors", "DL ReTX Frames"};
96
97 static const gchar *channel_titles[] = { "CCCH",
98                                          "LCID 1", "LCID 2", "LCID 3", "LCID 4", "LCID 5",
99                                          "LCID 6", "LCID 7", "LCID 8", "LCID 9", "LCID 10",
100                                          "Predefined"};
101
102
103 /* Stats for one UE */
104 typedef struct mac_lte_row_data {
105     /* Key for matching this row */
106     guint16 rnti;
107
108     gboolean is_predefined_data;
109
110     guint32 UL_frames;
111     guint32 UL_total_bytes;
112     guint32 UL_CRC_errors;
113     guint32 UL_retx_frames;
114
115     guint32 DL_frames;
116     guint32 DL_total_bytes;
117     guint32 DL_CRC_errors;
118     guint32 DL_retx_frames;
119
120     guint32 UL_bytes_for_lcid[11];
121     guint32 UL_sdus_for_lcid[11];
122     guint32 DL_bytes_for_lcid[11];
123     guint32 DL_sdus_for_lcid[11];
124 } mac_lte_row_data;
125
126
127 /* One row/UE in the UE table */
128 typedef struct mac_lte_ep {
129     struct mac_lte_ep* next;
130     struct mac_lte_row_data stats;
131     GtkTreeIter iter;
132     gboolean iter_valid;
133 } mac_lte_ep_t;
134
135
136 /* Common channel stats */
137 typedef struct mac_lte_common_stats {
138     guint32 all_frames;
139     guint32 bch_frames;
140     guint32 bch_bytes;
141     guint32 pch_frames;
142     guint32 pch_bytes;
143     guint32 rar_frames;
144     guint32 rar_entries;
145 } mac_lte_common_stats;
146
147 static const char * selected_ue_row_names[] = {"UL SDUs", "UL Bytes", "DL SDUs", "DL Bytes"};
148
149 static mac_lte_common_stats common_stats;
150
151 static GtkWidget *mac_lte_common_bch_frames;
152 static GtkWidget *mac_lte_common_bch_bytes;
153 static GtkWidget *mac_lte_common_pch_frames;
154 static GtkWidget *mac_lte_common_pch_bytes;
155 static GtkWidget *mac_lte_common_rar_frames;
156 static GtkWidget *mac_lte_common_rar_entries;
157
158 /* Labels in selected UE 'table' */
159 static GtkWidget *selected_ue_column_entry[NUM_CHANNEL_COLUMNS][5];
160
161
162 /* Top-level dialog and labels */
163 static GtkWidget  *mac_lte_stat_dlg_w = NULL;
164 static GtkWidget  *mac_lte_stat_common_channel_lb = NULL;
165 static GtkWidget  *mac_lte_stat_ues_lb = NULL;
166 static GtkWidget  *mac_lte_stat_selected_ue_lb = NULL;
167
168
169 /* Used to keep track of whole MAC LTE statistics window */
170 typedef struct mac_lte_stat_t {
171     GtkTreeView   *ue_table;
172     mac_lte_ep_t* ep_list;
173 } mac_lte_stat_t;
174
175
176 /* Reset the statistics window */
177 static void
178 mac_lte_stat_reset(void *phs)
179 {
180     mac_lte_stat_t* mac_lte_stat = (mac_lte_stat_t *)phs;
181     mac_lte_ep_t* list = mac_lte_stat->ep_list;
182     gchar title[256];
183     GtkListStore *store;
184     gint i, n;
185
186     /* Set the title */
187     if (mac_lte_stat_dlg_w != NULL) {
188         g_snprintf(title, sizeof(title), "Wireshark: LTE MAC Traffic Statistics: %s",
189                    cf_get_display_name(&cfile));
190         gtk_window_set_title(GTK_WINDOW(mac_lte_stat_dlg_w), title);
191     }
192
193     g_snprintf(title, sizeof(title), "UL/DL-SCH data (0 UEs)");
194     gtk_frame_set_label(GTK_FRAME(mac_lte_stat_ues_lb), title);
195
196     memset(&common_stats, 0, sizeof(common_stats));
197
198     /* Remove all entries from the UE list */
199     store = GTK_LIST_STORE(gtk_tree_view_get_model(mac_lte_stat->ue_table));
200     gtk_list_store_clear(store);
201
202     if (!list) {
203         return;
204     }
205
206     mac_lte_stat->ep_list = NULL;
207
208     /* Set all of the channel counters to 0 */
209     for (n=1; n <=4; n++) {
210         for (i=CCCH_COLUMN; i < NUM_CHANNEL_COLUMNS; i++) {
211              gtk_label_set_text(GTK_LABEL(selected_ue_column_entry[i][n]), "0");
212         }
213     }
214 }
215
216
217 /* Allocate a mac_lte_ep_t struct to store info for new UE */
218 static mac_lte_ep_t* alloc_mac_lte_ep(struct mac_lte_tap_info *si, packet_info *pinfo _U_)
219 {
220     mac_lte_ep_t* ep;
221     int n;
222
223     if (!si) {
224         return NULL;
225     }
226
227     if (!(ep = g_malloc(sizeof(mac_lte_ep_t)))) {
228         return NULL;
229     }
230
231     /* Copy SI data into ep->stats */
232     ep->stats.rnti = si->rnti;
233
234     /* Counts for new UE are all 0 */
235     ep->stats.UL_frames = 0;
236     ep->stats.DL_frames = 0;
237     ep->stats.UL_total_bytes = 0;
238     ep->stats.DL_total_bytes = 0;
239     ep->stats.UL_CRC_errors = 0;
240     ep->stats.DL_CRC_errors = 0;
241     ep->stats.UL_retx_frames = 0;
242     ep->stats.DL_retx_frames = 0;
243
244     for (n=0; n < 11; n++) {
245         ep->stats.UL_sdus_for_lcid[n] = 0;
246         ep->stats.UL_bytes_for_lcid[n] = 0;
247     }
248     ep->stats.DL_total_bytes = 0;
249     for (n=0; n < 11; n++) {
250         ep->stats.DL_sdus_for_lcid[n] = 0;
251         ep->stats.DL_bytes_for_lcid[n] = 0;
252     }
253
254     ep->next = NULL;
255
256     ep->iter_valid = FALSE;
257
258     return ep;
259 }
260
261
262 /* Process stat struct for a MAC LTE frame */
263 static int
264 mac_lte_stat_packet(void *phs, packet_info *pinfo, epan_dissect_t *edt _U_,
265                     const void *phi)
266 {
267     int n;
268
269     /* Get reference to stat window instance */
270     mac_lte_stat_t *hs = (mac_lte_stat_t *)phs;
271     mac_lte_ep_t *tmp = NULL, *te = NULL;
272
273     /* Cast tap info struct */
274     struct mac_lte_tap_info *si = (struct mac_lte_tap_info *)phi;
275
276     if (!hs) {
277         return (0);
278     }
279
280     common_stats.all_frames++;
281
282     /* For common channels, just update global counters */
283     switch (si->rntiType) {
284         case P_RNTI:
285             common_stats.pch_frames++;
286             common_stats.pch_bytes += si->single_number_of_bytes;
287             return 1;
288         case SI_RNTI:
289         case NO_RNTI:
290             common_stats.bch_frames++;
291             common_stats.bch_bytes += si->single_number_of_bytes;
292             return 1;
293         case RA_RNTI:
294             common_stats.rar_frames++;
295             common_stats.rar_entries += si->number_of_rars;
296             return 1;
297         case C_RNTI:
298             /* Drop through for per-UE update */
299             break;
300
301         default:
302             return 0;
303     }
304
305     /* For per-UE data, must create a new row if none already existing */
306     if (!hs->ep_list) {
307         /* Allocate new list */
308         hs->ep_list = alloc_mac_lte_ep(si, pinfo);
309         /* Make it the first/only entry */
310         te = hs->ep_list;
311     } else {
312         /* Look among existing rows for this RNTI */
313         for (tmp = hs->ep_list;(tmp != NULL); tmp = tmp->next) {
314             if (tmp->stats.rnti == si->rnti) {
315                 te = tmp;
316                 break;
317             }
318         }
319
320         /* Not found among existing, so create a new one anyway */
321         if (te == NULL) {
322             if ((te = alloc_mac_lte_ep(si, pinfo))) {
323                 /* New item is head of list */
324                 te->next = hs->ep_list;
325                 hs->ep_list = te;
326             }
327         }
328     }
329
330     /* Really should have a row pointer by now */
331     if (!te) {
332         return 0;
333     }
334
335     /* Update entry with details from si */
336     te->stats.rnti = si->rnti;
337     te->stats.is_predefined_data = si->isPredefinedData;
338     if (si->crcStatusValid && !si->crcStatus) {
339         if (si->direction == DIRECTION_UPLINK) {
340             te->stats.UL_CRC_errors++;
341             return 1;
342         }
343         else {
344             te->stats.DL_CRC_errors++;
345             return 1;
346         }
347     }
348
349     /* Uplink */
350     if (si->direction == DIRECTION_UPLINK) {
351         if (si->reTxCount >= 1) {
352             te->stats.UL_retx_frames++;
353             return 1;
354         }
355         te->stats.UL_frames++;
356
357         if (si->isPredefinedData) {
358             te->stats.UL_total_bytes += si->single_number_of_bytes;
359         }
360         else {
361             for (n=0; n < 11; n++) {
362                 if (si->bytes_for_lcid[n]) {
363                     te->stats.UL_sdus_for_lcid[n] += si->sdus_for_lcid[n];
364                 }
365                 te->stats.UL_bytes_for_lcid[n] += si->bytes_for_lcid[n];
366                 te->stats.UL_total_bytes += si->bytes_for_lcid[n];
367             }
368         }
369     }
370
371     /* Downlink */
372     else {
373         if (si->reTxCount >= 1) {
374             te->stats.DL_retx_frames++;
375             return 1;
376         }
377
378         te->stats.DL_frames++;
379
380         if (si->isPredefinedData) {
381             te->stats.DL_total_bytes += si->single_number_of_bytes;
382         }
383         else {
384             for (n=0; n < 11; n++) {
385                 if (si->bytes_for_lcid[n]) {
386                     te->stats.DL_sdus_for_lcid[n] += si->sdus_for_lcid[n];
387                 }
388                 te->stats.DL_bytes_for_lcid[n] += si->bytes_for_lcid[n];
389                 te->stats.DL_total_bytes += si->bytes_for_lcid[n];
390             }
391         }
392     }
393
394     return 1;
395 }
396
397
398 /* Draw the UE details table according to the current UE selection */
399 static void
400 mac_lte_ue_details(mac_lte_ep_t *mac_stat_ep)
401 {
402     int n;
403     gchar buff[32];
404
405     /**********************************/
406     /* Set data one row at a time     */
407
408     /* UL SDUs */
409     for (n=0; n < PREDEFINED_COLUMN-1; n++) {
410         g_snprintf(buff, sizeof(buff), "%u", mac_stat_ep ? mac_stat_ep->stats.UL_sdus_for_lcid[n] : 0);
411          gtk_label_set_text(GTK_LABEL(selected_ue_column_entry[n+1][1]), buff);
412     }
413
414     /* Predefined */
415     if (mac_stat_ep) {
416         g_snprintf(buff, sizeof(buff), "%u", mac_stat_ep->stats.is_predefined_data ?
417                                                  mac_stat_ep->stats.UL_frames :
418                                                  0);
419     }
420     else {
421         g_snprintf(buff, sizeof(buff), "%u", 0);
422     }
423     gtk_label_set_text(GTK_LABEL(selected_ue_column_entry[PREDEFINED_COLUMN][1]), buff);
424
425
426     /* UL Bytes */
427     for (n=0; n < PREDEFINED_COLUMN-1; n++) {
428         g_snprintf(buff, sizeof(buff), "%u",
429             (mac_stat_ep) ? mac_stat_ep->stats.UL_bytes_for_lcid[n] : 0);
430         gtk_label_set_text(GTK_LABEL(selected_ue_column_entry[n+1][2]), buff);
431     }
432
433     /* Predefined */
434     if (mac_stat_ep) {
435         g_snprintf(buff, sizeof(buff), "%u", mac_stat_ep->stats.is_predefined_data ?
436                                                  mac_stat_ep->stats.UL_total_bytes :
437                                                  0);
438     }
439     else {
440         g_snprintf(buff, sizeof(buff), "%u", 0);
441     }
442     gtk_label_set_text(GTK_LABEL(selected_ue_column_entry[PREDEFINED_COLUMN][2]), buff);
443
444
445     /* DL SDUs */
446     for (n=0; n < PREDEFINED_COLUMN-1; n++) {
447         g_snprintf(buff, sizeof(buff), "%u",
448                    mac_stat_ep ? mac_stat_ep->stats.DL_sdus_for_lcid[n] : 0);
449         gtk_label_set_text(GTK_LABEL(selected_ue_column_entry[n+1][3]), buff);
450     }
451     /* Predefined */
452     if (mac_stat_ep) {
453         g_snprintf(buff, sizeof(buff), "%u", mac_stat_ep->stats.is_predefined_data ?
454                                                  mac_stat_ep->stats.DL_frames :
455                                                  0);
456     }
457     else {
458         g_snprintf(buff, sizeof(buff), "%u", 0);
459     }
460     gtk_label_set_text(GTK_LABEL(selected_ue_column_entry[PREDEFINED_COLUMN][3]), buff);
461
462
463     /* DL Bytes */
464     for (n=0; n < PREDEFINED_COLUMN-1; n++) {
465         g_snprintf(buff, sizeof(buff), "%u",
466                    mac_stat_ep ? mac_stat_ep->stats.DL_bytes_for_lcid[n] : 0);
467         gtk_label_set_text(GTK_LABEL(selected_ue_column_entry[n+1][4]), buff);
468     }
469     /* Predefined */
470     if (mac_stat_ep) {
471         g_snprintf(buff, sizeof(buff), "%u", mac_stat_ep->stats.is_predefined_data ?
472                                                  mac_stat_ep->stats.DL_total_bytes :
473                                                  0);
474     }
475     else {
476         g_snprintf(buff, sizeof(buff), "%u", 0);
477     }
478     gtk_label_set_text(GTK_LABEL(selected_ue_column_entry[PREDEFINED_COLUMN][4]), buff);
479 }
480
481
482
483 /* (Re)draw the whole dialog window */
484 static void
485 mac_lte_stat_draw(void *phs)
486 {
487     gchar   buff[32];
488     guint16 number_of_ues = 0;
489     gchar title[256];
490
491     /* Look up the statistics window */
492     mac_lte_stat_t *hs = (mac_lte_stat_t *)phs;
493     mac_lte_ep_t* list = hs->ep_list, *tmp = 0;
494
495     GtkListStore *ues_store;
496     GtkTreeSelection *sel;
497     GtkTreeModel *model;
498     GtkTreeIter iter;
499
500     /* Common channel data */
501     g_snprintf(buff, sizeof(buff), "BCH Frames: %u", common_stats.bch_frames);
502     gtk_label_set_text(GTK_LABEL(mac_lte_common_bch_frames), buff);
503     g_snprintf(buff, sizeof(buff), "BCH Bytes: %u", common_stats.bch_bytes);
504     gtk_label_set_text(GTK_LABEL(mac_lte_common_bch_bytes), buff);
505     g_snprintf(buff, sizeof(buff), "PCH Frames: %u", common_stats.pch_frames);
506     gtk_label_set_text(GTK_LABEL(mac_lte_common_pch_frames), buff);
507     g_snprintf(buff, sizeof(buff), "PCH Bytes: %u", common_stats.pch_bytes);
508     gtk_label_set_text(GTK_LABEL(mac_lte_common_pch_bytes), buff);
509     g_snprintf(buff, sizeof(buff), "RAR Frames: %u", common_stats.rar_frames);
510     gtk_label_set_text(GTK_LABEL(mac_lte_common_rar_frames), buff);
511     g_snprintf(buff, sizeof(buff), "RAR Entries: %u", common_stats.rar_entries);
512     gtk_label_set_text(GTK_LABEL(mac_lte_common_rar_entries), buff);
513
514
515     /* Per-UE table entries */
516     ues_store = GTK_LIST_STORE(gtk_tree_view_get_model(hs->ue_table));
517
518     /* Set title that shows how many UEs currently in table */
519     for (tmp = list; (tmp!=NULL); tmp=tmp->next, number_of_ues++);
520     g_snprintf(title, sizeof(title), "UL/DL-SCH data (%u UEs)", number_of_ues);
521     gtk_frame_set_label(GTK_FRAME(mac_lte_stat_ues_lb), title);
522
523     /* Update title to include number of UEs and frames */
524     g_snprintf(title, sizeof(title), "Wireshark: LTE MAC Traffic Statistics: %s (%u UEs, %u frames)",
525                cf_get_display_name(&cfile),
526                number_of_ues,
527                common_stats.all_frames);
528     gtk_window_set_title(GTK_WINDOW(mac_lte_stat_dlg_w), title);
529
530
531
532     /* For each row/UE/C-RNTI in the model */
533     for (tmp = list; tmp; tmp=tmp->next) {
534         if (tmp->iter_valid != TRUE) {
535             /* Add to list control if not drawn this UE before */
536             gtk_list_store_append(ues_store, &tmp->iter);
537             tmp->iter_valid = TRUE;
538         }
539
540         /* Set each column for this row */
541         gtk_list_store_set(ues_store, &tmp->iter,
542                            RNTI_COLUMN, tmp->stats.rnti,
543                            UL_FRAMES_COLUMN, tmp->stats.UL_frames,
544                            UL_BYTES_COLUMN, tmp->stats.UL_total_bytes,
545                            UL_CRC_ERRORS_COLUMN, tmp->stats.UL_CRC_errors,
546                            UL_RETX_FRAMES_COLUMN, tmp->stats.UL_retx_frames,
547                            DL_FRAMES_COLUMN, tmp->stats.DL_frames,
548                            DL_BYTES_COLUMN, tmp->stats.DL_total_bytes,
549                            DL_CRC_ERRORS_COLUMN, tmp->stats.DL_CRC_errors,
550                            DL_RETX_FRAMES_COLUMN, tmp->stats.DL_retx_frames,
551                            TABLE_COLUMN, tmp,
552                            -1);
553     }
554
555     /* If there is a UE selected, update its counters in details window */
556     sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(hs->ue_table));
557     if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
558         mac_lte_ep_t *ep;
559
560         gtk_tree_model_get(model, &iter, TABLE_COLUMN, &ep, -1);
561         mac_lte_ue_details(ep);
562     }
563 }
564
565
566 /* What to do when a list item is selected/unselected */
567 static void mac_lte_select_cb(GtkTreeSelection *sel, gpointer data _U_)
568 {
569     mac_lte_ep_t   *ep;
570     GtkTreeModel   *model;
571     GtkTreeIter    iter;
572
573     if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
574         /* Show details of selected UE */
575         gtk_tree_model_get(model, &iter, TABLE_COLUMN, &ep, -1);
576         mac_lte_ue_details(ep);
577     }
578     else {
579         mac_lte_ue_details(NULL);
580     }
581 }
582
583
584
585 /* Destroy the stats window */
586 static void win_destroy_cb(GtkWindow *win _U_, gpointer data)
587 {
588     mac_lte_stat_t *hs = (mac_lte_stat_t *)data;
589
590     protect_thread_critical_region();
591     remove_tap_listener(hs);
592     unprotect_thread_critical_region();
593
594     if (mac_lte_stat_dlg_w != NULL) {
595         window_destroy(mac_lte_stat_dlg_w);
596         mac_lte_stat_dlg_w = NULL;
597     }
598     mac_lte_stat_reset(hs);
599     g_free(hs);
600 }
601
602
603 /* Create a new MAC LTE stats dialog */
604 static void mac_lte_stat_dlg_create(void)
605 {
606     mac_lte_stat_t    *hs;
607     GString       *error_string;
608     GtkWidget     *ues_scrolled_window;
609     GtkWidget     *bbox;
610     GtkWidget     *top_level_vbox;
611
612     GtkWidget     *common_row_hbox;
613     GtkWidget     *ues_vb;
614     GtkWidget     *selected_ue_hb;
615
616     GtkWidget     *selected_ue_vbox[NUM_CHANNEL_COLUMNS];
617     GtkWidget     *selected_ue_column_titles[5];
618
619     GtkWidget     *close_bt;
620     GtkWidget     *help_bt;
621
622     GtkListStore  *store;
623
624     GtkTreeView       *tree_view;
625     GtkCellRenderer   *renderer;
626     GtkTreeViewColumn *column;
627     GtkTreeSelection  *sel;
628     gchar title[256];
629     gint i, n;
630
631     /* Create dialog */
632     hs = g_malloc(sizeof(mac_lte_stat_t));
633     hs->ep_list = NULL;
634
635     /* Set title */
636     g_snprintf(title, sizeof(title), "Wireshark: LTE MAC Statistics: %s",
637                cf_get_display_name(&cfile));
638     mac_lte_stat_dlg_w = window_new_with_geom(GTK_WINDOW_TOPLEVEL, title, "LTE MAC Statistics");
639
640     /* Window size */
641     gtk_window_set_default_size(GTK_WINDOW(mac_lte_stat_dlg_w), 750, 300);
642
643     /* Will stack widgets vertically inside dlg */
644     top_level_vbox = gtk_vbox_new(FALSE, 3);       /* FALSE = not homogeneous */
645     gtk_container_add(GTK_CONTAINER(mac_lte_stat_dlg_w), top_level_vbox);
646
647     gtk_container_set_border_width(GTK_CONTAINER(top_level_vbox), 6);
648     gtk_widget_show(top_level_vbox);
649
650
651     /**********************************************/
652     /* Common Channel data                        */
653     /**********************************************/
654     mac_lte_stat_common_channel_lb = gtk_frame_new("Common Channel Data");
655
656     /* Will add BCH and PCH counters into one row */
657     common_row_hbox = gtk_hbox_new(FALSE, 0);
658     gtk_container_add(GTK_CONTAINER(mac_lte_stat_common_channel_lb), common_row_hbox);
659     gtk_container_set_border_width(GTK_CONTAINER(common_row_hbox), 5);
660
661     gtk_box_pack_start(GTK_BOX(top_level_vbox), mac_lte_stat_common_channel_lb, FALSE, FALSE, 0);
662
663     /* Create labels (that will hold label and counter value) */
664     mac_lte_common_bch_frames = gtk_label_new("BCH Frames:");
665     gtk_misc_set_alignment(GTK_MISC(mac_lte_common_bch_frames), 0.0f, .5f);
666     gtk_container_add(GTK_CONTAINER(common_row_hbox), mac_lte_common_bch_frames);
667     gtk_widget_show(mac_lte_common_bch_frames);
668
669     mac_lte_common_bch_bytes = gtk_label_new("BCH Bytes:");
670     gtk_misc_set_alignment(GTK_MISC(mac_lte_common_bch_bytes), 0.0f, .5f);
671     gtk_container_add(GTK_CONTAINER(common_row_hbox), mac_lte_common_bch_bytes);
672     gtk_widget_show(mac_lte_common_bch_bytes);
673
674     mac_lte_common_pch_frames = gtk_label_new("PCH Frames:");
675     gtk_misc_set_alignment(GTK_MISC(mac_lte_common_pch_frames), 0.0f, .5f);
676     gtk_container_add(GTK_CONTAINER(common_row_hbox), mac_lte_common_pch_frames);
677     gtk_widget_show(mac_lte_common_pch_frames);
678
679     mac_lte_common_pch_bytes = gtk_label_new("PCH Bytes:");
680     gtk_misc_set_alignment(GTK_MISC(mac_lte_common_pch_bytes), 0.0f, .5f);
681     gtk_container_add(GTK_CONTAINER(common_row_hbox), mac_lte_common_pch_bytes);
682     gtk_widget_show(mac_lte_common_pch_bytes);
683
684     mac_lte_common_rar_frames = gtk_label_new("RAR Frames:");
685     gtk_misc_set_alignment(GTK_MISC(mac_lte_common_rar_frames), 0.0f, .5f);
686     gtk_container_add(GTK_CONTAINER(common_row_hbox), mac_lte_common_rar_frames);
687     gtk_widget_show(mac_lte_common_rar_frames);
688
689     mac_lte_common_rar_entries = gtk_label_new("RAR Entries:");
690     gtk_misc_set_alignment(GTK_MISC(mac_lte_common_rar_entries), 0.0f, .5f);
691     gtk_container_add(GTK_CONTAINER(common_row_hbox), mac_lte_common_rar_entries);
692     gtk_widget_show(mac_lte_common_rar_entries);
693
694     /**********************************************/
695     /* UL/DL-SCH data                             */
696     /**********************************************/
697
698     mac_lte_stat_ues_lb = gtk_frame_new("UL/DL-SCH Data (0 UEs)");
699     ues_vb = gtk_vbox_new(FALSE, 0);
700     gtk_container_add(GTK_CONTAINER(mac_lte_stat_ues_lb), ues_vb);
701     gtk_container_set_border_width(GTK_CONTAINER(ues_vb), 5);
702
703     ues_scrolled_window = scrolled_window_new(NULL, NULL);
704     gtk_box_pack_start(GTK_BOX(ues_vb), ues_scrolled_window, TRUE, TRUE, 0);
705     gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(ues_scrolled_window),
706                                         GTK_SHADOW_IN);
707
708     /* Create the table of UE data */
709     store = gtk_list_store_new(NUM_UE_COLUMNS, G_TYPE_INT,
710                                G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT,  /* UL */
711                                G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT,  /* DL */
712                                G_TYPE_POINTER);
713     hs->ue_table = GTK_TREE_VIEW(tree_view_new(GTK_TREE_MODEL(store)));
714     gtk_container_add(GTK_CONTAINER (ues_scrolled_window), GTK_WIDGET(hs->ue_table));
715     g_object_unref(G_OBJECT(store));
716
717     tree_view = hs->ue_table;
718     gtk_tree_view_set_headers_visible(tree_view, TRUE);
719     gtk_tree_view_set_headers_clickable(tree_view, TRUE);
720
721     /* Create the titles for each column of the per-UE table */
722     for (i = 0; i < TABLE_COLUMN; i++) {
723         renderer = gtk_cell_renderer_text_new();
724         column = gtk_tree_view_column_new_with_attributes(ue_titles[i], renderer,
725                                                           "text", i, NULL);
726         gtk_tree_view_column_set_sort_column_id(column, i);
727
728         if (i == 0) {
729             /* Expand first column (RNTI, which is Key) */
730             gtk_tree_view_column_set_expand(column, TRUE);
731         } else {
732             /* For other columns, set all of the free space to be on the left */
733             g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL);
734         }
735         gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
736         gtk_tree_view_column_set_resizable(column, TRUE);
737         gtk_tree_view_append_column(tree_view, column);
738     }
739
740     /* Set callback function for selecting a row in the UE table */
741     sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(hs->ue_table));
742     gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
743     g_signal_connect(sel, "changed", G_CALLBACK(mac_lte_select_cb), hs);
744
745     gtk_box_pack_start(GTK_BOX(top_level_vbox), mac_lte_stat_ues_lb, TRUE, TRUE, 0);
746
747
748     /**********************************************/
749     /* Details of selected UE                     */
750     /**********************************************/
751
752     mac_lte_stat_selected_ue_lb = gtk_frame_new("Selected UE details");
753
754     selected_ue_hb = gtk_hbox_new(FALSE, 6);
755     gtk_container_add(GTK_CONTAINER(mac_lte_stat_selected_ue_lb), selected_ue_hb);
756     gtk_container_set_border_width(GTK_CONTAINER(selected_ue_hb), 5);
757
758     /********************************/
759     /* First (row titles) column    */
760     selected_ue_vbox[0] = gtk_vbox_new(FALSE, 0);
761     gtk_container_add(GTK_CONTAINER(selected_ue_hb), selected_ue_vbox[0]);
762
763     selected_ue_column_titles[0] = gtk_label_new("");
764     gtk_misc_set_alignment(GTK_MISC(selected_ue_column_titles[0]), 0.0f, 0.0f);
765     gtk_container_add(GTK_CONTAINER(selected_ue_vbox[0]), selected_ue_column_titles[0]);
766
767     for (n=1; n < 5; n++) {
768         selected_ue_column_titles[n] = gtk_label_new(selected_ue_row_names[n-1]);
769         gtk_misc_set_alignment(GTK_MISC(selected_ue_column_titles[n]), 0.0f, 0.0f);
770         gtk_container_add(GTK_CONTAINER(selected_ue_vbox[0]), selected_ue_column_titles[n]);
771         gtk_widget_show(selected_ue_column_titles[n]);
772     }
773
774
775     /*************************/
776     /* Other columns         */
777     for (i=CCCH_COLUMN; i < NUM_CHANNEL_COLUMNS; i++) {
778         selected_ue_vbox[i] = gtk_vbox_new(FALSE, 0);
779         gtk_container_add(GTK_CONTAINER(selected_ue_hb), selected_ue_vbox[i]);
780
781         /* Channel title */
782         selected_ue_column_entry[i][0] = gtk_label_new(channel_titles[i-1]);
783         gtk_misc_set_alignment(GTK_MISC(selected_ue_column_entry[i][0]), 0.5f, 0.0f);
784         gtk_container_add(GTK_CONTAINER(selected_ue_vbox[i]), selected_ue_column_entry[i][0]);
785
786
787         /* Counts for this channel */
788         for (n=1; n < 5; n++) {
789             selected_ue_column_entry[i][n] = gtk_label_new("0");
790             gtk_misc_set_alignment(GTK_MISC(selected_ue_column_entry[i][n]), 1.0f, 0.0f);
791             gtk_container_add(GTK_CONTAINER(selected_ue_vbox[i]), selected_ue_column_entry[i][n]);
792             gtk_widget_show(selected_ue_column_entry[i][n]);
793         }
794     }
795
796     gtk_box_pack_start(GTK_BOX(top_level_vbox), mac_lte_stat_selected_ue_lb, FALSE, FALSE, 0);
797
798
799     /**********************************************/
800     /* Register the tap listener                  */
801     /**********************************************/
802
803     error_string = register_tap_listener("mac-lte", hs, NULL, 0,
804                                          mac_lte_stat_reset,
805                                          mac_lte_stat_packet,
806                                          mac_lte_stat_draw);
807     if (error_string) {
808         simple_dialog (ESD_TYPE_ERROR, ESD_BTN_OK, "%s", error_string->str);
809         g_string_free (error_string, TRUE);
810         g_free (hs);
811         return;
812     }
813
814
815     /************************************/
816     /* Button row.                      */
817     /************************************/
818
819     bbox = dlg_button_row_new (GTK_STOCK_CLOSE, GTK_STOCK_HELP, NULL);
820     gtk_box_pack_end (GTK_BOX(top_level_vbox), bbox, FALSE, FALSE, 0);
821
822     /* Add the close button */
823     close_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_CLOSE);
824     window_set_cancel_button(mac_lte_stat_dlg_w, close_bt, window_cancel_button_cb);
825
826     help_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_HELP);
827     g_signal_connect(help_bt, "clicked", G_CALLBACK(topic_cb), (gpointer)HELP_STATS_LTE_MAC_TRAFFIC_DIALOG);
828
829     /* Set callbacks */
830     g_signal_connect(mac_lte_stat_dlg_w, "delete_event", G_CALLBACK(window_delete_event_cb), NULL);
831     g_signal_connect(mac_lte_stat_dlg_w, "destroy", G_CALLBACK(win_destroy_cb), hs);
832
833     /* Show the window */
834     gtk_widget_show_all(mac_lte_stat_dlg_w);
835     window_present(mac_lte_stat_dlg_w);
836
837     /* Retap */
838     cf_retap_packets(&cfile);
839     gdk_window_raise(mac_lte_stat_dlg_w->window);
840 }
841
842
843 /* Show window, creating if necessary */
844 static void mac_lte_stat_launch(GtkWidget *w _U_, gpointer data _U_)
845 {
846     if (mac_lte_stat_dlg_w) {
847         reactivate_window(mac_lte_stat_dlg_w);
848     } else {
849         mac_lte_stat_dlg_create();
850     }
851 }
852
853 /* Register this tap listener (need void on own so line register function found) */
854 void
855 register_tap_listener_mac_lte_stat(void)
856 {
857     register_stat_menu_item("LTE MAC...", REGISTER_STAT_GROUP_TELEPHONY,
858                             mac_lte_stat_launch, NULL, NULL, NULL);
859 }
860