📄 ctrl_iface_dbus.c
字号:
/* * WPA Supplicant / dbus-based control interface * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */#include "includes.h"#include <dbus/dbus.h>#include "common.h"#include "eloop.h"#include "wpa.h"#include "wpa_supplicant.h"#include "config.h"#include "eapol_sm.h"#include "wpa_supplicant_i.h"#include "ctrl_iface_dbus.h"#include "ctrl_iface_dbus_handlers.h"#include "l2_packet.h"#include "preauth.h"#include "wpa_ctrl.h"#include "eap.h"#define DBUS_VERSION (DBUS_VERSION_MAJOR << 8 | DBUS_VERSION_MINOR)#define DBUS_VER(major, minor) ((major) << 8 | (minor))#if DBUS_VERSION < DBUS_VER(1,1)#define dbus_watch_get_unix_fd dbus_watch_get_fd#endifstruct ctrl_iface_dbus_priv { DBusConnection *con; int should_dispatch; struct wpa_global *global; u32 next_objid;};static void process_watch(struct ctrl_iface_dbus_priv *iface, DBusWatch *watch, eloop_event_type type){ dbus_connection_ref(iface->con); iface->should_dispatch = 0; if (type == EVENT_TYPE_READ) dbus_watch_handle(watch, DBUS_WATCH_READABLE); else if (type == EVENT_TYPE_WRITE) dbus_watch_handle(watch, DBUS_WATCH_WRITABLE); else if (type == EVENT_TYPE_EXCEPTION) dbus_watch_handle(watch, DBUS_WATCH_ERROR); if (iface->should_dispatch) { while (dbus_connection_get_dispatch_status(iface->con) == DBUS_DISPATCH_DATA_REMAINS) dbus_connection_dispatch(iface->con); iface->should_dispatch = 0; } dbus_connection_unref(iface->con);}static void process_watch_exception(int sock, void *eloop_ctx, void *sock_ctx){ process_watch(eloop_ctx, sock_ctx, EVENT_TYPE_EXCEPTION);}static void process_watch_read(int sock, void *eloop_ctx, void *sock_ctx){ process_watch(eloop_ctx, sock_ctx, EVENT_TYPE_READ);}static void process_watch_write(int sock, void *eloop_ctx, void *sock_ctx){ process_watch(eloop_ctx, sock_ctx, EVENT_TYPE_WRITE);}static void connection_setup_add_watch(struct ctrl_iface_dbus_priv *iface, DBusWatch *watch){ unsigned int flags; int fd; if (!dbus_watch_get_enabled(watch)) return; flags = dbus_watch_get_flags(watch); fd = dbus_watch_get_unix_fd(watch); eloop_register_sock(fd, EVENT_TYPE_EXCEPTION, process_watch_exception, iface, watch); if (flags & DBUS_WATCH_READABLE) { eloop_register_sock(fd, EVENT_TYPE_READ, process_watch_read, iface, watch); } if (flags & DBUS_WATCH_WRITABLE) { eloop_register_sock(fd, EVENT_TYPE_WRITE, process_watch_write, iface, watch); } dbus_watch_set_data(watch, iface, NULL);}static void connection_setup_remove_watch(struct ctrl_iface_dbus_priv *iface, DBusWatch *watch){ unsigned int flags; int fd; flags = dbus_watch_get_flags(watch); fd = dbus_watch_get_unix_fd(watch); eloop_unregister_sock(fd, EVENT_TYPE_EXCEPTION); if (flags & DBUS_WATCH_READABLE) eloop_unregister_sock(fd, EVENT_TYPE_READ); if (flags & DBUS_WATCH_WRITABLE) eloop_unregister_sock(fd, EVENT_TYPE_WRITE); dbus_watch_set_data(watch, NULL, NULL);}static dbus_bool_t add_watch(DBusWatch *watch, void *data){ connection_setup_add_watch(data, watch); return TRUE;}static void remove_watch(DBusWatch *watch, void *data){ connection_setup_remove_watch(data, watch);}static void watch_toggled(DBusWatch *watch, void *data){ if (dbus_watch_get_enabled(watch)) add_watch(watch, data); else remove_watch(watch, data);}static void process_timeout(void *eloop_ctx, void *sock_ctx){ DBusTimeout *timeout = sock_ctx; dbus_timeout_handle(timeout);}static void connection_setup_add_timeout(struct ctrl_iface_dbus_priv *iface, DBusTimeout *timeout){ if (!dbus_timeout_get_enabled(timeout)) return; eloop_register_timeout(0, dbus_timeout_get_interval(timeout) * 1000, process_timeout, iface, timeout); dbus_timeout_set_data(timeout, iface, NULL);}static void connection_setup_remove_timeout(struct ctrl_iface_dbus_priv *iface, DBusTimeout *timeout){ eloop_cancel_timeout(process_timeout, iface, timeout); dbus_timeout_set_data(timeout, NULL, NULL);}static dbus_bool_t add_timeout(DBusTimeout *timeout, void *data){ if (!dbus_timeout_get_enabled(timeout)) return TRUE; connection_setup_add_timeout(data, timeout); return TRUE;}static void remove_timeout(DBusTimeout *timeout, void *data){ connection_setup_remove_timeout(data, timeout);}static void timeout_toggled(DBusTimeout *timeout, void *data){ if (dbus_timeout_get_enabled(timeout)) add_timeout(timeout, data); else remove_timeout(timeout, data);}static void process_wakeup_main(int sig, void *eloop_ctx, void *signal_ctx){ struct ctrl_iface_dbus_priv *iface = signal_ctx; if (sig != SIGPOLL || !iface->con) return; if (dbus_connection_get_dispatch_status(iface->con) != DBUS_DISPATCH_DATA_REMAINS) return; /* Only dispatch once - we do not want to starve other events */ dbus_connection_ref(iface->con); dbus_connection_dispatch(iface->con); dbus_connection_unref(iface->con);}/** * wakeup_main - Attempt to wake our mainloop up * @data: dbus control interface private data * * Try to wake up the main eloop so it will process * dbus events that may have happened. */static void wakeup_main(void *data){ struct ctrl_iface_dbus_priv *iface = data; /* Use SIGPOLL to break out of the eloop select() */ raise(SIGPOLL); iface->should_dispatch = 1;}/** * connection_setup_wakeup_main - Tell dbus about our wakeup_main function * @iface: dbus control interface private data * Returns: 0 on success, -1 on failure * * Register our wakeup_main handler with dbus */static int connection_setup_wakeup_main(struct ctrl_iface_dbus_priv *iface){ if (eloop_register_signal(SIGPOLL, process_wakeup_main, iface)) return -1; dbus_connection_set_wakeup_main_function(iface->con, wakeup_main, iface, NULL); return 0;}/** * wpa_supplicant_dbus_next_objid - Return next available object id * @iface: dbus control interface private data * Returns: Object id */u32 wpa_supplicant_dbus_next_objid (struct ctrl_iface_dbus_priv *iface){ return iface->next_objid++;}/** * wpas_dbus_decompose_object_path - Decompose an interface object path into parts * @path: The dbus object path * @network: (out) the configured network this object path refers to, if any * @bssid: (out) the scanned bssid this object path refers to, if any * Returns: The object path of the network interface this path refers to * * For a given object path, decomposes the object path into object id, network, * and BSSID parts, if those parts exist. */char * wpas_dbus_decompose_object_path(const char *path, char **network, char **bssid){ const unsigned int dev_path_prefix_len = strlen(WPAS_DBUS_PATH_INTERFACES "/"); char *obj_path_only; char *next_sep; /* Be a bit paranoid about path */ if (!path || strncmp(path, WPAS_DBUS_PATH_INTERFACES "/", dev_path_prefix_len)) return NULL; /* Ensure there's something at the end of the path */ if ((path + dev_path_prefix_len)[0] == '\0') return NULL; obj_path_only = strdup(path); if (obj_path_only == NULL) return NULL; next_sep = strchr(obj_path_only + dev_path_prefix_len, '/'); if (next_sep != NULL) { const char *net_part = strstr(next_sep, WPAS_DBUS_NETWORKS_PART "/"); const char *bssid_part = strstr(next_sep, WPAS_DBUS_BSSIDS_PART "/"); if (network && net_part) { /* Deal with a request for a configured network */ const char *net_name = net_part + strlen(WPAS_DBUS_NETWORKS_PART "/"); *network = NULL; if (strlen(net_name)) *network = strdup(net_name); } else if (bssid && bssid_part) { /* Deal with a request for a scanned BSSID */ const char *bssid_name = bssid_part + strlen(WPAS_DBUS_BSSIDS_PART "/"); if (strlen(bssid_name)) *bssid = strdup(bssid_name); else *bssid = NULL; } /* Cut off interface object path before "/" */ *next_sep = '\0'; } return obj_path_only;}/** * wpas_dbus_new_invalid_iface_error - Return a new invalid interface error message * @message: Pointer to incoming dbus message this error refers to * Returns: A dbus error message * * Convenience function to create and return an invalid interface error */DBusMessage * wpas_dbus_new_invalid_iface_error(DBusMessage *message){ return dbus_message_new_error(message, WPAS_ERROR_INVALID_IFACE, "wpa_supplicant knows nothing about " "this interface.");}/** * wpas_dbus_new_invalid_network_error - Return a new invalid network error message * @message: Pointer to incoming dbus message this error refers to * Returns: a dbus error message * * Convenience function to create and return an invalid network error */DBusMessage * wpas_dbus_new_invalid_network_error(DBusMessage *message){ return dbus_message_new_error(message, WPAS_ERROR_INVALID_NETWORK, "The requested network does not exist.");}/** * wpas_dbus_new_invalid_bssid_error - Return a new invalid bssid error message * @message: Pointer to incoming dbus message this error refers to * Returns: a dbus error message * * Convenience function to create and return an invalid bssid error */static DBusMessage * wpas_dbus_new_invalid_bssid_error(DBusMessage *message){ return dbus_message_new_error(message, WPAS_ERROR_INVALID_BSSID, "The BSSID requested was invalid.");}/** * wpas_dispatch_network_method - dispatch messages for configured networks * @message: the incoming dbus message * @wpa_s: a network interface's data * @network_id: id of the configured network we're interested in * Returns: a reply dbus message, or a dbus error message * * This function dispatches all incoming dbus messages for configured networks. */static DBusMessage * wpas_dispatch_network_method(DBusMessage *message, struct wpa_supplicant *wpa_s, int network_id){ DBusMessage *reply = NULL; const char *method = dbus_message_get_member(message); struct wpa_ssid *ssid; ssid = wpa_config_get_network(wpa_s->conf, network_id); if (ssid == NULL) return wpas_dbus_new_invalid_network_error(message); if (!strcmp(method, "set")) reply = wpas_dbus_iface_set_network(message, wpa_s, ssid); else if (!strcmp(method, "enable")) reply = wpas_dbus_iface_enable_network(message, wpa_s, ssid); else if (!strcmp(method, "disable")) reply = wpas_dbus_iface_disable_network(message, wpa_s, ssid); return reply;}/** * wpas_dispatch_bssid_method - dispatch messages for scanned networks * @message: the incoming dbus message * @wpa_s: a network interface's data * @bssid: bssid of the scanned network we're interested in * Returns: a reply dbus message, or a dbus error message * * This function dispatches all incoming dbus messages for scanned networks. */static DBusMessage * wpas_dispatch_bssid_method(DBusMessage *message, struct wpa_supplicant *wpa_s, const char *bssid){ DBusMessage *reply = NULL; const char *method = dbus_message_get_member(message); struct wpa_scan_result * res = NULL; int i; /* Ensure we actually have scan data */ if (wpa_s->scan_results == NULL && wpa_supplicant_get_scan_results(wpa_s) < 0) { reply = wpas_dbus_new_invalid_bssid_error(message); goto out; } /* Find the bssid's scan data */ for (i = 0; i < wpa_s->num_scan_results; i++) { struct wpa_scan_result * search_res = &wpa_s->scan_results[i]; char mac_str[18]; memset(mac_str, 0, sizeof(mac_str)); snprintf(mac_str, sizeof(mac_str) - 1, WPAS_DBUS_BSSID_FORMAT, MAC2STR(search_res->bssid)); if (!strcmp(bssid, mac_str)) { res = search_res; } } if (!res) { reply = wpas_dbus_new_invalid_bssid_error(message); goto out; } /* Dispatch the method call against the scanned bssid */ if (!strcmp(method, "properties")) reply = wpas_dbus_bssid_properties(message, wpa_s, res);out: return reply;}/** * wpas_iface_message_handler - Dispatch messages for interfaces or networks * @connection: Connection to the system message bus * @message: An incoming dbus message * @user_data: A pointer to a dbus control interface data structure * Returns: Whether or not the message was handled * * This function dispatches all incoming dbus messages for network interfaces, * or objects owned by them, such as scanned BSSIDs and configured networks. */static DBusHandlerResult wpas_iface_message_handler(DBusConnection *connection, DBusMessage *message, void *user_data){ struct wpa_supplicant *wpa_s = user_data; const char *method = dbus_message_get_member(message); const char *path = dbus_message_get_path(message); const char *msg_interface = dbus_message_get_interface(message); char *iface_obj_path = NULL; char *network = NULL; char *bssid = NULL; DBusMessage *reply = NULL; /* Caller must specify a message interface */ if (!msg_interface) goto out; iface_obj_path = wpas_dbus_decompose_object_path(path, &network, &bssid); if (iface_obj_path == NULL) { reply = wpas_dbus_new_invalid_iface_error(message); goto out; } /* Make sure the message's object path actually refers to the * wpa_supplicant structure it's supposed to (which is wpa_s) */ if (wpa_supplicant_get_iface_by_dbus_path(wpa_s->global, iface_obj_path) != wpa_s) { reply = wpas_dbus_new_invalid_iface_error(message); goto out; } if (network && !strcmp(msg_interface, WPAS_DBUS_IFACE_NETWORK)) { /* A method for one of this interface's configured networks */ int nid = strtoul(network, NULL, 10); if (errno != EINVAL) reply = wpas_dispatch_network_method(message, wpa_s, nid); else reply = wpas_dbus_new_invalid_network_error(message); } else if (bssid && !strcmp(msg_interface, WPAS_DBUS_IFACE_BSSID)) { /* A method for one of this interface's scanned BSSIDs */ reply = wpas_dispatch_bssid_method(message, wpa_s, bssid); } else if (!strcmp(msg_interface, WPAS_DBUS_IFACE_INTERFACE)) { /* A method for an interface only. */ if (!strcmp(method, "scan")) reply = wpas_dbus_iface_scan(message, wpa_s); else if (!strcmp(method, "scanResults"))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -