2 * Network Configuration Module
4 * Copyright (c) 2000 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
21 #include <vconf-keys.h>
26 #include "wifi-state.h"
27 #include "wifi-power.h"
28 #include "netsupplicant.h"
29 #include "network-state.h"
30 #include "wifi-indicator.h"
31 #include "network-statistics.h"
32 #include "wifi-background-scan.h"
34 #define NETCONFIG_NETWORK_NOTIFICATION_TIMEOUT 15 * 1000
36 static gboolean new_bss_found = FALSE;
37 static guint network_noti_timer_id = 0;
39 static wifi_service_state_e g_service_state = NETCONFIG_WIFI_UNKNOWN;
40 static wifi_tech_state_e g_tech_state = NETCONFIG_WIFI_TECH_UNKNOWN;
42 static GSList *notifier_list = NULL;
44 static guint network_connected_popup_timer_id = 0;
45 static gboolean block_network_connected_popup = FALSE;
47 static gboolean _block_network_connection_popup(gpointer data)
49 block_network_connected_popup = FALSE;
50 netconfig_stop_timer(&network_connected_popup_timer_id);
54 static void __set_wifi_connected_essid(void)
56 const char *essid_name = NULL;
57 const char *wifi_profile = netconfig_get_default_profile();
59 if (wifi_state_get_service_state() != NETCONFIG_WIFI_CONNECTED)
62 if (wifi_profile == NULL ||
63 netconfig_is_wifi_profile(wifi_profile) != TRUE) {
64 ERR("Can't get Wi-Fi profile");
68 essid_name = netconfig_wifi_get_connected_essid(wifi_profile);
69 if (essid_name == NULL) {
70 ERR("Can't get Wi-Fi name");
74 netconfig_set_vconf_str(VCONFKEY_WIFI_CONNECTED_AP_NAME, essid_name);
76 /* Block Network Connected popup for 3sec
77 * to avoid multiple popup's due to ready signals */
78 if (block_network_connected_popup == FALSE) {
79 block_network_connected_popup = TRUE;
80 netconfig_start_timer(3000, _block_network_connection_popup,
81 NULL, &network_connected_popup_timer_id);
82 __netconfig_pop_wifi_connected_poppup(essid_name);
86 static void __unset_wifi_connected_essid(void)
88 netconfig_set_vconf_str(VCONFKEY_WIFI_CONNECTED_AP_NAME, "");
91 static const char *__get_wifi_connected_essid(void)
93 const char *essid_name = NULL;
94 const char *wifi_profile = NULL;
96 if (wifi_state_get_service_state() != NETCONFIG_WIFI_CONNECTED)
99 wifi_profile = netconfig_get_default_profile();
101 if (wifi_profile == NULL || netconfig_is_wifi_profile(wifi_profile) != TRUE) {
102 ERR("Can't get Wi-Fi profile");
106 essid_name = netconfig_wifi_get_connected_essid(wifi_profile);
107 if (essid_name == NULL) {
108 ERR("Can't get Wi-Fi name");
115 static gboolean __is_wifi_profile_available(void)
117 GVariant *message = NULL;
118 GVariantIter *iter, *next;
121 message = netconfig_invoke_dbus_method(CONNMAN_SERVICE,
122 CONNMAN_MANAGER_PATH, CONNMAN_MANAGER_INTERFACE,
123 "GetServices", NULL);
124 if (message == NULL) {
125 ERR("Failed to get service list");
129 g_variant_get(message, "(a(oa{sv}))", &iter);
130 while (g_variant_iter_loop(iter, "(oa{sv})", &obj, &next)) {
131 if (obj == NULL || netconfig_is_wifi_profile((const gchar*)obj) == FALSE)
134 g_variant_iter_free(next);
139 g_variant_unref(message);
141 g_variant_iter_free(iter);
146 static gboolean __is_favorited(GVariantIter *array)
148 gboolean is_favorite = FALSE;
152 while (g_variant_iter_loop(array, "{sv}", &key, &var)) {
155 if (g_str_equal(key, "Favorite") != TRUE)
158 value = g_variant_get_boolean(var);
162 g_variant_unref(var);
169 static void _wifi_state_connected_activation(void)
171 /* Add activation of services when Wi-Fi is connected */
174 static void _wifi_state_changed(wifi_service_state_e state)
178 for (list = notifier_list; list; list = list->next) {
179 wifi_state_notifier *notifier = list->data;
181 if (notifier->wifi_state_changed != NULL)
182 notifier->wifi_state_changed(state, notifier->user_data);
186 static void _set_bss_found(gboolean found)
188 if (found != new_bss_found)
189 new_bss_found = found;
192 static gboolean _check_network_notification(gpointer data)
194 int qs_enable = 0, ug_state = 0;
195 static gboolean check_again = FALSE;
197 wifi_tech_state_e tech_state;
198 wifi_service_state_e service_state;
200 tech_state = wifi_state_get_technology_state();
201 if (tech_state < NETCONFIG_WIFI_TECH_POWERED) {
202 DBG("Wi-Fi off or WPS only supported[%d]", tech_state);
206 service_state = wifi_state_get_service_state();
207 if (service_state == NETCONFIG_WIFI_CONNECTED) {
208 DBG("Service state is connected");
210 } else if (service_state == NETCONFIG_WIFI_ASSOCIATION ||
211 service_state == NETCONFIG_WIFI_CONFIGURATION) {
212 DBG("Service state is connecting (check again : %d)", check_again);
220 if (__is_wifi_profile_available() == FALSE) {
221 netconfig_send_notification_to_net_popup(
222 NETCONFIG_DEL_FOUND_AP_NOTI, NULL);
226 netconfig_vconf_get_int(VCONFKEY_WIFI_ENABLE_QS, &qs_enable);
227 if (qs_enable != VCONFKEY_WIFI_QS_ENABLE) {
228 DBG("qs_enable != VCONFKEY_WIFI_QS_ENABLE");
232 netconfig_vconf_get_int(VCONFKEY_WIFI_UG_RUN_STATE, &ug_state);
233 if (ug_state == VCONFKEY_WIFI_UG_RUN_STATE_ON_FOREGROUND)
236 netconfig_send_notification_to_net_popup(NETCONFIG_ADD_FOUND_AP_NOTI, NULL);
238 _set_bss_found(FALSE);
241 netconfig_stop_timer(&network_noti_timer_id);
245 static char *_get_connman_favorite_service(void)
247 char *favorite_service = NULL;
248 GVariant *message = NULL;
250 GVariantIter *iter, *next;
252 message = netconfig_invoke_dbus_method(CONNMAN_SERVICE,
253 CONNMAN_MANAGER_PATH, CONNMAN_MANAGER_INTERFACE,
254 "GetServices", NULL);
255 if (message == NULL) {
256 ERR("Failed to get service list");
260 g_variant_get(message, "(a(oa{sv}))", &iter);
261 while (g_variant_iter_loop(iter, "(oa{sv})", &obj, &next)) {
262 if (obj == NULL || netconfig_is_wifi_profile(obj) == FALSE)
265 if (__is_favorited(next) == TRUE) {
266 favorite_service = g_strdup(obj);
268 g_variant_iter_free(next);
273 g_variant_iter_free(iter);
274 g_variant_unref(message);
276 return favorite_service;
279 static void __notification_value_changed_cb(keynode_t *node, void *user_data)
283 if (netconfig_vconf_get_int(VCONFKEY_WIFI_ENABLE_QS, &value) < 0)
286 if (value == VCONFKEY_WIFI_QS_DISABLE)
287 netconfig_send_notification_to_net_popup(NETCONFIG_DEL_FOUND_AP_NOTI, NULL);
290 static void _register_network_notification(void)
292 #if defined TIZEN_WEARABLE
295 vconf_notify_key_changed(VCONFKEY_WIFI_ENABLE_QS, __notification_value_changed_cb, NULL);
298 static void _deregister_network_notification(void)
300 #if defined TIZEN_WEARABLE
303 vconf_ignore_key_changed(VCONFKEY_WIFI_ENABLE_QS, __notification_value_changed_cb);
306 static void _set_power_save(gboolean power_save)
310 GVariant *input_args = NULL;
311 static gboolean old_state = TRUE;
312 const gchar *args_disable = "POWERMODE 1";
313 const gchar *args_enable = "POWERMODE 0";
314 if (old_state == power_save)
317 if_path = netconfig_wifi_get_supplicant_interface();
318 if (if_path == NULL) {
319 ERR("Fail to get wpa_supplicant DBus path");
324 input_args = g_variant_new_string(args_enable);
326 input_args = g_variant_new_string(args_disable);
328 result = netconfig_supplicant_invoke_dbus_method_nonblock(
331 SUPPLICANT_INTERFACE ".Interface",
336 ERR("Fail to set power save mode POWERMODE %d", power_save);
338 old_state = power_save;
340 g_variant_unref(input_args);
344 static void _set_power_lock(gboolean power_lock)
349 char state[] = "lcdoff";
350 char flag[] = "staycurstate";
351 char standby[] = "NULL";
353 char sleepmargin[] = "sleepmargin";
355 const char *lockstate = "lockstate";
356 const char *unlockstate = "unlockstate";
357 static gboolean old_state = FALSE;
358 const char *lock_method;
360 if (old_state == power_lock)
363 if (power_lock == TRUE) {
364 /* deviced power lock enable */
365 params = g_variant_new("(sssi)", state, flag, standby, timeout);
367 lock_method = lockstate;
369 /* deviced power lock disable */
370 params = g_variant_new("(ss)", state, sleepmargin);
372 lock_method = unlockstate;
375 reply = netconfig_invoke_dbus_method(
376 "org.tizen.system.deviced",
377 "/Org/Tizen/System/DeviceD/Display",
378 "org.tizen.system.deviced.display",
382 ERR("Failed to set_power_lock");
386 ret = g_variant_get_int32(reply);
388 ERR("Failed to set power lock %s with ret %d",
389 power_lock == TRUE ? "enable" : "disable", ret);
391 old_state = power_lock;
393 g_variant_unref(reply);
398 void wifi_state_emit_power_completed(gboolean power_on)
401 wifi_emit_power_on_completed((Wifi *)get_wifi_object());
403 wifi_emit_power_off_completed((Wifi *)get_wifi_object());
405 DBG("Successfully sent signal [%s]", (power_on) ? "powerOn" : "powerOff");
408 void wifi_state_emit_power_failed(void)
410 wifi_emit_power_operation_failed((Wifi *)get_wifi_object());
412 DBG("Successfully sent signal [PowerOperationFailed]");
415 void wifi_state_update_power_state(gboolean powered)
417 wifi_tech_state_e tech_state;
419 /* It's automatically updated by signal-handler
420 * DO NOT update manually
421 * It includes Wi-Fi state configuration
423 tech_state = wifi_state_get_technology_state();
425 if (powered == TRUE) {
426 if (tech_state < NETCONFIG_WIFI_TECH_POWERED && netconfig_is_wifi_tethering_on() != TRUE) {
427 DBG("Wi-Fi turned on or waken up from power-save mode");
429 wifi_state_set_tech_state(NETCONFIG_WIFI_TECH_POWERED);
431 wifi_state_emit_power_completed(TRUE);
433 netconfig_wifi_device_picker_service_start();
435 netconfig_set_vconf_int(VCONF_WIFI_LAST_POWER_STATE, VCONFKEY_WIFI_UNCONNECTED);
436 netconfig_set_vconf_int(VCONFKEY_WIFI_STATE, VCONFKEY_WIFI_UNCONNECTED);
437 netconfig_set_vconf_int(VCONFKEY_NETWORK_WIFI_STATE, VCONFKEY_NETWORK_WIFI_NOT_CONNECTED);
439 netconfig_set_system_event(SYS_EVT_WIFI_STATE, EKEY_WIFI_STATE, EVAL_WIFI_ON);
441 netconfig_wifi_bgscan_stop();
442 netconfig_wifi_bgscan_start(TRUE);
444 /* Add callback to track change in notification setting */
445 _register_network_notification();
447 } else if (tech_state > NETCONFIG_WIFI_TECH_OFF) {
448 DBG("Wi-Fi turned off or in power-save mode");
450 wifi_state_set_tech_state(NETCONFIG_WIFI_TECH_WPS_ONLY);
452 netconfig_wifi_device_picker_service_stop();
454 wifi_power_disable_technology_state_by_only_connman_signal();
455 wifi_power_driver_and_supplicant(FALSE);
457 wifi_state_emit_power_completed(FALSE);
459 netconfig_set_vconf_int(VCONF_WIFI_LAST_POWER_STATE, VCONFKEY_WIFI_OFF);
460 netconfig_set_vconf_int(VCONFKEY_WIFI_STATE, VCONFKEY_WIFI_OFF);
461 netconfig_set_vconf_int(VCONFKEY_NETWORK_WIFI_STATE, VCONFKEY_NETWORK_WIFI_OFF);
463 netconfig_set_system_event(SYS_EVT_WIFI_STATE, EKEY_WIFI_STATE, EVAL_WIFI_OFF);
465 netconfig_wifi_set_bgscan_pause(FALSE);
466 netconfig_wifi_bgscan_stop();
468 _set_bss_found(FALSE);
470 /* Inform net-popup to remove the wifi found notification */
471 netconfig_send_notification_to_net_popup(NETCONFIG_DEL_FOUND_AP_NOTI, NULL);
472 netconfig_send_notification_to_net_popup(NETCONFIG_DEL_PORTAL_NOTI, NULL);
474 _deregister_network_notification();
478 char *wifi_get_favorite_service(void)
480 return _get_connman_favorite_service();
483 void wifi_start_timer_network_notification(void)
485 #if defined TIZEN_WEARABLE
486 /* In case of wearable device, no need to notify available Wi-Fi APs */
489 netconfig_start_timer(NETCONFIG_NETWORK_NOTIFICATION_TIMEOUT, _check_network_notification, NULL, &network_noti_timer_id);
492 void wifi_state_notifier_register(wifi_state_notifier *notifier)
494 DBG("register notifier");
496 notifier_list = g_slist_append(notifier_list, notifier);
499 void wifi_state_notifier_unregister(wifi_state_notifier *notifier)
501 DBG("un-register notifier");
503 notifier_list = g_slist_remove_all(notifier_list, notifier);
506 void wifi_state_notifier_cleanup(void)
508 g_slist_free_full(notifier_list, NULL);
511 void wifi_state_set_bss_found(gboolean found)
513 _set_bss_found(found);
516 gboolean wifi_state_is_bss_found(void)
518 return new_bss_found;
521 void wifi_state_set_service_state(wifi_service_state_e new_state)
523 static gboolean dhcp_stage = FALSE;
524 wifi_service_state_e old_state = g_service_state;
526 if (old_state == new_state)
529 g_service_state = new_state;
530 DBG("Wi-Fi state %d ==> %d", old_state, new_state);
532 /* During DHCP, temporarily disable Wi-Fi power saving */
533 if ((old_state < NETCONFIG_WIFI_ASSOCIATION || old_state == NETCONFIG_WIFI_FAILURE) && new_state == NETCONFIG_WIFI_CONFIGURATION) {
534 _set_power_lock(TRUE);
535 _set_power_save(FALSE);
537 } else if (dhcp_stage == TRUE) {
538 _set_power_lock(FALSE);
539 _set_power_save(TRUE);
543 if (new_state == NETCONFIG_WIFI_CONNECTED) {
544 netconfig_send_notification_to_net_popup(NETCONFIG_DEL_FOUND_AP_NOTI, NULL);
546 netconfig_set_vconf_int(VCONFKEY_WIFI_STATE, VCONFKEY_WIFI_CONNECTED);
547 netconfig_set_vconf_int(VCONFKEY_NETWORK_WIFI_STATE, VCONFKEY_NETWORK_WIFI_CONNECTED);
549 netconfig_set_system_event(SYS_EVT_WIFI_STATE, EKEY_WIFI_STATE, EVAL_WIFI_CONNECTED);
551 __set_wifi_connected_essid();
553 netconfig_wifi_indicator_start();
554 } else if (old_state == NETCONFIG_WIFI_CONNECTED) {
555 netconfig_send_notification_to_net_popup(NETCONFIG_DEL_PORTAL_NOTI, NULL);
557 __unset_wifi_connected_essid();
559 netconfig_set_vconf_int (VCONFKEY_WIFI_STATE, VCONFKEY_WIFI_UNCONNECTED);
560 netconfig_set_vconf_int(VCONFKEY_NETWORK_WIFI_STATE, VCONFKEY_NETWORK_WIFI_NOT_CONNECTED);
562 netconfig_set_system_event(SYS_EVT_WIFI_STATE, EKEY_WIFI_STATE, EVAL_WIFI_ON);
564 netconfig_wifi_indicator_stop();
566 netconfig_wifi_set_bgscan_pause(FALSE);
568 netconfig_wifi_bgscan_stop();
569 netconfig_wifi_bgscan_start(TRUE);
570 } else if ((old_state > NETCONFIG_WIFI_IDLE && old_state < NETCONFIG_WIFI_CONNECTED) && new_state == NETCONFIG_WIFI_IDLE) {
571 /* in ipv6 case disconnect/association -> association */
572 DBG("reset the bg scan period");
573 netconfig_wifi_set_bgscan_pause(FALSE);
575 netconfig_wifi_bgscan_stop();
576 netconfig_wifi_bgscan_start(TRUE);
579 _wifi_state_changed(new_state);
581 if (new_state == NETCONFIG_WIFI_CONNECTED)
582 _wifi_state_connected_activation();
585 wifi_service_state_e wifi_state_get_service_state(void)
587 return g_service_state;
590 void wifi_state_set_tech_state(wifi_tech_state_e new_state)
592 wifi_tech_state_e old_state = g_tech_state;
594 if (old_state == new_state)
597 g_tech_state = new_state;
599 DBG("Wi-Fi technology state %d ==> %d", old_state, new_state);
602 wifi_tech_state_e wifi_state_get_technology_state(void)
604 GVariant *message = NULL, *variant;
605 GVariantIter *iter, *next;
606 wifi_tech_state_e ret = NETCONFIG_WIFI_TECH_OFF;
607 gboolean wifi_tech_powered = FALSE;
608 gboolean wifi_tech_connected = FALSE;
612 if (g_tech_state > NETCONFIG_WIFI_TECH_UNKNOWN)
615 message = netconfig_invoke_dbus_method(CONNMAN_SERVICE,
616 CONNMAN_MANAGER_PATH, CONNMAN_MANAGER_INTERFACE,
617 "GetTechnologies", NULL);
618 if (message == NULL) {
619 ERR("Failed to get_technology_state");
620 return NETCONFIG_WIFI_TECH_UNKNOWN;
623 g_variant_get(message, "(a(oa{sv}))", &iter);
624 while (g_variant_iter_loop(iter, "(oa{sv})", &path, &next)) {
625 if (path == NULL || g_strcmp0(path, CONNMAN_WIFI_TECHNOLOGY_PREFIX) != 0)
628 while (g_variant_iter_loop(next, "{sv}", &key, &variant)) {
629 const gchar *sdata = NULL;
632 if (g_variant_is_of_type(variant, G_VARIANT_TYPE_BOOLEAN)) {
633 data = g_variant_get_boolean(variant);
634 DBG("key-[%s] - %s", key, data ? "True" : "False");
636 if (strcmp(key, "Powered") == 0 && data)
637 wifi_tech_powered = TRUE;
638 else if (strcmp(key, "Connected") == 0 && data)
639 wifi_tech_connected = TRUE;
641 else if (strcmp(key, "Tethering") == 0 && data) {
643 } else if (g_variant_is_of_type(variant, G_VARIANT_TYPE_STRING)) {
644 sdata = g_variant_get_string(variant, NULL);
648 g_variant_iter_free(next);
651 g_variant_unref(message);
653 g_variant_iter_free(iter);
655 if (wifi_tech_powered == TRUE)
656 ret = NETCONFIG_WIFI_TECH_POWERED;
658 if (wifi_tech_connected == TRUE)
659 ret = NETCONFIG_WIFI_TECH_CONNECTED;
666 void wifi_state_set_connected_essid(void)
668 __set_wifi_connected_essid();
671 void wifi_state_get_connected_essid(gchar **essid)
673 *essid = g_strdup(__get_wifi_connected_essid());
676 /* wifi_connection_state_e in CAPI
678 * WIFI_CONNECTION_STATE_FAILURE = -1
679 * WIFI_CONNECTION_STATE_DISCONNECTED = 0
680 * WIFI_CONNECTION_STATE_ASSOCIATION = 1
681 * WIFI_CONNECTION_STATE_CONFIGURATION = 2
682 * WIFI_CONNECTION_STATE_CONNECTED = 3
684 /* connection_wifi_state_e in CAPI
686 * CONNECTION_WIFI_STATE_DEACTIVATED = 0
687 * CONNECTION_WIFI_STATE_DISCONNECTED = 1
688 * CONNECTION_WIFI_STATE_CONNECTED = 2
690 gboolean handle_get_wifi_state(Wifi *wifi, GDBusMethodInvocation *context)
692 g_return_val_if_fail(wifi != NULL, FALSE);
693 GVariant *param = NULL;
694 wifi_tech_state_e tech_state = NETCONFIG_WIFI_TECH_UNKNOWN;
695 wifi_service_state_e service_state = NETCONFIG_WIFI_UNKNOWN;
696 tech_state = wifi_state_get_technology_state();
697 service_state = wifi_state_get_service_state();
699 if (tech_state == NETCONFIG_WIFI_TECH_UNKNOWN)
700 param = g_variant_new("(s)", "unknown");
701 else if (tech_state == NETCONFIG_WIFI_TECH_OFF ||
702 tech_state == NETCONFIG_WIFI_TECH_WPS_ONLY)
703 param = g_variant_new("(s)", "deactivated");
704 else if (tech_state == NETCONFIG_WIFI_TECH_CONNECTED)
705 param = g_variant_new("(s)", "connected");
707 switch (service_state) {
708 case NETCONFIG_WIFI_FAILURE:
709 param = g_variant_new("(s)", "failure");
711 case NETCONFIG_WIFI_ASSOCIATION:
712 param = g_variant_new("(s)", "association");
714 case NETCONFIG_WIFI_CONFIGURATION:
715 param = g_variant_new("(s)", "configuration");
717 case NETCONFIG_WIFI_CONNECTED:
718 param = g_variant_new("(s)", "connected");
720 case NETCONFIG_WIFI_UNKNOWN:
721 case NETCONFIG_WIFI_IDLE:
723 param = g_variant_new("(s)", "disconnected");
727 g_dbus_method_invocation_return_value(context, param);