In Wireshark and TShark, run dumpcap to get interface lists and lists of
[obnox/wireshark/wip.git] / capture.c
1 /* capture.c
2  * Routines for packet capture
3  *
4  * $Id$
5  *
6  * Wireshark - Network traffic analyzer
7  * By Gerald Combs <gerald@wireshark.org>
8  * Copyright 1998 Gerald Combs
9  *
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.
14  *
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.
19  *
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.
23  */
24
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
28
29 #ifdef HAVE_LIBPCAP
30
31 #ifdef HAVE_UNISTD_H
32 #include <unistd.h>
33 #endif
34
35 #include <stdio.h>
36 #include <string.h>
37
38 #include <glib.h>
39
40 #include <epan/packet.h>
41 #include <epan/dfilter/dfilter.h>
42 #include "file.h"
43 #include "capture.h"
44 #include "capture_ifinfo.h"
45 #include "capture_sync.h"
46 #include "capture_info.h"
47 #include "capture_ui_utils.h"
48 #include "util.h"
49 #include "capture-pcap-util.h"
50 #include "simple_dialog.h"
51 #include <epan/prefs.h>
52
53 #ifdef _WIN32
54 #include "capture-wpcap.h"
55 #endif
56 #include "ui_util.h"
57 #include "wsutil/file_util.h"
58 #include "log.h"
59
60 typedef struct if_stat_cache_item_s {
61     char *name;
62     struct pcap_stat ps;
63 } if_stat_cache_item_t;
64
65 struct if_stat_cache_s {
66     int stat_fd;
67     int fork_child;
68     GList *cache_list;  /* List of if_stat_chache_entry_t */
69 };
70
71 /* this callback mechanism should possibly be replaced by the g_signal_...() stuff (if I only would know how :-) */
72 typedef struct {
73     capture_callback_t cb_fct;
74     gpointer user_data;
75 } capture_callback_data_t;
76
77 static GList *capture_callbacks = NULL;
78
79 static void
80 capture_callback_invoke(int event, capture_options *capture_opts)
81 {
82     capture_callback_data_t *cb;
83     GList *cb_item = capture_callbacks;
84
85     /* there should be at least one interested */
86     g_assert(cb_item != NULL);
87
88     while(cb_item != NULL) {
89         cb = cb_item->data;
90         cb->cb_fct(event, capture_opts, cb->user_data);
91         cb_item = g_list_next(cb_item);
92     }
93 }
94
95
96 void
97 capture_callback_add(capture_callback_t func, gpointer user_data)
98 {
99     capture_callback_data_t *cb;
100
101     cb = g_malloc(sizeof(capture_callback_data_t));
102     cb->cb_fct = func;
103     cb->user_data = user_data;
104
105     capture_callbacks = g_list_append(capture_callbacks, cb);
106 }
107
108 void
109 capture_callback_remove(capture_callback_t func)
110 {
111     capture_callback_data_t *cb;
112     GList *cb_item = capture_callbacks;
113
114     while(cb_item != NULL) {
115         cb = cb_item->data;
116         if(cb->cb_fct == func) {
117             capture_callbacks = g_list_remove(capture_callbacks, cb);
118             g_free(cb);
119             return;
120         }
121         cb_item = g_list_next(cb_item);
122     }
123
124     g_assert_not_reached();
125 }
126
127 /**
128  * Start a capture.
129  *
130  * @return TRUE if the capture starts successfully, FALSE otherwise.
131  */
132 gboolean
133 capture_start(capture_options *capture_opts)
134 {
135   gboolean ret;
136
137
138   /* close the currently loaded capture file */
139   cf_close(capture_opts->cf);
140
141   g_assert(capture_opts->state == CAPTURE_STOPPED);
142   capture_opts->state = CAPTURE_PREPARING;
143
144   g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Start ...");
145
146   /* try to start the capture child process */
147   ret = sync_pipe_start(capture_opts);
148   if(!ret) {
149       if(capture_opts->save_file != NULL) {
150           g_free(capture_opts->save_file);
151           capture_opts->save_file = NULL;
152       }
153
154       g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Start failed!");
155       capture_opts->state = CAPTURE_STOPPED;
156   } else {
157       /* the capture child might not respond shortly after bringing it up */
158       /* (for example: it will block if no input arrives from an input capture pipe (e.g. mkfifo)) */
159
160       /* to prevent problems, bring the main GUI into "capture mode" right after a successful */
161       /* spawn/exec of the capture child, without waiting for any response from it */
162       capture_callback_invoke(capture_cb_capture_prepared, capture_opts);
163
164       if(capture_opts->show_info)
165         capture_info_open(capture_opts);
166   }
167
168   return ret;
169 }
170
171
172 void
173 capture_stop(capture_options *capture_opts)
174 {
175   g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Stop ...");
176
177   capture_callback_invoke(capture_cb_capture_stopping, capture_opts);
178
179   /* stop the capture child gracefully */
180   sync_pipe_stop(capture_opts);
181 }
182
183
184 void
185 capture_restart(capture_options *capture_opts)
186 {
187     g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Restart");
188
189     capture_opts->restart = TRUE;
190     capture_stop(capture_opts);
191 }
192
193
194 void
195 capture_kill_child(capture_options *capture_opts)
196 {
197   g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_INFO, "Capture Kill");
198
199   /* kill the capture child */
200   sync_pipe_kill(capture_opts->fork_child);
201 }
202
203
204
205 /* We've succeeded in doing a (non real-time) capture; try to read it into a new capture file */
206 static gboolean
207 capture_input_read_all(capture_options *capture_opts, gboolean is_tempfile, gboolean drops_known,
208 guint32 drops)
209 {
210   int err;
211
212
213   /* Capture succeeded; attempt to open the capture file. */
214   if (cf_open(capture_opts->cf, capture_opts->save_file, is_tempfile, &err) != CF_OK) {
215     /* We're not doing a capture any more, so we don't have a save file. */
216     return FALSE;
217   }
218
219   /* Set the read filter to NULL. */
220   /* XXX - this is odd here; try to put it somewhere where it fits better */
221   cf_set_rfcode(capture_opts->cf, NULL);
222
223   /* Get the packet-drop statistics.
224
225      XXX - there are currently no packet-drop statistics stored
226      in libpcap captures, and that's what we're reading.
227
228      At some point, we will add support in Wiretap to return
229      packet-drop statistics for capture file formats that store it,
230      and will make "cf_read()" get those statistics from Wiretap.
231      We clear the statistics (marking them as "not known") in
232      "cf_open()", and "cf_read()" will only fetch them and mark
233      them as known if Wiretap supplies them, so if we get the
234      statistics now, after calling "cf_open()" but before calling
235      "cf_read()", the values we store will be used by "cf_read()".
236
237      If a future libpcap capture file format stores the statistics,
238      we'll put them into the capture file that we write, and will
239      thus not have to set them here - "cf_read()" will get them from
240      the file and use them. */
241   if (drops_known) {
242     cf_set_drops_known(capture_opts->cf, TRUE);
243
244     /* XXX - on some systems, libpcap doesn't bother filling in
245        "ps_ifdrop" - it doesn't even set it to zero - so we don't
246        bother looking at it.
247
248        Ideally, libpcap would have an interface that gave us
249        several statistics - perhaps including various interface
250        error statistics - and would tell us which of them it
251        supplies, allowing us to display only the ones it does. */
252     cf_set_drops(capture_opts->cf, drops);
253   }
254
255   /* read in the packet data */
256   switch (cf_read(capture_opts->cf, FALSE)) {
257
258   case CF_READ_OK:
259   case CF_READ_ERROR:
260     /* Just because we got an error, that doesn't mean we were unable
261        to read any of the file; we handle what we could get from the
262        file. */
263     break;
264
265   case CF_READ_ABORTED:
266     /* User wants to quit program. Exit by leaving the main loop,
267        so that any quit functions we registered get called. */
268     main_window_nested_quit();
269     return FALSE;
270   }
271
272   /* if we didn't capture even a single packet, close the file again */
273   if(cf_get_packet_count(capture_opts->cf) == 0 && !capture_opts->restart) {
274     simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
275 "%sNo packets captured!%s\n"
276 "\n"
277 "As no data was captured, closing the %scapture file!\n"
278 "\n"
279 "\n"
280 "Help about capturing can be found at:\n"
281 "\n"
282 "       http://wiki.wireshark.org/CaptureSetup"
283 #ifdef _WIN32
284 "\n\n"
285 "Wireless (Wi-Fi/WLAN):\n"
286 "Try to switch off promiscuous mode in the Capture Options!"
287 #endif
288 "",
289     simple_dialog_primary_start(), simple_dialog_primary_end(),
290     (cf_is_tempfile(capture_opts->cf)) ? "temporary " : "");
291     cf_close(capture_opts->cf);
292   }
293   return TRUE;
294 }
295
296
297 /* capture child tells us we have a new (or the first) capture file */
298 gboolean
299 capture_input_new_file(capture_options *capture_opts, gchar *new_file)
300 {
301   gboolean is_tempfile;
302   int  err;
303
304
305   if(capture_opts->state == CAPTURE_PREPARING) {
306     g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture started!");
307   }
308   g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "File: \"%s\"", new_file);
309
310   g_assert(capture_opts->state == CAPTURE_PREPARING || capture_opts->state == CAPTURE_RUNNING);
311
312   /* free the old filename */
313   if(capture_opts->save_file != NULL) {
314     /* we start a new capture file, close the old one (if we had one before). */
315     /* (we can only have an open capture file in real_time_mode!) */
316     if( ((capture_file *) capture_opts->cf)->state != FILE_CLOSED) {
317         capture_callback_invoke(capture_cb_capture_update_finished, capture_opts);
318         cf_finish_tail(capture_opts->cf, &err);
319         cf_close(capture_opts->cf);
320     }
321     g_free(capture_opts->save_file);
322     is_tempfile = FALSE;
323     cf_set_tempfile(capture_opts->cf, FALSE);
324   } else {
325     /* we didn't have a save_file before; must be a tempfile */
326     is_tempfile = TRUE;
327     cf_set_tempfile(capture_opts->cf, TRUE);
328   }
329
330   /* save the new filename */
331   capture_opts->save_file = g_strdup(new_file);
332
333   /* if we are in real-time mode, open the new file now */
334   if(capture_opts->real_time_mode) {
335     /* Attempt to open the capture file and set up to read from it. */
336     switch(cf_start_tail(capture_opts->cf, capture_opts->save_file, is_tempfile, &err)) {
337     case CF_OK:
338       break;
339     case CF_ERROR:
340       /* Don't unlink (delete) the save file - leave it around,
341          for debugging purposes. */
342       g_free(capture_opts->save_file);
343       capture_opts->save_file = NULL;
344       return FALSE;
345     }
346   }
347
348   if(capture_opts->show_info) {
349     if (!capture_info_new_file(new_file))
350       return FALSE;
351   }
352
353   if(capture_opts->real_time_mode) {
354     capture_callback_invoke(capture_cb_capture_update_started, capture_opts);
355   } else {
356     capture_callback_invoke(capture_cb_capture_fixed_started, capture_opts);
357   }
358   capture_opts->state = CAPTURE_RUNNING;
359
360   return TRUE;
361 }
362
363
364 /* capture child tells us we have new packets to read */
365 void
366 capture_input_new_packets(capture_options *capture_opts, int to_read)
367 {
368   int  err;
369
370
371   g_assert(capture_opts->save_file);
372
373   if(capture_opts->real_time_mode) {
374     /* Read from the capture file the number of records the child told us it added. */
375     switch (cf_continue_tail(capture_opts->cf, to_read, &err)) {
376
377     case CF_READ_OK:
378     case CF_READ_ERROR:
379       /* Just because we got an error, that doesn't mean we were unable
380          to read any of the file; we handle what we could get from the
381          file.
382
383          XXX - abort on a read error? */
384          capture_callback_invoke(capture_cb_capture_update_continue, capture_opts);
385       break;
386
387     case CF_READ_ABORTED:
388       /* Kill the child capture process; the user wants to exit, and we
389          shouldn't just leave it running. */
390       capture_kill_child(capture_opts);
391       break;
392     }
393   } else {
394     /* increase the capture file packet counter by the number of incoming packets */
395     cf_set_packet_count(capture_opts->cf,
396         cf_get_packet_count(capture_opts->cf) + to_read);
397
398     capture_callback_invoke(capture_cb_capture_fixed_continue, capture_opts);
399   }
400
401   /* update the main window so we get events (e.g. from the stop toolbar button) */
402   main_window_update();
403
404   if(capture_opts->show_info)
405     capture_info_new_packets(to_read);
406 }
407
408
409 /* Capture child told us how many dropped packets it counted.
410  */
411 void
412 capture_input_drops(capture_options *capture_opts, guint32 dropped)
413 {
414   g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_INFO, "%u packet%s dropped", dropped, plurality(dropped, "", "s"));
415
416   g_assert(capture_opts->state == CAPTURE_RUNNING);
417
418   cf_set_drops_known(capture_opts->cf, TRUE);
419   cf_set_drops(capture_opts->cf, dropped);
420 }
421
422
423 /* Capture child told us that an error has occurred while starting/running
424    the capture.
425    The buffer we're handed has *two* null-terminated strings in it - a
426    primary message and a secondary message, one right after the other.
427    The secondary message might be a null string.
428  */
429 void
430 capture_input_error_message(capture_options *capture_opts, char *error_msg, char *secondary_error_msg)
431 {
432   gchar *safe_error_msg;
433   gchar *safe_secondary_error_msg;
434
435   g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Error message from child: \"%s\", \"%s\"",
436         error_msg, secondary_error_msg);
437
438   g_assert(capture_opts->state == CAPTURE_PREPARING || capture_opts->state == CAPTURE_RUNNING);
439
440   safe_error_msg = simple_dialog_format_message(error_msg);
441   if (*secondary_error_msg != '\0') {
442     /* We have both primary and secondary messages. */
443     safe_secondary_error_msg = simple_dialog_format_message(secondary_error_msg);
444     simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s%s%s\n\n%s",
445                   simple_dialog_primary_start(), safe_error_msg,
446                   simple_dialog_primary_end(), safe_secondary_error_msg);
447     g_free(safe_secondary_error_msg);
448   } else {
449     /* We have only a primary message. */
450     simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s%s%s",
451                   simple_dialog_primary_start(), safe_error_msg,
452                   simple_dialog_primary_end());
453   }
454   g_free(safe_error_msg);
455
456   /* the capture child will close the sync_pipe if required, nothing to do for now */
457 }
458
459
460
461 /* Capture child told us that an error has occurred while parsing a
462    capture filter when starting/running the capture.
463  */
464 void
465 capture_input_cfilter_error_message(capture_options *capture_opts, char *error_message)
466 {
467   dfilter_t   *rfcode = NULL;
468   gchar *safe_cfilter = simple_dialog_format_message(capture_opts->cfilter);
469   gchar *safe_cfilter_error_msg = simple_dialog_format_message(error_message);
470
471   g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture filter error message from child: \"%s\"", error_message);
472
473   g_assert(capture_opts->state == CAPTURE_PREPARING || capture_opts->state == CAPTURE_RUNNING);
474
475   /* Did the user try a display filter? */
476   if (dfilter_compile(capture_opts->cfilter, &rfcode) && rfcode != NULL) {
477     simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
478       "%sInvalid capture filter: \"%s\"!%s\n"
479       "\n"
480       "That string looks like a valid display filter; however, it isn't a valid\n"
481       "capture filter (%s).\n"
482       "\n"
483       "Note that display filters and capture filters don't have the same syntax,\n"
484       "so you can't use most display filter expressions as capture filters.\n"
485       "\n"
486       "See the User's Guide for a description of the capture filter syntax.",
487       simple_dialog_primary_start(), safe_cfilter,
488       simple_dialog_primary_end(), safe_cfilter_error_msg);
489       dfilter_free(rfcode);
490   } else {
491     simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
492       "%sInvalid capture filter: \"%s\"!%s\n"
493       "\n"
494       "That string isn't a valid capture filter (%s).\n"
495       "See the User's Guide for a description of the capture filter syntax.",
496       simple_dialog_primary_start(), safe_cfilter,
497       simple_dialog_primary_end(), safe_cfilter_error_msg);
498   }
499   g_free(safe_cfilter_error_msg);
500   g_free(safe_cfilter);
501
502   /* the capture child will close the sync_pipe if required, nothing to do for now */
503 }
504
505
506 /* capture child closed its side of the pipe, do the required cleanup */
507 void
508 capture_input_closed(capture_options *capture_opts)
509 {
510     int  err;
511     int  packet_count_save;
512
513     g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture stopped!");
514     g_assert(capture_opts->state == CAPTURE_PREPARING || capture_opts->state == CAPTURE_RUNNING);
515
516     /* if we didn't start the capture, do a fake start. */
517     /* (happens if we got an error message - we won't get a filename then). */
518     if(capture_opts->state == CAPTURE_PREPARING) {
519         if(capture_opts->real_time_mode) {
520             capture_callback_invoke(capture_cb_capture_update_started, capture_opts);
521         } else {
522             capture_callback_invoke(capture_cb_capture_fixed_started, capture_opts);
523         }
524     }
525
526     if(capture_opts->real_time_mode) {
527         cf_read_status_t status;
528
529         /* Read what remains of the capture file. */
530         status = cf_finish_tail(capture_opts->cf, &err);
531
532         /* XXX: If -Q (quit-after-cap) then cf->count clr'd below so save it first */
533         packet_count_save = cf_get_packet_count(capture_opts->cf);
534         /* Tell the GUI we are not doing a capture any more.
535                    Must be done after the cf_finish_tail(), so file lengths are 
536                    correctly displayed */
537         capture_callback_invoke(capture_cb_capture_update_finished, capture_opts);
538
539         /* Finish the capture. */
540         switch (status) {
541
542         case CF_READ_OK:
543             if ((packet_count_save == 0) && !capture_opts->restart) {
544                 simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
545 "%sNo packets captured!%s\n"
546 "\n"
547 "As no data was captured, closing the %scapture file!\n"
548 "\n"
549 "\n"
550 "Help about capturing can be found at:\n"
551 "\n"
552 "       http://wiki.wireshark.org/CaptureSetup"
553 #ifdef _WIN32
554 "\n\n"
555 "Wireless (Wi-Fi/WLAN):\n"
556 "Try to switch off promiscuous mode in the Capture Options!"
557 #endif
558 "",
559               simple_dialog_primary_start(), simple_dialog_primary_end(),
560               cf_is_tempfile(capture_opts->cf) ? "temporary " : "");
561               cf_close(capture_opts->cf);
562             }
563             break;
564         case CF_READ_ERROR:
565           /* Just because we got an error, that doesn't mean we were unable
566              to read any of the file; we handle what we could get from the
567              file. */
568           break;
569
570         case CF_READ_ABORTED:
571           /* Exit by leaving the main loop, so that any quit functions
572              we registered get called. */
573           main_window_quit();
574         }
575
576     } else {
577         /* first of all, we are not doing a capture any more */
578         capture_callback_invoke(capture_cb_capture_fixed_finished, capture_opts);
579
580         /* this is a normal mode capture and if no error happened, read in the capture file data */
581         if(capture_opts->save_file != NULL) {
582             capture_input_read_all(capture_opts, cf_is_tempfile(capture_opts->cf),
583                 cf_get_drops_known(capture_opts->cf), cf_get_drops(capture_opts->cf));
584         }
585     }
586
587     if(capture_opts->show_info)
588       capture_info_close();
589
590     capture_opts->state = CAPTURE_STOPPED;
591
592     /* if we couldn't open a capture file, there's nothing more for us to do */
593     if(capture_opts->save_file == NULL) {
594         cf_close(capture_opts->cf);
595         return;
596     }
597
598     /* does the user wants to restart the current capture? */
599     if(capture_opts->restart) {
600         capture_opts->restart = FALSE;
601
602         ws_unlink(capture_opts->save_file);
603
604         /* if it was a tempfile, throw away the old filename (so it will become a tempfile again) */
605         if(cf_is_tempfile(capture_opts->cf)) {
606             g_free(capture_opts->save_file);
607             capture_opts->save_file = NULL;
608         }
609
610         /* ... and start the capture again */
611         capture_start(capture_opts);
612     } else {
613         /* We're not doing a capture any more, so we don't have a save file. */
614         g_free(capture_opts->save_file);
615         capture_opts->save_file = NULL;
616     }
617 }
618
619 if_stat_cache_t *
620 capture_stat_start(GList *if_list) {
621     int stat_fd, fork_child;
622     gchar *msg;
623     if_stat_cache_t *sc = NULL;
624     GList *if_entry;
625     if_info_t *if_info;
626     if_stat_cache_item_t *sc_item;
627
628     /* Fire up dumpcap. */
629     /*
630      * XXX - on systems with BPF, the number of BPF devices limits the
631      * number of devices on which you can capture simultaneously.
632      *
633      * This means that
634      *
635      *  1) this might fail if you run out of BPF devices
636      *
637      * and
638      *
639      *  2) opening every interface could leave too few BPF devices
640      *     for *other* programs.
641      *
642      * It also means the system could end up getting a lot of traffic
643      * that it has to pass through the networking stack and capture
644      * mechanism, so opening all the devices and presenting packet
645      * counts might not always be a good idea.
646      */
647      if (sync_interface_stats_open(&stat_fd, &fork_child, &msg) == 0) {
648         sc = g_malloc(sizeof(if_stat_cache_t));
649         sc->stat_fd = stat_fd;
650         sc->fork_child = fork_child;
651         sc->cache_list = NULL;
652
653         /* Initialize the cache */
654         for (if_entry = if_list; if_entry != NULL; if_entry = g_list_next(if_entry)) {
655             if_info = if_entry->data;
656             sc_item = g_malloc0(sizeof(if_stat_cache_item_t));
657             sc_item->name = g_strdup(if_info->name);
658             sc->cache_list = g_list_append(sc->cache_list, sc_item);
659         }
660     }
661     return sc;
662 }
663
664 #define MAX_STAT_LINE_LEN 500
665
666 static void
667 capture_stat_cache_update(if_stat_cache_t *sc) {
668     gchar stat_line[MAX_STAT_LINE_LEN];
669     gchar **stat_parts;
670     GList *sc_entry;
671     if_stat_cache_item_t *sc_item;
672
673     if (!sc)
674         return;
675
676     while (sync_pipe_gets_nonblock(sc->stat_fd, stat_line, MAX_STAT_LINE_LEN) > 0) {
677         g_strstrip(stat_line);
678         stat_parts = g_strsplit(stat_line, "\t", 3);
679         if (stat_parts[0] == NULL || stat_parts[1] == NULL ||
680             stat_parts[2] == NULL) {
681             g_strfreev(stat_parts);
682             continue;
683         }
684         for (sc_entry = sc->cache_list; sc_entry != NULL; sc_entry = g_list_next(sc_entry)) {
685             sc_item = sc_entry->data;
686             if (strcmp(sc_item->name, stat_parts[0]) == 0) {
687                 sc_item->ps.ps_recv = (u_int) strtoul(stat_parts[1], NULL, 10);
688                 sc_item->ps.ps_drop = (u_int) strtoul(stat_parts[2], NULL, 10);
689             }
690         }
691         g_strfreev(stat_parts);
692     }
693 }
694
695 gboolean
696 capture_stats(if_stat_cache_t *sc, char *ifname, struct pcap_stat *ps) {
697     GList *sc_entry;
698     if_stat_cache_item_t *sc_item;
699
700     if (!sc || !ifname || !ps) {
701         return FALSE;
702     }
703
704     capture_stat_cache_update(sc);
705     for (sc_entry = sc->cache_list; sc_entry != NULL; sc_entry = g_list_next(sc_entry)) {
706         sc_item = sc_entry->data;
707         if (strcmp(sc_item->name, ifname) == 0) {
708             memcpy(ps, &sc_item->ps, sizeof(struct pcap_stat));
709             return TRUE;
710         }
711     }
712     return FALSE;
713 }
714
715 void
716 capture_stat_stop(if_stat_cache_t *sc) {
717     GList *sc_entry;
718     if_stat_cache_item_t *sc_item;
719     gchar *msg;
720
721     if (!sc)
722         return;
723
724     sync_interface_stats_close(&sc->stat_fd, &sc->fork_child, &msg);
725
726     for (sc_entry = sc->cache_list; sc_entry != NULL; sc_entry = g_list_next(sc_entry)) {
727         sc_item = sc_entry->data;
728         g_free(sc_item->name);
729         g_free(sc_item);
730     }
731     g_free(sc);
732 }
733
734 #endif /* HAVE_LIBPCAP */