4 Copyright (C) 2009 Javier S. Pedro
6 @author Javier S. Pedro <javispedro@javispedro.com>
8 This file is part of libicd-network-wpa.
10 This program is free software; you can redistribute it and/or modify it
11 under the terms of the GNU General Public License as published by the
12 Free Software Foundation; either version 2 of the License, or (at your
13 option) any later version.
15 This program is distributed in the hope that it will be useful, but
16 WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 General Public License for more details.
20 You should have received a copy of the GNU General Public License along
21 with this program; if not, write to the Free Software Foundation, Inc.,
22 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
30 #include <dbus/dbus.h>
31 #include <gconf/gconf-client.h>
33 #include <osso-ic-dbus.h>
34 #include <osso-ic-gconf.h>
40 #include "dbus-helper.h"
44 #define WPAS_ERROR_INVALID_NETWORK \
45 WPAS_DBUS_IFACE_INTERFACE ".InvalidNetwork"
46 #define WPAS_ERROR_INVALID_BSSID \
47 WPAS_DBUS_IFACE_INTERFACE ".InvalidBSSID"
49 #define WPAS_ERROR_INVALID_OPTS \
50 WPAS_DBUS_INTERFACE ".InvalidOptions"
51 #define WPAS_ERROR_INVALID_IFACE \
52 WPAS_DBUS_INTERFACE ".InvalidInterface"
54 #define WPAS_ERROR_ADD_ERROR \
55 WPAS_DBUS_INTERFACE ".AddError"
56 #define WPAS_ERROR_EXISTS_ERROR \
57 WPAS_DBUS_INTERFACE ".ExistsError"
58 #define WPAS_ERROR_REMOVE_ERROR \
59 WPAS_DBUS_INTERFACE ".RemoveError"
61 #define WPAS_ERROR_SCAN_ERROR \
62 WPAS_DBUS_IFACE_INTERFACE ".ScanError"
63 #define WPAS_ERROR_ADD_NETWORK_ERROR \
64 WPAS_DBUS_IFACE_INTERFACE ".AddNetworkError"
65 #define WPAS_ERROR_INTERNAL_ERROR \
66 WPAS_DBUS_IFACE_INTERFACE ".InternalError"
67 #define WPAS_ERROR_REMOVE_NETWORK_ERROR \
68 WPAS_DBUS_IFACE_INTERFACE ".RemoveNetworkError"
70 #define WPAS_DBUS_BSSID_FORMAT "%02x%02x%02x%02x%02x%02x"
72 static pid_t supp_pid = 0;
73 static int supp_activation_tries = 0;
75 static gchar* supp_iface = NULL;
76 static gchar* supp_iface_path = NULL;
78 static gchar* supp_network_id = NULL;
79 static gchar* supp_config_path = NULL;
81 static gboolean supp_configured = FALSE; // Unused right now
83 /* Callback for supplicant events */
84 static supp_cb_fn supp_cb = NULL;
85 static gpointer supp_cb_data = NULL;
87 static void supp_configure();
89 void supp_set_callback(supp_cb_fn cb, gpointer user_data)
92 supp_cb_data = user_data;
95 static inline void supp_callback(int result, const char * message)
97 if (supp_cb) supp_cb(result, message, supp_cb_data);
100 static gboolean supp_set_interface_retry(gpointer data)
102 DLOG_DEBUG(__func__);
104 if (supp_pid && supp_iface) supp_set_interface(supp_iface);
108 static void add_iface_reply_cb(DBusPendingCall *pending, void *user_data)
113 DLOG_DEBUG("%s", __func__);
115 dbus_error_init(&error);
117 reply = dbus_pending_call_steal_reply(pending);
119 if (dbus_set_error_from_message(&error, reply)) {
120 DLOG_WARN_L("Error in %s:%s", __func__, error.name);
122 if (strcmp(DBUS_ERROR_SERVICE_UNKNOWN, error.name) == 0)
124 // Supplicant not (yet) active? Try later
125 DLOG_DEBUG("Still waiting for supplicant");
126 supp_activation_tries++;
127 if (supp_activation_tries >= 3) {
128 supp_callback(-1, error.name);
131 supp_set_interface_retry,
135 supp_callback(-1, error.name);
138 dbus_error_free(&error);
140 // Move on to next step
142 if (!dbus_message_get_args(
144 DBUS_TYPE_OBJECT_PATH, &path,
147 supp_callback(-1, error.name);
148 goto iface_reply_error;
151 supp_iface_path = g_strdup(path);
152 DLOG_DEBUG("Got interface path: %s", supp_iface_path);
153 if (supp_network_id && !supp_config_path) {
154 supp_set_network_id(supp_network_id);
155 } else if (supp_config_path && !supp_configured) {
162 dbus_message_unref(reply);
163 dbus_pending_call_unref(pending);
166 void supp_unset_interface()
169 // mostly uneeded, since we're killing the supplicant instead
170 g_free(supp_iface_path);
171 supp_iface_path = NULL;
176 void supp_set_interface(const char * iface)
179 DBusPendingCall *pending;
181 DLOG_DEBUG("%s: %s", __func__, iface);
183 if (supp_iface_path) {
184 supp_unset_interface();
187 if (iface != supp_iface) {
192 supp_iface = g_strdup(iface);
195 msg = new_dbus_method_call(
203 DBUS_TYPE_STRING, &iface,
206 if (!dbus_connection_send_with_reply(get_dbus_connection(),
208 die("Out of memory");
210 if (!dbus_pending_call_set_notify(pending,
211 add_iface_reply_cb, NULL, NULL))
212 die("Out of memory");
214 dbus_message_unref(msg);
217 static void add_network_reply_cb(DBusPendingCall *pending, void *user_data)
222 DLOG_DEBUG("%s", __func__);
224 dbus_error_init(&error);
226 reply = dbus_pending_call_steal_reply(pending);
228 if (dbus_set_error_from_message(&error, reply)) {
229 DLOG_WARN_L("Error in %s:%s", __func__, error.name);
231 supp_callback(-1, error.name);
232 dbus_error_free(&error);
234 // Move on to next step
236 if (!dbus_message_get_args(
238 DBUS_TYPE_OBJECT_PATH, &path,
241 supp_callback(-1, error.name);
242 goto net_reply_error;
245 supp_config_path = g_strdup(path);
246 DLOG_DEBUG("Got network path: %s", supp_iface_path);
247 if (supp_iface_path && !supp_configured) {
254 dbus_message_unref(reply);
255 dbus_pending_call_unref(pending);
258 void supp_unset_network_id()
260 g_free(supp_config_path);
261 supp_config_path = NULL;
262 g_free(supp_network_id);
263 supp_network_id = NULL;
267 void supp_set_network_id(const char * network_id)
270 DBusPendingCall *pending;
272 DLOG_DEBUG("%s: %s", __func__, network_id);
274 if (supp_config_path) {
275 supp_unset_network_id();
278 if (network_id != supp_network_id) {
279 if (supp_network_id) {
280 g_free(supp_network_id);
283 supp_network_id = g_strdup(network_id);
286 if (!supp_iface_path) {
287 DLOG_DEBUG("Deferring network creation");
291 msg = new_dbus_method_call(
294 WPAS_DBUS_IFACE_INTERFACE,
297 if (!dbus_connection_send_with_reply(get_dbus_connection(),
299 die("Out of memory");
301 if (!dbus_pending_call_set_notify(pending,
302 add_network_reply_cb, NULL, NULL))
303 die("Out of memory");
305 dbus_message_unref(msg);
308 static gchar * wpas_params[3] = { "/sbin/wpa_supplicant", "-u", NULL };
312 DLOG_DEBUG("%s", __func__);
314 supp_activation_tries = 0;
318 if (!g_spawn_async(NULL, wpas_params, NULL,
319 G_SPAWN_DO_NOT_REAP_CHILD,
320 NULL, NULL, &pid, &error)) {
321 DLOG_ERR("Couldn't spawn supplicant: %s", error->message);
327 DLOG_INFO("Spawned %s , pid %d", wpas_params[0], pid);
329 icd_watch_pid(supp_pid);
334 void supp_disable(void)
337 DLOG_INFO("Killing supplicant (pid %d)", supp_pid);
338 kill(supp_pid, SIGTERM);
341 // Consider everything as deconfigured
344 g_free(supp_iface_path);
345 supp_iface_path = NULL;
346 g_free(supp_network_id);
347 supp_network_id = NULL;
348 g_free(supp_config_path);
349 supp_config_path = NULL;
351 supp_configured = FALSE;
354 int supp_is_active(void)
356 return supp_pid ? TRUE : FALSE;
359 void supp_handle_signal(gchar* old_state, gchar* new_state)
361 DLOG_DEBUG("Supplicant StateChange %s -> %s", old_state, new_state);
363 if (strcmp(new_state, "COMPLETED") == 0)
365 supp_callback(SUPP_STATUS_CONNECTED, new_state);
366 } else if (strcmp(new_state, "DISCONNECTED") == 0) {
367 supp_callback(SUPP_STATUS_DISCONNECTED, new_state);
371 void supp_handle_killed(void)
373 DLOG_DEBUG("%s", __func__);
375 g_spawn_close_pid(supp_pid);
380 supp_callback(SUPP_STATUS_KILLED, NULL);
383 static void free_settings_item(gpointer data, gpointer user_data)
385 gconf_entry_free(data);
388 static void enable_reply_cb(DBusPendingCall *pending, void *user_data)
393 DLOG_DEBUG("%s", __func__);
395 dbus_error_init(&error);
397 reply = dbus_pending_call_steal_reply(pending);
399 if (dbus_set_error_from_message(&error, reply)) {
400 DLOG_WARN_L("Error in %s:%s", __func__, error.name);
402 supp_callback(SUPP_STATUS_ERROR, error.name);
403 dbus_error_free(&error);
407 dbus_message_unref(reply);
408 dbus_pending_call_unref(pending);
411 static void supp_enable_network()
413 DBusMessage* message; //The full mesage we are going to send.
414 DBusPendingCall *pending;
416 message = dbus_message_new_method_call(
419 WPAS_DBUS_IFACE_NETWORK,
420 WPAS_ENABLE_NETWORK_METHOD
423 DLOG_CRIT_L("Out of memory");
424 supp_callback(-1, ICD_DBUS_ERROR_SYSTEM_ERROR);
429 if (!dbus_connection_send_with_reply(get_dbus_connection(),
430 message, &pending, -1)) {
431 DLOG_CRIT_L("Out of memory");
432 supp_callback(-1, ICD_DBUS_ERROR_SYSTEM_ERROR);
436 if (!dbus_pending_call_set_notify(pending,
437 enable_reply_cb, NULL, NULL)) {
438 DLOG_CRIT_L("Out of memory");
439 supp_callback(-1, ICD_DBUS_ERROR_SYSTEM_ERROR);
444 dbus_message_unref(message);
447 static void configure_reply_cb(DBusPendingCall *pending, void *user_data)
452 DLOG_DEBUG("%s", __func__);
454 dbus_error_init(&error);
456 reply = dbus_pending_call_steal_reply(pending);
458 if (dbus_set_error_from_message(&error, reply)) {
459 DLOG_WARN_L("Error in %s:%s", __func__, error.name);
461 supp_callback(-1, error.name);
462 dbus_error_free(&error);
464 supp_enable_network();
468 dbus_message_unref(reply);
469 dbus_pending_call_unref(pending);
472 static void supp_configure()
474 // This is going to be long
475 DLOG_DEBUG("%s: %s", __func__, supp_network_id);
476 GConfClient *client = gconf_client_get_default();
477 GError *error = NULL;
479 DBusMessage* message; //The full mesage we are going to send.
480 DBusMessageIter iter, iter_dict;
481 DBusPendingCall *pending;
484 DLOG_ERR("Cannot get gconf client");
485 supp_callback(-1, ICD_DBUS_ERROR_SYSTEM_ERROR);
489 gchar * settings_path = g_strconcat(ICD_GCONF_PATH,
490 "/", supp_network_id, NULL);
492 GSList * settings = gconf_client_all_entries(client,
493 settings_path, &error);
495 DLOG_ERR("Could not get setting:%s, error:%s", settings_path,
497 g_free(settings_path);
498 g_clear_error(&error);
499 g_object_unref(client);
500 supp_callback(-1, error->message);
504 message = dbus_message_new_method_call(
507 WPAS_DBUS_IFACE_NETWORK,
508 WPAS_SET_NETWORK_METHOD
511 DLOG_CRIT_L("Out of memory");
512 supp_callback(-1, ICD_DBUS_ERROR_SYSTEM_ERROR);
516 dbus_message_iter_init_append(message, &iter);
517 if (dbus_dict_open_write(&iter, &iter_dict) != 0) {
518 DLOG_CRIT_L("Out of memory");
519 supp_callback(-1, ICD_DBUS_ERROR_SYSTEM_ERROR);
520 goto dict_init_error;
523 DLOG_DEBUG("Preparing to send %d settings", g_slist_length(settings));
526 for (i = settings; i; i = g_slist_next(i)) {
527 GConfEntry* entry = i->data;
528 gchar * key = g_path_get_basename(gconf_entry_get_key(entry));
529 GConfValue* value = gconf_entry_get_value(entry);
531 if (g_ascii_strncasecmp(key,
532 WPA_GCONF_SETTING_PREFIX,
533 WPA_GCONF_SETTING_PREFIX_LEN)) {
539 key += WPA_GCONF_SETTING_PREFIX_LEN;
541 switch (value->type) {
542 case GCONF_VALUE_STRING:
543 DLOG_DEBUG("Setting string %s = %s",
544 key, gconf_value_get_string(value));
545 dbus_dict_append_string(&iter_dict,
546 key, gconf_value_get_string(value));
549 case GCONF_VALUE_INT:
550 DLOG_DEBUG("Setting int32 %s = %d",
551 key, gconf_value_get_int(value));
552 dbus_dict_append_int32(&iter_dict,
553 key, gconf_value_get_int(value));
556 DLOG_DEBUG("Unknown setting type for %s",
561 key -= WPA_GCONF_SETTING_PREFIX_LEN;
565 if (dbus_dict_close_write(&iter, &iter_dict) != 0) {
566 supp_callback(-1, ICD_DBUS_ERROR_SYSTEM_ERROR);
567 goto dict_close_error;
571 if (!dbus_connection_send_with_reply(get_dbus_connection(),
572 message, &pending, -1)) {
573 DLOG_CRIT_L("Out of memory");
574 supp_callback(-1, ICD_DBUS_ERROR_SYSTEM_ERROR);
578 if (!dbus_pending_call_set_notify(pending,
579 configure_reply_cb, NULL, NULL)) {
580 DLOG_CRIT_L("Out of memory");
581 supp_callback(-1, ICD_DBUS_ERROR_SYSTEM_ERROR);
589 dbus_message_unref(message);
591 g_free(settings_path);
593 g_slist_foreach(settings, free_settings_item, NULL);
594 g_slist_free(settings);
596 g_object_unref(client);