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>
78 #include <epan/ws_strsplit.h>
81 #include "capture_sync.h"
82 #include "capture_info.h"
83 #include "capture_ui_utils.h"
85 #include "capture-pcap-util.h"
86 #include "alert_box.h"
87 #include "simple_dialog.h"
88 #include <epan/prefs.h>
91 #include "capture-wpcap.h"
94 #include "file_util.h"
97 typedef struct if_stat_cache_item_s {
100 } if_stat_cache_item_t;
102 struct if_stat_cache_s {
105 GList *cache_list; /* List of if_stat_chache_entry_t */
111 * @return TRUE if the capture starts successfully, FALSE otherwise.
114 capture_start(capture_options *capture_opts)
119 /* close the currently loaded capture file */
120 cf_close(capture_opts->cf);
122 g_assert(capture_opts->state == CAPTURE_STOPPED);
123 capture_opts->state = CAPTURE_PREPARING;
125 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Start ...");
127 /* try to start the capture child process */
128 ret = sync_pipe_start(capture_opts);
130 if(capture_opts->save_file != NULL) {
131 g_free(capture_opts->save_file);
132 capture_opts->save_file = NULL;
135 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Start failed!");
136 capture_opts->state = CAPTURE_STOPPED;
138 /* the capture child might not respond shortly after bringing it up */
139 /* (especially it will block, if no input coming from an input capture pipe (e.g. mkfifo) is coming in) */
141 /* to prevent problems, bring the main GUI into "capture mode" right after successfully */
142 /* spawn/exec the capture child, without waiting for any response from it */
143 cf_callback_invoke(cf_cb_live_capture_prepared, capture_opts);
145 if(capture_opts->show_info)
146 capture_info_open(capture_opts->iface);
154 capture_stop(capture_options *capture_opts)
156 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Stop ...");
158 cf_callback_invoke(cf_cb_live_capture_stopping, capture_opts);
160 /* stop the capture child gracefully */
161 sync_pipe_stop(capture_opts);
166 capture_restart(capture_options *capture_opts)
168 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Restart");
170 capture_opts->restart = TRUE;
171 capture_stop(capture_opts);
176 capture_kill_child(capture_options *capture_opts)
178 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_INFO, "Capture Kill");
180 /* kill the capture child */
181 sync_pipe_kill(capture_opts->fork_child);
186 /* We've succeeded a (non real-time) capture, try to read it into a new capture file */
188 capture_input_read_all(capture_options *capture_opts, gboolean is_tempfile, gboolean drops_known,
194 /* Capture succeeded; attempt to open the capture file. */
195 if (cf_open(capture_opts->cf, capture_opts->save_file, is_tempfile, &err) != CF_OK) {
196 /* We're not doing a capture any more, so we don't have a save
201 /* Set the read filter to NULL. */
202 /* XXX - this is odd here, try to put it somewhere, where it fits better */
203 cf_set_rfcode(capture_opts->cf, NULL);
205 /* Get the packet-drop statistics.
207 XXX - there are currently no packet-drop statistics stored
208 in libpcap captures, and that's what we're reading.
210 At some point, we will add support in Wiretap to return
211 packet-drop statistics for capture file formats that store it,
212 and will make "cf_read()" get those statistics from Wiretap.
213 We clear the statistics (marking them as "not known") in
214 "cf_open()", and "cf_read()" will only fetch them and mark
215 them as known if Wiretap supplies them, so if we get the
216 statistics now, after calling "cf_open()" but before calling
217 "cf_read()", the values we store will be used by "cf_read()".
219 If a future libpcap capture file format stores the statistics,
220 we'll put them into the capture file that we write, and will
221 thus not have to set them here - "cf_read()" will get them from
222 the file and use them. */
224 cf_set_drops_known(capture_opts->cf, TRUE);
226 /* XXX - on some systems, libpcap doesn't bother filling in
227 "ps_ifdrop" - it doesn't even set it to zero - so we don't
228 bother looking at it.
230 Ideally, libpcap would have an interface that gave us
231 several statistics - perhaps including various interface
232 error statistics - and would tell us which of them it
233 supplies, allowing us to display only the ones it does. */
234 cf_set_drops(capture_opts->cf, drops);
237 /* read in the packet data */
238 switch (cf_read(capture_opts->cf)) {
242 /* Just because we got an error, that doesn't mean we were unable
243 to read any of the file; we handle what we could get from the
247 case CF_READ_ABORTED:
248 /* User wants to quit program. Exit by leaving the main loop,
249 so that any quit functions we registered get called. */
250 main_window_nested_quit();
254 /* if we didn't captured even a single packet, close the file again */
255 if(cf_get_packet_count(capture_opts->cf) == 0 && !capture_opts->restart) {
256 simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
257 "%sNo packets captured!%s\n"
259 "As no data was captured, closing the %scapture file!\n"
262 "Help about capturing can be found at:\n"
264 " http://wiki.wireshark.org/CaptureSetup"
267 "Wireless (Wi-Fi/WLAN):\n"
268 "Try to switch off promiscuous mode in the Capture Options!"
271 simple_dialog_primary_start(), simple_dialog_primary_end(),
272 (cf_is_tempfile(capture_opts->cf)) ? "temporary " : "");
273 cf_close(capture_opts->cf);
279 /* capture child tells us we have a new (or the first) capture file */
281 capture_input_new_file(capture_options *capture_opts, gchar *new_file)
283 gboolean is_tempfile;
287 if(capture_opts->state == CAPTURE_PREPARING) {
288 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture started!");
290 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "File: \"%s\"", new_file);
292 g_assert(capture_opts->state == CAPTURE_PREPARING || capture_opts->state == CAPTURE_RUNNING);
294 /* free the old filename */
295 if(capture_opts->save_file != NULL) {
296 /* we start a new capture file, close the old one (if we had one before) */
297 /* (we can only have an open capture file in real_time_mode!) */
298 if( ((capture_file *) capture_opts->cf)->state != FILE_CLOSED) {
299 cf_callback_invoke(cf_cb_live_capture_update_finished, capture_opts->cf);
300 cf_finish_tail(capture_opts->cf, &err);
301 cf_close(capture_opts->cf);
303 g_free(capture_opts->save_file);
305 cf_set_tempfile(capture_opts->cf, FALSE);
307 /* we didn't had a save_file before, must be a tempfile */
309 cf_set_tempfile(capture_opts->cf, TRUE);
312 /* save the new filename */
313 capture_opts->save_file = g_strdup(new_file);
315 /* if we are in real-time mode, open the new file now */
316 if(capture_opts->real_time_mode) {
317 /* Attempt to open the capture file and set up to read from it. */
318 switch(cf_start_tail(capture_opts->cf, capture_opts->save_file, is_tempfile, &err)) {
322 /* Don't unlink (delete) the save file - leave it around,
323 for debugging purposes. */
324 g_free(capture_opts->save_file);
325 capture_opts->save_file = NULL;
330 if(capture_opts->show_info) {
331 if (!capture_info_new_file(new_file))
335 if(capture_opts->real_time_mode) {
336 cf_callback_invoke(cf_cb_live_capture_update_started, capture_opts);
338 cf_callback_invoke(cf_cb_live_capture_fixed_started, capture_opts);
340 capture_opts->state = CAPTURE_RUNNING;
346 /* capture child tells us we have new packets to read */
348 capture_input_new_packets(capture_options *capture_opts, int to_read)
353 g_assert(capture_opts->save_file);
355 if(capture_opts->real_time_mode) {
356 /* Read from the capture file the number of records the child told us it added. */
357 switch (cf_continue_tail(capture_opts->cf, to_read, &err)) {
361 /* Just because we got an error, that doesn't mean we were unable
362 to read any of the file; we handle what we could get from the
365 XXX - abort on a read error? */
366 cf_callback_invoke(cf_cb_live_capture_update_continue, capture_opts->cf);
369 case CF_READ_ABORTED:
370 /* Kill the child capture process; the user wants to exit, and we
371 shouldn't just leave it running. */
372 capture_kill_child(capture_opts);
376 /* increase capture file packet counter by the number or incoming packets */
377 cf_set_packet_count(capture_opts->cf,
378 cf_get_packet_count(capture_opts->cf) + to_read);
380 cf_callback_invoke(cf_cb_live_capture_fixed_continue, capture_opts->cf);
383 /* update the main window, so we get events (e.g. from the stop toolbar button) */
384 main_window_update();
386 if(capture_opts->show_info)
387 capture_info_new_packets(to_read);
391 /* Capture child told us how many dropped packets it counted.
394 capture_input_drops(capture_options *capture_opts, int dropped)
396 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_INFO, "%d packet%s dropped", dropped, plurality(dropped, "", "s"));
398 g_assert(capture_opts->state == CAPTURE_RUNNING);
400 cf_set_drops_known(capture_opts->cf, TRUE);
401 cf_set_drops(capture_opts->cf, dropped);
405 /* Capture child told us that an error has occurred while starting/running
407 The buffer we're handed has *two* null-terminated strings in it - a
408 primary message and a secondary message, one right after the other.
409 The secondary message might be a null string.
412 capture_input_error_message(capture_options *capture_opts, char *error_msg, char *secondary_error_msg)
414 gchar *safe_error_msg;
415 gchar *safe_secondary_error_msg;
417 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Error message from child: \"%s\", \"%s\"",
418 error_msg, secondary_error_msg);
420 g_assert(capture_opts->state == CAPTURE_PREPARING || capture_opts->state == CAPTURE_RUNNING);
422 safe_error_msg = simple_dialog_format_message(error_msg);
423 if (*secondary_error_msg != '\0') {
424 /* We have both primary and secondary messages. */
425 safe_secondary_error_msg = simple_dialog_format_message(secondary_error_msg);
426 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s%s%s\n\n%s",
427 simple_dialog_primary_start(), safe_error_msg,
428 simple_dialog_primary_end(), safe_secondary_error_msg);
429 g_free(safe_secondary_error_msg);
431 /* We have only a primary message. */
432 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s%s%s",
433 simple_dialog_primary_start(), safe_error_msg,
434 simple_dialog_primary_end());
436 g_free(safe_error_msg);
438 /* the capture child will close the sync_pipe if required, nothing to do for now */
443 /* Capture child told us that an error has occurred while parsing a
444 capture filter when starting/running the capture.
447 capture_input_cfilter_error_message(capture_options *capture_opts, char *error_message)
449 dfilter_t *rfcode = NULL;
450 gchar *safe_cfilter = simple_dialog_format_message(capture_opts->cfilter);
451 gchar *safe_cfilter_error_msg = simple_dialog_format_message(error_message);
453 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture filter error message from child: \"%s\"", error_message);
455 g_assert(capture_opts->state == CAPTURE_PREPARING || capture_opts->state == CAPTURE_RUNNING);
457 /* Did the user try a display filter? */
458 if (dfilter_compile(capture_opts->cfilter, &rfcode) && rfcode != NULL) {
459 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
460 "%sInvalid capture filter: \"%s\"!%s\n"
462 "That string looks like a valid display filter; however, it isn't a valid\n"
463 "capture filter (%s).\n"
465 "Note that display filters and capture filters don't have the same syntax,\n"
466 "so you can't use most display filter expressions as capture filters.\n"
468 "See the User's Guide for a description of the capture filter syntax.",
469 simple_dialog_primary_start(), safe_cfilter,
470 simple_dialog_primary_end(), safe_cfilter_error_msg);
471 dfilter_free(rfcode);
473 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
474 "%sInvalid capture filter: \"%s\"!%s\n"
476 "That string isn't a valid capture filter (%s).\n"
477 "See the User's Guide for a description of the capture filter syntax.",
478 simple_dialog_primary_start(), safe_cfilter,
479 simple_dialog_primary_end(), safe_cfilter_error_msg);
481 g_free(safe_cfilter_error_msg);
482 g_free(safe_cfilter);
484 /* the capture child will close the sync_pipe if required, nothing to do for now */
488 /* capture child closed its side of the pipe, do the required cleanup */
490 capture_input_closed(capture_options *capture_opts)
493 int packet_count_save;
495 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture stopped!");
496 g_assert(capture_opts->state == CAPTURE_PREPARING || capture_opts->state == CAPTURE_RUNNING);
498 /* if we didn't started the capture, do a fake start */
499 /* (happens if we got an error message - we won't get a filename then) */
500 if(capture_opts->state == CAPTURE_PREPARING) {
501 if(capture_opts->real_time_mode) {
502 cf_callback_invoke(cf_cb_live_capture_update_started, capture_opts);
504 cf_callback_invoke(cf_cb_live_capture_fixed_started, capture_opts);
508 if(capture_opts->real_time_mode) {
509 cf_read_status_t status;
511 /* Read what remains of the capture file. */
512 status = cf_finish_tail(capture_opts->cf, &err);
514 /* XXX: If -Q (quit-after-cap) then cf->count clr'd below so save it first */
515 packet_count_save = cf_get_packet_count(capture_opts->cf);
516 /* Tell the GUI, we are not doing a capture any more.
517 Must be done after the cf_finish_tail(), so file lengths are displayed
519 cf_callback_invoke(cf_cb_live_capture_update_finished, capture_opts->cf);
521 /* Finish the capture. */
525 if ((packet_count_save == 0) && !capture_opts->restart) {
526 simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
527 "%sNo packets captured!%s\n"
529 "As no data was captured, closing the %scapture file!\n"
532 "Help about capturing can be found at:\n"
534 " http://wiki.wireshark.org/CaptureSetup"
537 "Wireless (Wi-Fi/WLAN):\n"
538 "Try to switch off promiscuous mode in the Capture Options!"
541 simple_dialog_primary_start(), simple_dialog_primary_end(),
542 cf_is_tempfile(capture_opts->cf) ? "temporary " : "");
543 cf_close(capture_opts->cf);
547 /* Just because we got an error, that doesn't mean we were unable
548 to read any of the file; we handle what we could get from the
552 case CF_READ_ABORTED:
553 /* Exit by leaving the main loop, so that any quit functions
554 we registered get called. */
559 /* first of all, we are not doing a capture any more */
560 cf_callback_invoke(cf_cb_live_capture_fixed_finished, capture_opts->cf);
562 /* this is a normal mode capture and if no error happened, read in the capture file data */
563 if(capture_opts->save_file != NULL) {
564 capture_input_read_all(capture_opts, cf_is_tempfile(capture_opts->cf),
565 cf_get_drops_known(capture_opts->cf), cf_get_drops(capture_opts->cf));
569 if(capture_opts->show_info)
570 capture_info_close();
572 capture_opts->state = CAPTURE_STOPPED;
574 /* if we couldn't open a capture file, there's nothing more for us to do */
575 if(capture_opts->save_file == NULL) {
576 cf_close(capture_opts->cf);
580 /* does the user wants to restart the current capture? */
581 if(capture_opts->restart) {
582 capture_opts->restart = FALSE;
584 eth_unlink(capture_opts->save_file);
586 /* if it was a tempfile, throw away the old filename (so it will become a tempfile again) */
587 if(cf_is_tempfile(capture_opts->cf)) {
588 g_free(capture_opts->save_file);
589 capture_opts->save_file = NULL;
592 /* ... and start the capture again */
593 capture_start(capture_opts);
595 /* We're not doing a capture any more, so we don't have a save file. */
596 g_free(capture_opts->save_file);
597 capture_opts->save_file = NULL;
602 * Fetch the interface list from a child process (dumpcap).
604 * @return A GList containing if_info_t structs if successful, NULL otherwise.
607 /* XXX - We parse simple text output to get our interface list. Should
608 * we use "real" data serialization instead, e.g. via XML? */
610 capture_interface_list(int *err, char **err_str)
612 GList *if_list = NULL;
615 gchar **raw_list, **if_parts, **addr_parts;
620 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Interface List ...");
622 /* Try to get our interface list */
623 *err = sync_interface_list_open(&msg);
625 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Interface List failed!");
637 /* Split our lines */
638 raw_list = g_strsplit(msg, "\n", 0);
641 for (i = 0; raw_list[i] != NULL; i++) {
642 if_parts = g_strsplit(raw_list[i], "\t", 4);
643 if (if_parts[0] == NULL || if_parts[1] == NULL || if_parts[2] == NULL ||
644 if_parts[3] == NULL) {
645 g_strfreev(if_parts);
649 /* Number followed by the name, e.g "1. eth0" */
650 name = strchr(if_parts[0], ' ');
654 g_strfreev(if_parts);
658 if_info = g_malloc0(sizeof(if_info_t));
659 if_info->name = g_strdup(name);
660 if (strlen(if_parts[1]) > 0)
661 if_info->description = g_strdup(if_parts[1]);
662 addr_parts = g_strsplit(if_parts[2], ",", 0);
663 for (j = 0; addr_parts[j] != NULL; j++) {
664 if_addr = g_malloc0(sizeof(if_addr_t));
665 if (inet_pton(AF_INET, addr_parts[j], &if_addr->ip_addr.ip4_addr)) {
666 if_addr->type = AT_IPv4;
667 } else if (inet_pton(AF_INET6, addr_parts[j],
668 &if_addr->ip_addr.ip6_addr)) {
669 if_addr->type = AT_IPv6;
675 if_info->ip_addr = g_slist_append(if_info->ip_addr, if_addr);
678 if (strcmp(if_parts[3], "loopback") == 0)
679 if_info->loopback = TRUE;
680 g_strfreev(if_parts);
681 g_strfreev(addr_parts);
682 if_list = g_list_append(if_list, if_info);
684 g_strfreev(raw_list);
686 /* Check to see if we built a list */
687 if (if_list == NULL) {
688 if (err_str && *err_str)
689 *err_str = g_strdup("No interfaces found");
690 *err = NO_INTERFACES_FOUND;
695 /* XXX - We parse simple text output to get our interface list. Should
696 * we use "real" data serialization instead, e.g. via XML? */
698 capture_pcap_linktype_list(const gchar *ifname, char **err_str)
700 GList *linktype_list = NULL;
703 gchar **raw_list, **lt_parts;
704 data_link_info_t *data_link_info;
706 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Interface List ...");
708 /* Try to get our interface list */
709 err = sync_linktype_list_open(ifname, &msg);
711 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Interface List failed!");
720 /* Split our lines */
721 raw_list = g_strsplit(msg, "\n", 0);
724 for (i = 0; raw_list[i] != NULL; i++) {
725 /* ...and what if the interface name has a tab in it, Mr. Clever Programmer? */
726 lt_parts = g_strsplit(raw_list[i], "\t", 3);
727 if (lt_parts[0] == NULL || lt_parts[1] == NULL || lt_parts[2] == NULL) {
728 g_strfreev(lt_parts);
732 data_link_info = g_malloc(sizeof (data_link_info_t));
733 data_link_info->dlt = (int) strtol(lt_parts[0], NULL, 10);
734 data_link_info->name = g_strdup(lt_parts[1]);
735 if (strcmp(lt_parts[2], "(not supported)") != 0)
736 data_link_info->description = g_strdup(lt_parts[2]);
738 data_link_info->description = NULL;
740 linktype_list = g_list_append(linktype_list, data_link_info);
742 g_strfreev(raw_list);
744 /* Check to see if we built a list */
745 if (linktype_list == NULL) {
749 return linktype_list;
753 capture_stat_start(GList *if_list) {
754 int stat_fd, fork_child;
756 if_stat_cache_t *sc = NULL;
759 if_stat_cache_item_t *sc_item;
761 /* Fire up dumpcap. */
763 * XXX - on systems with BPF, the number of BPF devices limits the
764 * number of devices on which you can capture simultaneously.
768 * 1) this might fail if you run out of BPF devices
772 * 2) opening every interface could leave too few BPF devices
773 * for *other* programs.
775 * It also means the system could end up getting a lot of traffic
776 * that it has to pass through the networking stack and capture
777 * mechanism, so opening all the devices and presenting packet
778 * counts might not always be a good idea.
780 if (sync_interface_stats_open(&stat_fd, &fork_child, &msg) == 0) {
781 sc = g_malloc(sizeof(if_stat_cache_t));
782 sc->stat_fd = stat_fd;
783 sc->fork_child = fork_child;
784 sc->cache_list = NULL;
786 /* Initialize the cache */
787 for (if_entry = if_list; if_entry != NULL; if_entry = g_list_next(if_entry)) {
788 if_info = if_entry->data;
789 sc_item = g_malloc0(sizeof(if_stat_cache_item_t));
790 sc_item->name = g_strdup(if_info->name);
791 sc->cache_list = g_list_append(sc->cache_list, sc_item);
797 #define MAX_STAT_LINE_LEN 500
800 capture_stat_cache_update(if_stat_cache_t *sc) {
801 gchar stat_line[MAX_STAT_LINE_LEN];
804 if_stat_cache_item_t *sc_item;
809 while (sync_pipe_gets_nonblock(sc->stat_fd, stat_line, MAX_STAT_LINE_LEN) > 0) {
810 g_strstrip(stat_line);
811 stat_parts = g_strsplit(stat_line, "\t", 3);
812 if (stat_parts[0] == NULL || stat_parts[1] == NULL ||
813 stat_parts[2] == NULL) {
814 g_strfreev(stat_parts);
817 for (sc_entry = sc->cache_list; sc_entry != NULL; sc_entry = g_list_next(sc_entry)) {
818 sc_item = sc_entry->data;
819 if (strcmp(sc_item->name, stat_parts[0]) == 0) {
820 sc_item->ps.ps_recv = (u_int) strtoul(stat_parts[1], NULL, 10);
821 sc_item->ps.ps_drop = (u_int) strtoul(stat_parts[2], NULL, 10);
824 g_strfreev(stat_parts);
829 capture_stats(if_stat_cache_t *sc, char *ifname, struct pcap_stat *ps) {
831 if_stat_cache_item_t *sc_item;
833 if (!sc || !ifname || !ps) {
837 capture_stat_cache_update(sc);
838 for (sc_entry = sc->cache_list; sc_entry != NULL; sc_entry = g_list_next(sc_entry)) {
839 sc_item = sc_entry->data;
840 if (strcmp(sc_item->name, ifname) == 0) {
841 memcpy(ps, &sc_item->ps, sizeof(struct pcap_stat));
849 capture_stat_stop(if_stat_cache_t *sc) {
851 if_stat_cache_item_t *sc_item;
857 sync_interface_stats_close(&sc->stat_fd, &sc->fork_child, &msg);
859 for (sc_entry = sc->cache_list; sc_entry != NULL; sc_entry = g_list_next(sc_entry)) {
860 sc_item = sc_entry->data;
861 g_free(sc_item->name);
867 #endif /* HAVE_LIBPCAP */