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 #include <wsutil/ws_assert.h>
27 depended_frames_add(GHashTable
* depended_table
, frame_data_sequence
*frames
, frame_data
*frame
)
29 if (g_hash_table_add(depended_table
, GUINT_TO_POINTER(frame
->num
)) && frame
->dependent_frames
) {
32 frame_data
*depended_fd
;
33 g_hash_table_iter_init(&iter
, frame
->dependent_frames
);
34 while (g_hash_table_iter_next(&iter
, &key
, NULL
)) {
35 depended_fd
= frame_data_sequence_find(frames
, GPOINTER_TO_UINT(key
));
36 depended_frames_add(depended_table
, frames
, depended_fd
);
41 /* (re-)calculate the packet counts (except the user specified range) */
42 static void packet_range_calc(packet_range_t
*range
) {
46 uint32_t displayed_mark_low
;
47 uint32_t displayed_mark_high
;
54 range
->mark_range_cnt
= 0;
55 range
->ignored_cnt
= 0;
56 range
->ignored_selection_range_cnt
= 0;
57 range
->ignored_marked_cnt
= 0;
58 range
->ignored_mark_range_cnt
= 0;
59 range
->ignored_user_range_cnt
= 0;
61 displayed_mark_low
= 0;
62 displayed_mark_high
= 0;
64 range
->displayed_cnt
= 0;
65 range
->displayed_marked_cnt
= 0;
66 range
->displayed_mark_range_cnt
= 0;
67 range
->displayed_plus_dependents_cnt
= 0;
68 range
->displayed_mark_range_plus_depends_cnt
= 0;
69 range
->displayed_ignored_cnt
= 0;
70 range
->displayed_ignored_selection_range_cnt
= 0;
71 range
->displayed_ignored_marked_cnt
= 0;
72 range
->displayed_ignored_mark_range_cnt
= 0;
73 range
->displayed_ignored_user_range_cnt
= 0;
75 ws_assert(range
->cf
!= NULL
);
77 /* XXX - this doesn't work unless you have a full set of frame_data
78 * structures for all packets in the capture, which is not,
79 * for example, the case when TShark is doing a one-pass
80 * read of a file or a live capture.
82 * It's also horribly slow on large captures, causing it to
83 * take a long time for the Save As dialog to pop up, for
84 * example. We should really keep these statistics in
85 * the capture_file structure, updating them whenever we
86 * filter the display, etc..
88 if (range
->cf
->provider
.frames
!= NULL
) {
89 /* The next for-loop is used to obtain the amount of packets
90 * to be processed and is used to present the information in
91 * the Save/Print As widget.
92 * We have different types of ranges: All the packets, the number
93 * of packets of a marked range, a single packet, and a user specified
94 * packet range. The last one is not calculated here since this
95 * data must be entered in the widget by the user.
98 for(framenum
= 1; framenum
<= range
->cf
->count
; framenum
++) {
99 packet
= frame_data_sequence_find(range
->cf
->provider
.frames
, framenum
);
101 if (range
->cf
->current_frame
== packet
&& range
->selection_range
== NULL
) {
102 range_add_value(NULL
, &(range
->selection_range
), framenum
);
104 if (packet
->passed_dfilter
) {
105 range
->displayed_cnt
++;
107 if (packet
->passed_dfilter
||
108 packet
->dependent_of_displayed
) {
109 range
->displayed_plus_dependents_cnt
++;
111 if (packet
->marked
) {
112 if (packet
->ignored
) {
113 range
->ignored_marked_cnt
++;
115 if (packet
->passed_dfilter
) {
116 range
->displayed_marked_cnt
++;
117 if (packet
->ignored
) {
118 range
->displayed_ignored_marked_cnt
++;
120 if (displayed_mark_low
== 0) {
121 displayed_mark_low
= framenum
;
123 if (framenum
> displayed_mark_high
) {
124 displayed_mark_high
= framenum
;
126 depended_frames_add(range
->displayed_marked_plus_depends
, range
->cf
->provider
.frames
, packet
);
132 if (framenum
> mark_high
) {
133 mark_high
= framenum
;
135 depended_frames_add(range
->marked_plus_depends
, range
->cf
->provider
.frames
, packet
);
137 if (packet
->ignored
) {
138 range
->ignored_cnt
++;
139 if (packet
->passed_dfilter
) {
140 range
->displayed_ignored_cnt
++;
145 for(framenum
= 1; framenum
<= range
->cf
->count
; framenum
++) {
146 packet
= frame_data_sequence_find(range
->cf
->provider
.frames
, framenum
);
148 if (framenum
>= mark_low
&&
149 framenum
<= mark_high
)
151 range
->mark_range_cnt
++;
152 if (packet
->ignored
) {
153 range
->ignored_mark_range_cnt
++;
155 depended_frames_add(range
->mark_range_plus_depends
, range
->cf
->provider
.frames
, packet
);
158 if (framenum
>= displayed_mark_low
&&
159 framenum
<= displayed_mark_high
)
161 if (packet
->passed_dfilter
) {
162 range
->displayed_mark_range_cnt
++;
163 if (packet
->ignored
) {
164 range
->displayed_ignored_mark_range_cnt
++;
167 depended_frames_add(range
->displayed_mark_range_plus_depends
, range
->cf
->provider
.frames
, packet
);
170 range
->marked_plus_depends_cnt
= g_hash_table_size(range
->marked_plus_depends
);
171 range
->displayed_marked_plus_depends_cnt
= g_hash_table_size(range
->displayed_marked_plus_depends
);
172 range
->mark_range_plus_depends_cnt
= g_hash_table_size(range
->mark_range_plus_depends
);
173 range
->displayed_mark_range_plus_depends_cnt
= g_hash_table_size(range
->displayed_mark_range_plus_depends
);
178 /* (re-)calculate the user specified packet range counts */
179 static void packet_range_calc_user(packet_range_t
*range
) {
183 range
->user_range_cnt
= 0;
184 range
->ignored_user_range_cnt
= 0;
185 range
->displayed_user_range_cnt
= 0;
186 range
->displayed_user_range_plus_depends_cnt
= 0;
187 range
->displayed_ignored_user_range_cnt
= 0;
189 ws_assert(range
->cf
!= NULL
);
191 /* XXX - this doesn't work unless you have a full set of frame_data
192 * structures for all packets in the capture, which is not,
193 * for example, the case when TShark is doing a one-pass
194 * read of a file or a live capture.
196 * It's also horribly slow on large captures, causing it to
197 * take a long time for the Save As dialog to pop up, for
198 * example. This obviously can't be kept in the capture_file
199 * structure and recalculated whenever we filter the display
200 * or mark frames as ignored, as the results of this depend
201 * on what the user specifies. In some cases, limiting the
202 * frame_data structures at which we look to the ones specified
203 * by the user might help, but if most of the frames are in
204 * the range, that won't help. In that case, if we could
205 * examine the *complement* of the range, and *subtract* them
206 * from the statistics for the capture as a whole, that might
207 * help, but if the user specified about *half* the packets in
208 * the range, that won't help, either.
210 if (range
->cf
->provider
.frames
!= NULL
) {
211 for(framenum
= 1; framenum
<= range
->cf
->count
; framenum
++) {
212 packet
= frame_data_sequence_find(range
->cf
->provider
.frames
, framenum
);
214 if (value_is_in_range(range
->user_range
, framenum
)) {
215 range
->user_range_cnt
++;
216 if (packet
->ignored
) {
217 range
->ignored_user_range_cnt
++;
219 depended_frames_add(range
->user_range_plus_depends
, range
->cf
->provider
.frames
, packet
);
220 if (packet
->passed_dfilter
) {
221 range
->displayed_user_range_cnt
++;
222 if (packet
->ignored
) {
223 range
->displayed_ignored_user_range_cnt
++;
225 depended_frames_add(range
->displayed_user_range_plus_depends
, range
->cf
->provider
.frames
, packet
);
229 range
->user_range_plus_depends_cnt
= g_hash_table_size(range
->user_range_plus_depends
);
230 range
->displayed_user_range_plus_depends_cnt
= g_hash_table_size(range
->displayed_user_range_plus_depends
);
234 static void packet_range_calc_selection(packet_range_t
*range
) {
238 range
->selection_range_cnt
= 0;
239 range
->ignored_selection_range_cnt
= 0;
240 range
->displayed_selection_range_cnt
= 0;
241 range
->displayed_ignored_selection_range_cnt
= 0;
243 ws_assert(range
->cf
!= NULL
);
245 if (range
->cf
->provider
.frames
!= NULL
) {
246 for (framenum
= 1; framenum
<= range
->cf
->count
; framenum
++) {
247 packet
= frame_data_sequence_find(range
->cf
->provider
.frames
, framenum
);
249 if (value_is_in_range(range
->selection_range
, framenum
)) {
250 range
->selection_range_cnt
++;
251 if (packet
->ignored
) {
252 range
->ignored_selection_range_cnt
++;
254 depended_frames_add(range
->selected_plus_depends
, range
->cf
->provider
.frames
, packet
);
255 if (packet
->passed_dfilter
) {
256 range
->displayed_selection_range_cnt
++;
257 if (packet
->ignored
) {
258 range
->displayed_ignored_selection_range_cnt
++;
260 depended_frames_add(range
->displayed_selected_plus_depends
, range
->cf
->provider
.frames
, packet
);
264 range
->selected_plus_depends_cnt
= g_hash_table_size(range
->selected_plus_depends
);
265 range
->displayed_selected_plus_depends_cnt
= g_hash_table_size(range
->displayed_selected_plus_depends
);
270 /* init the range struct */
271 void packet_range_init(packet_range_t
*range
, capture_file
*cf
) {
273 memset(range
, 0, sizeof(packet_range_t
));
274 range
->process
= range_process_all
;
275 range
->user_range
= NULL
;
276 range
->selection_range
= NULL
;
278 range
->marked_plus_depends
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
279 range
->displayed_marked_plus_depends
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
280 range
->mark_range_plus_depends
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
281 range
->displayed_mark_range_plus_depends
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
282 range
->user_range_plus_depends
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
283 range
->displayed_user_range_plus_depends
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
284 range
->selected_plus_depends
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
285 range
->displayed_selected_plus_depends
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
287 /* calculate all packet range counters */
288 packet_range_calc(range
);
289 packet_range_calc_user(range
);
290 packet_range_calc_selection(range
);
293 void packet_range_cleanup(packet_range_t
*range
) {
294 wmem_free(NULL
, range
->user_range
);
295 wmem_free(NULL
, range
->selection_range
);
296 g_hash_table_destroy(range
->marked_plus_depends
);
297 g_hash_table_destroy(range
->displayed_marked_plus_depends
);
298 g_hash_table_destroy(range
->mark_range_plus_depends
);
299 g_hash_table_destroy(range
->displayed_mark_range_plus_depends
);
300 g_hash_table_destroy(range
->user_range_plus_depends
);
301 g_hash_table_destroy(range
->displayed_user_range_plus_depends
);
302 g_hash_table_destroy(range
->selected_plus_depends
);
303 g_hash_table_destroy(range
->displayed_selected_plus_depends
);
306 /* check whether the packet range is OK */
307 convert_ret_t
packet_range_check(packet_range_t
*range
) {
308 if (range
->process
== range_process_user_range
&& range
->user_range
== NULL
) {
309 /* Not valid - return the error. */
310 return range
->user_range_status
;
312 if (range
->process
== range_process_selected
&& range
->selection_range
== NULL
) {
313 return range
->selection_range_status
;
319 /* init the processing run */
320 void packet_range_process_init(packet_range_t
*range
) {
321 /* Check that, if an explicit range was selected, it's valid. */
322 /* "enumeration" values */
323 range
->marked_range_active
= false;
325 if (range
->process_filtered
== false) {
326 range
->marked_range_left
= range
->mark_range_cnt
;
328 range
->marked_range_left
= range
->displayed_mark_range_cnt
;
330 /* XXX: We could set the count to whichever case is active so we
331 * could decrement it and return finished.
335 /* do we have to process all packets? */
336 bool packet_range_process_all(packet_range_t
*range
) {
337 return range
->process
== range_process_all
&& !range
->process_filtered
&& !range
->remove_ignored
;
340 static range_process_e
341 packet_range_process_packet_include_depends(packet_range_t
*range
, frame_data
*fdata
) {
343 switch(range
->process
) {
344 case(range_process_all
):
345 if (range
->process_filtered
) {
346 if ((fdata
->passed_dfilter
|| fdata
->dependent_of_displayed
) == false) {
347 return range_process_next
;
351 case(range_process_selected
):
352 if (range
->process_filtered
) {
353 if (!g_hash_table_contains(range
->displayed_selected_plus_depends
, GUINT_TO_POINTER(fdata
->num
))) {
354 return range_process_next
;
357 if (!g_hash_table_contains(range
->selected_plus_depends
, GUINT_TO_POINTER(fdata
->num
))) {
358 return range_process_next
;
362 case(range_process_marked
):
363 if (range
->process_filtered
) {
364 if (!g_hash_table_contains(range
->displayed_marked_plus_depends
, GUINT_TO_POINTER(fdata
->num
))) {
365 return range_process_next
;
368 if (!g_hash_table_contains(range
->marked_plus_depends
, GUINT_TO_POINTER(fdata
->num
))) {
369 return range_process_next
;
373 case(range_process_marked_range
):
374 if (range
->process_filtered
) {
375 if (!g_hash_table_contains(range
->displayed_mark_range_plus_depends
, GUINT_TO_POINTER(fdata
->num
))) {
376 return range_process_next
;
379 if (!g_hash_table_contains(range
->mark_range_plus_depends
, GUINT_TO_POINTER(fdata
->num
))) {
380 return range_process_next
;
384 case(range_process_user_range
):
385 if (range
->process_filtered
) {
386 if (!g_hash_table_contains(range
->displayed_user_range_plus_depends
, GUINT_TO_POINTER(fdata
->num
))) {
387 return range_process_next
;
390 if (!g_hash_table_contains(range
->user_range_plus_depends
, GUINT_TO_POINTER(fdata
->num
))) {
391 return range_process_next
;
396 ws_assert_not_reached();
399 /* We fell through the conditions above, so we accept this packet */
400 return range_process_this
;
403 /* do we have to process this packet? */
404 range_process_e
packet_range_process_packet(packet_range_t
*range
, frame_data
*fdata
) {
406 /* For ignored packets, since we don't dissect them, we don't know
407 * anything about packets they depend upon, which is helpful as we
408 * don't have to calculate more counts based on interaction terms. If
409 * someone wants to include those, then don't ignore the packet.
411 if (range
->remove_ignored
&& fdata
->ignored
) {
412 return range_process_next
;
415 ws_assert(range
->cf
!= NULL
);
417 if (range
->include_dependents
) {
418 return packet_range_process_packet_include_depends(range
, fdata
);
421 switch(range
->process
) {
422 case(range_process_all
):
424 case(range_process_selected
):
425 if (value_is_in_range(range
->selection_range
, fdata
->num
) == false) {
426 return range_process_next
;
429 case(range_process_marked
):
430 if (fdata
->marked
== false) {
431 return range_process_next
;
434 case(range_process_marked_range
):
435 if (range
->marked_range_left
== 0) {
436 return range_processing_finished
;
438 if (fdata
->marked
== true) {
439 range
->marked_range_active
= true;
441 if (range
->marked_range_active
== false ) {
442 return range_process_next
;
444 if (!range
->process_filtered
||
445 (range
->process_filtered
&& fdata
->passed_dfilter
== true))
447 range
->marked_range_left
--;
450 case(range_process_user_range
):
451 if (value_is_in_range(range
->user_range
, fdata
->num
) == false) {
452 return range_process_next
;
456 ws_assert_not_reached();
459 /* This packet has to pass the display filter but didn't?
460 * Try next (if we're including dependent packets we called the
461 * other function above).
463 if ((range
->process_filtered
&& fdata
->passed_dfilter
== false)) {
464 return range_process_next
;
467 /* We fell through the conditions above, so we accept this packet */
468 return range_process_this
;
472 /******************** Range Entry Parser *********************************/
474 /* Converts a range string to a user range.
475 * The parameter 'es' points to the string to be converted, and is defined in
476 * the Save/Print-As widget.
479 void packet_range_convert_str(packet_range_t
*range
, const char *es
)
484 if (range
->user_range
!= NULL
)
485 wmem_free(NULL
, range
->user_range
);
487 ws_assert(range
->cf
!= NULL
);
489 ret
= range_convert_str(NULL
, &new_range
, es
, range
->cf
->count
);
490 if (ret
!= CVT_NO_ERROR
) {
491 /* range isn't valid */
492 range
->user_range
= NULL
;
493 range
->user_range_status
= ret
;
494 range
->user_range_cnt
= 0;
495 range
->user_range_plus_depends_cnt
= 0;
496 range
->ignored_user_range_cnt
= 0;
497 range
->displayed_user_range_cnt
= 0;
498 range
->displayed_ignored_user_range_cnt
= 0;
499 range
->displayed_user_range_plus_depends_cnt
= 0;
502 range
->user_range
= new_range
;
503 g_hash_table_remove_all(range
->user_range_plus_depends
);
504 g_hash_table_remove_all(range
->displayed_user_range_plus_depends
);
506 /* calculate new user specified packet range counts */
507 packet_range_calc_user(range
);
508 } /* packet_range_convert_str */
510 void packet_range_convert_selection_str(packet_range_t
*range
, const char *es
)
515 if (range
->selection_range
!= NULL
)
516 wmem_free(NULL
, range
->selection_range
);
518 ws_assert(range
->cf
!= NULL
);
520 ret
= range_convert_str(NULL
, &new_range
, es
, range
->cf
->count
);
521 if (ret
!= CVT_NO_ERROR
) {
522 /* range isn't valid */
523 range
->selection_range
= NULL
;
524 range
->selection_range_status
= ret
;
525 range
->selection_range_cnt
= 0;
526 range
->selected_plus_depends_cnt
= 0;
527 range
->ignored_selection_range_cnt
= 0;
528 range
->displayed_selection_range_cnt
= 0;
529 range
->displayed_selected_plus_depends_cnt
= 0;
530 range
->displayed_ignored_selection_range_cnt
= 0;
533 range
->selection_range
= new_range
;
534 g_hash_table_remove_all(range
->selected_plus_depends
);
535 g_hash_table_remove_all(range
->displayed_selected_plus_depends
);
537 /* calculate new user specified packet range counts */
538 packet_range_calc_selection(range
);
541 uint32_t packet_range_count(const packet_range_t
*range
)
544 switch(range
->process
) {
545 case(range_process_all
):
546 if (range
->process_filtered
) {
547 if (range
->include_dependents
) {
548 count
= range
->displayed_plus_dependents_cnt
;
550 count
= range
->displayed_cnt
;
552 if (range
->remove_ignored
) {
553 count
-= range
->displayed_ignored_cnt
;
556 count
= range
->cf
->count
;
557 if (range
->remove_ignored
) {
558 count
-= range
->ignored_cnt
;
562 case(range_process_selected
):
563 if (range
->process_filtered
) {
564 if (range
->include_dependents
) {
565 count
= range
->displayed_selected_plus_depends_cnt
;
567 count
= range
->displayed_selection_range_cnt
;
569 if (range
->remove_ignored
) {
570 count
-= range
->displayed_ignored_selection_range_cnt
;
573 if (range
->include_dependents
) {
574 count
= range
->selected_plus_depends_cnt
;
576 count
= range
->selection_range_cnt
;
578 if (range
->remove_ignored
) {
579 count
-= range
->ignored_selection_range_cnt
;
583 case(range_process_marked
):
584 if (range
->process_filtered
) {
585 if (range
->include_dependents
) {
586 count
= range
->displayed_marked_plus_depends_cnt
;
588 count
= range
->displayed_marked_cnt
;
590 if (range
->remove_ignored
) {
591 count
-= range
->displayed_ignored_marked_cnt
;
594 if (range
->include_dependents
) {
595 count
= range
->marked_plus_depends_cnt
;
597 count
= range
->cf
->marked_count
;
599 if (range
->remove_ignored
) {
600 count
-= range
->ignored_marked_cnt
;
604 case(range_process_marked_range
):
605 if (range
->process_filtered
) {
606 if (range
->include_dependents
) {
607 count
= range
->displayed_mark_range_plus_depends_cnt
;
609 count
= range
->displayed_mark_range_cnt
;
611 if (range
->remove_ignored
) {
612 count
-= range
->displayed_ignored_mark_range_cnt
;
615 if (range
->include_dependents
) {
616 count
= range
->mark_range_plus_depends_cnt
;
618 count
= range
->mark_range_cnt
;
620 if (range
->remove_ignored
) {
621 count
-= range
->ignored_mark_range_cnt
;
625 case(range_process_user_range
):
626 if (range
->process_filtered
) {
627 if (range
->include_dependents
) {
628 count
= range
->displayed_user_range_plus_depends_cnt
;
630 count
= range
->displayed_user_range_cnt
;
632 if (range
->remove_ignored
) {
633 count
-= range
->displayed_ignored_user_range_cnt
;
636 if (range
->include_dependents
) {
637 count
= range
->user_range_plus_depends_cnt
;
639 count
= range
->user_range_cnt
;
641 if (range
->remove_ignored
) {
642 count
-= range
->ignored_user_range_cnt
;
647 ws_assert_not_reached();