Get rid of -Wshadow warning - I guess we're including something that
[metze/wireshark/wip.git] / ui / cli / tap-macltestat.c
1 /* tap-macltestat.c
2  * Copyright 2011 Martin Mathieson
3  *
4  * $Id$
5  *
6  * Wireshark - Network traffic analyzer
7  * By Gerald Combs <gerald@wireshark.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23  */
24
25
26 #include "config.h"
27
28 #include <stdio.h>
29
30 #include <string.h>
31 #include <epan/packet.h>
32 #include <epan/packet_info.h>
33 #include <epan/tap.h>
34 #include <epan/stat_cmd_args.h>
35 #include <epan/dissectors/packet-mac-lte.h>
36
37 /**********************************************/
38 /* Table column identifiers and title strings */
39
40 enum {
41     RNTI_COLUMN,
42     RNTI_TYPE_COLUMN,
43     UEID_COLUMN,
44     UL_FRAMES_COLUMN,
45     UL_BYTES_COLUMN,
46     UL_BW_COLUMN,
47     UL_PADDING_PERCENT_COLUMN,
48     UL_RETX_FRAMES_COLUMN,
49     DL_FRAMES_COLUMN,
50     DL_BYTES_COLUMN,
51     DL_BW_COLUMN,
52     DL_PADDING_PERCENT_COLUMN,
53     DL_CRC_FAILED_COLUMN,
54     DL_CRC_HIGH_CODE_RATE_COLUMN,
55     DL_CRC_PDSCH_LOST_COLUMN,
56     DL_CRC_DUPLICATE_NONZERO_RV_COLUMN,
57     DL_RETX_FRAMES_COLUMN,
58     NUM_UE_COLUMNS
59 };
60
61
62 static const gchar *ue_titles[] = { " RNTI", "  Type", "UEId",
63                                     "UL Frames", "UL Bytes", "UL Mb/sec", " UL Pad %", "UL ReTX",
64                                     "DL Frames", "DL Bytes", "DL Mb/sec", " DL Pad %", "DL CRC Fail", "DL CRC HCR", "DL CRC PDSCH Lost", "DL CRC DupNonZeroRV", "DL ReTX"};
65
66
67 /* Stats for one UE */
68 typedef struct mac_lte_row_data {
69     /* Key for matching this row */
70     guint16  rnti;
71     guint8   rnti_type;
72     guint16  ueid;
73
74     gboolean is_predefined_data;
75
76     guint32  UL_frames;
77     guint32  UL_raw_bytes;   /* all bytes */
78     guint32  UL_total_bytes; /* payload */
79     nstime_t UL_time_start;
80     nstime_t UL_time_stop;
81     guint32  UL_padding_bytes;
82     guint32  UL_CRC_errors;
83     guint32  UL_retx_frames;
84
85     guint32  DL_frames;
86     guint32  DL_raw_bytes;   /* all bytes */
87     guint32  DL_total_bytes;
88     nstime_t DL_time_start;
89     nstime_t DL_time_stop;
90     guint32  DL_padding_bytes;
91
92     guint32  DL_CRC_failures;
93     guint32  DL_CRC_high_code_rate;
94     guint32  DL_CRC_PDSCH_lost;
95     guint32  DL_CRC_Duplicate_NonZero_RV;
96     guint32  DL_retx_frames;
97
98 } mac_lte_row_data;
99
100
101 /* One row/UE in the UE table */
102 typedef struct mac_lte_ep {
103     struct mac_lte_ep* next;
104     struct mac_lte_row_data stats;
105 } mac_lte_ep_t;
106
107
108 /* Common channel stats */
109 typedef struct mac_lte_common_stats {
110     guint32 all_frames;
111     guint32 mib_frames;
112     guint32 sib_frames;
113     guint32 sib_bytes;
114     guint32 pch_frames;
115     guint32 pch_bytes;
116     guint32 pch_paging_ids;
117     guint32 rar_frames;
118     guint32 rar_entries;
119
120     guint16  max_ul_ues_in_tti;
121     guint16  max_dl_ues_in_tti;
122 } mac_lte_common_stats;
123
124
125 /* Top-level struct for MAC LTE statistics */
126 typedef struct mac_lte_stat_t {
127     /* Common stats */
128     mac_lte_common_stats common_stats;
129
130     /* Keep track of unique rntis & ueids */
131     guint8 used_ueids[65535];
132     guint8 used_rntis[65535];
133     guint16 number_of_ueids;
134     guint16 number_of_rntis;
135
136     mac_lte_ep_t  *ep_list;
137 } mac_lte_stat_t;
138
139
140 /* Reset the statistics window */
141 static void
142 mac_lte_stat_reset(void *phs)
143 {
144     mac_lte_stat_t* mac_lte_stat = (mac_lte_stat_t *)phs;
145     mac_lte_ep_t* list = mac_lte_stat->ep_list;
146
147     /* Reset counts of unique ueids & rntis */
148     memset(mac_lte_stat->used_ueids, 0, 65535);
149     mac_lte_stat->number_of_ueids = 0;
150     memset(mac_lte_stat->used_rntis, 0, 65535);
151     mac_lte_stat->number_of_rntis = 0;
152
153     /* Zero common stats */
154     memset(&(mac_lte_stat->common_stats), 0, sizeof(mac_lte_common_stats));
155
156     if (!list) {
157         return;
158     }
159
160     mac_lte_stat->ep_list = NULL;
161 }
162
163
164 /* Allocate a mac_lte_ep_t struct to store info for new UE */
165 static mac_lte_ep_t* alloc_mac_lte_ep(const struct mac_lte_tap_info *si, packet_info *pinfo _U_)
166 {
167     mac_lte_ep_t* ep;
168
169     if (!si) {
170         return NULL;
171     }
172
173     if (!(ep = g_new(mac_lte_ep_t,1))) {
174         return NULL;
175     }
176
177     /* Copy SI data into ep->stats */
178     ep->stats.rnti = si->rnti;
179     ep->stats.rnti_type = si->rntiType;
180     ep->stats.ueid = si->ueid;
181
182     /* Counts for new UE are all 0 */
183     ep->stats.UL_frames = 0;
184     ep->stats.DL_frames = 0;
185     ep->stats.UL_total_bytes = 0;
186     ep->stats.UL_raw_bytes = 0;
187     ep->stats.UL_padding_bytes = 0;
188
189     ep->stats.DL_total_bytes = 0;
190     ep->stats.DL_raw_bytes = 0;
191     ep->stats.DL_padding_bytes = 0;
192
193     ep->stats.UL_CRC_errors = 0;
194     ep->stats.DL_CRC_failures = 0;
195     ep->stats.DL_CRC_high_code_rate = 0;
196     ep->stats.DL_CRC_PDSCH_lost = 0;
197     ep->stats.DL_CRC_Duplicate_NonZero_RV = 0;
198     ep->stats.UL_retx_frames = 0;
199     ep->stats.DL_retx_frames = 0;
200
201     ep->next = NULL;
202
203     return ep;
204 }
205
206
207 /* Update counts of unique rntis & ueids */
208 static void update_ueid_rnti_counts(guint16 rnti, guint16 ueid, mac_lte_stat_t *hs)
209 {
210     if (!hs->used_ueids[ueid]) {
211         hs->used_ueids[ueid] = TRUE;
212         hs->number_of_ueids++;
213     }
214     if (!hs->used_rntis[rnti]) {
215         hs->used_rntis[rnti] = TRUE;
216         hs->number_of_rntis++;
217     }
218 }
219
220
221 /* Process stat struct for a MAC LTE frame */
222 static int
223 mac_lte_stat_packet(void *phs, packet_info *pinfo, epan_dissect_t *edt _U_,
224                     const void *phi)
225 {
226     /* Get reference to stat window instance */
227     mac_lte_stat_t *hs = (mac_lte_stat_t *)phs;
228     mac_lte_ep_t *tmp = NULL, *te = NULL;
229
230     /* Cast tap info struct */
231     const struct mac_lte_tap_info *si = (const struct mac_lte_tap_info *)phi;
232
233     if (!hs) {
234         return 0;
235     }
236
237     hs->common_stats.all_frames++;
238
239     /* For common channels, just update global counters */
240     switch (si->rntiType) {
241         case P_RNTI:
242             hs->common_stats.pch_frames++;
243             hs->common_stats.pch_bytes += si->single_number_of_bytes;
244             hs->common_stats.pch_paging_ids += si->number_of_paging_ids;
245             return 1;
246         case SI_RNTI:
247             hs->common_stats.sib_frames++;
248             hs->common_stats.sib_bytes += si->single_number_of_bytes;
249             return 1;
250         case NO_RNTI:
251             hs->common_stats.mib_frames++;
252             return 1;
253         case RA_RNTI:
254             hs->common_stats.rar_frames++;
255             hs->common_stats.rar_entries += si->number_of_rars;
256             return 1;
257         case C_RNTI:
258         case SPS_RNTI:
259             /* Drop through for per-UE update */
260             break;
261
262         default:
263             /* Error */
264             return 0;
265     }
266
267     /* Check max UEs/tti counter */
268     switch (si->direction) {
269         case DIRECTION_UPLINK:
270             hs->common_stats.max_ul_ues_in_tti =
271                 MAX(hs->common_stats.max_ul_ues_in_tti, si->ueInTTI);
272             break;
273         case DIRECTION_DOWNLINK:
274             hs->common_stats.max_dl_ues_in_tti =
275                 MAX(hs->common_stats.max_dl_ues_in_tti, si->ueInTTI);
276             break;
277     }
278
279     /* For per-UE data, must create a new row if none already existing */
280     if (!hs->ep_list) {
281         /* Allocate new list */
282         hs->ep_list = alloc_mac_lte_ep(si, pinfo);
283         /* Make it the first/only entry */
284         te = hs->ep_list;
285
286         /* Update counts of unique ueids & rntis */
287         update_ueid_rnti_counts(si->rnti, si->ueid, hs);
288     } else {
289         /* Look among existing rows for this RNTI */
290         for (tmp = hs->ep_list;(tmp != NULL); tmp = tmp->next) {
291             /* Match only by RNTI and UEId together */
292             if ((tmp->stats.rnti == si->rnti) &&
293                 (tmp->stats.ueid == si->ueid)){
294                 te = tmp;
295                 break;
296             }
297         }
298
299         /* Not found among existing, so create a new one anyway */
300         if (te == NULL) {
301             if ((te = alloc_mac_lte_ep(si, pinfo))) {
302                 /* Add new item to end of list */
303                 mac_lte_ep_t *p = hs->ep_list;
304                 while (p->next) {
305                     p = p->next;
306                 }
307                 p->next = te;
308                 te->next = NULL;
309
310                 /* Update counts of unique ueids & rntis */
311                 update_ueid_rnti_counts(si->rnti, si->ueid, hs);
312             }
313         }
314     }
315
316     /* Really should have a row pointer by now */
317     if (!te) {
318         return 0;
319     }
320
321     /* Update entry with details from si */
322     te->stats.rnti = si->rnti;
323     te->stats.is_predefined_data = si->isPredefinedData;
324
325     /* Uplink */
326     if (si->direction == DIRECTION_UPLINK) {
327         if (si->isPHYRetx) {
328             te->stats.UL_retx_frames++;
329             return 1;
330         }
331
332         if (si->crcStatusValid && (si->crcStatus != crc_success)) {
333             te->stats.UL_CRC_errors++;
334             return 1;
335         }
336
337         /* Update time range */
338         if (te->stats.UL_frames == 0) {
339             te->stats.UL_time_start = si->time;
340         }
341         te->stats.UL_time_stop = si->time;
342
343         te->stats.UL_frames++;
344
345         te->stats.UL_raw_bytes += si->raw_length;
346         te->stats.UL_padding_bytes += si->padding_bytes;
347
348         if (si->isPredefinedData) {
349             te->stats.UL_total_bytes += si->single_number_of_bytes;
350         }
351         else {
352             te->stats.UL_total_bytes += si->single_number_of_bytes;
353         }
354     }
355
356     /* Downlink */
357     else {
358         if (si->isPHYRetx) {
359             te->stats.DL_retx_frames++;
360             return 1;
361         }
362
363         if (si->crcStatusValid && (si->crcStatus != crc_success)) {
364             switch (si->crcStatus) {
365                 case crc_fail:
366                     te->stats.DL_CRC_failures++;
367                     break;
368                 case crc_high_code_rate:
369                     te->stats.DL_CRC_high_code_rate++;
370                     break;
371                 case crc_pdsch_lost:
372                     te->stats.DL_CRC_PDSCH_lost++;
373                     break;
374                 case crc_duplicate_nonzero_rv:
375                     te->stats.DL_CRC_Duplicate_NonZero_RV++;
376                     break;
377
378                 default:
379                     /* Something went wrong! */
380                     break;
381             }
382             return 1;
383         }
384
385         /* Update time range */
386         if (te->stats.DL_frames == 0) {
387             te->stats.DL_time_start = si->time;
388         }
389         te->stats.DL_time_stop = si->time;
390
391         te->stats.DL_frames++;
392
393         te->stats.DL_raw_bytes += si->raw_length;
394         te->stats.DL_padding_bytes += si->padding_bytes;
395
396         if (si->isPredefinedData) {
397             te->stats.DL_total_bytes += si->single_number_of_bytes;
398         }
399         else {
400             te->stats.DL_total_bytes += si->single_number_of_bytes;
401         }
402
403     }
404
405     return 1;
406 }
407
408
409 /* Calculate and return a bandwidth figure, in Mbs */
410 static float calculate_bw(nstime_t *start_time, nstime_t *stop_time, guint32 bytes)
411 {
412     /* Can only calculate bandwidth if have time delta */
413     if (memcmp(start_time, stop_time, sizeof(nstime_t)) != 0) {
414         float elapsed_ms = (((float)stop_time->secs - (float)start_time->secs) * 1000) +
415                            (((float)stop_time->nsecs - (float)start_time->nsecs) / 1000000);
416
417         /* Only really meaningful if have a few frames spread over time...
418            For now at least avoid dividing by something very close to 0.0 */
419         if (elapsed_ms < 2.0) {
420            return 0.0f;
421         }
422         return ((bytes * 8) / elapsed_ms) / 1000;
423     }
424     else {
425         return 0.0f;
426     }
427 }
428
429
430
431 /* Output the accumulated stats */
432 static void
433 mac_lte_stat_draw(void *phs)
434 {
435     gint i;
436     guint16 number_of_ues = 0;
437
438     /* Deref the struct */
439     mac_lte_stat_t *hs = (mac_lte_stat_t *)phs;
440     mac_lte_ep_t* list = hs->ep_list, *tmp = 0;
441
442     /* System data */
443     printf("System data:\n");
444     printf("============\n");
445     printf("Max UL UEs/TTI: %u     Max DL UEs/TTI: %u\n\n",
446            hs->common_stats.max_ul_ues_in_tti, hs->common_stats.max_dl_ues_in_tti);
447
448     /* Common channel data */
449     printf("Common channel data:\n");
450     printf("====================\n");
451     printf("MIBs: %u    ", hs->common_stats.mib_frames);
452     printf("SIB Frames: %u    ", hs->common_stats.sib_frames);
453     printf("SIB Bytes: %u    ", hs->common_stats.sib_bytes);
454     printf("PCH Frames: %u    ", hs->common_stats.pch_frames);
455     printf("PCH Bytes: %u    ", hs->common_stats.pch_bytes);
456     printf("PCH Paging IDs: %u    ", hs->common_stats.pch_paging_ids);
457     printf("RAR Frames: %u    ", hs->common_stats.rar_frames);
458     printf("RAR Entries: %u\n\n", hs->common_stats.rar_entries);
459
460
461     /* Per-UE table entries */
462
463     /* Set title to show how many UEs in table */
464     for (tmp = list; (tmp!=NULL); tmp=tmp->next, number_of_ues++);
465     printf("UL/DL-SCH data (%u entries - %u unique RNTIs, %u unique UEIds):\n",
466            number_of_ues, hs->number_of_rntis, hs->number_of_ueids);
467     printf("==================================================================\n");
468
469     /* Show column titles */
470     for (i=0; i < NUM_UE_COLUMNS; i++) {
471         printf("%s  ", ue_titles[i]);
472     }
473     printf("\n");
474
475     /* Write a row for each UE */
476     for (tmp = list; tmp; tmp=tmp->next) {
477         /* Calculate bandwidth */
478         float UL_bw = calculate_bw(&tmp->stats.UL_time_start,
479                                    &tmp->stats.UL_time_stop,
480                                    tmp->stats.UL_total_bytes);
481         float DL_bw = calculate_bw(&tmp->stats.DL_time_start,
482                                    &tmp->stats.DL_time_stop,
483                                    tmp->stats.DL_total_bytes);
484
485         printf("%5u %7s %5u %10u %9u %10f %10f %8u %10u %9u %10f %10f %12u %11u %18u %20u %8u\n",
486                tmp->stats.rnti,
487                (tmp->stats.rnti_type == C_RNTI) ? "C-RNTI" : "SPS-RNTI",
488                tmp->stats.ueid,
489                tmp->stats.UL_frames,
490                tmp->stats.UL_total_bytes,
491                UL_bw,
492                tmp->stats.UL_raw_bytes ?
493                                     (((float)tmp->stats.UL_padding_bytes / (float)tmp->stats.UL_raw_bytes) * 100.0) :
494                                     0.0,
495                tmp->stats.UL_retx_frames,
496                tmp->stats.DL_frames,
497                tmp->stats.DL_total_bytes,
498                DL_bw,
499                tmp->stats.DL_raw_bytes ?
500                                     (((float)tmp->stats.DL_padding_bytes / (float)tmp->stats.DL_raw_bytes) * 100.0) :
501                                     0.0,
502                tmp->stats.DL_CRC_failures,
503                tmp->stats.DL_CRC_high_code_rate,
504                tmp->stats.DL_CRC_PDSCH_lost,
505                tmp->stats.DL_CRC_Duplicate_NonZero_RV,
506                tmp->stats.DL_retx_frames);
507     }
508 }
509
510 /* Create a new MAC LTE stats struct */
511 static void mac_lte_stat_init(const char *opt_arg, void *userdata _U_)
512 {
513     mac_lte_stat_t    *hs;
514     const char    *filter = NULL;
515     GString       *error_string;
516
517     /* Check for a filter string */
518     if (strncmp(opt_arg, "mac-lte,stat,", 13) == 0) {
519         /* Skip those characters from filter to display */
520         filter = opt_arg + 13;
521     }
522     else {
523         /* No filter */
524         filter = NULL;
525     }
526
527     /* Create struct */
528     hs = g_new0(mac_lte_stat_t,1);
529     hs->ep_list = NULL;
530
531     error_string = register_tap_listener("mac-lte", hs,
532                                          filter, 0,
533                                          mac_lte_stat_reset,
534                                          mac_lte_stat_packet,
535                                          mac_lte_stat_draw);
536     if (error_string) {
537         g_string_free(error_string, TRUE);
538         g_free(hs);
539         exit(1);
540     }
541 }
542
543
544 /* Register this tap listener (need void on own so line register function found) */
545 void
546 register_tap_listener_mac_lte_stat(void)
547 {
548     register_stat_cmd_arg("mac-lte,stat", mac_lte_stat_init, NULL);
549 }
550