1 /* packet_range.c
2  * Packet range routines (save, print, ...)
3  *
4  * Dick Gooris <gooris@lucent.com>
5  * Ulf Lamping <ulf.lamping@web.de>
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 "config.h"
15 
16 #include <string.h>
17 
18 #include <glib.h>
19 
20 #include <epan/frame_data.h>
21 
22 #include "packet_range.h"
23 
24 #include <wsutil/ws_assert.h>
25 
26 /* (re-)calculate the packet counts (except the user specified range) */
packet_range_calc(packet_range_t * range)27 static void packet_range_calc(packet_range_t *range) {
28     guint32       framenum;
29     guint32       mark_low;
30     guint32       mark_high;
31     guint32       displayed_mark_low;
32     guint32       displayed_mark_high;
33     frame_data    *packet;
34 
35 
36 
37     mark_low                                = 0;
38     mark_high                               = 0;
39     range->mark_range_cnt                   = 0;
40     range->ignored_cnt                      = 0;
41     range->ignored_selection_range_cnt      = 0;
42     range->ignored_marked_cnt               = 0;
43     range->ignored_mark_range_cnt           = 0;
44     range->ignored_user_range_cnt           = 0;
45 
46     displayed_mark_low                      = 0;
47     displayed_mark_high                     = 0;
48 
49     range->displayed_cnt                    = 0;
50     range->displayed_marked_cnt             = 0;
51     range->displayed_mark_range_cnt         = 0;
52     range->displayed_plus_dependents_cnt    = 0;
53     range->displayed_ignored_cnt            = 0;
54     range->displayed_ignored_selection_range_cnt  = 0;
55     range->displayed_ignored_marked_cnt     = 0;
56     range->displayed_ignored_mark_range_cnt = 0;
57     range->displayed_ignored_user_range_cnt = 0;
58 
59     ws_assert(range->cf != NULL);
60 
61     /* XXX - this doesn't work unless you have a full set of frame_data
62      * structures for all packets in the capture, which is not,
63      * for example, the case when TShark is doing a one-pass
64      * read of a file or a live capture.
65      *
66      * It's also horribly slow on large captures, causing it to
67      * take a long time for the Save As dialog to pop up, for
68      * example.  We should really keep these statistics in
69      * the capture_file structure, updating them whenever we
70      * filter the display, etc..
71      */
72     if (range->cf->provider.frames != NULL) {
73         /* The next for-loop is used to obtain the amount of packets
74          * to be processed and is used to present the information in
75          * the Save/Print As widget.
76          * We have different types of ranges: All the packets, the number
77          * of packets of a marked range, a single packet, and a user specified
78          * packet range. The last one is not calculated here since this
79          * data must be entered in the widget by the user.
80          */
81 
82         for(framenum = 1; framenum <= range->cf->count; framenum++) {
83             packet = frame_data_sequence_find(range->cf->provider.frames, framenum);
84 
85             if (range->cf->current_frame == packet && range->selection_range == NULL ) {
86                 range_add_value(NULL, &(range->selection_range), framenum);
87             }
88             if (packet->passed_dfilter) {
89                 range->displayed_cnt++;
90             }
91             if (packet->passed_dfilter ||
92                 packet->dependent_of_displayed) {
93                 range->displayed_plus_dependents_cnt++;
94             }
95             if (packet->marked) {
96                 if (packet->ignored) {
97                     range->ignored_marked_cnt++;
98                 }
99                 if (packet->passed_dfilter) {
100                     range->displayed_marked_cnt++;
101                     if (packet->ignored) {
102                         range->displayed_ignored_marked_cnt++;
103                     }
104                     if (displayed_mark_low == 0) {
105                        displayed_mark_low = framenum;
106                     }
107                     if (framenum > displayed_mark_high) {
108                        displayed_mark_high = framenum;
109                     }
110                 }
111 
112                 if (mark_low == 0) {
113                    mark_low = framenum;
114                 }
115                 if (framenum > mark_high) {
116                    mark_high = framenum;
117                 }
118             }
119             if (packet->ignored) {
120                 range->ignored_cnt++;
121                 if (packet->passed_dfilter) {
122                     range->displayed_ignored_cnt++;
123                 }
124             }
125         }
126 
127         for(framenum = 1; framenum <= range->cf->count; framenum++) {
128             packet = frame_data_sequence_find(range->cf->provider.frames, framenum);
129 
130             if (framenum >= mark_low &&
131                 framenum <= mark_high)
132             {
133                 range->mark_range_cnt++;
134                 if (packet->ignored) {
135                     range->ignored_mark_range_cnt++;
136                 }
137             }
138 
139             if (framenum >= displayed_mark_low &&
140                 framenum <= displayed_mark_high)
141             {
142                 if (packet->passed_dfilter) {
143                     range->displayed_mark_range_cnt++;
144                     if (packet->ignored) {
145                         range->displayed_ignored_mark_range_cnt++;
146                     }
147                 }
148             }
149         }
150 
151     }
152 }
153 
154 
155 /* (re-)calculate the user specified packet range counts */
packet_range_calc_user(packet_range_t * range)156 static void packet_range_calc_user(packet_range_t *range) {
157     guint32       framenum;
158     frame_data    *packet;
159 
160     range->user_range_cnt                   = 0;
161     range->ignored_user_range_cnt           = 0;
162     range->displayed_user_range_cnt         = 0;
163     range->displayed_ignored_user_range_cnt = 0;
164 
165     ws_assert(range->cf != NULL);
166 
167     /* XXX - this doesn't work unless you have a full set of frame_data
168      * structures for all packets in the capture, which is not,
169      * for example, the case when TShark is doing a one-pass
170      * read of a file or a live capture.
171      *
172      * It's also horribly slow on large captures, causing it to
173      * take a long time for the Save As dialog to pop up, for
174      * example.  This obviously can't be kept in the capture_file
175      * structure and recalculated whenever we filter the display
176      * or mark frames as ignored, as the results of this depend
177      * on what the user specifies.  In some cases, limiting the
178      * frame_data structures at which we look to the ones specified
179      * by the user might help, but if most of the frames are in
180      * the range, that won't help.  In that case, if we could
181      * examine the *complement* of the range, and *subtract* them
182      * from the statistics for the capture as a whole, that might
183      * help, but if the user specified about *half* the packets in
184      * the range, that won't help, either.
185      */
186     if (range->cf->provider.frames != NULL) {
187         for(framenum = 1; framenum <= range->cf->count; framenum++) {
188             packet = frame_data_sequence_find(range->cf->provider.frames, framenum);
189 
190             if (value_is_in_range(range->user_range, framenum)) {
191                 range->user_range_cnt++;
192                 if (packet->ignored) {
193                     range->ignored_user_range_cnt++;
194                 }
195                 if (packet->passed_dfilter) {
196                     range->displayed_user_range_cnt++;
197                     if (packet->ignored) {
198                         range->displayed_ignored_user_range_cnt++;
199                     }
200                 }
201             }
202         }
203     }
204 }
205 
packet_range_calc_selection(packet_range_t * range)206 static void packet_range_calc_selection(packet_range_t *range) {
207     guint32       framenum;
208     frame_data    *packet;
209 
210     range->selection_range_cnt                   = 0;
211     range->ignored_selection_range_cnt           = 0;
212     range->displayed_selection_range_cnt         = 0;
213     range->displayed_ignored_selection_range_cnt = 0;
214 
215     ws_assert(range->cf != NULL);
216 
217     if (range->cf->provider.frames != NULL) {
218         for (framenum = 1; framenum <= range->cf->count; framenum++) {
219             packet = frame_data_sequence_find(range->cf->provider.frames, framenum);
220 
221             if (value_is_in_range(range->selection_range, framenum)) {
222                 range->selection_range_cnt++;
223                 if (packet->ignored) {
224                     range->ignored_selection_range_cnt++;
225                 }
226                 if (packet->passed_dfilter) {
227                     range->displayed_selection_range_cnt++;
228                     if (packet->ignored) {
229                         range->displayed_ignored_selection_range_cnt++;
230                     }
231                 }
232             }
233         }
234     }
235 }
236 
237 
238 /* init the range struct */
packet_range_init(packet_range_t * range,capture_file * cf)239 void packet_range_init(packet_range_t *range, capture_file *cf) {
240 
241     memset(range, 0, sizeof(packet_range_t));
242     range->process    = range_process_all;
243     range->user_range = NULL;
244     range->selection_range = NULL;
245     range->cf         = cf;
246 
247     /* calculate all packet range counters */
248     packet_range_calc(range);
249     packet_range_calc_user(range);
250     packet_range_calc_selection(range);
251 }
252 
packet_range_cleanup(packet_range_t * range)253 void packet_range_cleanup(packet_range_t *range) {
254     wmem_free(NULL, range->user_range);
255     wmem_free(NULL, range->selection_range);
256 }
257 
258 /* check whether the packet range is OK */
packet_range_check(packet_range_t * range)259 convert_ret_t packet_range_check(packet_range_t *range) {
260     if (range->process == range_process_user_range && range->user_range == NULL) {
261         /* Not valid - return the error. */
262         return range->user_range_status;
263     }
264     if (range->process == range_process_selected && range->selection_range == NULL) {
265         return range->selection_range_status;
266     }
267 
268     return CVT_NO_ERROR;
269 }
270 
271 /* init the processing run */
packet_range_process_init(packet_range_t * range)272 void packet_range_process_init(packet_range_t *range) {
273     /* Check that, if an explicit range was selected, it's valid. */
274     /* "enumeration" values */
275     range->marked_range_active    = FALSE;
276     range->selected_done          = FALSE;
277 
278     if (range->process_filtered == FALSE) {
279         range->marked_range_left = range->mark_range_cnt;
280     } else {
281         range->marked_range_left = range->displayed_mark_range_cnt;
282     }
283 }
284 
285 /* do we have to process all packets? */
packet_range_process_all(packet_range_t * range)286 gboolean packet_range_process_all(packet_range_t *range) {
287     return range->process == range_process_all && !range->process_filtered && !range->remove_ignored;
288 }
289 
290 /* do we have to process this packet? */
packet_range_process_packet(packet_range_t * range,frame_data * fdata)291 range_process_e packet_range_process_packet(packet_range_t *range, frame_data *fdata) {
292 
293     if (range->remove_ignored && fdata->ignored) {
294         return range_process_next;
295     }
296 
297     ws_assert(range->cf != NULL);
298 
299     switch(range->process) {
300     case(range_process_all):
301         break;
302     case(range_process_selected):
303         if (value_is_in_range(range->selection_range, fdata->num) == FALSE) {
304           return range_process_next;
305         }
306         break;
307     case(range_process_marked):
308         if (fdata->marked == FALSE) {
309           return range_process_next;
310         }
311         break;
312     case(range_process_marked_range):
313         if (range->marked_range_left == 0) {
314           return range_processing_finished;
315         }
316         if (fdata->marked == TRUE) {
317           range->marked_range_active = TRUE;
318         }
319         if (range->marked_range_active == FALSE ) {
320           return range_process_next;
321         }
322         if (!range->process_filtered ||
323           (range->process_filtered && fdata->passed_dfilter == TRUE))
324         {
325           range->marked_range_left--;
326         }
327         break;
328     case(range_process_user_range):
329         if (value_is_in_range(range->user_range, fdata->num) == FALSE) {
330           return range_process_next;
331         }
332         break;
333     default:
334         ws_assert_not_reached();
335     }
336 
337     /* This packet has to pass the display filter but didn't?
338      * Try next, but only if we're not including dependent packets and this
339      * packet happens to be a dependency on something that is displayed.
340      */
341     if ((range->process_filtered && fdata->passed_dfilter == FALSE) &&
342         !(range->include_dependents && fdata->dependent_of_displayed)) {
343         return range_process_next;
344     }
345 
346     /* We fell through the conditions above, so we accept this packet */
347     return range_process_this;
348 }
349 
350 
351 /******************** Range Entry Parser *********************************/
352 
353 /* Converts a range string to a user range.
354  * The parameter 'es' points to the string to be converted, and is defined in
355  * the Save/Print-As widget.
356  */
357 
packet_range_convert_str(packet_range_t * range,const gchar * es)358 void packet_range_convert_str(packet_range_t *range, const gchar *es)
359 {
360     range_t *new_range;
361     convert_ret_t ret;
362 
363     if (range->user_range != NULL)
364         wmem_free(NULL, range->user_range);
365 
366     ws_assert(range->cf != NULL);
367 
368     ret = range_convert_str(NULL, &new_range, es, range->cf->count);
369     if (ret != CVT_NO_ERROR) {
370         /* range isn't valid */
371         range->user_range                       = NULL;
372         range->user_range_status                = ret;
373         range->user_range_cnt                   = 0;
374         range->ignored_user_range_cnt           = 0;
375         range->displayed_user_range_cnt         = 0;
376         range->displayed_ignored_user_range_cnt = 0;
377         return;
378     }
379     range->user_range = new_range;
380 
381     /* calculate new user specified packet range counts */
382     packet_range_calc_user(range);
383 } /* packet_range_convert_str */
384 
packet_range_convert_selection_str(packet_range_t * range,const char * es)385 void packet_range_convert_selection_str(packet_range_t *range, const char *es)
386 {
387     range_t *new_range;
388     convert_ret_t ret;
389 
390     if (range->selection_range != NULL)
391         wmem_free(NULL, range->selection_range);
392 
393     ws_assert(range->cf != NULL);
394 
395     ret = range_convert_str(NULL, &new_range, es, range->cf->count);
396     if (ret != CVT_NO_ERROR) {
397         /* range isn't valid */
398         range->selection_range                       = NULL;
399         range->selection_range_status                = ret;
400         range->selection_range_cnt                   = 0;
401         range->ignored_selection_range_cnt           = 0;
402         range->displayed_selection_range_cnt         = 0;
403         range->displayed_ignored_selection_range_cnt = 0;
404         return;
405     }
406     range->selection_range = new_range;
407 
408     /* calculate new user specified packet range counts */
409     packet_range_calc_selection(range);
410 }
411