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>
23 #include <bundle_internal.h>
24 #include <eventsystem.h>
25 #include <syspopup_caller.h>
30 #include "wifi-state.h"
31 #include "wifi-power.h"
32 #include "netsupplicant.h"
33 #include "network-state.h"
34 #include "wifi-indicator.h"
35 #include "network-statistics.h"
36 #include "wifi-background-scan.h"
38 #define NETCONFIG_NETWORK_NOTIFICATION_TIMEOUT 15 * 1000
40 static gboolean new_bss_found = FALSE;
41 static guint network_noti_timer_id = 0;
43 static wifi_service_state_e g_service_state = NETCONFIG_WIFI_UNKNOWN;
44 static wifi_tech_state_e g_tech_state = NETCONFIG_WIFI_TECH_UNKNOWN;
46 static GSList *notifier_list = NULL;
49 static void __netconfig_pop_wifi_connected_poppup(const char *ssid)
58 bundle_add(b, "_SYSPOPUP_TITLE_", "Network connection popup");
59 bundle_add(b, "_SYSPOPUP_TYPE_", "notification");
60 bundle_add(b, "_SYSPOPUP_CONTENT_", "wifi connected");
61 bundle_add(b, "_AP_NAME_", ssid);
63 DBG("Launch Wi-Fi connected alert network popup");
64 syspopup_launch("net.netpopup", b);
69 static void __set_wifi_connected_essid(void)
71 const char *essid_name = NULL;
72 const char *wifi_profile = netconfig_get_default_profile();
74 if (wifi_state_get_service_state() != NETCONFIG_WIFI_CONNECTED)
77 if (wifi_profile == NULL ||
78 netconfig_is_wifi_profile(wifi_profile) != TRUE) {
79 ERR("Can't get Wi-Fi profile");
83 essid_name = netconfig_wifi_get_connected_essid(wifi_profile);
84 if (essid_name == NULL) {
85 ERR("Can't get Wi-Fi name");
89 netconfig_set_vconf_str(VCONFKEY_WIFI_CONNECTED_AP_NAME, essid_name);
90 __netconfig_pop_wifi_connected_poppup(essid_name);
93 static void __unset_wifi_connected_essid(void)
95 netconfig_set_vconf_str(VCONFKEY_WIFI_CONNECTED_AP_NAME, "");
98 static const char *__get_wifi_connected_essid(void)
100 const char *essid_name = NULL;
101 const char *wifi_profile = NULL;
103 if (wifi_state_get_service_state() != NETCONFIG_WIFI_CONNECTED)
106 wifi_profile = netconfig_get_default_profile();
108 if (wifi_profile == NULL || netconfig_is_wifi_profile(wifi_profile) != TRUE) {
109 ERR("Can't get Wi-Fi profile");
113 essid_name = netconfig_wifi_get_connected_essid(wifi_profile);
114 if (essid_name == NULL) {
115 ERR("Can't get Wi-Fi name");
122 static gboolean __is_wifi_profile_available(void)
124 GVariant *message = NULL;
125 GVariantIter *iter, *next;
128 message = netconfig_invoke_dbus_method(CONNMAN_SERVICE,
129 CONNMAN_MANAGER_PATH, CONNMAN_MANAGER_INTERFACE,
130 "GetServices", NULL);
131 if (message == NULL) {
132 ERR("Failed to get service list");
136 g_variant_get(message, "(a(oa{sv}))", &iter);
137 while (g_variant_iter_loop(iter, "(oa{sv})", &obj, &next)) {
138 if (obj == NULL || netconfig_is_wifi_profile((const gchar*)obj) == FALSE)
141 g_variant_iter_free(next);
146 g_variant_unref(message);
148 g_variant_iter_free(iter);
153 static gboolean __is_favorited(GVariantIter *array)
155 gboolean is_favorite = FALSE;
159 while (g_variant_iter_loop(array, "{sv}", &key, &var)) {
162 if (g_str_equal(key, "Favorite") != TRUE)
165 value = g_variant_get_boolean(var);
169 g_variant_unref(var);
176 static void _wifi_state_connected_activation(void)
178 /* Add activation of services when Wi-Fi is connected */
181 static void _wifi_state_changed(wifi_service_state_e state)
185 for (list = notifier_list; list; list = list->next) {
186 wifi_state_notifier *notifier = list->data;
188 if (notifier->wifi_state_changed != NULL)
189 notifier->wifi_state_changed(state, notifier->user_data);
193 static void _set_bss_found(gboolean found)
195 if (found != new_bss_found)
196 new_bss_found = found;
199 static gboolean _check_network_notification(gpointer data)
201 int qs_enable = 0, ug_state = 0;
202 static gboolean check_again = FALSE;
204 wifi_tech_state_e tech_state;
205 wifi_service_state_e service_state;
207 tech_state = wifi_state_get_technology_state();
208 if (tech_state < NETCONFIG_WIFI_TECH_POWERED) {
209 DBG("Wi-Fi off or WPS only supported[%d]", tech_state);
213 service_state = wifi_state_get_service_state();
214 if (service_state == NETCONFIG_WIFI_CONNECTED) {
215 DBG("Service state is connected");
217 } else if (service_state == NETCONFIG_WIFI_ASSOCIATION ||
218 service_state == NETCONFIG_WIFI_CONFIGURATION) {
219 DBG("Service state is connecting (check again : %d)", check_again);
227 if (__is_wifi_profile_available() == FALSE) {
228 netconfig_send_notification_to_net_popup(
229 NETCONFIG_DEL_FOUND_AP_NOTI, NULL);
233 vconf_get_int(VCONFKEY_WIFI_ENABLE_QS, &qs_enable);
234 if (qs_enable != VCONFKEY_WIFI_QS_ENABLE) {
235 DBG("qs_enable != VCONFKEY_WIFI_QS_ENABLE");
239 vconf_get_int(VCONFKEY_WIFI_UG_RUN_STATE, &ug_state);
240 if (ug_state == VCONFKEY_WIFI_UG_RUN_STATE_ON_FOREGROUND)
243 netconfig_send_notification_to_net_popup(NETCONFIG_ADD_FOUND_AP_NOTI, NULL);
245 _set_bss_found(FALSE);
248 netconfig_stop_timer(&network_noti_timer_id);
252 static char *_get_connman_favorite_service(void)
254 char *favorite_service = NULL;
255 GVariant *message = NULL;
257 GVariantIter *iter, *next;
259 message = netconfig_invoke_dbus_method(CONNMAN_SERVICE,
260 CONNMAN_MANAGER_PATH, CONNMAN_MANAGER_INTERFACE,
261 "GetServices", NULL);
262 if (message == NULL) {
263 ERR("Failed to get service list");
267 g_variant_get(message, "(a(oa{sv}))", &iter);
268 while (g_variant_iter_loop(iter, "(oa{sv})", &obj, &next)) {
269 if (obj == NULL || netconfig_is_wifi_profile(obj) == FALSE)
272 if (__is_favorited(next) == TRUE) {
273 favorite_service = g_strdup(obj);
275 g_variant_iter_free(next);
280 g_variant_iter_free(iter);
281 g_variant_unref(message);
283 return favorite_service;
286 static void __notification_value_changed_cb(keynode_t *node, void *user_data)
290 if (vconf_get_int(VCONFKEY_WIFI_ENABLE_QS, &value) < 0)
293 if (value == VCONFKEY_WIFI_QS_DISABLE)
294 netconfig_send_notification_to_net_popup(NETCONFIG_DEL_FOUND_AP_NOTI, NULL);
297 static void _register_network_notification(void)
299 #if defined TIZEN_WEARABLE
302 vconf_notify_key_changed(VCONFKEY_WIFI_ENABLE_QS, __notification_value_changed_cb, NULL);
305 static void _deregister_network_notification(void)
307 #if defined TIZEN_WEARABLE
310 vconf_ignore_key_changed(VCONFKEY_WIFI_ENABLE_QS, __notification_value_changed_cb);
313 static void _set_power_save(gboolean power_save)
317 GVariant *input_args = NULL;
318 static gboolean old_state = TRUE;
319 const gchar *args_disable = "POWERMODE 1";
320 const gchar *args_enable = "POWERMODE 0";
321 if (old_state == power_save)
324 if_path = netconfig_wifi_get_supplicant_interface();
325 if (if_path == NULL) {
326 ERR("Fail to get wpa_supplicant DBus path");
331 input_args = g_variant_new_string(args_enable);
333 input_args = g_variant_new_string(args_disable);
335 result = netconfig_supplicant_invoke_dbus_method_nonblock(
338 SUPPLICANT_INTERFACE ".Interface",
343 ERR("Fail to set power save mode POWERMODE %d", power_save);
345 old_state = power_save;
350 static void _set_power_lock(gboolean power_lock)
355 char state[] = "lcdoff";
356 char flag[] = "staycurstate";
357 char standby[] = "NULL";
359 char sleepmargin[] = "sleepmargin";
361 const char *lockstate = "lockstate";
362 const char *unlockstate = "unlockstate";
363 static gboolean old_state = FALSE;
364 const char *lock_method;
366 if (old_state == power_lock)
369 if (power_lock == TRUE) {
370 /* deviced power lock enable */
371 params = g_variant_new("(sssi)", state, flag, standby, timeout);
373 lock_method = lockstate;
375 /* deviced power lock disable */
376 params = g_variant_new("(ss)", state, sleepmargin);
378 lock_method = unlockstate;
381 reply = netconfig_invoke_dbus_method(
382 "org.tizen.system.deviced",
383 "/Org/Tizen/System/DeviceD/Display",
384 "org.tizen.system.deviced.display",
388 ERR("Failed to set_power_lock");
392 ret = g_variant_get_int32(reply);
394 ERR("Failed to set power lock %s with ret %d",
395 power_lock == TRUE ? "enable" : "disable", ret);
397 old_state = power_lock;
399 g_variant_unref(reply);
404 void wifi_state_emit_power_completed(gboolean power_on)
407 wifi_emit_power_on_completed((Wifi *)get_wifi_object());
409 wifi_emit_power_off_completed((Wifi *)get_wifi_object());
411 DBG("Successfully sent signal [%s]", (power_on) ? "powerOn" : "powerOff");
414 void wifi_state_emit_power_failed(void)
416 wifi_emit_power_operation_failed((Wifi *)get_wifi_object());
418 DBG("Successfully sent signal [PowerOperationFailed]");
421 void wifi_state_update_power_state(gboolean powered)
423 wifi_tech_state_e tech_state;
425 /* It's automatically updated by signal-handler
426 * DO NOT update manually
427 * It includes Wi-Fi state configuration
429 tech_state = wifi_state_get_technology_state();
431 if (powered == TRUE) {
432 if (tech_state < NETCONFIG_WIFI_TECH_POWERED && netconfig_is_wifi_tethering_on() != TRUE) {
433 DBG("Wi-Fi turned on or waken up from power-save mode");
435 wifi_state_set_tech_state(NETCONFIG_WIFI_TECH_POWERED);
437 wifi_state_emit_power_completed(TRUE);
439 netconfig_wifi_device_picker_service_start();
441 netconfig_set_vconf_int(VCONF_WIFI_LAST_POWER_STATE, VCONFKEY_WIFI_UNCONNECTED);
442 netconfig_set_vconf_int(VCONFKEY_WIFI_STATE, VCONFKEY_WIFI_UNCONNECTED);
443 netconfig_set_vconf_int(VCONFKEY_NETWORK_WIFI_STATE, VCONFKEY_NETWORK_WIFI_NOT_CONNECTED);
445 netconfig_set_system_event(SYS_EVENT_WIFI_STATE, EVT_KEY_WIFI_STATE, EVT_VAL_WIFI_ON);
447 netconfig_wifi_bgscan_stop();
448 netconfig_wifi_bgscan_start(TRUE);
450 /* Add callback to track change in notification setting */
451 _register_network_notification();
453 } else if (tech_state > NETCONFIG_WIFI_TECH_OFF) {
454 DBG("Wi-Fi turned off or in power-save mode");
456 wifi_state_set_tech_state(NETCONFIG_WIFI_TECH_WPS_ONLY);
458 netconfig_wifi_device_picker_service_stop();
460 wifi_power_disable_technology_state_by_only_connman_signal();
461 wifi_power_driver_and_supplicant(FALSE);
463 wifi_state_emit_power_completed(FALSE);
465 netconfig_set_vconf_int(VCONF_WIFI_LAST_POWER_STATE, VCONFKEY_WIFI_OFF);
466 netconfig_set_vconf_int(VCONFKEY_WIFI_STATE, VCONFKEY_WIFI_OFF);
467 netconfig_set_vconf_int(VCONFKEY_NETWORK_WIFI_STATE, VCONFKEY_NETWORK_WIFI_OFF);
469 netconfig_set_system_event(SYS_EVENT_WIFI_STATE, EVT_KEY_WIFI_STATE, EVT_VAL_WIFI_OFF);
471 netconfig_wifi_set_bgscan_pause(FALSE);
472 netconfig_wifi_bgscan_stop();
474 _set_bss_found(FALSE);
476 /* Inform net-popup to remove the wifi found notification */
477 netconfig_send_notification_to_net_popup(NETCONFIG_DEL_FOUND_AP_NOTI, NULL);
478 netconfig_send_notification_to_net_popup(NETCONFIG_DEL_PORTAL_NOTI, NULL);
480 _deregister_network_notification();
484 char *wifi_get_favorite_service(void)
486 return _get_connman_favorite_service();
489 void wifi_start_timer_network_notification(void)
491 #if defined TIZEN_WEARABLE
492 /* In case of wearable device, no need to notify available Wi-Fi APs */
495 netconfig_start_timer(NETCONFIG_NETWORK_NOTIFICATION_TIMEOUT, _check_network_notification, NULL, &network_noti_timer_id);
498 void wifi_state_notifier_register(wifi_state_notifier *notifier)
500 DBG("register notifier");
502 notifier_list = g_slist_append(notifier_list, notifier);
505 void wifi_state_notifier_unregister(wifi_state_notifier *notifier)
507 DBG("un-register notifier");
509 notifier_list = g_slist_remove_all(notifier_list, notifier);
512 void wifi_state_notifier_cleanup(void)
514 g_slist_free_full(notifier_list, NULL);
517 void wifi_state_set_bss_found(gboolean found)
519 _set_bss_found(found);
522 gboolean wifi_state_is_bss_found(void)
524 return new_bss_found;
527 void wifi_state_set_service_state(wifi_service_state_e new_state)
529 static gboolean dhcp_stage = FALSE;
530 wifi_service_state_e old_state = g_service_state;
532 if (old_state == new_state)
535 g_service_state = new_state;
536 DBG("Wi-Fi state %d ==> %d", old_state, new_state);
538 /* During DHCP, temporarily disable Wi-Fi power saving */
539 if ((old_state < NETCONFIG_WIFI_ASSOCIATION || old_state == NETCONFIG_WIFI_FAILURE) && new_state == NETCONFIG_WIFI_CONFIGURATION) {
540 _set_power_lock(TRUE);
541 _set_power_save(FALSE);
543 } else if (dhcp_stage == TRUE) {
544 _set_power_lock(FALSE);
545 _set_power_save(TRUE);
549 if (new_state == NETCONFIG_WIFI_CONNECTED) {
550 netconfig_send_notification_to_net_popup(NETCONFIG_DEL_FOUND_AP_NOTI, NULL);
552 netconfig_set_vconf_int(VCONFKEY_WIFI_STATE, VCONFKEY_WIFI_CONNECTED);
553 netconfig_set_vconf_int(VCONFKEY_NETWORK_WIFI_STATE, VCONFKEY_NETWORK_WIFI_CONNECTED);
555 netconfig_set_system_event(SYS_EVENT_WIFI_STATE, EVT_KEY_WIFI_STATE, EVT_VAL_WIFI_CONNECTED);
557 __set_wifi_connected_essid();
559 netconfig_wifi_indicator_start();
560 } else if (old_state == NETCONFIG_WIFI_CONNECTED) {
561 netconfig_send_notification_to_net_popup(NETCONFIG_DEL_PORTAL_NOTI, NULL);
563 __unset_wifi_connected_essid();
565 netconfig_set_vconf_int (VCONFKEY_WIFI_STATE, VCONFKEY_WIFI_UNCONNECTED);
566 netconfig_set_vconf_int(VCONFKEY_NETWORK_WIFI_STATE, VCONFKEY_NETWORK_WIFI_NOT_CONNECTED);
568 netconfig_set_system_event(SYS_EVENT_WIFI_STATE, EVT_KEY_WIFI_STATE, EVT_VAL_WIFI_ON);
570 netconfig_wifi_indicator_stop();
572 netconfig_wifi_set_bgscan_pause(FALSE);
574 netconfig_wifi_bgscan_stop();
575 netconfig_wifi_bgscan_start(TRUE);
576 } else if ((old_state > NETCONFIG_WIFI_IDLE && old_state < NETCONFIG_WIFI_CONNECTED) && new_state == NETCONFIG_WIFI_IDLE) {
577 /* in ipv6 case disconnect/association -> association */
578 DBG("reset the bg scan period");
579 netconfig_wifi_set_bgscan_pause(FALSE);
581 netconfig_wifi_bgscan_stop();
582 netconfig_wifi_bgscan_start(TRUE);
585 _wifi_state_changed(new_state);
587 if (new_state == NETCONFIG_WIFI_CONNECTED) {
588 _wifi_state_connected_activation();
589 #if defined TIZEN_WEARABLE
590 wc_launch_syspopup(WC_POPUP_TYPE_WIFI_CONNECTED);
595 wifi_service_state_e wifi_state_get_service_state(void)
597 return g_service_state;
600 void wifi_state_set_tech_state(wifi_tech_state_e new_state)
602 wifi_tech_state_e old_state = g_tech_state;
604 if (old_state == new_state)
607 g_tech_state = new_state;
609 DBG("Wi-Fi technology state %d ==> %d", old_state, new_state);
612 wifi_tech_state_e wifi_state_get_technology_state(void)
614 GVariant *message = NULL, *variant;
615 GVariantIter *iter, *next;
616 wifi_tech_state_e ret = NETCONFIG_WIFI_TECH_OFF;
617 gboolean wifi_tech_powered = FALSE;
618 gboolean wifi_tech_connected = FALSE;
622 if (g_tech_state > NETCONFIG_WIFI_TECH_UNKNOWN)
625 message = netconfig_invoke_dbus_method(CONNMAN_SERVICE,
626 CONNMAN_MANAGER_PATH, CONNMAN_MANAGER_INTERFACE,
627 "GetTechnologies", NULL);
628 if (message == NULL) {
629 ERR("Failed to get_technology_state");
630 return NETCONFIG_WIFI_TECH_UNKNOWN;
633 g_variant_get(message, "(a(oa{sv}))", &iter);
634 while (g_variant_iter_loop(iter, "(oa{sv})", &path, &next)) {
635 if (path == NULL || g_strcmp0(path, CONNMAN_WIFI_TECHNOLOGY_PREFIX) != 0)
638 while (g_variant_iter_loop(next, "{sv}", &key, &variant)) {
639 const gchar *sdata = NULL;
642 if (g_variant_is_of_type(variant, G_VARIANT_TYPE_BOOLEAN)) {
643 data = g_variant_get_boolean(variant);
644 DBG("key-[%s] - %s", key, data ? "True" : "False");
646 if (strcmp(key, "Powered") == 0 && data)
647 wifi_tech_powered = TRUE;
648 else if (strcmp(key, "Connected") == 0 && data)
649 wifi_tech_connected = TRUE;
651 else if (strcmp(key, "Tethering") == 0 && data) {
653 } else if (g_variant_is_of_type(variant, G_VARIANT_TYPE_STRING)) {
654 sdata = g_variant_get_string(variant, NULL);
658 g_variant_iter_free(next);
661 g_variant_unref(message);
663 g_variant_iter_free(iter);
665 if (wifi_tech_powered == TRUE)
666 ret = NETCONFIG_WIFI_TECH_POWERED;
668 if (wifi_tech_connected == TRUE)
669 ret = NETCONFIG_WIFI_TECH_CONNECTED;
676 void wifi_state_set_connected_essid(void)
678 __set_wifi_connected_essid();
679 #if defined TIZEN_WEARABLE
680 wc_launch_syspopup(WC_POPUP_TYPE_WIFI_CONNECTED);
684 void wifi_state_get_connected_essid(gchar **essid)
686 *essid = g_strdup(__get_wifi_connected_essid());
689 /* wifi_connection_state_e in CAPI
691 * WIFI_CONNECTION_STATE_FAILURE = -1
692 * WIFI_CONNECTION_STATE_DISCONNECTED = 0
693 * WIFI_CONNECTION_STATE_ASSOCIATION = 1
694 * WIFI_CONNECTION_STATE_CONFIGURATION = 2
695 * WIFI_CONNECTION_STATE_CONNECTED = 3
697 /* connection_wifi_state_e in CAPI
699 * CONNECTION_WIFI_STATE_DEACTIVATED = 0
700 * CONNECTION_WIFI_STATE_DISCONNECTED = 1
701 * CONNECTION_WIFI_STATE_CONNECTED = 2
703 gboolean handle_get_wifi_state(Wifi *wifi, GDBusMethodInvocation *context)
705 g_return_val_if_fail(wifi != NULL, FALSE);
706 GVariant *param = NULL;
707 wifi_tech_state_e tech_state = NETCONFIG_WIFI_TECH_UNKNOWN;
708 wifi_service_state_e service_state = NETCONFIG_WIFI_UNKNOWN;
709 tech_state = wifi_state_get_technology_state();
710 service_state = wifi_state_get_service_state();
712 if (tech_state == NETCONFIG_WIFI_TECH_UNKNOWN)
713 param = g_variant_new("(s)", "unknown");
714 else if (tech_state == NETCONFIG_WIFI_TECH_OFF ||
715 tech_state == NETCONFIG_WIFI_TECH_WPS_ONLY)
716 param = g_variant_new("(s)", "deactivated");
717 else if (tech_state == NETCONFIG_WIFI_TECH_CONNECTED)
718 param = g_variant_new("(s)", "connected");
720 switch (service_state) {
721 case NETCONFIG_WIFI_FAILURE:
722 param = g_variant_new("(s)", "failure");
724 case NETCONFIG_WIFI_ASSOCIATION:
725 param = g_variant_new("(s)", "association");
727 case NETCONFIG_WIFI_CONFIGURATION:
728 param = g_variant_new("(s)", "configuration");
730 case NETCONFIG_WIFI_CONNECTED:
731 param = g_variant_new("(s)", "connected");
733 case NETCONFIG_WIFI_UNKNOWN:
734 case NETCONFIG_WIFI_IDLE:
736 param = g_variant_new("(s)", "disconnected");
740 g_dbus_method_invocation_return_value(context, param);