#include #include #include #include #include #include #include "wpa_ctrl.h" #include "plugin.h" #define WIRELESS_PATH PLUGIN_ROOT_PATH "/wireless" #define WIRELESS_INTERFACE PLUGIN_ROOT_INTF ".wireless" static int init(plugin_t *plugin, DBusConnection *connection); static void deinit(plugin_t *plugin, DBusConnection *connection); static void handle_incoming(plugin_t *plugin, DBusConnection *connection); static DBusHandlerResult handle_message(DBusConnection *connection, DBusMessage *message, plugin_t *plugin); static DBusHandlerResult select_network(DBusConnection *connection, DBusMessage *message, plugin_t *plugin); static DBusHandlerResult wpa_supplicant_request(DBusConnection *connection, DBusMessage *message, plugin_t *plugin, char *cmd); typedef struct { struct wpa_ctrl *ctrl_conn; const char *interface; } w_plugin_t; static int init(plugin_t *plugin, DBusConnection *connection) { const char *ctrl_iface_dir = "/var/run/wpa_supplicant"; w_plugin_t *w_plugin; w_plugin = malloc(sizeof(w_plugin_t)); if (!w_plugin) { fprintf(stderr, "unable to malloc w_plugin\n"); return -1; } w_plugin->ctrl_conn = NULL; DIR *dir = opendir(ctrl_iface_dir); if (dir) { struct dirent *dent; while ((dent = readdir(dir))) { char *cfile; int flen; if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0) continue; printf("Selected interface '%s'\n", dent->d_name); flen = strlen(ctrl_iface_dir) + strlen(dent->d_name) + 2; cfile = malloc(flen); if (cfile == NULL) return -1; snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, dent->d_name); w_plugin->ctrl_conn = wpa_ctrl_open(cfile); w_plugin->interface = strdup(dent->d_name); free(cfile); break; } closedir(dir); } if (w_plugin->ctrl_conn != NULL) { plugin->fd = wpa_ctrl_get_fd(w_plugin->ctrl_conn); wpa_ctrl_attach(w_plugin->ctrl_conn); } else { /* do not fail, the plugin will try to re-init when needed */ plugin->fd = -1; } plugin->priv = (void *) w_plugin; return 0; } static void deinit(plugin_t *plugin, DBusConnection *connection) { if (plugin->fd > 0) close(plugin->fd); } static void notify_event(DBusConnection *bus, plugin_t *plugin, char *event) { w_plugin_t *w_plugin = (w_plugin_t *) plugin->priv; DBusMessage *message; message = dbus_message_new_signal(WIRELESS_PATH, WIRELESS_INTERFACE, "Event"); dbus_message_append_args(message, DBUS_TYPE_STRING, &event, DBUS_TYPE_STRING, &w_plugin->interface, DBUS_TYPE_INVALID); dbus_connection_send(bus, message, NULL); dbus_connection_flush(bus); dbus_message_unref(message); } static void handle_incoming(plugin_t *plugin, DBusConnection *connection) { w_plugin_t *w_plugin = (w_plugin_t *) plugin->priv; char buf[2048]; size_t len = sizeof(buf); wpa_ctrl_recv(w_plugin->ctrl_conn, buf, &len); buf[len] = '\0'; printf("received event for %s: %s\n", w_plugin->interface, buf); notify_event(connection, plugin, buf); } static DBusHandlerResult handle_message(DBusConnection *connection, DBusMessage *message, plugin_t *plugin) { if (dbus_message_is_method_call(message, WIRELESS_INTERFACE, "ScanResults")) { return wpa_supplicant_request(connection, message, plugin, "SCAN_RESULTS"); } else if (dbus_message_is_method_call(message, WIRELESS_INTERFACE, "ListNetworks")) { return wpa_supplicant_request(connection, message, plugin, "LIST_NETWORKS"); } else if (dbus_message_is_method_call(message, WIRELESS_INTERFACE, "SelectNetwork")) { return select_network(connection, message, plugin); } return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } static DBusHandlerResult select_network(DBusConnection *connection, DBusMessage *message, plugin_t *plugin) { DBusError error; u_int32_t net; char cmd[32]; dbus_error_init (&error); if (!dbus_message_get_args (message, &error, DBUS_TYPE_UINT32, &net, DBUS_TYPE_INVALID)) { fprintf(stderr, "select_network(): failed to read D-BUS message args: %s\n", error.message); dbus_error_free (&error); return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } dbus_error_free (&error); snprintf(cmd, sizeof(cmd), "SELECT_NETWORK %u", net); return wpa_supplicant_request(connection, message, plugin, cmd); } static DBusHandlerResult wpa_supplicant_request(DBusConnection *connection, DBusMessage *message, plugin_t *plugin, char *cmd) { w_plugin_t *w_plugin = (w_plugin_t *) plugin->priv; DBusMessage *reply; char buf[2048]; size_t len; int ret = -1; /* DBus wants a char** for strings, and &char[] == char*, so use temporary variables */ char *tmp_buf; len = sizeof(buf) - 1; if (w_plugin->ctrl_conn) { ret = wpa_ctrl_request(w_plugin->ctrl_conn, cmd, strlen(cmd), buf, &len, NULL); } if (ret == -1) { fprintf(stderr, "connection to wpa_supplicant daemon lost, reconnecting\n"); init(plugin, connection); w_plugin = (w_plugin_t *) plugin->priv; if (w_plugin->ctrl_conn) { ret = wpa_ctrl_request(w_plugin->ctrl_conn, cmd, strlen(cmd), buf, &len, NULL); } } if (ret != 0) { fprintf(stderr, "unable to request command\n"); return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } buf[len] = '\0'; reply = dbus_message_new_method_return(message); tmp_buf = buf; dbus_message_append_args(reply, DBUS_TYPE_STRING, &tmp_buf, DBUS_TYPE_INVALID); dbus_connection_send(connection, reply, NULL); dbus_connection_flush(connection); dbus_message_unref(reply); return DBUS_HANDLER_RESULT_HANDLED; } plugin_t wpa_supplicant_plugin = { .name = "Wireless", .path = WIRELESS_PATH, .init = init, .handle_incoming = handle_incoming, .handle_message = handle_message, .deinit = deinit, };