2 * Copyright 2011 Martin Mathieson
4 * Wireshark - Network traffic analyzer
5 * By Gerald Combs <gerald@wireshark.org>
6 * Copyright 1998 Gerald Combs
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
30 #include <epan/packet.h>
32 #include <epan/stat_tap_ui.h>
33 #include <epan/dissectors/packet-rlc-lte.h>
35 void register_tap_listener_rlc_lte_stat(void);
54 static const gchar *ue_titles[] = { " UEId",
55 "UL Frames", "UL Bytes", " UL Mbs", "UL ACKs", "UL NACKs", "UL Missed",
56 "DL Frames", "DL Bytes", " DL Mbs", "DL ACKs", "DL NACKs", "DL Missed"};
58 /* Stats for one UE */
59 typedef struct rlc_lte_row_data {
60 /* Key for matching this row */
63 gboolean is_predefined_data;
66 guint32 UL_total_bytes;
67 nstime_t UL_time_start;
68 nstime_t UL_time_stop;
69 guint32 UL_total_acks;
70 guint32 UL_total_nacks;
71 guint32 UL_total_missing;
74 guint32 DL_total_bytes;
75 nstime_t DL_time_start;
76 nstime_t DL_time_stop;
77 guint32 DL_total_acks;
78 guint32 DL_total_nacks;
79 guint32 DL_total_missing;
84 /* Common channel stats */
85 typedef struct rlc_lte_common_stats {
90 } rlc_lte_common_stats;
93 /* One row/UE in the UE table */
94 typedef struct rlc_lte_ep {
95 struct rlc_lte_ep *next;
96 struct rlc_lte_row_data stats;
100 /* Used to keep track of all RLC LTE statistics */
101 typedef struct rlc_lte_stat_t {
102 rlc_lte_ep_t *ep_list;
103 guint32 total_frames;
106 rlc_lte_common_stats common_stats;
111 /* Reset RLC stats */
113 rlc_lte_stat_reset(void *phs)
115 rlc_lte_stat_t *rlc_lte_stat = (rlc_lte_stat_t *)phs;
116 rlc_lte_ep_t *list = rlc_lte_stat->ep_list;
118 rlc_lte_stat->total_frames = 0;
119 memset(&rlc_lte_stat->common_stats, 0, sizeof(rlc_lte_common_stats));
125 rlc_lte_stat->ep_list = NULL;
129 /* Allocate a rlc_lte_ep_t struct to store info for new UE */
130 static rlc_lte_ep_t *alloc_rlc_lte_ep(const struct rlc_lte_tap_info *si, packet_info *pinfo _U_)
138 if (!(ep = g_new(rlc_lte_ep_t, 1))) {
142 /* Copy SI data into ep->stats */
143 ep->stats.ueid = si->ueid;
145 /* Counts for new UE are all 0 */
146 ep->stats.UL_frames = 0;
147 ep->stats.DL_frames = 0;
148 ep->stats.UL_total_bytes = 0;
149 ep->stats.DL_total_bytes = 0;
150 memset(&ep->stats.DL_time_start, 0, sizeof(nstime_t));
151 memset(&ep->stats.DL_time_stop, 0, sizeof(nstime_t));
152 ep->stats.UL_total_acks = 0;
153 ep->stats.DL_total_acks = 0;
154 ep->stats.UL_total_nacks = 0;
155 ep->stats.DL_total_nacks = 0;
156 ep->stats.UL_total_missing = 0;
157 ep->stats.DL_total_missing = 0;
165 /* Process stat struct for a RLC LTE frame */
167 rlc_lte_stat_packet(void *phs, packet_info *pinfo, epan_dissect_t *edt _U_,
170 /* Get reference to stats struct */
171 rlc_lte_stat_t *hs = (rlc_lte_stat_t *)phs;
172 rlc_lte_ep_t *tmp = NULL, *te = NULL;
174 /* Cast tap info struct */
175 const struct rlc_lte_tap_info *si = (const struct rlc_lte_tap_info *)phi;
182 /* Inc top-level frame count */
185 /* Common channel stats */
186 switch (si->channelType) {
187 case CHANNEL_TYPE_BCCH_BCH:
188 case CHANNEL_TYPE_BCCH_DL_SCH:
189 hs->common_stats.bcch_frames++;
190 hs->common_stats.bcch_bytes += si->pduLength;
193 case CHANNEL_TYPE_PCCH:
194 hs->common_stats.pcch_frames++;
195 hs->common_stats.pcch_bytes += si->pduLength;
202 /* For per-UE data, must create a new row if none already existing */
204 /* Allocate new list */
205 hs->ep_list = alloc_rlc_lte_ep(si, pinfo);
206 /* Make it the first/only entry */
209 /* Look among existing rows for this UEId */
210 for (tmp = hs->ep_list; (tmp != NULL); tmp = tmp->next) {
211 if (tmp->stats.ueid == si->ueid) {
217 /* Not found among existing, so create a new one anyway */
219 if ((te = alloc_rlc_lte_ep(si, pinfo))) {
220 /* Add new item to end of list */
221 rlc_lte_ep_t *p = hs->ep_list;
231 /* Really should have a row pointer by now */
236 /* Update entry with details from si */
237 te->stats.ueid = si->ueid;
239 /* Top-level traffic stats */
240 if (si->direction == DIRECTION_UPLINK) {
241 /* Update time range */
242 if (te->stats.UL_frames == 0) {
243 te->stats.UL_time_start = si->time;
245 te->stats.UL_time_stop = si->time;
247 te->stats.UL_frames++;
248 te->stats.UL_total_bytes += si->pduLength;
251 /* Update time range */
252 if (te->stats.DL_frames == 0) {
253 te->stats.DL_time_start = si->time;
255 te->stats.DL_time_stop = si->time;
257 te->stats.DL_frames++;
258 te->stats.DL_total_bytes += si->pduLength;
262 if (si->direction == DIRECTION_UPLINK) {
263 if (si->isControlPDU) {
264 te->stats.UL_total_acks++;
266 te->stats.UL_total_nacks += si->noOfNACKs;
267 te->stats.UL_total_missing += si->missingSNs;
270 if (si->isControlPDU) {
271 te->stats.DL_total_acks++;
273 te->stats.DL_total_nacks += si->noOfNACKs;
274 te->stats.DL_total_missing += si->missingSNs;
281 /* Calculate and return a bandwidth figure, in Mbs */
282 static float calculate_bw(nstime_t *start_time, nstime_t *stop_time, guint32 bytes)
284 /* Can only calculate bandwidth if have time delta */
285 if (memcmp(start_time, stop_time, sizeof(nstime_t)) != 0) {
286 float elapsed_ms = (((float)stop_time->secs - (float)start_time->secs) * 1000) +
287 (((float)stop_time->nsecs - (float)start_time->nsecs) / 1000000);
289 /* Only really meaningful if have a few frames spread over time...
290 For now at least avoid dividing by something very close to 0.0 */
291 if (elapsed_ms < 2.0) {
294 return ((bytes * 8) / elapsed_ms) / 1000;
303 /* (Re)draw RLC stats */
305 rlc_lte_stat_draw(void *phs)
307 guint16 number_of_ues = 0;
310 /* Look up the statistics struct */
311 rlc_lte_stat_t *hs = (rlc_lte_stat_t *)phs;
312 rlc_lte_ep_t *list = hs->ep_list, *tmp = 0;
314 /* Common channel data */
315 printf("Common Data:\n");
316 printf("==============\n");
317 printf("BCCH Frames: %u BCCH Bytes: %u PCCH Frames: %u PCCH Bytes: %u\n\n",
318 hs->common_stats.bcch_frames, hs->common_stats.bcch_bytes,
319 hs->common_stats.pcch_frames, hs->common_stats.pcch_bytes);
321 /* Per-UE table entries */
324 /* Set title that shows how many UEs currently in table */
325 for (tmp = list; (tmp!=NULL); tmp=tmp->next, number_of_ues++);
326 printf("Per UE Data - %u UEs (%u frames)\n", number_of_ues, hs->total_frames);
327 printf("==========================================\n");
329 /* Show column titles */
330 for (i=0; i < NUM_UE_COLUMNS; i++) {
331 printf("%s ", ue_titles[i]);
335 /* For each row/UE in the model */
336 for (tmp = list; tmp; tmp=tmp->next) {
337 /* Calculate bandwidth */
338 float UL_bw = calculate_bw(&tmp->stats.UL_time_start,
339 &tmp->stats.UL_time_stop,
340 tmp->stats.UL_total_bytes);
341 float DL_bw = calculate_bw(&tmp->stats.DL_time_start,
342 &tmp->stats.DL_time_stop,
343 tmp->stats.DL_total_bytes);
345 printf("%5u %10u %9u %10f %8u %9u %10u %10u %9u %10f %8u %9u %10u\n",
347 tmp->stats.UL_frames,
348 tmp->stats.UL_total_bytes, UL_bw,
349 tmp->stats.UL_total_acks,
350 tmp->stats.UL_total_nacks,
351 tmp->stats.UL_total_missing,
352 tmp->stats.DL_frames,
353 tmp->stats.DL_total_bytes, DL_bw,
354 tmp->stats.DL_total_acks,
355 tmp->stats.DL_total_nacks,
356 tmp->stats.DL_total_missing);
363 /* Create a new RLC LTE stats struct */
364 static void rlc_lte_stat_init(const char *opt_arg, void *userdata _U_)
367 const char *filter = NULL;
368 GString *error_string;
370 /* Check for a filter string */
371 if (strncmp(opt_arg, "rlc-lte,stat,", 13) == 0) {
372 /* Skip those characters from filter to display */
373 filter = opt_arg + 13;
380 /* Create top-level struct */
381 hs = g_new0(rlc_lte_stat_t, 1);
385 /**********************************************/
386 /* Register the tap listener */
387 /**********************************************/
389 error_string = register_tap_listener("rlc-lte", hs,
395 g_string_free(error_string, TRUE);
403 /* Register this tap listener (need void on own so line register function found) */
404 static stat_tap_ui rlc_lte_stat_ui = {
405 REGISTER_STAT_GROUP_GENERIC,
415 register_tap_listener_rlc_lte_stat(void)
417 register_stat_tap_ui(&rlc_lte_stat_ui, NULL);
421 * Editor modelines - http://www.wireshark.org/tools/modelines.html
426 * indent-tabs-mode: nil
429 * vi: set shiftwidth=4 tabstop=8 expandtab:
430 * :indentSize=4:tabSize=8:noTabs=true: