1214501Srpaulo/* 2214501Srpaulo * WPA Supplicant / dbus-based control interface 3214501Srpaulo * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc. 4214501Srpaulo * 5252190Srpaulo * This software may be distributed under the terms of the BSD license. 6252190Srpaulo * See README for more details. 7214501Srpaulo */ 8214501Srpaulo 9214501Srpaulo#include "includes.h" 10214501Srpaulo#include <dbus/dbus.h> 11214501Srpaulo 12214501Srpaulo#include "common.h" 13214501Srpaulo#include "eloop.h" 14214501Srpaulo#include "wps/wps.h" 15214501Srpaulo#include "../config.h" 16214501Srpaulo#include "../wpa_supplicant_i.h" 17214501Srpaulo#include "../bss.h" 18214501Srpaulo#include "dbus_old.h" 19214501Srpaulo#include "dbus_old_handlers.h" 20214501Srpaulo#include "dbus_common_i.h" 21214501Srpaulo 22214501Srpaulo 23214501Srpaulo/** 24214501Srpaulo * wpas_dbus_decompose_object_path - Decompose an interface object path into parts 25214501Srpaulo * @path: The dbus object path 26214501Srpaulo * @network: (out) the configured network this object path refers to, if any 27214501Srpaulo * @bssid: (out) the scanned bssid this object path refers to, if any 28214501Srpaulo * Returns: The object path of the network interface this path refers to 29214501Srpaulo * 30214501Srpaulo * For a given object path, decomposes the object path into object id, network, 31214501Srpaulo * and BSSID parts, if those parts exist. 32214501Srpaulo */ 33214501Srpaulochar * wpas_dbus_decompose_object_path(const char *path, char **network, 34214501Srpaulo char **bssid) 35214501Srpaulo{ 36214501Srpaulo const unsigned int dev_path_prefix_len = 37214501Srpaulo strlen(WPAS_DBUS_PATH_INTERFACES "/"); 38214501Srpaulo char *obj_path_only; 39214501Srpaulo char *next_sep; 40214501Srpaulo 41214501Srpaulo /* Be a bit paranoid about path */ 42214501Srpaulo if (!path || strncmp(path, WPAS_DBUS_PATH_INTERFACES "/", 43214501Srpaulo dev_path_prefix_len)) 44214501Srpaulo return NULL; 45214501Srpaulo 46214501Srpaulo /* Ensure there's something at the end of the path */ 47214501Srpaulo if ((path + dev_path_prefix_len)[0] == '\0') 48214501Srpaulo return NULL; 49214501Srpaulo 50214501Srpaulo obj_path_only = os_strdup(path); 51214501Srpaulo if (obj_path_only == NULL) 52214501Srpaulo return NULL; 53214501Srpaulo 54214501Srpaulo next_sep = strchr(obj_path_only + dev_path_prefix_len, '/'); 55214501Srpaulo if (next_sep != NULL) { 56214501Srpaulo const char *net_part = strstr(next_sep, 57214501Srpaulo WPAS_DBUS_NETWORKS_PART "/"); 58214501Srpaulo const char *bssid_part = strstr(next_sep, 59214501Srpaulo WPAS_DBUS_BSSIDS_PART "/"); 60214501Srpaulo 61214501Srpaulo if (network && net_part) { 62214501Srpaulo /* Deal with a request for a configured network */ 63214501Srpaulo const char *net_name = net_part + 64214501Srpaulo strlen(WPAS_DBUS_NETWORKS_PART "/"); 65214501Srpaulo *network = NULL; 66214501Srpaulo if (strlen(net_name)) 67214501Srpaulo *network = os_strdup(net_name); 68214501Srpaulo } else if (bssid && bssid_part) { 69214501Srpaulo /* Deal with a request for a scanned BSSID */ 70214501Srpaulo const char *bssid_name = bssid_part + 71214501Srpaulo strlen(WPAS_DBUS_BSSIDS_PART "/"); 72214501Srpaulo if (strlen(bssid_name)) 73214501Srpaulo *bssid = os_strdup(bssid_name); 74214501Srpaulo else 75214501Srpaulo *bssid = NULL; 76214501Srpaulo } 77214501Srpaulo 78214501Srpaulo /* Cut off interface object path before "/" */ 79214501Srpaulo *next_sep = '\0'; 80214501Srpaulo } 81214501Srpaulo 82214501Srpaulo return obj_path_only; 83214501Srpaulo} 84214501Srpaulo 85214501Srpaulo 86214501Srpaulo/** 87214501Srpaulo * wpas_dbus_new_invalid_iface_error - Return a new invalid interface error message 88214501Srpaulo * @message: Pointer to incoming dbus message this error refers to 89214501Srpaulo * Returns: A dbus error message 90214501Srpaulo * 91214501Srpaulo * Convenience function to create and return an invalid interface error 92214501Srpaulo */ 93214501SrpauloDBusMessage * wpas_dbus_new_invalid_iface_error(DBusMessage *message) 94214501Srpaulo{ 95214501Srpaulo return dbus_message_new_error(message, WPAS_ERROR_INVALID_IFACE, 96214501Srpaulo "wpa_supplicant knows nothing about " 97214501Srpaulo "this interface."); 98214501Srpaulo} 99214501Srpaulo 100214501Srpaulo 101214501Srpaulo/** 102214501Srpaulo * wpas_dbus_new_invalid_network_error - Return a new invalid network error message 103214501Srpaulo * @message: Pointer to incoming dbus message this error refers to 104214501Srpaulo * Returns: a dbus error message 105214501Srpaulo * 106214501Srpaulo * Convenience function to create and return an invalid network error 107214501Srpaulo */ 108214501SrpauloDBusMessage * wpas_dbus_new_invalid_network_error(DBusMessage *message) 109214501Srpaulo{ 110214501Srpaulo return dbus_message_new_error(message, WPAS_ERROR_INVALID_NETWORK, 111214501Srpaulo "The requested network does not exist."); 112214501Srpaulo} 113214501Srpaulo 114214501Srpaulo 115214501Srpaulo/** 116214501Srpaulo * wpas_dbus_new_invalid_bssid_error - Return a new invalid bssid error message 117214501Srpaulo * @message: Pointer to incoming dbus message this error refers to 118214501Srpaulo * Returns: a dbus error message 119214501Srpaulo * 120214501Srpaulo * Convenience function to create and return an invalid bssid error 121214501Srpaulo */ 122214501Srpaulostatic DBusMessage * wpas_dbus_new_invalid_bssid_error(DBusMessage *message) 123214501Srpaulo{ 124214501Srpaulo return dbus_message_new_error(message, WPAS_ERROR_INVALID_BSSID, 125214501Srpaulo "The BSSID requested was invalid."); 126214501Srpaulo} 127214501Srpaulo 128214501Srpaulo 129214501Srpaulo/** 130214501Srpaulo * wpas_dispatch_network_method - dispatch messages for configured networks 131214501Srpaulo * @message: the incoming dbus message 132214501Srpaulo * @wpa_s: a network interface's data 133214501Srpaulo * @network_id: id of the configured network we're interested in 134214501Srpaulo * Returns: a reply dbus message, or a dbus error message 135214501Srpaulo * 136214501Srpaulo * This function dispatches all incoming dbus messages for configured networks. 137214501Srpaulo */ 138214501Srpaulostatic DBusMessage * wpas_dispatch_network_method(DBusMessage *message, 139214501Srpaulo struct wpa_supplicant *wpa_s, 140214501Srpaulo int network_id) 141214501Srpaulo{ 142214501Srpaulo DBusMessage *reply = NULL; 143214501Srpaulo const char *method = dbus_message_get_member(message); 144214501Srpaulo struct wpa_ssid *ssid; 145214501Srpaulo 146214501Srpaulo ssid = wpa_config_get_network(wpa_s->conf, network_id); 147214501Srpaulo if (ssid == NULL) 148214501Srpaulo return wpas_dbus_new_invalid_network_error(message); 149214501Srpaulo 150214501Srpaulo if (!strcmp(method, "set")) 151214501Srpaulo reply = wpas_dbus_iface_set_network(message, wpa_s, ssid); 152214501Srpaulo else if (!strcmp(method, "enable")) 153214501Srpaulo reply = wpas_dbus_iface_enable_network(message, wpa_s, ssid); 154214501Srpaulo else if (!strcmp(method, "disable")) 155214501Srpaulo reply = wpas_dbus_iface_disable_network(message, wpa_s, ssid); 156214501Srpaulo 157214501Srpaulo return reply; 158214501Srpaulo} 159214501Srpaulo 160214501Srpaulo 161214501Srpaulo/** 162214501Srpaulo * wpas_dispatch_bssid_method - dispatch messages for scanned networks 163214501Srpaulo * @message: the incoming dbus message 164214501Srpaulo * @wpa_s: a network interface's data 165214501Srpaulo * @bssid: bssid of the scanned network we're interested in 166214501Srpaulo * Returns: a reply dbus message, or a dbus error message 167214501Srpaulo * 168214501Srpaulo * This function dispatches all incoming dbus messages for scanned networks. 169214501Srpaulo */ 170214501Srpaulostatic DBusMessage * wpas_dispatch_bssid_method(DBusMessage *message, 171214501Srpaulo struct wpa_supplicant *wpa_s, 172214501Srpaulo const char *bssid_txt) 173214501Srpaulo{ 174214501Srpaulo u8 bssid[ETH_ALEN]; 175214501Srpaulo struct wpa_bss *bss; 176214501Srpaulo 177214501Srpaulo if (hexstr2bin(bssid_txt, bssid, ETH_ALEN) < 0) 178214501Srpaulo return wpas_dbus_new_invalid_bssid_error(message); 179214501Srpaulo 180214501Srpaulo bss = wpa_bss_get_bssid(wpa_s, bssid); 181214501Srpaulo if (bss == NULL) 182214501Srpaulo return wpas_dbus_new_invalid_bssid_error(message); 183214501Srpaulo 184214501Srpaulo /* Dispatch the method call against the scanned bssid */ 185214501Srpaulo if (os_strcmp(dbus_message_get_member(message), "properties") == 0) 186214501Srpaulo return wpas_dbus_bssid_properties(message, wpa_s, bss); 187214501Srpaulo 188214501Srpaulo return NULL; 189214501Srpaulo} 190214501Srpaulo 191214501Srpaulo 192214501Srpaulo/** 193214501Srpaulo * wpas_iface_message_handler - Dispatch messages for interfaces or networks 194214501Srpaulo * @connection: Connection to the system message bus 195214501Srpaulo * @message: An incoming dbus message 196214501Srpaulo * @user_data: A pointer to a dbus control interface data structure 197214501Srpaulo * Returns: Whether or not the message was handled 198214501Srpaulo * 199214501Srpaulo * This function dispatches all incoming dbus messages for network interfaces, 200214501Srpaulo * or objects owned by them, such as scanned BSSIDs and configured networks. 201214501Srpaulo */ 202214501Srpaulostatic DBusHandlerResult wpas_iface_message_handler(DBusConnection *connection, 203214501Srpaulo DBusMessage *message, 204214501Srpaulo void *user_data) 205214501Srpaulo{ 206214501Srpaulo struct wpa_supplicant *wpa_s = user_data; 207214501Srpaulo const char *method = dbus_message_get_member(message); 208214501Srpaulo const char *path = dbus_message_get_path(message); 209214501Srpaulo const char *msg_interface = dbus_message_get_interface(message); 210214501Srpaulo char *iface_obj_path = NULL; 211214501Srpaulo char *network = NULL; 212214501Srpaulo char *bssid = NULL; 213214501Srpaulo DBusMessage *reply = NULL; 214214501Srpaulo 215214501Srpaulo /* Caller must specify a message interface */ 216214501Srpaulo if (!msg_interface) 217214501Srpaulo goto out; 218214501Srpaulo 219214501Srpaulo iface_obj_path = wpas_dbus_decompose_object_path(path, &network, 220214501Srpaulo &bssid); 221214501Srpaulo if (iface_obj_path == NULL) { 222214501Srpaulo reply = wpas_dbus_new_invalid_iface_error(message); 223214501Srpaulo goto out; 224214501Srpaulo } 225214501Srpaulo 226214501Srpaulo /* Make sure the message's object path actually refers to the 227214501Srpaulo * wpa_supplicant structure it's supposed to (which is wpa_s) 228214501Srpaulo */ 229214501Srpaulo if (wpa_supplicant_get_iface_by_dbus_path(wpa_s->global, 230214501Srpaulo iface_obj_path) != wpa_s) { 231214501Srpaulo reply = wpas_dbus_new_invalid_iface_error(message); 232214501Srpaulo goto out; 233214501Srpaulo } 234214501Srpaulo 235214501Srpaulo if (network && !strcmp(msg_interface, WPAS_DBUS_IFACE_NETWORK)) { 236214501Srpaulo /* A method for one of this interface's configured networks */ 237214501Srpaulo int nid = strtoul(network, NULL, 10); 238214501Srpaulo if (errno != EINVAL) 239214501Srpaulo reply = wpas_dispatch_network_method(message, wpa_s, 240214501Srpaulo nid); 241214501Srpaulo else 242214501Srpaulo reply = wpas_dbus_new_invalid_network_error(message); 243214501Srpaulo } else if (bssid && !strcmp(msg_interface, WPAS_DBUS_IFACE_BSSID)) { 244214501Srpaulo /* A method for one of this interface's scanned BSSIDs */ 245214501Srpaulo reply = wpas_dispatch_bssid_method(message, wpa_s, bssid); 246214501Srpaulo } else if (!strcmp(msg_interface, WPAS_DBUS_IFACE_INTERFACE)) { 247214501Srpaulo /* A method for an interface only. */ 248214501Srpaulo if (!strcmp(method, "scan")) 249214501Srpaulo reply = wpas_dbus_iface_scan(message, wpa_s); 250214501Srpaulo else if (!strcmp(method, "scanResults")) 251214501Srpaulo reply = wpas_dbus_iface_scan_results(message, wpa_s); 252214501Srpaulo else if (!strcmp(method, "addNetwork")) 253214501Srpaulo reply = wpas_dbus_iface_add_network(message, wpa_s); 254214501Srpaulo else if (!strcmp(method, "removeNetwork")) 255214501Srpaulo reply = wpas_dbus_iface_remove_network(message, wpa_s); 256214501Srpaulo else if (!strcmp(method, "selectNetwork")) 257214501Srpaulo reply = wpas_dbus_iface_select_network(message, wpa_s); 258214501Srpaulo else if (!strcmp(method, "capabilities")) 259214501Srpaulo reply = wpas_dbus_iface_capabilities(message, wpa_s); 260214501Srpaulo else if (!strcmp(method, "disconnect")) 261214501Srpaulo reply = wpas_dbus_iface_disconnect(message, wpa_s); 262214501Srpaulo else if (!strcmp(method, "setAPScan")) 263214501Srpaulo reply = wpas_dbus_iface_set_ap_scan(message, wpa_s); 264214501Srpaulo else if (!strcmp(method, "setSmartcardModules")) 265214501Srpaulo reply = wpas_dbus_iface_set_smartcard_modules(message, 266214501Srpaulo wpa_s); 267214501Srpaulo else if (!strcmp(method, "state")) 268214501Srpaulo reply = wpas_dbus_iface_get_state(message, wpa_s); 269214501Srpaulo else if (!strcmp(method, "scanning")) 270214501Srpaulo reply = wpas_dbus_iface_get_scanning(message, wpa_s); 271214501Srpaulo else if (!strcmp(method, "setBlobs")) 272214501Srpaulo reply = wpas_dbus_iface_set_blobs(message, wpa_s); 273214501Srpaulo else if (!strcmp(method, "removeBlobs")) 274214501Srpaulo reply = wpas_dbus_iface_remove_blobs(message, wpa_s); 275214501Srpaulo#ifdef CONFIG_WPS 276214501Srpaulo else if (!os_strcmp(method, "wpsPbc")) 277214501Srpaulo reply = wpas_dbus_iface_wps_pbc(message, wpa_s); 278214501Srpaulo else if (!os_strcmp(method, "wpsPin")) 279214501Srpaulo reply = wpas_dbus_iface_wps_pin(message, wpa_s); 280214501Srpaulo else if (!os_strcmp(method, "wpsReg")) 281214501Srpaulo reply = wpas_dbus_iface_wps_reg(message, wpa_s); 282214501Srpaulo#endif /* CONFIG_WPS */ 283252190Srpaulo else if (!os_strcmp(method, "flush")) 284252190Srpaulo reply = wpas_dbus_iface_flush(message, wpa_s); 285214501Srpaulo } 286214501Srpaulo 287214501Srpaulo /* If the message was handled, send back the reply */ 288214501Srpaulo if (reply) { 289214501Srpaulo if (!dbus_message_get_no_reply(message)) 290214501Srpaulo dbus_connection_send(connection, reply, NULL); 291214501Srpaulo dbus_message_unref(reply); 292214501Srpaulo } 293214501Srpaulo 294214501Srpauloout: 295214501Srpaulo os_free(iface_obj_path); 296214501Srpaulo os_free(network); 297214501Srpaulo os_free(bssid); 298214501Srpaulo return reply ? DBUS_HANDLER_RESULT_HANDLED : 299214501Srpaulo DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 300214501Srpaulo} 301214501Srpaulo 302214501Srpaulo 303214501Srpaulo/** 304214501Srpaulo * wpas_message_handler - dispatch incoming dbus messages 305214501Srpaulo * @connection: connection to the system message bus 306214501Srpaulo * @message: an incoming dbus message 307214501Srpaulo * @user_data: a pointer to a dbus control interface data structure 308214501Srpaulo * Returns: whether or not the message was handled 309214501Srpaulo * 310214501Srpaulo * This function dispatches all incoming dbus messages to the correct 311214501Srpaulo * handlers, depending on what the message's target object path is, 312214501Srpaulo * and what the method call is. 313214501Srpaulo */ 314214501Srpaulostatic DBusHandlerResult wpas_message_handler(DBusConnection *connection, 315214501Srpaulo DBusMessage *message, void *user_data) 316214501Srpaulo{ 317214501Srpaulo struct wpas_dbus_priv *ctrl_iface = user_data; 318214501Srpaulo const char *method; 319214501Srpaulo const char *path; 320214501Srpaulo const char *msg_interface; 321214501Srpaulo DBusMessage *reply = NULL; 322214501Srpaulo 323214501Srpaulo method = dbus_message_get_member(message); 324214501Srpaulo path = dbus_message_get_path(message); 325214501Srpaulo msg_interface = dbus_message_get_interface(message); 326214501Srpaulo if (!method || !path || !ctrl_iface || !msg_interface) 327214501Srpaulo return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 328214501Srpaulo 329214501Srpaulo /* Validate the method interface */ 330214501Srpaulo if (strcmp(msg_interface, WPAS_DBUS_INTERFACE) != 0) 331214501Srpaulo return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 332214501Srpaulo 333214501Srpaulo if (!strcmp(path, WPAS_DBUS_PATH)) { 334214501Srpaulo /* dispatch methods against our global dbus interface here */ 335214501Srpaulo if (!strcmp(method, "addInterface")) { 336214501Srpaulo reply = wpas_dbus_global_add_interface( 337214501Srpaulo message, ctrl_iface->global); 338214501Srpaulo } else if (!strcmp(method, "removeInterface")) { 339214501Srpaulo reply = wpas_dbus_global_remove_interface( 340214501Srpaulo message, ctrl_iface->global); 341214501Srpaulo } else if (!strcmp(method, "getInterface")) { 342214501Srpaulo reply = wpas_dbus_global_get_interface( 343214501Srpaulo message, ctrl_iface->global); 344214501Srpaulo } else if (!strcmp(method, "setDebugParams")) { 345214501Srpaulo reply = wpas_dbus_global_set_debugparams( 346214501Srpaulo message, ctrl_iface->global); 347214501Srpaulo } 348214501Srpaulo } 349214501Srpaulo 350214501Srpaulo /* If the message was handled, send back the reply */ 351214501Srpaulo if (reply) { 352214501Srpaulo if (!dbus_message_get_no_reply(message)) 353214501Srpaulo dbus_connection_send(connection, reply, NULL); 354214501Srpaulo dbus_message_unref(reply); 355214501Srpaulo } 356214501Srpaulo 357214501Srpaulo return reply ? DBUS_HANDLER_RESULT_HANDLED : 358214501Srpaulo DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 359214501Srpaulo} 360214501Srpaulo 361214501Srpaulo 362214501Srpaulo/** 363214501Srpaulo * wpa_supplicant_dbus_notify_scan_results - Send a scan results signal 364214501Srpaulo * @wpa_s: %wpa_supplicant network interface data 365214501Srpaulo * Returns: 0 on success, -1 on failure 366214501Srpaulo * 367214501Srpaulo * Notify listeners that this interface has updated scan results. 368214501Srpaulo */ 369214501Srpaulovoid wpa_supplicant_dbus_notify_scan_results(struct wpa_supplicant *wpa_s) 370214501Srpaulo{ 371214501Srpaulo struct wpas_dbus_priv *iface = wpa_s->global->dbus; 372214501Srpaulo DBusMessage *_signal; 373214501Srpaulo 374214501Srpaulo /* Do nothing if the control interface is not turned on */ 375214501Srpaulo if (iface == NULL) 376214501Srpaulo return; 377214501Srpaulo 378214501Srpaulo _signal = dbus_message_new_signal(wpa_s->dbus_path, 379214501Srpaulo WPAS_DBUS_IFACE_INTERFACE, 380214501Srpaulo "ScanResultsAvailable"); 381214501Srpaulo if (_signal == NULL) { 382214501Srpaulo wpa_printf(MSG_ERROR, "dbus: Not enough memory to send scan " 383214501Srpaulo "results signal"); 384214501Srpaulo return; 385214501Srpaulo } 386214501Srpaulo dbus_connection_send(iface->con, _signal, NULL); 387214501Srpaulo dbus_message_unref(_signal); 388214501Srpaulo} 389214501Srpaulo 390214501Srpaulo 391214501Srpaulo/** 392214501Srpaulo * wpa_supplicant_dbus_notify_state_change - Send a state change signal 393214501Srpaulo * @wpa_s: %wpa_supplicant network interface data 394214501Srpaulo * @new_state: new state wpa_supplicant is entering 395214501Srpaulo * @old_state: old state wpa_supplicant is leaving 396214501Srpaulo * Returns: 0 on success, -1 on failure 397214501Srpaulo * 398214501Srpaulo * Notify listeners that wpa_supplicant has changed state 399214501Srpaulo */ 400214501Srpaulovoid wpa_supplicant_dbus_notify_state_change(struct wpa_supplicant *wpa_s, 401214501Srpaulo enum wpa_states new_state, 402214501Srpaulo enum wpa_states old_state) 403214501Srpaulo{ 404214501Srpaulo struct wpas_dbus_priv *iface; 405214501Srpaulo DBusMessage *_signal = NULL; 406214501Srpaulo const char *new_state_str, *old_state_str; 407214501Srpaulo 408214501Srpaulo if (wpa_s->dbus_path == NULL) 409214501Srpaulo return; /* Skip signal since D-Bus setup is not yet ready */ 410214501Srpaulo 411214501Srpaulo /* Do nothing if the control interface is not turned on */ 412214501Srpaulo if (wpa_s->global == NULL) 413214501Srpaulo return; 414214501Srpaulo iface = wpa_s->global->dbus; 415214501Srpaulo if (iface == NULL) 416214501Srpaulo return; 417214501Srpaulo 418214501Srpaulo /* Only send signal if state really changed */ 419214501Srpaulo if (new_state == old_state) 420214501Srpaulo return; 421214501Srpaulo 422214501Srpaulo _signal = dbus_message_new_signal(wpa_s->dbus_path, 423214501Srpaulo WPAS_DBUS_IFACE_INTERFACE, 424214501Srpaulo "StateChange"); 425214501Srpaulo if (_signal == NULL) { 426214501Srpaulo wpa_printf(MSG_ERROR, 427214501Srpaulo "dbus: wpa_supplicant_dbus_notify_state_change: " 428214501Srpaulo "could not create dbus signal; likely out of " 429214501Srpaulo "memory"); 430214501Srpaulo return; 431214501Srpaulo } 432214501Srpaulo 433214501Srpaulo new_state_str = wpa_supplicant_state_txt(new_state); 434214501Srpaulo old_state_str = wpa_supplicant_state_txt(old_state); 435214501Srpaulo if (new_state_str == NULL || old_state_str == NULL) { 436214501Srpaulo wpa_printf(MSG_ERROR, 437214501Srpaulo "dbus: wpa_supplicant_dbus_notify_state_change: " 438214501Srpaulo "Could not convert state strings"); 439214501Srpaulo goto out; 440214501Srpaulo } 441214501Srpaulo 442214501Srpaulo if (!dbus_message_append_args(_signal, 443214501Srpaulo DBUS_TYPE_STRING, &new_state_str, 444214501Srpaulo DBUS_TYPE_STRING, &old_state_str, 445214501Srpaulo DBUS_TYPE_INVALID)) { 446214501Srpaulo wpa_printf(MSG_ERROR, 447214501Srpaulo "dbus: wpa_supplicant_dbus_notify_state_change: " 448214501Srpaulo "Not enough memory to construct state change " 449214501Srpaulo "signal"); 450214501Srpaulo goto out; 451214501Srpaulo } 452214501Srpaulo 453214501Srpaulo dbus_connection_send(iface->con, _signal, NULL); 454214501Srpaulo 455214501Srpauloout: 456214501Srpaulo dbus_message_unref(_signal); 457214501Srpaulo} 458214501Srpaulo 459214501Srpaulo 460214501Srpaulo/** 461214501Srpaulo * wpa_supplicant_dbus_notify_scanning - send scanning status 462214501Srpaulo * @wpa_s: %wpa_supplicant network interface data 463214501Srpaulo * Returns: 0 on success, -1 on failure 464214501Srpaulo * 465214501Srpaulo * Notify listeners of interface scanning state changes 466214501Srpaulo */ 467214501Srpaulovoid wpa_supplicant_dbus_notify_scanning(struct wpa_supplicant *wpa_s) 468214501Srpaulo{ 469214501Srpaulo struct wpas_dbus_priv *iface = wpa_s->global->dbus; 470214501Srpaulo DBusMessage *_signal; 471214501Srpaulo dbus_bool_t scanning = wpa_s->scanning ? TRUE : FALSE; 472214501Srpaulo 473214501Srpaulo /* Do nothing if the control interface is not turned on */ 474214501Srpaulo if (iface == NULL) 475214501Srpaulo return; 476214501Srpaulo 477214501Srpaulo _signal = dbus_message_new_signal(wpa_s->dbus_path, 478214501Srpaulo WPAS_DBUS_IFACE_INTERFACE, 479214501Srpaulo "Scanning"); 480214501Srpaulo if (_signal == NULL) { 481214501Srpaulo wpa_printf(MSG_ERROR, "dbus: Not enough memory to send scan " 482214501Srpaulo "results signal"); 483214501Srpaulo return; 484214501Srpaulo } 485214501Srpaulo 486214501Srpaulo if (dbus_message_append_args(_signal, 487214501Srpaulo DBUS_TYPE_BOOLEAN, &scanning, 488214501Srpaulo DBUS_TYPE_INVALID)) { 489214501Srpaulo dbus_connection_send(iface->con, _signal, NULL); 490214501Srpaulo } else { 491214501Srpaulo wpa_printf(MSG_ERROR, "dbus: Not enough memory to construct " 492214501Srpaulo "signal"); 493214501Srpaulo } 494214501Srpaulo dbus_message_unref(_signal); 495214501Srpaulo} 496214501Srpaulo 497214501Srpaulo 498214501Srpaulo#ifdef CONFIG_WPS 499214501Srpaulovoid wpa_supplicant_dbus_notify_wps_cred(struct wpa_supplicant *wpa_s, 500214501Srpaulo const struct wps_credential *cred) 501214501Srpaulo{ 502214501Srpaulo struct wpas_dbus_priv *iface; 503214501Srpaulo DBusMessage *_signal = NULL; 504214501Srpaulo 505214501Srpaulo /* Do nothing if the control interface is not turned on */ 506214501Srpaulo if (wpa_s->global == NULL) 507214501Srpaulo return; 508214501Srpaulo iface = wpa_s->global->dbus; 509214501Srpaulo if (iface == NULL) 510214501Srpaulo return; 511214501Srpaulo 512214501Srpaulo _signal = dbus_message_new_signal(wpa_s->dbus_path, 513214501Srpaulo WPAS_DBUS_IFACE_INTERFACE, 514214501Srpaulo "WpsCred"); 515214501Srpaulo if (_signal == NULL) { 516214501Srpaulo wpa_printf(MSG_ERROR, 517214501Srpaulo "dbus: wpa_supplicant_dbus_notify_wps_cred: " 518214501Srpaulo "Could not create dbus signal; likely out of " 519214501Srpaulo "memory"); 520214501Srpaulo return; 521214501Srpaulo } 522214501Srpaulo 523214501Srpaulo if (!dbus_message_append_args(_signal, 524214501Srpaulo DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, 525214501Srpaulo &cred->cred_attr, cred->cred_attr_len, 526214501Srpaulo DBUS_TYPE_INVALID)) { 527214501Srpaulo wpa_printf(MSG_ERROR, 528214501Srpaulo "dbus: wpa_supplicant_dbus_notify_wps_cred: " 529214501Srpaulo "Not enough memory to construct signal"); 530214501Srpaulo goto out; 531214501Srpaulo } 532214501Srpaulo 533214501Srpaulo dbus_connection_send(iface->con, _signal, NULL); 534214501Srpaulo 535214501Srpauloout: 536214501Srpaulo dbus_message_unref(_signal); 537214501Srpaulo} 538214501Srpaulo#else /* CONFIG_WPS */ 539214501Srpaulovoid wpa_supplicant_dbus_notify_wps_cred(struct wpa_supplicant *wpa_s, 540214501Srpaulo const struct wps_credential *cred) 541214501Srpaulo{ 542214501Srpaulo} 543214501Srpaulo#endif /* CONFIG_WPS */ 544214501Srpaulo 545252190Srpaulovoid wpa_supplicant_dbus_notify_certification(struct wpa_supplicant *wpa_s, 546252190Srpaulo int depth, const char *subject, 547252190Srpaulo const char *cert_hash, 548252190Srpaulo const struct wpabuf *cert) 549252190Srpaulo{ 550252190Srpaulo struct wpas_dbus_priv *iface; 551252190Srpaulo DBusMessage *_signal = NULL; 552252190Srpaulo const char *hash; 553252190Srpaulo const char *cert_hex; 554252190Srpaulo int cert_hex_len; 555214501Srpaulo 556252190Srpaulo /* Do nothing if the control interface is not turned on */ 557252190Srpaulo if (wpa_s->global == NULL) 558252190Srpaulo return; 559252190Srpaulo iface = wpa_s->global->dbus; 560252190Srpaulo if (iface == NULL) 561252190Srpaulo return; 562252190Srpaulo 563252190Srpaulo _signal = dbus_message_new_signal(wpa_s->dbus_path, 564252190Srpaulo WPAS_DBUS_IFACE_INTERFACE, 565252190Srpaulo "Certification"); 566252190Srpaulo if (_signal == NULL) { 567252190Srpaulo wpa_printf(MSG_ERROR, 568252190Srpaulo "dbus: wpa_supplicant_dbus_notify_certification: " 569252190Srpaulo "Could not create dbus signal; likely out of " 570252190Srpaulo "memory"); 571252190Srpaulo return; 572252190Srpaulo } 573252190Srpaulo 574252190Srpaulo hash = cert_hash ? cert_hash : ""; 575252190Srpaulo cert_hex = cert ? wpabuf_head(cert) : ""; 576252190Srpaulo cert_hex_len = cert ? wpabuf_len(cert) : 0; 577252190Srpaulo 578252190Srpaulo if (!dbus_message_append_args(_signal, 579252190Srpaulo DBUS_TYPE_INT32,&depth, 580252190Srpaulo DBUS_TYPE_STRING, &subject, 581252190Srpaulo DBUS_TYPE_STRING, &hash, 582252190Srpaulo DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, 583252190Srpaulo &cert_hex, cert_hex_len, 584252190Srpaulo DBUS_TYPE_INVALID)) { 585252190Srpaulo wpa_printf(MSG_ERROR, 586252190Srpaulo "dbus: wpa_supplicant_dbus_notify_certification: " 587252190Srpaulo "Not enough memory to construct signal"); 588252190Srpaulo goto out; 589252190Srpaulo } 590252190Srpaulo 591252190Srpaulo dbus_connection_send(iface->con, _signal, NULL); 592252190Srpaulo 593252190Srpauloout: 594252190Srpaulo dbus_message_unref(_signal); 595252190Srpaulo 596252190Srpaulo} 597252190Srpaulo 598252190Srpaulo 599214501Srpaulo/** 600214501Srpaulo * wpa_supplicant_dbus_ctrl_iface_init - Initialize dbus control interface 601214501Srpaulo * @global: Pointer to global data from wpa_supplicant_init() 602214501Srpaulo * Returns: 0 on success, -1 on failure 603214501Srpaulo * 604214501Srpaulo * Initialize the dbus control interface and start receiving commands from 605214501Srpaulo * external programs over the bus. 606214501Srpaulo */ 607214501Srpauloint wpa_supplicant_dbus_ctrl_iface_init(struct wpas_dbus_priv *iface) 608214501Srpaulo{ 609214501Srpaulo DBusError error; 610214501Srpaulo int ret = -1; 611214501Srpaulo DBusObjectPathVTable wpas_vtable = { 612214501Srpaulo NULL, &wpas_message_handler, NULL, NULL, NULL, NULL 613214501Srpaulo }; 614214501Srpaulo 615214501Srpaulo /* Register the message handler for the global dbus interface */ 616214501Srpaulo if (!dbus_connection_register_object_path(iface->con, 617214501Srpaulo WPAS_DBUS_PATH, &wpas_vtable, 618214501Srpaulo iface)) { 619214501Srpaulo wpa_printf(MSG_ERROR, "dbus: Could not set up message " 620214501Srpaulo "handler"); 621214501Srpaulo return -1; 622214501Srpaulo } 623214501Srpaulo 624214501Srpaulo /* Register our service with the message bus */ 625214501Srpaulo dbus_error_init(&error); 626214501Srpaulo switch (dbus_bus_request_name(iface->con, WPAS_DBUS_SERVICE, 627214501Srpaulo 0, &error)) { 628214501Srpaulo case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER: 629214501Srpaulo ret = 0; 630214501Srpaulo break; 631214501Srpaulo case DBUS_REQUEST_NAME_REPLY_EXISTS: 632214501Srpaulo case DBUS_REQUEST_NAME_REPLY_IN_QUEUE: 633214501Srpaulo case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER: 634214501Srpaulo wpa_printf(MSG_ERROR, "dbus: Could not request service name: " 635214501Srpaulo "already registered"); 636214501Srpaulo break; 637214501Srpaulo default: 638214501Srpaulo wpa_printf(MSG_ERROR, "dbus: Could not request service name: " 639214501Srpaulo "%s %s", error.name, error.message); 640214501Srpaulo break; 641214501Srpaulo } 642214501Srpaulo dbus_error_free(&error); 643214501Srpaulo 644214501Srpaulo if (ret != 0) 645214501Srpaulo return -1; 646214501Srpaulo 647214501Srpaulo wpa_printf(MSG_DEBUG, "Providing DBus service '" WPAS_DBUS_SERVICE 648214501Srpaulo "'."); 649214501Srpaulo 650214501Srpaulo return 0; 651214501Srpaulo} 652214501Srpaulo 653214501Srpaulo 654214501Srpaulo/** 655214501Srpaulo * wpas_dbus_register_new_iface - Register a new interface with dbus 656214501Srpaulo * @wpa_s: %wpa_supplicant interface description structure to register 657214501Srpaulo * Returns: 0 on success, -1 on error 658214501Srpaulo * 659214501Srpaulo * Registers a new interface with dbus and assigns it a dbus object path. 660214501Srpaulo */ 661214501Srpauloint wpas_dbus_register_iface(struct wpa_supplicant *wpa_s) 662214501Srpaulo{ 663214501Srpaulo struct wpas_dbus_priv *ctrl_iface = wpa_s->global->dbus; 664214501Srpaulo DBusConnection * con; 665214501Srpaulo u32 next; 666214501Srpaulo DBusObjectPathVTable vtable = { 667214501Srpaulo NULL, &wpas_iface_message_handler, NULL, NULL, NULL, NULL 668214501Srpaulo }; 669214501Srpaulo 670214501Srpaulo /* Do nothing if the control interface is not turned on */ 671214501Srpaulo if (ctrl_iface == NULL) 672214501Srpaulo return 0; 673214501Srpaulo 674214501Srpaulo con = ctrl_iface->con; 675214501Srpaulo next = ctrl_iface->next_objid++; 676214501Srpaulo 677214501Srpaulo /* Create and set the interface's object path */ 678214501Srpaulo wpa_s->dbus_path = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX); 679214501Srpaulo if (wpa_s->dbus_path == NULL) 680214501Srpaulo return -1; 681214501Srpaulo os_snprintf(wpa_s->dbus_path, WPAS_DBUS_OBJECT_PATH_MAX, 682214501Srpaulo WPAS_DBUS_PATH_INTERFACES "/%u", 683214501Srpaulo next); 684214501Srpaulo 685214501Srpaulo /* Register the message handler for the interface functions */ 686214501Srpaulo if (!dbus_connection_register_fallback(con, wpa_s->dbus_path, &vtable, 687214501Srpaulo wpa_s)) { 688214501Srpaulo wpa_printf(MSG_ERROR, "dbus: Could not set up message " 689214501Srpaulo "handler for interface %s", wpa_s->ifname); 690214501Srpaulo return -1; 691214501Srpaulo } 692214501Srpaulo 693214501Srpaulo return 0; 694214501Srpaulo} 695214501Srpaulo 696214501Srpaulo 697214501Srpaulo/** 698214501Srpaulo * wpas_dbus_unregister_iface - Unregister an interface from dbus 699214501Srpaulo * @wpa_s: wpa_supplicant interface structure 700214501Srpaulo * Returns: 0 on success, -1 on failure 701214501Srpaulo * 702214501Srpaulo * Unregisters the interface with dbus 703214501Srpaulo */ 704214501Srpauloint wpas_dbus_unregister_iface(struct wpa_supplicant *wpa_s) 705214501Srpaulo{ 706214501Srpaulo struct wpas_dbus_priv *ctrl_iface; 707214501Srpaulo DBusConnection *con; 708214501Srpaulo 709214501Srpaulo /* Do nothing if the control interface is not turned on */ 710214501Srpaulo if (wpa_s == NULL || wpa_s->global == NULL) 711214501Srpaulo return 0; 712214501Srpaulo ctrl_iface = wpa_s->global->dbus; 713214501Srpaulo if (ctrl_iface == NULL) 714214501Srpaulo return 0; 715214501Srpaulo 716214501Srpaulo con = ctrl_iface->con; 717214501Srpaulo if (!dbus_connection_unregister_object_path(con, wpa_s->dbus_path)) 718214501Srpaulo return -1; 719214501Srpaulo 720214501Srpaulo os_free(wpa_s->dbus_path); 721214501Srpaulo wpa_s->dbus_path = NULL; 722214501Srpaulo 723214501Srpaulo return 0; 724214501Srpaulo} 725214501Srpaulo 726214501Srpaulo 727214501Srpaulo/** 728214501Srpaulo * wpa_supplicant_get_iface_by_dbus_path - Get a new network interface 729214501Srpaulo * @global: Pointer to global data from wpa_supplicant_init() 730214501Srpaulo * @path: Pointer to a dbus object path representing an interface 731214501Srpaulo * Returns: Pointer to the interface or %NULL if not found 732214501Srpaulo */ 733214501Srpaulostruct wpa_supplicant * wpa_supplicant_get_iface_by_dbus_path( 734214501Srpaulo struct wpa_global *global, const char *path) 735214501Srpaulo{ 736214501Srpaulo struct wpa_supplicant *wpa_s; 737214501Srpaulo 738214501Srpaulo for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) { 739214501Srpaulo if (strcmp(wpa_s->dbus_path, path) == 0) 740214501Srpaulo return wpa_s; 741214501Srpaulo } 742214501Srpaulo return NULL; 743214501Srpaulo} 744