dbus_new_helpers.c 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050
  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, 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. struct wpa_dbus_property_desc *property_dsc;
  79. for (property_dsc = props; property_dsc;
  80. property_dsc = property_dsc->next) {
  81. if (!os_strncmp(property_dsc->dbus_interface, interface,
  82. WPAS_DBUS_INTERFACE_MAX) &&
  83. property_dsc->access != W && property_dsc->getter) {
  84. reply = property_dsc->getter(NULL, user_data);
  85. if (!reply)
  86. continue;
  87. if (dbus_message_get_type(reply) ==
  88. DBUS_MESSAGE_TYPE_ERROR) {
  89. dbus_message_unref(reply);
  90. continue;
  91. }
  92. dbus_message_iter_init(reply, &ret_iter);
  93. dbus_message_iter_open_container(dict_iter,
  94. DBUS_TYPE_DICT_ENTRY,
  95. NULL, &entry_iter);
  96. dbus_message_iter_append_basic(
  97. &entry_iter, DBUS_TYPE_STRING,
  98. &(property_dsc->dbus_property));
  99. recursive_iter_copy(&ret_iter, &entry_iter);
  100. dbus_message_iter_close_container(dict_iter,
  101. &entry_iter);
  102. dbus_message_unref(reply);
  103. counter++;
  104. }
  105. }
  106. return counter;
  107. }
  108. /**
  109. * get_all_properties - Responds for GetAll properties calls on object
  110. * @message: Message with GetAll call
  111. * @interface: interface name which properties will be returned
  112. * @property_dsc: list of object's properties
  113. * Returns: Message with dict of variants as argument with properties values
  114. *
  115. * Iterates over all properties registered with object and execute getters
  116. * of those, which are readable and which interface matches interface
  117. * specified as argument. Returned message contains one dict argument
  118. * with properties names as keys and theirs values as values.
  119. */
  120. static DBusMessage * get_all_properties(
  121. DBusMessage *message, char *interface,
  122. struct wpa_dbus_object_desc *obj_dsc)
  123. {
  124. /* Create and initialize the return message */
  125. DBusMessage *reply = dbus_message_new_method_return(message);
  126. DBusMessageIter iter, dict_iter;
  127. int props_num;
  128. dbus_message_iter_init_append(reply, &iter);
  129. dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
  130. DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
  131. DBUS_TYPE_STRING_AS_STRING
  132. DBUS_TYPE_VARIANT_AS_STRING
  133. DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
  134. &dict_iter);
  135. props_num = fill_dict_with_properties(&dict_iter,obj_dsc->properties,
  136. interface, obj_dsc->user_data);
  137. dbus_message_iter_close_container(&iter, &dict_iter);
  138. if (props_num == 0) {
  139. dbus_message_unref(reply);
  140. reply = dbus_message_new_error(message,
  141. DBUS_ERROR_INVALID_ARGS,
  142. "No readable properties in "
  143. "this interface");
  144. }
  145. return reply;
  146. }
  147. static int is_signature_correct(DBusMessage *message,
  148. struct wpa_dbus_method_desc *method_dsc)
  149. {
  150. /* According to DBus documentation max length of signature is 255 */
  151. #define MAX_SIG_LEN 256
  152. char registered_sig[MAX_SIG_LEN], *pos;
  153. const char *sig = dbus_message_get_signature(message);
  154. int i, ret;
  155. pos = registered_sig;
  156. *pos = '\0';
  157. for (i = 0; i < method_dsc->args_num; i++) {
  158. struct wpa_dbus_argument arg = method_dsc->args[i];
  159. if (arg.dir == ARG_IN) {
  160. size_t blen = registered_sig + MAX_SIG_LEN - pos;
  161. ret = os_snprintf(pos, blen, "%s", arg.type);
  162. if (ret < 0 || (size_t) ret >= blen)
  163. return 0;
  164. pos += ret;
  165. }
  166. }
  167. return !os_strncmp(registered_sig, sig, MAX_SIG_LEN);
  168. }
  169. static DBusMessage * properties_get_all(DBusMessage *message, char *interface,
  170. struct wpa_dbus_object_desc *obj_dsc)
  171. {
  172. if (os_strcmp(dbus_message_get_signature(message), "s") != 0)
  173. return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
  174. NULL);
  175. return get_all_properties(message, interface, obj_dsc);
  176. }
  177. static DBusMessage * properties_get(DBusMessage *message,
  178. struct wpa_dbus_property_desc *dsc,
  179. void *user_data)
  180. {
  181. if (os_strcmp(dbus_message_get_signature(message), "ss"))
  182. return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
  183. NULL);
  184. if (dsc->access != W && dsc->getter)
  185. return dsc->getter(message, user_data);
  186. return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
  187. "Property is write-only");
  188. }
  189. static DBusMessage * properties_set(DBusMessage *message,
  190. struct wpa_dbus_property_desc *dsc,
  191. void *user_data)
  192. {
  193. if (os_strcmp(dbus_message_get_signature(message), "ssv"))
  194. return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
  195. NULL);
  196. if (dsc->access != R && dsc->setter)
  197. return dsc->setter(message, user_data);
  198. return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
  199. "Property is read-only");
  200. }
  201. static DBusMessage *
  202. properties_get_or_set(DBusMessage *message, DBusMessageIter *iter,
  203. char *interface,
  204. struct wpa_dbus_object_desc *obj_dsc)
  205. {
  206. struct wpa_dbus_property_desc *property_dsc;
  207. char *property;
  208. const char *method;
  209. method = dbus_message_get_member(message);
  210. property_dsc = obj_dsc->properties;
  211. /* Second argument: property name (DBUS_TYPE_STRING) */
  212. if (!dbus_message_iter_next(iter) ||
  213. dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING) {
  214. return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
  215. NULL);
  216. }
  217. dbus_message_iter_get_basic(iter, &property);
  218. while (property_dsc) {
  219. /* compare property names and
  220. * interfaces */
  221. if (!os_strncmp(property_dsc->dbus_property, property,
  222. WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) &&
  223. !os_strncmp(property_dsc->dbus_interface, interface,
  224. WPAS_DBUS_INTERFACE_MAX))
  225. break;
  226. property_dsc = property_dsc->next;
  227. }
  228. if (property_dsc == NULL) {
  229. wpa_printf(MSG_DEBUG, "no property handler for %s.%s on %s",
  230. interface, property,
  231. dbus_message_get_path(message));
  232. return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
  233. "No such property");
  234. }
  235. if (os_strncmp(WPA_DBUS_PROPERTIES_GET, method,
  236. WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) == 0)
  237. return properties_get(message, property_dsc,
  238. obj_dsc->user_data);
  239. return properties_set(message, property_dsc, obj_dsc->user_data);
  240. }
  241. static DBusMessage * properties_handler(DBusMessage *message,
  242. struct wpa_dbus_object_desc *obj_dsc)
  243. {
  244. DBusMessageIter iter;
  245. char *interface;
  246. const char *method;
  247. method = dbus_message_get_member(message);
  248. dbus_message_iter_init(message, &iter);
  249. if (!os_strncmp(WPA_DBUS_PROPERTIES_GET, method,
  250. WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) ||
  251. !os_strncmp(WPA_DBUS_PROPERTIES_SET, method,
  252. WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) ||
  253. !os_strncmp(WPA_DBUS_PROPERTIES_GETALL, method,
  254. WPAS_DBUS_METHOD_SIGNAL_PROP_MAX)) {
  255. /* First argument: interface name (DBUS_TYPE_STRING) */
  256. if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
  257. {
  258. return dbus_message_new_error(message,
  259. DBUS_ERROR_INVALID_ARGS,
  260. NULL);
  261. }
  262. dbus_message_iter_get_basic(&iter, &interface);
  263. if (!os_strncmp(WPA_DBUS_PROPERTIES_GETALL, method,
  264. WPAS_DBUS_METHOD_SIGNAL_PROP_MAX)) {
  265. /* GetAll */
  266. return properties_get_all(message, interface, obj_dsc);
  267. }
  268. /* Get or Set */
  269. return properties_get_or_set(message, &iter, interface,
  270. obj_dsc);
  271. }
  272. return dbus_message_new_error(message, DBUS_ERROR_UNKNOWN_METHOD,
  273. NULL);
  274. }
  275. static DBusMessage * msg_method_handler(DBusMessage *message,
  276. struct wpa_dbus_object_desc *obj_dsc)
  277. {
  278. struct wpa_dbus_method_desc *method_dsc = obj_dsc->methods;
  279. const char *method;
  280. const char *msg_interface;
  281. method = dbus_message_get_member(message);
  282. msg_interface = dbus_message_get_interface(message);
  283. /* try match call to any registered method */
  284. while (method_dsc) {
  285. /* compare method names and interfaces */
  286. if (!os_strncmp(method_dsc->dbus_method, method,
  287. WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) &&
  288. !os_strncmp(method_dsc->dbus_interface, msg_interface,
  289. WPAS_DBUS_INTERFACE_MAX))
  290. break;
  291. method_dsc = method_dsc->next;
  292. }
  293. if (method_dsc == NULL) {
  294. wpa_printf(MSG_DEBUG, "no method handler for %s.%s on %s",
  295. msg_interface, method,
  296. dbus_message_get_path(message));
  297. return dbus_message_new_error(message,
  298. DBUS_ERROR_UNKNOWN_METHOD, NULL);
  299. }
  300. if (!is_signature_correct(message, method_dsc)) {
  301. return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
  302. NULL);
  303. }
  304. return method_dsc->method_handler(message,
  305. obj_dsc->user_data);
  306. }
  307. /**
  308. * message_handler - Handles incoming DBus messages
  309. * @connection: DBus connection on which message was received
  310. * @message: Received message
  311. * @user_data: pointer to description of object to which message was sent
  312. * Returns: Returns information whether message was handled or not
  313. *
  314. * Reads message interface and method name, then checks if they matches one
  315. * of the special cases i.e. introspection call or properties get/getall/set
  316. * methods and handles it. Else it iterates over registered methods list
  317. * and tries to match method's name and interface to those read from message
  318. * If appropriate method was found its handler function is called and
  319. * response is sent. Otherwise, the DBUS_ERROR_UNKNOWN_METHOD error message
  320. * will be sent.
  321. */
  322. static DBusHandlerResult message_handler(DBusConnection *connection,
  323. DBusMessage *message, void *user_data)
  324. {
  325. struct wpa_dbus_object_desc *obj_dsc = user_data;
  326. const char *method;
  327. const char *path;
  328. const char *msg_interface;
  329. DBusMessage *reply;
  330. /* get method, interface and path the message is addressed to */
  331. method = dbus_message_get_member(message);
  332. path = dbus_message_get_path(message);
  333. msg_interface = dbus_message_get_interface(message);
  334. if (!method || !path || !msg_interface)
  335. return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
  336. wpa_printf(MSG_MSGDUMP, "dbus: %s.%s (%s)",
  337. msg_interface, method, path);
  338. /* if message is introspection method call */
  339. if (!os_strncmp(WPA_DBUS_INTROSPECTION_METHOD, method,
  340. WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) &&
  341. !os_strncmp(WPA_DBUS_INTROSPECTION_INTERFACE, msg_interface,
  342. WPAS_DBUS_INTERFACE_MAX)) {
  343. #ifdef CONFIG_CTRL_IFACE_DBUS_INTRO
  344. reply = wpa_dbus_introspect(message, obj_dsc);
  345. #else /* CONFIG_CTRL_IFACE_DBUS_INTRO */
  346. reply = dbus_message_new_error(
  347. message, DBUS_ERROR_UNKNOWN_METHOD,
  348. "wpa_supplicant was compiled without "
  349. "introspection support.");
  350. #endif /* CONFIG_CTRL_IFACE_DBUS_INTRO */
  351. } else if (!os_strncmp(WPA_DBUS_PROPERTIES_INTERFACE, msg_interface,
  352. WPAS_DBUS_INTERFACE_MAX)) {
  353. /* if message is properties method call */
  354. reply = properties_handler(message, obj_dsc);
  355. } else {
  356. reply = msg_method_handler(message, obj_dsc);
  357. }
  358. /* If handler succeed returning NULL, reply empty message */
  359. if (!reply)
  360. reply = dbus_message_new_method_return(message);
  361. if (reply) {
  362. if (!dbus_message_get_no_reply(message))
  363. dbus_connection_send(connection, reply, NULL);
  364. dbus_message_unref(reply);
  365. }
  366. return DBUS_HANDLER_RESULT_HANDLED;
  367. }
  368. /**
  369. * free_dbus_object_desc - Frees object description data structure
  370. * @connection: DBus connection
  371. * @obj_dsc: Object description to free
  372. *
  373. * Frees each of properties, methods and signals description lists and
  374. * the object description structure itself.
  375. */
  376. void free_dbus_object_desc(struct wpa_dbus_object_desc *obj_dsc)
  377. {
  378. struct wpa_dbus_method_desc *method_dsc, *tmp_met_dsc;
  379. struct wpa_dbus_signal_desc *signal_dsc, *tmp_sig_dsc;
  380. struct wpa_dbus_property_desc *property_dsc, *tmp_prop_dsc;
  381. int i;
  382. if (!obj_dsc)
  383. return;
  384. /* free methods */
  385. method_dsc = obj_dsc->methods;
  386. while (method_dsc) {
  387. tmp_met_dsc = method_dsc;
  388. method_dsc = method_dsc->next;
  389. os_free(tmp_met_dsc->dbus_interface);
  390. os_free(tmp_met_dsc->dbus_method);
  391. for (i = 0; i < tmp_met_dsc->args_num; i++) {
  392. os_free(tmp_met_dsc->args[i].name);
  393. os_free(tmp_met_dsc->args[i].type);
  394. }
  395. os_free(tmp_met_dsc);
  396. }
  397. /* free signals */
  398. signal_dsc = obj_dsc->signals;
  399. while (signal_dsc) {
  400. tmp_sig_dsc = signal_dsc;
  401. signal_dsc = signal_dsc->next;
  402. os_free(tmp_sig_dsc->dbus_interface);
  403. os_free(tmp_sig_dsc->dbus_signal);
  404. for (i = 0; i < tmp_sig_dsc->args_num; i++) {
  405. os_free(tmp_sig_dsc->args[i].name);
  406. os_free(tmp_sig_dsc->args[i].type);
  407. }
  408. os_free(tmp_sig_dsc);
  409. }
  410. /* free properties */
  411. property_dsc = obj_dsc->properties;
  412. while (property_dsc) {
  413. tmp_prop_dsc = property_dsc;
  414. property_dsc = property_dsc->next;
  415. os_free(tmp_prop_dsc->dbus_interface);
  416. os_free(tmp_prop_dsc->dbus_property);
  417. os_free(tmp_prop_dsc->type);
  418. os_free(tmp_prop_dsc);
  419. }
  420. /* free handler's argument */
  421. if (obj_dsc->user_data_free_func)
  422. obj_dsc->user_data_free_func(obj_dsc->user_data);
  423. os_free(obj_dsc);
  424. }
  425. static void free_dbus_object_desc_cb(DBusConnection *connection, void *obj_dsc)
  426. {
  427. free_dbus_object_desc(obj_dsc);
  428. }
  429. /**
  430. * wpa_dbus_ctrl_iface_init - Initialize dbus control interface
  431. * @application_data: Pointer to application specific data structure
  432. * @dbus_path: DBus path to interface object
  433. * @dbus_service: DBus service name to register with
  434. * @messageHandler: a pointer to function which will handle dbus messages
  435. * coming on interface
  436. * Returns: 0 on success, -1 on failure
  437. *
  438. * Initialize the dbus control interface and start receiving commands from
  439. * external programs over the bus.
  440. */
  441. int wpa_dbus_ctrl_iface_init(struct wpas_dbus_priv *iface,
  442. char *dbus_path, char *dbus_service,
  443. struct wpa_dbus_object_desc *obj_desc)
  444. {
  445. DBusError error;
  446. int ret = -1;
  447. DBusObjectPathVTable wpa_vtable = {
  448. &free_dbus_object_desc_cb, &message_handler,
  449. NULL, NULL, NULL, NULL
  450. };
  451. obj_desc->connection = iface->con;
  452. /* Register the message handler for the global dbus interface */
  453. if (!dbus_connection_register_object_path(iface->con,
  454. dbus_path, &wpa_vtable,
  455. obj_desc)) {
  456. wpa_printf(MSG_ERROR, "dbus: Could not set up message "
  457. "handler");
  458. return -1;
  459. }
  460. /* Register our service with the message bus */
  461. dbus_error_init(&error);
  462. switch (dbus_bus_request_name(iface->con, dbus_service,
  463. 0, &error)) {
  464. case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER:
  465. ret = 0;
  466. break;
  467. case DBUS_REQUEST_NAME_REPLY_EXISTS:
  468. case DBUS_REQUEST_NAME_REPLY_IN_QUEUE:
  469. case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER:
  470. wpa_printf(MSG_ERROR, "dbus: Could not request service name: "
  471. "already registered");
  472. break;
  473. default:
  474. wpa_printf(MSG_ERROR, "dbus: Could not request service name: "
  475. "%s %s", error.name, error.message);
  476. break;
  477. }
  478. dbus_error_free(&error);
  479. if (ret != 0)
  480. return -1;
  481. wpa_printf(MSG_DEBUG, "Providing DBus service '%s'.", dbus_service);
  482. return 0;
  483. }
  484. /**
  485. * wpa_dbus_register_object_per_iface - Register a new object with dbus
  486. * @ctrl_iface: pointer to dbus private data
  487. * @path: DBus path to object
  488. * @ifname: interface name
  489. * @obj_desc: description of object's methods, signals and properties
  490. * Returns: 0 on success, -1 on error
  491. *
  492. * Registers a new interface with dbus and assigns it a dbus object path.
  493. */
  494. int wpa_dbus_register_object_per_iface(
  495. struct wpas_dbus_priv *ctrl_iface,
  496. const char *path, const char *ifname,
  497. struct wpa_dbus_object_desc *obj_desc)
  498. {
  499. DBusConnection *con;
  500. DBusObjectPathVTable vtable = {
  501. &free_dbus_object_desc_cb, &message_handler,
  502. NULL, NULL, NULL, NULL
  503. };
  504. /* Do nothing if the control interface is not turned on */
  505. if (ctrl_iface == NULL)
  506. return 0;
  507. con = ctrl_iface->con;
  508. obj_desc->connection = con;
  509. /* Register the message handler for the interface functions */
  510. if (!dbus_connection_register_object_path(con, path, &vtable,
  511. obj_desc)) {
  512. wpa_printf(MSG_ERROR, "dbus: Could not set up message "
  513. "handler for interface %s object %s", ifname, path);
  514. return -1;
  515. }
  516. return 0;
  517. }
  518. /**
  519. * wpa_dbus_unregister_object_per_iface - Unregisters DBus object
  520. * @ctrl_iface: Pointer to dbus private data
  521. * @path: DBus path to object which will be unregistered
  522. * Returns: Zero on success and -1 on failure
  523. *
  524. * Unregisters DBus object given by its path
  525. */
  526. int wpa_dbus_unregister_object_per_iface(
  527. struct wpas_dbus_priv *ctrl_iface, const char *path)
  528. {
  529. DBusConnection *con = ctrl_iface->con;
  530. if (!dbus_connection_unregister_object_path(con, path))
  531. return -1;
  532. return 0;
  533. }
  534. /**
  535. * wpa_dbus_method_register - Registers DBus method for given object
  536. * @obj_dsc: Object description for which a method will be registered
  537. * @dbus_interface: DBus interface under which method will be registered
  538. * @dbus_method: a name the method will be registered with
  539. * @method_handler: a function which will be called to handle this method call
  540. * @args: method arguments list
  541. * Returns: Zero on success and -1 on failure
  542. *
  543. * Registers DBus method under given name and interface for the object.
  544. * Method calls will be handled with given handling function.
  545. * Handler function is required to return a DBusMessage pointer which
  546. * will be response to method call. Any method call before being handled
  547. * must have registered appropriate handler by using this function.
  548. */
  549. int wpa_dbus_method_register(struct wpa_dbus_object_desc *obj_dsc,
  550. const char *dbus_interface,
  551. const char *dbus_method,
  552. WPADBusMethodHandler method_handler,
  553. const struct wpa_dbus_argument args[])
  554. {
  555. struct wpa_dbus_method_desc *method_dsc = obj_dsc->methods;
  556. struct wpa_dbus_method_desc *prev_desc;
  557. int args_num = 0;
  558. int i, error;
  559. prev_desc = NULL;
  560. while (method_dsc) {
  561. prev_desc = method_dsc;
  562. method_dsc = method_dsc->next;
  563. }
  564. /* count args */
  565. if (args) {
  566. while (args[args_num].name && args[args_num].type)
  567. args_num++;
  568. }
  569. method_dsc = os_zalloc(sizeof(struct wpa_dbus_method_desc) +
  570. args_num * sizeof(struct wpa_dbus_argument));
  571. if (!method_dsc)
  572. goto err;
  573. if (prev_desc == NULL)
  574. obj_dsc->methods = method_dsc;
  575. else
  576. prev_desc->next = method_dsc;
  577. /* copy interface name */
  578. method_dsc->dbus_interface = os_strdup(dbus_interface);
  579. if (!method_dsc->dbus_interface)
  580. goto err;
  581. /* copy method name */
  582. method_dsc->dbus_method = os_strdup(dbus_method);
  583. if (!method_dsc->dbus_method)
  584. goto err;
  585. /* copy arguments */
  586. error = 0;
  587. method_dsc->args_num = args_num;
  588. for (i = 0; i < args_num; i++) {
  589. method_dsc->args[i].name = os_strdup(args[i].name);
  590. if (!method_dsc->args[i].name) {
  591. error = 1;
  592. continue;
  593. }
  594. method_dsc->args[i].type = os_strdup(args[i].type);
  595. if (!method_dsc->args[i].type) {
  596. error = 1;
  597. continue;
  598. }
  599. method_dsc->args[i].dir = args[i].dir;
  600. }
  601. if (error)
  602. goto err;
  603. method_dsc->method_handler = method_handler;
  604. method_dsc->next = NULL;
  605. return 0;
  606. err:
  607. wpa_printf(MSG_WARNING, "Failed to register dbus method %s in "
  608. "interface %s", dbus_method, dbus_interface);
  609. if (method_dsc) {
  610. os_free(method_dsc->dbus_interface);
  611. os_free(method_dsc->dbus_method);
  612. for (i = 0; i < method_dsc->args_num; i++) {
  613. os_free(method_dsc->args[i].name);
  614. os_free(method_dsc->args[i].type);
  615. }
  616. if (prev_desc == NULL)
  617. obj_dsc->methods = NULL;
  618. else
  619. prev_desc->next = NULL;
  620. os_free(method_dsc);
  621. }
  622. return -1;
  623. }
  624. /**
  625. * wpa_dbus_signal_register - Registers DBus signal for given object
  626. * @obj_dsc: Object description for which a signal will be registered
  627. * @dbus_interface: DBus interface under which signal will be registered
  628. * @dbus_signal: a name the signal will be registered with
  629. * @args: signal arguments list
  630. * Returns: Zero on success and -1 on failure
  631. *
  632. * Registers DBus signal under given name and interface for the object.
  633. * Signal registration is NOT required in order to send signals, but not
  634. * registered signals will not be respected in introspection data
  635. * therefore it is highly recommended to register every signal before
  636. * using it.
  637. */
  638. int wpa_dbus_signal_register(struct wpa_dbus_object_desc *obj_dsc,
  639. const char *dbus_interface,
  640. const char *dbus_signal,
  641. const struct wpa_dbus_argument args[])
  642. {
  643. struct wpa_dbus_signal_desc *signal_dsc = obj_dsc->signals;
  644. struct wpa_dbus_signal_desc *prev_desc;
  645. int args_num = 0;
  646. int i, error = 0;
  647. prev_desc = NULL;
  648. while (signal_dsc) {
  649. prev_desc = signal_dsc;
  650. signal_dsc = signal_dsc->next;
  651. }
  652. /* count args */
  653. if (args) {
  654. while (args[args_num].name && args[args_num].type)
  655. args_num++;
  656. }
  657. signal_dsc = os_zalloc(sizeof(struct wpa_dbus_signal_desc) +
  658. args_num * sizeof(struct wpa_dbus_argument));
  659. if (!signal_dsc)
  660. goto err;
  661. if (prev_desc == NULL)
  662. obj_dsc->signals = signal_dsc;
  663. else
  664. prev_desc->next = signal_dsc;
  665. /* copy interface name */
  666. signal_dsc->dbus_interface = os_strdup(dbus_interface);
  667. if (!signal_dsc->dbus_interface)
  668. goto err;
  669. /* copy signal name */
  670. signal_dsc->dbus_signal = os_strdup(dbus_signal);
  671. if (!signal_dsc->dbus_signal)
  672. goto err;
  673. /* copy arguments */
  674. signal_dsc->args_num = args_num;
  675. for (i = 0; i < args_num; i++) {
  676. signal_dsc->args[i].name = os_strdup(args[i].name);
  677. if (!signal_dsc->args[i].name) {
  678. error = 1;
  679. continue;
  680. }
  681. signal_dsc->args[i].type = os_strdup(args[i].type);
  682. if (!signal_dsc->args[i].type) {
  683. error = 1;
  684. continue;
  685. }
  686. }
  687. if (error)
  688. goto err;
  689. signal_dsc->next = NULL;
  690. return 0;
  691. err:
  692. wpa_printf(MSG_WARNING, "Failed to register dbus signal %s in "
  693. "interface %s", dbus_signal, dbus_interface);
  694. if (signal_dsc) {
  695. os_free(signal_dsc->dbus_interface);
  696. os_free(signal_dsc->dbus_signal);
  697. for (i = 0; i < signal_dsc->args_num; i++) {
  698. os_free(signal_dsc->args[i].name);
  699. os_free(signal_dsc->args[i].type);
  700. }
  701. if (prev_desc == NULL)
  702. obj_dsc->signals = NULL;
  703. else
  704. prev_desc->next = NULL;
  705. os_free(signal_dsc);
  706. }
  707. return -1;
  708. }
  709. /**
  710. * wpa_dbus_property_register - Registers DBus property for given object
  711. * @obj_dsc: Object description for which a property will be registered
  712. * @dbus_interface: DBus interface under which method will be registered
  713. * @dbus_property: a name the property will be registered with
  714. * @type: a property type signature in form of DBus type description
  715. * @getter: a function called in order to get property value
  716. * @setter: a function called in order to set property value
  717. * @access: property access permissions specifier (R, W or RW)
  718. * Returns: Zero on success and -1 on failure
  719. *
  720. * Registers DBus property under given name and interface for the object.
  721. * Properties are set with giver setter function and get with getter.Getter
  722. * or setter are required to return DBusMessage which is response to Set/Get
  723. * method calls. Every property must be registered by this function before
  724. * being used.
  725. */
  726. int wpa_dbus_property_register(struct wpa_dbus_object_desc *obj_dsc,
  727. const char *dbus_interface,
  728. const char *dbus_property,
  729. const char *type,
  730. WPADBusPropertyAccessor getter,
  731. WPADBusPropertyAccessor setter,
  732. enum dbus_prop_access _access)
  733. {
  734. struct wpa_dbus_property_desc *property_dsc = obj_dsc->properties;
  735. struct wpa_dbus_property_desc *prev_desc;
  736. prev_desc = NULL;
  737. while (property_dsc) {
  738. prev_desc = property_dsc;
  739. property_dsc = property_dsc->next;
  740. }
  741. property_dsc = os_zalloc(sizeof(struct wpa_dbus_property_desc));
  742. if (!property_dsc)
  743. goto err;
  744. if (prev_desc == NULL)
  745. obj_dsc->properties = property_dsc;
  746. else
  747. prev_desc->next = property_dsc;
  748. /* copy interface name */
  749. property_dsc->dbus_interface = os_strdup(dbus_interface);
  750. if (!property_dsc->dbus_interface)
  751. goto err;
  752. /* copy property name */
  753. property_dsc->dbus_property = os_strdup(dbus_property);
  754. if (!property_dsc->dbus_property)
  755. goto err;
  756. /* copy property type */
  757. property_dsc->type = os_strdup(type);
  758. if (!property_dsc->type)
  759. goto err;
  760. property_dsc->getter = getter;
  761. property_dsc->setter = setter;
  762. property_dsc->access = _access;
  763. property_dsc->next = NULL;
  764. return 0;
  765. err:
  766. wpa_printf(MSG_WARNING, "Failed to register dbus property %s in "
  767. "interface %s", dbus_property, dbus_interface);
  768. if (property_dsc) {
  769. os_free(property_dsc->dbus_interface);
  770. os_free(property_dsc->dbus_property);
  771. os_free(property_dsc->type);
  772. if (prev_desc == NULL)
  773. obj_dsc->properties = NULL;
  774. else
  775. prev_desc->next = NULL;
  776. os_free(property_dsc);
  777. }
  778. return -1;
  779. }
  780. /**
  781. * wpas_dbus_signal_network_added - Send a property changed signal
  782. * @iface: dbus priv struct
  783. * @property_getter: propperty getter used to fetch new property value
  784. * @getter_arg: argument passed to property getter
  785. * @path: path to object which property has changed
  786. * @interface_name: signal and property interface
  787. * @property_name: name of property which has changed
  788. *
  789. * Notify listeners about changing value of some property. Signal
  790. * contains property name and its value fetched using given property
  791. * getter.
  792. */
  793. void wpa_dbus_signal_property_changed(struct wpas_dbus_priv *iface,
  794. WPADBusPropertyAccessor property_getter,
  795. void *getter_arg,
  796. const char *path,
  797. const char *interface_name,
  798. const char *property_name)
  799. {
  800. DBusConnection *connection;
  801. DBusMessage *msg, *getter_reply;
  802. DBusMessageIter prop_iter, signal_iter, dict_iter, entry_iter;
  803. if (!iface)
  804. return;
  805. connection = iface->con;
  806. if (!property_getter || !path || !interface_name || !property_name) {
  807. wpa_printf(MSG_ERROR, "dbus: %s: A parameter not specified",
  808. __func__);
  809. return;
  810. }
  811. getter_reply = property_getter(NULL, getter_arg);
  812. if (!getter_reply ||
  813. dbus_message_get_type(getter_reply) == DBUS_MESSAGE_TYPE_ERROR) {
  814. wpa_printf(MSG_ERROR, "dbus: %s: Cannot get new value of "
  815. "property %s", __func__, property_name);
  816. return;
  817. }
  818. msg = dbus_message_new_signal(path, interface_name,
  819. "PropertiesChanged");
  820. if (msg == NULL) {
  821. dbus_message_unref(getter_reply);
  822. return;
  823. }
  824. dbus_message_iter_init(getter_reply, &prop_iter);
  825. dbus_message_iter_init_append(msg, &signal_iter);
  826. if (!dbus_message_iter_open_container(&signal_iter, DBUS_TYPE_ARRAY,
  827. "{sv}", &dict_iter) ||
  828. !dbus_message_iter_open_container(&dict_iter, DBUS_TYPE_DICT_ENTRY,
  829. NULL, &entry_iter) ||
  830. !dbus_message_iter_append_basic(&entry_iter, DBUS_TYPE_STRING,
  831. &property_name))
  832. goto err;
  833. recursive_iter_copy(&prop_iter, &entry_iter);
  834. if (!dbus_message_iter_close_container(&dict_iter, &entry_iter) ||
  835. !dbus_message_iter_close_container(&signal_iter, &dict_iter))
  836. goto err;
  837. dbus_connection_send(connection, msg, NULL);
  838. out:
  839. dbus_message_unref(getter_reply);
  840. dbus_message_unref(msg);
  841. return;
  842. err:
  843. wpa_printf(MSG_DEBUG, "dbus: %s: Failed to construct signal",
  844. __func__);
  845. goto out;
  846. }
  847. /**
  848. * wpa_dbus_get_object_properties - Put object's properties into dictionary
  849. * @iface: dbus priv struct
  850. * @path: path to DBus object which properties will be obtained
  851. * @interface: interface name which properties will be obtained
  852. * @dict_iter: correct, open DBus dictionary iterator.
  853. *
  854. * Iterates over all properties registered with object and execute getters
  855. * of those, which are readable and which interface matches interface
  856. * specified as argument. Obtained properties values are stored in
  857. * dict_iter dictionary.
  858. */
  859. void wpa_dbus_get_object_properties(struct wpas_dbus_priv *iface,
  860. const char *path, const char *interface,
  861. DBusMessageIter *dict_iter)
  862. {
  863. struct wpa_dbus_object_desc *obj_desc = NULL;
  864. dbus_connection_get_object_path_data(iface->con, path,
  865. (void **) &obj_desc);
  866. if (!obj_desc) {
  867. wpa_printf(MSG_ERROR, "dbus: wpa_dbus_get_object_properties: "
  868. "could not obtain object's private data: %s", path);
  869. return;
  870. }
  871. fill_dict_with_properties(dict_iter, obj_desc->properties,
  872. interface, obj_desc->user_data);
  873. }