1214501Srpaulo/* 2214501Srpaulo * wpa_supplicant D-Bus control interface - common functionality 3214501Srpaulo * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc. 4214501Srpaulo * Copyright (c) 2009, Witold Sowa <witold.sowa@gmail.com> 5214501Srpaulo * Copyright (c) 2009, Jouni Malinen <j@w1.fi> 6214501Srpaulo * 7252190Srpaulo * This software may be distributed under the terms of the BSD license. 8252190Srpaulo * See README for more details. 9214501Srpaulo */ 10214501Srpaulo 11214501Srpaulo#include "utils/includes.h" 12214501Srpaulo#include <dbus/dbus.h> 13214501Srpaulo 14214501Srpaulo#include "utils/common.h" 15214501Srpaulo#include "utils/eloop.h" 16214501Srpaulo#include "dbus_common.h" 17214501Srpaulo#include "dbus_common_i.h" 18214501Srpaulo#include "dbus_new.h" 19214501Srpaulo#include "dbus_old.h" 20214501Srpaulo 21214501Srpaulo 22214501Srpaulo#ifndef SIGPOLL 23214501Srpaulo#ifdef SIGIO 24214501Srpaulo/* 25214501Srpaulo * If we do not have SIGPOLL, try to use SIGIO instead. This is needed for 26214501Srpaulo * FreeBSD. 27214501Srpaulo */ 28214501Srpaulo#define SIGPOLL SIGIO 29214501Srpaulo#endif 30214501Srpaulo#endif 31214501Srpaulo 32214501Srpaulo 33214501Srpaulostatic void dispatch_data(DBusConnection *con) 34214501Srpaulo{ 35214501Srpaulo while (dbus_connection_get_dispatch_status(con) == 36214501Srpaulo DBUS_DISPATCH_DATA_REMAINS) 37214501Srpaulo dbus_connection_dispatch(con); 38214501Srpaulo} 39214501Srpaulo 40214501Srpaulo 41214501Srpaulo/** 42214501Srpaulo * dispatch_initial_dbus_messages - Dispatch initial dbus messages after 43214501Srpaulo * claiming bus name 44214501Srpaulo * @eloop_ctx: the DBusConnection to dispatch on 45214501Srpaulo * @timeout_ctx: unused 46214501Srpaulo * 47214501Srpaulo * If clients are quick to notice that service claimed its bus name, 48214501Srpaulo * there may have been messages that came in before initialization was 49214501Srpaulo * all finished. Dispatch those here. 50214501Srpaulo */ 51214501Srpaulostatic void dispatch_initial_dbus_messages(void *eloop_ctx, void *timeout_ctx) 52214501Srpaulo{ 53214501Srpaulo DBusConnection *con = eloop_ctx; 54214501Srpaulo dispatch_data(con); 55214501Srpaulo} 56214501Srpaulo 57214501Srpaulo 58214501Srpaulostatic void process_watch(struct wpas_dbus_priv *priv, 59214501Srpaulo DBusWatch *watch, eloop_event_type type) 60214501Srpaulo{ 61214501Srpaulo dbus_connection_ref(priv->con); 62214501Srpaulo 63214501Srpaulo priv->should_dispatch = 0; 64214501Srpaulo 65214501Srpaulo if (type == EVENT_TYPE_READ) 66214501Srpaulo dbus_watch_handle(watch, DBUS_WATCH_READABLE); 67214501Srpaulo else if (type == EVENT_TYPE_WRITE) 68214501Srpaulo dbus_watch_handle(watch, DBUS_WATCH_WRITABLE); 69214501Srpaulo else if (type == EVENT_TYPE_EXCEPTION) 70214501Srpaulo dbus_watch_handle(watch, DBUS_WATCH_ERROR); 71214501Srpaulo 72214501Srpaulo if (priv->should_dispatch) { 73214501Srpaulo dispatch_data(priv->con); 74214501Srpaulo priv->should_dispatch = 0; 75214501Srpaulo } 76214501Srpaulo 77214501Srpaulo dbus_connection_unref(priv->con); 78214501Srpaulo} 79214501Srpaulo 80214501Srpaulo 81214501Srpaulostatic void process_watch_exception(int sock, void *eloop_ctx, void *sock_ctx) 82214501Srpaulo{ 83214501Srpaulo process_watch(eloop_ctx, sock_ctx, EVENT_TYPE_EXCEPTION); 84214501Srpaulo} 85214501Srpaulo 86214501Srpaulo 87214501Srpaulostatic void process_watch_read(int sock, void *eloop_ctx, void *sock_ctx) 88214501Srpaulo{ 89214501Srpaulo process_watch(eloop_ctx, sock_ctx, EVENT_TYPE_READ); 90214501Srpaulo} 91214501Srpaulo 92214501Srpaulo 93214501Srpaulostatic void process_watch_write(int sock, void *eloop_ctx, void *sock_ctx) 94214501Srpaulo{ 95214501Srpaulo process_watch(eloop_ctx, sock_ctx, EVENT_TYPE_WRITE); 96214501Srpaulo} 97214501Srpaulo 98214501Srpaulo 99214501Srpaulostatic dbus_bool_t add_watch(DBusWatch *watch, void *data) 100214501Srpaulo{ 101214501Srpaulo struct wpas_dbus_priv *priv = data; 102214501Srpaulo unsigned int flags; 103214501Srpaulo int fd; 104214501Srpaulo 105214501Srpaulo if (!dbus_watch_get_enabled(watch)) 106214501Srpaulo return TRUE; 107214501Srpaulo 108214501Srpaulo flags = dbus_watch_get_flags(watch); 109214501Srpaulo fd = dbus_watch_get_unix_fd(watch); 110214501Srpaulo 111214501Srpaulo eloop_register_sock(fd, EVENT_TYPE_EXCEPTION, process_watch_exception, 112214501Srpaulo priv, watch); 113214501Srpaulo 114214501Srpaulo if (flags & DBUS_WATCH_READABLE) { 115214501Srpaulo eloop_register_sock(fd, EVENT_TYPE_READ, process_watch_read, 116214501Srpaulo priv, watch); 117214501Srpaulo } 118214501Srpaulo if (flags & DBUS_WATCH_WRITABLE) { 119214501Srpaulo eloop_register_sock(fd, EVENT_TYPE_WRITE, process_watch_write, 120214501Srpaulo priv, watch); 121214501Srpaulo } 122214501Srpaulo 123214501Srpaulo dbus_watch_set_data(watch, priv, NULL); 124214501Srpaulo 125214501Srpaulo return TRUE; 126214501Srpaulo} 127214501Srpaulo 128214501Srpaulo 129214501Srpaulostatic void remove_watch(DBusWatch *watch, void *data) 130214501Srpaulo{ 131214501Srpaulo unsigned int flags; 132214501Srpaulo int fd; 133214501Srpaulo 134214501Srpaulo flags = dbus_watch_get_flags(watch); 135214501Srpaulo fd = dbus_watch_get_unix_fd(watch); 136214501Srpaulo 137214501Srpaulo eloop_unregister_sock(fd, EVENT_TYPE_EXCEPTION); 138214501Srpaulo 139214501Srpaulo if (flags & DBUS_WATCH_READABLE) 140214501Srpaulo eloop_unregister_sock(fd, EVENT_TYPE_READ); 141214501Srpaulo if (flags & DBUS_WATCH_WRITABLE) 142214501Srpaulo eloop_unregister_sock(fd, EVENT_TYPE_WRITE); 143214501Srpaulo 144214501Srpaulo dbus_watch_set_data(watch, NULL, NULL); 145214501Srpaulo} 146214501Srpaulo 147214501Srpaulo 148214501Srpaulostatic void watch_toggled(DBusWatch *watch, void *data) 149214501Srpaulo{ 150214501Srpaulo if (dbus_watch_get_enabled(watch)) 151214501Srpaulo add_watch(watch, data); 152214501Srpaulo else 153214501Srpaulo remove_watch(watch, data); 154214501Srpaulo} 155214501Srpaulo 156214501Srpaulo 157214501Srpaulostatic void process_timeout(void *eloop_ctx, void *sock_ctx) 158214501Srpaulo{ 159214501Srpaulo DBusTimeout *timeout = sock_ctx; 160214501Srpaulo dbus_timeout_handle(timeout); 161214501Srpaulo} 162214501Srpaulo 163214501Srpaulo 164214501Srpaulostatic dbus_bool_t add_timeout(DBusTimeout *timeout, void *data) 165214501Srpaulo{ 166214501Srpaulo struct wpas_dbus_priv *priv = data; 167214501Srpaulo if (!dbus_timeout_get_enabled(timeout)) 168214501Srpaulo return TRUE; 169214501Srpaulo 170214501Srpaulo eloop_register_timeout(0, dbus_timeout_get_interval(timeout) * 1000, 171214501Srpaulo process_timeout, priv, timeout); 172214501Srpaulo 173214501Srpaulo dbus_timeout_set_data(timeout, priv, NULL); 174214501Srpaulo 175214501Srpaulo return TRUE; 176214501Srpaulo} 177214501Srpaulo 178214501Srpaulo 179214501Srpaulostatic void remove_timeout(DBusTimeout *timeout, void *data) 180214501Srpaulo{ 181214501Srpaulo struct wpas_dbus_priv *priv = data; 182214501Srpaulo eloop_cancel_timeout(process_timeout, priv, timeout); 183214501Srpaulo dbus_timeout_set_data(timeout, NULL, NULL); 184214501Srpaulo} 185214501Srpaulo 186214501Srpaulo 187214501Srpaulostatic void timeout_toggled(DBusTimeout *timeout, void *data) 188214501Srpaulo{ 189214501Srpaulo if (dbus_timeout_get_enabled(timeout)) 190214501Srpaulo add_timeout(timeout, data); 191214501Srpaulo else 192214501Srpaulo remove_timeout(timeout, data); 193214501Srpaulo} 194214501Srpaulo 195214501Srpaulo 196214501Srpaulostatic void process_wakeup_main(int sig, void *signal_ctx) 197214501Srpaulo{ 198214501Srpaulo struct wpas_dbus_priv *priv = signal_ctx; 199214501Srpaulo 200214501Srpaulo if (sig != SIGPOLL || !priv->con) 201214501Srpaulo return; 202214501Srpaulo 203214501Srpaulo if (dbus_connection_get_dispatch_status(priv->con) != 204214501Srpaulo DBUS_DISPATCH_DATA_REMAINS) 205214501Srpaulo return; 206214501Srpaulo 207214501Srpaulo /* Only dispatch once - we do not want to starve other events */ 208214501Srpaulo dbus_connection_ref(priv->con); 209214501Srpaulo dbus_connection_dispatch(priv->con); 210214501Srpaulo dbus_connection_unref(priv->con); 211214501Srpaulo} 212214501Srpaulo 213214501Srpaulo 214214501Srpaulo/** 215214501Srpaulo * wakeup_main - Attempt to wake our mainloop up 216214501Srpaulo * @data: dbus control interface private data 217214501Srpaulo * 218214501Srpaulo * Try to wake up the main eloop so it will process 219214501Srpaulo * dbus events that may have happened. 220214501Srpaulo */ 221214501Srpaulostatic void wakeup_main(void *data) 222214501Srpaulo{ 223214501Srpaulo struct wpas_dbus_priv *priv = data; 224214501Srpaulo 225214501Srpaulo /* Use SIGPOLL to break out of the eloop select() */ 226214501Srpaulo raise(SIGPOLL); 227214501Srpaulo priv->should_dispatch = 1; 228214501Srpaulo} 229214501Srpaulo 230214501Srpaulo 231214501Srpaulo/** 232214501Srpaulo * integrate_with_eloop - Register our mainloop integration with dbus 233214501Srpaulo * @connection: connection to the system message bus 234214501Srpaulo * @priv: a dbus control interface data structure 235214501Srpaulo * Returns: 0 on success, -1 on failure 236214501Srpaulo */ 237214501Srpaulostatic int integrate_with_eloop(struct wpas_dbus_priv *priv) 238214501Srpaulo{ 239214501Srpaulo if (!dbus_connection_set_watch_functions(priv->con, add_watch, 240214501Srpaulo remove_watch, watch_toggled, 241214501Srpaulo priv, NULL) || 242214501Srpaulo !dbus_connection_set_timeout_functions(priv->con, add_timeout, 243214501Srpaulo remove_timeout, 244214501Srpaulo timeout_toggled, priv, 245214501Srpaulo NULL)) { 246214501Srpaulo wpa_printf(MSG_ERROR, "dbus: Failed to set callback " 247214501Srpaulo "functions"); 248214501Srpaulo return -1; 249214501Srpaulo } 250214501Srpaulo 251214501Srpaulo if (eloop_register_signal(SIGPOLL, process_wakeup_main, priv)) 252214501Srpaulo return -1; 253214501Srpaulo dbus_connection_set_wakeup_main_function(priv->con, wakeup_main, 254214501Srpaulo priv, NULL); 255214501Srpaulo 256214501Srpaulo return 0; 257214501Srpaulo} 258214501Srpaulo 259214501Srpaulo 260214501Srpaulostatic int wpas_dbus_init_common(struct wpas_dbus_priv *priv) 261214501Srpaulo{ 262214501Srpaulo DBusError error; 263214501Srpaulo int ret = 0; 264214501Srpaulo 265214501Srpaulo /* Get a reference to the system bus */ 266214501Srpaulo dbus_error_init(&error); 267214501Srpaulo priv->con = dbus_bus_get(DBUS_BUS_SYSTEM, &error); 268214501Srpaulo if (!priv->con) { 269214501Srpaulo wpa_printf(MSG_ERROR, "dbus: Could not acquire the system " 270214501Srpaulo "bus: %s - %s", error.name, error.message); 271214501Srpaulo ret = -1; 272214501Srpaulo } 273214501Srpaulo dbus_error_free(&error); 274214501Srpaulo 275214501Srpaulo return ret; 276214501Srpaulo} 277214501Srpaulo 278214501Srpaulo 279214501Srpaulostatic int wpas_dbus_init_common_finish(struct wpas_dbus_priv *priv) 280214501Srpaulo{ 281214501Srpaulo /* Tell dbus about our mainloop integration functions */ 282214501Srpaulo integrate_with_eloop(priv); 283214501Srpaulo 284214501Srpaulo /* 285214501Srpaulo * Dispatch initial DBus messages that may have come in since the bus 286214501Srpaulo * name was claimed above. Happens when clients are quick to notice the 287214501Srpaulo * service. 288214501Srpaulo * 289214501Srpaulo * FIXME: is there a better solution to this problem? 290214501Srpaulo */ 291214501Srpaulo eloop_register_timeout(0, 50, dispatch_initial_dbus_messages, 292214501Srpaulo priv->con, NULL); 293214501Srpaulo 294214501Srpaulo return 0; 295214501Srpaulo} 296214501Srpaulo 297214501Srpaulo 298214501Srpaulostatic void wpas_dbus_deinit_common(struct wpas_dbus_priv *priv) 299214501Srpaulo{ 300214501Srpaulo if (priv->con) { 301214501Srpaulo eloop_cancel_timeout(dispatch_initial_dbus_messages, 302214501Srpaulo priv->con, NULL); 303214501Srpaulo dbus_connection_set_watch_functions(priv->con, NULL, NULL, 304214501Srpaulo NULL, NULL, NULL); 305214501Srpaulo dbus_connection_set_timeout_functions(priv->con, NULL, NULL, 306214501Srpaulo NULL, NULL, NULL); 307214501Srpaulo dbus_connection_unref(priv->con); 308214501Srpaulo } 309214501Srpaulo 310214501Srpaulo os_free(priv); 311214501Srpaulo} 312214501Srpaulo 313214501Srpaulo 314214501Srpaulostruct wpas_dbus_priv * wpas_dbus_init(struct wpa_global *global) 315214501Srpaulo{ 316214501Srpaulo struct wpas_dbus_priv *priv; 317214501Srpaulo 318214501Srpaulo priv = os_zalloc(sizeof(*priv)); 319214501Srpaulo if (priv == NULL) 320214501Srpaulo return NULL; 321214501Srpaulo priv->global = global; 322214501Srpaulo 323214501Srpaulo if (wpas_dbus_init_common(priv) < 0) { 324214501Srpaulo wpas_dbus_deinit(priv); 325214501Srpaulo return NULL; 326214501Srpaulo } 327214501Srpaulo 328214501Srpaulo#ifdef CONFIG_CTRL_IFACE_DBUS_NEW 329214501Srpaulo if (wpas_dbus_ctrl_iface_init(priv) < 0) { 330214501Srpaulo wpas_dbus_deinit(priv); 331214501Srpaulo return NULL; 332214501Srpaulo } 333214501Srpaulo#endif /* CONFIG_CTRL_IFACE_DBUS_NEW */ 334214501Srpaulo 335214501Srpaulo#ifdef CONFIG_CTRL_IFACE_DBUS 336214501Srpaulo if (wpa_supplicant_dbus_ctrl_iface_init(priv) < 0) { 337214501Srpaulo wpas_dbus_deinit(priv); 338214501Srpaulo return NULL; 339214501Srpaulo } 340214501Srpaulo#endif /* CONFIG_CTRL_IFACE_DBUS */ 341214501Srpaulo 342214501Srpaulo if (wpas_dbus_init_common_finish(priv) < 0) { 343214501Srpaulo wpas_dbus_deinit(priv); 344214501Srpaulo return NULL; 345214501Srpaulo } 346214501Srpaulo 347214501Srpaulo return priv; 348214501Srpaulo} 349214501Srpaulo 350214501Srpaulo 351214501Srpaulovoid wpas_dbus_deinit(struct wpas_dbus_priv *priv) 352214501Srpaulo{ 353214501Srpaulo if (priv == NULL) 354214501Srpaulo return; 355214501Srpaulo 356214501Srpaulo#ifdef CONFIG_CTRL_IFACE_DBUS_NEW 357214501Srpaulo wpas_dbus_ctrl_iface_deinit(priv); 358214501Srpaulo#endif /* CONFIG_CTRL_IFACE_DBUS_NEW */ 359214501Srpaulo 360214501Srpaulo#ifdef CONFIG_CTRL_IFACE_DBUS 361214501Srpaulo /* TODO: is any deinit needed? */ 362214501Srpaulo#endif /* CONFIG_CTRL_IFACE_DBUS */ 363214501Srpaulo 364214501Srpaulo wpas_dbus_deinit_common(priv); 365214501Srpaulo} 366