1214501Srpaulo/* 2214501Srpaulo * WPA Supplicant / dbus-based control interface 3214501Srpaulo * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc. 4214501Srpaulo * Copyright (c) 2009, Witold Sowa <witold.sowa@gmail.com> 5214501Srpaulo * 6252190Srpaulo * This software may be distributed under the terms of the BSD license. 7252190Srpaulo * See README for more details. 8214501Srpaulo */ 9214501Srpaulo 10214501Srpaulo#include "utils/includes.h" 11214501Srpaulo 12214501Srpaulo#include "utils/common.h" 13214501Srpaulo#include "utils/eloop.h" 14214501Srpaulo#include "dbus_common.h" 15214501Srpaulo#include "dbus_common_i.h" 16214501Srpaulo#include "dbus_new.h" 17214501Srpaulo#include "dbus_new_helpers.h" 18252190Srpaulo#include "dbus_dict_helpers.h" 19214501Srpaulo 20214501Srpaulo 21252190Srpaulostatic dbus_bool_t fill_dict_with_properties( 22252190Srpaulo DBusMessageIter *dict_iter, 23252190Srpaulo const struct wpa_dbus_property_desc *props, 24252190Srpaulo const char *interface, void *user_data, DBusError *error) 25214501Srpaulo{ 26252190Srpaulo DBusMessageIter entry_iter; 27214501Srpaulo const struct wpa_dbus_property_desc *dsc; 28214501Srpaulo 29214501Srpaulo for (dsc = props; dsc && dsc->dbus_property; dsc++) { 30252190Srpaulo /* Only return properties for the requested D-Bus interface */ 31252190Srpaulo if (os_strncmp(dsc->dbus_interface, interface, 32252190Srpaulo WPAS_DBUS_INTERFACE_MAX) != 0) 33252190Srpaulo continue; 34214501Srpaulo 35252190Srpaulo /* Skip write-only properties */ 36252190Srpaulo if (dsc->getter == NULL) 37252190Srpaulo continue; 38214501Srpaulo 39252190Srpaulo if (!dbus_message_iter_open_container(dict_iter, 40252190Srpaulo DBUS_TYPE_DICT_ENTRY, 41252190Srpaulo NULL, &entry_iter)) { 42252190Srpaulo dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, 43252190Srpaulo "no memory"); 44252190Srpaulo return FALSE; 45252190Srpaulo } 46252190Srpaulo if (!dbus_message_iter_append_basic(&entry_iter, 47252190Srpaulo DBUS_TYPE_STRING, 48252190Srpaulo &dsc->dbus_property)) { 49252190Srpaulo dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, 50252190Srpaulo "no memory"); 51252190Srpaulo return FALSE; 52252190Srpaulo } 53214501Srpaulo 54252190Srpaulo /* An error getting a property fails the request entirely */ 55252190Srpaulo if (!dsc->getter(&entry_iter, error, user_data)) 56252190Srpaulo return FALSE; 57214501Srpaulo 58252190Srpaulo dbus_message_iter_close_container(dict_iter, &entry_iter); 59214501Srpaulo } 60214501Srpaulo 61252190Srpaulo return TRUE; 62214501Srpaulo} 63214501Srpaulo 64214501Srpaulo 65214501Srpaulo/** 66214501Srpaulo * get_all_properties - Responds for GetAll properties calls on object 67214501Srpaulo * @message: Message with GetAll call 68214501Srpaulo * @interface: interface name which properties will be returned 69214501Srpaulo * @property_dsc: list of object's properties 70214501Srpaulo * Returns: Message with dict of variants as argument with properties values 71214501Srpaulo * 72214501Srpaulo * Iterates over all properties registered with object and execute getters 73214501Srpaulo * of those, which are readable and which interface matches interface 74214501Srpaulo * specified as argument. Returned message contains one dict argument 75214501Srpaulo * with properties names as keys and theirs values as values. 76214501Srpaulo */ 77252190Srpaulostatic DBusMessage * get_all_properties(DBusMessage *message, char *interface, 78252190Srpaulo struct wpa_dbus_object_desc *obj_dsc) 79214501Srpaulo{ 80252190Srpaulo DBusMessage *reply; 81214501Srpaulo DBusMessageIter iter, dict_iter; 82252190Srpaulo DBusError error; 83214501Srpaulo 84252190Srpaulo reply = dbus_message_new_method_return(message); 85252190Srpaulo if (reply == NULL) { 86252190Srpaulo wpa_printf(MSG_ERROR, "%s: out of memory creating dbus reply", 87252190Srpaulo __func__); 88252190Srpaulo return NULL; 89252190Srpaulo } 90252190Srpaulo 91214501Srpaulo dbus_message_iter_init_append(reply, &iter); 92252190Srpaulo if (!wpa_dbus_dict_open_write(&iter, &dict_iter)) { 93252190Srpaulo wpa_printf(MSG_ERROR, "%s: out of memory creating reply", 94252190Srpaulo __func__); 95252190Srpaulo dbus_message_unref(reply); 96252190Srpaulo reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, 97252190Srpaulo "out of memory"); 98252190Srpaulo return reply; 99252190Srpaulo } 100214501Srpaulo 101252190Srpaulo dbus_error_init(&error); 102252190Srpaulo if (!fill_dict_with_properties(&dict_iter, obj_dsc->properties, 103252190Srpaulo interface, obj_dsc->user_data, &error)) 104252190Srpaulo { 105214501Srpaulo dbus_message_unref(reply); 106252190Srpaulo reply = wpas_dbus_reply_new_from_error(message, &error, 107252190Srpaulo DBUS_ERROR_INVALID_ARGS, 108252190Srpaulo "No readable properties" 109252190Srpaulo " in this interface"); 110252190Srpaulo dbus_error_free(&error); 111252190Srpaulo return reply; 112214501Srpaulo } 113214501Srpaulo 114252190Srpaulo wpa_dbus_dict_close_write(&iter, &dict_iter); 115214501Srpaulo return reply; 116214501Srpaulo} 117214501Srpaulo 118214501Srpaulo 119214501Srpaulostatic int is_signature_correct(DBusMessage *message, 120214501Srpaulo const struct wpa_dbus_method_desc *method_dsc) 121214501Srpaulo{ 122214501Srpaulo /* According to DBus documentation max length of signature is 255 */ 123214501Srpaulo#define MAX_SIG_LEN 256 124214501Srpaulo char registered_sig[MAX_SIG_LEN], *pos; 125214501Srpaulo const char *sig = dbus_message_get_signature(message); 126214501Srpaulo int ret; 127214501Srpaulo const struct wpa_dbus_argument *arg; 128214501Srpaulo 129214501Srpaulo pos = registered_sig; 130214501Srpaulo *pos = '\0'; 131214501Srpaulo 132214501Srpaulo for (arg = method_dsc->args; arg && arg->name; arg++) { 133214501Srpaulo if (arg->dir == ARG_IN) { 134214501Srpaulo size_t blen = registered_sig + MAX_SIG_LEN - pos; 135214501Srpaulo ret = os_snprintf(pos, blen, "%s", arg->type); 136214501Srpaulo if (ret < 0 || (size_t) ret >= blen) 137214501Srpaulo return 0; 138214501Srpaulo pos += ret; 139214501Srpaulo } 140214501Srpaulo } 141214501Srpaulo 142214501Srpaulo return !os_strncmp(registered_sig, sig, MAX_SIG_LEN); 143214501Srpaulo} 144214501Srpaulo 145214501Srpaulo 146214501Srpaulostatic DBusMessage * properties_get_all(DBusMessage *message, char *interface, 147214501Srpaulo struct wpa_dbus_object_desc *obj_dsc) 148214501Srpaulo{ 149214501Srpaulo if (os_strcmp(dbus_message_get_signature(message), "s") != 0) 150214501Srpaulo return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, 151214501Srpaulo NULL); 152214501Srpaulo 153214501Srpaulo return get_all_properties(message, interface, obj_dsc); 154214501Srpaulo} 155214501Srpaulo 156214501Srpaulo 157214501Srpaulostatic DBusMessage * properties_get(DBusMessage *message, 158214501Srpaulo const struct wpa_dbus_property_desc *dsc, 159214501Srpaulo void *user_data) 160214501Srpaulo{ 161252190Srpaulo DBusMessage *reply; 162252190Srpaulo DBusMessageIter iter; 163252190Srpaulo DBusError error; 164252190Srpaulo 165252190Srpaulo if (os_strcmp(dbus_message_get_signature(message), "ss")) { 166214501Srpaulo return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, 167214501Srpaulo NULL); 168252190Srpaulo } 169214501Srpaulo 170252190Srpaulo if (dsc->getter == NULL) { 171252190Srpaulo return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, 172252190Srpaulo "Property is write-only"); 173252190Srpaulo } 174214501Srpaulo 175252190Srpaulo reply = dbus_message_new_method_return(message); 176252190Srpaulo dbus_message_iter_init_append(reply, &iter); 177252190Srpaulo 178252190Srpaulo dbus_error_init(&error); 179252190Srpaulo if (dsc->getter(&iter, &error, user_data) == FALSE) { 180252190Srpaulo dbus_message_unref(reply); 181252190Srpaulo reply = wpas_dbus_reply_new_from_error( 182252190Srpaulo message, &error, DBUS_ERROR_FAILED, 183252190Srpaulo "Failed to read property"); 184252190Srpaulo dbus_error_free(&error); 185252190Srpaulo } 186252190Srpaulo 187252190Srpaulo return reply; 188214501Srpaulo} 189214501Srpaulo 190214501Srpaulo 191214501Srpaulostatic DBusMessage * properties_set(DBusMessage *message, 192214501Srpaulo const struct wpa_dbus_property_desc *dsc, 193214501Srpaulo void *user_data) 194214501Srpaulo{ 195252190Srpaulo DBusMessage *reply; 196252190Srpaulo DBusMessageIter iter; 197252190Srpaulo DBusError error; 198252190Srpaulo 199252190Srpaulo if (os_strcmp(dbus_message_get_signature(message), "ssv")) { 200214501Srpaulo return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, 201214501Srpaulo NULL); 202252190Srpaulo } 203214501Srpaulo 204252190Srpaulo if (dsc->setter == NULL) { 205252190Srpaulo return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, 206252190Srpaulo "Property is read-only"); 207252190Srpaulo } 208214501Srpaulo 209252190Srpaulo dbus_message_iter_init(message, &iter); 210252190Srpaulo /* Skip the interface name and the property name */ 211252190Srpaulo dbus_message_iter_next(&iter); 212252190Srpaulo dbus_message_iter_next(&iter); 213252190Srpaulo 214252190Srpaulo /* Iter will now point to the property's new value */ 215252190Srpaulo dbus_error_init(&error); 216252190Srpaulo if (dsc->setter(&iter, &error, user_data) == TRUE) { 217252190Srpaulo /* Success */ 218252190Srpaulo reply = dbus_message_new_method_return(message); 219252190Srpaulo } else { 220252190Srpaulo reply = wpas_dbus_reply_new_from_error( 221252190Srpaulo message, &error, DBUS_ERROR_FAILED, 222252190Srpaulo "Failed to set property"); 223252190Srpaulo dbus_error_free(&error); 224252190Srpaulo } 225252190Srpaulo 226252190Srpaulo return reply; 227214501Srpaulo} 228214501Srpaulo 229214501Srpaulo 230214501Srpaulostatic DBusMessage * 231214501Srpauloproperties_get_or_set(DBusMessage *message, DBusMessageIter *iter, 232214501Srpaulo char *interface, 233214501Srpaulo struct wpa_dbus_object_desc *obj_dsc) 234214501Srpaulo{ 235214501Srpaulo const struct wpa_dbus_property_desc *property_dsc; 236214501Srpaulo char *property; 237214501Srpaulo const char *method; 238214501Srpaulo 239214501Srpaulo method = dbus_message_get_member(message); 240214501Srpaulo property_dsc = obj_dsc->properties; 241214501Srpaulo 242214501Srpaulo /* Second argument: property name (DBUS_TYPE_STRING) */ 243214501Srpaulo if (!dbus_message_iter_next(iter) || 244214501Srpaulo dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING) { 245214501Srpaulo return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, 246214501Srpaulo NULL); 247214501Srpaulo } 248214501Srpaulo dbus_message_iter_get_basic(iter, &property); 249214501Srpaulo 250214501Srpaulo while (property_dsc && property_dsc->dbus_property) { 251214501Srpaulo /* compare property names and 252214501Srpaulo * interfaces */ 253214501Srpaulo if (!os_strncmp(property_dsc->dbus_property, property, 254214501Srpaulo WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) && 255214501Srpaulo !os_strncmp(property_dsc->dbus_interface, interface, 256214501Srpaulo WPAS_DBUS_INTERFACE_MAX)) 257214501Srpaulo break; 258214501Srpaulo 259214501Srpaulo property_dsc++; 260214501Srpaulo } 261214501Srpaulo if (property_dsc == NULL || property_dsc->dbus_property == NULL) { 262214501Srpaulo wpa_printf(MSG_DEBUG, "no property handler for %s.%s on %s", 263214501Srpaulo interface, property, 264214501Srpaulo dbus_message_get_path(message)); 265214501Srpaulo return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, 266214501Srpaulo "No such property"); 267214501Srpaulo } 268214501Srpaulo 269214501Srpaulo if (os_strncmp(WPA_DBUS_PROPERTIES_GET, method, 270214501Srpaulo WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) == 0) 271214501Srpaulo return properties_get(message, property_dsc, 272214501Srpaulo obj_dsc->user_data); 273214501Srpaulo 274214501Srpaulo return properties_set(message, property_dsc, obj_dsc->user_data); 275214501Srpaulo} 276214501Srpaulo 277214501Srpaulo 278214501Srpaulostatic DBusMessage * properties_handler(DBusMessage *message, 279214501Srpaulo struct wpa_dbus_object_desc *obj_dsc) 280214501Srpaulo{ 281214501Srpaulo DBusMessageIter iter; 282214501Srpaulo char *interface; 283214501Srpaulo const char *method; 284214501Srpaulo 285214501Srpaulo method = dbus_message_get_member(message); 286214501Srpaulo dbus_message_iter_init(message, &iter); 287214501Srpaulo 288214501Srpaulo if (!os_strncmp(WPA_DBUS_PROPERTIES_GET, method, 289214501Srpaulo WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) || 290214501Srpaulo !os_strncmp(WPA_DBUS_PROPERTIES_SET, method, 291214501Srpaulo WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) || 292214501Srpaulo !os_strncmp(WPA_DBUS_PROPERTIES_GETALL, method, 293214501Srpaulo WPAS_DBUS_METHOD_SIGNAL_PROP_MAX)) { 294214501Srpaulo /* First argument: interface name (DBUS_TYPE_STRING) */ 295214501Srpaulo if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) 296214501Srpaulo { 297214501Srpaulo return dbus_message_new_error(message, 298214501Srpaulo DBUS_ERROR_INVALID_ARGS, 299214501Srpaulo NULL); 300214501Srpaulo } 301214501Srpaulo 302214501Srpaulo dbus_message_iter_get_basic(&iter, &interface); 303214501Srpaulo 304214501Srpaulo if (!os_strncmp(WPA_DBUS_PROPERTIES_GETALL, method, 305214501Srpaulo WPAS_DBUS_METHOD_SIGNAL_PROP_MAX)) { 306214501Srpaulo /* GetAll */ 307214501Srpaulo return properties_get_all(message, interface, obj_dsc); 308214501Srpaulo } 309214501Srpaulo /* Get or Set */ 310214501Srpaulo return properties_get_or_set(message, &iter, interface, 311214501Srpaulo obj_dsc); 312214501Srpaulo } 313214501Srpaulo return dbus_message_new_error(message, DBUS_ERROR_UNKNOWN_METHOD, 314214501Srpaulo NULL); 315214501Srpaulo} 316214501Srpaulo 317214501Srpaulo 318214501Srpaulostatic DBusMessage * msg_method_handler(DBusMessage *message, 319214501Srpaulo struct wpa_dbus_object_desc *obj_dsc) 320214501Srpaulo{ 321214501Srpaulo const struct wpa_dbus_method_desc *method_dsc = obj_dsc->methods; 322214501Srpaulo const char *method; 323214501Srpaulo const char *msg_interface; 324214501Srpaulo 325214501Srpaulo method = dbus_message_get_member(message); 326214501Srpaulo msg_interface = dbus_message_get_interface(message); 327214501Srpaulo 328214501Srpaulo /* try match call to any registered method */ 329214501Srpaulo while (method_dsc && method_dsc->dbus_method) { 330214501Srpaulo /* compare method names and interfaces */ 331214501Srpaulo if (!os_strncmp(method_dsc->dbus_method, method, 332214501Srpaulo WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) && 333214501Srpaulo !os_strncmp(method_dsc->dbus_interface, msg_interface, 334214501Srpaulo WPAS_DBUS_INTERFACE_MAX)) 335214501Srpaulo break; 336214501Srpaulo 337214501Srpaulo method_dsc++; 338214501Srpaulo } 339214501Srpaulo if (method_dsc == NULL || method_dsc->dbus_method == NULL) { 340214501Srpaulo wpa_printf(MSG_DEBUG, "no method handler for %s.%s on %s", 341214501Srpaulo msg_interface, method, 342214501Srpaulo dbus_message_get_path(message)); 343214501Srpaulo return dbus_message_new_error(message, 344214501Srpaulo DBUS_ERROR_UNKNOWN_METHOD, NULL); 345214501Srpaulo } 346214501Srpaulo 347214501Srpaulo if (!is_signature_correct(message, method_dsc)) { 348214501Srpaulo return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, 349214501Srpaulo NULL); 350214501Srpaulo } 351214501Srpaulo 352214501Srpaulo return method_dsc->method_handler(message, 353214501Srpaulo obj_dsc->user_data); 354214501Srpaulo} 355214501Srpaulo 356214501Srpaulo 357214501Srpaulo/** 358214501Srpaulo * message_handler - Handles incoming DBus messages 359214501Srpaulo * @connection: DBus connection on which message was received 360214501Srpaulo * @message: Received message 361214501Srpaulo * @user_data: pointer to description of object to which message was sent 362214501Srpaulo * Returns: Returns information whether message was handled or not 363214501Srpaulo * 364214501Srpaulo * Reads message interface and method name, then checks if they matches one 365214501Srpaulo * of the special cases i.e. introspection call or properties get/getall/set 366214501Srpaulo * methods and handles it. Else it iterates over registered methods list 367214501Srpaulo * and tries to match method's name and interface to those read from message 368214501Srpaulo * If appropriate method was found its handler function is called and 369214501Srpaulo * response is sent. Otherwise, the DBUS_ERROR_UNKNOWN_METHOD error message 370214501Srpaulo * will be sent. 371214501Srpaulo */ 372214501Srpaulostatic DBusHandlerResult message_handler(DBusConnection *connection, 373214501Srpaulo DBusMessage *message, void *user_data) 374214501Srpaulo{ 375214501Srpaulo struct wpa_dbus_object_desc *obj_dsc = user_data; 376214501Srpaulo const char *method; 377214501Srpaulo const char *path; 378214501Srpaulo const char *msg_interface; 379214501Srpaulo DBusMessage *reply; 380214501Srpaulo 381214501Srpaulo /* get method, interface and path the message is addressed to */ 382214501Srpaulo method = dbus_message_get_member(message); 383214501Srpaulo path = dbus_message_get_path(message); 384214501Srpaulo msg_interface = dbus_message_get_interface(message); 385214501Srpaulo if (!method || !path || !msg_interface) 386214501Srpaulo return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 387214501Srpaulo 388214501Srpaulo wpa_printf(MSG_MSGDUMP, "dbus: %s.%s (%s)", 389214501Srpaulo msg_interface, method, path); 390214501Srpaulo 391214501Srpaulo /* if message is introspection method call */ 392214501Srpaulo if (!os_strncmp(WPA_DBUS_INTROSPECTION_METHOD, method, 393214501Srpaulo WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) && 394214501Srpaulo !os_strncmp(WPA_DBUS_INTROSPECTION_INTERFACE, msg_interface, 395214501Srpaulo WPAS_DBUS_INTERFACE_MAX)) { 396214501Srpaulo#ifdef CONFIG_CTRL_IFACE_DBUS_INTRO 397214501Srpaulo reply = wpa_dbus_introspect(message, obj_dsc); 398214501Srpaulo#else /* CONFIG_CTRL_IFACE_DBUS_INTRO */ 399214501Srpaulo reply = dbus_message_new_error( 400214501Srpaulo message, DBUS_ERROR_UNKNOWN_METHOD, 401214501Srpaulo "wpa_supplicant was compiled without " 402214501Srpaulo "introspection support."); 403214501Srpaulo#endif /* CONFIG_CTRL_IFACE_DBUS_INTRO */ 404214501Srpaulo } else if (!os_strncmp(WPA_DBUS_PROPERTIES_INTERFACE, msg_interface, 405214501Srpaulo WPAS_DBUS_INTERFACE_MAX)) { 406214501Srpaulo /* if message is properties method call */ 407214501Srpaulo reply = properties_handler(message, obj_dsc); 408214501Srpaulo } else { 409214501Srpaulo reply = msg_method_handler(message, obj_dsc); 410214501Srpaulo } 411214501Srpaulo 412214501Srpaulo /* If handler succeed returning NULL, reply empty message */ 413214501Srpaulo if (!reply) 414214501Srpaulo reply = dbus_message_new_method_return(message); 415214501Srpaulo if (reply) { 416214501Srpaulo if (!dbus_message_get_no_reply(message)) 417214501Srpaulo dbus_connection_send(connection, reply, NULL); 418214501Srpaulo dbus_message_unref(reply); 419214501Srpaulo } 420214501Srpaulo 421214501Srpaulo wpa_dbus_flush_all_changed_properties(connection); 422214501Srpaulo 423214501Srpaulo return DBUS_HANDLER_RESULT_HANDLED; 424214501Srpaulo} 425214501Srpaulo 426214501Srpaulo 427214501Srpaulo/** 428214501Srpaulo * free_dbus_object_desc - Frees object description data structure 429214501Srpaulo * @connection: DBus connection 430214501Srpaulo * @obj_dsc: Object description to free 431214501Srpaulo * 432214501Srpaulo * Frees each of properties, methods and signals description lists and 433214501Srpaulo * the object description structure itself. 434214501Srpaulo */ 435214501Srpaulovoid free_dbus_object_desc(struct wpa_dbus_object_desc *obj_dsc) 436214501Srpaulo{ 437214501Srpaulo if (!obj_dsc) 438214501Srpaulo return; 439214501Srpaulo 440214501Srpaulo /* free handler's argument */ 441214501Srpaulo if (obj_dsc->user_data_free_func) 442214501Srpaulo obj_dsc->user_data_free_func(obj_dsc->user_data); 443214501Srpaulo 444214501Srpaulo os_free(obj_dsc->path); 445214501Srpaulo os_free(obj_dsc->prop_changed_flags); 446214501Srpaulo os_free(obj_dsc); 447214501Srpaulo} 448214501Srpaulo 449214501Srpaulo 450214501Srpaulostatic void free_dbus_object_desc_cb(DBusConnection *connection, void *obj_dsc) 451214501Srpaulo{ 452214501Srpaulo free_dbus_object_desc(obj_dsc); 453214501Srpaulo} 454214501Srpaulo 455214501Srpaulo/** 456214501Srpaulo * wpa_dbus_ctrl_iface_init - Initialize dbus control interface 457214501Srpaulo * @application_data: Pointer to application specific data structure 458214501Srpaulo * @dbus_path: DBus path to interface object 459214501Srpaulo * @dbus_service: DBus service name to register with 460214501Srpaulo * @messageHandler: a pointer to function which will handle dbus messages 461214501Srpaulo * coming on interface 462214501Srpaulo * Returns: 0 on success, -1 on failure 463214501Srpaulo * 464214501Srpaulo * Initialize the dbus control interface and start receiving commands from 465214501Srpaulo * external programs over the bus. 466214501Srpaulo */ 467214501Srpauloint wpa_dbus_ctrl_iface_init(struct wpas_dbus_priv *iface, 468214501Srpaulo char *dbus_path, char *dbus_service, 469214501Srpaulo struct wpa_dbus_object_desc *obj_desc) 470214501Srpaulo{ 471214501Srpaulo DBusError error; 472214501Srpaulo int ret = -1; 473214501Srpaulo DBusObjectPathVTable wpa_vtable = { 474214501Srpaulo &free_dbus_object_desc_cb, &message_handler, 475214501Srpaulo NULL, NULL, NULL, NULL 476214501Srpaulo }; 477214501Srpaulo 478214501Srpaulo obj_desc->connection = iface->con; 479214501Srpaulo obj_desc->path = os_strdup(dbus_path); 480214501Srpaulo 481214501Srpaulo /* Register the message handler for the global dbus interface */ 482214501Srpaulo if (!dbus_connection_register_object_path(iface->con, 483214501Srpaulo dbus_path, &wpa_vtable, 484214501Srpaulo obj_desc)) { 485214501Srpaulo wpa_printf(MSG_ERROR, "dbus: Could not set up message " 486214501Srpaulo "handler"); 487214501Srpaulo return -1; 488214501Srpaulo } 489214501Srpaulo 490214501Srpaulo /* Register our service with the message bus */ 491214501Srpaulo dbus_error_init(&error); 492214501Srpaulo switch (dbus_bus_request_name(iface->con, dbus_service, 493214501Srpaulo 0, &error)) { 494214501Srpaulo case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER: 495214501Srpaulo ret = 0; 496214501Srpaulo break; 497214501Srpaulo case DBUS_REQUEST_NAME_REPLY_EXISTS: 498214501Srpaulo case DBUS_REQUEST_NAME_REPLY_IN_QUEUE: 499214501Srpaulo case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER: 500214501Srpaulo wpa_printf(MSG_ERROR, "dbus: Could not request service name: " 501214501Srpaulo "already registered"); 502214501Srpaulo break; 503214501Srpaulo default: 504214501Srpaulo wpa_printf(MSG_ERROR, "dbus: Could not request service name: " 505214501Srpaulo "%s %s", error.name, error.message); 506214501Srpaulo break; 507214501Srpaulo } 508214501Srpaulo dbus_error_free(&error); 509214501Srpaulo 510214501Srpaulo if (ret != 0) 511214501Srpaulo return -1; 512214501Srpaulo 513214501Srpaulo wpa_printf(MSG_DEBUG, "Providing DBus service '%s'.", dbus_service); 514214501Srpaulo 515214501Srpaulo return 0; 516214501Srpaulo} 517214501Srpaulo 518214501Srpaulo 519214501Srpaulo/** 520214501Srpaulo * wpa_dbus_register_object_per_iface - Register a new object with dbus 521214501Srpaulo * @ctrl_iface: pointer to dbus private data 522214501Srpaulo * @path: DBus path to object 523214501Srpaulo * @ifname: interface name 524214501Srpaulo * @obj_desc: description of object's methods, signals and properties 525214501Srpaulo * Returns: 0 on success, -1 on error 526214501Srpaulo * 527214501Srpaulo * Registers a new interface with dbus and assigns it a dbus object path. 528214501Srpaulo */ 529214501Srpauloint wpa_dbus_register_object_per_iface( 530214501Srpaulo struct wpas_dbus_priv *ctrl_iface, 531214501Srpaulo const char *path, const char *ifname, 532214501Srpaulo struct wpa_dbus_object_desc *obj_desc) 533214501Srpaulo{ 534214501Srpaulo DBusConnection *con; 535252190Srpaulo DBusError error; 536214501Srpaulo 537214501Srpaulo DBusObjectPathVTable vtable = { 538214501Srpaulo &free_dbus_object_desc_cb, &message_handler, 539214501Srpaulo NULL, NULL, NULL, NULL 540214501Srpaulo }; 541214501Srpaulo 542214501Srpaulo /* Do nothing if the control interface is not turned on */ 543214501Srpaulo if (ctrl_iface == NULL) 544214501Srpaulo return 0; 545214501Srpaulo 546214501Srpaulo con = ctrl_iface->con; 547214501Srpaulo obj_desc->connection = con; 548214501Srpaulo obj_desc->path = os_strdup(path); 549214501Srpaulo 550252190Srpaulo dbus_error_init(&error); 551214501Srpaulo /* Register the message handler for the interface functions */ 552252190Srpaulo if (!dbus_connection_try_register_object_path(con, path, &vtable, 553252190Srpaulo obj_desc, &error)) { 554252190Srpaulo if (!os_strcmp(error.name, DBUS_ERROR_OBJECT_PATH_IN_USE)) { 555252190Srpaulo wpa_printf(MSG_DEBUG, "dbus: %s", error.message); 556252190Srpaulo } else { 557252190Srpaulo wpa_printf(MSG_ERROR, "dbus: Could not set up message " 558252190Srpaulo "handler for interface %s object %s", 559252190Srpaulo ifname, path); 560252190Srpaulo wpa_printf(MSG_ERROR, "dbus error: %s", error.name); 561252190Srpaulo wpa_printf(MSG_ERROR, "dbus: %s", error.message); 562252190Srpaulo } 563252190Srpaulo dbus_error_free(&error); 564214501Srpaulo return -1; 565214501Srpaulo } 566214501Srpaulo 567252190Srpaulo dbus_error_free(&error); 568214501Srpaulo return 0; 569214501Srpaulo} 570214501Srpaulo 571214501Srpaulo 572214501Srpaulostatic void flush_object_timeout_handler(void *eloop_ctx, void *timeout_ctx); 573214501Srpaulo 574214501Srpaulo 575214501Srpaulo/** 576214501Srpaulo * wpa_dbus_unregister_object_per_iface - Unregisters DBus object 577214501Srpaulo * @ctrl_iface: Pointer to dbus private data 578214501Srpaulo * @path: DBus path to object which will be unregistered 579214501Srpaulo * Returns: Zero on success and -1 on failure 580214501Srpaulo * 581214501Srpaulo * Unregisters DBus object given by its path 582214501Srpaulo */ 583214501Srpauloint wpa_dbus_unregister_object_per_iface( 584214501Srpaulo struct wpas_dbus_priv *ctrl_iface, const char *path) 585214501Srpaulo{ 586214501Srpaulo DBusConnection *con = ctrl_iface->con; 587214501Srpaulo struct wpa_dbus_object_desc *obj_desc = NULL; 588214501Srpaulo 589214501Srpaulo dbus_connection_get_object_path_data(con, path, (void **) &obj_desc); 590214501Srpaulo if (!obj_desc) { 591214501Srpaulo wpa_printf(MSG_ERROR, "dbus: %s: Could not obtain object's " 592214501Srpaulo "private data: %s", __func__, path); 593214501Srpaulo } else { 594214501Srpaulo eloop_cancel_timeout(flush_object_timeout_handler, con, 595214501Srpaulo obj_desc); 596214501Srpaulo } 597214501Srpaulo 598214501Srpaulo if (!dbus_connection_unregister_object_path(con, path)) 599214501Srpaulo return -1; 600214501Srpaulo 601214501Srpaulo return 0; 602214501Srpaulo} 603214501Srpaulo 604214501Srpaulo 605252190Srpaulostatic dbus_bool_t put_changed_properties( 606252190Srpaulo const struct wpa_dbus_object_desc *obj_dsc, const char *interface, 607252190Srpaulo DBusMessageIter *dict_iter, int clear_changed) 608214501Srpaulo{ 609252190Srpaulo DBusMessageIter entry_iter; 610214501Srpaulo const struct wpa_dbus_property_desc *dsc; 611214501Srpaulo int i; 612252190Srpaulo DBusError error; 613214501Srpaulo 614214501Srpaulo for (dsc = obj_dsc->properties, i = 0; dsc && dsc->dbus_property; 615214501Srpaulo dsc++, i++) { 616214501Srpaulo if (obj_dsc->prop_changed_flags == NULL || 617214501Srpaulo !obj_dsc->prop_changed_flags[i]) 618214501Srpaulo continue; 619214501Srpaulo if (os_strcmp(dsc->dbus_interface, interface) != 0) 620214501Srpaulo continue; 621252190Srpaulo if (clear_changed) 622252190Srpaulo obj_dsc->prop_changed_flags[i] = 0; 623214501Srpaulo 624252190Srpaulo if (!dbus_message_iter_open_container(dict_iter, 625252190Srpaulo DBUS_TYPE_DICT_ENTRY, 626252190Srpaulo NULL, &entry_iter)) 627252190Srpaulo return FALSE; 628214501Srpaulo 629252190Srpaulo if (!dbus_message_iter_append_basic(&entry_iter, 630214501Srpaulo DBUS_TYPE_STRING, 631214501Srpaulo &dsc->dbus_property)) 632252190Srpaulo return FALSE; 633214501Srpaulo 634252190Srpaulo dbus_error_init(&error); 635252190Srpaulo if (!dsc->getter(&entry_iter, &error, obj_dsc->user_data)) { 636252190Srpaulo if (dbus_error_is_set (&error)) { 637252190Srpaulo wpa_printf(MSG_ERROR, "dbus: %s: Cannot get " 638252190Srpaulo "new value of property %s: (%s) %s", 639252190Srpaulo __func__, dsc->dbus_property, 640252190Srpaulo error.name, error.message); 641252190Srpaulo } else { 642252190Srpaulo wpa_printf(MSG_ERROR, "dbus: %s: Cannot get " 643252190Srpaulo "new value of property %s", 644252190Srpaulo __func__, dsc->dbus_property); 645252190Srpaulo } 646252190Srpaulo dbus_error_free(&error); 647252190Srpaulo return FALSE; 648252190Srpaulo } 649214501Srpaulo 650214501Srpaulo if (!dbus_message_iter_close_container(dict_iter, &entry_iter)) 651252190Srpaulo return FALSE; 652214501Srpaulo } 653214501Srpaulo 654252190Srpaulo return TRUE; 655252190Srpaulo} 656252190Srpaulo 657252190Srpaulo 658252190Srpaulostatic void do_send_prop_changed_signal( 659252190Srpaulo DBusConnection *con, const char *path, const char *interface, 660252190Srpaulo const struct wpa_dbus_object_desc *obj_dsc) 661252190Srpaulo{ 662252190Srpaulo DBusMessage *msg; 663252190Srpaulo DBusMessageIter signal_iter, dict_iter; 664252190Srpaulo 665252190Srpaulo msg = dbus_message_new_signal(path, DBUS_INTERFACE_PROPERTIES, 666252190Srpaulo "PropertiesChanged"); 667252190Srpaulo if (msg == NULL) 668252190Srpaulo return; 669252190Srpaulo 670252190Srpaulo dbus_message_iter_init_append(msg, &signal_iter); 671252190Srpaulo 672252190Srpaulo if (!dbus_message_iter_append_basic(&signal_iter, DBUS_TYPE_STRING, 673252190Srpaulo &interface)) 674252190Srpaulo goto err; 675252190Srpaulo 676252190Srpaulo /* Changed properties dict */ 677252190Srpaulo if (!dbus_message_iter_open_container(&signal_iter, DBUS_TYPE_ARRAY, 678252190Srpaulo "{sv}", &dict_iter)) 679252190Srpaulo goto err; 680252190Srpaulo 681252190Srpaulo if (!put_changed_properties(obj_dsc, interface, &dict_iter, 0)) 682252190Srpaulo goto err; 683252190Srpaulo 684252190Srpaulo if (!dbus_message_iter_close_container(&signal_iter, &dict_iter)) 685252190Srpaulo goto err; 686252190Srpaulo 687252190Srpaulo /* Invalidated properties array (empty) */ 688252190Srpaulo if (!dbus_message_iter_open_container(&signal_iter, DBUS_TYPE_ARRAY, 689252190Srpaulo "s", &dict_iter)) 690252190Srpaulo goto err; 691252190Srpaulo 692252190Srpaulo if (!dbus_message_iter_close_container(&signal_iter, &dict_iter)) 693252190Srpaulo goto err; 694252190Srpaulo 695252190Srpaulo dbus_connection_send(con, msg, NULL); 696252190Srpaulo 697252190Srpauloout: 698252190Srpaulo dbus_message_unref(msg); 699214501Srpaulo return; 700214501Srpaulo 701214501Srpauloerr: 702252190Srpaulo wpa_printf(MSG_DEBUG, "dbus: %s: Failed to construct signal", 703252190Srpaulo __func__); 704252190Srpaulo goto out; 705214501Srpaulo} 706214501Srpaulo 707214501Srpaulo 708252190Srpaulostatic void do_send_deprecated_prop_changed_signal( 709214501Srpaulo DBusConnection *con, const char *path, const char *interface, 710214501Srpaulo const struct wpa_dbus_object_desc *obj_dsc) 711214501Srpaulo{ 712214501Srpaulo DBusMessage *msg; 713214501Srpaulo DBusMessageIter signal_iter, dict_iter; 714214501Srpaulo 715214501Srpaulo msg = dbus_message_new_signal(path, interface, "PropertiesChanged"); 716214501Srpaulo if (msg == NULL) 717214501Srpaulo return; 718214501Srpaulo 719214501Srpaulo dbus_message_iter_init_append(msg, &signal_iter); 720214501Srpaulo 721214501Srpaulo if (!dbus_message_iter_open_container(&signal_iter, DBUS_TYPE_ARRAY, 722214501Srpaulo "{sv}", &dict_iter)) 723214501Srpaulo goto err; 724214501Srpaulo 725252190Srpaulo if (!put_changed_properties(obj_dsc, interface, &dict_iter, 1)) 726252190Srpaulo goto err; 727214501Srpaulo 728214501Srpaulo if (!dbus_message_iter_close_container(&signal_iter, &dict_iter)) 729214501Srpaulo goto err; 730214501Srpaulo 731214501Srpaulo dbus_connection_send(con, msg, NULL); 732214501Srpaulo 733214501Srpauloout: 734214501Srpaulo dbus_message_unref(msg); 735214501Srpaulo return; 736214501Srpaulo 737214501Srpauloerr: 738214501Srpaulo wpa_printf(MSG_DEBUG, "dbus: %s: Failed to construct signal", 739214501Srpaulo __func__); 740214501Srpaulo goto out; 741214501Srpaulo} 742214501Srpaulo 743214501Srpaulo 744252190Srpaulostatic void send_prop_changed_signal( 745252190Srpaulo DBusConnection *con, const char *path, const char *interface, 746252190Srpaulo const struct wpa_dbus_object_desc *obj_dsc) 747252190Srpaulo{ 748252190Srpaulo /* 749252190Srpaulo * First, send property change notification on the standardized 750252190Srpaulo * org.freedesktop.DBus.Properties interface. This call will not 751252190Srpaulo * clear the property change bits, so that they are preserved for 752252190Srpaulo * the call that follows. 753252190Srpaulo */ 754252190Srpaulo do_send_prop_changed_signal(con, path, interface, obj_dsc); 755252190Srpaulo 756252190Srpaulo /* 757252190Srpaulo * Now send PropertiesChanged on our own interface for backwards 758252190Srpaulo * compatibility. This is deprecated and will be removed in a future 759252190Srpaulo * release. 760252190Srpaulo */ 761252190Srpaulo do_send_deprecated_prop_changed_signal(con, path, interface, obj_dsc); 762252190Srpaulo 763252190Srpaulo /* Property change bits have now been cleared. */ 764252190Srpaulo} 765252190Srpaulo 766252190Srpaulo 767214501Srpaulostatic void flush_object_timeout_handler(void *eloop_ctx, void *timeout_ctx) 768214501Srpaulo{ 769214501Srpaulo DBusConnection *con = eloop_ctx; 770214501Srpaulo struct wpa_dbus_object_desc *obj_desc = timeout_ctx; 771214501Srpaulo 772214501Srpaulo wpa_printf(MSG_DEBUG, "dbus: %s: Timeout - sending changed properties " 773214501Srpaulo "of object %s", __func__, obj_desc->path); 774214501Srpaulo wpa_dbus_flush_object_changed_properties(con, obj_desc->path); 775214501Srpaulo} 776214501Srpaulo 777214501Srpaulo 778214501Srpaulostatic void recursive_flush_changed_properties(DBusConnection *con, 779214501Srpaulo const char *path) 780214501Srpaulo{ 781214501Srpaulo char **objects = NULL; 782214501Srpaulo char subobj_path[WPAS_DBUS_OBJECT_PATH_MAX]; 783214501Srpaulo int i; 784214501Srpaulo 785214501Srpaulo wpa_dbus_flush_object_changed_properties(con, path); 786214501Srpaulo 787214501Srpaulo if (!dbus_connection_list_registered(con, path, &objects)) 788214501Srpaulo goto out; 789214501Srpaulo 790214501Srpaulo for (i = 0; objects[i]; i++) { 791214501Srpaulo os_snprintf(subobj_path, WPAS_DBUS_OBJECT_PATH_MAX, 792214501Srpaulo "%s/%s", path, objects[i]); 793214501Srpaulo recursive_flush_changed_properties(con, subobj_path); 794214501Srpaulo } 795214501Srpaulo 796214501Srpauloout: 797214501Srpaulo dbus_free_string_array(objects); 798214501Srpaulo} 799214501Srpaulo 800214501Srpaulo 801214501Srpaulo/** 802214501Srpaulo * wpa_dbus_flush_all_changed_properties - Send all PropertiesChanged signals 803214501Srpaulo * @con: DBus connection 804214501Srpaulo * 805214501Srpaulo * Traverses through all registered objects and sends PropertiesChanged for 806214501Srpaulo * each properties. 807214501Srpaulo */ 808214501Srpaulovoid wpa_dbus_flush_all_changed_properties(DBusConnection *con) 809214501Srpaulo{ 810214501Srpaulo recursive_flush_changed_properties(con, WPAS_DBUS_NEW_PATH); 811214501Srpaulo} 812214501Srpaulo 813214501Srpaulo 814214501Srpaulo/** 815214501Srpaulo * wpa_dbus_flush_object_changed_properties - Send PropertiesChanged for object 816214501Srpaulo * @con: DBus connection 817214501Srpaulo * @path: path to a DBus object for which PropertiesChanged will be sent. 818214501Srpaulo * 819214501Srpaulo * Iterates over all properties registered with object and for each interface 820214501Srpaulo * containing properties marked as changed, sends a PropertiesChanged signal 821214501Srpaulo * containing names and new values of properties that have changed. 822214501Srpaulo * 823214501Srpaulo * You need to call this function after wpa_dbus_mark_property_changed() 824214501Srpaulo * if you want to send PropertiesChanged signal immediately (i.e., without 825214501Srpaulo * waiting timeout to expire). PropertiesChanged signal for an object is sent 826214501Srpaulo * automatically short time after first marking property as changed. All 827214501Srpaulo * PropertiesChanged signals are sent automatically after responding on DBus 828214501Srpaulo * message, so if you marked a property changed as a result of DBus call 829214501Srpaulo * (e.g., param setter), you usually do not need to call this function. 830214501Srpaulo */ 831214501Srpaulovoid wpa_dbus_flush_object_changed_properties(DBusConnection *con, 832214501Srpaulo const char *path) 833214501Srpaulo{ 834214501Srpaulo struct wpa_dbus_object_desc *obj_desc = NULL; 835214501Srpaulo const struct wpa_dbus_property_desc *dsc; 836214501Srpaulo int i; 837214501Srpaulo 838214501Srpaulo dbus_connection_get_object_path_data(con, path, (void **) &obj_desc); 839214501Srpaulo if (!obj_desc) 840214501Srpaulo return; 841214501Srpaulo eloop_cancel_timeout(flush_object_timeout_handler, con, obj_desc); 842214501Srpaulo 843214501Srpaulo dsc = obj_desc->properties; 844214501Srpaulo for (dsc = obj_desc->properties, i = 0; dsc && dsc->dbus_property; 845214501Srpaulo dsc++, i++) { 846214501Srpaulo if (obj_desc->prop_changed_flags == NULL || 847214501Srpaulo !obj_desc->prop_changed_flags[i]) 848214501Srpaulo continue; 849214501Srpaulo send_prop_changed_signal(con, path, dsc->dbus_interface, 850214501Srpaulo obj_desc); 851214501Srpaulo } 852214501Srpaulo} 853214501Srpaulo 854214501Srpaulo 855214501Srpaulo#define WPA_DBUS_SEND_PROP_CHANGED_TIMEOUT 5000 856214501Srpaulo 857214501Srpaulo 858214501Srpaulo/** 859214501Srpaulo * wpa_dbus_mark_property_changed - Mark a property as changed and 860214501Srpaulo * @iface: dbus priv struct 861214501Srpaulo * @path: path to DBus object which property has changed 862214501Srpaulo * @interface: interface containing changed property 863214501Srpaulo * @property: property name which has changed 864214501Srpaulo * 865214501Srpaulo * Iterates over all properties registered with an object and marks the one 866214501Srpaulo * given in parameters as changed. All parameters registered for an object 867214501Srpaulo * within a single interface will be aggregated together and sent in one 868214501Srpaulo * PropertiesChanged signal when function 869214501Srpaulo * wpa_dbus_flush_object_changed_properties() is called. 870214501Srpaulo */ 871214501Srpaulovoid wpa_dbus_mark_property_changed(struct wpas_dbus_priv *iface, 872214501Srpaulo const char *path, const char *interface, 873214501Srpaulo const char *property) 874214501Srpaulo{ 875214501Srpaulo struct wpa_dbus_object_desc *obj_desc = NULL; 876214501Srpaulo const struct wpa_dbus_property_desc *dsc; 877214501Srpaulo int i = 0; 878214501Srpaulo 879214501Srpaulo if (iface == NULL) 880214501Srpaulo return; 881214501Srpaulo 882214501Srpaulo dbus_connection_get_object_path_data(iface->con, path, 883214501Srpaulo (void **) &obj_desc); 884214501Srpaulo if (!obj_desc) { 885214501Srpaulo wpa_printf(MSG_ERROR, "dbus: wpa_dbus_property_changed: " 886214501Srpaulo "could not obtain object's private data: %s", path); 887214501Srpaulo return; 888214501Srpaulo } 889214501Srpaulo 890214501Srpaulo for (dsc = obj_desc->properties; dsc && dsc->dbus_property; dsc++, i++) 891214501Srpaulo if (os_strcmp(property, dsc->dbus_property) == 0 && 892214501Srpaulo os_strcmp(interface, dsc->dbus_interface) == 0) { 893214501Srpaulo if (obj_desc->prop_changed_flags) 894214501Srpaulo obj_desc->prop_changed_flags[i] = 1; 895214501Srpaulo break; 896214501Srpaulo } 897214501Srpaulo 898214501Srpaulo if (!dsc || !dsc->dbus_property) { 899214501Srpaulo wpa_printf(MSG_ERROR, "dbus: wpa_dbus_property_changed: " 900214501Srpaulo "no property %s in object %s", property, path); 901214501Srpaulo return; 902214501Srpaulo } 903214501Srpaulo 904214501Srpaulo if (!eloop_is_timeout_registered(flush_object_timeout_handler, 905214501Srpaulo iface->con, obj_desc->path)) { 906214501Srpaulo eloop_register_timeout(0, WPA_DBUS_SEND_PROP_CHANGED_TIMEOUT, 907214501Srpaulo flush_object_timeout_handler, 908214501Srpaulo iface->con, obj_desc); 909214501Srpaulo } 910214501Srpaulo} 911214501Srpaulo 912214501Srpaulo 913214501Srpaulo/** 914214501Srpaulo * wpa_dbus_get_object_properties - Put object's properties into dictionary 915214501Srpaulo * @iface: dbus priv struct 916214501Srpaulo * @path: path to DBus object which properties will be obtained 917214501Srpaulo * @interface: interface name which properties will be obtained 918252190Srpaulo * @iter: DBus message iter at which to append property dictionary. 919214501Srpaulo * 920214501Srpaulo * Iterates over all properties registered with object and execute getters 921214501Srpaulo * of those, which are readable and which interface matches interface 922214501Srpaulo * specified as argument. Obtained properties values are stored in 923214501Srpaulo * dict_iter dictionary. 924214501Srpaulo */ 925252190Srpaulodbus_bool_t wpa_dbus_get_object_properties(struct wpas_dbus_priv *iface, 926252190Srpaulo const char *path, 927252190Srpaulo const char *interface, 928252190Srpaulo DBusMessageIter *iter) 929214501Srpaulo{ 930214501Srpaulo struct wpa_dbus_object_desc *obj_desc = NULL; 931252190Srpaulo DBusMessageIter dict_iter; 932252190Srpaulo DBusError error; 933214501Srpaulo 934214501Srpaulo dbus_connection_get_object_path_data(iface->con, path, 935214501Srpaulo (void **) &obj_desc); 936214501Srpaulo if (!obj_desc) { 937252190Srpaulo wpa_printf(MSG_ERROR, "dbus: %s: could not obtain object's " 938252190Srpaulo "private data: %s", __func__, path); 939252190Srpaulo return FALSE; 940214501Srpaulo } 941214501Srpaulo 942252190Srpaulo if (!wpa_dbus_dict_open_write(iter, &dict_iter)) { 943252190Srpaulo wpa_printf(MSG_ERROR, "dbus: %s: failed to open message dict", 944252190Srpaulo __func__); 945252190Srpaulo return FALSE; 946252190Srpaulo } 947252190Srpaulo 948252190Srpaulo dbus_error_init(&error); 949252190Srpaulo if (!fill_dict_with_properties(&dict_iter, obj_desc->properties, 950252190Srpaulo interface, obj_desc->user_data, 951252190Srpaulo &error)) { 952252190Srpaulo wpa_printf(MSG_ERROR, "dbus: %s: failed to get object" 953252190Srpaulo " properties: (%s) %s", __func__, 954252190Srpaulo dbus_error_is_set(&error) ? error.name : "none", 955252190Srpaulo dbus_error_is_set(&error) ? error.message : "none"); 956252190Srpaulo dbus_error_free(&error); 957252190Srpaulo return FALSE; 958252190Srpaulo } 959252190Srpaulo 960252190Srpaulo return wpa_dbus_dict_close_write(iter, &dict_iter); 961214501Srpaulo} 962252190Srpaulo 963252190Srpaulo/** 964252190Srpaulo * wpas_dbus_new_decompose_object_path - Decompose an interface object path into parts 965252190Srpaulo * @path: The dbus object path 966252190Srpaulo * @p2p_persistent_group: indicates whether to parse the path as a P2P 967252190Srpaulo * persistent group object 968252190Srpaulo * @network: (out) the configured network this object path refers to, if any 969252190Srpaulo * @bssid: (out) the scanned bssid this object path refers to, if any 970252190Srpaulo * Returns: The object path of the network interface this path refers to 971252190Srpaulo * 972252190Srpaulo * For a given object path, decomposes the object path into object id, network, 973252190Srpaulo * and BSSID parts, if those parts exist. 974252190Srpaulo */ 975252190Srpaulochar *wpas_dbus_new_decompose_object_path(const char *path, 976252190Srpaulo int p2p_persistent_group, 977252190Srpaulo char **network, 978252190Srpaulo char **bssid) 979252190Srpaulo{ 980252190Srpaulo const unsigned int dev_path_prefix_len = 981252190Srpaulo os_strlen(WPAS_DBUS_NEW_PATH_INTERFACES "/"); 982252190Srpaulo char *obj_path_only; 983252190Srpaulo char *next_sep; 984252190Srpaulo 985252190Srpaulo /* Be a bit paranoid about path */ 986252190Srpaulo if (!path || os_strncmp(path, WPAS_DBUS_NEW_PATH_INTERFACES "/", 987252190Srpaulo dev_path_prefix_len)) 988252190Srpaulo return NULL; 989252190Srpaulo 990252190Srpaulo /* Ensure there's something at the end of the path */ 991252190Srpaulo if ((path + dev_path_prefix_len)[0] == '\0') 992252190Srpaulo return NULL; 993252190Srpaulo 994252190Srpaulo obj_path_only = os_strdup(path); 995252190Srpaulo if (obj_path_only == NULL) 996252190Srpaulo return NULL; 997252190Srpaulo 998252190Srpaulo next_sep = os_strchr(obj_path_only + dev_path_prefix_len, '/'); 999252190Srpaulo if (next_sep != NULL) { 1000252190Srpaulo const char *net_part = os_strstr( 1001252190Srpaulo next_sep, p2p_persistent_group ? 1002252190Srpaulo WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/" : 1003252190Srpaulo WPAS_DBUS_NEW_NETWORKS_PART "/"); 1004252190Srpaulo const char *bssid_part = os_strstr( 1005252190Srpaulo next_sep, WPAS_DBUS_NEW_BSSIDS_PART "/"); 1006252190Srpaulo 1007252190Srpaulo if (network && net_part) { 1008252190Srpaulo /* Deal with a request for a configured network */ 1009252190Srpaulo const char *net_name = net_part + 1010252190Srpaulo os_strlen(p2p_persistent_group ? 1011252190Srpaulo WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART 1012252190Srpaulo "/" : 1013252190Srpaulo WPAS_DBUS_NEW_NETWORKS_PART "/"); 1014252190Srpaulo *network = NULL; 1015252190Srpaulo if (os_strlen(net_name)) 1016252190Srpaulo *network = os_strdup(net_name); 1017252190Srpaulo } else if (bssid && bssid_part) { 1018252190Srpaulo /* Deal with a request for a scanned BSSID */ 1019252190Srpaulo const char *bssid_name = bssid_part + 1020252190Srpaulo os_strlen(WPAS_DBUS_NEW_BSSIDS_PART "/"); 1021252190Srpaulo if (os_strlen(bssid_name)) 1022252190Srpaulo *bssid = os_strdup(bssid_name); 1023252190Srpaulo else 1024252190Srpaulo *bssid = NULL; 1025252190Srpaulo } 1026252190Srpaulo 1027252190Srpaulo /* Cut off interface object path before "/" */ 1028252190Srpaulo *next_sep = '\0'; 1029252190Srpaulo } 1030252190Srpaulo 1031252190Srpaulo return obj_path_only; 1032252190Srpaulo} 1033252190Srpaulo 1034252190Srpaulo 1035252190Srpaulo/** 1036252190Srpaulo * wpas_dbus_reply_new_from_error - Create a new D-Bus error message from a 1037252190Srpaulo * dbus error structure 1038252190Srpaulo * @message: The original request message for which the error is a reply 1039252190Srpaulo * @error: The error containing a name and a descriptive error cause 1040252190Srpaulo * @fallback_name: A generic error name if @error was not set 1041252190Srpaulo * @fallback_string: A generic error string if @error was not set 1042252190Srpaulo * Returns: A new D-Bus error message 1043252190Srpaulo * 1044252190Srpaulo * Given a DBusMessage structure, creates a new D-Bus error message using 1045252190Srpaulo * the error name and string contained in that structure. 1046252190Srpaulo */ 1047252190SrpauloDBusMessage * wpas_dbus_reply_new_from_error(DBusMessage *message, 1048252190Srpaulo DBusError *error, 1049252190Srpaulo const char *fallback_name, 1050252190Srpaulo const char *fallback_string) 1051252190Srpaulo{ 1052252190Srpaulo if (error && error->name && error->message) { 1053252190Srpaulo return dbus_message_new_error(message, error->name, 1054252190Srpaulo error->message); 1055252190Srpaulo } 1056252190Srpaulo if (fallback_name && fallback_string) { 1057252190Srpaulo return dbus_message_new_error(message, fallback_name, 1058252190Srpaulo fallback_string); 1059252190Srpaulo } 1060252190Srpaulo return NULL; 1061252190Srpaulo} 1062