dbus_common.c 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380
  1. /*
  2. * wpa_supplicant D-Bus control interface - common functionality
  3. * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
  4. * Copyright (c) 2009, Witold Sowa <witold.sowa@gmail.com>
  5. * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
  6. *
  7. * This software may be distributed under the terms of the BSD license.
  8. * See README for more details.
  9. */
  10. #include "utils/includes.h"
  11. #include <dbus/dbus.h>
  12. #include "utils/common.h"
  13. #include "utils/eloop.h"
  14. #include "dbus_common.h"
  15. #include "dbus_common_i.h"
  16. #include "dbus_new.h"
  17. #include "dbus_old.h"
  18. #include "../wpa_supplicant_i.h"
  19. #ifndef SIGPOLL
  20. #ifdef SIGIO
  21. /*
  22. * If we do not have SIGPOLL, try to use SIGIO instead. This is needed for
  23. * FreeBSD.
  24. */
  25. #define SIGPOLL SIGIO
  26. #endif
  27. #endif
  28. static void dispatch_data(DBusConnection *con)
  29. {
  30. while (dbus_connection_get_dispatch_status(con) ==
  31. DBUS_DISPATCH_DATA_REMAINS)
  32. dbus_connection_dispatch(con);
  33. }
  34. /**
  35. * dispatch_initial_dbus_messages - Dispatch initial dbus messages after
  36. * claiming bus name
  37. * @eloop_ctx: the DBusConnection to dispatch on
  38. * @timeout_ctx: unused
  39. *
  40. * If clients are quick to notice that service claimed its bus name,
  41. * there may have been messages that came in before initialization was
  42. * all finished. Dispatch those here.
  43. */
  44. static void dispatch_initial_dbus_messages(void *eloop_ctx, void *timeout_ctx)
  45. {
  46. DBusConnection *con = eloop_ctx;
  47. dispatch_data(con);
  48. }
  49. static void process_watch(struct wpas_dbus_priv *priv,
  50. DBusWatch *watch, eloop_event_type type)
  51. {
  52. dbus_connection_ref(priv->con);
  53. priv->should_dispatch = 0;
  54. if (type == EVENT_TYPE_READ)
  55. dbus_watch_handle(watch, DBUS_WATCH_READABLE);
  56. else if (type == EVENT_TYPE_WRITE)
  57. dbus_watch_handle(watch, DBUS_WATCH_WRITABLE);
  58. else if (type == EVENT_TYPE_EXCEPTION)
  59. dbus_watch_handle(watch, DBUS_WATCH_ERROR);
  60. if (priv->should_dispatch) {
  61. dispatch_data(priv->con);
  62. priv->should_dispatch = 0;
  63. }
  64. dbus_connection_unref(priv->con);
  65. }
  66. static void process_watch_exception(int sock, void *eloop_ctx, void *sock_ctx)
  67. {
  68. process_watch(eloop_ctx, sock_ctx, EVENT_TYPE_EXCEPTION);
  69. }
  70. static void process_watch_read(int sock, void *eloop_ctx, void *sock_ctx)
  71. {
  72. process_watch(eloop_ctx, sock_ctx, EVENT_TYPE_READ);
  73. }
  74. static void process_watch_write(int sock, void *eloop_ctx, void *sock_ctx)
  75. {
  76. process_watch(eloop_ctx, sock_ctx, EVENT_TYPE_WRITE);
  77. }
  78. static dbus_bool_t add_watch(DBusWatch *watch, void *data)
  79. {
  80. struct wpas_dbus_priv *priv = data;
  81. unsigned int flags;
  82. int fd;
  83. if (!dbus_watch_get_enabled(watch))
  84. return TRUE;
  85. flags = dbus_watch_get_flags(watch);
  86. fd = dbus_watch_get_unix_fd(watch);
  87. eloop_register_sock(fd, EVENT_TYPE_EXCEPTION, process_watch_exception,
  88. priv, watch);
  89. if (flags & DBUS_WATCH_READABLE) {
  90. eloop_register_sock(fd, EVENT_TYPE_READ, process_watch_read,
  91. priv, watch);
  92. }
  93. if (flags & DBUS_WATCH_WRITABLE) {
  94. eloop_register_sock(fd, EVENT_TYPE_WRITE, process_watch_write,
  95. priv, watch);
  96. }
  97. dbus_watch_set_data(watch, priv, NULL);
  98. return TRUE;
  99. }
  100. static void remove_watch(DBusWatch *watch, void *data)
  101. {
  102. unsigned int flags;
  103. int fd;
  104. flags = dbus_watch_get_flags(watch);
  105. fd = dbus_watch_get_unix_fd(watch);
  106. eloop_unregister_sock(fd, EVENT_TYPE_EXCEPTION);
  107. if (flags & DBUS_WATCH_READABLE)
  108. eloop_unregister_sock(fd, EVENT_TYPE_READ);
  109. if (flags & DBUS_WATCH_WRITABLE)
  110. eloop_unregister_sock(fd, EVENT_TYPE_WRITE);
  111. dbus_watch_set_data(watch, NULL, NULL);
  112. }
  113. static void watch_toggled(DBusWatch *watch, void *data)
  114. {
  115. if (dbus_watch_get_enabled(watch))
  116. add_watch(watch, data);
  117. else
  118. remove_watch(watch, data);
  119. }
  120. static void process_timeout(void *eloop_ctx, void *sock_ctx)
  121. {
  122. DBusTimeout *timeout = sock_ctx;
  123. dbus_timeout_handle(timeout);
  124. }
  125. static dbus_bool_t add_timeout(DBusTimeout *timeout, void *data)
  126. {
  127. struct wpas_dbus_priv *priv = data;
  128. if (!dbus_timeout_get_enabled(timeout))
  129. return TRUE;
  130. eloop_register_timeout(0, dbus_timeout_get_interval(timeout) * 1000,
  131. process_timeout, priv, timeout);
  132. dbus_timeout_set_data(timeout, priv, NULL);
  133. return TRUE;
  134. }
  135. static void remove_timeout(DBusTimeout *timeout, void *data)
  136. {
  137. struct wpas_dbus_priv *priv = data;
  138. eloop_cancel_timeout(process_timeout, priv, timeout);
  139. dbus_timeout_set_data(timeout, NULL, NULL);
  140. }
  141. static void timeout_toggled(DBusTimeout *timeout, void *data)
  142. {
  143. if (dbus_timeout_get_enabled(timeout))
  144. add_timeout(timeout, data);
  145. else
  146. remove_timeout(timeout, data);
  147. }
  148. static void process_wakeup_main(int sig, void *signal_ctx)
  149. {
  150. struct wpas_dbus_priv *priv = signal_ctx;
  151. if (sig != SIGPOLL || !priv->con)
  152. return;
  153. if (dbus_connection_get_dispatch_status(priv->con) !=
  154. DBUS_DISPATCH_DATA_REMAINS)
  155. return;
  156. /* Only dispatch once - we do not want to starve other events */
  157. dbus_connection_ref(priv->con);
  158. dbus_connection_dispatch(priv->con);
  159. dbus_connection_unref(priv->con);
  160. }
  161. /**
  162. * wakeup_main - Attempt to wake our mainloop up
  163. * @data: dbus control interface private data
  164. *
  165. * Try to wake up the main eloop so it will process
  166. * dbus events that may have happened.
  167. */
  168. static void wakeup_main(void *data)
  169. {
  170. struct wpas_dbus_priv *priv = data;
  171. /* Use SIGPOLL to break out of the eloop select() */
  172. raise(SIGPOLL);
  173. priv->should_dispatch = 1;
  174. }
  175. /**
  176. * integrate_with_eloop - Register our mainloop integration with dbus
  177. * @connection: connection to the system message bus
  178. * @priv: a dbus control interface data structure
  179. * Returns: 0 on success, -1 on failure
  180. */
  181. static int integrate_with_eloop(struct wpas_dbus_priv *priv)
  182. {
  183. if (!dbus_connection_set_watch_functions(priv->con, add_watch,
  184. remove_watch, watch_toggled,
  185. priv, NULL) ||
  186. !dbus_connection_set_timeout_functions(priv->con, add_timeout,
  187. remove_timeout,
  188. timeout_toggled, priv,
  189. NULL)) {
  190. wpa_printf(MSG_ERROR, "dbus: Failed to set callback functions");
  191. return -1;
  192. }
  193. if (eloop_register_signal(SIGPOLL, process_wakeup_main, priv))
  194. return -1;
  195. dbus_connection_set_wakeup_main_function(priv->con, wakeup_main,
  196. priv, NULL);
  197. return 0;
  198. }
  199. static DBusHandlerResult disconnect_filter(DBusConnection *conn,
  200. DBusMessage *message, void *data)
  201. {
  202. struct wpas_dbus_priv *priv = data;
  203. if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL,
  204. "Disconnected")) {
  205. wpa_printf(MSG_DEBUG, "dbus: bus disconnected, terminating");
  206. dbus_connection_set_exit_on_disconnect(conn, FALSE);
  207. wpa_supplicant_terminate_proc(priv->global);
  208. return DBUS_HANDLER_RESULT_HANDLED;
  209. } else
  210. return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
  211. }
  212. static int wpas_dbus_init_common(struct wpas_dbus_priv *priv)
  213. {
  214. DBusError error;
  215. int ret = 0;
  216. /* Get a reference to the system bus */
  217. dbus_error_init(&error);
  218. priv->con = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
  219. if (priv->con) {
  220. dbus_connection_add_filter(priv->con, disconnect_filter, priv,
  221. NULL);
  222. } else {
  223. wpa_printf(MSG_ERROR,
  224. "dbus: Could not acquire the system bus: %s - %s",
  225. error.name, error.message);
  226. ret = -1;
  227. }
  228. dbus_error_free(&error);
  229. return ret;
  230. }
  231. static int wpas_dbus_init_common_finish(struct wpas_dbus_priv *priv)
  232. {
  233. /* Tell dbus about our mainloop integration functions */
  234. integrate_with_eloop(priv);
  235. /*
  236. * Dispatch initial DBus messages that may have come in since the bus
  237. * name was claimed above. Happens when clients are quick to notice the
  238. * service.
  239. *
  240. * FIXME: is there a better solution to this problem?
  241. */
  242. eloop_register_timeout(0, 50, dispatch_initial_dbus_messages,
  243. priv->con, NULL);
  244. return 0;
  245. }
  246. static void wpas_dbus_deinit_common(struct wpas_dbus_priv *priv)
  247. {
  248. if (priv->con) {
  249. eloop_cancel_timeout(dispatch_initial_dbus_messages,
  250. priv->con, NULL);
  251. eloop_cancel_timeout(process_timeout, priv, ELOOP_ALL_CTX);
  252. dbus_connection_set_watch_functions(priv->con, NULL, NULL,
  253. NULL, NULL, NULL);
  254. dbus_connection_set_timeout_functions(priv->con, NULL, NULL,
  255. NULL, NULL, NULL);
  256. dbus_connection_remove_filter(priv->con, disconnect_filter,
  257. priv);
  258. dbus_connection_unref(priv->con);
  259. }
  260. os_free(priv);
  261. }
  262. struct wpas_dbus_priv * wpas_dbus_init(struct wpa_global *global)
  263. {
  264. struct wpas_dbus_priv *priv;
  265. priv = os_zalloc(sizeof(*priv));
  266. if (priv == NULL)
  267. return NULL;
  268. priv->global = global;
  269. if (wpas_dbus_init_common(priv) < 0 ||
  270. #ifdef CONFIG_CTRL_IFACE_DBUS_NEW
  271. wpas_dbus_ctrl_iface_init(priv) < 0 ||
  272. #endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
  273. #ifdef CONFIG_CTRL_IFACE_DBUS
  274. wpa_supplicant_dbus_ctrl_iface_init(priv) < 0 ||
  275. #endif /* CONFIG_CTRL_IFACE_DBUS */
  276. wpas_dbus_init_common_finish(priv) < 0) {
  277. wpas_dbus_deinit(priv);
  278. return NULL;
  279. }
  280. return priv;
  281. }
  282. void wpas_dbus_deinit(struct wpas_dbus_priv *priv)
  283. {
  284. if (priv == NULL)
  285. return;
  286. #ifdef CONFIG_CTRL_IFACE_DBUS_NEW
  287. wpas_dbus_ctrl_iface_deinit(priv);
  288. #endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
  289. #ifdef CONFIG_CTRL_IFACE_DBUS
  290. /* TODO: is any deinit needed? */
  291. #endif /* CONFIG_CTRL_IFACE_DBUS */
  292. wpas_dbus_deinit_common(priv);
  293. }