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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
43 #ifdef HAVE_SYS_TYPES_H
44 #include <sys/types.h>
47 #ifdef HAVE_NETINET_IN_H
48 #include <netinet/in.h>
55 #ifdef HAVE_ARPA_INET_H
56 #include <arpa/inet.h>
59 #ifdef HAVE_SYS_SOCKET_H
60 #include <sys/socket.h> /* needed to define AF_ values on UNIX */
63 #ifdef HAVE_WINSOCK2_H
64 #include <winsock2.h> /* needed to define AF_ values on Windows */
67 #ifdef NEED_INET_V6DEFS_H
68 # include "inet_v6defs.h"
76 #include <epan/packet.h>
77 #include <epan/dfilter/dfilter.h>
80 #include "capture_sync.h"
81 #include "capture_info.h"
82 #include "capture_ui_utils.h"
84 #include "capture-pcap-util.h"
85 #include "alert_box.h"
86 #include "simple_dialog.h"
87 #include <epan/prefs.h>
90 #include "capture-wpcap.h"
93 #include "file_util.h"
96 typedef struct if_stat_cache_item_s {
99 } if_stat_cache_item_t;
101 struct if_stat_cache_s {
104 GList *cache_list; /* List of if_stat_chache_entry_t */
110 * @return TRUE if the capture starts successfully, FALSE otherwise.
113 capture_start(capture_options *capture_opts)
118 /* close the currently loaded capture file */
119 cf_close(capture_opts->cf);
121 g_assert(capture_opts->state == CAPTURE_STOPPED);
122 capture_opts->state = CAPTURE_PREPARING;
124 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Start ...");
126 /* try to start the capture child process */
127 ret = sync_pipe_start(capture_opts);
129 if(capture_opts->save_file != NULL) {
130 g_free(capture_opts->save_file);
131 capture_opts->save_file = NULL;
134 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Start failed!");
135 capture_opts->state = CAPTURE_STOPPED;
137 /* the capture child might not respond shortly after bringing it up */
138 /* (especially it will block, if no input coming from an input capture pipe (e.g. mkfifo) is coming in) */
140 /* to prevent problems, bring the main GUI into "capture mode" right after successfully */
141 /* spawn/exec the capture child, without waiting for any response from it */
142 cf_callback_invoke(cf_cb_live_capture_prepared, capture_opts);
144 if(capture_opts->show_info)
145 capture_info_open(capture_opts->iface);
153 capture_stop(capture_options *capture_opts)
155 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Stop ...");
157 cf_callback_invoke(cf_cb_live_capture_stopping, capture_opts);
159 /* stop the capture child gracefully */
160 sync_pipe_stop(capture_opts);
165 capture_restart(capture_options *capture_opts)
167 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Restart");
169 capture_opts->restart = TRUE;
170 capture_stop(capture_opts);
175 capture_kill_child(capture_options *capture_opts)
177 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_INFO, "Capture Kill");
179 /* kill the capture child */
180 sync_pipe_kill(capture_opts->fork_child);
185 /* We've succeeded a (non real-time) capture, try to read it into a new capture file */
187 capture_input_read_all(capture_options *capture_opts, gboolean is_tempfile, gboolean drops_known,
193 /* Capture succeeded; attempt to open the capture file. */
194 if (cf_open(capture_opts->cf, capture_opts->save_file, is_tempfile, &err) != CF_OK) {
195 /* We're not doing a capture any more, so we don't have a save
200 /* Set the read filter to NULL. */
201 /* XXX - this is odd here, try to put it somewhere, where it fits better */
202 cf_set_rfcode(capture_opts->cf, NULL);
204 /* Get the packet-drop statistics.
206 XXX - there are currently no packet-drop statistics stored
207 in libpcap captures, and that's what we're reading.
209 At some point, we will add support in Wiretap to return
210 packet-drop statistics for capture file formats that store it,
211 and will make "cf_read()" get those statistics from Wiretap.
212 We clear the statistics (marking them as "not known") in
213 "cf_open()", and "cf_read()" will only fetch them and mark
214 them as known if Wiretap supplies them, so if we get the
215 statistics now, after calling "cf_open()" but before calling
216 "cf_read()", the values we store will be used by "cf_read()".
218 If a future libpcap capture file format stores the statistics,
219 we'll put them into the capture file that we write, and will
220 thus not have to set them here - "cf_read()" will get them from
221 the file and use them. */
223 cf_set_drops_known(capture_opts->cf, TRUE);
225 /* XXX - on some systems, libpcap doesn't bother filling in
226 "ps_ifdrop" - it doesn't even set it to zero - so we don't
227 bother looking at it.
229 Ideally, libpcap would have an interface that gave us
230 several statistics - perhaps including various interface
231 error statistics - and would tell us which of them it
232 supplies, allowing us to display only the ones it does. */
233 cf_set_drops(capture_opts->cf, drops);
236 /* read in the packet data */
237 switch (cf_read(capture_opts->cf)) {
241 /* Just because we got an error, that doesn't mean we were unable
242 to read any of the file; we handle what we could get from the
246 case CF_READ_ABORTED:
247 /* User wants to quit program. Exit by leaving the main loop,
248 so that any quit functions we registered get called. */
249 main_window_nested_quit();
253 /* if we didn't captured even a single packet, close the file again */
254 if(cf_get_packet_count(capture_opts->cf) == 0 && !capture_opts->restart) {
255 simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
256 "%sNo packets captured!%s\n"
258 "As no data was captured, closing the %scapture file!\n"
261 "Help about capturing can be found at:\n"
263 " http://wiki.wireshark.org/CaptureSetup"
266 "Wireless (Wi-Fi/WLAN):\n"
267 "Try to switch off promiscuous mode in the Capture Options!"
270 simple_dialog_primary_start(), simple_dialog_primary_end(),
271 (cf_is_tempfile(capture_opts->cf)) ? "temporary " : "");
272 cf_close(capture_opts->cf);
278 /* capture child tells us we have a new (or the first) capture file */
280 capture_input_new_file(capture_options *capture_opts, gchar *new_file)
282 gboolean is_tempfile;
286 if(capture_opts->state == CAPTURE_PREPARING) {
287 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture started!");
289 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "File: \"%s\"", new_file);
291 g_assert(capture_opts->state == CAPTURE_PREPARING || capture_opts->state == CAPTURE_RUNNING);
293 /* free the old filename */
294 if(capture_opts->save_file != NULL) {
295 /* we start a new capture file, close the old one (if we had one before) */
296 /* (we can only have an open capture file in real_time_mode!) */
297 if( ((capture_file *) capture_opts->cf)->state != FILE_CLOSED) {
298 cf_callback_invoke(cf_cb_live_capture_update_finished, capture_opts->cf);
299 cf_finish_tail(capture_opts->cf, &err);
300 cf_close(capture_opts->cf);
302 g_free(capture_opts->save_file);
304 cf_set_tempfile(capture_opts->cf, FALSE);
306 /* we didn't had a save_file before, must be a tempfile */
308 cf_set_tempfile(capture_opts->cf, TRUE);
311 /* save the new filename */
312 capture_opts->save_file = g_strdup(new_file);
314 /* if we are in real-time mode, open the new file now */
315 if(capture_opts->real_time_mode) {
316 /* Attempt to open the capture file and set up to read from it. */
317 switch(cf_start_tail(capture_opts->cf, capture_opts->save_file, is_tempfile, &err)) {
321 /* Don't unlink (delete) the save file - leave it around,
322 for debugging purposes. */
323 g_free(capture_opts->save_file);
324 capture_opts->save_file = NULL;
329 if(capture_opts->show_info) {
330 if (!capture_info_new_file(new_file))
334 if(capture_opts->real_time_mode) {
335 cf_callback_invoke(cf_cb_live_capture_update_started, capture_opts);
337 cf_callback_invoke(cf_cb_live_capture_fixed_started, capture_opts);
339 capture_opts->state = CAPTURE_RUNNING;
345 /* capture child tells us we have new packets to read */
347 capture_input_new_packets(capture_options *capture_opts, int to_read)
352 g_assert(capture_opts->save_file);
354 if(capture_opts->real_time_mode) {
355 /* Read from the capture file the number of records the child told us it added. */
356 switch (cf_continue_tail(capture_opts->cf, to_read, &err)) {
360 /* Just because we got an error, that doesn't mean we were unable
361 to read any of the file; we handle what we could get from the
364 XXX - abort on a read error? */
365 cf_callback_invoke(cf_cb_live_capture_update_continue, capture_opts->cf);
368 case CF_READ_ABORTED:
369 /* Kill the child capture process; the user wants to exit, and we
370 shouldn't just leave it running. */
371 capture_kill_child(capture_opts);
375 /* increase capture file packet counter by the number or incoming packets */
376 cf_set_packet_count(capture_opts->cf,
377 cf_get_packet_count(capture_opts->cf) + to_read);
379 cf_callback_invoke(cf_cb_live_capture_fixed_continue, capture_opts->cf);
382 /* update the main window, so we get events (e.g. from the stop toolbar button) */
383 main_window_update();
385 if(capture_opts->show_info)
386 capture_info_new_packets(to_read);
390 /* Capture child told us how many dropped packets it counted.
393 capture_input_drops(capture_options *capture_opts, int dropped)
395 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_INFO, "%d packet%s dropped", dropped, plurality(dropped, "", "s"));
397 g_assert(capture_opts->state == CAPTURE_RUNNING);
399 cf_set_drops_known(capture_opts->cf, TRUE);
400 cf_set_drops(capture_opts->cf, dropped);
404 /* Capture child told us that an error has occurred while starting/running
406 The buffer we're handed has *two* null-terminated strings in it - a
407 primary message and a secondary message, one right after the other.
408 The secondary message might be a null string.
411 capture_input_error_message(capture_options *capture_opts, char *error_msg, char *secondary_error_msg)
413 gchar *safe_error_msg;
414 gchar *safe_secondary_error_msg;
416 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Error message from child: \"%s\", \"%s\"",
417 error_msg, secondary_error_msg);
419 g_assert(capture_opts->state == CAPTURE_PREPARING || capture_opts->state == CAPTURE_RUNNING);
421 safe_error_msg = simple_dialog_format_message(error_msg);
422 if (*secondary_error_msg != '\0') {
423 /* We have both primary and secondary messages. */
424 safe_secondary_error_msg = simple_dialog_format_message(secondary_error_msg);
425 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s%s%s\n\n%s",
426 simple_dialog_primary_start(), safe_error_msg,
427 simple_dialog_primary_end(), safe_secondary_error_msg);
428 g_free(safe_secondary_error_msg);
430 /* We have only a primary message. */
431 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s%s%s",
432 simple_dialog_primary_start(), safe_error_msg,
433 simple_dialog_primary_end());
435 g_free(safe_error_msg);
437 /* the capture child will close the sync_pipe if required, nothing to do for now */
442 /* Capture child told us that an error has occurred while parsing a
443 capture filter when starting/running the capture.
446 capture_input_cfilter_error_message(capture_options *capture_opts, char *error_message)
448 dfilter_t *rfcode = NULL;
449 gchar *safe_cfilter = simple_dialog_format_message(capture_opts->cfilter);
450 gchar *safe_cfilter_error_msg = simple_dialog_format_message(error_message);
452 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture filter error message from child: \"%s\"", error_message);
454 g_assert(capture_opts->state == CAPTURE_PREPARING || capture_opts->state == CAPTURE_RUNNING);
456 /* Did the user try a display filter? */
457 if (dfilter_compile(capture_opts->cfilter, &rfcode) && rfcode != NULL) {
458 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
459 "%sInvalid capture filter: \"%s\"!%s\n"
461 "That string looks like a valid display filter; however, it isn't a valid\n"
462 "capture filter (%s).\n"
464 "Note that display filters and capture filters don't have the same syntax,\n"
465 "so you can't use most display filter expressions as capture filters.\n"
467 "See the User's Guide for a description of the capture filter syntax.",
468 simple_dialog_primary_start(), safe_cfilter,
469 simple_dialog_primary_end(), safe_cfilter_error_msg);
470 dfilter_free(rfcode);
472 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
473 "%sInvalid capture filter: \"%s\"!%s\n"
475 "That string isn't a valid capture filter (%s).\n"
476 "See the User's Guide for a description of the capture filter syntax.",
477 simple_dialog_primary_start(), safe_cfilter,
478 simple_dialog_primary_end(), safe_cfilter_error_msg);
480 g_free(safe_cfilter_error_msg);
481 g_free(safe_cfilter);
483 /* the capture child will close the sync_pipe if required, nothing to do for now */
487 /* capture child closed its side of the pipe, do the required cleanup */
489 capture_input_closed(capture_options *capture_opts)
492 int packet_count_save;
494 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture stopped!");
495 g_assert(capture_opts->state == CAPTURE_PREPARING || capture_opts->state == CAPTURE_RUNNING);
497 /* if we didn't started the capture, do a fake start */
498 /* (happens if we got an error message - we won't get a filename then) */
499 if(capture_opts->state == CAPTURE_PREPARING) {
500 if(capture_opts->real_time_mode) {
501 cf_callback_invoke(cf_cb_live_capture_update_started, capture_opts);
503 cf_callback_invoke(cf_cb_live_capture_fixed_started, capture_opts);
507 if(capture_opts->real_time_mode) {
508 cf_read_status_t status;
510 /* Read what remains of the capture file. */
511 status = cf_finish_tail(capture_opts->cf, &err);
513 /* XXX: If -Q (quit-after-cap) then cf->count clr'd below so save it first */
514 packet_count_save = cf_get_packet_count(capture_opts->cf);
515 /* Tell the GUI, we are not doing a capture any more.
516 Must be done after the cf_finish_tail(), so file lengths are displayed
518 cf_callback_invoke(cf_cb_live_capture_update_finished, capture_opts->cf);
520 /* Finish the capture. */
524 if ((packet_count_save == 0) && !capture_opts->restart) {
525 simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
526 "%sNo packets captured!%s\n"
528 "As no data was captured, closing the %scapture file!\n"
531 "Help about capturing can be found at:\n"
533 " http://wiki.wireshark.org/CaptureSetup"
536 "Wireless (Wi-Fi/WLAN):\n"
537 "Try to switch off promiscuous mode in the Capture Options!"
540 simple_dialog_primary_start(), simple_dialog_primary_end(),
541 cf_is_tempfile(capture_opts->cf) ? "temporary " : "");
542 cf_close(capture_opts->cf);
546 /* Just because we got an error, that doesn't mean we were unable
547 to read any of the file; we handle what we could get from the
551 case CF_READ_ABORTED:
552 /* Exit by leaving the main loop, so that any quit functions
553 we registered get called. */
558 /* first of all, we are not doing a capture any more */
559 cf_callback_invoke(cf_cb_live_capture_fixed_finished, capture_opts->cf);
561 /* this is a normal mode capture and if no error happened, read in the capture file data */
562 if(capture_opts->save_file != NULL) {
563 capture_input_read_all(capture_opts, cf_is_tempfile(capture_opts->cf),
564 cf_get_drops_known(capture_opts->cf), cf_get_drops(capture_opts->cf));
568 if(capture_opts->show_info)
569 capture_info_close();
571 capture_opts->state = CAPTURE_STOPPED;
573 /* if we couldn't open a capture file, there's nothing more for us to do */
574 if(capture_opts->save_file == NULL) {
575 cf_close(capture_opts->cf);
579 /* does the user wants to restart the current capture? */
580 if(capture_opts->restart) {
581 capture_opts->restart = FALSE;
583 eth_unlink(capture_opts->save_file);
585 /* if it was a tempfile, throw away the old filename (so it will become a tempfile again) */
586 if(cf_is_tempfile(capture_opts->cf)) {
587 g_free(capture_opts->save_file);
588 capture_opts->save_file = NULL;
591 /* ... and start the capture again */
592 capture_start(capture_opts);
594 /* We're not doing a capture any more, so we don't have a save file. */
595 g_free(capture_opts->save_file);
596 capture_opts->save_file = NULL;
601 * Fetch the interface list from a child process (dumpcap).
603 * @return A GList containing if_info_t structs if successful, NULL otherwise.
606 /* XXX - We parse simple text output to get our interface list. Should
607 * we use "real" data serialization instead, e.g. via XML? */
609 capture_interface_list(int *err, char **err_str)
611 GList *if_list = NULL;
614 gchar **raw_list, **if_parts, **addr_parts;
619 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Interface List ...");
621 /* Try to get our interface list */
622 *err = sync_interface_list_open(&msg);
624 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Interface List failed!");
636 /* Split our lines */
637 raw_list = g_strsplit(msg, "\n", 0);
640 for (i = 0; raw_list[i] != NULL; i++) {
641 if_parts = g_strsplit(raw_list[i], "\t", 4);
642 if (if_parts[0] == NULL || if_parts[1] == NULL || if_parts[2] == NULL ||
643 if_parts[3] == NULL) {
644 g_strfreev(if_parts);
648 /* Number followed by the name, e.g "1. eth0" */
649 name = strchr(if_parts[0], ' ');
653 g_strfreev(if_parts);
657 if_info = g_malloc0(sizeof(if_info_t));
658 if_info->name = g_strdup(name);
659 if (strlen(if_parts[1]) > 0)
660 if_info->description = g_strdup(if_parts[1]);
661 addr_parts = g_strsplit(if_parts[2], ",", 0);
662 for (j = 0; addr_parts[j] != NULL; j++) {
663 if_addr = g_malloc0(sizeof(if_addr_t));
664 if (inet_pton(AF_INET, addr_parts[j], &if_addr->ip_addr.ip4_addr)) {
665 if_addr->type = AT_IPv4;
666 } else if (inet_pton(AF_INET6, addr_parts[j],
667 &if_addr->ip_addr.ip6_addr)) {
668 if_addr->type = AT_IPv6;
674 if_info->ip_addr = g_slist_append(if_info->ip_addr, if_addr);
677 if (strcmp(if_parts[3], "loopback") == 0)
678 if_info->loopback = TRUE;
679 g_strfreev(if_parts);
680 g_strfreev(addr_parts);
681 if_list = g_list_append(if_list, if_info);
683 g_strfreev(raw_list);
685 /* Check to see if we built a list */
686 if (if_list == NULL) {
687 if (err_str && *err_str)
688 *err_str = g_strdup("No interfaces found");
689 *err = NO_INTERFACES_FOUND;
694 /* XXX - We parse simple text output to get our interface list. Should
695 * we use "real" data serialization instead, e.g. via XML? */
697 capture_pcap_linktype_list(const gchar *ifname, char **err_str)
699 GList *linktype_list = NULL;
702 gchar **raw_list, **lt_parts;
703 data_link_info_t *data_link_info;
705 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Interface List ...");
707 /* Try to get our interface list */
708 err = sync_linktype_list_open(ifname, &msg);
710 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Interface List failed!");
719 /* Split our lines */
720 raw_list = g_strsplit(msg, "\n", 0);
723 for (i = 0; raw_list[i] != NULL; i++) {
724 /* ...and what if the interface name has a tab in it, Mr. Clever Programmer? */
725 lt_parts = g_strsplit(raw_list[i], "\t", 3);
726 if (lt_parts[0] == NULL || lt_parts[1] == NULL || lt_parts[2] == NULL) {
727 g_strfreev(lt_parts);
731 data_link_info = g_malloc(sizeof (data_link_info_t));
732 data_link_info->dlt = (int) strtol(lt_parts[0], NULL, 10);
733 data_link_info->name = g_strdup(lt_parts[1]);
734 if (strcmp(lt_parts[2], "(not supported)") != 0)
735 data_link_info->description = g_strdup(lt_parts[2]);
737 data_link_info->description = NULL;
739 linktype_list = g_list_append(linktype_list, data_link_info);
741 g_strfreev(raw_list);
743 /* Check to see if we built a list */
744 if (linktype_list == NULL) {
748 return linktype_list;
752 capture_stat_start(GList *if_list) {
753 int stat_fd, fork_child;
755 if_stat_cache_t *sc = NULL;
758 if_stat_cache_item_t *sc_item;
760 /* Fire up dumpcap. */
762 * XXX - on systems with BPF, the number of BPF devices limits the
763 * number of devices on which you can capture simultaneously.
767 * 1) this might fail if you run out of BPF devices
771 * 2) opening every interface could leave too few BPF devices
772 * for *other* programs.
774 * It also means the system could end up getting a lot of traffic
775 * that it has to pass through the networking stack and capture
776 * mechanism, so opening all the devices and presenting packet
777 * counts might not always be a good idea.
779 if (sync_interface_stats_open(&stat_fd, &fork_child, &msg) == 0) {
780 sc = g_malloc(sizeof(if_stat_cache_t));
781 sc->stat_fd = stat_fd;
782 sc->fork_child = fork_child;
783 sc->cache_list = NULL;
785 /* Initialize the cache */
786 for (if_entry = if_list; if_entry != NULL; if_entry = g_list_next(if_entry)) {
787 if_info = if_entry->data;
788 sc_item = g_malloc0(sizeof(if_stat_cache_item_t));
789 sc_item->name = g_strdup(if_info->name);
790 sc->cache_list = g_list_append(sc->cache_list, sc_item);
796 #define MAX_STAT_LINE_LEN 500
799 capture_stat_cache_update(if_stat_cache_t *sc) {
800 gchar stat_line[MAX_STAT_LINE_LEN];
803 if_stat_cache_item_t *sc_item;
808 while (sync_pipe_gets_nonblock(sc->stat_fd, stat_line, MAX_STAT_LINE_LEN) > 0) {
809 g_strstrip(stat_line);
810 stat_parts = g_strsplit(stat_line, "\t", 3);
811 if (stat_parts[0] == NULL || stat_parts[1] == NULL ||
812 stat_parts[2] == NULL) {
813 g_strfreev(stat_parts);
816 for (sc_entry = sc->cache_list; sc_entry != NULL; sc_entry = g_list_next(sc_entry)) {
817 sc_item = sc_entry->data;
818 if (strcmp(sc_item->name, stat_parts[0]) == 0) {
819 sc_item->ps.ps_recv = (u_int) strtoul(stat_parts[1], NULL, 10);
820 sc_item->ps.ps_drop = (u_int) strtoul(stat_parts[2], NULL, 10);
823 g_strfreev(stat_parts);
828 capture_stats(if_stat_cache_t *sc, char *ifname, struct pcap_stat *ps) {
830 if_stat_cache_item_t *sc_item;
832 if (!sc || !ifname || !ps) {
836 capture_stat_cache_update(sc);
837 for (sc_entry = sc->cache_list; sc_entry != NULL; sc_entry = g_list_next(sc_entry)) {
838 sc_item = sc_entry->data;
839 if (strcmp(sc_item->name, ifname) == 0) {
840 memcpy(ps, &sc_item->ps, sizeof(struct pcap_stat));
848 capture_stat_stop(if_stat_cache_t *sc) {
850 if_stat_cache_item_t *sc_item;
856 sync_interface_stats_close(&sc->stat_fd, &sc->fork_child, &msg);
858 for (sc_entry = sc->cache_list; sc_entry != NULL; sc_entry = g_list_next(sc_entry)) {
859 sc_item = sc_entry->data;
860 g_free(sc_item->name);
866 #endif /* HAVE_LIBPCAP */