Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / ui / cli / tap-macltestat.c
blob88785b703a51f5c76b66432e45422c95e5709ed2
1 /* tap-macltestat.c
2 * Copyright 2011 Martin Mathieson
4 * Wireshark - Network traffic analyzer
5 * By Gerald Combs <gerald@wireshark.org>
6 * Copyright 1998 Gerald Combs
8 * SPDX-License-Identifier: GPL-2.0-or-later
9 */
12 #include "config.h"
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
18 #include <epan/packet.h>
19 #include <epan/tap.h>
20 #include <epan/stat_tap_ui.h>
21 #include <epan/dissectors/packet-mac-lte.h>
23 void register_tap_listener_mac_lte_stat(void);
25 /**********************************************/
26 /* Table column identifiers and title strings */
28 enum {
29 RAT_COLUMN,
30 RNTI_COLUMN,
31 RNTI_TYPE_COLUMN,
32 UEID_COLUMN,
33 UL_FRAMES_COLUMN,
34 UL_BYTES_COLUMN,
35 UL_BW_COLUMN,
36 UL_PADDING_PERCENT_COLUMN,
37 UL_RETX_FRAMES_COLUMN,
38 DL_FRAMES_COLUMN,
39 DL_BYTES_COLUMN,
40 DL_BW_COLUMN,
41 DL_PADDING_PERCENT_COLUMN,
42 DL_CRC_FAILED_COLUMN,
43 DL_RETX_FRAMES_COLUMN,
44 NUM_UE_COLUMNS
48 static const char *ue_titles[] = { "RAT", " RNTI", " Type", "UEId",
49 "UL Frames", "UL Bytes", "UL Mb/sec", " UL Pad %", "UL ReTX",
50 "DL Frames", "DL Bytes", "DL Mb/sec", " DL Pad %", "DL CRC Fail", "DL ReTX"};
53 /* Stats for one UE */
54 typedef struct mac_lte_nr_row_data {
55 /* Key for matching this row */
56 uint8_t rat;
57 uint16_t rnti;
58 uint8_t rnti_type;
59 uint16_t ueid;
61 bool is_predefined_data;
63 uint32_t UL_frames;
64 uint32_t UL_raw_bytes; /* all bytes */
65 uint32_t UL_total_bytes; /* payload */
66 nstime_t UL_time_start;
67 nstime_t UL_time_stop;
68 uint32_t UL_padding_bytes;
69 uint32_t UL_CRC_errors;
70 uint32_t UL_retx_frames;
72 uint32_t DL_frames;
73 uint32_t DL_raw_bytes; /* all bytes */
74 uint32_t DL_total_bytes;
75 nstime_t DL_time_start;
76 nstime_t DL_time_stop;
77 uint32_t DL_padding_bytes;
79 uint32_t DL_CRC_failures;
80 uint32_t DL_retx_frames;
82 } mac_lte_nr_row_data;
85 /* One row/UE list item in the UE table */
86 typedef struct mac_lte_ep {
87 struct mac_lte_ep *next;
88 struct mac_lte_nr_row_data stats;
89 } mac_lte_ep_t;
92 /* Common channel stats (i.e. independent of UEs) */
93 typedef struct mac_lte_common_stats {
94 uint32_t all_frames;
95 uint32_t mib_frames;
96 uint32_t sib_frames;
97 uint32_t sib_bytes;
98 uint32_t pch_frames;
99 uint32_t pch_bytes;
100 uint32_t pch_paging_ids;
101 uint32_t rar_frames;
102 uint32_t rar_entries;
104 uint16_t max_ul_ues_in_tti;
105 uint16_t max_dl_ues_in_tti;
106 } mac_lte_common_stats;
109 /* Top-level struct for MAC LTE statistics */
110 typedef struct mac_lte_nr_stat_t {
111 /* Common stats */
112 mac_lte_common_stats common_stats;
114 /* Keep track of unique rntis & ueids. N.B. only used for counting number of UEs - not for lookup */
115 uint8_t used_ueids[65535];
116 uint8_t used_rntis[65535];
117 uint16_t number_of_ueids;
118 uint16_t number_of_rntis;
120 /* List of UE entries */
121 mac_lte_ep_t *ep_list;
122 } mac_lte_nr_stat_t;
125 /* Reset the statistics window */
126 static void
127 mac_lte_stat_reset(void *phs)
129 mac_lte_nr_stat_t *mac_lte_stat = (mac_lte_nr_stat_t *)phs;
130 mac_lte_ep_t *list = mac_lte_stat->ep_list;
132 /* Reset counts of unique ueids & rntis */
133 memset(mac_lte_stat->used_ueids, 0, 65535);
134 mac_lte_stat->number_of_ueids = 0;
135 memset(mac_lte_stat->used_rntis, 0, 65535);
136 mac_lte_stat->number_of_rntis = 0;
138 /* Zero common stats */
139 memset(&(mac_lte_stat->common_stats), 0, sizeof(mac_lte_common_stats));
141 if (!list) {
142 return;
145 mac_lte_stat->ep_list = NULL;
149 /* Allocate a mac_lte_ep_t struct to store info for new UE */
150 static mac_lte_ep_t *alloc_mac_lte_ep(const struct mac_3gpp_tap_info *si, packet_info *pinfo _U_)
152 mac_lte_ep_t *ep;
154 if (!si) {
155 return NULL;
158 if (!(ep = g_new(mac_lte_ep_t, 1))) {
159 return NULL;
162 /* Copy SI data into ep->stats */
163 ep->stats.rnti = si->rnti;
164 ep->stats.rnti_type = si->rntiType;
165 ep->stats.ueid = si->ueid;
167 /* Counts for new UE are all 0 */
168 ep->stats.UL_frames = 0;
169 ep->stats.DL_frames = 0;
170 ep->stats.UL_total_bytes = 0;
171 ep->stats.UL_raw_bytes = 0;
172 ep->stats.UL_padding_bytes = 0;
174 ep->stats.DL_total_bytes = 0;
175 ep->stats.DL_raw_bytes = 0;
176 ep->stats.DL_padding_bytes = 0;
178 ep->stats.UL_CRC_errors = 0;
179 ep->stats.DL_CRC_failures = 0;
180 ep->stats.UL_retx_frames = 0;
181 ep->stats.DL_retx_frames = 0;
183 ep->next = NULL;
185 return ep;
189 /* Update counts of unique rntis & ueids */
190 static void update_ueid_rnti_counts(uint16_t rnti, uint16_t ueid, mac_lte_nr_stat_t *hs)
192 if (hs->number_of_ueids == 65535 || hs->number_of_rntis == 65535) {
193 /* Arrays are already full! */
194 return;
197 if (!hs->used_ueids[ueid]) {
198 hs->used_ueids[ueid] = true;
199 hs->number_of_ueids++;
201 if (!hs->used_rntis[rnti]) {
202 hs->used_rntis[rnti] = true;
203 hs->number_of_rntis++;
208 /* Process stat struct for a MAC LTE frame */
209 static tap_packet_status
210 mac_lte_stat_packet(void *phs, packet_info *pinfo, epan_dissect_t *edt _U_,
211 const void *phi, tap_flags_t flags _U_)
213 /* Get reference to stat window instance */
214 mac_lte_nr_stat_t *hs = (mac_lte_nr_stat_t*)phs;
215 mac_lte_ep_t *tmp = NULL, *te = NULL;
216 int i;
218 /* Cast tap info struct */
219 const struct mac_3gpp_tap_info *si = (const struct mac_3gpp_tap_info *)phi;
221 if (!hs) {
222 return TAP_PACKET_DONT_REDRAW;
225 hs->common_stats.all_frames++;
227 /* For common channels, just update global counters */
228 switch (si->rntiType) {
229 case P_RNTI:
230 hs->common_stats.pch_frames++;
231 hs->common_stats.pch_bytes += si->single_number_of_bytes;
232 hs->common_stats.pch_paging_ids += si->number_of_paging_ids;
233 return TAP_PACKET_REDRAW;
234 case SI_RNTI:
235 hs->common_stats.sib_frames++;
236 hs->common_stats.sib_bytes += si->single_number_of_bytes;
237 return TAP_PACKET_REDRAW;
238 case NO_RNTI:
239 hs->common_stats.mib_frames++;
240 return TAP_PACKET_REDRAW;
241 case RA_RNTI:
242 hs->common_stats.rar_frames++;
243 hs->common_stats.rar_entries += si->number_of_rars;
244 return TAP_PACKET_REDRAW;
245 case C_RNTI:
246 case SPS_RNTI:
247 /* Drop through for per-UE update */
248 break;
250 default:
251 /* Error */
252 return TAP_PACKET_DONT_REDRAW;
255 /* Check/update max UEs/tti counter */
256 switch (si->direction) {
257 case DIRECTION_UPLINK:
258 hs->common_stats.max_ul_ues_in_tti =
259 MAX(hs->common_stats.max_ul_ues_in_tti, si->ueInTTI);
260 break;
261 case DIRECTION_DOWNLINK:
262 hs->common_stats.max_dl_ues_in_tti =
263 MAX(hs->common_stats.max_dl_ues_in_tti, si->ueInTTI);
264 break;
267 /* For per-UE data, must create a new row if none already existing */
268 if (!hs->ep_list) {
269 /* Allocate new list */
270 hs->ep_list = alloc_mac_lte_ep(si, pinfo);
271 /* Make it the first/only entry */
272 te = hs->ep_list;
274 /* Update counts of unique ueids & rntis */
275 update_ueid_rnti_counts(si->rnti, si->ueid, hs);
276 } else {
277 /* Look among existing rows for this RNTI */
278 /* TODO: with different data structures, could avoid this linear search */
279 for (tmp = hs->ep_list; tmp != NULL; tmp = tmp->next) {
280 /* Match only by RAT, RNTI and UEId together */
281 if ((tmp->stats.rat == si->rat) &&
282 (tmp->stats.rnti == si->rnti) &&
283 (tmp->stats.ueid == si->ueid)) {
284 te = tmp;
285 break;
289 /* Not found among existing, so create a new one now */
290 if (te == NULL) {
291 if ((te = alloc_mac_lte_ep(si, pinfo))) {
292 /* Add new item to end of list */
293 mac_lte_ep_t *p = hs->ep_list;
294 while (p->next) {
295 p = p->next;
297 p->next = te;
298 te->next = NULL;
300 /* Update counts of unique ueids & rntis */
301 update_ueid_rnti_counts(si->rnti, si->ueid, hs);
306 /* Really should have a row pointer by now */
307 if (!te) {
308 return TAP_PACKET_DONT_REDRAW;
311 /* Update entry with details from si */
312 te->stats.rat = si->rat;
313 te->stats.rnti = si->rnti;
314 te->stats.is_predefined_data = si->isPredefinedData;
316 /* Uplink */
317 if (si->direction == DIRECTION_UPLINK) {
318 if (si->isPHYRetx) {
319 te->stats.UL_retx_frames++;
320 return TAP_PACKET_REDRAW;
323 if (si->crcStatusValid && (si->crcStatus != crc_success)) {
324 te->stats.UL_CRC_errors++;
325 return TAP_PACKET_REDRAW;
328 /* Update time range */
329 if (te->stats.UL_frames == 0) {
330 te->stats.UL_time_start = si->mac_time;
332 te->stats.UL_time_stop = si->mac_time;
334 te->stats.UL_frames++;
336 te->stats.UL_raw_bytes += si->raw_length;
337 te->stats.UL_padding_bytes += si->padding_bytes;
339 if (si->isPredefinedData) {
340 te->stats.UL_total_bytes += si->single_number_of_bytes;
342 else {
343 for (i = 0; i < MAC_3GPP_DATA_LCID_COUNT_MAX; i++) {
344 te->stats.UL_total_bytes += si->bytes_for_lcid[i];
349 /* Downlink */
350 else {
351 if (si->isPHYRetx) {
352 te->stats.DL_retx_frames++;
353 return TAP_PACKET_REDRAW;
356 if (si->crcStatusValid && (si->crcStatus != crc_success)) {
357 te->stats.DL_CRC_failures++;
358 return TAP_PACKET_REDRAW;
361 /* Update time range */
362 if (te->stats.DL_frames == 0) {
363 te->stats.DL_time_start = si->mac_time;
365 te->stats.DL_time_stop = si->mac_time;
367 te->stats.DL_frames++;
369 te->stats.DL_raw_bytes += si->raw_length;
370 te->stats.DL_padding_bytes += si->padding_bytes;
372 if (si->isPredefinedData) {
373 te->stats.DL_total_bytes += si->single_number_of_bytes;
375 else {
376 for (i = 0; i < MAC_3GPP_DATA_LCID_COUNT_MAX; i++) {
377 te->stats.DL_total_bytes += si->bytes_for_lcid[i];
383 return TAP_PACKET_REDRAW;
387 /* Calculate and return a bandwidth figure, in Mbs */
388 static float calculate_bw(nstime_t *start_time, nstime_t *stop_time, uint32_t bytes)
390 /* Can only calculate bandwidth if have time delta */
391 if (memcmp(start_time, stop_time, sizeof(nstime_t)) != 0) {
392 float elapsed_ms = (((float)stop_time->secs - (float)start_time->secs) * 1000) +
393 (((float)stop_time->nsecs - (float)start_time->nsecs) / 1000000);
395 /* Only really meaningful if have a few frames spread over time...
396 For now at least avoid dividing by something very close to 0.0 */
397 if (elapsed_ms < 2.0) {
398 return 0.0f;
400 return ((bytes * 8) / elapsed_ms) / 1000;
402 else {
403 return 0.0f;
409 /* Output the accumulated stats */
410 static void
411 mac_lte_stat_draw(void *phs)
413 int i;
414 uint16_t number_of_ues = 0;
416 /* Deref the struct */
417 mac_lte_nr_stat_t *hs = (mac_lte_nr_stat_t*)phs;
418 mac_lte_ep_t *list = hs->ep_list, *tmp = 0;
420 /* System data */
421 printf("System data:\n");
422 printf("============\n");
423 printf("Max UL UEs/TTI: %u Max DL UEs/TTI: %u\n\n",
424 hs->common_stats.max_ul_ues_in_tti, hs->common_stats.max_dl_ues_in_tti);
426 /* Common channel data */
427 printf("Common channel data:\n");
428 printf("====================\n");
429 printf("MIBs: %u ", hs->common_stats.mib_frames);
430 printf("SIB Frames: %u ", hs->common_stats.sib_frames);
431 printf("SIB Bytes: %u ", hs->common_stats.sib_bytes);
432 printf("PCH Frames: %u ", hs->common_stats.pch_frames);
433 printf("PCH Bytes: %u ", hs->common_stats.pch_bytes);
434 printf("PCH Paging IDs: %u ", hs->common_stats.pch_paging_ids);
435 printf("RAR Frames: %u ", hs->common_stats.rar_frames);
436 printf("RAR Entries: %u\n\n", hs->common_stats.rar_entries);
439 /* Per-UE table entries */
441 /* Set title to show how many UEs in table */
442 for (tmp = list; (tmp!=NULL); tmp=tmp->next, number_of_ues++);
443 printf("UL/DL-SCH data (%u entries - %u unique RNTIs, %u unique UEIds):\n",
444 number_of_ues, hs->number_of_rntis, hs->number_of_ueids);
445 printf("==================================================================\n");
447 /* Show column titles */
448 for (i=0; i < NUM_UE_COLUMNS; i++) {
449 printf("%s ", ue_titles[i]);
451 printf("\n");
453 /* Write a row for each UE */
454 for (tmp = list; tmp; tmp=tmp->next) {
455 /* Calculate bandwidth */
456 float UL_bw = calculate_bw(&tmp->stats.UL_time_start,
457 &tmp->stats.UL_time_stop,
458 tmp->stats.UL_total_bytes);
459 float DL_bw = calculate_bw(&tmp->stats.DL_time_start,
460 &tmp->stats.DL_time_stop,
461 tmp->stats.DL_total_bytes);
463 printf("%s %5u %7s %5u %10u %9u %10f %10f %8u %10u %9u %10f %10f %12u %8u\n",
464 (tmp->stats.rat == MAC_RAT_LTE) ? "LTE " : "NR ",
465 tmp->stats.rnti,
466 (tmp->stats.rnti_type == C_RNTI) ? "C-RNTI" : "SPS-RNTI",
467 tmp->stats.ueid,
468 tmp->stats.UL_frames,
469 tmp->stats.UL_total_bytes,
470 UL_bw,
471 tmp->stats.UL_raw_bytes ?
472 (((float)tmp->stats.UL_padding_bytes / (float)tmp->stats.UL_raw_bytes) * 100.0) :
473 0.0,
474 tmp->stats.UL_retx_frames,
475 tmp->stats.DL_frames,
476 tmp->stats.DL_total_bytes,
477 DL_bw,
478 tmp->stats.DL_raw_bytes ?
479 (((float)tmp->stats.DL_padding_bytes / (float)tmp->stats.DL_raw_bytes) * 100.0) :
480 0.0,
481 tmp->stats.DL_CRC_failures,
482 tmp->stats.DL_retx_frames);
486 /* Create a new MAC LTE stats struct */
487 static void mac_lte_stat_init(const char *opt_arg, void *userdata _U_)
489 mac_lte_nr_stat_t *hs;
490 const char *filter = NULL;
491 GString *error_string;
493 /* Check for a filter string */
494 if (strncmp(opt_arg, "mac-3gpp,stat,", 14) == 0) {
495 /* Skip those characters from filter to display */
496 filter = opt_arg + 14;
498 else {
499 /* No filter */
500 filter = NULL;
503 /* Create struct */
504 hs = g_new0(mac_lte_nr_stat_t, 1);
505 hs->ep_list = NULL;
507 error_string = register_tap_listener("mac-3gpp", hs,
508 filter, 0,
509 mac_lte_stat_reset,
510 mac_lte_stat_packet,
511 mac_lte_stat_draw,
512 NULL);
513 if (error_string) {
514 g_string_free(error_string, TRUE);
515 g_free(hs);
516 exit(1);
520 static stat_tap_ui mac_lte_stat_ui = {
521 REGISTER_STAT_GROUP_GENERIC,
522 NULL,
523 "mac-3gpp,stat",
524 mac_lte_stat_init,
526 NULL
529 /* Register this tap listener (need void on own so line register function found) */
530 void
531 register_tap_listener_mac_lte_stat(void)
533 register_stat_tap_ui(&mac_lte_stat_ui, NULL);