#include <unistd.h>
#endif
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+
#include <glib.h>
#include <log.h>
#endif
#define EXTCAP_PREF_SIZE 256
+static void extcap_child_watch_cb(GPid pid, gint status _U_, gpointer user_data);
/* internal container, for all the extcap interfaces that have been found.
* will be resetted by every call to extcap_interface_list() and is being
typedef gboolean (*extcap_cb_t)(const gchar *extcap, const gchar *ifname, gchar *output, void *data,
gchar **err_str);
-/* #define ARG_DEBUG */
-#if ARG_DEBUG
-static void extcap_debug_arguments ( extcap_arg *arg_iter );
-#endif
-
static gboolean
extcap_if_exists(const gchar *ifname)
{
}
+static void extcap_free_dlt(gpointer d, gpointer user_data _U_) {
+ if (d == NULL)
+ return;
+
+ g_free(((extcap_dlt *)d)->name);
+ g_free(((extcap_dlt *)d)->display);
+}
+
static gboolean dlt_cb(const gchar *extcap _U_, const gchar *ifname _U_, gchar *output, void *data,
char **err_str) {
- extcap_token_sentence *tokens;
- extcap_dlt *dlts, *dlt_iter, *next;
+ GList *dlts = NULL, *temp = NULL;
+
if_capabilities_t *caps;
GList *linktype_list = NULL;
data_link_info_t *data_link_info;
+ extcap_dlt * dlt_item;
- tokens = extcap_tokenize_sentences(output);
- extcap_parse_dlts(tokens, &dlts);
-
- extcap_free_tokenized_sentence_list(tokens);
+ dlts = extcap_parse_dlts(output);
+ temp = dlts;
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Extcap pipe %s ", extcap);
caps = (if_capabilities_t *) g_malloc(sizeof *caps);
caps->can_set_rfmon = FALSE;
- dlt_iter = dlts;
- while (dlt_iter != NULL ) {
- g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG,
- " DLT %d name=\"%s\" display=\"%s\" ", dlt_iter->number,
- dlt_iter->name, dlt_iter->display);
-
- data_link_info = g_new(data_link_info_t, 1);
- data_link_info->dlt = dlt_iter->number;
- data_link_info->name = g_strdup(dlt_iter->name);
- data_link_info->description = g_strdup(dlt_iter->display);
- linktype_list = g_list_append(linktype_list, data_link_info);
- dlt_iter = dlt_iter->next_dlt;
+ while (dlts) {
+ dlt_item = (extcap_dlt *)dlts->data;
+ if (dlt_item) {
+ g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG,
+ " DLT %d name=\"%s\" display=\"%s\" ", dlt_item->number,
+ dlt_item->name, dlt_item->display);
+
+ data_link_info = g_new(data_link_info_t, 1);
+ data_link_info->dlt = dlt_item->number;
+ data_link_info->name = g_strdup(dlt_item->name);
+ data_link_info->description = g_strdup(dlt_item->display);
+ linktype_list = g_list_append(linktype_list, data_link_info);
+ }
+
+ dlts = g_list_next(dlts);
}
/* Check to see if we built a list */
g_free(caps);
}
- dlt_iter = dlts;
- while (dlt_iter != NULL ) {
- next = dlt_iter->next_dlt;
- extcap_free_dlt(dlt_iter);
- dlt_iter = next;
- }
+ g_list_foreach(temp, extcap_free_dlt, NULL);
return FALSE;
}
return caps;
}
+static void extcap_free_interface(gpointer i, gpointer user_data _U_) {
+
+ extcap_interface * interface = (extcap_interface *)i;
+
+ if ( i == NULL )
+ return;
+
+ g_free(interface->call);
+ g_free(interface->display);
+ g_free(interface->version);
+}
+
static gboolean interfaces_cb(const gchar *extcap, const gchar *ifname _U_, gchar *output, void *data,
char **err_str _U_) {
GList **il = (GList **) data;
- extcap_token_sentence *tokens;
- extcap_interface *interfaces, *int_iter; /*, *next; */
- if_info_t *if_info;
+ GList *interfaces = NULL, *walker = NULL;
+ extcap_interface *int_iter = NULL;
+ if_info_t *if_info = NULL;
- tokens = extcap_tokenize_sentences(output);
- extcap_parse_interfaces(tokens, &interfaces);
-
- extcap_free_tokenized_sentence_list(tokens);
+ interfaces = extcap_parse_interfaces(output);
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Extcap pipe %s ", extcap);
- int_iter = interfaces;
- while (int_iter != NULL ) {
+ walker = interfaces;
+ while (walker != NULL ) {
+ int_iter = (extcap_interface *)walker->data;
if ( int_iter->if_type == EXTCAP_SENTENCE_INTERFACE && extcap_if_exists(int_iter->call) )
{
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_WARNING, "Extcap interface \"%s\" is already provided by \"%s\" ",
int_iter->call, (gchar *)extcap_if_executable(int_iter->call) );
- int_iter = int_iter->next_interface;
+ walker = g_list_next(walker);
continue;
}
* interfaces) are handled internally */
extcap_tool_add(extcap, int_iter);
- int_iter = int_iter->next_interface;
+ walker = g_list_next(walker);
}
- extcap_free_interface(interfaces);
+
+ g_list_foreach(interfaces, extcap_free_interface, NULL);
return TRUE;
}
extcap_pref_for_argument(const gchar *ifname, struct _extcap_arg * arg) {
struct preference * pref = NULL;
- GRegex * regex = g_regex_new ("[-]+", (GRegexCompileFlags) 0, (GRegexMatchFlags) 0, NULL );
- if (regex) {
+ GRegex * regex_name = g_regex_new ("[-]+", (GRegexCompileFlags) 0, (GRegexMatchFlags) 0, NULL );
+ GRegex * regex_ifname = g_regex_new ("(?![a-zA-Z1-9_]).", (GRegexCompileFlags) 0, (GRegexMatchFlags) 0, NULL );
+ if (regex_name && regex_ifname) {
if ( prefs_find_module("extcap") ) {
- gchar * pref_name = g_regex_replace(regex, arg->call, strlen(arg->call), 0, "", (GRegexMatchFlags) 0, NULL );
- gchar * pref_ifname = g_strdup(g_strconcat(ifname, ".", pref_name, NULL));
+ gchar * pref_name = g_regex_replace(regex_name, arg->call, strlen(arg->call), 0, "", (GRegexMatchFlags) 0, NULL );
+ gchar * ifname_underscore = g_regex_replace(regex_ifname, ifname, strlen(ifname), 0, "_", (GRegexMatchFlags) 0, NULL );
+ gchar * ifname_lowercase = g_ascii_strdown(ifname_underscore, -1);
+ gchar * pref_ifname = g_strconcat(ifname_lowercase, ".", pref_name, NULL);
pref = prefs_find_preference(prefs_find_module("extcap"), pref_ifname);
g_free(pref_name);
+ g_free(ifname_underscore);
+ g_free(ifname_lowercase);
g_free(pref_ifname);
}
- g_regex_unref(regex);
+ }
+ if (regex_name) {
+ g_regex_unref(regex_name);
+ }
+ if (regex_ifname) {
+ g_regex_unref(regex_ifname);
}
return pref;
static gboolean search_cb(const gchar *extcap _U_, const gchar *ifname _U_, gchar *output, void *data,
char **err_str _U_) {
- extcap_token_sentence *tokens = NULL;
GList *arguments = NULL;
GList **il = (GList **) data;
module_t * dev_module = NULL;
- tokens = extcap_tokenize_sentences(output);
- arguments = extcap_parse_args(tokens);
-
- extcap_free_tokenized_sentence_list(tokens);
-
-#if ARG_DEBUG
- extcap_debug_arguments ( arguments );
-#endif
+ arguments = extcap_parse_args(output);
dev_module = prefs_find_module("extcap");
if ( dev_module ) {
GList * walker = arguments;
- GRegex * regex = g_regex_new ("[-]+", (GRegexCompileFlags) 0, (GRegexMatchFlags) 0, NULL );
- if (regex) {
+ GRegex * regex_name = g_regex_new ("[-]+", (GRegexCompileFlags) 0, (GRegexMatchFlags) 0, NULL );
+ GRegex * regex_ifname = g_regex_new ("(?![a-zA-Z1-9_]).", (GRegexCompileFlags) 0, (GRegexMatchFlags) 0, NULL );
+ if (regex_name && regex_ifname) {
while ( walker != NULL ) {
extcap_arg * arg = (extcap_arg *)walker->data;
arg->device_name = g_strdup(ifname);
if ( arg->save ) {
struct preference * pref = NULL;
- gchar * pref_name = g_regex_replace(regex, arg->call, strlen(arg->call), 0, "", (GRegexMatchFlags) 0, NULL );
- gchar * pref_ifname = g_strdup(g_strconcat(ifname, ".", pref_name, NULL));
+ gchar * pref_name = g_regex_replace(regex_name, arg->call, strlen(arg->call), 0, "", (GRegexMatchFlags) 0, NULL );
+ gchar * ifname_underscore = g_regex_replace(regex_ifname, ifname, strlen(ifname), 0, "_", (GRegexMatchFlags) 0, NULL );
+ gchar * ifname_lowercase = g_ascii_strdown(ifname_underscore, -1);
+ gchar * pref_ifname = g_strconcat(ifname_lowercase, ".", pref_name, NULL);
if ( ( pref = prefs_find_preference(dev_module, pref_ifname) ) == NULL ) {
/* Set an initial value */
}
g_free(pref_name);
+ g_free(ifname_underscore);
+ g_free(ifname_lowercase);
g_free(pref_ifname);
}
walker = g_list_next(walker);
}
- g_regex_unref(regex);
+ }
+ if (regex_name) {
+ g_regex_unref(regex_name);
+ }
+ if (regex_ifname) {
+ g_regex_unref(regex_ifname);
}
}
return found;
}
-void extcap_if_cleanup(capture_options * capture_opts) {
+/* taken from capchild/capture_sync.c */
+static gboolean pipe_data_available(int pipe_fd) {
+#ifdef _WIN32 /* PeekNamedPipe */
+ HANDLE hPipe = (HANDLE) _get_osfhandle(pipe_fd);
+ DWORD bytes_avail;
+
+ if (hPipe == INVALID_HANDLE_VALUE)
+ return FALSE;
+
+ if (! PeekNamedPipe(hPipe, NULL, 0, NULL, &bytes_avail, NULL))
+ return FALSE;
+
+ if (bytes_avail > 0)
+ return TRUE;
+ return FALSE;
+#else /* select */
+ fd_set rfds;
+ struct timeval timeout;
+
+ FD_ZERO(&rfds);
+ FD_SET(pipe_fd, &rfds);
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 0;
+
+ if (select(pipe_fd+1, &rfds, NULL, NULL, &timeout) > 0)
+ return TRUE;
+
+ return FALSE;
+#endif
+}
+
+void extcap_if_cleanup(capture_options * capture_opts, gchar ** errormsg) {
interface_options interface_opts;
+ extcap_userdata * userdata;
guint icnt = 0;
+ gboolean overwrite_exitcode;
+ gchar * buffer;
+#define STDERR_BUFFER_SIZE 1024
for (icnt = 0; icnt < capture_opts->ifaces->len; icnt++) {
interface_opts = g_array_index(capture_opts->ifaces, interface_options,
if (interface_opts.if_type != IF_EXTCAP)
continue;
+ overwrite_exitcode = FALSE;
+
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG,
"Extcap [%s] - Cleaning up fifo: %s; PID: %d", interface_opts.name,
interface_opts.extcap_fifo, interface_opts.extcap_pid);
"Extcap [%s] - Closing spawned PID: %d", interface_opts.name,
interface_opts.extcap_pid);
+ userdata = (extcap_userdata *) interface_opts.extcap_userdata;
+ if ( userdata )
+ {
+ if (userdata->extcap_stderr_rd > 0 && pipe_data_available(userdata->extcap_stderr_rd) )
+ {
+ buffer = (gchar * )g_malloc0(sizeof(gchar) * STDERR_BUFFER_SIZE + 1);
+#ifdef _WIN32
+ win32_readfrompipe((HANDLE)_get_osfhandle(userdata->extcap_stderr_rd), STDERR_BUFFER_SIZE, buffer);
+#else
+ if (read(userdata->extcap_stderr_rd, buffer, sizeof(gchar) * STDERR_BUFFER_SIZE) <= 0 )
+ buffer[0] = '\0';
+#endif
+ if ( strlen ( buffer) > 0 )
+ {
+ userdata->extcap_stderr = g_strdup_printf("%s", buffer);
+ userdata->exitcode = 1;
+ }
+ g_free(buffer);
+ }
+
+#ifndef _WIN32
+ /* Final child watch may not have been called */
+ if ( interface_opts.extcap_child_watch != 0 )
+ {
+ extcap_child_watch_cb(userdata->pid, 0, capture_opts);
+ /* it will have changed in extcap_child_watch_cb */
+ interface_opts = g_array_index(capture_opts->ifaces, interface_options,
+ icnt);
+ }
+#endif
+
+ if ( userdata->extcap_stderr != NULL )
+ overwrite_exitcode = TRUE;
+
+ if ( overwrite_exitcode || userdata->exitcode != 0 )
+ {
+ if ( userdata->extcap_stderr != 0 )
+ {
+ if ( *errormsg == NULL )
+ *errormsg = g_strdup_printf("Error by extcap pipe: %s", userdata->extcap_stderr);
+ else
+ {
+ gchar * temp = g_strconcat ( *errormsg, "\nError by extcap pipe: " ,userdata->extcap_stderr, NULL );
+ g_free(*errormsg);
+ *errormsg = temp;
+ }
+ g_free (userdata->extcap_stderr );
+ }
+
+ userdata->extcap_stderr = NULL;
+ userdata->exitcode = 0;
+ }
+ }
+
+ if (interface_opts.extcap_child_watch > 0)
+ {
+ g_source_remove(interface_opts.extcap_child_watch);
+ interface_opts.extcap_child_watch = 0;
+ }
+
if (interface_opts.extcap_pid != INVALID_EXTCAP_PID)
{
#ifdef _WIN32
#endif
g_spawn_close_pid(interface_opts.extcap_pid);
interface_opts.extcap_pid = INVALID_EXTCAP_PID;
+
+ g_free(interface_opts.extcap_userdata);
+ interface_opts.extcap_userdata = NULL;
}
/* Make sure modified interface_opts is saved in capture_opts. */
return FALSE;
}
-static void extcap_child_watch_cb(GPid pid, gint status _U_, gpointer user_data)
+void extcap_child_watch_cb(GPid pid, gint status _U_, gpointer user_data)
{
guint i;
interface_options interface_opts;
- capture_options *capture_opts = (capture_options *)user_data;
+ extcap_userdata * userdata = NULL;
+ capture_options * capture_opts = (capture_options *)(user_data);
+
+ if ( capture_opts == NULL || capture_opts->ifaces == NULL || capture_opts->ifaces->len == 0 )
+ return;
/* Close handle to child process. */
g_spawn_close_pid(pid);
interface_opts = g_array_index(capture_opts->ifaces, interface_options, i);
if (interface_opts.extcap_pid == pid)
{
- interface_opts.extcap_pid = INVALID_EXTCAP_PID;
+ userdata = (extcap_userdata *)interface_opts.extcap_userdata;
+ if ( userdata != NULL )
+ {
+ interface_opts.extcap_pid = INVALID_EXTCAP_PID;
+ userdata->exitcode = 0;
+#ifndef _WIN32
+ if ( WIFEXITED(status) )
+ {
+ if ( WEXITSTATUS(status) != 0 )
+ userdata->exitcode = WEXITSTATUS(status);
+ }
+ else
+ userdata->exitcode = G_SPAWN_ERROR_FAILED;
+#else
+ if (status != 0)
+ userdata->exitcode = status;
+#endif
+ if ( status == 0 && userdata->extcap_stderr != NULL )
+ userdata->exitcode = 1;
+ }
g_source_remove(interface_opts.extcap_child_watch);
interface_opts.extcap_child_watch = 0;
GPtrArray * extcap_prepare_arguments(interface_options interface_opts)
{
GPtrArray *result = NULL;
-#if ARG_DEBUG
- gchar **tmp;
- int tmp_i;
-#endif
if (interface_opts.if_type == IF_EXTCAP )
{
add_arg(NULL);
#undef add_arg
-#if ARG_DEBUG
- /* Dump commandline parameters sent to extcap. */
- for (tmp = (gchar **)result->pdata, tmp_i = 0; *tmp && **tmp; ++tmp_i, ++tmp)
- {
- g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "argv[%d]: %s", tmp_i, *tmp);
- }
-#endif
-
}
return result;
{
guint i;
interface_options interface_opts;
+ extcap_userdata * userdata;
for (i = 0; i < capture_opts->ifaces->len; i++)
{
/* Create extcap call */
args = extcap_prepare_arguments(interface_opts);
- interface_opts.extcap_userdata = NULL;
+ userdata = g_new0(extcap_userdata, 1);
- pid = extcap_spawn_async(&interface_opts, args );
+ pid = extcap_spawn_async(userdata, args );
g_ptr_array_foreach(args, (GFunc)g_free, NULL);
g_ptr_array_free(args, TRUE);
if ( pid == INVALID_EXTCAP_PID )
+ {
+ g_free(userdata);
continue;
+ }
interface_opts.extcap_pid = pid;
interface_opts.extcap_child_watch =
g_child_watch_add(pid, extcap_child_watch_cb, (gpointer)capture_opts);
- capture_opts->ifaces = g_array_remove_index(capture_opts->ifaces, i);
- g_array_insert_val(capture_opts->ifaces, i, interface_opts);
#ifdef _WIN32
/* On Windows, wait for extcap to connect to named pipe.
{
extcap_wait_for_pipe(pipe_h, pid);
}
+
#endif
+
+ interface_opts.extcap_userdata = (gpointer) userdata;
+
+ capture_opts->ifaces = g_array_remove_index(capture_opts->ifaces, i);
+ g_array_insert_val(capture_opts->ifaces, i, interface_opts);
}
return TRUE;
return TRUE;
}
-#if ARG_DEBUG
-void extcap_debug_arguments ( extcap_arg *arg_iter )
-{
- extcap_value *v = NULL;
- GList *walker = NULL;
-
- printf("debug - parser dump\n");
- while (arg_iter != NULL) {
- printf("ARG %d call=%s display=\"%s\" type=", arg_iter->arg_num, arg_iter->call, arg_iter->display);
-
- switch (arg_iter->arg_type) {
- case EXTCAP_ARG_INTEGER:
- printf("int\n");
- break;
- case EXTCAP_ARG_UNSIGNED:
- printf("unsigned\n");
- break;
- case EXTCAP_ARG_LONG:
- printf("long\n");
- break;
- case EXTCAP_ARG_DOUBLE:
- printf("double\n");
- break;
- case EXTCAP_ARG_BOOLEAN:
- printf("boolean\n");
- break;
- case EXTCAP_ARG_MENU:
- printf("menu\n");
- break;
- case EXTCAP_ARG_RADIO:
- printf("radio\n");
- break;
- case EXTCAP_ARG_SELECTOR:
- printf("selctor\n");
- break;
- case EXTCAP_ARG_STRING:
- printf ( "string\n" );
- break;
- case EXTCAP_ARG_PASSWORD:
- printf ( "PASSWORD\n" );
- break;
- case EXTCAP_ARG_MULTICHECK:
- printf ( "unknown\n" );
- break;
- case EXTCAP_ARG_UNKNOWN:
- printf ( "unknown\n" );
- break;
- }
-
- if (arg_iter->range_start != NULL && arg_iter->range_end != NULL) {
- printf("\tRange: ");
- extcap_printf_complex(arg_iter->range_start);
- printf(" - ");
- extcap_printf_complex(arg_iter->range_end);
- printf("\n");
- }
-
- for ( walker = g_list_first ( arg_iter->value_list ); walker; walker = walker->next )
- {
- v = (extcap_value *)walker->data;
- if (v->is_default)
- printf("*");
- printf("\tcall=\"%p\" display=\"%p\"\n", v->call, v->display);
- printf("\tcall=\"%s\" display=\"%s\"\n", v->call, v->display);
- }
-
- arg_iter = arg_iter->next_arg;
- }
-}
-#endif
-
/*
* Editor modelines - http://www.wireshark.org/tools/modelines.html
*