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