2 * Packet range routines (save, print, ...)
4 * Dick Gooris <gooris@lucent.com>
5 * Ulf Lamping <ulf.lamping@web.de>
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1998 Gerald Combs
11 * SPDX-License-Identifier: GPL-2.0-or-later
20 #include <epan/frame_data.h>
22 #include "packet_range.h"
24 /* (re-)calculate the packet counts (except the user specified range) */
25 static void packet_range_calc(packet_range_t *range) {
29 guint32 displayed_mark_low;
30 guint32 displayed_mark_high;
34 range->selected_packet = 0;
38 range->mark_range_cnt = 0;
39 range->ignored_cnt = 0;
40 range->ignored_marked_cnt = 0;
41 range->ignored_mark_range_cnt = 0;
42 range->ignored_user_range_cnt = 0;
44 displayed_mark_low = 0;
45 displayed_mark_high = 0;
47 range->displayed_cnt = 0;
48 range->displayed_marked_cnt = 0;
49 range->displayed_mark_range_cnt = 0;
50 range->displayed_plus_dependents_cnt = 0;
51 range->displayed_ignored_cnt = 0;
52 range->displayed_ignored_marked_cnt = 0;
53 range->displayed_ignored_mark_range_cnt = 0;
54 range->displayed_ignored_user_range_cnt = 0;
56 g_assert(range->cf != NULL);
58 /* XXX - this doesn't work unless you have a full set of frame_data
59 * structures for all packets in the capture, which is not,
60 * for example, the case when TShark is doing a one-pass
61 * read of a file or a live capture.
63 * It's also horribly slow on large captures, causing it to
64 * take a long time for the Save As dialog to pop up, for
65 * example. We should really keep these statistics in
66 * the capture_file structure, updating them whenever we
67 * filter the display, etc..
69 if (range->cf->provider.frames != NULL) {
70 /* The next for-loop is used to obtain the amount of packets
71 * to be processed and is used to present the information in
72 * the Save/Print As widget.
73 * We have different types of ranges: All the packets, the number
74 * of packets of a marked range, a single packet, and a user specified
75 * packet range. The last one is not calculated here since this
76 * data must be entered in the widget by the user.
79 for(framenum = 1; framenum <= range->cf->count; framenum++) {
80 packet = frame_data_sequence_find(range->cf->provider.frames, framenum);
82 if (range->cf->current_frame == packet) {
83 range->selected_packet = framenum;
85 if (packet->passed_dfilter) {
86 range->displayed_cnt++;
88 if (packet->passed_dfilter ||
89 packet->dependent_of_displayed) {
90 range->displayed_plus_dependents_cnt++;
93 if (packet->ignored) {
94 range->ignored_marked_cnt++;
96 if (packet->passed_dfilter) {
97 range->displayed_marked_cnt++;
98 if (packet->ignored) {
99 range->displayed_ignored_marked_cnt++;
101 if (displayed_mark_low == 0) {
102 displayed_mark_low = framenum;
104 if (framenum > displayed_mark_high) {
105 displayed_mark_high = framenum;
112 if (framenum > mark_high) {
113 mark_high = framenum;
116 if (packet->ignored) {
117 range->ignored_cnt++;
118 if (packet->passed_dfilter) {
119 range->displayed_ignored_cnt++;
124 for(framenum = 1; framenum <= range->cf->count; framenum++) {
125 packet = frame_data_sequence_find(range->cf->provider.frames, framenum);
127 if (framenum >= mark_low &&
128 framenum <= mark_high)
130 range->mark_range_cnt++;
131 if (packet->ignored) {
132 range->ignored_mark_range_cnt++;
136 if (framenum >= displayed_mark_low &&
137 framenum <= displayed_mark_high)
139 if (packet->passed_dfilter) {
140 range->displayed_mark_range_cnt++;
141 if (packet->ignored) {
142 range->displayed_ignored_mark_range_cnt++;
149 /* in case we marked just one packet, we add 1. */
150 if (range->cf->marked_count != 0) {
151 range->mark_range = mark_high - mark_low + 1;
154 /* in case we marked just one packet, we add 1. */
155 if (range->displayed_marked_cnt != 0) {
156 range->displayed_mark_range = displayed_mark_high - displayed_mark_low + 1;
163 /* (re-)calculate the user specified packet range counts */
164 static void packet_range_calc_user(packet_range_t *range) {
168 range->user_range_cnt = 0;
169 range->ignored_user_range_cnt = 0;
170 range->displayed_user_range_cnt = 0;
171 range->displayed_ignored_user_range_cnt = 0;
173 g_assert(range->cf != NULL);
175 /* XXX - this doesn't work unless you have a full set of frame_data
176 * structures for all packets in the capture, which is not,
177 * for example, the case when TShark is doing a one-pass
178 * read of a file or a live capture.
180 * It's also horribly slow on large captures, causing it to
181 * take a long time for the Save As dialog to pop up, for
182 * example. This obviously can't be kept in the capture_file
183 * structure and recalculated whenever we filter the display
184 * or mark frames as ignored, as the results of this depend
185 * on what the user specifies. In some cases, limiting the
186 * frame_data structures at which we look to the ones specified
187 * by the user might help, but if most of the frames are in
188 * the range, that won't help. In that case, if we could
189 * examine the *complement* of the range, and *subtract* them
190 * from the statistics for the capture as a whole, that might
191 * help, but if the user specified about *half* the packets in
192 * the range, that won't help, either.
194 if (range->cf->provider.frames != NULL) {
195 for(framenum = 1; framenum <= range->cf->count; framenum++) {
196 packet = frame_data_sequence_find(range->cf->provider.frames, framenum);
198 if (value_is_in_range(range->user_range, framenum)) {
199 range->user_range_cnt++;
200 if (packet->ignored) {
201 range->ignored_user_range_cnt++;
203 if (packet->passed_dfilter) {
204 range->displayed_user_range_cnt++;
205 if (packet->ignored) {
206 range->displayed_ignored_user_range_cnt++;
215 /* init the range struct */
216 void packet_range_init(packet_range_t *range, capture_file *cf) {
218 memset(range, 0, sizeof(packet_range_t));
219 range->process = range_process_all;
220 range->user_range = NULL;
223 /* calculate all packet range counters */
224 packet_range_calc(range);
225 packet_range_calc_user(range);
228 void packet_range_cleanup(packet_range_t *range) {
229 wmem_free(NULL, range->user_range);
232 /* check whether the packet range is OK */
233 convert_ret_t packet_range_check(packet_range_t *range) {
234 if (range->process == range_process_user_range && range->user_range == NULL) {
235 /* Not valid - return the error. */
236 return range->user_range_status;
241 /* init the processing run */
242 void packet_range_process_init(packet_range_t *range) {
243 /* Check that, if an explicit range was selected, it's valid. */
244 /* "enumeration" values */
245 range->marked_range_active = FALSE;
246 range->selected_done = FALSE;
248 if (range->process_filtered == FALSE) {
249 range->marked_range_left = range->mark_range_cnt;
251 range->marked_range_left = range->displayed_mark_range_cnt;
255 /* do we have to process all packets? */
256 gboolean packet_range_process_all(packet_range_t *range) {
257 return range->process == range_process_all && !range->process_filtered && !range->remove_ignored;
260 /* do we have to process this packet? */
261 range_process_e packet_range_process_packet(packet_range_t *range, frame_data *fdata) {
263 if (range->remove_ignored && fdata->ignored) {
264 return range_process_next;
267 g_assert(range->cf != NULL);
269 switch(range->process) {
270 case(range_process_all):
272 case(range_process_selected):
273 if (range->selected_done) {
274 return range_processing_finished;
276 if (fdata->num != range->cf->current_frame->num) {
277 return range_process_next;
279 range->selected_done = TRUE;
281 case(range_process_marked):
282 if (fdata->marked == FALSE) {
283 return range_process_next;
286 case(range_process_marked_range):
287 if (range->marked_range_left == 0) {
288 return range_processing_finished;
290 if (fdata->marked == TRUE) {
291 range->marked_range_active = TRUE;
293 if (range->marked_range_active == FALSE ) {
294 return range_process_next;
296 if (!range->process_filtered ||
297 (range->process_filtered && fdata->passed_dfilter == TRUE))
299 range->marked_range_left--;
302 case(range_process_user_range):
303 if (value_is_in_range(range->user_range, fdata->num) == FALSE) {
304 return range_process_next;
308 g_assert_not_reached();
311 /* This packet has to pass the display filter but didn't?
312 * Try next, but only if we're not including dependent packets and this
313 * packet happens to be a dependency on something that is displayed.
315 if ((range->process_filtered && fdata->passed_dfilter == FALSE) &&
316 !(range->include_dependents && fdata->dependent_of_displayed)) {
317 return range_process_next;
320 /* We fell through the conditions above, so we accept this packet */
321 return range_process_this;
325 /******************** Range Entry Parser *********************************/
327 /* Converts a range string to a user range.
328 * The parameter 'es' points to the string to be converted, and is defined in
329 * the Save/Print-As widget.
332 void packet_range_convert_str(packet_range_t *range, const gchar *es)
337 if (range->user_range != NULL)
338 wmem_free(NULL, range->user_range);
340 g_assert(range->cf != NULL);
342 ret = range_convert_str(NULL, &new_range, es, range->cf->count);
343 if (ret != CVT_NO_ERROR) {
344 /* range isn't valid */
345 range->user_range = NULL;
346 range->user_range_status = ret;
347 range->user_range_cnt = 0;
348 range->ignored_user_range_cnt = 0;
349 range->displayed_user_range_cnt = 0;
350 range->displayed_ignored_user_range_cnt = 0;
353 range->user_range = new_range;
355 /* calculate new user specified packet range counts */
356 packet_range_calc_user(range);
357 } /* packet_range_convert_str */
361 * Editor modelines - https://www.wireshark.org/tools/modelines.html
366 * indent-tabs-mode: nil
369 * vi: set shiftwidth=4 tabstop=8 expandtab:
370 * :indentSize=4:tabSize=8:noTabs=true: