4bd9045c596ccb6cc221c7dc20b07bcc4b99a144
[metze/wireshark/wip.git] / ui / 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  * Wireshark - Network traffic analyzer
6  * By Gerald Combs <gerald@wireshark.org>
7  * Copyright 1998 Gerald Combs
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22  */
23
24 #include "config.h"
25
26 #include <string.h>
27
28 #include <gtk/gtk.h>
29
30 #include "ui/gtk/gtkglobals.h"
31
32 #include <epan/packet.h>
33 #include <epan/packet_info.h>
34 #include <epan/tap.h>
35 #include <epan/dissectors/packet-mac-lte.h>
36
37 #include "ui/simple_dialog.h"
38 #include <epan/stat_groups.h>
39
40 #include "ui/gtk/dlg_utils.h"
41 #include "ui/gtk/gui_stat_menu.h"
42 #include "ui/gtk/tap_param_dlg.h"
43 #include "ui/gtk/gui_utils.h"
44 #include "ui/gtk/help_dlg.h"
45 #include "ui/gtk/main.h"
46
47 #include "ui/gtk/old-gtk-compat.h"
48
49 void register_tap_listener_mac_lte_stat(void);
50
51 /**********************************************/
52 /* Table column identifiers and title strings */
53
54 enum {
55     RNTI_COLUMN,
56     RNTI_TYPE_COLUMN,
57     UEID_COLUMN,
58     UL_FRAMES_COLUMN,
59     UL_BYTES_COLUMN,
60     UL_BW_COLUMN,
61     UL_PADDING_PERCENT_COLUMN,
62     UL_RETX_FRAMES_COLUMN,
63     DL_FRAMES_COLUMN,
64     DL_BYTES_COLUMN,
65     DL_BW_COLUMN,
66     DL_PADDING_PERCENT_COLUMN,
67     DL_CRC_FAILED_COLUMN,
68     DL_CRC_HIGH_CODE_RATE_COLUMN,
69     DL_CRC_PDSCH_LOST_COLUMN,
70     DL_CRC_DUPLICATE_NONZERO_RV,
71     DL_RETX_FRAMES_COLUMN,
72     TABLE_COLUMN,
73     NUM_UE_COLUMNS
74 };
75
76 enum {
77     CCCH_COLUMN=1,
78     LCID1_COLUMN,
79     LCID2_COLUMN,
80     LCID3_COLUMN,
81     LCID4_COLUMN,
82     LCID5_COLUMN,
83     LCID6_COLUMN,
84     LCID7_COLUMN,
85     LCID8_COLUMN,
86     LCID9_COLUMN,
87     LCID10_COLUMN,
88     PREDEFINED_COLUMN,
89     NUM_CHANNEL_COLUMNS
90 };
91
92 static const gchar *ue_titles[] = { "RNTI", "Type", "UEId",
93                                     "UL Frames", "UL Bytes", "UL MBit/sec", "UL Padding %", "UL ReTX",
94                                     "DL Frames", "DL Bytes", "DL MBit/sec", "DL Padding %", "DL CRC Failed",
95                                     "DL CRC High Code Rate", "DL CRC PDSCH Lost", "DL CRC Dup NonZero RV", "DL ReTX"};
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     guint8   rnti_type;
108     guint16  ueid;
109
110     gboolean is_predefined_data;
111
112     guint32  UL_frames;
113     guint32  UL_raw_bytes;   /* all bytes */
114     guint32  UL_total_bytes; /* payload */
115     nstime_t UL_time_start;
116     nstime_t UL_time_stop;
117     guint32  UL_padding_bytes;
118     guint32  UL_CRC_errors;
119     guint32  UL_retx_frames;
120
121     guint32  DL_frames;
122     guint32  DL_raw_bytes;   /* all bytes */
123     guint32  DL_total_bytes;
124     nstime_t DL_time_start;
125     nstime_t DL_time_stop;
126     guint32  DL_padding_bytes;
127     guint32  DL_CRC_failures;
128     guint32  DL_CRC_high_code_rate;
129     guint32  DL_CRC_PDSCH_lost;
130     guint32  DL_CRC_Duplicate_Nonzero_rv;
131     guint32  DL_retx_frames;
132
133     guint32  UL_bytes_for_lcid[11];
134     guint32  UL_sdus_for_lcid[11];
135     guint32  DL_bytes_for_lcid[11];
136     guint32  DL_sdus_for_lcid[11];
137 } mac_lte_row_data;
138
139
140 /* One row/UE in the UE table */
141 typedef struct mac_lte_ep {
142     struct mac_lte_ep *next;
143     struct mac_lte_row_data stats;
144     GtkTreeIter iter;
145     gboolean iter_valid;
146 } mac_lte_ep_t;
147
148
149 /* Common channel stats */
150 typedef struct mac_lte_common_stats {
151     guint32 all_frames;
152     guint32 mib_frames;
153     guint32 sib_frames;
154     guint32 sib_bytes;
155     guint32 pch_frames;
156     guint32 pch_bytes;
157     guint32 pch_paging_ids;
158     guint32 rar_frames;
159     guint32 rar_entries;
160
161     guint16  max_ul_ues_in_tti;
162     guint16  max_dl_ues_in_tti;
163 } mac_lte_common_stats;
164
165
166 static const char *selected_ue_row_names[] = {"UL SDUs", "UL Bytes", "DL SDUs", "DL Bytes"};
167
168
169 /* Used to keep track of whole MAC LTE statistics window */
170 typedef struct mac_lte_stat_t {
171     /* Stats window itself */
172     GtkWidget    *mac_lte_stat_dlg_w;
173
174     char         *filter;
175
176     /* Labels */
177     GtkWidget    *mac_lte_stat_ues_lb;
178     GtkWidget    *ul_filter_bt;
179     GtkWidget    *dl_filter_bt;
180     GtkWidget    *uldl_filter_bt;
181
182     GtkWidget    *show_mac_rach_cb;
183     GtkWidget    *show_mac_srs_cb;
184     GtkWidget    *show_dct_errors_cb;
185     GtkWidget    *dct_error_substring_lb;
186     GtkWidget    *dct_error_substring_te;
187
188     GtkWidget    *ul_max_ues_per_tti;
189     GtkWidget    *dl_max_ues_per_tti;
190
191     /* Common stats */
192     mac_lte_common_stats common_stats;
193     GtkWidget    *common_mib_frames;
194     GtkWidget    *common_sib_frames;
195     GtkWidget    *common_sib_bytes;
196     GtkWidget    *common_pch_frames;
197     GtkWidget    *common_pch_bytes;
198     GtkWidget    *common_pch_paging_ids;
199     GtkWidget    *common_rar_frames;
200     GtkWidget    *common_rar_entries;
201
202     /* Keep track of unique rntis & ueids */
203     guint8        used_ueids[65535];
204     guint8        used_rntis[65535];
205     guint16       number_of_ueids;
206     guint16       number_of_rntis;
207
208     guint16       selected_rnti;
209     guint16       selected_ueid;
210
211     /* Labels in selected UE 'table' */
212     GtkWidget    *selected_ue_column_entry[NUM_CHANNEL_COLUMNS][5];
213
214     GtkTreeView  *ue_table;
215     mac_lte_ep_t *ep_list;
216 } mac_lte_stat_t;
217
218
219 /* Reset the statistics window */
220 static void mac_lte_stat_reset(void *phs)
221 {
222     mac_lte_stat_t *mac_lte_stat = (mac_lte_stat_t *)phs;
223     mac_lte_ep_t   *list         = mac_lte_stat->ep_list;
224     char           *display_name;
225     gchar           title[256];
226     GtkListStore   *store;
227     gint            i, n;
228
229     /* Set the title */
230     if (mac_lte_stat->mac_lte_stat_dlg_w != NULL) {
231         display_name = cf_get_display_name(&cfile);
232         g_snprintf(title, sizeof(title), "Wireshark: LTE MAC Traffic Statistics: %s (filter=\"%s\")",
233                    display_name,
234                    strlen(mac_lte_stat->filter) ? mac_lte_stat->filter : "none");
235         g_free(display_name);
236         gtk_window_set_title(GTK_WINDOW(mac_lte_stat->mac_lte_stat_dlg_w), title);
237     }
238
239     g_snprintf(title, sizeof(title), "UL/DL-SCH data (0 entries)");
240     gtk_frame_set_label(GTK_FRAME(mac_lte_stat->mac_lte_stat_ues_lb), title);
241
242     /* Reset counts of unique ueids & rntis */
243     memset(mac_lte_stat->used_ueids, 0, 65535);
244     mac_lte_stat->number_of_ueids = 0;
245     memset(mac_lte_stat->used_rntis, 0, 65535);
246     mac_lte_stat->number_of_rntis = 0;
247
248     /* Zero common stats */
249     memset(&(mac_lte_stat->common_stats), 0, sizeof(mac_lte_common_stats));
250
251     /* Remove all entries from the UE list */
252     store = GTK_LIST_STORE(gtk_tree_view_get_model(mac_lte_stat->ue_table));
253     gtk_list_store_clear(store);
254
255     if (!list) {
256         return;
257     }
258
259     mac_lte_stat->ep_list = NULL;
260
261     /* Set all of the channel counters to 0 */
262     for (n=1; n <=4; n++) {
263         for (i=CCCH_COLUMN; i < NUM_CHANNEL_COLUMNS; i++) {
264              gtk_label_set_text(GTK_LABEL(mac_lte_stat->selected_ue_column_entry[i][n]), "0");
265         }
266     }
267 }
268
269
270 /* Allocate a mac_lte_ep_t struct to store info for new UE */
271 static mac_lte_ep_t* alloc_mac_lte_ep(const struct mac_lte_tap_info *si, packet_info *pinfo _U_)
272 {
273     mac_lte_ep_t *ep;
274     int n;
275
276     if (!si) {
277         return NULL;
278     }
279
280     if (!(ep = (mac_lte_ep_t *)g_malloc(sizeof(mac_lte_ep_t)))) {
281         return NULL;
282     }
283
284     /* Copy SI data into ep->stats */
285     ep->stats.rnti = si->rnti;
286     ep->stats.rnti_type = si->rntiType;
287     ep->stats.ueid = si->ueid;
288
289     /* Counts for new UE are all 0 */
290     ep->stats.UL_frames = 0;
291     ep->stats.DL_frames = 0;
292     ep->stats.UL_total_bytes = 0;
293     ep->stats.UL_raw_bytes = 0;
294     ep->stats.DL_raw_bytes = 0;
295     ep->stats.UL_padding_bytes = 0;
296     ep->stats.DL_padding_bytes = 0;
297     ep->stats.DL_total_bytes = 0;
298     ep->stats.UL_CRC_errors = 0;
299     ep->stats.DL_CRC_failures = 0;
300     ep->stats.DL_CRC_high_code_rate = 0;
301     ep->stats.DL_CRC_PDSCH_lost = 0;
302     ep->stats.DL_CRC_Duplicate_Nonzero_rv = 0;
303     ep->stats.UL_retx_frames = 0;
304     ep->stats.DL_retx_frames = 0;
305
306     for (n=0; n < 11; n++) {
307         ep->stats.UL_sdus_for_lcid[n] = 0;
308         ep->stats.UL_bytes_for_lcid[n] = 0;
309     }
310     ep->stats.DL_total_bytes = 0;
311     for (n=0; n < 11; n++) {
312         ep->stats.DL_sdus_for_lcid[n] = 0;
313         ep->stats.DL_bytes_for_lcid[n] = 0;
314     }
315
316     ep->next = NULL;
317
318     ep->iter_valid = FALSE;
319
320     return ep;
321 }
322
323
324 /* Update counts of unique rntis & ueids */
325 static void update_ueid_rnti_counts(guint16 rnti, guint16 ueid, mac_lte_stat_t *hs)
326 {
327     if (!hs->used_ueids[ueid]) {
328         hs->used_ueids[ueid] = TRUE;
329         hs->number_of_ueids++;
330     }
331     if (!hs->used_rntis[rnti]) {
332         hs->used_rntis[rnti] = TRUE;
333         hs->number_of_rntis++;
334     }
335 }
336
337
338 /* Process stat struct for a MAC LTE frame */
339 static int mac_lte_stat_packet(void *phs, packet_info *pinfo, epan_dissect_t *edt _U_,
340                                const void *phi)
341 {
342     int n;
343
344     /* Get reference to stat window instance */
345     mac_lte_stat_t *hs = (mac_lte_stat_t *)phs;
346     mac_lte_ep_t *tmp = NULL, *te = NULL;
347
348     /* Cast tap info struct */
349     const struct mac_lte_tap_info *si = (const struct mac_lte_tap_info *)phi;
350
351     if (!hs) {
352         return 0;
353     }
354
355     hs->common_stats.all_frames++;
356
357     /* For common channels, just update global counters */
358     switch (si->rntiType) {
359         case P_RNTI:
360             hs->common_stats.pch_frames++;
361             hs->common_stats.pch_bytes += si->single_number_of_bytes;
362             hs->common_stats.pch_paging_ids += si->number_of_paging_ids;
363             return 1;
364         case SI_RNTI:
365             hs->common_stats.sib_frames++;
366             hs->common_stats.sib_bytes += si->single_number_of_bytes;
367             return 1;
368         case NO_RNTI:
369             hs->common_stats.mib_frames++;
370             return 1;
371         case RA_RNTI:
372             hs->common_stats.rar_frames++;
373             hs->common_stats.rar_entries += si->number_of_rars;
374             return 1;
375         case C_RNTI:
376         case SPS_RNTI:
377             /* Drop through for per-UE update */
378             break;
379
380         default:
381             /* Error */
382             return 0;
383     }
384
385     /* Check max UEs/tti counter */
386     switch (si->direction) {
387         case DIRECTION_UPLINK:
388             hs->common_stats.max_ul_ues_in_tti =
389                 MAX(hs->common_stats.max_ul_ues_in_tti, si->ueInTTI);
390             break;
391         case DIRECTION_DOWNLINK:
392             hs->common_stats.max_dl_ues_in_tti =
393                 MAX(hs->common_stats.max_dl_ues_in_tti, si->ueInTTI);
394             break;
395     }
396
397     /* For per-UE data, must create a new row if none already existing */
398     if (!hs->ep_list) {
399         /* Allocate new list */
400         hs->ep_list = alloc_mac_lte_ep(si, pinfo);
401         /* Make it the first/only entry */
402         te = hs->ep_list;
403
404         /* Update counts of unique ueids & rntis */
405         update_ueid_rnti_counts(si->rnti, si->ueid, hs);
406     } else {
407         /* Look among existing rows for this RNTI */
408         for (tmp = hs->ep_list;(tmp != NULL); tmp = tmp->next) {
409             /* Match only by RNTI and UEId together */
410             if ((tmp->stats.rnti == si->rnti) &&
411                 (tmp->stats.ueid == si->ueid)) {
412                 te = tmp;
413                 break;
414             }
415         }
416
417         /* Not found among existing, so create a new one anyway */
418         if (te == NULL) {
419             if ((te = alloc_mac_lte_ep(si, pinfo))) {
420                 /* Add new item to end of list */
421                 mac_lte_ep_t *p = hs->ep_list;
422                 while (p->next) {
423                     p = p->next;
424                 }
425                 p->next = te;
426                 te->next = NULL;
427
428                 /* Update counts of unique ueids & rntis */
429                 update_ueid_rnti_counts(si->rnti, si->ueid, hs);
430             }
431         }
432     }
433
434     /* Really should have a row pointer by now */
435     if (!te) {
436         return 0;
437     }
438
439     /* Update entry with details from si */
440     te->stats.rnti = si->rnti;
441     te->stats.is_predefined_data = si->isPredefinedData;
442
443     /* Uplink */
444     if (si->direction == DIRECTION_UPLINK) {
445         if (si->isPHYRetx) {
446             te->stats.UL_retx_frames++;
447             return 1;
448         }
449
450         if (si->crcStatusValid && (si->crcStatus != crc_success)) {
451             te->stats.UL_CRC_errors++;
452             return 1;
453         }
454
455         /* Update time range */
456         if (te->stats.UL_frames == 0) {
457             te->stats.UL_time_start = si->time;
458         }
459         te->stats.UL_time_stop = si->time;
460
461         te->stats.UL_frames++;
462
463         te->stats.UL_raw_bytes += si->raw_length;
464         te->stats.UL_padding_bytes += si->padding_bytes;
465
466         if (si->isPredefinedData) {
467             te->stats.UL_total_bytes += si->single_number_of_bytes;
468         }
469         else {
470             for (n=0; n < 11; n++) {
471                 te->stats.UL_sdus_for_lcid[n] += si->sdus_for_lcid[n];
472                 te->stats.UL_bytes_for_lcid[n] += si->bytes_for_lcid[n];
473                 te->stats.UL_total_bytes += si->bytes_for_lcid[n];
474             }
475         }
476     }
477
478     /* Downlink */
479     else {
480         if (si->isPHYRetx) {
481             te->stats.DL_retx_frames++;
482             return 1;
483         }
484
485         if (si->crcStatusValid && (si->crcStatus != crc_success)) {
486             switch (si->crcStatus) {
487                 case crc_fail:
488                     te->stats.DL_CRC_failures++;
489                     break;
490                 case crc_high_code_rate:
491                     te->stats.DL_CRC_high_code_rate++;
492                     break;
493                 case crc_pdsch_lost:
494                     te->stats.DL_CRC_PDSCH_lost++;
495                     break;
496                 case crc_duplicate_nonzero_rv:
497                     te->stats.DL_CRC_Duplicate_Nonzero_rv++;
498                     break;
499
500                 default:
501                     /* Something went wrong! */
502                     break;
503             }
504             return 1;
505         }
506
507         /* Update time range */
508         if (te->stats.DL_frames == 0) {
509             te->stats.DL_time_start = si->time;
510         }
511         te->stats.DL_time_stop = si->time;
512
513         te->stats.DL_frames++;
514
515         te->stats.DL_raw_bytes += si->raw_length;
516         te->stats.DL_padding_bytes += si->padding_bytes;
517
518         if (si->isPredefinedData) {
519             te->stats.DL_total_bytes += si->single_number_of_bytes;
520         }
521         else {
522             for (n=0; n < 11; n++) {
523                 te->stats.DL_sdus_for_lcid[n] += si->sdus_for_lcid[n];
524                 te->stats.DL_bytes_for_lcid[n] += si->bytes_for_lcid[n];
525                 te->stats.DL_total_bytes += si->bytes_for_lcid[n];
526             }
527         }
528     }
529
530     return 1;
531 }
532
533
534 /* Draw the UE details table according to the current UE selection */
535 static void mac_lte_ue_details(mac_lte_ep_t *mac_stat_ep, mac_lte_stat_t *hs)
536 {
537     int    n;
538     gchar  buff[32];
539     guint8 show_dct_errors;
540
541     /**********************************/
542     /* Set data one row at a time     */
543
544     /* UL SDUs */
545     for (n=0; n < PREDEFINED_COLUMN-1; n++) {
546         g_snprintf(buff, sizeof(buff), "%u",
547                    (mac_stat_ep != NULL) ? mac_stat_ep->stats.UL_sdus_for_lcid[n] : 0);
548          gtk_label_set_text(GTK_LABEL(hs->selected_ue_column_entry[n+1][1]), buff);
549     }
550
551     /* Predefined */
552     if (mac_stat_ep != NULL) {
553         g_snprintf(buff, sizeof(buff), "%u",
554                    mac_stat_ep->stats.is_predefined_data ? mac_stat_ep->stats.UL_frames : 0);
555     }
556     else {
557         g_snprintf(buff, sizeof(buff), "%u", 0);
558     }
559     gtk_label_set_text(GTK_LABEL(hs->selected_ue_column_entry[PREDEFINED_COLUMN][1]), buff);
560
561
562     /* UL Bytes */
563     for (n=0; n < PREDEFINED_COLUMN-1; n++) {
564         g_snprintf(buff, sizeof(buff), "%u",
565                    (mac_stat_ep != NULL) ? mac_stat_ep->stats.UL_bytes_for_lcid[n] : 0);
566         gtk_label_set_text(GTK_LABEL(hs->selected_ue_column_entry[n+1][2]), buff);
567     }
568
569     /* Predefined */
570     if (mac_stat_ep != NULL) {
571         g_snprintf(buff, sizeof(buff), "%u",
572                    mac_stat_ep->stats.is_predefined_data ? mac_stat_ep->stats.UL_total_bytes : 0);
573     }
574     else {
575         g_snprintf(buff, sizeof(buff), "%u", 0);
576     }
577     gtk_label_set_text(GTK_LABEL(hs->selected_ue_column_entry[PREDEFINED_COLUMN][2]), buff);
578
579
580     /* DL SDUs */
581     for (n=0; n < PREDEFINED_COLUMN-1; n++) {
582         g_snprintf(buff, sizeof(buff), "%u",
583                    (mac_stat_ep != NULL) ? mac_stat_ep->stats.DL_sdus_for_lcid[n] : 0);
584         gtk_label_set_text(GTK_LABEL(hs->selected_ue_column_entry[n+1][3]), buff);
585     }
586     /* Predefined */
587     if (mac_stat_ep != NULL) {
588         g_snprintf(buff, sizeof(buff), "%u",
589                    mac_stat_ep->stats.is_predefined_data ? mac_stat_ep->stats.DL_frames : 0);
590     }
591     else {
592         g_snprintf(buff, sizeof(buff), "%u", 0);
593     }
594     gtk_label_set_text(GTK_LABEL(hs->selected_ue_column_entry[PREDEFINED_COLUMN][3]), buff);
595
596
597     /* DL Bytes */
598     for (n=0; n < PREDEFINED_COLUMN-1; n++) {
599         g_snprintf(buff, sizeof(buff), "%u",
600                    (mac_stat_ep != NULL) ? mac_stat_ep->stats.DL_bytes_for_lcid[n] : 0);
601         gtk_label_set_text(GTK_LABEL(hs->selected_ue_column_entry[n+1][4]), buff);
602     }
603     /* Predefined */
604     if (mac_stat_ep != NULL) {
605         g_snprintf(buff, sizeof(buff), "%u",
606                    mac_stat_ep->stats.is_predefined_data ? mac_stat_ep->stats.DL_total_bytes : 0);
607     }
608     else {
609         g_snprintf(buff, sizeof(buff), "%u", 0);
610     }
611     gtk_label_set_text(GTK_LABEL(hs->selected_ue_column_entry[PREDEFINED_COLUMN][4]), buff);
612
613     /* Remember selected UE */
614     if (mac_stat_ep) {
615         hs->selected_rnti = mac_stat_ep->stats.rnti;
616         hs->selected_ueid = mac_stat_ep->stats.ueid;
617     }
618
619     /* Enable/disable filter controls */
620     gtk_widget_set_sensitive(hs->ul_filter_bt, mac_stat_ep != NULL);
621     gtk_widget_set_sensitive(hs->dl_filter_bt, mac_stat_ep != NULL);
622     gtk_widget_set_sensitive(hs->uldl_filter_bt, mac_stat_ep != NULL);
623     gtk_widget_set_sensitive(hs->show_mac_rach_cb, mac_stat_ep != NULL);
624     gtk_widget_set_sensitive(hs->show_mac_srs_cb, mac_stat_ep != NULL);
625     gtk_widget_set_sensitive(hs->show_dct_errors_cb, mac_stat_ep != NULL);
626
627     /* Enabling substring control only if errors enabled */
628     show_dct_errors = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(hs->show_dct_errors_cb));
629     gtk_widget_set_sensitive(hs->dct_error_substring_lb, show_dct_errors && (mac_stat_ep != NULL));
630     gtk_widget_set_sensitive(hs->dct_error_substring_te, show_dct_errors && (mac_stat_ep != NULL));
631 }
632
633
634 /* Calculate and return a bandwidth figure, in Mbs */
635 static float calculate_bw(nstime_t *start_time, nstime_t *stop_time, guint32 bytes)
636 {
637     /* Can only calculate bandwidth if have time delta */
638     if (memcmp(start_time, stop_time, sizeof(nstime_t)) != 0) {
639         float elapsed_ms = (((float)stop_time->secs - (float)start_time->secs) * 1000) +
640                            (((float)stop_time->nsecs - (float)start_time->nsecs) / 1000000);
641
642         /* Only really meaningful if have a few frames spread over time...
643            For now at least avoid dividing by something very close to 0.0 */
644         if (elapsed_ms < 2.0) {
645            return 0.0f;
646         }
647         return ((bytes * 8) / elapsed_ms) / 1000;
648     }
649     else {
650         return 0.0f;
651     }
652 }
653
654
655 /* (Re)draw the whole dialog window */
656 static void mac_lte_stat_draw(void *phs)
657 {
658     gchar    buff[32];
659     guint16  number_of_ues = 0;
660     char    *display_name;
661     gchar    title[256];
662
663     /* Look up the statistics window */
664     mac_lte_stat_t   *hs   = (mac_lte_stat_t *)phs;
665     mac_lte_ep_t     *list = hs->ep_list, *tmp = 0;
666
667     GtkListStore     *ues_store;
668     GtkTreeSelection *sel;
669     GtkTreeModel     *model;
670     GtkTreeIter       iter;
671
672     /* System data */
673     g_snprintf(buff, sizeof(buff), "Max UL UEs/TTI: %u", hs->common_stats.max_ul_ues_in_tti);
674     gtk_label_set_text(GTK_LABEL(hs->ul_max_ues_per_tti), buff);
675     g_snprintf(buff, sizeof(buff), "Max DL UEs/TTI: %u", hs->common_stats.max_dl_ues_in_tti);
676     gtk_label_set_text(GTK_LABEL(hs->dl_max_ues_per_tti), buff);
677
678     /* Common channel data */
679     g_snprintf(buff, sizeof(buff), "MIBs: %u", hs->common_stats.mib_frames);
680     gtk_label_set_text(GTK_LABEL(hs->common_mib_frames), buff);
681     g_snprintf(buff, sizeof(buff), "SIB Frames: %u", hs->common_stats.sib_frames);
682     gtk_label_set_text(GTK_LABEL(hs->common_sib_frames), buff);
683     g_snprintf(buff, sizeof(buff), "SIB Bytes: %u", hs->common_stats.sib_bytes);
684     gtk_label_set_text(GTK_LABEL(hs->common_sib_bytes), buff);
685     g_snprintf(buff, sizeof(buff), "PCH Frames: %u", hs->common_stats.pch_frames);
686     gtk_label_set_text(GTK_LABEL(hs->common_pch_frames), buff);
687     g_snprintf(buff, sizeof(buff), "PCH Bytes: %u", hs->common_stats.pch_bytes);
688     gtk_label_set_text(GTK_LABEL(hs->common_pch_bytes), buff);
689     g_snprintf(buff, sizeof(buff), "PCH Paging Ids: %u", hs->common_stats.pch_paging_ids);
690     gtk_label_set_text(GTK_LABEL(hs->common_pch_paging_ids), buff);
691     g_snprintf(buff, sizeof(buff), "RAR Frames: %u", hs->common_stats.rar_frames);
692     gtk_label_set_text(GTK_LABEL(hs->common_rar_frames), buff);
693     g_snprintf(buff, sizeof(buff), "RAR Entries: %u", hs->common_stats.rar_entries);
694     gtk_label_set_text(GTK_LABEL(hs->common_rar_entries), buff);
695
696
697     /* Per-UE table entries */
698     ues_store = GTK_LIST_STORE(gtk_tree_view_get_model(hs->ue_table));
699
700     /* Set title that shows how many UEs currently in table */
701     for (tmp = list; (tmp!=NULL); tmp=tmp->next, number_of_ues++);
702     g_snprintf(title, sizeof(title), "UL/DL-SCH data (%u entries - %u unique RNTIs, %u unique UEIds)",
703                number_of_ues, hs->number_of_rntis, hs->number_of_ueids);
704     gtk_frame_set_label(GTK_FRAME(hs->mac_lte_stat_ues_lb), title);
705
706     /* Update title to include number of UEs and frames */
707     display_name = cf_get_display_name(&cfile);
708     g_snprintf(title, sizeof(title), "Wireshark: LTE MAC Traffic Statistics: %s (%u UEs, %u frames) (filter=\"%s\")",
709                display_name,
710                number_of_ues,
711                hs->common_stats.all_frames,
712                strlen(hs->filter) ? hs->filter : "none");
713     g_free(display_name);
714     gtk_window_set_title(GTK_WINDOW(hs->mac_lte_stat_dlg_w), title);
715
716
717     for (tmp = list; tmp; tmp=tmp->next) {
718
719         /* Calculate bandwidth */
720         float UL_bw = calculate_bw(&tmp->stats.UL_time_start,
721                                    &tmp->stats.UL_time_stop,
722                                    tmp->stats.UL_total_bytes);
723         float DL_bw = calculate_bw(&tmp->stats.DL_time_start,
724                                    &tmp->stats.DL_time_stop,
725                                    tmp->stats.DL_total_bytes);
726
727         if (tmp->iter_valid != TRUE) {
728             /* Add to list control if not drawn this UE before */
729             gtk_list_store_append(ues_store, &tmp->iter);
730             tmp->iter_valid = TRUE;
731         }
732
733         /* Set each column for this row */
734         gtk_list_store_set(ues_store, &tmp->iter,
735                            RNTI_COLUMN, tmp->stats.rnti,
736                            RNTI_TYPE_COLUMN,
737                                (tmp->stats.rnti_type == C_RNTI) ? "C-RNTI" : "SPS-RNTI",
738                            UEID_COLUMN, tmp->stats.ueid,
739                            UL_FRAMES_COLUMN, tmp->stats.UL_frames,
740                            UL_BYTES_COLUMN, tmp->stats.UL_total_bytes,
741                            UL_BW_COLUMN, UL_bw,
742                            UL_PADDING_PERCENT_COLUMN,
743                                 tmp->stats.UL_raw_bytes ?
744                                     (((float)tmp->stats.UL_padding_bytes / (float)tmp->stats.UL_raw_bytes) * 100.0) :
745                                     0.0,
746                            UL_RETX_FRAMES_COLUMN, tmp->stats.UL_retx_frames,
747                            DL_FRAMES_COLUMN, tmp->stats.DL_frames,
748                            DL_BYTES_COLUMN, tmp->stats.DL_total_bytes,
749                            DL_BW_COLUMN, DL_bw,
750                            DL_PADDING_PERCENT_COLUMN,
751                                 tmp->stats.DL_raw_bytes ?
752                                     (((float)tmp->stats.DL_padding_bytes / (float)tmp->stats.DL_raw_bytes) * 100.0) :
753                                     0.0,
754                            DL_CRC_FAILED_COLUMN, tmp->stats.DL_CRC_failures,
755                            DL_CRC_HIGH_CODE_RATE_COLUMN, tmp->stats.DL_CRC_high_code_rate,
756                            DL_CRC_PDSCH_LOST_COLUMN, tmp->stats.DL_CRC_PDSCH_lost,
757                            DL_CRC_DUPLICATE_NONZERO_RV, tmp->stats.DL_CRC_Duplicate_Nonzero_rv,
758                            DL_RETX_FRAMES_COLUMN, tmp->stats.DL_retx_frames,
759                            TABLE_COLUMN, tmp,
760                            -1);
761     }
762
763     /* Reselect UE? */
764     if (hs->selected_rnti != 0) {
765         GtkTreeIter *ue_iter = NULL;
766         mac_lte_ep_t *ep = hs->ep_list;
767         while (ep != NULL) {
768             if ((ep->stats.ueid == hs->selected_ueid) &&
769                 (ep->stats.rnti == hs->selected_rnti)) {
770                 ue_iter = &ep->iter;
771                 break;
772             }
773             ep = ep->next;
774         }
775         if (ue_iter != NULL) {
776             /* Make selection */
777             gtk_tree_selection_select_iter(gtk_tree_view_get_selection(hs->ue_table),
778                                            ue_iter);
779         }
780     }
781
782     /* If there is a UE selected, update its counters in details window */
783     sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(hs->ue_table));
784     if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
785         mac_lte_ep_t *ep;
786
787         gtk_tree_model_get(model, &iter, TABLE_COLUMN, &ep, -1);
788         mac_lte_ue_details(ep, hs);
789     }
790 }
791
792
793 /* Compose and set appropriate display filter */
794 typedef enum Direction_t {UL_Only, DL_Only, UL_and_DL} Direction_t;
795
796 static void set_filter_expression(guint16         ueid,
797                                   guint16         rnti,
798                                   Direction_t     direction,
799                                   gint            showRACH,
800                                   gint            showSRs,
801                                   gint            showDCTErrors,
802                                   const gchar    *DCTErrorSubstring,
803                                   mac_lte_stat_t *hs)
804 {
805     #define MAX_FILTER_LEN 512
806     static char buffer[MAX_FILTER_LEN];
807     int         offset = 0;
808
809     /* Create the filter expression */
810
811     /* Show MAC RACH (preamble attempts and RAR PDUs) */
812     if (showRACH) {
813         offset += g_snprintf(buffer+offset, MAX_FILTER_LEN-offset,
814                                          "(mac-lte.rar or (mac-lte.preamble-sent and mac-lte.ueid == %u)) or (",
815                                          ueid);
816     }
817
818     /* Show MAC SRs */
819     if (showSRs) {
820         offset += g_snprintf(buffer+offset, MAX_FILTER_LEN-offset,
821                                          "(mac-lte.sr-req and mac-lte.ueid == %u) or (",
822                                          ueid);
823     }
824
825     /* Errors */
826     if (showDCTErrors) {
827         if (strlen(DCTErrorSubstring) > 0) {
828             offset += g_snprintf(buffer+offset, MAX_FILTER_LEN-offset,
829                                  "(dct2000.error-comment and (dct2000.comment contains \"%s\")) or (",
830                                  DCTErrorSubstring);
831         }
832         else {
833             offset += g_snprintf(buffer+offset, MAX_FILTER_LEN-offset,
834                                  "dct2000.error-comment or (");
835         }
836     }
837
838     /* Filter expression */
839     if (strlen(hs->filter)) {
840         offset += g_snprintf(buffer+offset, MAX_FILTER_LEN-offset, "%s and ", hs->filter);
841     }
842
843     /* Direction */
844     switch (direction) {
845         case UL_Only:
846             offset += g_snprintf(buffer+offset, MAX_FILTER_LEN-offset, "(mac-lte.direction == 0) and ");
847             break;
848         case DL_Only:
849             offset += g_snprintf(buffer+offset, MAX_FILTER_LEN-offset, "(mac-lte.direction == 1) and ");
850             break;
851         default:
852             break;
853     }
854
855     /* Selected UE */
856     offset += g_snprintf(buffer+offset, MAX_FILTER_LEN-offset,
857                          "mac-lte.rnti == %u and mac-lte.ueid == %u",
858                          rnti, ueid);
859
860     /* Close () if open */
861     if (showRACH) {
862         offset += g_snprintf(buffer+offset, MAX_FILTER_LEN-offset, ")");
863     }
864
865     /* Close () if open */
866     if (showSRs) {
867         offset += g_snprintf(buffer+offset, MAX_FILTER_LEN-offset, ")");
868     }
869
870
871     /* Close () if open */
872     if (showDCTErrors) {
873         /*offset +=*/ g_snprintf(buffer+offset, MAX_FILTER_LEN-offset, ")");
874     }
875
876     /* Set its value to our new string */
877     gtk_entry_set_text(GTK_ENTRY(main_display_filter_widget), buffer);
878
879     /* Run the filter */
880     main_filter_packets(&cfile, buffer, TRUE);
881 }
882
883 /* Respond to UL filter button being clicked by building and using filter */
884 static void ul_filter_clicked(GtkWindow *win _U_, mac_lte_stat_t* hs)
885 {
886     GtkTreeSelection *sel;
887     GtkTreeModel     *model;
888     GtkTreeIter       iter;
889
890     /* If there is a UE selected, update its counters in details window */
891     sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(hs->ue_table));
892     if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
893         mac_lte_ep_t *ep;
894
895         /* Get the UE details */
896         gtk_tree_model_get(model, &iter, TABLE_COLUMN, &ep, -1);
897
898         set_filter_expression(ep->stats.ueid, ep->stats.rnti, UL_Only,
899                               gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(hs->show_mac_rach_cb)),
900                               gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(hs->show_mac_srs_cb)),
901                               gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(hs->show_dct_errors_cb)),
902                               gtk_entry_get_text(GTK_ENTRY(hs->dct_error_substring_te)),
903                               hs);
904     }
905 }
906
907 /* Respond to DL filter button being clicked by building and using filter */
908 static void dl_filter_clicked(GtkWindow *win _U_, mac_lte_stat_t *hs)
909 {
910     GtkTreeSelection *sel;
911     GtkTreeModel     *model;
912     GtkTreeIter       iter;
913
914     /* If there is a UE selected, update its counters in details window */
915     sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(hs->ue_table));
916     if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
917         mac_lte_ep_t *ep;
918
919         /* Get the UE details */
920         gtk_tree_model_get(model, &iter, TABLE_COLUMN, &ep, -1);
921
922         set_filter_expression(ep->stats.ueid, ep->stats.rnti, DL_Only,
923                               gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(hs->show_mac_rach_cb)),
924                               gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(hs->show_mac_srs_cb)),
925                               gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(hs->show_dct_errors_cb)),
926                               gtk_entry_get_text(GTK_ENTRY(hs->dct_error_substring_te)),
927                               hs);
928     }
929
930 }
931
932 /* Respond to UL/DL filter button being clicked by building and using filter */
933 static void uldl_filter_clicked(GtkWindow *win _U_, mac_lte_stat_t *hs)
934 {
935     GtkTreeSelection *sel;
936     GtkTreeModel     *model;
937     GtkTreeIter       iter;
938
939     /* If there is a UE selected, update its counters in details window */
940     sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(hs->ue_table));
941     if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
942         mac_lte_ep_t *ep;
943
944         /* Get the UE details */
945         gtk_tree_model_get(model, &iter, TABLE_COLUMN, &ep, -1);
946
947         set_filter_expression(ep->stats.ueid, ep->stats.rnti, UL_and_DL,
948                               gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(hs->show_mac_rach_cb)),
949                               gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(hs->show_mac_srs_cb)),
950                               gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(hs->show_dct_errors_cb)),
951                               gtk_entry_get_text(GTK_ENTRY(hs->dct_error_substring_te)),
952                               hs);
953     }
954
955 }
956
957
958 /* What to do when a list item is selected/unselected */
959 static void mac_lte_select_cb(GtkTreeSelection *sel, gpointer data)
960 {
961     mac_lte_stat_t *hs = (mac_lte_stat_t *)data;
962     mac_lte_ep_t   *ep;
963     GtkTreeModel   *model;
964     GtkTreeIter     iter;
965
966     if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
967         /* Show details of selected UE */
968         gtk_tree_model_get(model, &iter, TABLE_COLUMN, &ep, -1);
969         mac_lte_ue_details(ep, hs);
970     }
971     else {
972         mac_lte_ue_details(NULL, hs);
973     }
974 }
975
976 /* When DCT errors check-box is toggled, enable substring controls accordingly */
977 static void mac_lte_dct_errors_cb(GtkTreeSelection *sel _U_, gpointer data)
978 {
979     mac_lte_stat_t *hs = (mac_lte_stat_t*)data;
980     guint8 show_dct_errors = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(hs->show_dct_errors_cb));
981
982     gtk_widget_set_sensitive(hs->dct_error_substring_lb, show_dct_errors);
983     gtk_widget_set_sensitive(hs->dct_error_substring_te, show_dct_errors);
984 }
985
986
987 /* Destroy the stats window */
988 static void win_destroy_cb(GtkWindow *win _U_, gpointer data)
989 {
990     mac_lte_stat_t *hs = (mac_lte_stat_t *)data;
991
992     remove_tap_listener(hs);
993
994     if (hs->mac_lte_stat_dlg_w != NULL) {
995         window_destroy(hs->mac_lte_stat_dlg_w);
996         hs->mac_lte_stat_dlg_w = NULL;
997     }
998     mac_lte_stat_reset(hs);
999     g_free(hs->filter);
1000     g_free(hs);
1001 }
1002
1003
1004 /* Create a new MAC LTE stats dialog */
1005 static void gtk_mac_lte_stat_init(const char *opt_arg, void *userdata _U_)
1006 {
1007     mac_lte_stat_t *hs;
1008     const char *filter = NULL;
1009     GString    *error_string;
1010     GtkWidget  *ues_scrolled_window;
1011     GtkWidget  *bbox;
1012     GtkWidget  *top_level_vbox;
1013
1014     GtkWidget  *system_row_hbox;
1015     GtkWidget  *common_row_hbox;
1016     GtkWidget  *ues_vb;
1017     GtkWidget  *selected_ue_hb;
1018
1019     GtkWidget  *mac_lte_stat_system_lb;
1020     GtkWidget  *mac_lte_stat_common_channel_lb;
1021     GtkWidget  *mac_lte_stat_selected_ue_lb;
1022     GtkWidget  *selected_ue_vbox[NUM_CHANNEL_COLUMNS];
1023     GtkWidget  *selected_ue_column_titles[5];
1024
1025     GtkWidget  *mac_lte_stat_filters_lb;
1026     GtkWidget  *filter_buttons_hb;
1027
1028     GtkWidget  *close_bt;
1029     GtkWidget  *help_bt;
1030
1031     GtkListStore *store;
1032
1033     GtkTreeView       *tree_view;
1034     GtkCellRenderer   *renderer;
1035     GtkTreeViewColumn *column;
1036     GtkTreeSelection  *sel;
1037     gchar *display_name;
1038     gchar  title[256];
1039     gint   i, n;
1040
1041     /* Check for a filter string */
1042     if (strncmp(opt_arg, "mac-lte,stat,", 13) == 0) {
1043         /* Skip those characters from filter to display */
1044         filter = opt_arg + 13;
1045     }
1046     else {
1047         /* No filter */
1048         filter = NULL;
1049     }
1050
1051
1052     /* Create dialog */
1053     hs = (mac_lte_stat_t *)g_malloc(sizeof(mac_lte_stat_t));
1054     hs->ep_list = NULL;
1055
1056     /* Copy filter (so can be used for window title at reset) */
1057     if (filter) {
1058         hs->filter = g_strdup(filter);
1059     }
1060     else {
1061         hs->filter = NULL;
1062     }
1063
1064     /* Set title */
1065     display_name = cf_get_display_name(&cfile);
1066     g_snprintf(title, sizeof(title), "Wireshark: LTE MAC Statistics: %s",
1067                display_name);
1068     g_free(display_name);
1069
1070     /* Create top-level window */
1071     hs->mac_lte_stat_dlg_w = window_new_with_geom(GTK_WINDOW_TOPLEVEL, title, "LTE MAC Statistics", GTK_WIN_POS_CENTER_ON_PARENT);
1072
1073     /* Window size */
1074     gtk_window_set_default_size(GTK_WINDOW(hs->mac_lte_stat_dlg_w), 750, 300);
1075
1076     /* Will stack widgets vertically inside dlg */
1077     top_level_vbox = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 3, FALSE);       /* FALSE = not homogeneous */
1078     gtk_container_add(GTK_CONTAINER(hs->mac_lte_stat_dlg_w), top_level_vbox);
1079
1080     gtk_container_set_border_width(GTK_CONTAINER(top_level_vbox), 6);
1081     gtk_widget_show(top_level_vbox);
1082
1083
1084     /**********************************************/
1085     /* System data                                */
1086     /**********************************************/
1087     mac_lte_stat_system_lb = gtk_frame_new("System Data");
1088
1089     /* Add max UEs/TTI counts in one row */
1090     system_row_hbox = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0, FALSE);
1091     gtk_container_add(GTK_CONTAINER(mac_lte_stat_system_lb), system_row_hbox);
1092     gtk_container_set_border_width(GTK_CONTAINER(system_row_hbox), 5);
1093
1094     gtk_box_pack_start(GTK_BOX(top_level_vbox), mac_lte_stat_system_lb, FALSE, FALSE, 0);
1095
1096     /* Create labels (that will hold label and counter value) */
1097     hs->ul_max_ues_per_tti = gtk_label_new("Max UL UEs/TTI:");
1098     gtk_misc_set_alignment(GTK_MISC(hs->ul_max_ues_per_tti), 0.0f, .5f);
1099     gtk_box_pack_start(GTK_BOX(system_row_hbox), hs->ul_max_ues_per_tti, TRUE, TRUE, 0);
1100     gtk_widget_show(hs->ul_max_ues_per_tti);
1101
1102     hs->dl_max_ues_per_tti = gtk_label_new("Max DL UEs/TTI:");
1103     gtk_misc_set_alignment(GTK_MISC(hs->dl_max_ues_per_tti), 0.0f, .5f);
1104     gtk_box_pack_start(GTK_BOX(system_row_hbox), hs->dl_max_ues_per_tti, TRUE, TRUE, 0);
1105     gtk_widget_show(hs->dl_max_ues_per_tti);
1106
1107
1108     /**********************************************/
1109     /* Common Channel data                        */
1110     /**********************************************/
1111     mac_lte_stat_common_channel_lb = gtk_frame_new("Common Channel Data");
1112
1113     /* Will add BCH and PCH counters into one row */
1114     common_row_hbox = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0, FALSE);
1115     gtk_container_add(GTK_CONTAINER(mac_lte_stat_common_channel_lb), common_row_hbox);
1116     gtk_container_set_border_width(GTK_CONTAINER(common_row_hbox), 5);
1117
1118     gtk_box_pack_start(GTK_BOX(top_level_vbox), mac_lte_stat_common_channel_lb, FALSE, FALSE, 0);
1119
1120     /* Create labels (that will hold label and counter value) */
1121     hs->common_mib_frames = gtk_label_new("MIBs:");
1122     gtk_misc_set_alignment(GTK_MISC(hs->common_mib_frames), 0.0f, .5f);
1123     gtk_box_pack_start(GTK_BOX(common_row_hbox), hs->common_mib_frames, TRUE, TRUE, 0);
1124     gtk_widget_show(hs->common_mib_frames);
1125
1126     hs->common_sib_frames = gtk_label_new("SIB Frames:");
1127     gtk_misc_set_alignment(GTK_MISC(hs->common_sib_frames), 0.0f, .5f);
1128     gtk_box_pack_start(GTK_BOX(common_row_hbox), hs->common_sib_frames, TRUE, TRUE, 0);
1129     gtk_widget_show(hs->common_sib_frames);
1130
1131     hs->common_sib_bytes = gtk_label_new("SIB Bytes:");
1132     gtk_misc_set_alignment(GTK_MISC(hs->common_sib_bytes), 0.0f, .5f);
1133     gtk_box_pack_start(GTK_BOX(common_row_hbox), hs->common_sib_bytes, TRUE, TRUE, 0);
1134     gtk_widget_show(hs->common_sib_bytes);
1135
1136     hs->common_pch_frames = gtk_label_new("PCH Frames:");
1137     gtk_misc_set_alignment(GTK_MISC(hs->common_pch_frames), 0.0f, .5f);
1138     gtk_box_pack_start(GTK_BOX(common_row_hbox), hs->common_pch_frames, TRUE, TRUE, 0);
1139     gtk_widget_show(hs->common_pch_frames);
1140
1141     hs->common_pch_bytes = gtk_label_new("PCH Bytes:");
1142     gtk_misc_set_alignment(GTK_MISC(hs->common_pch_bytes), 0.0f, .5f);
1143     gtk_box_pack_start(GTK_BOX(common_row_hbox), hs->common_pch_bytes, TRUE, TRUE, 0);
1144     gtk_widget_show(hs->common_pch_bytes);
1145
1146     hs->common_pch_paging_ids = gtk_label_new("PCH Paging IDs:");
1147     gtk_misc_set_alignment(GTK_MISC(hs->common_pch_paging_ids), 0.0f, .5f);
1148     gtk_box_pack_start(GTK_BOX(common_row_hbox), hs->common_pch_paging_ids, TRUE, TRUE, 0);
1149     gtk_widget_show(hs->common_pch_paging_ids);
1150
1151
1152     hs->common_rar_frames = gtk_label_new("RAR Frames:");
1153     gtk_misc_set_alignment(GTK_MISC(hs->common_rar_frames), 0.0f, .5f);
1154     gtk_box_pack_start(GTK_BOX(common_row_hbox), hs->common_rar_frames, TRUE, TRUE, 0);
1155     gtk_widget_show(hs->common_rar_frames);
1156
1157     hs->common_rar_entries = gtk_label_new("RAR Entries:");
1158     gtk_misc_set_alignment(GTK_MISC(hs->common_rar_entries), 0.0f, .5f);
1159     gtk_box_pack_start(GTK_BOX(common_row_hbox), hs->common_rar_entries, TRUE, TRUE, 0);
1160     gtk_widget_show(hs->common_rar_entries);
1161
1162     /**********************************************/
1163     /* UL/DL-SCH data                             */
1164     /**********************************************/
1165
1166     hs->mac_lte_stat_ues_lb = gtk_frame_new("UL/DL-SCH Data (0 UEs)");
1167     ues_vb = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 0, FALSE);
1168     gtk_container_add(GTK_CONTAINER(hs->mac_lte_stat_ues_lb), ues_vb);
1169     gtk_container_set_border_width(GTK_CONTAINER(ues_vb), 5);
1170
1171     ues_scrolled_window = scrolled_window_new(NULL, NULL);
1172     gtk_box_pack_start(GTK_BOX(ues_vb), ues_scrolled_window, TRUE, TRUE, 0);
1173     gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(ues_scrolled_window),
1174                                         GTK_SHADOW_IN);
1175
1176     /* Create the table of UE data */
1177     store = gtk_list_store_new(NUM_UE_COLUMNS, G_TYPE_INT, G_TYPE_STRING, G_TYPE_INT,
1178                                G_TYPE_INT, G_TYPE_INT, G_TYPE_FLOAT, G_TYPE_FLOAT, G_TYPE_INT, /* UL */
1179                                G_TYPE_INT, G_TYPE_INT, G_TYPE_FLOAT, G_TYPE_FLOAT, G_TYPE_INT,
1180                                G_TYPE_INT, G_TYPE_INT,  G_TYPE_INT, G_TYPE_INT, /* DL */
1181                                G_TYPE_POINTER);
1182     hs->ue_table = GTK_TREE_VIEW(tree_view_new(GTK_TREE_MODEL(store)));
1183     gtk_container_add(GTK_CONTAINER (ues_scrolled_window), GTK_WIDGET(hs->ue_table));
1184     g_object_unref(G_OBJECT(store));
1185
1186     tree_view = hs->ue_table;
1187     gtk_tree_view_set_headers_visible(tree_view, TRUE);
1188     gtk_tree_view_set_headers_clickable(tree_view, TRUE);
1189
1190     /* Create the titles for each column of the per-UE table */
1191     for (i = 0; i < TABLE_COLUMN; i++) {
1192         if ((i == UL_PADDING_PERCENT_COLUMN) ||
1193             (i == DL_PADDING_PERCENT_COLUMN)) {
1194             /* Show % as progress bar */
1195             /* XXX: "progess" rendering doesn't seem to work for Gtk3 ?? */
1196             renderer = gtk_cell_renderer_progress_new();
1197             column = gtk_tree_view_column_new_with_attributes(ue_titles[i], renderer,
1198                                                               "text", i,
1199                                                               "value", i,
1200                                                               NULL);
1201         }
1202         else {
1203             renderer = gtk_cell_renderer_text_new();
1204             column = gtk_tree_view_column_new_with_attributes(ue_titles[i], renderer,
1205                                                               "text", i, NULL);
1206         }
1207         gtk_tree_view_column_set_sort_column_id(column, i);
1208
1209         if (i == 0) {
1210             /* Expand first column (RNTI, which is Key) */
1211             gtk_tree_view_column_set_expand(column, TRUE);
1212         } else {
1213             /* For other columns, set all of the free space to be on the left */
1214             g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL);
1215         }
1216         gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
1217         gtk_tree_view_column_set_resizable(column, TRUE);
1218         gtk_tree_view_append_column(tree_view, column);
1219     }
1220
1221     /* Set callback function for selecting a row in the UE table */
1222     sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(hs->ue_table));
1223     gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
1224     g_signal_connect(sel, "changed", G_CALLBACK(mac_lte_select_cb), hs);
1225
1226     gtk_box_pack_start(GTK_BOX(top_level_vbox), hs->mac_lte_stat_ues_lb, TRUE, TRUE, 0);
1227
1228
1229     /**********************************************/
1230     /* Details of selected UE                     */
1231     /**********************************************/
1232
1233     mac_lte_stat_selected_ue_lb = gtk_frame_new("Selected UE details");
1234
1235     selected_ue_hb = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6, FALSE);
1236     gtk_container_add(GTK_CONTAINER(mac_lte_stat_selected_ue_lb), selected_ue_hb);
1237     gtk_container_set_border_width(GTK_CONTAINER(selected_ue_hb), 5);
1238
1239     /********************************/
1240     /* First (row titles) column    */
1241     selected_ue_vbox[0] = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 0, FALSE);
1242     gtk_box_pack_start(GTK_BOX(selected_ue_hb), selected_ue_vbox[0], TRUE, TRUE, 0);
1243
1244     selected_ue_column_titles[0] = gtk_label_new("");
1245     gtk_misc_set_alignment(GTK_MISC(selected_ue_column_titles[0]), 0.0f, 0.0f);
1246     gtk_box_pack_start(GTK_BOX(selected_ue_vbox[0]), selected_ue_column_titles[0], FALSE, FALSE, 0);
1247
1248     for (n=1; n < 5; n++) {
1249         selected_ue_column_titles[n] = gtk_label_new(selected_ue_row_names[n-1]);
1250         gtk_misc_set_alignment(GTK_MISC(selected_ue_column_titles[n]), 0.0f, 0.0f);
1251         gtk_box_pack_start(GTK_BOX(selected_ue_vbox[0]), selected_ue_column_titles[n], FALSE, FALSE, 0);
1252         gtk_widget_show(selected_ue_column_titles[n]);
1253     }
1254
1255
1256     /*************************/
1257     /* Other columns         */
1258     for (i=CCCH_COLUMN; i < NUM_CHANNEL_COLUMNS; i++) {
1259         selected_ue_vbox[i] = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 0, FALSE);
1260         gtk_box_pack_start(GTK_BOX(selected_ue_hb), selected_ue_vbox[i], TRUE, TRUE, 0);
1261
1262         /* Channel title */
1263         hs->selected_ue_column_entry[i][0] = gtk_label_new(channel_titles[i-1]);
1264         gtk_misc_set_alignment(GTK_MISC(hs->selected_ue_column_entry[i][0]), 0.5f, 0.0f);
1265         gtk_box_pack_start(GTK_BOX(selected_ue_vbox[i]), hs->selected_ue_column_entry[i][0], FALSE, FALSE, 0);
1266
1267         /* Counts for this channel */
1268         for (n=1; n < 5; n++) {
1269             hs->selected_ue_column_entry[i][n] = gtk_label_new("0");
1270             gtk_misc_set_alignment(GTK_MISC(hs->selected_ue_column_entry[i][n]), 1.0f, 0.0f);
1271             gtk_box_pack_start(GTK_BOX(selected_ue_vbox[i]), hs->selected_ue_column_entry[i][n], FALSE, FALSE, 0);
1272             gtk_widget_show(hs->selected_ue_column_entry[i][n]);
1273         }
1274     }
1275
1276     gtk_box_pack_start(GTK_BOX(top_level_vbox), mac_lte_stat_selected_ue_lb, FALSE, FALSE, 0);
1277
1278
1279     /**************************************/
1280     /* Filter on RNTI/UEId                */
1281     /**************************************/
1282     mac_lte_stat_filters_lb = gtk_frame_new("Filter on UE");
1283
1284     /* Horizontal row of filter controls */
1285     filter_buttons_hb = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6, FALSE);
1286     gtk_container_add(GTK_CONTAINER(mac_lte_stat_filters_lb), filter_buttons_hb);
1287     gtk_container_set_border_width(GTK_CONTAINER(filter_buttons_hb), 2);
1288
1289     /* Add filters box to top-level window */
1290     gtk_box_pack_start(GTK_BOX(top_level_vbox), mac_lte_stat_filters_lb, FALSE, FALSE, 0);
1291
1292     /* Filter buttons */
1293
1294     /* UL only */
1295     hs->ul_filter_bt = gtk_button_new_with_label("Set UL display filter on selected this UE");
1296     gtk_box_pack_start(GTK_BOX(filter_buttons_hb), hs->ul_filter_bt, FALSE, FALSE, 0);
1297     g_signal_connect(hs->ul_filter_bt, "clicked", G_CALLBACK(ul_filter_clicked), hs);
1298     gtk_widget_set_sensitive(hs->ul_filter_bt, FALSE);
1299     gtk_widget_show(hs->ul_filter_bt);
1300     gtk_widget_set_tooltip_text(hs->ul_filter_bt,
1301                          "Generate and set a filter showing only UL frames with selected RNTI and UEId");
1302
1303     /* DL only */
1304     hs->dl_filter_bt = gtk_button_new_with_label("Set DL display filter on selected this UE");
1305     gtk_box_pack_start(GTK_BOX(filter_buttons_hb), hs->dl_filter_bt, FALSE, FALSE, 0);
1306     g_signal_connect(hs->dl_filter_bt, "clicked", G_CALLBACK(dl_filter_clicked), hs);
1307     gtk_widget_set_sensitive(hs->dl_filter_bt, FALSE);
1308     gtk_widget_show(hs->dl_filter_bt);
1309     gtk_widget_set_tooltip_text(hs->dl_filter_bt,
1310                          "Generate and set a filter showing only DL frames with selected RNTI and UEId");
1311
1312     /* UL and DL */
1313     hs->uldl_filter_bt = gtk_button_new_with_label("Set UL / DL display filter on selected this UE");
1314     gtk_box_pack_start(GTK_BOX(filter_buttons_hb), hs->uldl_filter_bt, FALSE, FALSE, 0);
1315     g_signal_connect(hs->uldl_filter_bt, "clicked", G_CALLBACK(uldl_filter_clicked), hs);
1316     gtk_widget_set_sensitive(hs->uldl_filter_bt, FALSE);
1317     gtk_widget_show(hs->uldl_filter_bt);
1318     gtk_widget_set_tooltip_text(hs->uldl_filter_bt,
1319                          "Generate and set a filter showing only frames with selected RNTI and UEId");
1320
1321     /* Show MAC RACH */
1322     hs->show_mac_rach_cb = gtk_check_button_new_with_mnemonic("Show MAC RACH");
1323     gtk_widget_set_sensitive(hs->show_mac_rach_cb, FALSE);
1324     gtk_box_pack_start(GTK_BOX(filter_buttons_hb), hs->show_mac_rach_cb, TRUE, TRUE, 0);
1325     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(hs->show_mac_rach_cb), FALSE);
1326     gtk_widget_set_tooltip_text(hs->show_mac_rach_cb, "When checked, generated filters will show "
1327                          "MAC RACH attempts for the UE");
1328
1329     /* Show MAC SRs */
1330     hs->show_mac_srs_cb = gtk_check_button_new_with_mnemonic("Show MAC SRs");
1331     gtk_widget_set_sensitive(hs->show_mac_srs_cb, FALSE);
1332     gtk_box_pack_start(GTK_BOX(filter_buttons_hb), hs->show_mac_srs_cb, TRUE, TRUE, 0);
1333     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(hs->show_mac_srs_cb), FALSE);
1334     gtk_widget_set_tooltip_text(hs->show_mac_srs_cb, "When checked, generated filters will show "
1335                          "MAC SRs for the UE");
1336
1337
1338     /* Allow DCT errors to be shown... */
1339     hs->show_dct_errors_cb = gtk_check_button_new_with_mnemonic("Show DCT2000 error strings");
1340     gtk_box_pack_start(GTK_BOX(filter_buttons_hb), hs->show_dct_errors_cb, TRUE, TRUE, 0);
1341     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(hs->show_dct_errors_cb), FALSE);
1342     g_signal_connect(hs->show_dct_errors_cb, "toggled", G_CALLBACK(mac_lte_dct_errors_cb), hs);
1343     gtk_widget_set_tooltip_text(hs->show_dct_errors_cb, "When checked, generated filters will "
1344                          "include DCT2000 error strings");
1345     /* Initially disabled */
1346     gtk_widget_set_sensitive(hs->show_dct_errors_cb, FALSE);
1347
1348     /* ... optionally limited by a substring */
1349     hs->dct_error_substring_lb = gtk_label_new("...containing");
1350     gtk_box_pack_start(GTK_BOX(filter_buttons_hb), hs->dct_error_substring_lb, FALSE, FALSE, 0);
1351     gtk_widget_show(hs->dct_error_substring_lb);
1352     gtk_widget_set_sensitive(hs->dct_error_substring_lb, FALSE);
1353
1354     hs->dct_error_substring_te = gtk_entry_new();
1355     gtk_box_pack_start(GTK_BOX(filter_buttons_hb), hs->dct_error_substring_te, FALSE, FALSE, 0);
1356     gtk_widget_show(hs->dct_error_substring_te);
1357     gtk_widget_set_sensitive(hs->dct_error_substring_te, FALSE);
1358     gtk_widget_set_tooltip_text(hs->dct_error_substring_te,
1359                          "If given, only match error strings containing this substring");
1360
1361
1362     /**********************************************/
1363     /* Register the tap listener                  */
1364     /**********************************************/
1365
1366     error_string = register_tap_listener("mac-lte", hs,
1367                                          filter, 0,
1368                                          mac_lte_stat_reset,
1369                                          mac_lte_stat_packet,
1370                                          mac_lte_stat_draw);
1371     if (error_string) {
1372         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", error_string->str);
1373         g_string_free(error_string, TRUE);
1374         g_free(hs);
1375         return;
1376     }
1377
1378
1379     /************************************/
1380     /* Button row.                      */
1381     /************************************/
1382
1383     bbox = dlg_button_row_new (GTK_STOCK_CLOSE, GTK_STOCK_HELP, NULL);
1384     gtk_box_pack_end (GTK_BOX(top_level_vbox), bbox, FALSE, FALSE, 0);
1385
1386     /* Add the close button */
1387     close_bt = (GtkWidget *)g_object_get_data(G_OBJECT(bbox), GTK_STOCK_CLOSE);
1388     window_set_cancel_button(hs->mac_lte_stat_dlg_w, close_bt, window_cancel_button_cb);
1389
1390     help_bt = (GtkWidget *)g_object_get_data(G_OBJECT(bbox), GTK_STOCK_HELP);
1391     g_signal_connect(help_bt, "clicked", G_CALLBACK(topic_cb), (gpointer)HELP_STATS_LTE_MAC_TRAFFIC_DIALOG);
1392
1393     /* Set callbacks */
1394     g_signal_connect(hs->mac_lte_stat_dlg_w, "delete_event", G_CALLBACK(window_delete_event_cb), NULL);
1395     g_signal_connect(hs->mac_lte_stat_dlg_w, "destroy", G_CALLBACK(win_destroy_cb), hs);
1396
1397     /* Show the window */
1398     gtk_widget_show_all(hs->mac_lte_stat_dlg_w);
1399     window_present(hs->mac_lte_stat_dlg_w);
1400
1401     /* Retap */
1402     cf_retap_packets(&cfile);
1403     gdk_window_raise(gtk_widget_get_window(hs->mac_lte_stat_dlg_w));
1404 }
1405
1406
1407 static tap_param mac_lte_stat_params[] = {
1408     { PARAM_FILTER, "Filter", NULL, TRUE }
1409 };
1410
1411 static tap_param_dlg mac_lte_stat_dlg = {
1412     "LTE MAC Stats",
1413     "mac-lte,stat",
1414     gtk_mac_lte_stat_init,
1415     -1,
1416     G_N_ELEMENTS(mac_lte_stat_params),
1417     mac_lte_stat_params
1418 };
1419
1420
1421 /* Register this tap listener (need void on own so line register function found) */
1422 void register_tap_listener_mac_lte_stat(void)
1423 {
1424     register_param_stat(&mac_lte_stat_dlg, "_MAC", REGISTER_STAT_GROUP_TELEPHONY_LTE);
1425 }