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