| /* |
| * WPA Supplicant / dbus-based control interface |
| * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc. |
| * |
| * This software may be distributed under the terms of the BSD license. |
| * See README for more details. |
| */ |
| |
| #include "includes.h" |
| #include <dbus/dbus.h> |
| |
| #include "common.h" |
| #include "eloop.h" |
| #include "wps/wps.h" |
| #include "../config.h" |
| #include "../wpa_supplicant_i.h" |
| #include "../bss.h" |
| #include "dbus_old.h" |
| #include "dbus_old_handlers.h" |
| #include "dbus_common_i.h" |
| |
| |
| /** |
| * 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 = os_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 = os_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 = os_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_txt) |
| { |
| u8 bssid[ETH_ALEN]; |
| struct wpa_bss *bss; |
| |
| if (hexstr2bin(bssid_txt, bssid, ETH_ALEN) < 0) |
| return wpas_dbus_new_invalid_bssid_error(message); |
| |
| bss = wpa_bss_get_bssid(wpa_s, bssid); |
| if (bss == NULL) |
| return wpas_dbus_new_invalid_bssid_error(message); |
| |
| /* Dispatch the method call against the scanned bssid */ |
| if (os_strcmp(dbus_message_get_member(message), "properties") == 0) |
| return wpas_dbus_bssid_properties(message, wpa_s, bss); |
| |
| return NULL; |
| } |
| |
| |
| /** |
| * 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")) |
| reply = wpas_dbus_iface_scan_results(message, wpa_s); |
| else if (!strcmp(method, "addNetwork")) |
| reply = wpas_dbus_iface_add_network(message, wpa_s); |
| else if (!strcmp(method, "removeNetwork")) |
| reply = wpas_dbus_iface_remove_network(message, wpa_s); |
| else if (!strcmp(method, "selectNetwork")) |
| reply = wpas_dbus_iface_select_network(message, wpa_s); |
| else if (!strcmp(method, "capabilities")) |
| reply = wpas_dbus_iface_capabilities(message, wpa_s); |
| else if (!strcmp(method, "disconnect")) |
| reply = wpas_dbus_iface_disconnect(message, wpa_s); |
| else if (!strcmp(method, "setAPScan")) |
| reply = wpas_dbus_iface_set_ap_scan(message, wpa_s); |
| else if (!strcmp(method, "setSmartcardModules")) |
| reply = wpas_dbus_iface_set_smartcard_modules(message, |
| wpa_s); |
| else if (!strcmp(method, "state")) |
| reply = wpas_dbus_iface_get_state(message, wpa_s); |
| else if (!strcmp(method, "scanning")) |
| reply = wpas_dbus_iface_get_scanning(message, wpa_s); |
| else if (!strcmp(method, "setBlobs")) |
| reply = wpas_dbus_iface_set_blobs(message, wpa_s); |
| else if (!strcmp(method, "removeBlobs")) |
| reply = wpas_dbus_iface_remove_blobs(message, wpa_s); |
| #ifdef CONFIG_WPS |
| else if (!os_strcmp(method, "wpsPbc")) |
| reply = wpas_dbus_iface_wps_pbc(message, wpa_s); |
| else if (!os_strcmp(method, "wpsPin")) |
| reply = wpas_dbus_iface_wps_pin(message, wpa_s); |
| else if (!os_strcmp(method, "wpsReg")) |
| reply = wpas_dbus_iface_wps_reg(message, wpa_s); |
| #endif /* CONFIG_WPS */ |
| else if (!os_strcmp(method, "flush")) |
| reply = wpas_dbus_iface_flush(message, wpa_s); |
| } |
| |
| /* If the message was handled, send back the reply */ |
| if (reply) { |
| if (!dbus_message_get_no_reply(message)) |
| dbus_connection_send(connection, reply, NULL); |
| dbus_message_unref(reply); |
| } |
| |
| out: |
| os_free(iface_obj_path); |
| os_free(network); |
| os_free(bssid); |
| return reply ? DBUS_HANDLER_RESULT_HANDLED : |
| DBUS_HANDLER_RESULT_NOT_YET_HANDLED; |
| } |
| |
| |
| /** |
| * wpas_message_handler - dispatch incoming dbus messages |
| * @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 to the correct |
| * handlers, depending on what the message's target object path is, |
| * and what the method call is. |
| */ |
| static DBusHandlerResult wpas_message_handler(DBusConnection *connection, |
| DBusMessage *message, void *user_data) |
| { |
| struct wpas_dbus_priv *ctrl_iface = user_data; |
| const char *method; |
| const char *path; |
| const char *msg_interface; |
| DBusMessage *reply = NULL; |
| |
| method = dbus_message_get_member(message); |
| path = dbus_message_get_path(message); |
| msg_interface = dbus_message_get_interface(message); |
| if (!method || !path || !ctrl_iface || !msg_interface) |
| return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; |
| |
| /* Validate the method interface */ |
| if (strcmp(msg_interface, WPAS_DBUS_INTERFACE) != 0) |
| return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; |
| |
| if (!strcmp(path, WPAS_DBUS_PATH)) { |
| /* dispatch methods against our global dbus interface here */ |
| if (!strcmp(method, "addInterface")) { |
| reply = wpas_dbus_global_add_interface( |
| message, ctrl_iface->global); |
| } else if (!strcmp(method, "removeInterface")) { |
| reply = wpas_dbus_global_remove_interface( |
| message, ctrl_iface->global); |
| } else if (!strcmp(method, "getInterface")) { |
| reply = wpas_dbus_global_get_interface( |
| message, ctrl_iface->global); |
| } else if (!strcmp(method, "setDebugParams")) { |
| reply = wpas_dbus_global_set_debugparams( |
| message, ctrl_iface->global); |
| } |
| } |
| |
| /* If the message was handled, send back the reply */ |
| if (reply) { |
| if (!dbus_message_get_no_reply(message)) |
| dbus_connection_send(connection, reply, NULL); |
| dbus_message_unref(reply); |
| } |
| |
| return reply ? DBUS_HANDLER_RESULT_HANDLED : |
| DBUS_HANDLER_RESULT_NOT_YET_HANDLED; |
| } |
| |
| |
| /** |
| * wpa_supplicant_dbus_notify_scan_results - Send a scan results signal |
| * @wpa_s: %wpa_supplicant network interface data |
| * Returns: 0 on success, -1 on failure |
| * |
| * Notify listeners that this interface has updated scan results. |
| */ |
| void wpa_supplicant_dbus_notify_scan_results(struct wpa_supplicant *wpa_s) |
| { |
| struct wpas_dbus_priv *iface = wpa_s->global->dbus; |
| DBusMessage *_signal; |
| |
| /* Do nothing if the control interface is not turned on */ |
| if (iface == NULL) |
| return; |
| |
| _signal = dbus_message_new_signal(wpa_s->dbus_path, |
| WPAS_DBUS_IFACE_INTERFACE, |
| "ScanResultsAvailable"); |
| if (_signal == NULL) { |
| wpa_printf(MSG_ERROR, "dbus: Not enough memory to send scan " |
| "results signal"); |
| return; |
| } |
| dbus_connection_send(iface->con, _signal, NULL); |
| dbus_message_unref(_signal); |
| } |
| |
| |
| /** |
| * wpa_supplicant_dbus_notify_state_change - Send a state change signal |
| * @wpa_s: %wpa_supplicant network interface data |
| * @new_state: new state wpa_supplicant is entering |
| * @old_state: old state wpa_supplicant is leaving |
| * Returns: 0 on success, -1 on failure |
| * |
| * Notify listeners that wpa_supplicant has changed state |
| */ |
| void wpa_supplicant_dbus_notify_state_change(struct wpa_supplicant *wpa_s, |
| enum wpa_states new_state, |
| enum wpa_states old_state) |
| { |
| struct wpas_dbus_priv *iface; |
| DBusMessage *_signal = NULL; |
| const char *new_state_str, *old_state_str; |
| |
| if (wpa_s->dbus_path == NULL) |
| return; /* Skip signal since D-Bus setup is not yet ready */ |
| |
| /* Do nothing if the control interface is not turned on */ |
| if (wpa_s->global == NULL) |
| return; |
| iface = wpa_s->global->dbus; |
| if (iface == NULL) |
| return; |
| |
| /* Only send signal if state really changed */ |
| if (new_state == old_state) |
| return; |
| |
| _signal = dbus_message_new_signal(wpa_s->dbus_path, |
| WPAS_DBUS_IFACE_INTERFACE, |
| "StateChange"); |
| if (_signal == NULL) { |
| wpa_printf(MSG_ERROR, |
| "dbus: wpa_supplicant_dbus_notify_state_change: " |
| "could not create dbus signal; likely out of " |
| "memory"); |
| return; |
| } |
| |
| new_state_str = wpa_supplicant_state_txt(new_state); |
| old_state_str = wpa_supplicant_state_txt(old_state); |
| if (new_state_str == NULL || old_state_str == NULL) { |
| wpa_printf(MSG_ERROR, |
| "dbus: wpa_supplicant_dbus_notify_state_change: " |
| "Could not convert state strings"); |
| goto out; |
| } |
| |
| if (!dbus_message_append_args(_signal, |
| DBUS_TYPE_STRING, &new_state_str, |
| DBUS_TYPE_STRING, &old_state_str, |
| DBUS_TYPE_INVALID)) { |
| wpa_printf(MSG_ERROR, |
| "dbus: wpa_supplicant_dbus_notify_state_change: " |
| "Not enough memory to construct state change " |
| "signal"); |
| goto out; |
| } |
| |
| dbus_connection_send(iface->con, _signal, NULL); |
| |
| out: |
| dbus_message_unref(_signal); |
| } |
| |
| |
| /** |
| * wpa_supplicant_dbus_notify_scanning - send scanning status |
| * @wpa_s: %wpa_supplicant network interface data |
| * Returns: 0 on success, -1 on failure |
| * |
| * Notify listeners of interface scanning state changes |
| */ |
| void wpa_supplicant_dbus_notify_scanning(struct wpa_supplicant *wpa_s) |
| { |
| struct wpas_dbus_priv *iface = wpa_s->global->dbus; |
| DBusMessage *_signal; |
| dbus_bool_t scanning = wpa_s->scanning ? TRUE : FALSE; |
| |
| /* Do nothing if the control interface is not turned on */ |
| if (iface == NULL) |
| return; |
| |
| _signal = dbus_message_new_signal(wpa_s->dbus_path, |
| WPAS_DBUS_IFACE_INTERFACE, |
| "Scanning"); |
| if (_signal == NULL) { |
| wpa_printf(MSG_ERROR, "dbus: Not enough memory to send scan " |
| "results signal"); |
| return; |
| } |
| |
| if (dbus_message_append_args(_signal, |
| DBUS_TYPE_BOOLEAN, &scanning, |
| DBUS_TYPE_INVALID)) { |
| dbus_connection_send(iface->con, _signal, NULL); |
| } else { |
| wpa_printf(MSG_ERROR, "dbus: Not enough memory to construct " |
| "signal"); |
| } |
| dbus_message_unref(_signal); |
| } |
| |
| |
| #ifdef CONFIG_WPS |
| void wpa_supplicant_dbus_notify_wps_cred(struct wpa_supplicant *wpa_s, |
| const struct wps_credential *cred) |
| { |
| struct wpas_dbus_priv *iface; |
| DBusMessage *_signal = NULL; |
| |
| /* Do nothing if the control interface is not turned on */ |
| if (wpa_s->global == NULL) |
| return; |
| iface = wpa_s->global->dbus; |
| if (iface == NULL) |
| return; |
| |
| _signal = dbus_message_new_signal(wpa_s->dbus_path, |
| WPAS_DBUS_IFACE_INTERFACE, |
| "WpsCred"); |
| if (_signal == NULL) { |
| wpa_printf(MSG_ERROR, |
| "dbus: wpa_supplicant_dbus_notify_wps_cred: " |
| "Could not create dbus signal; likely out of " |
| "memory"); |
| return; |
| } |
| |
| if (!dbus_message_append_args(_signal, |
| DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, |
| &cred->cred_attr, cred->cred_attr_len, |
| DBUS_TYPE_INVALID)) { |
| wpa_printf(MSG_ERROR, |
| "dbus: wpa_supplicant_dbus_notify_wps_cred: " |
| "Not enough memory to construct signal"); |
| goto out; |
| } |
| |
| dbus_connection_send(iface->con, _signal, NULL); |
| |
| out: |
| dbus_message_unref(_signal); |
| } |
| #else /* CONFIG_WPS */ |
| void wpa_supplicant_dbus_notify_wps_cred(struct wpa_supplicant *wpa_s, |
| const struct wps_credential *cred) |
| { |
| } |
| #endif /* CONFIG_WPS */ |
| |
| void wpa_supplicant_dbus_notify_certification(struct wpa_supplicant *wpa_s, |
| int depth, const char *subject, |
| const char *cert_hash, |
| const struct wpabuf *cert) |
| { |
| struct wpas_dbus_priv *iface; |
| DBusMessage *_signal = NULL; |
| const char *hash; |
| const char *cert_hex; |
| int cert_hex_len; |
| |
| /* Do nothing if the control interface is not turned on */ |
| if (wpa_s->global == NULL) |
| return; |
| iface = wpa_s->global->dbus; |
| if (iface == NULL) |
| return; |
| |
| _signal = dbus_message_new_signal(wpa_s->dbus_path, |
| WPAS_DBUS_IFACE_INTERFACE, |
| "Certification"); |
| if (_signal == NULL) { |
| wpa_printf(MSG_ERROR, |
| "dbus: wpa_supplicant_dbus_notify_certification: " |
| "Could not create dbus signal; likely out of " |
| "memory"); |
| return; |
| } |
| |
| hash = cert_hash ? cert_hash : ""; |
| cert_hex = cert ? wpabuf_head(cert) : ""; |
| cert_hex_len = cert ? wpabuf_len(cert) : 0; |
| |
| if (!dbus_message_append_args(_signal, |
| DBUS_TYPE_INT32,&depth, |
| DBUS_TYPE_STRING, &subject, |
| DBUS_TYPE_STRING, &hash, |
| DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, |
| &cert_hex, cert_hex_len, |
| DBUS_TYPE_INVALID)) { |
| wpa_printf(MSG_ERROR, |
| "dbus: wpa_supplicant_dbus_notify_certification: " |
| "Not enough memory to construct signal"); |
| goto out; |
| } |
| |
| dbus_connection_send(iface->con, _signal, NULL); |
| |
| out: |
| dbus_message_unref(_signal); |
| |
| } |
| |
| |
| /** |
| * wpa_supplicant_dbus_ctrl_iface_init - Initialize dbus control interface |
| * @global: Pointer to global data from wpa_supplicant_init() |
| * Returns: 0 on success, -1 on failure |
| * |
| * Initialize the dbus control interface and start receiving commands from |
| * external programs over the bus. |
| */ |
| int wpa_supplicant_dbus_ctrl_iface_init(struct wpas_dbus_priv *iface) |
| { |
| DBusError error; |
| int ret = -1; |
| DBusObjectPathVTable wpas_vtable = { |
| NULL, &wpas_message_handler, NULL, NULL, NULL, NULL |
| }; |
| |
| /* Register the message handler for the global dbus interface */ |
| if (!dbus_connection_register_object_path(iface->con, |
| WPAS_DBUS_PATH, &wpas_vtable, |
| iface)) { |
| wpa_printf(MSG_ERROR, "dbus: Could not set up message " |
| "handler"); |
| return -1; |
| } |
| |
| /* Register our service with the message bus */ |
| dbus_error_init(&error); |
| switch (dbus_bus_request_name(iface->con, WPAS_DBUS_SERVICE, |
| 0, &error)) { |
| case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER: |
| ret = 0; |
| break; |
| case DBUS_REQUEST_NAME_REPLY_EXISTS: |
| case DBUS_REQUEST_NAME_REPLY_IN_QUEUE: |
| case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER: |
| wpa_printf(MSG_ERROR, "dbus: Could not request service name: " |
| "already registered"); |
| break; |
| default: |
| wpa_printf(MSG_ERROR, "dbus: Could not request service name: " |
| "%s %s", error.name, error.message); |
| break; |
| } |
| dbus_error_free(&error); |
| |
| if (ret != 0) |
| return -1; |
| |
| wpa_printf(MSG_DEBUG, "Providing DBus service '" WPAS_DBUS_SERVICE |
| "'."); |
| |
| return 0; |
| } |
| |
| |
| /** |
| * wpas_dbus_register_new_iface - Register a new interface with dbus |
| * @wpa_s: %wpa_supplicant interface description structure to register |
| * Returns: 0 on success, -1 on error |
| * |
| * Registers a new interface with dbus and assigns it a dbus object path. |
| */ |
| int wpas_dbus_register_iface(struct wpa_supplicant *wpa_s) |
| { |
| struct wpas_dbus_priv *ctrl_iface = wpa_s->global->dbus; |
| DBusConnection * con; |
| u32 next; |
| DBusObjectPathVTable vtable = { |
| NULL, &wpas_iface_message_handler, NULL, NULL, NULL, NULL |
| }; |
| |
| /* Do nothing if the control interface is not turned on */ |
| if (ctrl_iface == NULL) |
| return 0; |
| |
| con = ctrl_iface->con; |
| next = ctrl_iface->next_objid++; |
| |
| /* Create and set the interface's object path */ |
| wpa_s->dbus_path = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX); |
| if (wpa_s->dbus_path == NULL) |
| return -1; |
| os_snprintf(wpa_s->dbus_path, WPAS_DBUS_OBJECT_PATH_MAX, |
| WPAS_DBUS_PATH_INTERFACES "/%u", |
| next); |
| |
| /* Register the message handler for the interface functions */ |
| if (!dbus_connection_register_fallback(con, wpa_s->dbus_path, &vtable, |
| wpa_s)) { |
| wpa_printf(MSG_ERROR, "dbus: Could not set up message " |
| "handler for interface %s", wpa_s->ifname); |
| return -1; |
| } |
| |
| return 0; |
| } |
| |
| |
| /** |
| * wpas_dbus_unregister_iface - Unregister an interface from dbus |
| * @wpa_s: wpa_supplicant interface structure |
| * Returns: 0 on success, -1 on failure |
| * |
| * Unregisters the interface with dbus |
| */ |
| int wpas_dbus_unregister_iface(struct wpa_supplicant *wpa_s) |
| { |
| struct wpas_dbus_priv *ctrl_iface; |
| DBusConnection *con; |
| |
| /* Do nothing if the control interface is not turned on */ |
| if (wpa_s == NULL || wpa_s->global == NULL) |
| return 0; |
| ctrl_iface = wpa_s->global->dbus; |
| if (ctrl_iface == NULL) |
| return 0; |
| |
| con = ctrl_iface->con; |
| if (!dbus_connection_unregister_object_path(con, wpa_s->dbus_path)) |
| return -1; |
| |
| os_free(wpa_s->dbus_path); |
| wpa_s->dbus_path = NULL; |
| |
| return 0; |
| } |
| |
| |
| /** |
| * wpa_supplicant_get_iface_by_dbus_path - Get a new network interface |
| * @global: Pointer to global data from wpa_supplicant_init() |
| * @path: Pointer to a dbus object path representing an interface |
| * Returns: Pointer to the interface or %NULL if not found |
| */ |
| struct wpa_supplicant * wpa_supplicant_get_iface_by_dbus_path( |
| struct wpa_global *global, const char *path) |
| { |
| struct wpa_supplicant *wpa_s; |
| |
| for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) { |
| if (strcmp(wpa_s->dbus_path, path) == 0) |
| return wpa_s; |
| } |
| return NULL; |
| } |