$search
00001 /* 00002 * wpa_supplicant D-Bus control interface - common functionality 00003 * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc. 00004 * Copyright (c) 2009, Witold Sowa <witold.sowa@gmail.com> 00005 * Copyright (c) 2009, Jouni Malinen <j@w1.fi> 00006 * 00007 * This program is free software; you can redistribute it and/or modify 00008 * it under the terms of the GNU General Public License version 2 as 00009 * published by the Free Software Foundation. 00010 * 00011 * Alternatively, this software may be distributed under the terms of BSD 00012 * license. 00013 * 00014 * See README and COPYING for more details. 00015 */ 00016 00017 #include "utils/includes.h" 00018 #include <dbus/dbus.h> 00019 00020 #include "utils/common.h" 00021 #include "utils/eloop.h" 00022 #include "dbus_common.h" 00023 #include "dbus_common_i.h" 00024 #include "dbus_new.h" 00025 #include "dbus_old.h" 00026 00027 00028 #ifndef SIGPOLL 00029 #ifdef SIGIO 00030 /* 00031 * If we do not have SIGPOLL, try to use SIGIO instead. This is needed for 00032 * FreeBSD. 00033 */ 00034 #define SIGPOLL SIGIO 00035 #endif 00036 #endif 00037 00038 00039 static void dispatch_data(DBusConnection *con) 00040 { 00041 while (dbus_connection_get_dispatch_status(con) == 00042 DBUS_DISPATCH_DATA_REMAINS) 00043 dbus_connection_dispatch(con); 00044 } 00045 00046 00057 static void dispatch_initial_dbus_messages(void *eloop_ctx, void *timeout_ctx) 00058 { 00059 DBusConnection *con = eloop_ctx; 00060 dispatch_data(con); 00061 } 00062 00063 00064 static void process_watch(struct wpas_dbus_priv *priv, 00065 DBusWatch *watch, eloop_event_type type) 00066 { 00067 dbus_connection_ref(priv->con); 00068 00069 priv->should_dispatch = 0; 00070 00071 if (type == EVENT_TYPE_READ) 00072 dbus_watch_handle(watch, DBUS_WATCH_READABLE); 00073 else if (type == EVENT_TYPE_WRITE) 00074 dbus_watch_handle(watch, DBUS_WATCH_WRITABLE); 00075 else if (type == EVENT_TYPE_EXCEPTION) 00076 dbus_watch_handle(watch, DBUS_WATCH_ERROR); 00077 00078 if (priv->should_dispatch) { 00079 dispatch_data(priv->con); 00080 priv->should_dispatch = 0; 00081 } 00082 00083 dbus_connection_unref(priv->con); 00084 } 00085 00086 00087 static void process_watch_exception(int sock, void *eloop_ctx, void *sock_ctx) 00088 { 00089 process_watch(eloop_ctx, sock_ctx, EVENT_TYPE_EXCEPTION); 00090 } 00091 00092 00093 static void process_watch_read(int sock, void *eloop_ctx, void *sock_ctx) 00094 { 00095 process_watch(eloop_ctx, sock_ctx, EVENT_TYPE_READ); 00096 } 00097 00098 00099 static void process_watch_write(int sock, void *eloop_ctx, void *sock_ctx) 00100 { 00101 process_watch(eloop_ctx, sock_ctx, EVENT_TYPE_WRITE); 00102 } 00103 00104 00105 static dbus_bool_t add_watch(DBusWatch *watch, void *data) 00106 { 00107 struct wpas_dbus_priv *priv = data; 00108 unsigned int flags; 00109 int fd; 00110 00111 if (!dbus_watch_get_enabled(watch)) 00112 return TRUE; 00113 00114 flags = dbus_watch_get_flags(watch); 00115 fd = dbus_watch_get_unix_fd(watch); 00116 00117 eloop_register_sock(fd, EVENT_TYPE_EXCEPTION, process_watch_exception, 00118 priv, watch); 00119 00120 if (flags & DBUS_WATCH_READABLE) { 00121 eloop_register_sock(fd, EVENT_TYPE_READ, process_watch_read, 00122 priv, watch); 00123 } 00124 if (flags & DBUS_WATCH_WRITABLE) { 00125 eloop_register_sock(fd, EVENT_TYPE_WRITE, process_watch_write, 00126 priv, watch); 00127 } 00128 00129 dbus_watch_set_data(watch, priv, NULL); 00130 00131 return TRUE; 00132 } 00133 00134 00135 static void remove_watch(DBusWatch *watch, void *data) 00136 { 00137 unsigned int flags; 00138 int fd; 00139 00140 flags = dbus_watch_get_flags(watch); 00141 fd = dbus_watch_get_unix_fd(watch); 00142 00143 eloop_unregister_sock(fd, EVENT_TYPE_EXCEPTION); 00144 00145 if (flags & DBUS_WATCH_READABLE) 00146 eloop_unregister_sock(fd, EVENT_TYPE_READ); 00147 if (flags & DBUS_WATCH_WRITABLE) 00148 eloop_unregister_sock(fd, EVENT_TYPE_WRITE); 00149 00150 dbus_watch_set_data(watch, NULL, NULL); 00151 } 00152 00153 00154 static void watch_toggled(DBusWatch *watch, void *data) 00155 { 00156 if (dbus_watch_get_enabled(watch)) 00157 add_watch(watch, data); 00158 else 00159 remove_watch(watch, data); 00160 } 00161 00162 00163 static void process_timeout(void *eloop_ctx, void *sock_ctx) 00164 { 00165 DBusTimeout *timeout = sock_ctx; 00166 dbus_timeout_handle(timeout); 00167 } 00168 00169 00170 static dbus_bool_t add_timeout(DBusTimeout *timeout, void *data) 00171 { 00172 struct wpas_dbus_priv *priv = data; 00173 if (!dbus_timeout_get_enabled(timeout)) 00174 return TRUE; 00175 00176 eloop_register_timeout(0, dbus_timeout_get_interval(timeout) * 1000, 00177 process_timeout, priv, timeout); 00178 00179 dbus_timeout_set_data(timeout, priv, NULL); 00180 00181 return TRUE; 00182 } 00183 00184 00185 static void remove_timeout(DBusTimeout *timeout, void *data) 00186 { 00187 struct wpas_dbus_priv *priv = data; 00188 eloop_cancel_timeout(process_timeout, priv, timeout); 00189 dbus_timeout_set_data(timeout, NULL, NULL); 00190 } 00191 00192 00193 static void timeout_toggled(DBusTimeout *timeout, void *data) 00194 { 00195 if (dbus_timeout_get_enabled(timeout)) 00196 add_timeout(timeout, data); 00197 else 00198 remove_timeout(timeout, data); 00199 } 00200 00201 00202 static void process_wakeup_main(int sig, void *signal_ctx) 00203 { 00204 struct wpas_dbus_priv *priv = signal_ctx; 00205 00206 if (sig != SIGPOLL || !priv->con) 00207 return; 00208 00209 if (dbus_connection_get_dispatch_status(priv->con) != 00210 DBUS_DISPATCH_DATA_REMAINS) 00211 return; 00212 00213 /* Only dispatch once - we do not want to starve other events */ 00214 dbus_connection_ref(priv->con); 00215 dbus_connection_dispatch(priv->con); 00216 dbus_connection_unref(priv->con); 00217 } 00218 00219 00227 static void wakeup_main(void *data) 00228 { 00229 struct wpas_dbus_priv *priv = data; 00230 00231 /* Use SIGPOLL to break out of the eloop select() */ 00232 raise(SIGPOLL); 00233 priv->should_dispatch = 1; 00234 } 00235 00236 00243 static int integrate_with_eloop(struct wpas_dbus_priv *priv) 00244 { 00245 if (!dbus_connection_set_watch_functions(priv->con, add_watch, 00246 remove_watch, watch_toggled, 00247 priv, NULL) || 00248 !dbus_connection_set_timeout_functions(priv->con, add_timeout, 00249 remove_timeout, 00250 timeout_toggled, priv, 00251 NULL)) { 00252 wpa_printf(MSG_ERROR, "dbus: Failed to set callback " 00253 "functions"); 00254 return -1; 00255 } 00256 00257 if (eloop_register_signal(SIGPOLL, process_wakeup_main, priv)) 00258 return -1; 00259 dbus_connection_set_wakeup_main_function(priv->con, wakeup_main, 00260 priv, NULL); 00261 00262 return 0; 00263 } 00264 00265 00266 static int wpas_dbus_init_common(struct wpas_dbus_priv *priv) 00267 { 00268 DBusError error; 00269 int ret = 0; 00270 00271 /* Get a reference to the system bus */ 00272 dbus_error_init(&error); 00273 priv->con = dbus_bus_get(DBUS_BUS_SYSTEM, &error); 00274 if (!priv->con) { 00275 wpa_printf(MSG_ERROR, "dbus: Could not acquire the system " 00276 "bus: %s - %s", error.name, error.message); 00277 ret = -1; 00278 } 00279 dbus_error_free(&error); 00280 00281 return ret; 00282 } 00283 00284 00285 static int wpas_dbus_init_common_finish(struct wpas_dbus_priv *priv) 00286 { 00287 /* Tell dbus about our mainloop integration functions */ 00288 integrate_with_eloop(priv); 00289 00290 /* 00291 * Dispatch initial DBus messages that may have come in since the bus 00292 * name was claimed above. Happens when clients are quick to notice the 00293 * service. 00294 * 00295 * FIXME: is there a better solution to this problem? 00296 */ 00297 eloop_register_timeout(0, 50, dispatch_initial_dbus_messages, 00298 priv->con, NULL); 00299 00300 return 0; 00301 } 00302 00303 00304 static void wpas_dbus_deinit_common(struct wpas_dbus_priv *priv) 00305 { 00306 if (priv->con) { 00307 eloop_cancel_timeout(dispatch_initial_dbus_messages, 00308 priv->con, NULL); 00309 dbus_connection_set_watch_functions(priv->con, NULL, NULL, 00310 NULL, NULL, NULL); 00311 dbus_connection_set_timeout_functions(priv->con, NULL, NULL, 00312 NULL, NULL, NULL); 00313 dbus_connection_unref(priv->con); 00314 } 00315 00316 os_free(priv); 00317 } 00318 00319 00320 struct wpas_dbus_priv * wpas_dbus_init(struct wpa_global *global) 00321 { 00322 struct wpas_dbus_priv *priv; 00323 00324 priv = os_zalloc(sizeof(*priv)); 00325 if (priv == NULL) 00326 return NULL; 00327 priv->global = global; 00328 00329 if (wpas_dbus_init_common(priv) < 0) { 00330 wpas_dbus_deinit(priv); 00331 return NULL; 00332 } 00333 00334 #ifdef CONFIG_CTRL_IFACE_DBUS_NEW 00335 if (wpas_dbus_ctrl_iface_init(priv) < 0) { 00336 wpas_dbus_deinit(priv); 00337 return NULL; 00338 } 00339 #endif /* CONFIG_CTRL_IFACE_DBUS_NEW */ 00340 00341 #ifdef CONFIG_CTRL_IFACE_DBUS 00342 if (wpa_supplicant_dbus_ctrl_iface_init(priv) < 0) { 00343 wpas_dbus_deinit(priv); 00344 return NULL; 00345 } 00346 #endif /* CONFIG_CTRL_IFACE_DBUS */ 00347 00348 if (wpas_dbus_init_common_finish(priv) < 0) { 00349 wpas_dbus_deinit(priv); 00350 return NULL; 00351 } 00352 00353 return priv; 00354 } 00355 00356 00357 void wpas_dbus_deinit(struct wpas_dbus_priv *priv) 00358 { 00359 if (priv == NULL) 00360 return; 00361 00362 #ifdef CONFIG_CTRL_IFACE_DBUS_NEW 00363 wpas_dbus_ctrl_iface_deinit(priv); 00364 #endif /* CONFIG_CTRL_IFACE_DBUS_NEW */ 00365 00366 #ifdef CONFIG_CTRL_IFACE_DBUS 00367 /* TODO: is any deinit needed? */ 00368 #endif /* CONFIG_CTRL_IFACE_DBUS */ 00369 00370 wpas_dbus_deinit_common(priv); 00371 }