2 * Routines for packet capture
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
39 #include <epan/packet.h>
40 #include <epan/dfilter/dfilter.h>
43 #include "capture_ifinfo.h"
44 #include "capture_sync.h"
45 #include "capture_info.h"
46 #include "capture_ui_utils.h"
48 #include "capture-pcap-util.h"
49 #include <epan/prefs.h>
52 #include "capture-wpcap.h"
55 #include "ui/simple_dialog.h"
56 #include "ui/ui_util.h"
58 #include "wsutil/file_util.h"
61 typedef struct if_stat_cache_item_s {
64 } if_stat_cache_item_t;
66 struct if_stat_cache_s {
69 GList *cache_list; /* List of if_stat_chache_entry_t */
72 /* this callback mechanism should possibly be replaced by the g_signal_...() stuff (if I only would know how :-) */
74 capture_callback_t cb_fct;
76 } capture_callback_data_t;
78 static GList *capture_callbacks = NULL;
81 capture_callback_invoke(int event, capture_session *cap_session)
83 capture_callback_data_t *cb;
84 GList *cb_item = capture_callbacks;
86 /* there should be at least one interested */
87 g_assert(cb_item != NULL);
89 while(cb_item != NULL) {
90 cb = (capture_callback_data_t *)cb_item->data;
91 cb->cb_fct(event, cap_session, cb->user_data);
92 cb_item = g_list_next(cb_item);
98 capture_callback_add(capture_callback_t func, gpointer user_data)
100 capture_callback_data_t *cb;
102 cb = (capture_callback_data_t *)g_malloc(sizeof(capture_callback_data_t));
104 cb->user_data = user_data;
106 capture_callbacks = g_list_append(capture_callbacks, cb);
110 capture_callback_remove(capture_callback_t func)
112 capture_callback_data_t *cb;
113 GList *cb_item = capture_callbacks;
115 while(cb_item != NULL) {
116 cb = (capture_callback_data_t *)cb_item->data;
117 if(cb->cb_fct == func) {
118 capture_callbacks = g_list_remove(capture_callbacks, cb);
122 cb_item = g_list_next(cb_item);
125 g_assert_not_reached();
131 * @return TRUE if the capture starts successfully, FALSE otherwise.
134 capture_start(capture_options *capture_opts, capture_session *cap_session, void(*update_cb)(void))
138 GString *source = g_string_new("");
140 cap_session->state = CAPTURE_PREPARING;
141 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Start ...");
143 if (capture_opts->ifaces->len < 2) {
145 if (capture_opts->ifaces->len < 4) {
147 for (i = 0; i < capture_opts->ifaces->len; i++) {
148 interface_options interface_opts;
150 interface_opts = g_array_index(capture_opts->ifaces, interface_options, i);
152 if (capture_opts->ifaces->len > 2) {
153 g_string_append_printf(source, ",");
155 g_string_append_printf(source, " ");
156 if (i == capture_opts->ifaces->len - 1) {
157 g_string_append_printf(source, "and ");
160 g_string_append_printf(source, "%s", get_iface_description_for_interface(capture_opts, i));
161 if ((interface_opts.cfilter != NULL) &&
162 (strlen(interface_opts.cfilter) > 0)) {
163 g_string_append_printf(source, " (%s)", interface_opts.cfilter);
167 g_string_append_printf(source, "%u interfaces", capture_opts->ifaces->len);
169 cf_set_tempfile_source((capture_file *)cap_session->cf, source->str);
170 g_string_free(source, TRUE);
171 /* try to start the capture child process */
172 ret = sync_pipe_start(capture_opts, cap_session, update_cb);
174 if(capture_opts->save_file != NULL) {
175 g_free(capture_opts->save_file);
176 capture_opts->save_file = NULL;
179 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Start failed!");
180 cap_session->state = CAPTURE_STOPPED;
182 /* the capture child might not respond shortly after bringing it up */
183 /* (for example: it will block if no input arrives from an input capture pipe (e.g. mkfifo)) */
185 /* to prevent problems, bring the main GUI into "capture mode" right after a successful */
186 /* spawn/exec of the capture child, without waiting for any response from it */
187 capture_callback_invoke(capture_cb_capture_prepared, cap_session);
189 if(capture_opts->show_info)
190 capture_info_open(cap_session);
198 capture_stop(capture_session *cap_session)
200 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Stop ...");
202 capture_callback_invoke(capture_cb_capture_stopping, cap_session);
204 /* stop the capture child gracefully */
205 sync_pipe_stop(cap_session);
210 capture_restart(capture_session *cap_session)
212 capture_options *capture_opts = cap_session->capture_opts;
214 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Restart");
216 capture_opts->restart = TRUE;
217 capture_stop(cap_session);
222 capture_kill_child(capture_session *cap_session)
224 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_INFO, "Capture Kill");
226 /* kill the capture child */
227 sync_pipe_kill(cap_session->fork_child);
230 /* We've succeeded in doing a (non real-time) capture; try to read it into a new capture file */
232 capture_input_read_all(capture_session *cap_session, gboolean is_tempfile,
233 gboolean drops_known, guint32 drops)
235 capture_options *capture_opts = cap_session->capture_opts;
238 /* Capture succeeded; attempt to open the capture file. */
239 if (cf_open((capture_file *)cap_session->cf, capture_opts->save_file, is_tempfile, &err) != CF_OK) {
240 /* We're not doing a capture any more, so we don't have a save file. */
244 /* Set the read filter to NULL. */
245 /* XXX - this is odd here; try to put it somewhere where it fits better */
246 cf_set_rfcode((capture_file *)cap_session->cf, NULL);
248 /* Get the packet-drop statistics.
250 XXX - there are currently no packet-drop statistics stored
251 in libpcap captures, and that's what we're reading.
253 At some point, we will add support in Wiretap to return
254 packet-drop statistics for capture file formats that store it,
255 and will make "cf_read()" get those statistics from Wiretap.
256 We clear the statistics (marking them as "not known") in
257 "cf_open()", and "cf_read()" will only fetch them and mark
258 them as known if Wiretap supplies them, so if we get the
259 statistics now, after calling "cf_open()" but before calling
260 "cf_read()", the values we store will be used by "cf_read()".
262 If a future libpcap capture file format stores the statistics,
263 we'll put them into the capture file that we write, and will
264 thus not have to set them here - "cf_read()" will get them from
265 the file and use them. */
267 cf_set_drops_known((capture_file *)cap_session->cf, TRUE);
269 /* XXX - on some systems, libpcap doesn't bother filling in
270 "ps_ifdrop" - it doesn't even set it to zero - so we don't
271 bother looking at it.
273 Ideally, libpcap would have an interface that gave us
274 several statistics - perhaps including various interface
275 error statistics - and would tell us which of them it
276 supplies, allowing us to display only the ones it does. */
277 cf_set_drops((capture_file *)cap_session->cf, drops);
280 /* read in the packet data */
281 switch (cf_read((capture_file *)cap_session->cf, FALSE)) {
285 /* Just because we got an error, that doesn't mean we were unable
286 to read any of the file; we handle what we could get from the
290 case CF_READ_ABORTED:
291 /* User wants to quit program. Exit by leaving the main loop,
292 so that any quit functions we registered get called. */
293 main_window_nested_quit();
297 /* if we didn't capture even a single packet, close the file again */
298 if(cf_get_packet_count((capture_file *)cap_session->cf) == 0 && !capture_opts->restart) {
299 simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
300 "%sNo packets captured!%s\n"
302 "As no data was captured, closing the %scapture file!\n"
305 "Help about capturing can be found at:\n"
307 " http://wiki.wireshark.org/CaptureSetup"
310 "Wireless (Wi-Fi/WLAN):\n"
311 "Try to switch off promiscuous mode in the Capture Options!"
314 simple_dialog_primary_start(), simple_dialog_primary_end(),
315 (cf_is_tempfile((capture_file *)cap_session->cf)) ? "temporary " : "");
316 cf_close((capture_file *)cap_session->cf);
322 /* capture child tells us we have a new (or the first) capture file */
324 capture_input_new_file(capture_session *cap_session, gchar *new_file)
326 capture_options *capture_opts = cap_session->capture_opts;
327 gboolean is_tempfile;
330 if(cap_session->state == CAPTURE_PREPARING) {
331 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture started!");
333 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "File: \"%s\"", new_file);
335 g_assert(cap_session->state == CAPTURE_PREPARING || cap_session->state == CAPTURE_RUNNING);
337 /* free the old filename */
338 if(capture_opts->save_file != NULL) {
339 /* we start a new capture file, close the old one (if we had one before). */
340 /* (we can only have an open capture file in real_time_mode!) */
341 if( ((capture_file *) cap_session->cf)->state != FILE_CLOSED) {
342 if(capture_opts->real_time_mode) {
343 capture_callback_invoke(capture_cb_capture_update_finished, cap_session);
344 cf_finish_tail((capture_file *)cap_session->cf, &err);
345 cf_close((capture_file *)cap_session->cf);
347 capture_callback_invoke(capture_cb_capture_fixed_finished, cap_session);
350 g_free(capture_opts->save_file);
352 cf_set_tempfile((capture_file *)cap_session->cf, FALSE);
354 /* we didn't have a save_file before; must be a tempfile */
356 cf_set_tempfile((capture_file *)cap_session->cf, TRUE);
359 /* save the new filename */
360 capture_opts->save_file = g_strdup(new_file);
362 /* if we are in real-time mode, open the new file now */
363 if(capture_opts->real_time_mode) {
364 /* Attempt to open the capture file and set up to read from it. */
365 switch(cf_open((capture_file *)cap_session->cf, capture_opts->save_file, is_tempfile, &err)) {
369 /* Don't unlink (delete) the save file - leave it around,
370 for debugging purposes. */
371 g_free(capture_opts->save_file);
372 capture_opts->save_file = NULL;
376 capture_callback_invoke(capture_cb_capture_prepared, cap_session);
379 if(capture_opts->show_info) {
380 if (!capture_info_new_file(new_file))
384 if(capture_opts->real_time_mode) {
385 capture_callback_invoke(capture_cb_capture_update_started, cap_session);
387 capture_callback_invoke(capture_cb_capture_fixed_started, cap_session);
389 cap_session->state = CAPTURE_RUNNING;
395 /* capture child tells us we have new packets to read */
397 capture_input_new_packets(capture_session *cap_session, int to_read)
399 capture_options *capture_opts = cap_session->capture_opts;
402 g_assert(capture_opts->save_file);
404 if(capture_opts->real_time_mode) {
405 /* Read from the capture file the number of records the child told us it added. */
406 switch (cf_continue_tail((capture_file *)cap_session->cf, to_read, &err)) {
410 /* Just because we got an error, that doesn't mean we were unable
411 to read any of the file; we handle what we could get from the
414 XXX - abort on a read error? */
415 capture_callback_invoke(capture_cb_capture_update_continue, cap_session);
418 case CF_READ_ABORTED:
419 /* Kill the child capture process; the user wants to exit, and we
420 shouldn't just leave it running. */
421 capture_kill_child(cap_session);
425 /* increase the capture file packet counter by the number of incoming packets */
426 cf_set_packet_count((capture_file *)cap_session->cf,
427 cf_get_packet_count((capture_file *)cap_session->cf) + to_read);
428 cf_fake_continue_tail((capture_file *)cap_session->cf);
430 capture_callback_invoke(capture_cb_capture_fixed_continue, cap_session);
433 /* update the main window so we get events (e.g. from the stop toolbar button) */
434 /* This causes a hang on Windows (see bug 7305). Do we need this on any platform? */
436 main_window_update();
439 if(capture_opts->show_info)
440 capture_info_new_packets(to_read);
444 /* Capture child told us how many dropped packets it counted.
447 capture_input_drops(capture_session *cap_session, guint32 dropped)
449 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_INFO, "%u packet%s dropped", dropped, plurality(dropped, "", "s"));
451 g_assert(cap_session->state == CAPTURE_RUNNING);
453 cf_set_drops_known((capture_file *)cap_session->cf, TRUE);
454 cf_set_drops((capture_file *)cap_session->cf, dropped);
458 /* Capture child told us that an error has occurred while starting/running
460 The buffer we're handed has *two* null-terminated strings in it - a
461 primary message and a secondary message, one right after the other.
462 The secondary message might be a null string.
465 capture_input_error_message(capture_session *cap_session, char *error_msg,
466 char *secondary_error_msg)
468 gchar *safe_error_msg;
469 gchar *safe_secondary_error_msg;
471 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Error message from child: \"%s\", \"%s\"",
472 error_msg, secondary_error_msg);
474 g_assert(cap_session->state == CAPTURE_PREPARING || cap_session->state == CAPTURE_RUNNING);
476 safe_error_msg = simple_dialog_format_message(error_msg);
477 if (*secondary_error_msg != '\0') {
478 /* We have both primary and secondary messages. */
479 safe_secondary_error_msg = simple_dialog_format_message(secondary_error_msg);
480 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s%s%s\n\n%s",
481 simple_dialog_primary_start(), safe_error_msg,
482 simple_dialog_primary_end(), safe_secondary_error_msg);
483 g_free(safe_secondary_error_msg);
485 /* We have only a primary message. */
486 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s%s%s",
487 simple_dialog_primary_start(), safe_error_msg,
488 simple_dialog_primary_end());
490 g_free(safe_error_msg);
492 /* the capture child will close the sync_pipe if required, nothing to do for now */
495 /* Capture child told us that an error has occurred while parsing a
496 capture filter when starting/running the capture.
499 capture_input_cfilter_error_message(capture_session *cap_session, guint i,
502 capture_options *capture_opts = cap_session->capture_opts;
503 dfilter_t *rfcode = NULL;
506 gchar *safe_cfilter_error_msg;
507 interface_options interface_opts;
509 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture filter error message from child: \"%s\"", error_message);
511 g_assert(cap_session->state == CAPTURE_PREPARING || cap_session->state == CAPTURE_RUNNING);
512 g_assert(i < capture_opts->ifaces->len);
514 interface_opts = g_array_index(capture_opts->ifaces, interface_options, i);
515 safe_cfilter = simple_dialog_format_message(interface_opts.cfilter);
516 safe_descr = simple_dialog_format_message(interface_opts.descr);
517 safe_cfilter_error_msg = simple_dialog_format_message(error_message);
518 /* Did the user try a display filter? */
519 if (dfilter_compile(interface_opts.cfilter, &rfcode) && rfcode != NULL) {
520 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
521 "%sInvalid capture filter \"%s\" for interface %s!%s\n"
523 "That string looks like a valid display filter; however, it isn't a valid\n"
524 "capture filter (%s).\n"
526 "Note that display filters and capture filters don't have the same syntax,\n"
527 "so you can't use most display filter expressions as capture filters.\n"
529 "See the User's Guide for a description of the capture filter syntax.",
530 simple_dialog_primary_start(), safe_cfilter, safe_descr,
531 simple_dialog_primary_end(), safe_cfilter_error_msg);
532 dfilter_free(rfcode);
534 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
535 "%sInvalid capture filter \"%s\" for interface %s!%s\n"
537 "That string isn't a valid capture filter (%s).\n"
538 "See the User's Guide for a description of the capture filter syntax.",
539 simple_dialog_primary_start(), safe_cfilter, safe_descr,
540 simple_dialog_primary_end(), safe_cfilter_error_msg);
542 g_free(safe_cfilter_error_msg);
544 g_free(safe_cfilter);
546 /* the capture child will close the sync_pipe if required, nothing to do for now */
549 /* capture child closed its side of the pipe, do the required cleanup */
551 capture_input_closed(capture_session *cap_session, gchar *msg)
553 capture_options *capture_opts = cap_session->capture_opts;
555 int packet_count_save;
557 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture stopped!");
558 g_assert(cap_session->state == CAPTURE_PREPARING || cap_session->state == CAPTURE_RUNNING);
561 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", msg);
563 if(cap_session->state == CAPTURE_PREPARING) {
564 /* We didn't start a capture; note that the attempt to start it
566 capture_callback_invoke(capture_cb_capture_failed, cap_session);
568 /* We started a capture; process what's left of the capture file if
569 we were in "update list of packets in real time" mode, or process
570 all of it if we weren't. */
571 if(capture_opts->real_time_mode) {
572 cf_read_status_t status;
574 /* Read what remains of the capture file. */
575 status = cf_finish_tail((capture_file *)cap_session->cf, &err);
577 /* XXX: If -Q (quit-after-cap) then cf->count clr'd below so save it first */
578 packet_count_save = cf_get_packet_count((capture_file *)cap_session->cf);
579 /* Tell the GUI we are not doing a capture any more.
580 Must be done after the cf_finish_tail(), so file lengths are
581 correctly displayed */
582 capture_callback_invoke(capture_cb_capture_update_finished, cap_session);
584 /* Finish the capture. */
588 if ((packet_count_save == 0) && !capture_opts->restart) {
589 simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
590 "%sNo packets captured!%s\n"
592 "As no data was captured, closing the %scapture file!\n"
595 "Help about capturing can be found at:\n"
597 " http://wiki.wireshark.org/CaptureSetup"
600 "Wireless (Wi-Fi/WLAN):\n"
601 "Try to switch off promiscuous mode in the Capture Options!"
604 simple_dialog_primary_start(), simple_dialog_primary_end(),
605 cf_is_tempfile((capture_file *)cap_session->cf) ? "temporary " : "");
606 cf_close((capture_file *)cap_session->cf);
610 /* Just because we got an error, that doesn't mean we were unable
611 to read any of the file; we handle what we could get from the
615 case CF_READ_ABORTED:
616 /* Exit by leaving the main loop, so that any quit functions
617 we registered get called. */
622 /* first of all, we are not doing a capture any more */
623 capture_callback_invoke(capture_cb_capture_fixed_finished, cap_session);
625 /* this is a normal mode capture and if no error happened, read in the capture file data */
626 if(capture_opts->save_file != NULL) {
627 capture_input_read_all(cap_session, cf_is_tempfile((capture_file *)cap_session->cf),
628 cf_get_drops_known((capture_file *)cap_session->cf), cf_get_drops((capture_file *)cap_session->cf));
633 if(capture_opts->show_info)
634 capture_info_close();
636 cap_session->state = CAPTURE_STOPPED;
638 /* if we couldn't open a capture file, there's nothing more for us to do */
639 if(capture_opts->save_file == NULL) {
640 cf_close((capture_file *)cap_session->cf);
644 /* does the user wants to restart the current capture? */
645 if(capture_opts->restart) {
646 capture_opts->restart = FALSE;
648 ws_unlink(capture_opts->save_file);
650 /* If we have a ring buffer, the original save file has been overwritten
651 with the "ring filename". Restore it before starting again */
652 if ((capture_opts->multi_files_on) && (capture_opts->orig_save_file != NULL)) {
653 g_free(capture_opts->save_file);
654 capture_opts->save_file = g_strdup(capture_opts->orig_save_file);
657 /* if it was a tempfile, throw away the old filename (so it will become a tempfile again) */
658 if(cf_is_tempfile((capture_file *)cap_session->cf)) {
659 g_free(capture_opts->save_file);
660 capture_opts->save_file = NULL;
663 /* ... and start the capture again */
664 if (capture_opts->ifaces->len == 0) {
665 collect_ifaces(capture_opts);
668 /* close the currently loaded capture file */
669 cf_close((capture_file *)cap_session->cf);
671 capture_start(capture_opts, cap_session,NULL); /*XXX is this NULL ok or we need an update_cb???*/
673 /* We're not doing a capture any more, so we don't have a save file. */
674 g_free(capture_opts->save_file);
675 capture_opts->save_file = NULL;
680 capture_stat_start(capture_options *capture_opts) {
681 int stat_fd, fork_child;
683 if_stat_cache_t *sc = NULL;
684 if_stat_cache_item_t *sc_item;
688 /* Fire up dumpcap. */
690 * XXX - on systems with BPF, the number of BPF devices limits the
691 * number of devices on which you can capture simultaneously.
695 * 1) this might fail if you run out of BPF devices
699 * 2) opening every interface could leave too few BPF devices
700 * for *other* programs.
702 * It also means the system could end up getting a lot of traffic
703 * that it has to pass through the networking stack and capture
704 * mechanism, so opening all the devices and presenting packet
705 * counts might not always be a good idea.
707 if (sync_interface_stats_open(&stat_fd, &fork_child, &msg, NULL) == 0) {
708 sc = (if_stat_cache_t *)g_malloc(sizeof(if_stat_cache_t));
709 sc->stat_fd = stat_fd;
710 sc->fork_child = fork_child;
711 sc->cache_list = NULL;
713 /* Initialize the cache */
714 for (i = 0; i < capture_opts->all_ifaces->len; i++) {
715 device = g_array_index(capture_opts->all_ifaces, interface_t, i);
716 if (device.type != IF_PIPE && &(device.if_info)) {
717 sc_item = (if_stat_cache_item_t *)g_malloc0(sizeof(if_stat_cache_item_t));
718 sc_item->name = g_strdup(device.if_info.name);
719 sc->cache_list = g_list_append(sc->cache_list, sc_item);
726 #define MAX_STAT_LINE_LEN 500
729 capture_stat_cache_update(if_stat_cache_t *sc) {
730 gchar stat_line[MAX_STAT_LINE_LEN] = "";
733 if_stat_cache_item_t *sc_item;
738 while (sync_pipe_gets_nonblock(sc->stat_fd, stat_line, MAX_STAT_LINE_LEN) > 0) {
739 g_strstrip(stat_line);
740 stat_parts = g_strsplit(stat_line, "\t", 3);
741 if (stat_parts[0] == NULL || stat_parts[1] == NULL ||
742 stat_parts[2] == NULL) {
743 g_strfreev(stat_parts);
746 for (sc_entry = sc->cache_list; sc_entry != NULL; sc_entry = g_list_next(sc_entry)) {
747 sc_item = (if_stat_cache_item_t *)sc_entry->data;
748 if (strcmp(sc_item->name, stat_parts[0]) == 0) {
749 sc_item->ps.ps_recv = (u_int) strtoul(stat_parts[1], NULL, 10);
750 sc_item->ps.ps_drop = (u_int) strtoul(stat_parts[2], NULL, 10);
753 g_strfreev(stat_parts);
758 capture_stats(if_stat_cache_t *sc, char *ifname, struct pcap_stat *ps) {
760 if_stat_cache_item_t *sc_item;
762 if (!sc || !ifname || !ps) {
766 capture_stat_cache_update(sc);
767 for (sc_entry = sc->cache_list; sc_entry != NULL; sc_entry = g_list_next(sc_entry)) {
768 sc_item = (if_stat_cache_item_t *)sc_entry->data;
769 if (strcmp(sc_item->name, ifname) == 0) {
770 memcpy(ps, &sc_item->ps, sizeof(struct pcap_stat));
778 capture_stat_stop(if_stat_cache_t *sc) {
780 if_stat_cache_item_t *sc_item;
787 ret = sync_interface_stats_close(&sc->stat_fd, &sc->fork_child, &msg);
789 /* XXX - report failure? */
793 for (sc_entry = sc->cache_list; sc_entry != NULL; sc_entry = g_list_next(sc_entry)) {
794 sc_item = (if_stat_cache_item_t *)sc_entry->data;
795 g_free(sc_item->name);
801 #endif /* HAVE_LIBPCAP */