2 * Copyright 2011 Martin Mathieson
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
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.
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.
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
32 #ifdef HAVE_SYS_TYPES_H
33 #include <sys/types.h>
37 #include <epan/packet.h>
38 #include <epan/packet_info.h>
40 #include <epan/stat_cmd_args.h>
41 #include <epan/dissectors/packet-rlc-lte.h>
61 static const gchar *ue_titles[] = { " UEId",
62 "UL Frames", "UL Bytes", " UL Mbs", "UL ACKs", "UL NACKs", "UL Missed",
63 "DL Frames", "DL Bytes", " DL Mbs", "DL ACKs", "DL NACKs", "DL Missed"};
65 /* Stats for one UE */
66 typedef struct rlc_lte_row_data {
67 /* Key for matching this row */
70 gboolean is_predefined_data;
73 guint32 UL_total_bytes;
74 nstime_t UL_time_start;
75 nstime_t UL_time_stop;
76 guint32 UL_total_acks;
77 guint32 UL_total_nacks;
78 guint32 UL_total_missing;
81 guint32 DL_total_bytes;
82 nstime_t DL_time_start;
83 nstime_t DL_time_stop;
84 guint32 DL_total_acks;
85 guint32 DL_total_nacks;
86 guint32 DL_total_missing;
91 /* Common channel stats */
92 typedef struct rlc_lte_common_stats {
97 } rlc_lte_common_stats;
100 /* One row/UE in the UE table */
101 typedef struct rlc_lte_ep {
102 struct rlc_lte_ep* next;
103 struct rlc_lte_row_data stats;
107 /* Used to keep track of all RLC LTE statistics */
108 typedef struct rlc_lte_stat_t {
109 rlc_lte_ep_t *ep_list;
110 guint32 total_frames;
113 rlc_lte_common_stats common_stats;
118 /* Reset RLC stats */
120 rlc_lte_stat_reset(void *phs)
122 rlc_lte_stat_t* rlc_lte_stat = (rlc_lte_stat_t *)phs;
123 rlc_lte_ep_t* list = rlc_lte_stat->ep_list;
125 rlc_lte_stat->total_frames = 0;
126 memset(&rlc_lte_stat->common_stats, 0, sizeof(rlc_lte_common_stats));
132 rlc_lte_stat->ep_list = NULL;
136 /* Allocate a rlc_lte_ep_t struct to store info for new UE */
137 static rlc_lte_ep_t* alloc_rlc_lte_ep(struct rlc_lte_tap_info *si, packet_info *pinfo _U_)
145 if (!(ep = g_malloc(sizeof(rlc_lte_ep_t)))) {
149 /* Copy SI data into ep->stats */
150 ep->stats.ueid = si->ueid;
152 /* Counts for new UE are all 0 */
153 ep->stats.UL_frames = 0;
154 ep->stats.DL_frames = 0;
155 ep->stats.UL_total_bytes = 0;
156 ep->stats.DL_total_bytes = 0;
157 memset(&ep->stats.DL_time_start, 0, sizeof(nstime_t));
158 memset(&ep->stats.DL_time_stop, 0, sizeof(nstime_t));
159 ep->stats.UL_total_acks = 0;
160 ep->stats.DL_total_acks = 0;
161 ep->stats.UL_total_nacks = 0;
162 ep->stats.DL_total_nacks = 0;
163 ep->stats.UL_total_missing = 0;
164 ep->stats.DL_total_missing = 0;
172 /* Process stat struct for a RLC LTE frame */
174 rlc_lte_stat_packet(void *phs, packet_info *pinfo, epan_dissect_t *edt _U_,
177 /* Get reference to stats struct */
178 rlc_lte_stat_t *hs = (rlc_lte_stat_t *)phs;
179 rlc_lte_ep_t *tmp = NULL, *te = NULL;
181 /* Cast tap info struct */
182 struct rlc_lte_tap_info *si = (struct rlc_lte_tap_info *)phi;
189 /* Inc top-level frame count */
192 /* Common channel stats */
193 switch (si->channelType) {
194 case CHANNEL_TYPE_BCCH_BCH:
195 case CHANNEL_TYPE_BCCH_DL_SCH:
196 hs->common_stats.bcch_frames++;
197 hs->common_stats.bcch_bytes += si->pduLength;
200 case CHANNEL_TYPE_PCCH:
201 hs->common_stats.pcch_frames++;
202 hs->common_stats.pcch_bytes += si->pduLength;
209 /* For per-UE data, must create a new row if none already existing */
211 /* Allocate new list */
212 hs->ep_list = alloc_rlc_lte_ep(si, pinfo);
213 /* Make it the first/only entry */
216 /* Look among existing rows for this UEId */
217 for (tmp = hs->ep_list; (tmp != NULL); tmp = tmp->next) {
218 if (tmp->stats.ueid == si->ueid) {
224 /* Not found among existing, so create a new one anyway */
226 if ((te = alloc_rlc_lte_ep(si, pinfo))) {
227 /* Add new item to end of list */
228 rlc_lte_ep_t *p = hs->ep_list;
238 /* Really should have a row pointer by now */
243 /* Update entry with details from si */
244 te->stats.ueid = si->ueid;
246 /* Top-level traffic stats */
247 if (si->direction == DIRECTION_UPLINK) {
248 /* Update time range */
249 if (te->stats.UL_frames == 0) {
250 te->stats.UL_time_start = si->time;
252 te->stats.UL_time_stop = si->time;
254 te->stats.UL_frames++;
255 te->stats.UL_total_bytes += si->pduLength;
258 /* Update time range */
259 if (te->stats.DL_frames == 0) {
260 te->stats.DL_time_start = si->time;
262 te->stats.DL_time_stop = si->time;
264 te->stats.DL_frames++;
265 te->stats.DL_total_bytes += si->pduLength;
269 if (si->direction == DIRECTION_UPLINK) {
270 if (si->isControlPDU) {
271 te->stats.UL_total_acks++;
273 te->stats.UL_total_nacks += si->noOfNACKs;
274 te->stats.UL_total_missing += si->missingSNs;
277 if (si->isControlPDU) {
278 te->stats.DL_total_acks++;
280 te->stats.DL_total_nacks += si->noOfNACKs;
281 te->stats.DL_total_missing += si->missingSNs;
288 /* Calculate and return a bandwidth figure, in Mbs */
289 static float calculate_bw(nstime_t *start_time, nstime_t *stop_time, guint32 bytes)
291 if (memcmp(start_time, stop_time, sizeof(nstime_t)) != 0) {
292 float elapsed_ms = (((float)stop_time->secs - (float)start_time->secs) * 1000) +
293 (((float)stop_time->nsecs - (float)start_time->nsecs) / 1000000);
294 return ((bytes * 8) / elapsed_ms) / 1000;
304 /* (Re)draw RLC stats */
306 rlc_lte_stat_draw(void *phs)
308 guint16 number_of_ues = 0;
311 /* Look up the statistics struct */
312 rlc_lte_stat_t *hs = (rlc_lte_stat_t *)phs;
313 rlc_lte_ep_t* list = hs->ep_list, *tmp = 0;
315 /* Common channel data */
316 printf("Common Data:\n");
317 printf("==============\n");
318 printf("BCCH Frames: %u BCCH Bytes: %u PCCH Frames: %u PCCH Bytes: %u\n\n",
319 hs->common_stats.bcch_frames, hs->common_stats.bcch_bytes,
320 hs->common_stats.pcch_frames, hs->common_stats.pcch_bytes);
322 /* Per-UE table entries */
325 /* Set title that shows how many UEs currently in table */
326 for (tmp = list; (tmp!=NULL); tmp=tmp->next, number_of_ues++);
327 printf("Per UE Data - %u UEs (%u frames)\n", number_of_ues, hs->total_frames);
328 printf("==========================================\n");
330 /* Show column titles */
331 for (i=0; i < NUM_UE_COLUMNS; i++) {
332 printf("%s ", ue_titles[i]);
336 /* For each row/UE in the model */
337 for (tmp = list; tmp; tmp=tmp->next) {
338 /* Calculate bandwidth */
339 float UL_bw = calculate_bw(&tmp->stats.UL_time_start,
340 &tmp->stats.UL_time_stop,
341 tmp->stats.UL_total_bytes);
342 float DL_bw = calculate_bw(&tmp->stats.DL_time_start,
343 &tmp->stats.DL_time_stop,
344 tmp->stats.DL_total_bytes);
346 printf("%5u %10u %9u %10f %8u %9u %10u %10u %9u %10f %8u %9u %10u\n",
348 tmp->stats.UL_frames,
349 tmp->stats.UL_total_bytes, UL_bw,
350 tmp->stats.UL_total_acks,
351 tmp->stats.UL_total_nacks,
352 tmp->stats.UL_total_missing,
353 tmp->stats.DL_frames,
354 tmp->stats.DL_total_bytes, DL_bw,
355 tmp->stats.DL_total_acks,
356 tmp->stats.DL_total_nacks,
357 tmp->stats.DL_total_missing);
364 /* Create a new RLC LTE stats struct */
365 static void rlc_lte_stat_init(const char *optarg, void *userdata _U_)
368 const char *filter = NULL;
369 GString *error_string;
371 /* Check for a filter string */
372 if (strncmp(optarg, "rlc-lte,stat,", 13) == 0) {
373 /* Skip those characters from filter to display */
374 filter = optarg + 13;
381 /* Create top-level struct */
382 hs = g_malloc(sizeof(rlc_lte_stat_t));
383 memset(hs, 0, sizeof(rlc_lte_stat_t));
387 /**********************************************/
388 /* Register the tap listener */
389 /**********************************************/
391 error_string = register_tap_listener("rlc-lte", hs,
397 g_string_free(error_string, TRUE);
405 /* Register this tap listener (need void on own so line register function found) */
407 register_tap_listener_rlc_lte_stat(void)
409 register_stat_cmd_arg("rlc-lte,stat", rlc_lte_stat_init, NULL);