extcap: Create callback structure
[metze/wireshark/wip.git] / extcap.c
1 /* extcap.c
2  *
3  * Routines for extcap external capture
4  * Copyright 2013, Mike Ryan <mikeryan@lacklustre.net>
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23  */
24
25 #include <config.h>
26
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30
31 #ifdef _WIN32
32 #include <windows.h>
33 #include <process.h>
34 #include <time.h>
35 #else
36 /* Include for unlink */
37 #include <unistd.h>
38 #endif
39
40 #ifdef HAVE_SYS_TYPES_H
41 #include <sys/types.h>
42 #endif
43 #ifdef HAVE_SYS_WAIT_H
44 #include <sys/wait.h>
45 #endif
46
47 #include <glib.h>
48 #include <log.h>
49
50 #include <epan/prefs.h>
51
52 #include <wsutil/file_util.h>
53 #include <wsutil/filesystem.h>
54 #include <wsutil/tempfile.h>
55
56 #include "capture_opts.h"
57
58 #include "extcap.h"
59 #include "extcap_parser.h"
60 #include "extcap_spawn.h"
61
62 #ifdef _WIN32
63 static HANDLE pipe_h = NULL;
64 #endif
65
66 static void extcap_child_watch_cb(GPid pid, gint status, gpointer user_data);
67
68 /* internal container, for all the extcap executables that have been found.
69  * Will be resetted if extcap_clear_interfaces() is being explicitly called
70  * and is being used for printing information about all extcap interfaces found,
71  * as well as storing all sub-interfaces
72  */
73 static GHashTable * _loaded_interfaces = NULL;
74
75 /* Internal container, which maps each ifname to the tool providing it, for faster
76  * lookup.
77  */
78 static GHashTable * _tool_for_ifname = NULL;
79
80 /* internal container, to map preference names to pointers that hold preference
81  * values. These ensure that preferences can survive extcap if garbage
82  * collection, and does not lead to dangling pointers in the prefs subsystem.
83  */
84 static GHashTable *extcap_prefs_dynamic_vals = NULL;
85
86 typedef struct _extcap_callback_info_t
87 {
88     const gchar * extcap;
89     const gchar * ifname;
90     gchar * output;
91     void * data;
92     gchar ** err_str;
93 } extcap_callback_info_t;
94
95 /* Callback definition for extcap_foreach */
96 typedef gboolean(*extcap_cb_t)(extcap_callback_info_t info_structure);
97
98 static void extcap_load_interface_list(void);
99
100 GHashTable *
101 extcap_loaded_interfaces(void)
102 {
103     if ( !_loaded_interfaces || g_hash_table_size(_loaded_interfaces) == 0 )
104         extcap_load_interface_list();
105
106     return _loaded_interfaces;
107 }
108
109 void
110 extcap_clear_interfaces(void)
111 {
112     if ( _loaded_interfaces )
113         g_hash_table_destroy(_loaded_interfaces);
114     _loaded_interfaces = NULL;
115
116     if ( _tool_for_ifname )
117         g_hash_table_destroy(_tool_for_ifname);
118     _tool_for_ifname = NULL;
119 }
120
121 guint extcap_count(void)
122 {
123     const char *dirname = get_extcap_dir();
124     GDir *dir;
125     guint count;
126
127     count = 0;
128
129     if ((dir = g_dir_open(dirname, 0, NULL)) != NULL)
130     {
131         GString *extcap_path = NULL;
132         const gchar *file;
133
134         extcap_path = g_string_new("");
135         while ((file = g_dir_read_name(dir)) != NULL)
136         {
137             /* full path to extcap binary */
138             g_string_printf(extcap_path, "%s" G_DIR_SEPARATOR_S "%s", dirname, file);
139             /* treat anything executable as an extcap binary */
140             if (g_file_test(extcap_path->str, G_FILE_TEST_IS_EXECUTABLE))
141             {
142                 count++;
143             }
144         }
145
146         g_dir_close(dir);
147         g_string_free(extcap_path, TRUE);
148     }
149     return count;
150 }
151
152 static gboolean
153 extcap_if_exists(const gchar *ifname)
154 {
155     if (!ifname || !_tool_for_ifname)
156     {
157         return FALSE;
158     }
159
160     if (g_hash_table_lookup(_tool_for_ifname, ifname))
161     {
162         return TRUE;
163     }
164
165     return FALSE;
166 }
167
168 static extcap_interface *
169 extcap_find_interface_for_ifname(const gchar *ifname)
170 {
171     extcap_interface * result = NULL;
172
173     if ( !ifname || ! _tool_for_ifname || ! _loaded_interfaces )
174         return result;
175
176     gchar * extcap_util = (gchar *)g_hash_table_lookup(_tool_for_ifname, ifname);
177     if ( ! extcap_util )
178         return result;
179
180     extcap_info * element = (extcap_info *)g_hash_table_lookup(_loaded_interfaces, extcap_util);
181     if ( ! element )
182         return result;
183
184     GList * walker = element->interfaces;
185     while ( walker && walker->data && ! result )
186     {
187         extcap_interface * interface = (extcap_interface *)walker->data;
188         if ( g_strcmp0(interface->call, ifname) == 0 )
189         {
190             result = interface;
191             break;
192         }
193
194         walker = g_list_next ( walker );
195     }
196
197     return result;
198 }
199
200 static gboolean
201 extcap_if_exists_for_extcap(const gchar *ifname, const gchar *extcap)
202 {
203     extcap_interface *entry = extcap_find_interface_for_ifname(ifname);
204
205     if (entry && strcmp(entry->extcap_path, extcap) == 0)
206     {
207         return TRUE;
208     }
209
210     return FALSE;
211 }
212
213 static gchar *
214 extcap_if_executable(const gchar *ifname)
215 {
216     extcap_interface *interface = extcap_find_interface_for_ifname(ifname);
217     return interface != NULL ? interface->extcap_path : NULL;
218 }
219
220 /* Note: args does not need to be NULL-terminated. */
221 static gboolean extcap_foreach(gint argc, gchar **args,
222                                       extcap_cb_t cb, extcap_callback_info_t cb_info)
223 {
224     GDir *dir;
225     gboolean keep_going;
226     const char *dirname = get_extcap_dir();
227
228     keep_going = TRUE;
229
230     if ((dir = g_dir_open(dirname, 0, NULL)) != NULL)
231     {
232         GString *extcap_path = NULL;
233         const gchar *file;
234
235         extcap_path = g_string_new("");
236         while (keep_going && (file = g_dir_read_name(dir)) != NULL)
237         {
238             gchar *command_output = NULL;
239
240             /* full path to extcap binary */
241             g_string_printf(extcap_path, "%s" G_DIR_SEPARATOR_S "%s", dirname, file);
242             if (extcap_if_exists(cb_info.ifname) && !extcap_if_exists_for_extcap(cb_info.ifname, extcap_path->str))
243             {
244                 continue;
245             }
246
247             if (extcap_spawn_sync((gchar *) dirname, extcap_path->str, argc, args, &command_output))
248             {
249                 cb_info.output = command_output;
250                 cb_info.extcap = extcap_path->str;
251
252                 keep_going = cb(cb_info);
253             }
254
255             g_free(command_output);
256         }
257
258         g_dir_close(dir);
259         g_string_free(extcap_path, TRUE);
260     }
261
262     return keep_going;
263 }
264
265 static void extcap_free_dlt(gpointer d, gpointer user_data _U_)
266 {
267     if (d == NULL)
268     {
269         return;
270     }
271
272     g_free(((extcap_dlt *)d)->name);
273     g_free(((extcap_dlt *)d)->display);
274     g_free(d);
275 }
276
277 static void extcap_free_dlts(GList *dlts)
278 {
279     g_list_foreach(dlts, extcap_free_dlt, NULL);
280     g_list_free(dlts);
281 }
282
283 static gboolean cb_dlt(extcap_callback_info_t cb_info)
284 {
285     GList *dlts = NULL, *temp = NULL;
286
287     if_capabilities_t *caps;
288     GList *linktype_list = NULL;
289     data_link_info_t *data_link_info;
290     extcap_dlt *dlt_item;
291
292     dlts = extcap_parse_dlts(cb_info.output);
293     temp = dlts;
294
295     g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Extcap pipe %s ", cb_info.extcap);
296
297     /*
298      * Allocate the interface capabilities structure.
299      */
300     caps = (if_capabilities_t *) g_malloc(sizeof * caps);
301     caps->can_set_rfmon = FALSE;
302
303     while (dlts)
304     {
305         dlt_item = (extcap_dlt *)dlts->data;
306         if (dlt_item)
307         {
308             g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG,
309                   "  DLT %d name=\"%s\" display=\"%s\" ", dlt_item->number,
310                   dlt_item->name, dlt_item->display);
311
312             data_link_info = g_new(data_link_info_t, 1);
313             data_link_info->dlt = dlt_item->number;
314             data_link_info->name = g_strdup(dlt_item->name);
315             data_link_info->description = g_strdup(dlt_item->display);
316             linktype_list = g_list_append(linktype_list, data_link_info);
317         }
318
319         dlts = g_list_next(dlts);
320     }
321
322     /* Check to see if we built a list */
323     if (linktype_list != NULL && cb_info.data != NULL)
324     {
325         caps->data_link_types = linktype_list;
326         *(if_capabilities_t **) cb_info.data = caps;
327     }
328     else
329     {
330         if (cb_info.err_str)
331         {
332             g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "  returned no DLTs");
333             *(cb_info.err_str) = g_strdup("Extcap returned no DLTs");
334         }
335         g_free(caps);
336     }
337
338     extcap_free_dlts(temp);
339
340     return FALSE;
341 }
342
343 if_capabilities_t *
344 extcap_get_if_dlts(const gchar *ifname, char **err_str)
345 {
346     gchar *argv[3];
347     gint i;
348     if_capabilities_t *caps = NULL;
349
350     if (err_str != NULL)
351     {
352         *err_str = NULL;
353     }
354
355     if (extcap_if_exists(ifname))
356     {
357         argv[0] = g_strdup(EXTCAP_ARGUMENT_LIST_DLTS);
358         argv[1] = g_strdup(EXTCAP_ARGUMENT_INTERFACE);
359         argv[2] = g_strdup(ifname);
360
361         extcap_callback_info_t cb_info;
362         cb_info.data = &caps;
363         cb_info.err_str = err_str;
364         cb_info.ifname = ifname;
365
366         extcap_foreach(3, argv, cb_dlt, cb_info);
367
368         for (i = 0; i < 3; ++i)
369         {
370             g_free(argv[i]);
371         }
372     }
373
374     return caps;
375 }
376
377 static void extcap_free_interface(gpointer i)
378 {
379
380     extcap_interface *interface = (extcap_interface *)i;
381
382     if (i == NULL)
383     {
384         return;
385     }
386
387     g_free(interface->call);
388     g_free(interface->display);
389     g_free(interface->version);
390     g_free(interface->help);
391     g_free(interface->extcap_path);
392     g_free(interface);
393 }
394
395 static void extcap_free_interfaces(GList *interfaces)
396 {
397     if (interfaces == NULL)
398     {
399         return;
400     }
401
402     g_list_foreach(interfaces, (GFunc)extcap_free_interface, NULL);
403     g_list_free(interfaces);
404 }
405
406 static gint
407 if_info_compare(gconstpointer a, gconstpointer b)
408 {
409     gint comp = 0;
410     const if_info_t *if_a = (const if_info_t *)a;
411     const if_info_t *if_b = (const if_info_t *)b;
412
413     if ((comp = g_strcmp0(if_a->name, if_b->name)) == 0)
414     {
415         return g_strcmp0(if_a->friendly_name, if_b->friendly_name);
416     }
417
418     return comp;
419 }
420
421 gchar *
422 extcap_get_help_for_ifname(const char *ifname)
423 {
424     extcap_interface *interface = extcap_find_interface_for_ifname(ifname);
425     return interface != NULL ? interface->help : NULL;
426 }
427
428 GList *
429 append_extcap_interface_list(GList *list, char **err_str _U_)
430 {
431     GList *interface_list = NULL;
432     extcap_interface *data = NULL;
433     GList * ifutilkeys = NULL;
434
435     /* Update the extcap interfaces and get a list of their if_infos */
436     if ( !_loaded_interfaces || g_hash_table_size(_loaded_interfaces) == 0 )
437         extcap_load_interface_list();
438
439     ifutilkeys = g_hash_table_get_keys(_loaded_interfaces);
440     while ( ifutilkeys && ifutilkeys->data )
441     {
442         extcap_info * extinfo =
443                 (extcap_info *) g_hash_table_lookup(_loaded_interfaces, (gchar *)ifutilkeys->data);
444         GList * walker = extinfo->interfaces;
445         while ( walker && walker->data )
446         {
447             interface_list = g_list_append(interface_list, walker->data);
448             walker = g_list_next(walker);
449         }
450
451         ifutilkeys = g_list_next(ifutilkeys);
452     }
453
454     /* Sort that list */
455     interface_list = g_list_sort(interface_list, if_info_compare);
456
457     /* Append the interfaces in that list to the list we're handed. */
458     while (interface_list != NULL)
459     {
460         GList *entry = g_list_first(interface_list);
461         data = (extcap_interface *)entry->data;
462         interface_list = g_list_delete_link(interface_list, entry);
463
464         if_info_t * if_info = g_new0(if_info_t, 1);
465         if_info->name = g_strdup(data->call);
466         if_info->friendly_name = g_strdup(data->display);
467
468         if_info->type = IF_EXTCAP;
469
470         if_info->extcap = g_strdup(data->extcap_path);
471
472         list = g_list_append(list, if_info);
473     }
474
475     return list;
476 }
477
478 static void
479 extcap_register_preferences_callback(gpointer key, gpointer value _U_, gpointer user_data _U_)
480 {
481     GList *arguments;
482
483     arguments = extcap_get_if_configuration((gchar *)key);
484     /* Memory for prefs are external to an interface, they are part of
485      * extcap core, so the parsed arguments can be freed. */
486     extcap_free_if_configuration(arguments, TRUE);
487 }
488
489 void extcap_register_preferences(void)
490 {
491     module_t *dev_module = prefs_find_module("extcap");
492
493     if (!dev_module)
494     {
495         return;
496     }
497
498     if ( !_loaded_interfaces || g_hash_table_size(_loaded_interfaces) == 0 )
499         extcap_load_interface_list();
500
501
502     g_hash_table_foreach(_tool_for_ifname, extcap_register_preferences_callback, NULL);
503 }
504
505 /**
506  * Releases the dynamic preference value pointers. Must not be called before
507  * prefs_cleanup since these pointers could still be in use.
508  */
509 void extcap_cleanup(void)
510 {
511     if (extcap_prefs_dynamic_vals)
512         g_hash_table_destroy(extcap_prefs_dynamic_vals);
513
514     if (_loaded_interfaces)
515         g_hash_table_destroy(_loaded_interfaces);
516
517     if (_tool_for_ifname)
518         g_hash_table_destroy(_tool_for_ifname);
519 }
520
521 void extcap_pref_store(extcap_arg *arg, const char *newval)
522 {
523     if (arg && arg->pref_valptr != NULL)
524     {
525         g_free(*arg->pref_valptr);
526         *arg->pref_valptr = g_strdup(newval);
527     }
528
529 }
530
531 /**
532  * Obtains a pointer which can store a value for the given preference name.
533  * The preference name that can be passed to the prefs API is stored into
534  * 'prefs_name'.
535  *
536  * Extcap interfaces (and their preferences) are dynamic, they can be created
537  * and destroyed at will. Thus their data structures are insufficient to pass to
538  * the preferences APIs which require pointers which are valid until the
539  * preferences are removed (at exit).
540  */
541 static gchar **extcap_prefs_dynamic_valptr(const char *name, char **pref_name)
542 {
543     gchar **valp;
544     if (!extcap_prefs_dynamic_vals)
545     {
546         /* Initialize table only as needed, most preferences are not dynamic */
547         extcap_prefs_dynamic_vals = g_hash_table_new_full(g_str_hash, g_str_equal,
548                                     g_free, g_free);
549     }
550     if (!g_hash_table_lookup_extended(extcap_prefs_dynamic_vals, name,
551                                       (gpointer *)pref_name, (gpointer *)&valp))
552     {
553         /* New dynamic pref, allocate, initialize and store. */
554         valp = g_new0(gchar *, 1);
555         *pref_name = g_strdup(name);
556         g_hash_table_insert(extcap_prefs_dynamic_vals, *pref_name, valp);
557     }
558     return valp;
559 }
560
561 void extcap_free_if_configuration(GList *list, gboolean free_args)
562 {
563     GList *elem, *sl;
564
565     for (elem = g_list_first(list); elem; elem = elem->next)
566     {
567         if (elem->data != NULL)
568         {
569             sl = g_list_first((GList *)elem->data);
570             if (free_args)
571             {
572                 extcap_free_arg_list(sl);
573             }
574             else
575             {
576                 g_list_free(sl);
577             }
578         }
579     }
580     g_list_free(list);
581 }
582
583 struct preference *
584 extcap_pref_for_argument(const gchar *ifname, struct _extcap_arg *arg)
585 {
586     struct preference *pref = NULL;
587
588     GRegex *regex_name = g_regex_new("[-]+", (GRegexCompileFlags) 0, (GRegexMatchFlags) 0, NULL);
589     GRegex *regex_ifname = g_regex_new("(?![a-zA-Z1-9_]).", (GRegexCompileFlags) 0, (GRegexMatchFlags) 0, NULL);
590     if (regex_name && regex_ifname)
591     {
592         if (prefs_find_module("extcap"))
593         {
594             gchar *pref_name = g_regex_replace(regex_name, arg->call, strlen(arg->call), 0, "", (GRegexMatchFlags) 0, NULL);
595             gchar *ifname_underscore = g_regex_replace(regex_ifname, ifname, strlen(ifname), 0, "_", (GRegexMatchFlags) 0, NULL);
596             gchar *ifname_lowercase = g_ascii_strdown(ifname_underscore, -1);
597             gchar *pref_ifname = g_strconcat(ifname_lowercase, ".", pref_name, NULL);
598
599             pref = prefs_find_preference(prefs_find_module("extcap"), pref_ifname);
600
601             g_free(pref_name);
602             g_free(ifname_underscore);
603             g_free(ifname_lowercase);
604             g_free(pref_ifname);
605         }
606     }
607     if (regex_name)
608     {
609         g_regex_unref(regex_name);
610     }
611     if (regex_ifname)
612     {
613         g_regex_unref(regex_ifname);
614     }
615
616     return pref;
617 }
618
619 static gboolean cb_preference(extcap_callback_info_t cb_info)
620 {
621     GList *arguments = NULL;
622     GList **il = (GList **) cb_info.data;
623     module_t *dev_module = NULL;
624
625     arguments = extcap_parse_args(cb_info.output);
626
627     dev_module = prefs_find_module("extcap");
628
629     if (dev_module)
630     {
631         GList *walker = arguments;
632
633         GRegex *regex_name = g_regex_new("[-]+", (GRegexCompileFlags) 0, (GRegexMatchFlags) 0, NULL);
634         GRegex *regex_ifname = g_regex_new("(?![a-zA-Z1-9_]).", (GRegexCompileFlags) 0, (GRegexMatchFlags) 0, NULL);
635         if (regex_name && regex_ifname)
636         {
637             while (walker != NULL)
638             {
639                 extcap_arg *arg = (extcap_arg *)walker->data;
640                 arg->device_name = g_strdup(cb_info.ifname);
641
642                 if (arg->save)
643                 {
644                     struct preference *pref = NULL;
645
646                     gchar *pref_name = g_regex_replace(regex_name, arg->call, strlen(arg->call), 0, "", (GRegexMatchFlags) 0, NULL);
647                     gchar *ifname_underscore = g_regex_replace(regex_ifname, cb_info.ifname, strlen(cb_info.ifname), 0, "_", (GRegexMatchFlags) 0, NULL);
648                     gchar *ifname_lowercase = g_ascii_strdown(ifname_underscore, -1);
649                     gchar *pref_ifname = g_strconcat(ifname_lowercase, ".", pref_name, NULL);
650
651                     if ((pref = prefs_find_preference(dev_module, pref_ifname)) == NULL)
652                     {
653                         char *pref_name_for_prefs;
654                         char *pref_title = wmem_strdup(wmem_epan_scope(), arg->display);
655
656                         arg->pref_valptr = extcap_prefs_dynamic_valptr(pref_ifname, &pref_name_for_prefs);
657                         /* Set an initial value if any (the string will be copied at registration) */
658                         if (arg->default_complex)
659                         {
660                             *arg->pref_valptr = arg->default_complex->_val;
661                         }
662
663                         prefs_register_string_preference(dev_module, pref_name_for_prefs,
664                                                          pref_title, pref_title, (const char **)arg->pref_valptr);
665                     }
666                     else
667                     {
668                         /* Been here before, restore stored value */
669                         if (arg->pref_valptr == NULL)
670                         {
671                             arg->pref_valptr = (gchar**)g_hash_table_lookup(extcap_prefs_dynamic_vals, pref_ifname);
672                         }
673                     }
674
675                     g_free(pref_name);
676                     g_free(ifname_underscore);
677                     g_free(ifname_lowercase);
678                     g_free(pref_ifname);
679                 }
680
681                 walker = g_list_next(walker);
682             }
683         }
684         if (regex_name)
685         {
686             g_regex_unref(regex_name);
687         }
688         if (regex_ifname)
689         {
690             g_regex_unref(regex_ifname);
691         }
692     }
693
694     *il = g_list_append(*il, arguments);
695
696     /* By returning false, extcap_foreach will break on first found */
697     return TRUE;
698 }
699
700 GList *
701 extcap_get_if_configuration(const char *ifname)
702 {
703     gchar *argv[3];
704     GList *ret = NULL;
705     gchar **err_str = NULL;
706     int i;
707
708     if (extcap_if_exists(ifname))
709     {
710         g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Extcap path %s",
711               get_extcap_dir());
712
713         argv[0] = g_strdup(EXTCAP_ARGUMENT_CONFIG);
714         argv[1] = g_strdup(EXTCAP_ARGUMENT_INTERFACE);
715         argv[2] = g_strdup(ifname);
716
717         extcap_callback_info_t cb_info;
718         cb_info.data = &ret;
719         cb_info.err_str = err_str;
720         cb_info.ifname = ifname;
721
722         extcap_foreach(3, argv, cb_preference, cb_info);
723
724         for (i = 0; i < 3; i++)
725         {
726             g_free(argv[i]);
727         }
728     }
729
730     return ret;
731 }
732
733 /**
734  * If is_required is FALSE: returns TRUE if the extcap interface has
735  * configurable options.
736  * If is_required is TRUE: returns TRUE when the extcap interface has
737  * configurable options that required modification. (For example, when an
738  * argument is required but empty.)
739  */
740 gboolean
741 extcap_has_configuration(const char *ifname, gboolean is_required)
742 {
743     GList *arguments = 0;
744     GList *walker = 0, * item = 0;
745
746     gboolean found = FALSE;
747
748     arguments = extcap_get_if_configuration((const char *)(ifname));
749     walker = g_list_first(arguments);
750
751     while (walker != NULL && !found)
752     {
753         item = g_list_first((GList *)(walker->data));
754         while (item != NULL && !found)
755         {
756             if ((extcap_arg *)(item->data) != NULL)
757             {
758                 extcap_arg *arg = (extcap_arg *)(item->data);
759                 /* Should required options be present, or any kind of options */
760                 if (!is_required)
761                 {
762                     found = TRUE;
763                 }
764                 else if (arg->is_required)
765                 {
766                     const gchar *stored = NULL;
767                     const gchar *defval = NULL;
768
769                     if (arg->pref_valptr != NULL)
770                     {
771                         stored = *arg->pref_valptr;
772                     }
773
774                     if (arg->default_complex != NULL && arg->default_complex->_val != NULL)
775                     {
776                         defval = arg->default_complex->_val;
777                     }
778
779                     if (arg->is_required)
780                     {
781                         /* If stored and defval is identical and the argument is required,
782                          * configuration is needed */
783                         if (defval && stored && g_strcmp0(stored, defval) == 0)
784                         {
785                             found = TRUE;
786                         }
787                         else if (!defval && (!stored || !*stored))
788                         {
789                             found = TRUE;
790                         }
791                     }
792
793                     if (arg->arg_type == EXTCAP_ARG_FILESELECT)
794                     {
795                         if (arg->fileexists && !(file_exists(defval) || file_exists(stored)))
796                         {
797                             found = TRUE;
798                         }
799                     }
800                 }
801             }
802
803             item = item->next;
804         }
805         walker = walker->next;
806     }
807     extcap_free_if_configuration(arguments, TRUE);
808
809     return found;
810 }
811
812 /* taken from capchild/capture_sync.c */
813 static gboolean pipe_data_available(int pipe_fd)
814 {
815 #ifdef _WIN32 /* PeekNamedPipe */
816     HANDLE hPipe = (HANDLE) _get_osfhandle(pipe_fd);
817     DWORD bytes_avail;
818
819     if (hPipe == INVALID_HANDLE_VALUE)
820     {
821         return FALSE;
822     }
823
824     if (! PeekNamedPipe(hPipe, NULL, 0, NULL, &bytes_avail, NULL))
825     {
826         return FALSE;
827     }
828
829     if (bytes_avail > 0)
830     {
831         return TRUE;
832     }
833     return FALSE;
834 #else /* select */
835     fd_set rfds;
836     struct timeval timeout;
837
838     FD_ZERO(&rfds);
839     FD_SET(pipe_fd, &rfds);
840     timeout.tv_sec = 0;
841     timeout.tv_usec = 0;
842
843     if (select(pipe_fd + 1, &rfds, NULL, NULL, &timeout) > 0)
844     {
845         return TRUE;
846     }
847
848     return FALSE;
849 #endif
850 }
851
852 void extcap_if_cleanup(capture_options *capture_opts, gchar **errormsg)
853 {
854     interface_options interface_opts;
855     extcap_userdata *userdata;
856     guint icnt = 0;
857     gboolean overwrite_exitcode;
858     gchar *buffer;
859 #define STDERR_BUFFER_SIZE 1024
860
861     for (icnt = 0; icnt < capture_opts->ifaces->len; icnt++)
862     {
863         interface_opts = g_array_index(capture_opts->ifaces, interface_options,
864                                        icnt);
865
866         /* skip native interfaces */
867         if (interface_opts.if_type != IF_EXTCAP)
868         {
869             continue;
870         }
871
872         overwrite_exitcode = FALSE;
873
874         g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG,
875               "Extcap [%s] - Cleaning up fifo: %s; PID: %d", interface_opts.name,
876               interface_opts.extcap_fifo, interface_opts.extcap_pid);
877 #ifdef _WIN32
878         if (pipe_h)
879         {
880             g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG,
881                   "Extcap [%s] - Closing pipe", interface_opts.name);
882             FlushFileBuffers(pipe_h);
883             DisconnectNamedPipe(pipe_h);
884             CloseHandle(pipe_h);
885         }
886 #else
887         if (interface_opts.extcap_fifo != NULL && file_exists(interface_opts.extcap_fifo))
888         {
889             /* the fifo will not be freed here, but with the other capture_opts in capture_sync */
890             ws_unlink(interface_opts.extcap_fifo);
891             interface_opts.extcap_fifo = NULL;
892         }
893 #endif
894         /* Maybe the client closed and removed fifo, but ws should check if
895          * pid should be closed */
896         g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG,
897               "Extcap [%s] - Closing spawned PID: %d", interface_opts.name,
898               interface_opts.extcap_pid);
899
900         userdata = (extcap_userdata *) interface_opts.extcap_userdata;
901         if (userdata)
902         {
903             if (userdata->extcap_stderr_rd > 0 && pipe_data_available(userdata->extcap_stderr_rd))
904             {
905                 buffer = (gchar *)g_malloc0(sizeof(gchar) * STDERR_BUFFER_SIZE + 1);
906 #ifdef _WIN32
907                 win32_readfrompipe((HANDLE)_get_osfhandle(userdata->extcap_stderr_rd), STDERR_BUFFER_SIZE, buffer);
908 #else
909                 if (read(userdata->extcap_stderr_rd, buffer, sizeof(gchar) * STDERR_BUFFER_SIZE) <= 0)
910                 {
911                     buffer[0] = '\0';
912                 }
913 #endif
914                 if (strlen(buffer) > 0)
915                 {
916                     userdata->extcap_stderr = g_strdup_printf("%s", buffer);
917                     userdata->exitcode = 1;
918                 }
919                 g_free(buffer);
920             }
921
922 #ifndef _WIN32
923             /* Final child watch may not have been called */
924             if (interface_opts.extcap_child_watch != 0)
925             {
926                 extcap_child_watch_cb(userdata->pid, 0, capture_opts);
927                 /* it will have changed in extcap_child_watch_cb */
928                 interface_opts = g_array_index(capture_opts->ifaces, interface_options,
929                                                icnt);
930             }
931 #endif
932
933             if (userdata->extcap_stderr != NULL)
934             {
935                 overwrite_exitcode = TRUE;
936             }
937
938             if (overwrite_exitcode || userdata->exitcode != 0)
939             {
940                 if (userdata->extcap_stderr != 0)
941                 {
942                     if (*errormsg == NULL)
943                     {
944                         *errormsg = g_strdup_printf("Error by extcap pipe: %s", userdata->extcap_stderr);
945                     }
946                     else
947                     {
948                         gchar *temp = g_strconcat(*errormsg, "\nError by extcap pipe: " , userdata->extcap_stderr, NULL);
949                         g_free(*errormsg);
950                         *errormsg = temp;
951                     }
952                     g_free(userdata->extcap_stderr);
953                 }
954
955                 userdata->extcap_stderr = NULL;
956                 userdata->exitcode = 0;
957             }
958         }
959
960         if (interface_opts.extcap_child_watch > 0)
961         {
962             g_source_remove(interface_opts.extcap_child_watch);
963             interface_opts.extcap_child_watch = 0;
964         }
965
966         if (interface_opts.extcap_pid != INVALID_EXTCAP_PID)
967         {
968 #ifdef _WIN32
969             TerminateProcess(interface_opts.extcap_pid, 0);
970 #endif
971             g_spawn_close_pid(interface_opts.extcap_pid);
972             interface_opts.extcap_pid = INVALID_EXTCAP_PID;
973
974             g_free(interface_opts.extcap_userdata);
975             interface_opts.extcap_userdata = NULL;
976         }
977
978         /* Make sure modified interface_opts is saved in capture_opts. */
979         capture_opts->ifaces = g_array_remove_index(capture_opts->ifaces, icnt);
980         g_array_insert_val(capture_opts->ifaces, icnt, interface_opts);
981     }
982 }
983
984 static gboolean
985 extcap_add_arg_and_remove_cb(gpointer key, gpointer value, gpointer data)
986 {
987     GPtrArray *args = (GPtrArray *)data;
988
989     if (key != NULL)
990     {
991         g_ptr_array_add(args, g_strdup((const gchar *)key));
992
993         if (value != NULL)
994         {
995             g_ptr_array_add(args, g_strdup((const gchar *)value));
996         }
997
998         return TRUE;
999     }
1000
1001     return FALSE;
1002 }
1003
1004 void extcap_child_watch_cb(GPid pid, gint status, gpointer user_data)
1005 {
1006     guint i;
1007     interface_options interface_opts;
1008     extcap_userdata *userdata = NULL;
1009     capture_options *capture_opts = (capture_options *)(user_data);
1010
1011     if (capture_opts == NULL || capture_opts->ifaces == NULL || capture_opts->ifaces->len == 0)
1012     {
1013         return;
1014     }
1015
1016     /* Close handle to child process. */
1017     g_spawn_close_pid(pid);
1018
1019     /* Update extcap_pid in interface options structure. */
1020     for (i = 0; i < capture_opts->ifaces->len; i++)
1021     {
1022         interface_opts = g_array_index(capture_opts->ifaces, interface_options, i);
1023         if (interface_opts.extcap_pid == pid)
1024         {
1025             userdata = (extcap_userdata *)interface_opts.extcap_userdata;
1026             if (userdata != NULL)
1027             {
1028                 interface_opts.extcap_pid = INVALID_EXTCAP_PID;
1029                 userdata->exitcode = 0;
1030 #ifndef _WIN32
1031                 if (WIFEXITED(status))
1032                 {
1033                     if (WEXITSTATUS(status) != 0)
1034                     {
1035                         userdata->exitcode = WEXITSTATUS(status);
1036                     }
1037                 }
1038                 else
1039                 {
1040                     userdata->exitcode = G_SPAWN_ERROR_FAILED;
1041                 }
1042 #else
1043                 if (status != 0)
1044                 {
1045                     userdata->exitcode = status;
1046                 }
1047 #endif
1048                 if (status == 0 && userdata->extcap_stderr != NULL)
1049                 {
1050                     userdata->exitcode = 1;
1051                 }
1052             }
1053             g_source_remove(interface_opts.extcap_child_watch);
1054             interface_opts.extcap_child_watch = 0;
1055
1056             capture_opts->ifaces = g_array_remove_index(capture_opts->ifaces, i);
1057             g_array_insert_val(capture_opts->ifaces, i, interface_opts);
1058             break;
1059         }
1060     }
1061 }
1062
1063 static
1064 GPtrArray *extcap_prepare_arguments(interface_options interface_opts)
1065 {
1066     GPtrArray *result = NULL;
1067
1068     if (interface_opts.if_type == IF_EXTCAP)
1069     {
1070         result = g_ptr_array_new();
1071
1072 #define add_arg(X) g_ptr_array_add(result, g_strdup(X))
1073
1074         add_arg(interface_opts.extcap);
1075         add_arg(EXTCAP_ARGUMENT_RUN_CAPTURE);
1076         add_arg(EXTCAP_ARGUMENT_INTERFACE);
1077         add_arg(interface_opts.name);
1078         if (interface_opts.cfilter && strlen(interface_opts.cfilter) > 0)
1079         {
1080             add_arg(EXTCAP_ARGUMENT_CAPTURE_FILTER);
1081             add_arg(interface_opts.cfilter);
1082         }
1083         add_arg(EXTCAP_ARGUMENT_RUN_PIPE);
1084         add_arg(interface_opts.extcap_fifo);
1085         if (interface_opts.extcap_args == NULL || g_hash_table_size(interface_opts.extcap_args) == 0)
1086         {
1087             /* User did not perform interface configuration.
1088              *
1089              * Check if there are any boolean flags that are set by default
1090              * and hence their argument should be added.
1091              */
1092             GList *arglist;
1093             GList *elem;
1094
1095             arglist = extcap_get_if_configuration(interface_opts.name);
1096             for (elem = g_list_first(arglist); elem; elem = elem->next)
1097             {
1098                 GList *arg_list;
1099                 extcap_arg *arg_iter;
1100
1101                 if (elem->data == NULL)
1102                 {
1103                     continue;
1104                 }
1105
1106                 arg_list = g_list_first((GList *)elem->data);
1107                 while (arg_list != NULL)
1108                 {
1109                     const gchar *stored = NULL, * defval = NULL;
1110                     /* In case of boolflags only first element in arg_list is relevant. */
1111                     arg_iter = (extcap_arg *)(arg_list->data);
1112                     if (arg_iter->pref_valptr != NULL)
1113                     {
1114                         stored = *arg_iter->pref_valptr;
1115                     }
1116
1117                     if (arg_iter->default_complex != NULL && arg_iter->default_complex->_val != NULL)
1118                     {
1119                         defval = arg_iter->default_complex->_val;
1120                     }
1121
1122                     /* Different data in storage then set for default */
1123                     if (g_strcmp0(stored, defval) != 0)
1124                     {
1125                         if (arg_iter->arg_type == EXTCAP_ARG_BOOLFLAG)
1126                         {
1127                             if (g_strcmp0(stored, "true") == 0)
1128                             {
1129                                 add_arg(arg_iter->call);
1130                             }
1131                         }
1132                         else
1133                         {
1134                             add_arg(arg_iter->call);
1135                             add_arg(stored);
1136                         }
1137                     }
1138                     else if (arg_iter->arg_type == EXTCAP_ARG_BOOLFLAG)
1139                     {
1140                         if (extcap_complex_get_bool(arg_iter->default_complex))
1141                         {
1142                             add_arg(arg_iter->call);
1143                         }
1144                     }
1145
1146                     arg_list = arg_list->next;
1147                 }
1148             }
1149
1150             extcap_free_if_configuration(arglist, TRUE);
1151         }
1152         else
1153         {
1154             g_hash_table_foreach_remove(interface_opts.extcap_args, extcap_add_arg_and_remove_cb, result);
1155         }
1156         add_arg(NULL);
1157 #undef add_arg
1158
1159     }
1160
1161     return result;
1162 }
1163
1164 /* call mkfifo for each extcap,
1165  * returns FALSE if there's an error creating a FIFO */
1166 gboolean
1167 extcap_init_interfaces(capture_options *capture_opts)
1168 {
1169     guint i;
1170     interface_options interface_opts;
1171     extcap_userdata *userdata;
1172
1173     for (i = 0; i < capture_opts->ifaces->len; i++)
1174     {
1175         GPtrArray *args = NULL;
1176         GPid pid = INVALID_EXTCAP_PID;
1177
1178         interface_opts = g_array_index(capture_opts->ifaces, interface_options, i);
1179
1180         /* skip native interfaces */
1181         if (interface_opts.if_type != IF_EXTCAP)
1182         {
1183             continue;
1184         }
1185
1186         /* create pipe for fifo */
1187         if (!extcap_create_pipe(&interface_opts.extcap_fifo))
1188         {
1189             return FALSE;
1190         }
1191
1192         /* Create extcap call */
1193         args = extcap_prepare_arguments(interface_opts);
1194
1195         userdata = g_new0(extcap_userdata, 1);
1196
1197         pid = extcap_spawn_async(userdata, args);
1198
1199         g_ptr_array_foreach(args, (GFunc)g_free, NULL);
1200         g_ptr_array_free(args, TRUE);
1201
1202         if (pid == INVALID_EXTCAP_PID)
1203         {
1204             g_free(userdata);
1205             continue;
1206         }
1207
1208         interface_opts.extcap_pid = pid;
1209
1210         interface_opts.extcap_child_watch =
1211             g_child_watch_add(pid, extcap_child_watch_cb, (gpointer)capture_opts);
1212
1213 #ifdef _WIN32
1214         /* On Windows, wait for extcap to connect to named pipe.
1215          * Some extcaps will present UAC screen to user.
1216          * 30 second timeout should be reasonable timeout for extcap to
1217          * connect to named pipe (including user interaction).
1218          * Wait on multiple object in case of extcap termination
1219          * without opening pipe.
1220          *
1221          * Minimum supported version of Windows: XP / Server 2003.
1222          */
1223         if (pid != INVALID_EXTCAP_PID)
1224         {
1225             extcap_wait_for_pipe(pipe_h, pid);
1226         }
1227
1228 #endif
1229
1230         interface_opts.extcap_userdata = (gpointer) userdata;
1231
1232         capture_opts->ifaces = g_array_remove_index(capture_opts->ifaces, i);
1233         g_array_insert_val(capture_opts->ifaces, i, interface_opts);
1234     }
1235
1236     return TRUE;
1237 }
1238
1239 #ifdef _WIN32
1240 /* called by capture_sync to get the CreatNamedPipe handle*/
1241 HANDLE
1242 extcap_get_win32_handle()
1243 {
1244     return pipe_h;
1245 }
1246 #endif
1247
1248 gboolean extcap_create_pipe(char **fifo)
1249 {
1250 #ifdef _WIN32
1251     gchar timestr[ 14 + 1 ];
1252     time_t current_time;
1253
1254     gchar *pipename = NULL;
1255
1256     SECURITY_ATTRIBUTES security;
1257     /* create pipename */
1258     current_time = time(NULL);
1259     /*
1260      * XXX - we trust Windows not to return a time before the Epoch here,
1261      * so we won't get a null pointer back from localtime().
1262      */
1263     strftime(timestr, sizeof(timestr), "%Y%m%d%H%M%S", localtime(&current_time));
1264     pipename = g_strconcat("\\\\.\\pipe\\", EXTCAP_PIPE_PREFIX, "_", timestr, NULL);
1265
1266     /* Security struct to enable Inheritable HANDLE */
1267     memset(&security, 0, sizeof(SECURITY_ATTRIBUTES));
1268     security.nLength = sizeof(SECURITY_ATTRIBUTES);
1269     security.bInheritHandle = TRUE;
1270     security.lpSecurityDescriptor = NULL;
1271
1272     /* create a namedPipe*/
1273     pipe_h = CreateNamedPipe(
1274                  utf_8to16(pipename),
1275                  PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
1276                  PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
1277                  5, 65536, 65536,
1278                  300,
1279                  &security);
1280
1281     if (pipe_h == INVALID_HANDLE_VALUE)
1282     {
1283         g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "\nError creating pipe => (%d)", GetLastError());
1284         return FALSE;
1285     }
1286     else
1287     {
1288         g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "\nWireshark Created pipe =>(%s)", pipename);
1289         *fifo = g_strdup(pipename);
1290     }
1291 #else
1292     gchar *temp_name = NULL;
1293     int fd = 0;
1294
1295     if ((fd = create_tempfile(&temp_name, EXTCAP_PIPE_PREFIX, NULL)) < 0)
1296     {
1297         return FALSE;
1298     }
1299
1300     ws_close(fd);
1301
1302     g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG,
1303           "Extcap - Creating fifo: %s", temp_name);
1304
1305     if (file_exists(temp_name))
1306     {
1307         ws_unlink(temp_name);
1308     }
1309
1310     if (mkfifo(temp_name, 0600) == 0)
1311     {
1312         *fifo = g_strdup(temp_name);
1313     }
1314 #endif
1315
1316     return TRUE;
1317 }
1318
1319 /************* EXTCAP LOAD INTERFACE LIST ***************
1320  *
1321  * The following code handles loading and reloading the interface list. It is explicitly
1322  * kept separate from the rest
1323  */
1324
1325
1326 static void
1327 extcap_free_interface_info(gpointer data _U_)
1328 {
1329     extcap_info *info = (extcap_info *)data;
1330
1331     g_free(info->basename);
1332     g_free(info->full_path);
1333     g_free(info->version);
1334
1335     extcap_free_interfaces(info->interfaces);
1336
1337     g_free(info);
1338 }
1339
1340 static extcap_info *
1341 extcap_ensure_interface(const gchar * toolname)
1342 {
1343     extcap_info * element = 0;
1344
1345     if ( ! toolname )
1346         return element;
1347
1348     if ( ! _loaded_interfaces )
1349         _loaded_interfaces = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, extcap_free_interface);
1350
1351     if ( ( element = (extcap_info *) g_hash_table_lookup(_loaded_interfaces, toolname ) ) == NULL )
1352     {
1353         g_hash_table_insert(_loaded_interfaces, g_strdup(toolname), g_new0(extcap_info, 1));
1354         element = (extcap_info *) g_hash_table_lookup(_loaded_interfaces, toolname );
1355     }
1356
1357     return element;
1358 }
1359
1360 static void remove_extcap_entry(gpointer entry, gpointer data _U_)
1361 {
1362     extcap_interface *int_iter = (extcap_interface*)entry;
1363
1364     if (int_iter->if_type == EXTCAP_SENTENCE_EXTCAP)
1365         g_free(int_iter);
1366 }
1367
1368 static gboolean cb_load_interfaces(extcap_callback_info_t cb_info)
1369 {
1370     GList *interfaces = NULL, *walker = NULL;
1371     extcap_interface *int_iter = NULL;
1372     gchar *toolname = g_path_get_basename(cb_info.extcap);
1373
1374     GList * interface_keys = g_hash_table_get_keys(_loaded_interfaces);
1375
1376     interfaces = extcap_parse_interfaces(cb_info.output);
1377
1378     g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Loading interface list for %s ", cb_info.extcap);
1379
1380     walker = interfaces;
1381     gchar* help = NULL;
1382     while (walker != NULL)
1383     {
1384         int_iter = (extcap_interface *)walker->data;
1385
1386         extcap_info * element = extcap_ensure_interface(toolname);
1387
1388         if ( element == NULL )
1389         {
1390             g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_ERROR, "Cannot store interface %s", cb_info.extcap);
1391             walker = g_list_next(walker);
1392             continue;
1393         }
1394
1395         g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Interface found %s\n", int_iter->call);
1396
1397         /* Help is not necessarily stored with the interface, but rather with the version string.
1398          * As the version string allways comes in front of the interfaces, this ensures, that it get's
1399          * properly stored with the interface */
1400         if (int_iter->if_type == EXTCAP_SENTENCE_EXTCAP)
1401         {
1402             g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "  Extcap [%s] ", int_iter->call);
1403             /* Only initialize values if none are set. Need to check only one element here */
1404             if ( ! element->version )
1405             {
1406                 element->version = g_strdup(int_iter->version);
1407                 element->basename = g_strdup(toolname);
1408                 element->full_path = g_strdup(cb_info.extcap);
1409             }
1410
1411             help = int_iter->help;
1412
1413             walker = g_list_next(walker);
1414             continue;
1415         }
1416
1417         /* Only interface definitions will be parsed here. help is already set by the extcap element,
1418          * which makes it necessary to have version in the list before the interfaces. This is normally
1419          * the case by design, but could be changed by separating the information in extcap-base. */
1420         if ( int_iter->if_type == EXTCAP_SENTENCE_INTERFACE )
1421         {
1422             if ( g_list_find(interface_keys, int_iter->call) )
1423             {
1424                 g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_WARNING, "Extcap interface \"%s\" is already provided by \"%s\" ",
1425                       int_iter->call, (gchar *)extcap_if_executable(int_iter->call));
1426                 walker = g_list_next(walker);
1427                 continue;
1428             }
1429
1430             g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "  Interface [%s] \"%s\" ",
1431                   int_iter->call, int_iter->display);
1432
1433             int_iter->extcap_path = g_strdup(cb_info.extcap);
1434
1435             /* Only set the help, if it exists and no parsed help information is present */
1436             if ( ! int_iter->help && help )
1437                 int_iter->help = g_strdup(help);
1438
1439             element->interfaces = g_list_append(element->interfaces, int_iter);
1440             g_hash_table_insert(_tool_for_ifname, g_strdup(int_iter->call), g_strdup(toolname));
1441         }
1442
1443         walker = g_list_next(walker);
1444     }
1445
1446     g_list_foreach(interfaces, remove_extcap_entry, NULL);
1447     g_list_free(interfaces);
1448     g_list_free(interface_keys);
1449     g_free(toolname);
1450     return TRUE;
1451 }
1452
1453
1454 /* Handles loading of the interfaces.
1455  *
1456  * A list of interfaces can be obtained by calling \ref extcap_loaded_interfaces
1457  */
1458 static void
1459 extcap_load_interface_list(void)
1460 {
1461     gchar *argv;
1462     gchar *error;
1463
1464     if (_loaded_interfaces == NULL)
1465     {
1466         _loaded_interfaces = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, extcap_free_interface_info);
1467         /* Cleanup lookup table */
1468         if ( _tool_for_ifname )
1469         {
1470             g_hash_table_remove_all(_tool_for_ifname);
1471             _tool_for_ifname = 0;
1472         }
1473         _tool_for_ifname = g_hash_table_new(g_str_hash, g_str_equal);
1474
1475         argv = g_strdup(EXTCAP_ARGUMENT_LIST_INTERFACES);
1476
1477         extcap_callback_info_t cb_info;
1478         cb_info.data = NULL;
1479         cb_info.ifname = NULL;
1480         cb_info.err_str = &error;
1481
1482         extcap_foreach(1, &argv, cb_load_interfaces, cb_info);
1483
1484         g_free(argv);
1485     }
1486 }
1487
1488 /*
1489  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
1490  *
1491  * Local variables:
1492  * c-basic-offset: 4
1493  * tab-width: 8
1494  * indent-tabs-mode: nil
1495  * End:
1496  *
1497  * vi: set shiftwidth=4 tabstop=8 expandtab:
1498  * :indentSize=4:tabSize=8:noTabs=true:
1499  */