dbus_new_helpers.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700
  1. /*
  2. * WPA Supplicant / dbus-based control interface
  3. * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
  4. * Copyright (c) 2009, Witold Sowa <witold.sowa@gmail.com>
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License version 2 as
  8. * published by the Free Software Foundation.
  9. *
  10. * Alternatively, this software may be distributed under the terms of BSD
  11. * license.
  12. *
  13. * See README and COPYING for more details.
  14. */
  15. #include "includes.h"
  16. #include "common.h"
  17. #include "dbus_common.h"
  18. #include "dbus_common_i.h"
  19. #include "dbus_new_helpers.h"
  20. /**
  21. * recursive_iter_copy - Reads arguments from one iterator and
  22. * writes to another recursively
  23. * @from: iterator to read from
  24. * @to: iterator to write to
  25. *
  26. * Copies one iterator's elements to another. If any element in
  27. * iterator is of container type, its content is copied recursively
  28. */
  29. static void recursive_iter_copy(DBusMessageIter *from, DBusMessageIter *to)
  30. {
  31. char *subtype = NULL;
  32. int type;
  33. /* iterate over iterator to copy */
  34. while ((type = dbus_message_iter_get_arg_type(from)) !=
  35. DBUS_TYPE_INVALID) {
  36. /* simply copy basic type entries */
  37. if (dbus_type_is_basic(type)) {
  38. if (dbus_type_is_fixed(type)) {
  39. /*
  40. * According to DBus documentation all
  41. * fixed-length types are guaranteed to fit
  42. * 8 bytes
  43. */
  44. dbus_uint64_t v;
  45. dbus_message_iter_get_basic(from, &v);
  46. dbus_message_iter_append_basic(to, type, &v);
  47. } else {
  48. char *v;
  49. dbus_message_iter_get_basic(from, &v);
  50. dbus_message_iter_append_basic(to, type, &v);
  51. }
  52. } else {
  53. /* recursively copy container type entries */
  54. DBusMessageIter write_subiter, read_subiter;
  55. dbus_message_iter_recurse(from, &read_subiter);
  56. if (type == DBUS_TYPE_VARIANT ||
  57. type == DBUS_TYPE_ARRAY) {
  58. subtype = dbus_message_iter_get_signature(
  59. &read_subiter);
  60. }
  61. dbus_message_iter_open_container(to, type, subtype,
  62. &write_subiter);
  63. recursive_iter_copy(&read_subiter, &write_subiter);
  64. dbus_message_iter_close_container(to, &write_subiter);
  65. if (subtype)
  66. dbus_free(subtype);
  67. }
  68. dbus_message_iter_next(from);
  69. }
  70. }
  71. static unsigned int fill_dict_with_properties(
  72. DBusMessageIter *dict_iter, const struct wpa_dbus_property_desc *props,
  73. const char *interface, const void *user_data)
  74. {
  75. DBusMessage *reply;
  76. DBusMessageIter entry_iter, ret_iter;
  77. unsigned int counter = 0;
  78. const struct wpa_dbus_property_desc *dsc;
  79. for (dsc = props; dsc && dsc->dbus_property; dsc++) {
  80. if (!os_strncmp(dsc->dbus_interface, interface,
  81. WPAS_DBUS_INTERFACE_MAX) &&
  82. dsc->access != W && dsc->getter) {
  83. reply = dsc->getter(NULL, user_data);
  84. if (!reply)
  85. continue;
  86. if (dbus_message_get_type(reply) ==
  87. DBUS_MESSAGE_TYPE_ERROR) {
  88. dbus_message_unref(reply);
  89. continue;
  90. }
  91. dbus_message_iter_init(reply, &ret_iter);
  92. dbus_message_iter_open_container(dict_iter,
  93. DBUS_TYPE_DICT_ENTRY,
  94. NULL, &entry_iter);
  95. dbus_message_iter_append_basic(
  96. &entry_iter, DBUS_TYPE_STRING,
  97. &dsc->dbus_property);
  98. recursive_iter_copy(&ret_iter, &entry_iter);
  99. dbus_message_iter_close_container(dict_iter,
  100. &entry_iter);
  101. dbus_message_unref(reply);
  102. counter++;
  103. }
  104. }
  105. return counter;
  106. }
  107. /**
  108. * get_all_properties - Responds for GetAll properties calls on object
  109. * @message: Message with GetAll call
  110. * @interface: interface name which properties will be returned
  111. * @property_dsc: list of object's properties
  112. * Returns: Message with dict of variants as argument with properties values
  113. *
  114. * Iterates over all properties registered with object and execute getters
  115. * of those, which are readable and which interface matches interface
  116. * specified as argument. Returned message contains one dict argument
  117. * with properties names as keys and theirs values as values.
  118. */
  119. static DBusMessage * get_all_properties(
  120. DBusMessage *message, char *interface,
  121. struct wpa_dbus_object_desc *obj_dsc)
  122. {
  123. /* Create and initialize the return message */
  124. DBusMessage *reply = dbus_message_new_method_return(message);
  125. DBusMessageIter iter, dict_iter;
  126. int props_num;
  127. dbus_message_iter_init_append(reply, &iter);
  128. dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
  129. DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
  130. DBUS_TYPE_STRING_AS_STRING
  131. DBUS_TYPE_VARIANT_AS_STRING
  132. DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
  133. &dict_iter);
  134. props_num = fill_dict_with_properties(&dict_iter, obj_dsc->properties,
  135. interface, obj_dsc->user_data);
  136. dbus_message_iter_close_container(&iter, &dict_iter);
  137. if (props_num == 0) {
  138. dbus_message_unref(reply);
  139. reply = dbus_message_new_error(message,
  140. DBUS_ERROR_INVALID_ARGS,
  141. "No readable properties in "
  142. "this interface");
  143. }
  144. return reply;
  145. }
  146. static int is_signature_correct(DBusMessage *message,
  147. const struct wpa_dbus_method_desc *method_dsc)
  148. {
  149. /* According to DBus documentation max length of signature is 255 */
  150. #define MAX_SIG_LEN 256
  151. char registered_sig[MAX_SIG_LEN], *pos;
  152. const char *sig = dbus_message_get_signature(message);
  153. int ret;
  154. const struct wpa_dbus_argument *arg;
  155. pos = registered_sig;
  156. *pos = '\0';
  157. for (arg = method_dsc->args; arg && arg->name; arg++) {
  158. if (arg->dir == ARG_IN) {
  159. size_t blen = registered_sig + MAX_SIG_LEN - pos;
  160. ret = os_snprintf(pos, blen, "%s", arg->type);
  161. if (ret < 0 || (size_t) ret >= blen)
  162. return 0;
  163. pos += ret;
  164. }
  165. }
  166. return !os_strncmp(registered_sig, sig, MAX_SIG_LEN);
  167. }
  168. static DBusMessage * properties_get_all(DBusMessage *message, char *interface,
  169. struct wpa_dbus_object_desc *obj_dsc)
  170. {
  171. if (os_strcmp(dbus_message_get_signature(message), "s") != 0)
  172. return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
  173. NULL);
  174. return get_all_properties(message, interface, obj_dsc);
  175. }
  176. static DBusMessage * properties_get(DBusMessage *message,
  177. const struct wpa_dbus_property_desc *dsc,
  178. void *user_data)
  179. {
  180. if (os_strcmp(dbus_message_get_signature(message), "ss"))
  181. return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
  182. NULL);
  183. if (dsc->access != W && dsc->getter)
  184. return dsc->getter(message, user_data);
  185. return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
  186. "Property is write-only");
  187. }
  188. static DBusMessage * properties_set(DBusMessage *message,
  189. const struct wpa_dbus_property_desc *dsc,
  190. void *user_data)
  191. {
  192. if (os_strcmp(dbus_message_get_signature(message), "ssv"))
  193. return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
  194. NULL);
  195. if (dsc->access != R && dsc->setter)
  196. return dsc->setter(message, user_data);
  197. return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
  198. "Property is read-only");
  199. }
  200. static DBusMessage *
  201. properties_get_or_set(DBusMessage *message, DBusMessageIter *iter,
  202. char *interface,
  203. struct wpa_dbus_object_desc *obj_dsc)
  204. {
  205. const struct wpa_dbus_property_desc *property_dsc;
  206. char *property;
  207. const char *method;
  208. method = dbus_message_get_member(message);
  209. property_dsc = obj_dsc->properties;
  210. /* Second argument: property name (DBUS_TYPE_STRING) */
  211. if (!dbus_message_iter_next(iter) ||
  212. dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING) {
  213. return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
  214. NULL);
  215. }
  216. dbus_message_iter_get_basic(iter, &property);
  217. while (property_dsc && property_dsc->dbus_property) {
  218. /* compare property names and
  219. * interfaces */
  220. if (!os_strncmp(property_dsc->dbus_property, property,
  221. WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) &&
  222. !os_strncmp(property_dsc->dbus_interface, interface,
  223. WPAS_DBUS_INTERFACE_MAX))
  224. break;
  225. property_dsc++;
  226. }
  227. if (property_dsc == NULL || property_dsc->dbus_property == NULL) {
  228. wpa_printf(MSG_DEBUG, "no property handler for %s.%s on %s",
  229. interface, property,
  230. dbus_message_get_path(message));
  231. return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
  232. "No such property");
  233. }
  234. if (os_strncmp(WPA_DBUS_PROPERTIES_GET, method,
  235. WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) == 0)
  236. return properties_get(message, property_dsc,
  237. obj_dsc->user_data);
  238. return properties_set(message, property_dsc, obj_dsc->user_data);
  239. }
  240. static DBusMessage * properties_handler(DBusMessage *message,
  241. struct wpa_dbus_object_desc *obj_dsc)
  242. {
  243. DBusMessageIter iter;
  244. char *interface;
  245. const char *method;
  246. method = dbus_message_get_member(message);
  247. dbus_message_iter_init(message, &iter);
  248. if (!os_strncmp(WPA_DBUS_PROPERTIES_GET, method,
  249. WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) ||
  250. !os_strncmp(WPA_DBUS_PROPERTIES_SET, method,
  251. WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) ||
  252. !os_strncmp(WPA_DBUS_PROPERTIES_GETALL, method,
  253. WPAS_DBUS_METHOD_SIGNAL_PROP_MAX)) {
  254. /* First argument: interface name (DBUS_TYPE_STRING) */
  255. if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
  256. {
  257. return dbus_message_new_error(message,
  258. DBUS_ERROR_INVALID_ARGS,
  259. NULL);
  260. }
  261. dbus_message_iter_get_basic(&iter, &interface);
  262. if (!os_strncmp(WPA_DBUS_PROPERTIES_GETALL, method,
  263. WPAS_DBUS_METHOD_SIGNAL_PROP_MAX)) {
  264. /* GetAll */
  265. return properties_get_all(message, interface, obj_dsc);
  266. }
  267. /* Get or Set */
  268. return properties_get_or_set(message, &iter, interface,
  269. obj_dsc);
  270. }
  271. return dbus_message_new_error(message, DBUS_ERROR_UNKNOWN_METHOD,
  272. NULL);
  273. }
  274. static DBusMessage * msg_method_handler(DBusMessage *message,
  275. struct wpa_dbus_object_desc *obj_dsc)
  276. {
  277. const struct wpa_dbus_method_desc *method_dsc = obj_dsc->methods;
  278. const char *method;
  279. const char *msg_interface;
  280. method = dbus_message_get_member(message);
  281. msg_interface = dbus_message_get_interface(message);
  282. /* try match call to any registered method */
  283. while (method_dsc && method_dsc->dbus_method) {
  284. /* compare method names and interfaces */
  285. if (!os_strncmp(method_dsc->dbus_method, method,
  286. WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) &&
  287. !os_strncmp(method_dsc->dbus_interface, msg_interface,
  288. WPAS_DBUS_INTERFACE_MAX))
  289. break;
  290. method_dsc++;
  291. }
  292. if (method_dsc == NULL || method_dsc->dbus_method == NULL) {
  293. wpa_printf(MSG_DEBUG, "no method handler for %s.%s on %s",
  294. msg_interface, method,
  295. dbus_message_get_path(message));
  296. return dbus_message_new_error(message,
  297. DBUS_ERROR_UNKNOWN_METHOD, NULL);
  298. }
  299. if (!is_signature_correct(message, method_dsc)) {
  300. return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
  301. NULL);
  302. }
  303. return method_dsc->method_handler(message,
  304. obj_dsc->user_data);
  305. }
  306. /**
  307. * message_handler - Handles incoming DBus messages
  308. * @connection: DBus connection on which message was received
  309. * @message: Received message
  310. * @user_data: pointer to description of object to which message was sent
  311. * Returns: Returns information whether message was handled or not
  312. *
  313. * Reads message interface and method name, then checks if they matches one
  314. * of the special cases i.e. introspection call or properties get/getall/set
  315. * methods and handles it. Else it iterates over registered methods list
  316. * and tries to match method's name and interface to those read from message
  317. * If appropriate method was found its handler function is called and
  318. * response is sent. Otherwise, the DBUS_ERROR_UNKNOWN_METHOD error message
  319. * will be sent.
  320. */
  321. static DBusHandlerResult message_handler(DBusConnection *connection,
  322. DBusMessage *message, void *user_data)
  323. {
  324. struct wpa_dbus_object_desc *obj_dsc = user_data;
  325. const char *method;
  326. const char *path;
  327. const char *msg_interface;
  328. DBusMessage *reply;
  329. /* get method, interface and path the message is addressed to */
  330. method = dbus_message_get_member(message);
  331. path = dbus_message_get_path(message);
  332. msg_interface = dbus_message_get_interface(message);
  333. if (!method || !path || !msg_interface)
  334. return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
  335. wpa_printf(MSG_MSGDUMP, "dbus: %s.%s (%s)",
  336. msg_interface, method, path);
  337. /* if message is introspection method call */
  338. if (!os_strncmp(WPA_DBUS_INTROSPECTION_METHOD, method,
  339. WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) &&
  340. !os_strncmp(WPA_DBUS_INTROSPECTION_INTERFACE, msg_interface,
  341. WPAS_DBUS_INTERFACE_MAX)) {
  342. #ifdef CONFIG_CTRL_IFACE_DBUS_INTRO
  343. reply = wpa_dbus_introspect(message, obj_dsc);
  344. #else /* CONFIG_CTRL_IFACE_DBUS_INTRO */
  345. reply = dbus_message_new_error(
  346. message, DBUS_ERROR_UNKNOWN_METHOD,
  347. "wpa_supplicant was compiled without "
  348. "introspection support.");
  349. #endif /* CONFIG_CTRL_IFACE_DBUS_INTRO */
  350. } else if (!os_strncmp(WPA_DBUS_PROPERTIES_INTERFACE, msg_interface,
  351. WPAS_DBUS_INTERFACE_MAX)) {
  352. /* if message is properties method call */
  353. reply = properties_handler(message, obj_dsc);
  354. } else {
  355. reply = msg_method_handler(message, obj_dsc);
  356. }
  357. /* If handler succeed returning NULL, reply empty message */
  358. if (!reply)
  359. reply = dbus_message_new_method_return(message);
  360. if (reply) {
  361. if (!dbus_message_get_no_reply(message))
  362. dbus_connection_send(connection, reply, NULL);
  363. dbus_message_unref(reply);
  364. }
  365. return DBUS_HANDLER_RESULT_HANDLED;
  366. }
  367. /**
  368. * free_dbus_object_desc - Frees object description data structure
  369. * @connection: DBus connection
  370. * @obj_dsc: Object description to free
  371. *
  372. * Frees each of properties, methods and signals description lists and
  373. * the object description structure itself.
  374. */
  375. void free_dbus_object_desc(struct wpa_dbus_object_desc *obj_dsc)
  376. {
  377. if (!obj_dsc)
  378. return;
  379. /* free handler's argument */
  380. if (obj_dsc->user_data_free_func)
  381. obj_dsc->user_data_free_func(obj_dsc->user_data);
  382. os_free(obj_dsc);
  383. }
  384. static void free_dbus_object_desc_cb(DBusConnection *connection, void *obj_dsc)
  385. {
  386. free_dbus_object_desc(obj_dsc);
  387. }
  388. /**
  389. * wpa_dbus_ctrl_iface_init - Initialize dbus control interface
  390. * @application_data: Pointer to application specific data structure
  391. * @dbus_path: DBus path to interface object
  392. * @dbus_service: DBus service name to register with
  393. * @messageHandler: a pointer to function which will handle dbus messages
  394. * coming on interface
  395. * Returns: 0 on success, -1 on failure
  396. *
  397. * Initialize the dbus control interface and start receiving commands from
  398. * external programs over the bus.
  399. */
  400. int wpa_dbus_ctrl_iface_init(struct wpas_dbus_priv *iface,
  401. char *dbus_path, char *dbus_service,
  402. struct wpa_dbus_object_desc *obj_desc)
  403. {
  404. DBusError error;
  405. int ret = -1;
  406. DBusObjectPathVTable wpa_vtable = {
  407. &free_dbus_object_desc_cb, &message_handler,
  408. NULL, NULL, NULL, NULL
  409. };
  410. obj_desc->connection = iface->con;
  411. /* Register the message handler for the global dbus interface */
  412. if (!dbus_connection_register_object_path(iface->con,
  413. dbus_path, &wpa_vtable,
  414. obj_desc)) {
  415. wpa_printf(MSG_ERROR, "dbus: Could not set up message "
  416. "handler");
  417. return -1;
  418. }
  419. /* Register our service with the message bus */
  420. dbus_error_init(&error);
  421. switch (dbus_bus_request_name(iface->con, dbus_service,
  422. 0, &error)) {
  423. case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER:
  424. ret = 0;
  425. break;
  426. case DBUS_REQUEST_NAME_REPLY_EXISTS:
  427. case DBUS_REQUEST_NAME_REPLY_IN_QUEUE:
  428. case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER:
  429. wpa_printf(MSG_ERROR, "dbus: Could not request service name: "
  430. "already registered");
  431. break;
  432. default:
  433. wpa_printf(MSG_ERROR, "dbus: Could not request service name: "
  434. "%s %s", error.name, error.message);
  435. break;
  436. }
  437. dbus_error_free(&error);
  438. if (ret != 0)
  439. return -1;
  440. wpa_printf(MSG_DEBUG, "Providing DBus service '%s'.", dbus_service);
  441. return 0;
  442. }
  443. /**
  444. * wpa_dbus_register_object_per_iface - Register a new object with dbus
  445. * @ctrl_iface: pointer to dbus private data
  446. * @path: DBus path to object
  447. * @ifname: interface name
  448. * @obj_desc: description of object's methods, signals and properties
  449. * Returns: 0 on success, -1 on error
  450. *
  451. * Registers a new interface with dbus and assigns it a dbus object path.
  452. */
  453. int wpa_dbus_register_object_per_iface(
  454. struct wpas_dbus_priv *ctrl_iface,
  455. const char *path, const char *ifname,
  456. struct wpa_dbus_object_desc *obj_desc)
  457. {
  458. DBusConnection *con;
  459. DBusObjectPathVTable vtable = {
  460. &free_dbus_object_desc_cb, &message_handler,
  461. NULL, NULL, NULL, NULL
  462. };
  463. /* Do nothing if the control interface is not turned on */
  464. if (ctrl_iface == NULL)
  465. return 0;
  466. con = ctrl_iface->con;
  467. obj_desc->connection = con;
  468. /* Register the message handler for the interface functions */
  469. if (!dbus_connection_register_object_path(con, path, &vtable,
  470. obj_desc)) {
  471. wpa_printf(MSG_ERROR, "dbus: Could not set up message "
  472. "handler for interface %s object %s", ifname, path);
  473. return -1;
  474. }
  475. return 0;
  476. }
  477. /**
  478. * wpa_dbus_unregister_object_per_iface - Unregisters DBus object
  479. * @ctrl_iface: Pointer to dbus private data
  480. * @path: DBus path to object which will be unregistered
  481. * Returns: Zero on success and -1 on failure
  482. *
  483. * Unregisters DBus object given by its path
  484. */
  485. int wpa_dbus_unregister_object_per_iface(
  486. struct wpas_dbus_priv *ctrl_iface, const char *path)
  487. {
  488. DBusConnection *con = ctrl_iface->con;
  489. if (!dbus_connection_unregister_object_path(con, path))
  490. return -1;
  491. return 0;
  492. }
  493. /**
  494. * wpas_dbus_signal_network_added - Send a property changed signal
  495. * @iface: dbus priv struct
  496. * @property_getter: propperty getter used to fetch new property value
  497. * @getter_arg: argument passed to property getter
  498. * @path: path to object which property has changed
  499. * @interface_name: signal and property interface
  500. * @property_name: name of property which has changed
  501. *
  502. * Notify listeners about changing value of some property. Signal
  503. * contains property name and its value fetched using given property
  504. * getter.
  505. */
  506. void wpa_dbus_signal_property_changed(struct wpas_dbus_priv *iface,
  507. WPADBusPropertyAccessor property_getter,
  508. void *getter_arg,
  509. const char *path,
  510. const char *interface_name,
  511. const char *property_name)
  512. {
  513. DBusConnection *connection;
  514. DBusMessage *msg, *getter_reply;
  515. DBusMessageIter prop_iter, signal_iter, dict_iter, entry_iter;
  516. if (!iface)
  517. return;
  518. connection = iface->con;
  519. if (!property_getter || !path || !interface_name || !property_name) {
  520. wpa_printf(MSG_ERROR, "dbus: %s: A parameter not specified",
  521. __func__);
  522. return;
  523. }
  524. getter_reply = property_getter(NULL, getter_arg);
  525. if (!getter_reply ||
  526. dbus_message_get_type(getter_reply) == DBUS_MESSAGE_TYPE_ERROR) {
  527. wpa_printf(MSG_ERROR, "dbus: %s: Cannot get new value of "
  528. "property %s", __func__, property_name);
  529. return;
  530. }
  531. msg = dbus_message_new_signal(path, interface_name,
  532. "PropertiesChanged");
  533. if (msg == NULL) {
  534. dbus_message_unref(getter_reply);
  535. return;
  536. }
  537. dbus_message_iter_init(getter_reply, &prop_iter);
  538. dbus_message_iter_init_append(msg, &signal_iter);
  539. if (!dbus_message_iter_open_container(&signal_iter, DBUS_TYPE_ARRAY,
  540. "{sv}", &dict_iter) ||
  541. !dbus_message_iter_open_container(&dict_iter, DBUS_TYPE_DICT_ENTRY,
  542. NULL, &entry_iter) ||
  543. !dbus_message_iter_append_basic(&entry_iter, DBUS_TYPE_STRING,
  544. &property_name))
  545. goto err;
  546. recursive_iter_copy(&prop_iter, &entry_iter);
  547. if (!dbus_message_iter_close_container(&dict_iter, &entry_iter) ||
  548. !dbus_message_iter_close_container(&signal_iter, &dict_iter))
  549. goto err;
  550. dbus_connection_send(connection, msg, NULL);
  551. out:
  552. dbus_message_unref(getter_reply);
  553. dbus_message_unref(msg);
  554. return;
  555. err:
  556. wpa_printf(MSG_DEBUG, "dbus: %s: Failed to construct signal",
  557. __func__);
  558. goto out;
  559. }
  560. /**
  561. * wpa_dbus_get_object_properties - Put object's properties into dictionary
  562. * @iface: dbus priv struct
  563. * @path: path to DBus object which properties will be obtained
  564. * @interface: interface name which properties will be obtained
  565. * @dict_iter: correct, open DBus dictionary iterator.
  566. *
  567. * Iterates over all properties registered with object and execute getters
  568. * of those, which are readable and which interface matches interface
  569. * specified as argument. Obtained properties values are stored in
  570. * dict_iter dictionary.
  571. */
  572. void wpa_dbus_get_object_properties(struct wpas_dbus_priv *iface,
  573. const char *path, const char *interface,
  574. DBusMessageIter *dict_iter)
  575. {
  576. struct wpa_dbus_object_desc *obj_desc = NULL;
  577. dbus_connection_get_object_path_data(iface->con, path,
  578. (void **) &obj_desc);
  579. if (!obj_desc) {
  580. wpa_printf(MSG_ERROR, "dbus: wpa_dbus_get_object_properties: "
  581. "could not obtain object's private data: %s", path);
  582. return;
  583. }
  584. fill_dict_with_properties(dict_iter, obj_desc->properties,
  585. interface, obj_desc->user_data);
  586. }