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