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