1 /* mtp3_summary_dialog.cpp
2  *
3  * Wireshark - Network traffic analyzer
4  * By Gerald Combs <gerald@wireshark.org>
5  * Copyright 1998 Gerald Combs
6  *
7  * Wireshark - Network traffic analyzer
8  * By Gerald Combs <gerald@wireshark.org>
9  * Copyright 1998 Gerald Combs
10  *
11  * SPDX-License-Identifier: GPL-2.0-or-later
12  */
13 
14 #include "mtp3_summary_dialog.h"
15 #include <ui_mtp3_summary_dialog.h>
16 
17 #include "config.h"
18 
19 #include <glib.h>
20 
21 #include <epan/tap.h>
22 
23 #include <epan/dissectors/packet-mtp3.h>
24 
25 #include "wsutil/utf8_entities.h"
26 
27 #include "ui/capture_globals.h"
28 #include "ui/simple_dialog.h"
29 #include "ui/summary.h"
30 
31 #include <ui/qt/utils/qt_ui_utils.h>
32 
33 #include <QTextStream>
34 
35 typedef struct _mtp3_stat_si_code_t {
36     int			num_msus;
37     int			size;
38 } mtp3_stat_si_code_t;
39 
40 typedef struct _mtp3_stat_t {
41     mtp3_addr_pc_t		addr_opc;
42     mtp3_addr_pc_t		addr_dpc;
43     mtp3_stat_si_code_t		mtp3_si_code[MTP3_NUM_SI_CODE];
44 } mtp3_stat_t;
45 
46 #define	MTP3_MAX_NUM_OPC_DPC	50
47 
48 static mtp3_stat_t mtp3_stat[MTP3_MAX_NUM_OPC_DPC];
49 static size_t mtp3_num_used;
50 
Mtp3SummaryDialog(QWidget & parent,CaptureFile & capture_file)51 Mtp3SummaryDialog::Mtp3SummaryDialog(QWidget &parent, CaptureFile &capture_file) :
52     WiresharkDialog(parent, capture_file),
53     ui(new Ui::Mtp3SummaryDialog)
54 {
55     ui->setupUi(this);
56 
57     setWindowSubtitle(tr("MTP3 Summary"));
58     updateWidgets();
59 }
60 
~Mtp3SummaryDialog()61 Mtp3SummaryDialog::~Mtp3SummaryDialog()
62 {
63     delete ui;
64 }
65 
summaryToHtml()66 QString Mtp3SummaryDialog::summaryToHtml()
67 {
68     summary_tally summary;
69     memset(&summary, 0, sizeof(summary_tally));
70 
71     QString section_tmpl;
72     QString table_begin, table_end;
73     QString table_row_begin, table_ul_row_begin, table_row_end;
74     QString table_vheader_tmpl, table_hheader15_tmpl, table_hheader25_tmpl;
75     QString table_data_tmpl;
76 
77     section_tmpl = "<p><strong>%1</strong></p>\n";
78     table_begin = "<p><table>\n";
79     table_end = "</table></p>\n";
80     table_row_begin = "<tr>\n";
81     table_ul_row_begin = "<tr style=\"border-bottom: 1px solid gray;\">\n";
82     table_row_end = "</tr>\n";
83     table_vheader_tmpl = "<td width=\"50%\">%1:</td>"; // <th align="left"> looked odd
84     table_hheader15_tmpl = "<td width=\"15%\"><u>%1</u></td>";
85     table_hheader25_tmpl = "<td width=\"25%\"><u>%1</u></td>";
86     table_data_tmpl = "<td>%1</td>";
87 
88     if (cap_file_.isValid()) {
89         /* initial computations */
90         summary_fill_in(cap_file_.capFile(), &summary);
91 #ifdef HAVE_LIBPCAP
92         summary_fill_in_capture(cap_file_.capFile(), &global_capture_opts, &summary);
93 #endif
94     }
95 
96     QString summary_str;
97     QTextStream out(&summary_str);
98 
99     // File Section
100     out << section_tmpl.arg(tr("File"));
101     out << table_begin;
102 
103     out << table_row_begin
104         << table_vheader_tmpl.arg(tr("Name"))
105         << table_data_tmpl.arg(summary.filename)
106         << table_row_end;
107 
108     out << table_row_begin
109         << table_vheader_tmpl.arg(tr("Length"))
110         << table_data_tmpl.arg(file_size_to_qstring(summary.file_length))
111         << table_row_end;
112 
113     QString format_str = wtap_file_type_subtype_description(summary.file_type);
114     const char *compression_type_description = wtap_compression_type_description(summary.compression_type);
115     if (compression_type_description != NULL) {
116         format_str += QString(" (%1)").arg(compression_type_description);
117     }
118     out << table_row_begin
119         << table_vheader_tmpl.arg(tr("Format"))
120         << table_data_tmpl.arg(format_str)
121         << table_row_end;
122 
123     if (summary.snap != 0) {
124         out << table_row_begin
125             << table_vheader_tmpl.arg(tr("Snapshot length"))
126             << table_data_tmpl.arg(summary.snap)
127             << table_row_end;
128     }
129 
130     out << table_end;
131 
132     // Data Section
133     out << section_tmpl.arg(tr("Data"));
134     out << table_begin;
135 
136     if (summary.packet_count_ts == summary.packet_count &&
137             summary.packet_count >= 1)
138     {
139         // start time
140         out << table_row_begin
141             << table_vheader_tmpl.arg(tr("First packet"))
142             << table_data_tmpl.arg(time_t_to_qstring((time_t)summary.start_time))
143             << table_row_end;
144 
145         // stop time
146         out << table_row_begin
147             << table_vheader_tmpl.arg(tr("Last packet"))
148             << table_data_tmpl.arg(time_t_to_qstring((time_t)summary.stop_time))
149             << table_row_end;
150 
151         // elapsed seconds (capture duration)
152         if (summary.packet_count_ts > 1)
153         {
154             /* elapsed seconds */
155             QString elapsed_str;
156             unsigned int elapsed_time = (unsigned int)summary.elapsed_time;
157             if (elapsed_time/86400)
158             {
159                 elapsed_str = QString("%1 days ").arg(elapsed_time / 86400);
160             }
161 
162             elapsed_str += QString("%1:%2:%3")
163                     .arg(elapsed_time % 86400 / 3600, 2, 10, QChar('0'))
164                     .arg(elapsed_time % 3600 / 60, 2, 10, QChar('0'))
165                     .arg(elapsed_time % 60, 2, 10, QChar('0'));
166             out << table_row_begin
167                 << table_vheader_tmpl.arg(tr("Elapsed"))
168                 << table_data_tmpl.arg(elapsed_str)
169                 << table_row_end;
170         }
171     }
172 
173     // count
174     out << table_row_begin
175         << table_vheader_tmpl.arg(tr("Packets"))
176         << table_data_tmpl.arg(summary.packet_count)
177         << table_row_end;
178 
179     out << table_end;
180 
181     QString n_a = UTF8_EM_DASH;
182     int total_msus = 0;
183     int total_bytes = 0;
184     double seconds = summary.stop_time - summary.start_time;
185 
186     // SI Section
187     out << section_tmpl.arg(tr("Service Indicator (SI) Totals"));
188     out << table_begin;
189 
190     out << table_row_begin
191         << table_hheader25_tmpl.arg(tr("SI"))
192         << table_hheader15_tmpl.arg(tr("MSUs"))
193         << table_hheader15_tmpl.arg(tr("MSUs/s"))
194         << table_hheader15_tmpl.arg(tr("Bytes"))
195         << table_hheader15_tmpl.arg(tr("Bytes/MSU"))
196         << table_hheader15_tmpl.arg(tr("Bytes/s"))
197         << table_row_end;
198 
199     for (size_t ws_si_code = 0; ws_si_code < MTP3_NUM_SI_CODE; ws_si_code++) {
200         int si_msus = 0;
201         int si_bytes = 0;
202         QString msus_s_str = n_a;
203         QString bytes_msu_str = n_a;
204         QString bytes_s_str = n_a;
205 
206         for (size_t stat_idx = 0; stat_idx < mtp3_num_used; stat_idx++) {
207             si_msus += mtp3_stat[stat_idx].mtp3_si_code[ws_si_code].num_msus;
208             si_bytes += mtp3_stat[stat_idx].mtp3_si_code[ws_si_code].size;
209         }
210         total_msus += si_msus;
211         total_bytes += si_bytes;
212 
213         if (seconds > 0) {
214             msus_s_str = QString("%1").arg(si_msus / seconds, 1, 'f', 1);
215             bytes_s_str = QString("%1").arg(si_bytes / seconds, 1, 'f', 1);
216         }
217 
218         if (si_msus > 0) {
219             bytes_msu_str = QString("%1").arg((double) si_bytes / si_msus, 1, 'f', 1);
220         }
221 
222         out << table_row_begin
223             << table_data_tmpl.arg(mtp3_service_indicator_code_short_vals[ws_si_code].strptr)
224             << table_data_tmpl.arg(si_msus)
225             << table_data_tmpl.arg(msus_s_str)
226             << table_data_tmpl.arg(si_bytes)
227             << table_data_tmpl.arg(bytes_msu_str)
228             << table_data_tmpl.arg(bytes_s_str)
229             << table_row_end;
230     }
231 
232     out << table_end;
233 
234     // Totals Section
235 
236     QString total_msus_s_str = n_a;
237     QString total_bytes_msu_str = n_a;
238     QString total_bytes_s_str = n_a;
239 
240     if (seconds > 0) {
241         total_msus_s_str = QString("%1").arg(total_msus / seconds, 1, 'f', 1);
242         total_bytes_s_str = QString("%1").arg(total_bytes / seconds, 1, 'f', 1);
243     }
244     if (total_msus > 0) {
245         total_bytes_msu_str = QString("%1").arg((double) total_bytes / total_msus, 1, 'f', 1);
246     }
247 
248     out << section_tmpl.arg(tr("Totals"));
249     out << table_begin;
250 
251     out << table_row_begin
252         << table_vheader_tmpl.arg(tr("Total MSUs"))
253         << table_data_tmpl.arg(total_msus)
254         << table_row_end;
255 
256     out << table_row_begin
257         << table_vheader_tmpl.arg(tr("MSUs/s"))
258         << table_data_tmpl.arg(total_msus_s_str)
259         << table_row_end;
260 
261     out << table_row_begin
262         << table_vheader_tmpl.arg(tr("Total Bytes"))
263         << table_data_tmpl.arg(total_bytes)
264         << table_row_end;
265 
266     out << table_row_begin
267         << table_vheader_tmpl.arg(tr("Average Bytes/MSU"))
268         << table_data_tmpl.arg(total_bytes_msu_str)
269         << table_row_end;
270 
271     out << table_row_begin
272         << table_vheader_tmpl.arg(tr("Average Bytes/s"))
273         << table_data_tmpl.arg(total_bytes_s_str)
274         << table_row_end;
275 
276     out << table_end;
277 
278     return summary_str;
279 }
280 
updateWidgets()281 void Mtp3SummaryDialog::updateWidgets()
282 {
283     ui->summaryTextEdit->setHtml(summaryToHtml());
284 
285     WiresharkDialog::updateWidgets();
286 }
287 
288 extern "C" {
289 
290 void register_tap_listener_qt_mtp3_summary(void);
291 
292 static void
mtp3_summary_reset(void * tapdata)293 mtp3_summary_reset(
294     void        *tapdata)
295 {
296     mtp3_stat_t     (*stat_p)[MTP3_MAX_NUM_OPC_DPC] = (mtp3_stat_t(*)[MTP3_MAX_NUM_OPC_DPC])tapdata;
297 
298     mtp3_num_used = 0;
299     memset(stat_p, 0, MTP3_MAX_NUM_OPC_DPC * sizeof(mtp3_stat_t));
300 }
301 
302 
303 static tap_packet_status
mtp3_summary_packet(void * tapdata,packet_info *,epan_dissect_t *,const void * data)304 mtp3_summary_packet(
305     void            *tapdata,
306     packet_info     *,
307     epan_dissect_t  *,
308     const void      *data)
309 {
310     mtp3_stat_t           (*stat_p)[MTP3_MAX_NUM_OPC_DPC] = (mtp3_stat_t(*)[MTP3_MAX_NUM_OPC_DPC])tapdata;
311     const mtp3_tap_rec_t  *data_p = (const mtp3_tap_rec_t *)data;
312     size_t                 i;
313 
314     if (data_p->mtp3_si_code >= MTP3_NUM_SI_CODE)
315     {
316         /*
317          * we thought this si_code was not used ?
318          * is MTP3_NUM_SI_CODE out of date ?
319          * XXX - if this is an error, report it and return TAP_PACKET_FAILED.
320          */
321         return(TAP_PACKET_DONT_REDRAW);
322     }
323 
324     /*
325      * look for opc/dpc pair
326      */
327     i = 0;
328     while (i < mtp3_num_used)
329     {
330         if (memcmp(&data_p->addr_opc, &(*stat_p)[i].addr_opc, sizeof(mtp3_addr_pc_t)) == 0)
331         {
332             if (memcmp(&data_p->addr_dpc, &(*stat_p)[i].addr_dpc, sizeof(mtp3_addr_pc_t)) == 0)
333             {
334                 break;
335             }
336         }
337 
338         i++;
339     }
340 
341     if (i == mtp3_num_used)
342     {
343         if (mtp3_num_used == MTP3_MAX_NUM_OPC_DPC)
344         {
345             /*
346              * too many
347              * XXX - report an error and return TAP_PACKET_FAILED?
348              */
349             return(TAP_PACKET_DONT_REDRAW);
350         }
351 
352         mtp3_num_used++;
353     }
354 
355     (*stat_p)[i].addr_opc = data_p->addr_opc;
356     (*stat_p)[i].addr_dpc = data_p->addr_dpc;
357     (*stat_p)[i].mtp3_si_code[data_p->mtp3_si_code].num_msus++;
358     (*stat_p)[i].mtp3_si_code[data_p->mtp3_si_code].size += data_p->size;
359 
360     return(TAP_PACKET_REDRAW);
361 }
362 
363 void
register_tap_listener_qt_mtp3_summary(void)364 register_tap_listener_qt_mtp3_summary(void)
365 {
366     GString     *err_p;
367 
368     memset((void *) &mtp3_stat, 0, sizeof(mtp3_stat));
369 
370     err_p =
371     register_tap_listener("mtp3", &mtp3_stat, NULL, 0,
372         mtp3_summary_reset,
373         mtp3_summary_packet,
374         NULL,
375         NULL);
376 
377     if (err_p != NULL)
378     {
379         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", err_p->str);
380         g_string_free(err_p, TRUE);
381 
382         exit(1);
383     }
384 }
385 
386 } // extern "C"
387